class ExpressionAbc(SolidityAbc, ABC):
"""
Abstract base class for all IR expression nodes.
> Something that has a value.
"""
_type_descriptions: TypeDescriptionsModel
_statement_cache: Optional[weakref.ReferenceType[StatementAbc]]
def __init__(
self, init: IrInitTuple, expression: SolcExpressionUnion, parent: SolidityAbc
):
super().__init__(init, expression, parent)
self._type_descriptions = expression.type_descriptions
@classmethod
def _strip_weakrefs(cls, state: dict):
super()._strip_weakrefs(state)
state.pop("_statement_cache", None)
@staticmethod
def from_ast(
init: IrInitTuple, expression: SolcExpressionUnion, parent: SolidityAbc
) -> ExpressionAbc:
from .assignment import Assignment
from .binary_operation import BinaryOperation
from .conditional import Conditional
from .elementary_type_name_expression import ElementaryTypeNameExpression
from .function_call import FunctionCall
from .function_call_options import FunctionCallOptions
from .identifier import Identifier
from .index_access import IndexAccess
from .index_range_access import IndexRangeAccess
from .literal import Literal
from .member_access import MemberAccess
from .new_expression import NewExpression
from .tuple_expression import TupleExpression
from .unary_operation import UnaryOperation
if isinstance(expression, SolcAssignment):
return Assignment(init, expression, parent)
elif isinstance(expression, SolcBinaryOperation):
return BinaryOperation(init, expression, parent)
elif isinstance(expression, SolcConditional):
return Conditional(init, expression, parent)
elif isinstance(expression, SolcElementaryTypeNameExpression):
return ElementaryTypeNameExpression(init, expression, parent)
elif isinstance(expression, SolcFunctionCall):
return FunctionCall(init, expression, parent)
elif isinstance(expression, SolcFunctionCallOptions):
return FunctionCallOptions(init, expression, parent)
elif isinstance(expression, SolcIdentifier):
return Identifier(init, expression, parent)
elif isinstance(expression, SolcIndexAccess):
return IndexAccess(init, expression, parent)
elif isinstance(expression, SolcIndexRangeAccess):
return IndexRangeAccess(init, expression, parent)
elif isinstance(expression, SolcLiteral):
return Literal(init, expression, parent)
elif isinstance(expression, SolcMemberAccess):
return MemberAccess(init, expression, parent)
elif isinstance(expression, SolcNewExpression):
return NewExpression(init, expression, parent)
elif isinstance(expression, SolcTupleExpression):
return TupleExpression(init, expression, parent)
elif isinstance(expression, SolcUnaryOperation):
return UnaryOperation(init, expression, parent)
@property
@weak_self_lru_cache(maxsize=2048)
def type(self) -> Optional[TypeAbc]:
"""
Can be `None` in case of an [Identifier][wake.ir.expressions.identifier.Identifier] in an [ImportDirective][wake.ir.meta.import_directive.ImportDirective].
!!! example
`Ownable` in the following example has no type information:
```solidity
import { Ownable } from './Ownable.sol';
```
Returns:
Type of the expression.
"""
if self._type_descriptions.type_identifier is None:
return None
type_identifier = StringReader(self._type_descriptions.type_identifier)
ret = TypeAbc.from_type_identifier(
type_identifier, self._reference_resolver, self.source_unit.cu_hash
)
assert (
len(type_identifier) == 0
), f"Failed to parse type_identifier: {self._type_descriptions.type_identifier}"
return ret
@property
def type_identifier(self) -> Optional[str]:
return self._type_descriptions.type_identifier
@property
def type_string(self) -> Optional[str]:
"""
!!! example
`:::solidity function (uint256,uint256) returns (uint256)` in the case of the `foo` [Identifier][wake.ir.expressions.identifier.Identifier] in the `:::solidity foo(1, 2)` expression for the following function:
```solidity
function foo(uint a, uint b) public onlyOwner payable virtual onlyOwner returns(uint) {
return a + b;
}
```
Can be `None` in case of an [Identifier][wake.ir.expressions.identifier.Identifier] in an [ImportDirective][wake.ir.meta.import_directive.ImportDirective].
!!! example
`Ownable` in the following example has no type information:
```solidity
import { Ownable } from './Ownable.sol';
```
Returns:
User-friendly string describing the expression type.
"""
return self._type_descriptions.type_string
@property
@abstractmethod
def is_ref_to_state_variable(self) -> bool:
"""
In many cases it may be useful to know if an [Assignment][wake.ir.expressions.assignment.Assignment] to an expression modifies a state variable or not.
This may not be straightforward to determine, e.g. if the expression is a [MemberAccess][wake.ir.expressions.member_access.MemberAccess] or [IndexAccess][wake.ir.expressions.index_access.IndexAccess] to a state variable.
WARNING:
Is not considered stable and so is not exported in the documentation.
Returns:
`True` if the expression (possibly) is a reference to a state variable.
"""
...
@property
@abstractmethod
def modifies_state(
self,
) -> Set[Tuple[Union[ExpressionAbc, StatementAbc, YulAbc], ModifiesStateFlag]]:
"""
WARNING:
Is not considered stable and so is not exported in the documentation.
Returns:
Set of child IR nodes (including `self`) that modify the blockchain state and flags describing how the state is modified.
"""
...
@property
def statement(self) -> Optional[StatementAbc]:
"""
May be `None` if the expression is not part of a function or modifier body.
This may happen in:
- [ModifierInvocation][wake.ir.meta.modifier_invocation.ModifierInvocation] arguments,
- [InheritanceSpecifier][wake.ir.meta.inheritance_specifier.InheritanceSpecifier] arguments,
- [ArrayTypeName][wake.ir.type_names.array_type_name.ArrayTypeName] length value,
- [VariableDeclaration][wake.ir.declarations.variable_declaration.VariableDeclaration] initializer.
Returns:
Statement that contains the expression.
"""
if not hasattr(self, "_statement_cache"):
from ..statements.abc import StatementAbc
node = self
while node is not None:
if isinstance(node, StatementAbc):
self._statement_cache = weakref.ref(node)
return node
node = node.parent
self._statement_cache = None
return None
else:
return (
is_not_none(self._statement_cache())
if self._statement_cache is not None
else None
)