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_type_visitor(): t = TypeStruct(scope=scope('T'), is_fully_resolved=False) t_star = TypePointer(pointee=t) t_star2 = TypePointer(pointee=t_star) assert simplify_type_system( parse_expr('fp + 3 + [ap]')) == (parse_expr('fp + 3 + [ap]'), TypeFelt()) assert simplify_type_system( parse_expr('cast(fp + 3 + [ap], T*)')) == (parse_expr('fp + 3 + [ap]'), t_star) # Two casts. assert simplify_type_system( parse_expr('cast(cast(fp, T*), felt)')) == (parse_expr('fp'), TypeFelt()) # Cast from T to T. assert simplify_type_system( parse_expr('cast([cast(fp, T*)], T)')) == (parse_expr('[fp]'), t) # Dereference. assert simplify_type_system( parse_expr('[cast(fp, T**)]')) == (parse_expr('[fp]'), t_star) assert simplify_type_system( parse_expr('[[cast(fp, T**)]]')) == (parse_expr('[[fp]]'), t) # Address of. assert simplify_type_system( parse_expr('&([[cast(fp, T**)]])')) == (parse_expr('[fp]'), t_star) assert simplify_type_system( parse_expr('&&[[cast(fp, T**)]]')) == (parse_expr('fp'), t_star2)
def test_struct_collector(): modules = {'module': """ struct S: member x : S* member y : S* end """, '__main__': """ from module import S func foo{z}(a : S, b) -> (c : S): struct T: member x : S* end const X = 5 return (c=a + X) end const Y = 1 + 1 """} scope = ScopedName.from_string struct_defs = _collect_struct_definitions(modules) expected_def = { 'module.S': StructDefinition( full_name=scope('module.S'), members={ 'x': MemberDefinition(offset=0, cairo_type=TypePointer(pointee=TypeStruct( scope=scope('module.S'), is_fully_resolved=True))), 'y': MemberDefinition(offset=1, cairo_type=TypePointer(pointee=TypeStruct( scope=scope('module.S'), is_fully_resolved=True))), }, size=2), '__main__.S': AliasDefinition(destination=scope('module.S')), '__main__.foo.Args': StructDefinition( full_name=scope('__main__.foo.Args'), members={ 'a': MemberDefinition(offset=0, cairo_type=TypeStruct( scope=scope('module.S'), is_fully_resolved=True)), 'b': MemberDefinition(offset=2, cairo_type=TypeFelt()), }, size=3), '__main__.foo.ImplicitArgs': StructDefinition( full_name=scope('__main__.foo.ImplicitArgs'), members={'z': MemberDefinition(offset=0, cairo_type=TypeFelt())}, size=1), '__main__.foo.Return': StructDefinition( full_name=scope('__main__.foo.Return'), members={ 'c': MemberDefinition(offset=0, cairo_type=TypeStruct( scope=scope('module.S'), is_fully_resolved=True)) }, size=2), '__main__.foo.T': StructDefinition( full_name=scope('__main__.foo.T'), members={ 'x': MemberDefinition(offset=0, cairo_type=TypePointer(pointee=TypeStruct( scope=scope('module.S'), is_fully_resolved=True))), }, size=1) } assert struct_defs == expected_def
def test_reference_rebinding(): identifier_values = { scope('ref'): ReferenceDefinition( full_name=scope('ref'), cairo_type=TypeFelt(), references=[], ) } reference_manager = ReferenceManager() flow_tracking_data = FlowTrackingDataActual(ap_tracking=RegTrackingData()) consts = get_vm_consts(identifier_values, reference_manager, flow_tracking_data) with pytest.raises(FlowTrackingError, match='Reference ref revoked'): consts.ref flow_tracking_data = flow_tracking_data.add_reference( reference_manager=reference_manager, name=scope('ref'), ref=Reference( pc=10, value=parse_expr('10'), ap_tracking_data=RegTrackingData(group=0, offset=2), ), ) consts = get_vm_consts(identifier_values, reference_manager, flow_tracking_data) assert consts.ref == 10
def test_revoked_reference(): reference_manager = ReferenceManager() ref_id = reference_manager.alloc_id(reference=Reference( pc=0, value=parse_expr('[ap + 1]'), ap_tracking_data=RegTrackingData(group=0, offset=2), )) identifier_values = { scope('x'): ReferenceDefinition(full_name=scope('x'), cairo_type=TypeFelt(), references=[]), } prime = 2**64 + 13 ap = 100 fp = 200 memory = {} flow_tracking_data = FlowTrackingDataActual( ap_tracking=RegTrackingData(group=1, offset=4), reference_ids={scope('x'): ref_id}, ) context = VmConstsContext( identifiers=IdentifierManager.from_dict(identifier_values), evaluator=ExpressionEvaluator(prime, ap, fp, memory).eval, reference_manager=reference_manager, flow_tracking_data=flow_tracking_data, memory=memory, pc=0) consts = VmConsts(context=context, accessible_scopes=[ScopedName()]) with pytest.raises(FlowTrackingError, match='Failed to deduce ap.'): assert consts.x
def test_type_tuples(): t = TypeStruct(scope=scope('T'), is_fully_resolved=True) t_star = TypePointer(pointee=t) # Simple tuple. simplify_type_system_test('(fp, [cast(fp, T*)], cast(fp,T*))', '(fp, [fp], fp)', TypeTuple(members=[TypeFelt(), t, t_star], )) # Nested. simplify_type_system_test( '(fp, (), ([cast(fp, T*)],))', '(fp, (), ([fp],))', TypeTuple(members=[ TypeFelt(), TypeTuple(members=[]), TypeTuple(members=[t]) ], ))
def test_type_visitor_pointer_arithmetic(): t = TypeStruct(scope=scope('T'), is_fully_resolved=True) t_star = TypePointer(pointee=t) simplify_type_system_test('cast(fp, T*) + 3', 'fp + 3', t_star) simplify_type_system_test('cast(fp, T*) - 3', 'fp - 3', t_star) simplify_type_system_test('cast(fp, T*) - cast(3, T*)', 'fp - 3', TypeFelt())
def test_type_visitor_pointer_arithmetic(): t = TypeStruct(scope=scope('T'), is_fully_resolved=False) t_star = TypePointer(pointee=t) assert simplify_type_system(parse_expr('cast(fp, T*) + 3')) == ( parse_expr('fp + 3'), t_star) assert simplify_type_system(parse_expr('cast(fp, T*) - 3')) == ( parse_expr('fp - 3'), t_star) assert simplify_type_system(parse_expr('cast(fp, T*) - cast(3, T*)')) == ( parse_expr('fp - 3'), TypeFelt())
def test_type_tuples(): t = TypeStruct(scope=scope('T'), is_fully_resolved=False) t_star = TypePointer(pointee=t) # Simple tuple. assert simplify_type_system(parse_expr('(fp, [cast(fp, T*)], cast(fp,T*))')) == ( parse_expr('(fp, [fp], fp)'), TypeTuple(members=[TypeFelt(), t, t_star],) ) # Nested. assert simplify_type_system(parse_expr('(fp, (), ([cast(fp, T*)],))')) == ( parse_expr('(fp, (), ([fp],))'), TypeTuple( members=[ TypeFelt(), TypeTuple(members=[]), TypeTuple(members=[t])], ) )
def test_type_visitor(): t = TypeStruct(scope=scope('T'), is_fully_resolved=True) t_star = TypePointer(pointee=t) t_star2 = TypePointer(pointee=t_star) simplify_type_system_test('fp + 3 + [ap]', 'fp + 3 + [ap]', TypeFelt()) simplify_type_system_test('cast(fp + 3 + [ap], T*)', 'fp + 3 + [ap]', t_star) # Two casts. simplify_type_system_test('cast(cast(fp, T*), felt)', 'fp', TypeFelt()) # Cast from T to T. simplify_type_system_test('cast([cast(fp, T*)], T)', '[fp]', t) # Dereference. simplify_type_system_test('[cast(fp, T**)]', '[fp]', t_star) simplify_type_system_test('[[cast(fp, T**)]]', '[[fp]]', t) # Address of. simplify_type_system_test('&([[cast(fp, T**)]])', '[fp]', t_star) simplify_type_system_test('&&[[cast(fp, T**)]]', 'fp', t_star2)
def visit_ExprNeg(self, expr: ExprNeg) -> Tuple[ExprNeg, TypeFelt]: inner_expr, inner_type = self.visit(expr.val) if not isinstance(inner_type, TypeFelt): raise CairoTypeError( f"Unary '-' is not supported for type '{inner_type.format()}'.", location=expr.location) return dataclasses.replace( expr, val=inner_expr), TypeFelt(location=expr.location)
def visit_ExprDeref(self, expr: ExprDeref) -> Tuple[ExprDeref, CairoType]: addr_expr, addr_type = self.visit(expr.addr) if isinstance(addr_type, TypeFelt): return dataclasses.replace( expr, addr=addr_expr), TypeFelt(location=expr.location) elif isinstance(addr_type, TypePointer): return dataclasses.replace(expr, addr=addr_expr), addr_type.pointee else: raise CairoTypeError( f"Cannot dereference type '{addr_type.format()}'.", location=expr.location)
def test_process_calldata_failure(): location = dummy_location() with pytest.raises(PreprocessorError, match=re.escape('Unsupported argument type felt**.')): process_test_calldata( members={ 'arg_a': MemberDefinition( offset=0, cairo_type=FELT_STAR_STAR, location=location), 'arg_b': MemberDefinition( offset=1, cairo_type=TypeFelt(), location=location), }) with pytest.raises( PreprocessorError, match='Array argument "arg_a" must be preceeded by a length ' 'argument named "arg_a_len" of type felt.'): process_test_calldata( members={ 'arg_a': MemberDefinition( offset=0, cairo_type=FELT_STAR, location=location), 'arg_b': MemberDefinition( offset=1, cairo_type=TypeFelt(), location=location), }) with pytest.raises( PreprocessorError, match=re.escape( "The 'range_check' builtin must be declared in the '%builtins' directive when using " 'array arguments in external functions.')): process_test_calldata(members={ 'arg_len': MemberDefinition(offset=0, cairo_type=TypeFelt(), location=location), 'arg': MemberDefinition(offset=1, cairo_type=FELT_STAR, location=location), }, has_range_check_builtin=False)
def process_retdata( self, ret_struct_ptr: Expression, ret_struct_type: CairoType, struct_def: StructDefinition, location: Optional[Location]) -> Tuple[Expression, Expression]: """ Processes the return values and return retdata_size and retdata_ptr. """ # Verify all of the return types are felts. for _, member_def in struct_def.members.items(): cairo_type = member_def.cairo_type if not isinstance(cairo_type, TypeFelt): raise PreprocessorError( f'Unsupported argument type {cairo_type.format()}.', location=cairo_type.location) self.add_reference( name=self.current_scope + 'retdata_ptr', value=ExprDeref( addr=ExprReg(reg=Register.AP), location=location, ), cairo_type=TypePointer(TypeFelt()), require_future_definition=False, location=location) self.visit(CodeElementHint( hint=ExprHint( hint_code='memory[ap] = segments.add()', n_prefix_newlines=0, location=location, ), location=location, )) # Skip check of hint whitelist as it fails before the workaround below. super().visit_CodeElementInstruction(CodeElementInstruction(InstructionAst( body=AddApInstruction(ExprConst(1)), inc_ap=False, location=location))) # Remove the references from the last instruction's flow tracking as they are # not needed by the hint and they cause the hint whitelist to fail. assert len(self.instructions[-1].hints) == 1 hint, hint_flow_tracking_data = self.instructions[-1].hints[0] self.instructions[-1].hints[0] = hint, dataclasses.replace( hint_flow_tracking_data, reference_ids={}) self.visit(CodeElementCompoundAssertEq( ExprDeref( ExprCast(ExprIdentifier('retdata_ptr'), TypePointer(ret_struct_type))), ret_struct_ptr)) return (ExprConst(struct_def.size), ExprIdentifier('retdata_ptr'))
def test_struct_sorting(): orig = StructDefinition(full_name=ScopedName.from_string('T'), members={ 'b': MemberDefinition(offset=1, cairo_type=TypeFelt()), 'a': MemberDefinition(offset=0, cairo_type=TypeFelt()), }, size=2) members = orig.members assert list(members.items()) != sorted( members.items(), key=lambda key_value: key_value[1].offset) schema = IdentifierDefinitionSchema() loaded = schema.load(schema.dump(orig)) members = loaded.members assert list(members.items()) == sorted( members.items(), key=lambda key_value: key_value[1].offset)
def test_type_tuples_failures(): identifier_dict = { scope('T'): StructDefinition( full_name=scope('T'), members={ 'x': MemberDefinition(offset=0, cairo_type=TypeFelt()), 'y': MemberDefinition(offset=1, cairo_type=TypeFelt()), }, size=2, ), } identifiers = IdentifierManager.from_dict(identifier_dict) verify_exception('1 + cast((1, 2), T).x', """ file:?:?: Accessing struct members for r-value structs is not supported yet. 1 + cast((1, 2), T).x ^***************^ """, identifiers=identifiers)
def visit_ExprPow(self, expr: ExprOperator) -> Tuple[ExprOperator, CairoType]: a_expr, a_type = self.visit(expr.a) b_expr, b_type = self.visit(expr.b) if not isinstance(a_type, TypeFelt) and isinstance(b_type, TypeFelt): raise CairoTypeError( f"Operator '**' is not implemented for types " f"'{a_type.format()}' and '{b_type.format()}'.", location=expr.location) return dataclasses.replace(expr, a=a_expr, b=b_expr), TypeFelt(location=expr.location)
def test_offset_reference_definition_typed_members(): t = TypeStruct(scope=scope('T'), is_fully_resolved=True) s_star = TypePointer( pointee=TypeStruct(scope=scope('S'), is_fully_resolved=True)) reference_manager = ReferenceManager() identifiers = { scope('T'): ScopeDefinition(), scope('T.x'): MemberDefinition(offset=3, cairo_type=s_star), scope('T.flt'): MemberDefinition(offset=4, cairo_type=TypeFelt()), scope('S'): ScopeDefinition(), scope('S.x'): MemberDefinition(offset=10, cairo_type=t), } main_reference = ReferenceDefinition(full_name=scope('a'), references=[]) references = { scope('a'): reference_manager.get_id( Reference( pc=0, value=mark_types_in_expr_resolved(parse_expr('cast(ap, T*)')), ap_tracking_data=RegTrackingData(group=0, offset=0), )), } flow_tracking_data = FlowTrackingDataActual( ap_tracking=RegTrackingData(group=0, offset=1), reference_ids=references, ) # Create OffsetReferenceDefinition instances for expressions of the form "a.<member_path>", # such as a.x and a.x.x, and check the result of evaluation those expressions. for member_path, expected_result in [ ('x', 'cast([ap - 1 + 3], S*)'), ('x.x', 'cast([[ap - 1 + 3] + 10], T)'), ('x.x.x', 'cast([&[[ap - 1 + 3] + 10] + 3], S*)'), ('x.x.flt', 'cast([&[[ap - 1 + 3] + 10] + 4], felt)') ]: definition = OffsetReferenceDefinition(parent=main_reference, identifier_values=identifiers, member_path=scope(member_path)) assert definition.eval( reference_manager=reference_manager, flow_tracking_data=flow_tracking_data).format() == expected_result definition = OffsetReferenceDefinition(parent=main_reference, identifier_values=identifiers, member_path=scope('x.x.flt.x')) with pytest.raises( DefinitionError, match='Member access requires a type of the form Struct*.'): assert definition.eval( reference_manager=reference_manager, flow_tracking_data=flow_tracking_data).format() == expected_result
def wrap(self, expr: Expression) -> ExprIdentifier: identifier = ExprIdentifier(name=self.context.new_tempvar_name(), location=expr.location) expr = self.translate_ap(expr) self.n_vars += 1 self.code_elements.append( CodeElementTemporaryVariable(typed_identifier=TypedIdentifier( identifier=identifier, expr_type=TypeFelt(location=expr.location)), expr=expr, location=expr.location)) return identifier
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)
def test_process_calldata_flow(): location = dummy_location() code_elements, expr = process_test_calldata( members={ 'a_len': MemberDefinition( offset=0, cairo_type=TypeFelt(), location=location), 'a': MemberDefinition(offset=1, cairo_type=FELT_STAR, location=location), 'b': MemberDefinition( offset=2, cairo_type=TypeFelt(), location=location), }) assert ''.join( code_element.format(100) + '\n' for code_element in code_elements) == """\ let __calldata_ptr : felt* = cast(calldata_ptr, felt*) let __calldata_arg_a_len = [__calldata_ptr] let __calldata_ptr = __calldata_ptr + 1 assert [range_check_ptr] = __calldata_arg_a_len let range_check_ptr = range_check_ptr + 1 let __calldata_arg_a : felt* = __calldata_ptr tempvar __calldata_ptr = __calldata_ptr + __calldata_arg_a_len let __calldata_arg_b = [__calldata_ptr] let __calldata_ptr = __calldata_ptr + 1 let __calldata_actual_size = __calldata_ptr - cast(calldata_ptr, felt*) assert calldata_size = __calldata_actual_size """ assert expr.format( ) == 'a_len=__calldata_arg_a_len, a=__calldata_arg_a, b=__calldata_arg_b,' assert code_elements[0].expr.location.parent_location == ( location, 'While handling calldata of')
def visit_ExprOperator( self, expr: ExprOperator) -> Tuple[ExprOperator, CairoType]: a_expr, a_type = self.visit(expr.a) b_expr, b_type = self.visit(expr.b) op = expr.op result_type: CairoType if isinstance(a_type, TypeFelt) and isinstance(b_type, TypeFelt): result_type = TypeFelt(location=expr.location) elif isinstance(a_type, TypePointer) and isinstance( b_type, TypeFelt) and op in ['+', '-']: result_type = a_type elif isinstance(a_type, TypeFelt) and isinstance( b_type, TypePointer) and op == '+': result_type = b_type elif isinstance(a_type, TypePointer) and a_type == b_type and op == '-': result_type = TypeFelt(location=expr.location) else: raise CairoTypeError( f"Operator '{op}' is not implemented for types " f"'{a_type.format()}' and '{b_type.format()}'.", location=expr.location) return dataclasses.replace(expr, a=a_expr, b=b_expr), result_type
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 type_felt(self, value, meta): return TypeFelt(location=self.meta2loc(meta))
import itertools from typing import Optional from starkware.cairo.lang.compiler.ast.cairo_types import (CairoType, CastType, TypeFelt, TypePointer, TypeStruct, TypeTuple) from starkware.cairo.lang.compiler.ast.expr import ExprDeref, Expression, ExprTuple from starkware.cairo.lang.compiler.error_handling import LocationError from starkware.cairo.lang.compiler.identifier_manager import IdentifierManager from starkware.cairo.lang.compiler.identifier_utils import get_struct_definition FELT_STAR = TypePointer(pointee=TypeFelt()) class CairoTypeError(LocationError): pass def check_cast(src_type: CairoType, dest_type: CairoType, identifier_manager: IdentifierManager, expr: Optional[Expression] = None, cast_type: CastType = CastType.EXPLICIT) -> bool: """ Returns true if the given expression can be casted from src_type to dest_type according to the given 'cast_type'. In some cases of cast failure, an exception with more specific details is raised. 'expr' must be specified (not None) when CastType.EXPLICIT (or above) is used.
def get_type(self) -> CairoType: """ Returns the type of the identifier. If not specified, the default type is felt (TypeFelt). """ return TypeFelt(location=self.location ) if self.expr_type is None else self.expr_type
def test_type_tuple(): typ = parse_type('(felt)') assert typ == TypeTuple(members=[TypeFelt()]) assert typ.format() == '(felt)' assert parse_type('( felt, felt* , (felt, T.S,)* )').format( ) == '(felt, felt*, (felt, T.S)*)'
def visit_ExprReg(self, expr: ExprReg) -> Tuple[ExprReg, TypeFelt]: return expr, TypeFelt(location=expr.location)
def test_references(): reference_manager = ReferenceManager() references = { scope('x.ref'): reference_manager.get_id( Reference( pc=0, value=parse_expr('[ap + 1]'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.ref2'): reference_manager.get_id( Reference( pc=0, value=parse_expr('[ap + 1] + 0'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.ref3'): reference_manager.get_id( Reference( pc=0, value=parse_expr('ap + 1'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.typeref'): reference_manager.get_id( Reference( pc=0, value=mark_types_in_expr_resolved( parse_expr('cast(ap + 1, a*)')), ap_tracking_data=RegTrackingData(group=0, offset=3), )), scope('x.typeref2'): reference_manager.get_id( Reference( pc=0, value=mark_types_in_expr_resolved( parse_expr('cast([ap + 1], a*)')), ap_tracking_data=RegTrackingData(group=0, offset=3), )), } identifier_values = { scope('x.ref'): ReferenceDefinition(full_name=scope('x.ref'), references=[]), scope('x.ref2'): ReferenceDefinition(full_name=scope('x.ref2'), references=[]), scope('x.ref3'): ReferenceDefinition(full_name=scope('x.ref3'), references=[]), scope('x.typeref'): ReferenceDefinition(full_name=scope('x.typeref'), references=[]), scope('x.typeref2'): ReferenceDefinition(full_name=scope('x.typeref2'), references=[]), scope('a.member'): MemberDefinition(offset=10, cairo_type=TypeFelt()), scope('a.scope0.member'): MemberDefinition(offset=2, cairo_type=TypeFelt()), } prime = 2**64 + 13 ap = 100 fp = 200 memory = { (ap - 2) + 1: 1234, (ap - 1) + 1: 1000, (ap - 1) + 1 + 2: 13, (ap - 1) + 1 + 10: 17, } flow_tracking_data = FlowTrackingDataActual( ap_tracking=RegTrackingData(group=0, offset=4), reference_ids=references, ) context = VmConstsContext( identifiers=IdentifierManager.from_dict(identifier_values), evaluator=ExpressionEvaluator(prime, ap, fp, memory).eval, reference_manager=reference_manager, flow_tracking_data=flow_tracking_data, memory=memory, pc=0) consts = VmConsts(context=context, accessible_scopes=[ScopedName()]) assert consts.x.ref == memory[(ap - 2) + 1] assert consts.x.typeref.address_ == (ap - 1) + 1 assert consts.x.typeref.member == memory[(ap - 1) + 1 + 10] with pytest.raises( NotImplementedError, match="Expected a member, found 'scope0' which is 'scope'"): consts.x.typeref.scope0 # Test that VmConsts can be used to assign values to references of the form '[...]'. memory.clear() consts.x.ref = 1234 assert memory == {(ap - 2) + 1: 1234} memory.clear() consts.x.typeref.member = 1001 assert memory == {(ap - 1) + 1 + 10: 1001} memory.clear() consts.x.typeref2 = 4321 assert memory == {(ap - 1) + 1: 4321} consts.x.typeref2.member = 1 assert memory == { (ap - 1) + 1: 4321, 4321 + 10: 1, } with pytest.raises(AssertionError, match='Cannot change the value of a scope definition'): consts.x = 1000 with pytest.raises( AssertionError, match= r'x.ref2 \(= \[ap \+ 1\] \+ 0\) does not reference memory and cannot be assigned.', ): consts.x.ref2 = 1000 with pytest.raises( AssertionError, match= r'x.typeref \(= ap \+ 1\) does not reference memory and cannot be assigned.', ): consts.x.typeref = 1000
def test_references(): reference_manager = ReferenceManager() references = { scope('x.ref'): reference_manager.alloc_id( Reference( pc=0, value=parse_expr('[ap + 1]'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.ref2'): reference_manager.alloc_id( Reference( pc=0, value=parse_expr('[ap + 1] + 0'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.ref3'): reference_manager.alloc_id( Reference( pc=0, value=parse_expr('ap + 1'), ap_tracking_data=RegTrackingData(group=0, offset=2), )), scope('x.typeref'): reference_manager.alloc_id( Reference( pc=0, value=mark_types_in_expr_resolved( parse_expr('cast(ap + 1, MyStruct*)')), ap_tracking_data=RegTrackingData(group=0, offset=3), )), scope('x.typeref2'): reference_manager.alloc_id( Reference( pc=0, value=mark_types_in_expr_resolved( parse_expr('cast([ap + 1], MyStruct*)')), ap_tracking_data=RegTrackingData(group=0, offset=3), )), } my_struct_star = TypePointer( pointee=TypeStruct(scope=scope('MyStruct'), is_fully_resolved=True)) identifier_values = { scope('x.ref'): ReferenceDefinition(full_name=scope('x.ref'), cairo_type=TypeFelt(), references=[]), scope('x.ref2'): ReferenceDefinition(full_name=scope('x.ref2'), cairo_type=TypeFelt(), references=[]), scope('x.ref3'): ReferenceDefinition(full_name=scope('x.ref3'), cairo_type=TypeFelt(), references=[]), scope('x.typeref'): ReferenceDefinition(full_name=scope('x.typeref'), cairo_type=my_struct_star, references=[]), scope('x.typeref2'): ReferenceDefinition(full_name=scope('x.typeref2'), cairo_type=my_struct_star, references=[]), scope('MyStruct'): StructDefinition( full_name=scope('MyStruct'), members={ 'member': MemberDefinition(offset=10, cairo_type=TypeFelt()), }, size=11, ), } prime = 2**64 + 13 ap = 100 fp = 200 memory = { (ap - 2) + 1: 1234, (ap - 1) + 1: 1000, (ap - 1) + 1 + 2: 13, (ap - 1) + 1 + 10: 17, } flow_tracking_data = FlowTrackingDataActual( ap_tracking=RegTrackingData(group=0, offset=4), reference_ids=references, ) context = VmConstsContext( identifiers=IdentifierManager.from_dict(identifier_values), evaluator=ExpressionEvaluator(prime, ap, fp, memory).eval, reference_manager=reference_manager, flow_tracking_data=flow_tracking_data, memory=memory, pc=0) consts = VmConsts(context=context, accessible_scopes=[ScopedName()]) assert consts.x.ref == memory[(ap - 2) + 1] assert consts.x.typeref.address_ == (ap - 1) + 1 assert consts.x.typeref.member == memory[(ap - 1) + 1 + 10] with pytest.raises(IdentifierError, match="'abc' is not a member of 'MyStruct'."): consts.x.typeref.abc with pytest.raises(IdentifierError, match="'SIZE' is not a member of 'MyStruct'."): consts.x.typeref.SIZE with pytest.raises( AssertionError, match='Cannot change the value of a struct definition.'): consts.MyStruct = 13 assert consts.MyStruct.member == 10 with pytest.raises(AssertionError, match='Cannot change the value of a constant.'): consts.MyStruct.member = 13 assert consts.MyStruct.SIZE == 11 with pytest.raises(AssertionError, match='Cannot change the value of a constant.'): consts.MyStruct.SIZE = 13 with pytest.raises(IdentifierError, match="'abc' is not a member of 'MyStruct'."): consts.MyStruct.abc # Test that VmConsts can be used to assign values to references of the form '[...]'. memory.clear() consts.x.ref = 1234 assert memory == {(ap - 2) + 1: 1234} memory.clear() consts.x.typeref.member = 1001 assert memory == {(ap - 1) + 1 + 10: 1001} memory.clear() consts.x.typeref2 = 4321 assert memory == {(ap - 1) + 1: 4321} consts.x.typeref2.member = 1 assert memory == { (ap - 1) + 1: 4321, 4321 + 10: 1, } with pytest.raises(AssertionError, match='Cannot change the value of a scope definition'): consts.x = 1000 with pytest.raises( AssertionError, match= r'x.ref2 \(= \[ap \+ 1\] \+ 0\) does not reference memory and cannot be assigned.', ): consts.x.ref2 = 1000 with pytest.raises( AssertionError, match= r'x.typeref \(= ap \+ 1\) does not reference memory and cannot be assigned.', ): consts.x.typeref = 1000