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'))
Ejemplo n.º 2
0
def test_scope_order():
    identifier_values = {
        scope('x.y'): ConstDefinition(1),
        scope('y'): ConstDefinition(2),
    }
    context = VmConstsContext(
        identifiers=IdentifierManager.from_dict(identifier_values), evaluator=dummy_evaluator,
        reference_manager=ReferenceManager(),
        flow_tracking_data=FlowTrackingDataActual(ap_tracking=RegTrackingData()), memory={}, pc=0)
    consts = VmConsts(context=context, accessible_scopes=[ScopedName(), scope('x')])
    assert consts.y == 1
    assert consts.x.y == 1
Ejemplo n.º 3
0
def test_get_struct_definition():
    identifier_dict = {
        scope('T'):
        StructDefinition(
            full_name=scope('T'),
            members={
                'a': MemberDefinition(offset=0, cairo_type=TypeFelt()),
                'b': MemberDefinition(offset=1, cairo_type=TypeFelt()),
            },
            size=2,
        ),
        scope('MyConst'):
        ConstDefinition(value=5),
    }

    manager = IdentifierManager.from_dict(identifier_dict)

    struct_def = get_struct_definition(ScopedName.from_string('T'), manager)

    # Convert to a list, to check the order of the elements in the dict.
    assert list(struct_def.members.items()) == [
        ('a', MemberDefinition(offset=0, cairo_type=TypeFelt())),
        ('b', MemberDefinition(offset=1, cairo_type=TypeFelt())),
    ]

    assert struct_def.size == 2

    with pytest.raises(
            DefinitionError,
            match="Expected 'MyConst' to be a struct. Found: 'const'."):
        get_struct_definition(scope('MyConst'), manager)

    with pytest.raises(MissingIdentifierError,
                       match=re.escape("Unknown identifier 'abc'.")):
        get_struct_definition(scope('abc'), manager)
Ejemplo n.º 4
0
def test_missing_attributes():
    identifier_values = {
        scope('x.y'): ConstDefinition(1),
        scope('z'): AliasDefinition(scope('x')),
        scope('x.missing'): AliasDefinition(scope('nothing')),
    }

    context = VmConstsContext(
        identifiers=IdentifierManager.from_dict(identifier_values), evaluator=dummy_evaluator,
        reference_manager=ReferenceManager(),
        flow_tracking_data=FlowTrackingDataActual(ap_tracking=RegTrackingData()), memory={}, pc=0)
    consts = VmConsts(context=context, accessible_scopes=[ScopedName()])

    # Identifier not exists anywhere.
    with pytest.raises(MissingIdentifierError, match="Unknown identifier 'xx'."):
        consts.xx

    # Identifier not exists in accessible scopes.
    with pytest.raises(MissingIdentifierError, match="Unknown identifier 'y'."):
        consts.y

    # Recursive search.
    with pytest.raises(MissingIdentifierError, match="Unknown identifier 'x.z'."):
        consts.x.z

    # Pass through alias.
    with pytest.raises(MissingIdentifierError, match="Unknown identifier 'z.x'."):
        consts.z.x

    # Pass through bad alias.
    with pytest.raises(
            IdentifierError,
            match="Alias resolution failed: x.missing -> nothing. Unknown identifier 'nothing'."):
        consts.x.missing.y
def test_add_name_definition_no_future():
    visitor = IdentifierAwareVisitor()

    test_id = ScopedName.from_string('test_id')
    location = None

    visitor.add_name_definition(name=test_id,
                                identifier_definition=ConstDefinition(value=1),
                                location=location,
                                require_future_definition=False)

    with pytest.raises(PreprocessorError, match=f"Redefinition of 'test_id'."):
        visitor.add_name_definition(
            name=test_id,
            identifier_definition=ConstDefinition(value=1),
            location=location,
            require_future_definition=False)
Ejemplo n.º 6
0
def test_get_struct_members():
    identifier_dict = {
        scope('T.b'): MemberDefinition(offset=1, cairo_type=TypeFelt()),
        scope('T.a'): MemberDefinition(offset=0, cairo_type=TypeFelt()),
        scope('T.SIZE'): ConstDefinition(value=2),
        scope('S.a'): MemberDefinition(offset=0, cairo_type=TypeFelt()),
        scope('S.c'): MemberDefinition(offset=1, cairo_type=TypeFelt()),
        scope('S.SIZE'): ConstDefinition(value=2),
    }
    manager = IdentifierManager.from_dict(identifier_dict)

    member = get_struct_members(scope('T'), manager)
    # Convert to a list, to check the order of the elements in the dict.
    assert list(member.items()) == [
        ('a', MemberDefinition(offset=0, cairo_type=TypeFelt())),
        ('b', MemberDefinition(offset=1, cairo_type=TypeFelt())),
    ]
Ejemplo n.º 7
0
def test_process_file_scope():
    # Verify the good scenario.
    valid_scope = ScopedName.from_string('some.valid.scope')
    program = preprocess_str('const x = 4', prime=PRIME, main_scope=valid_scope)

    module = CairoModule(cairo_file=program, module_name=valid_scope)
    assert program.identifiers.as_dict() == {
        valid_scope + 'x': ConstDefinition(4)
    }
