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'))
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
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)
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)
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())), ]
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
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'))
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)
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
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))