def visit_Log(self, node): if not isinstance(node.value, vy_ast.Call): raise StructureException("Log must call an event", node) event = get_exact_type_from_node(node.value.func) if not isinstance(event, Event): raise StructureException("Value is not an event", node.value) event.fetch_call_return(node.value)
def visit_Subscript(self, node, type_): base_type = get_exact_type_from_node(node.value) if isinstance(base_type, BaseTypeDefinition): # in the vast majority of cases `base_type` is a type definition, # however there are some edge cases with args to builtin functions self.visit(node.slice, base_type.get_index_type(node.slice.value)) self.visit(node.value, base_type)
def visit_Expr(self, node): if not isinstance(node.value, vy_ast.Call): raise StructureException("Expressions without assignment are disallowed", node) fn_type = get_exact_type_from_node(node.value.func) if isinstance(fn_type, Event): raise StructureException("To call an event you must use the `log` statement", node) if isinstance(fn_type, ContractFunction): if ( fn_type.mutability > StateMutability.VIEW and self.func.mutability <= StateMutability.VIEW ): raise StateAccessViolation( f"Cannot call a mutating function from a {self.func.mutability.value} function", node, ) if self.func.mutability == StateMutability.PURE: raise StateAccessViolation( f"Cannot call any function from a {self.func.mutability.value} function", node ) return_value = fn_type.fetch_call_return(node.value) if return_value and not isinstance(fn_type, ContractFunction): raise StructureException( f"Function '{fn_type._id}' cannot be called without assigning the result", node )
def _is_terminus_node(node: vy_ast.VyperNode) -> bool: if getattr(node, "_is_terminus", None): return True if isinstance(node, vy_ast.Expr) and isinstance(node.value, vy_ast.Call): func = get_exact_type_from_node(node.value.func) if getattr(func, "_is_terminus", None): return True return False
def visit_Call(self, node, type_): call_type = get_exact_type_from_node(node.func) node._metadata["type"] = type_ or call_type.fetch_call_return(node) if isinstance(call_type, (Event, ContractFunction)): for arg, arg_type in zip(node.args, list(call_type.arguments.values())): self.visit(arg, arg_type)
def visit_AugAssign(self, node): if isinstance(node.value, vy_ast.Tuple): raise StructureException("Right-hand side of assignment cannot be a tuple", node.value) target = get_exact_type_from_node(node.target) validate_expected_type(node.value, target) if self.func.mutability <= StateMutability.VIEW and target.location == DataLocation.STORAGE: raise StateAccessViolation( f"Cannot modify storage in a {self.func.mutability.value} function", node ) target.validate_modification(node)
def check_constant(node: vy_ast.VyperNode) -> bool: """ Check if the given node is a literal or constant value. """ if check_literal(node): return True if isinstance(node, (vy_ast.Tuple, vy_ast.List)): for item in node.elements: if not check_constant(item): return False return True value_type = get_exact_type_from_node(node) return getattr(value_type, "is_immutable", False)
def visit_Compare(self, node, type_): if isinstance(node.op, (vy_ast.In, vy_ast.NotIn)): if isinstance(node.right, vy_ast.List): type_ = get_common_types(node.left, *node.right.elements).pop() self.visit(node.left, type_) for element in node.right.elements: self.visit(element, type_) else: type_ = get_exact_type_from_node(node.right) self.visit(node.right, type_) self.visit(node.left, type_.value_type) else: type_ = get_common_types(node.left, node.right).pop() self.visit(node.left, type_) self.visit(node.right, type_)
def visit_Call(self, node, type_): call_type = get_exact_type_from_node(node.func) node._metadata["type"] = type_ or call_type.fetch_call_return(node) self.visit(node.func) if isinstance(call_type, (Event, ContractFunction)): # events and internal function calls for arg, arg_type in zip(node.args, list(call_type.arguments.values())): self.visit(arg, arg_type) elif isinstance(call_type, StructPrimitive): # literal structs for value, arg_type in zip(node.args[0].values, list(call_type.members.values())): self.visit(value, arg_type) elif node.func.id not in ("empty", "range"): # builtin functions for arg in node.args: self.visit(arg, None)
def visit_Attribute(self, node, type_): base_type = get_exact_type_from_node(node.value) node._metadata["type"] = base_type.get_member(node.attr, None)
def visit_AugAssign(self, node): type_ = get_exact_type_from_node(node.target) self.expr_visitor.visit(node.target, type_) self.expr_visitor.visit(node.value, type_)
def visit_Subscript(self, node, type_): base_type = get_exact_type_from_node(node.value) self.visit(node.slice, base_type.get_index_type(node.slice.value)) self.visit(node.value, base_type)
def visit_Name(self, node, type_): node._metadata["type"] = get_exact_type_from_node(node)