Пример #1
0
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
Пример #2
0
def _build_vyper_ast_init_kwargs(
    source_code: str,
    node: python_ast.AST,
    vyper_class: vyper_ast.VyperNode,
    source_id: int,
) -> Generator:
    start = node.first_token.start if hasattr(node, 'first_token') else (
        None, None)  # type: ignore
    yield ('col_offset', start[1])
    yield ('lineno', start[0])
    yield ('node_id', node.node_id)  # type: ignore
    yield ('source_code', source_code)

    end = node.last_token.end if hasattr(node, 'last_token') else (
        None, None)  # type: ignore
    yield ('end_lineno', end[0])
    yield ('end_col_offset', end[1])
    if hasattr(node, 'last_token'):
        start_pos = node.first_token.startpos  # type: ignore
        end_pos = node.last_token.endpos  # type: ignore
        yield ('src', f"{start_pos}:{end_pos-start_pos}:{source_id}")

    if isinstance(node, python_ast.ClassDef):
        yield ('class_type', node.class_type)  # type: ignore

    for field_name in vyper_class.get_slots():
        if hasattr(node, field_name):
            yield (field_name,
                   parse_python_ast(source_code=source_code,
                                    node=getattr(node, field_name),
                                    source_id=source_id))
Пример #3
0
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
Пример #4
0
    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)
Пример #5
0
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
Пример #6
0
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
Пример #7
0
def to_python_ast(vyper_ast_node: vyper_ast.VyperNode) -> python_ast.AST:
    if isinstance(vyper_ast_node, list):
        return [to_python_ast(n) for n in vyper_ast_node]
    elif isinstance(vyper_ast_node, vyper_ast.VyperNode):
        class_name = vyper_ast_node.__class__.__name__
        if hasattr(python_ast, class_name):
            py_klass = getattr(python_ast, class_name)
            return py_klass(
                **{
                    k: to_python_ast(getattr(vyper_ast_node, k, None))
                    for k in vyper_ast_node.get_slots()
                })
        else:
            raise CompilerPanic(
                f'Unknown vyper AST class "{class_name}" provided.')
    else:
        return vyper_ast_node
Пример #8
0
def _ast_to_dict(node: vyper_ast.VyperNode) -> Generator:
    for f in node.get_slots():
        if f not in DICT_AST_SKIPLIST:
            yield (f, ast_to_dict(getattr(node, f, None)))
    yield ('ast_type', node.__class__.__name__)