def _check_iterator_modification( target_node: vy_ast.VyperNode, search_node: vy_ast.VyperNode) -> Optional[vy_ast.VyperNode]: similar_nodes = [ n for n in search_node.get_descendants(type(target_node)) if vy_ast.compare_nodes(target_node, n) ] for node in similar_nodes: # raise if the node is the target of an assignment statement assign_node = node.get_ancestor((vy_ast.Assign, vy_ast.AugAssign)) # note the use of get_descendants() blocks statements like # self.my_array[i] = x if assign_node and node in assign_node.target.get_descendants( include_self=True): return node attr_node = node.get_ancestor(vy_ast.Attribute) # note the use of get_descendants() blocks statements like # self.my_array[i].append(x) if (attr_node is not None and node in attr_node.value.get_descendants(include_self=True) and attr_node.attr in ("append", "pop", "extend")): return node return None
def get_type_from_annotation( node: vy_ast.VyperNode, location: DataLocation, is_constant: bool = False, is_public: bool = False, is_immutable: bool = False, ) -> BaseTypeDefinition: """ Return a type object for the given AST node. Arguments --------- node : VyperNode Vyper ast node from the `annotation` member of a `VariableDef` or `AnnAssign` node. Returns ------- BaseTypeDefinition Type definition object. """ namespace = get_namespace() if isinstance(node, vy_ast.Tuple): values = node.elements types = tuple( get_type_from_annotation(v, DataLocation.UNSET) for v in values) return TupleDefinition(types) try: # get id of leftmost `Name` node from the annotation type_name = next( i.id for i in node.get_descendants(vy_ast.Name, include_self=True)) except StopIteration: raise StructureException("Invalid syntax for type declaration", node) try: type_obj = namespace[type_name] except UndeclaredDefinition: suggestions_str = get_levenshtein_error_suggestions( type_name, namespace, 0.3) raise UnknownType( f"No builtin or user-defined type named '{type_name}'. {suggestions_str}", node) from None if (getattr(type_obj, "_as_array", False) and isinstance(node, vy_ast.Subscript) and node.value.get("id") != "DynArray"): # TODO: handle `is_immutable` for arrays # if type can be an array and node is a subscript, create an `ArrayDefinition` length = get_index_value(node.slice) value_type = get_type_from_annotation(node.value, location, is_constant, False, is_immutable) return ArrayDefinition(value_type, length, location, is_constant, is_public, is_immutable) try: return type_obj.from_annotation(node, location, is_constant, is_public, is_immutable) except AttributeError: raise InvalidType(f"'{type_name}' is not a valid type", node) from None
def _check_iterator_assign( target_node: vy_ast.VyperNode, search_node: vy_ast.VyperNode ) -> Optional[vy_ast.VyperNode]: similar_nodes = [ n for n in search_node.get_descendants(type(target_node)) if vy_ast.compare_nodes(target_node, n) ] for node in similar_nodes: # raise if the node is the target of an assignment statement assign_node = node.get_ancestor((vy_ast.Assign, vy_ast.AugAssign)) if assign_node and node in assign_node.target.get_descendants(include_self=True): return node return None
def get_type_from_annotation( node: vy_ast.VyperNode, location: DataLocation, is_immutable: bool = False, is_public: bool = False, ) -> BaseTypeDefinition: """ Return a type object for the given AST node. Arguments --------- node : VyperNode Vyper ast node from the `annotation` member of an `AnnAssign` node. Returns ------- BaseTypeDefinition Type definition object. """ namespace = get_namespace() try: # get id of leftmost `Name` node from the annotation type_name = next( i.id for i in node.get_descendants(vy_ast.Name, include_self=True)) except StopIteration: raise StructureException("Invalid syntax for type declaration", node) try: type_obj = namespace[type_name] except UndeclaredDefinition: raise UnknownType( f"No builtin or user-defined type named '{type_name}'", node) from None if getattr(type_obj, "_as_array", False) and isinstance( node, vy_ast.Subscript): # if type can be an array and node is a subscript, create an `ArrayDefinition` length = get_index_value(node.slice) value_type = get_type_from_annotation(node.value, location, is_immutable, False) return ArrayDefinition(value_type, length, location, is_immutable, is_public) try: return type_obj.from_annotation(node, location, is_immutable, is_public) except AttributeError: raise InvalidType(f"'{type_name}' is not a valid type", node) from None
def from_annotation( cls, node: vy_ast.VyperNode, location: DataLocation = DataLocation.MEMORY, is_immutable: bool = False, is_public: bool = False, ) -> _ArrayValueDefinition: if not isinstance(node, vy_ast.Subscript): raise StructureException( f"Cannot declare {cls._id} type without a maximum length", node ) if len(node.get_descendants(vy_ast.Subscript, include_self=True)) > 1: raise StructureException(f"Multidimensional {cls._id} arrays are not supported", node) if node.get("value.id") != cls._id: raise UnexpectedValue("Node id does not match type name") length = validation.utils.get_index_value(node.slice) # type: ignore return cls._type(length, location, is_immutable, is_public)