Base expression node.
| 280 | |
| 281 | |
| 282 | class ExprRef: |
| 283 | """Base expression node.""" |
| 284 | |
| 285 | __slots__ = ("_ast", "_sort", "_vars") |
| 286 | |
| 287 | def __init__( |
| 288 | self, |
| 289 | ast: ASTNode, |
| 290 | sort: SortRef, |
| 291 | vars: frozenset[tuple[str, ASTSort]] = frozenset(), |
| 292 | ) -> None: |
| 293 | self._ast = ast |
| 294 | self._sort = sort |
| 295 | self._vars = vars |
| 296 | |
| 297 | def sort(self) -> SortRef: |
| 298 | return self._sort |
| 299 | |
| 300 | def __repr__(self) -> str: |
| 301 | return _ast_repr(self._ast) |
| 302 | |
| 303 | def __eq__(self, other: object) -> BoolRef: # type: ignore[override] |
| 304 | if isinstance(other, (int, float)): |
| 305 | other = _coerce_val(other, self._sort) |
| 306 | if not isinstance(other, ExprRef): |
| 307 | return NotImplemented |
| 308 | # Normalize: put non-literal args on the left. Python's reflected |
| 309 | # comparison protocol can swap self/other when one type is a subclass |
| 310 | # of the other (e.g. IntNumRef subclasses ArithRef), leading to |
| 311 | # "5 = x + 3" instead of "x + 3 = 5". We canonicalize by putting |
| 312 | # literal/value AST nodes on the RHS so tactics see the natural order. |
| 313 | lhs, rhs = self._ast, other._ast |
| 314 | if _is_literal(lhs) and not _is_literal(rhs): |
| 315 | lhs, rhs = rhs, lhs |
| 316 | return BoolRef( |
| 317 | BinOpNode(BinOp.EQ, lhs, rhs), |
| 318 | _merge(self._vars, other._vars), |
| 319 | ) |
| 320 | |
| 321 | def __ne__(self, other: object) -> BoolRef: # type: ignore[override] |
| 322 | if isinstance(other, (int, float)): |
| 323 | other = _coerce_val(other, self._sort) |
| 324 | if not isinstance(other, ExprRef): |
| 325 | return NotImplemented |
| 326 | return BoolRef( |
| 327 | BinOpNode(BinOp.NE, self._ast, other._ast), |
| 328 | _merge(self._vars, other._vars), |
| 329 | ) |
| 330 | |
| 331 | def __hash__(self) -> int: |
| 332 | return hash(self._ast) |
| 333 | |
| 334 | def __bool__(self) -> bool: |
| 335 | raise TypeError("Symbolic expressions cannot be cast to concrete Boolean values") |
| 336 | |
| 337 | def num_args(self) -> int: |
| 338 | """Number of arguments (children) of this expression.""" |
| 339 | return len(_ast_children(self._ast)) |
no outgoing calls
no test coverage detected