def test_identifier_manager_aliases():
    identifier_dict = {
        scope('a.b.c'): AliasDefinition(destination=scope('x.y')),
        scope('x.y'): AliasDefinition(destination=scope('x.y2')),
        scope('x.y2.z'): ConstDefinition(value=3),
        scope('x.y2.s.z'): ConstDefinition(value=4),
        scope('x.y2.s2'): AliasDefinition(destination=scope('x.y2.s')),

        scope('z0'): AliasDefinition(destination=scope('z1.z2')),
        scope('z1.z2'): AliasDefinition(destination=scope('z3')),
        scope('z3'): AliasDefinition(destination=scope('z0')),

        scope('to_const'): AliasDefinition(destination=scope('x.y2.z')),
        scope('unresolved'): AliasDefinition(destination=scope('z1.missing')),
    }
    manager = IdentifierManager.from_dict(identifier_dict)

    # Test manager.get().
    assert manager.get(scope('a.b.c.z.w')) == IdentifierSearchResult(
        identifier_definition=identifier_dict[scope('x.y2.z')],
        canonical_name=scope('x.y2.z'),
        non_parsed=scope('w'))
    assert manager.get(scope('to_const.w')) == IdentifierSearchResult(
        identifier_definition=identifier_dict[scope('x.y2.z')],
        canonical_name=scope('x.y2.z'),
        non_parsed=scope('w'))

    with pytest.raises(IdentifierError, match='Cyclic aliasing detected: z0 -> z1.z2 -> z3 -> z0'):
        manager.get(scope('z0'))

    with pytest.raises(IdentifierError, match=(re.escape(
            'Alias resolution failed: unresolved -> z1.missing. '
            "Unknown identifier 'z1.missing'."))):
        manager.get(scope('unresolved'))

    # Test manager.get_scope().
    assert manager.get_scope(scope('a.b')).fullname == scope('a.b')
    assert manager.get_scope(scope('a.b.c')).fullname == scope('x.y2')
    assert manager.get_scope(scope('a.b.c.s')).fullname == scope('x.y2.s')
    assert manager.get_scope(scope('a.b.c.s2')).fullname == scope('x.y2.s')

    with pytest.raises(IdentifierError, match='Cyclic aliasing detected: z0 -> z1.z2 -> z3 -> z0'):
        manager.get_scope(scope('z0'))
    with pytest.raises(IdentifierError, match=(
            'Alias resolution failed: unresolved -> z1.missing. '
            "Unknown identifier 'z1.missing'.")):
        manager.get_scope(scope('unresolved'))
    with pytest.raises(IdentifierError, match=(
            "^Identifier 'x.y2.z' is const, expected a scope.")):
        manager.get_scope(scope('x.y2.z'))
    with pytest.raises(IdentifierError, match=(
            'Alias resolution failed: a.b.c.z.w -> x.y.z.w -> x.y2.z.w. '
            "Identifier 'x.y2.z' is const, expected a scope.")):
        manager.get_scope(scope('a.b.c.z.w'))
예제 #2
0
def resolve_search_result(
        search_result: IdentifierSearchResult,
        identifiers: IdentifierManager) -> IdentifierDefinition:
    """
    Returns a fully parsed identifier definition for the given identifier search result.
    If search_result contains a reference with non_parsed data, returns an instance of
    OffsetReferenceDefinition.
    """
    identifier_definition = search_result.identifier_definition
    if isinstance(identifier_definition, ReferenceDefinition) and \
            len(search_result.non_parsed) > 0:
        identifier_definition = OffsetReferenceDefinition(
            parent=identifier_definition,
            identifier_values=identifiers.as_dict(),
            member_path=search_result.non_parsed)
    else:
        search_result.assert_fully_parsed()

    return identifier_definition
예제 #3
0
def resolve_search_result(
        search_result: IdentifierSearchResult,
        identifiers: IdentifierManager) -> IdentifierDefinition:
    """
    Returns a fully parsed identifier definition for the given identifier search result.
    If search_result contains a reference with non_parsed data, returns an instance of
    OffsetReferenceDefinition.
    """
    identifier_definition = search_result.identifier_definition

    if len(search_result.non_parsed) == 0:
        return identifier_definition

    if isinstance(identifier_definition, StructDefinition):
        if search_result.non_parsed == SIZE_CONSTANT:
            return ConstDefinition(value=identifier_definition.size)

        member_def = identifier_definition.members.get(
            search_result.non_parsed.path[0])
        struct_name = identifier_definition.full_name
        if member_def is None:
            raise DefinitionError(
                f"'{search_result.non_parsed}' is not a member of '{struct_name}'."
            )

        if len(search_result.non_parsed) > 1:
            raise IdentifierError(
                f"Unexpected '.' after '{struct_name + search_result.non_parsed.path[0]}' which is "
                f'{member_def.TYPE}.')

        identifier_definition = member_def
    elif isinstance(identifier_definition, ReferenceDefinition):
        identifier_definition = OffsetReferenceDefinition(
            parent=identifier_definition,
            identifiers=identifiers,
            member_path=search_result.non_parsed)
    else:
        search_result.assert_fully_parsed()

    return identifier_definition
예제 #4
0
def test_identifier_manager_get():
    identifier_dict = {
        scope('a.b.c'): ConstDefinition(value=7),
    }
    manager = IdentifierManager.from_dict(identifier_dict)

    for name in ['a', 'a.b']:
        with pytest.raises(MissingIdentifierError,
                           match=f"Unknown identifier '{name}'."):
            manager.get(scope(name))

    # Search 'a.b.c.*'.
    for suffix in ['d', 'd.e']:
        result = manager.get(scope('a.b.c') + scope(suffix))
        assert result == IdentifierSearchResult(
            identifier_definition=identifier_dict[scope('a.b.c')],
            canonical_name=scope('a.b.c'),
            non_parsed=scope(suffix))

        error_msg = re.escape("Unexpected '.' after 'a.b.c' which is const")
        with pytest.raises(IdentifierError, match=error_msg):
            result.assert_fully_parsed()
        with pytest.raises(IdentifierError, match=error_msg):
            result.get_canonical_name()

    result = manager.get(scope('a.b.c'))
    assert result == IdentifierSearchResult(
        identifier_definition=identifier_dict[scope('a.b.c')],
        canonical_name=scope('a.b.c'),
        non_parsed=ScopedName())
    result.assert_fully_parsed()
    assert result.get_canonical_name() == scope('a.b.c')

    for name in ['a.d', 'a.d.e']:
        # The error should point to the first unknown item, rather then the entire name.
        with pytest.raises(MissingIdentifierError,
                           match="Unknown identifier 'a.d'."):
            manager.get(scope(name))
def test_resolve_search_result():
    struct_def = StructDefinition(
        full_name=scope('T'),
        members={
            'a': MemberDefinition(offset=0, cairo_type=TypeFelt()),
            'b': MemberDefinition(offset=1, cairo_type=TypeFelt()),
        },
        size=2,
    )

    identifier_dict = {
        struct_def.full_name: struct_def,
    }

    identifier = IdentifierManager.from_dict(identifier_dict)

    with pytest.raises(IdentifierError,
                       match="Unexpected '.' after 'T.a' which is member"):
        resolve_search_result(search_result=IdentifierSearchResult(
            identifier_definition=struct_def,
            canonical_name=struct_def.full_name,
            non_parsed=scope('a.z')),
                              identifiers=identifier)