def test_identifier_manager_get_by_full_name():
    identifier_dict = {
        scope('a.b.c'): ConstDefinition(value=7),
        scope('x'): AliasDefinition(destination=scope('a')),
    }
    manager = IdentifierManager.from_dict(identifier_dict)
    assert manager.get_by_full_name(scope('a.b.c')) == identifier_dict[scope('a.b.c')]
    assert manager.get_by_full_name(scope('x')) == identifier_dict[scope('x')]

    assert manager.get_by_full_name(scope('a.b')) is None
    assert manager.get_by_full_name(scope('a.b.c.d')) is None
    assert manager.get_by_full_name(scope('x.b.c')) is None
Ejemplo n.º 9
0
def test_main_scope():
    identifiers = IdentifierManager.from_dict({
        ScopedName.from_string('a.b'):
        ConstDefinition(value=1),
        ScopedName.from_string('x.y.z'):
        ConstDefinition(value=2),
    })
    reference_manager = ReferenceManager()

    program = Program(prime=0,
                      data=[],
                      hints={},
                      builtins=[],
                      main_scope=ScopedName.from_string('a'),
                      identifiers=identifiers,
                      reference_manager=reference_manager)

    # Check accessible identifiers.
    assert program.get_identifier('b', ConstDefinition).value == 1

    # Ensure inaccessible identifiers.
    with pytest.raises(MissingIdentifierError,
                       match="Unknown identifier 'a'."):
        program.get_identifier('a.b', ConstDefinition)

    with pytest.raises(MissingIdentifierError,
                       match="Unknown identifier 'x'."):
        program.get_identifier('x.y', ConstDefinition)

    with pytest.raises(MissingIdentifierError,
                       match="Unknown identifier 'y'."):
        program.get_identifier('y', ConstDefinition)

    # Full name lookup.
    assert program.get_identifier('a.b',
                                  ConstDefinition,
                                  full_name_lookup=True).value == 1
    assert program.get_identifier('x.y.z',
                                  ConstDefinition,
                                  full_name_lookup=True).value == 2
def test_identifier_manager_search():
    identifier_dict = {
        scope('a.b.c.y'): ConstDefinition(value=1),
        scope('a.b.x'): ConstDefinition(value=2),
        scope('a.b.z'): ConstDefinition(value=3),
        scope('a.x'): ConstDefinition(value=4),
        scope('x'): ConstDefinition(value=5),
        scope('d.b.w'): ConstDefinition(value=6),
    }
    manager = IdentifierManager.from_dict(identifier_dict)

    for accessible_scopes, name, canonical_name in [
        (['a', 'a.b', 'a.b.c', 'e'], 'x', 'a.b.x'),
        (['a', 'a.b'], 'x', 'a.b.x'),
        (['a.b', 'a'], 'x', 'a.x'),
        ([''], 'x', 'x'),
        (['a', 'e', 'a.b.c'], 'b.z', 'a.b.z'),
    ]:
        result = manager.search(list(map(scope, accessible_scopes)), scope(name))
        assert result.canonical_name == scope(canonical_name)
        assert result.identifier_definition == identifier_dict[scope(canonical_name)]

    with pytest.raises(IdentifierError, match="Unknown identifier 'x'"):
        manager.search([], scope('x'))

    # Since 'd.b' exists, and it does not contain a sub-identifier 'z' the following raises an
    # exception (even though a.b.z exists).
    # Compare with the line (['a', 'e', 'a.b.c'], 'b.z', 'a.b.z') above.
    with pytest.raises(IdentifierError, match="Unknown identifier 'd.b.z'."):
        manager.search([scope('a'), scope('d'), scope('e'), scope('a.b.c')], scope('b.z.w'))
Ejemplo n.º 11
0
def test_imports():
    collector = IdentifierCollector()
    collector.identifiers.add_identifier(ScopedName.from_string('foo.bar'),
                                         ConstDefinition(value=0))
    ast = parse_file("""
from foo import bar as bar0
""")
    with collector.scoped(ScopedName(), parent=ast):
        collector.visit(ast.code_block)

    assert collector.identifiers.get_scope(ScopedName()).identifiers == {
        'bar0': AliasDefinition(destination=ScopedName.from_string('foo.bar')),
    }
def test_get_struct_size():
    identifiers = {
        scope('T'): ScopeDefinition(),
        scope('T.SIZE'): ConstDefinition(value=2),
        scope('S'): ScopeDefinition(),
        scope('S.SIZE'): ScopeDefinition(),
    }

    assert get_struct_size(ScopedName.from_string('T'), identifiers) == 2

    with pytest.raises(
            DefinitionError,
            match=re.escape("The identifier 'abc.SIZE' was not found.")):
        get_struct_size(ScopedName.from_string('abc'), identifiers)

    with pytest.raises(
            DefinitionError,
            match=re.escape(
                f"Expected 'S.SIZE' to be a const, but it is a scope.")):
        get_struct_size(ScopedName.from_string('S'), identifiers)
Ejemplo n.º 13
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
Ejemplo n.º 14
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))