示例#1
0
def test_program_start_property():
    identifiers = IdentifierManager.from_dict({
        ScopedName.from_string('some.main.__start__'):
        LabelDefinition(3),
    })
    reference_manager = ReferenceManager()
    main_scope = ScopedName.from_string('some.main')

    # The label __start__ is in identifiers.
    program = Program(prime=0,
                      data=[],
                      hints={},
                      builtins=[],
                      main_scope=main_scope,
                      identifiers=identifiers,
                      reference_manager=reference_manager)
    assert program.start == 3

    # The label __start__ is not in identifiers.
    program = Program(prime=0,
                      data=[],
                      hints={},
                      builtins=[],
                      main_scope=main_scope,
                      identifiers=IdentifierManager(),
                      reference_manager=reference_manager)
    assert program.start == 0
 def _deserialize(self, value, attr, data, **kwargs) -> IdentifierManager:
     identifier_definition_schema = IdentifierDefinitionSchema()
     return IdentifierManager.from_dict({
         ScopedName.from_string(name):
         identifier_definition_schema.load(serialized_identifier_definition)
         for name, serialized_identifier_definition in value.items()
     })
示例#3
0
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
示例#4
0
def test_unsupported_attribute():
    class UnsupportedIdentifier(IdentifierDefinition):
        TYPE: ClassVar[str] = 'tested_t'

    identifier_values = {
        scope('x'): UnsupportedIdentifier(),
        scope('y.z'): UnsupportedIdentifier(),
    }
    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=[scope('')])

    # Identifier in root namespace.
    with pytest.raises(
            NotImplementedError,
            match="Unsupported identifier type 'tested_t' of identifier 'x'."):
        consts.x

    # Identifier in sub namespace.
    with pytest.raises(
            NotImplementedError,
            match="Unsupported identifier type 'tested_t' of identifier 'y.z'."
    ):
        consts.y.z
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_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_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_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 get_vm_consts(identifier_values, reference_manager, flow_tracking_data, memory={}):
    """
    Creates a simple VmConsts object.
    """
    identifiers = IdentifierManager.from_dict(identifier_values)
    context = VmConstsContext(
        identifiers=identifiers,
        evaluator=ExpressionEvaluator(2**64 + 13, 0, 0, memory, identifiers).eval,
        reference_manager=reference_manager,
        flow_tracking_data=flow_tracking_data, memory=memory, pc=9)
    return VmConsts(context=context, accessible_scopes=[ScopedName()])
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
示例#11
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
示例#12
0
def test_unparsed():
    identifier_values = {
        scope('x'): LabelDefinition(10),
    }
    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=[scope('')])

    with pytest.raises(IdentifierError, match="Unexpected '.' after 'x' which is label."):
        consts.x.z
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_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)
示例#15
0
def process_test_calldata(members: Dict[str, MemberDefinition],
                          has_range_check_builtin=True):
    identifier_values: Dict[ScopedName, IdentifierDefinition] = {
        scope('MyStruct'):
        StructDefinition(
            full_name=scope('MyStruct'),
            members=members,
            size=0,
        ),
    }
    identifiers = IdentifierManager.from_dict(identifier_values)
    calldata_ptr = ExprIdentifier('calldata_ptr')
    calldata_size = ExprIdentifier('calldata_size')
    return process_calldata(calldata_ptr=calldata_ptr,
                            calldata_size=calldata_size,
                            identifiers=identifiers,
                            struct_def=get_struct_definition(
                                struct_name=scope('MyStruct'),
                                identifier_manager=identifiers),
                            has_range_check_builtin=has_range_check_builtin,
                            location=dummy_location())
示例#16
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
示例#17
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_identifier_manager_field_serialization():
    @marshmallow_dataclass.dataclass
    class Foo:
        identifiers: IdentifierManager = field(metadata=dict(
            marshmallow_field=IdentifierManagerField()))

    Schema = marshmallow_dataclass.class_schema(Foo)

    foo = Foo(identifiers=IdentifierManager.from_dict({
        scope('aa.b'):
        LabelDefinition(pc=1000),
    }))
    serialized = Schema().dump(foo)
    assert serialized == {
        'identifiers': {
            'aa.b': {
                'pc': 1000,
                'type': 'label'
            }
        }
    }

    assert Schema().load(serialized) == foo
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_type_dot_op():
    """
    Tests type_system_visitor for ExprDot-s, in the following struct architecture:

    struct S:
        member x : felt
        member y : felt
    end

    struct T:
        member t : felt
        member s : S
        member sp : S*
    end

    struct R:
        member r : R*
    end
    """
    t = TypeStruct(scope=scope('T'), is_fully_resolved=True)
    s = TypeStruct(scope=scope('S'), is_fully_resolved=True)
    s_star = TypePointer(pointee=s)
    r = TypeStruct(scope=scope('R'), is_fully_resolved=True)
    r_star = TypePointer(pointee=r)

    identifier_dict = {
        scope('T'):
        StructDefinition(
            full_name=scope('T'),
            members={
                't': MemberDefinition(offset=0, cairo_type=TypeFelt()),
                's': MemberDefinition(offset=1, cairo_type=s),
                'sp': MemberDefinition(offset=3, cairo_type=s_star),
            },
            size=4,
        ),
        scope('S'):
        StructDefinition(
            full_name=scope('S'),
            members={
                'x': MemberDefinition(offset=0, cairo_type=TypeFelt()),
                'y': MemberDefinition(offset=1, cairo_type=TypeFelt()),
            },
            size=2,
        ),
        scope('R'):
        StructDefinition(
            full_name=scope('R'),
            members={
                'r': MemberDefinition(offset=0, cairo_type=r_star),
            },
            size=1,
        ),
    }

    identifiers = IdentifierManager.from_dict(identifier_dict)

    for (orig_expr, simplified_expr, simplified_type) in [
        ('[cast(fp, T*)].t', '[fp]', TypeFelt()),
        ('[cast(fp, T*)].s', '[fp + 1]', s),
        ('[cast(fp, T*)].sp', '[fp + 3]', s_star),
        ('[cast(fp, T*)].s.x', '[fp + 1]', TypeFelt()),
        ('[cast(fp, T*)].s.y', '[fp + 1 + 1]', TypeFelt()),
        ('[[cast(fp, T*)].sp].x', '[[fp + 3]]', TypeFelt()),
        ('[cast(fp, R*)]', '[fp]', r),
        ('[cast(fp, R*)].r', '[fp]', r_star),
        ('[[[cast(fp, R*)].r].r].r', '[[[fp]]]', r_star),
            # Test . as ->
        ('cast(fp, T*).t', '[fp]', TypeFelt()),
        ('cast(fp, T*).sp.y', '[[fp + 3] + 1]', TypeFelt()),
        ('cast(fp, R*).r.r.r', '[[[fp]]]', r_star),
            # More tests.
        ('(cast(fp, T*).s)', '[fp + 1]', s),
        ('(cast(fp, T*).s).x', '[fp + 1]', TypeFelt()),
        ('(&(cast(fp, T*).s)).x', '[fp + 1]', TypeFelt())
    ]:
        simplify_type_system_test(orig_expr,
                                  simplified_expr,
                                  simplified_type,
                                  identifiers=identifiers)

    # Test failures.

    verify_exception('cast(fp, felt).x',
                     """
file:?:?: Cannot apply dot-operator to non-struct type 'felt'.
cast(fp, felt).x
^**************^
""",
                     identifiers=identifiers)

    verify_exception('cast(fp, felt*).x',
                     """
file:?:?: Cannot apply dot-operator to pointer-to-non-struct type 'felt*'.
cast(fp, felt*).x
^***************^
""",
                     identifiers=identifiers)

    verify_exception('cast(fp, T*).x',
                     """
file:?:?: Member 'x' does not appear in definition of struct 'T'.
cast(fp, T*).x
^************^
""",
                     identifiers=identifiers)

    verify_exception('cast(fp, Z*).x',
                     """
file:?:?: Unknown identifier 'Z'.
cast(fp, Z*).x
^************^
""",
                     identifiers=identifiers)

    verify_exception('cast(fp, T*).x',
                     """
file:?:?: Identifiers must be initialized for type-simplification of dot-operator expressions.
cast(fp, T*).x
^************^
""",
                     identifiers=None)

    verify_exception('cast(fp, Z*).x',
                     """
file:?:?: Type is expected to be fully resolved at this point.
cast(fp, Z*).x
^************^
""",
                     identifiers=identifiers,
                     resolve_types=False)
def test_type_subscript_op():
    felt_star_star = TypePointer(pointee=TypePointer(pointee=TypeFelt()))
    t = TypeStruct(scope=scope('T'), is_fully_resolved=True)
    t_star = TypePointer(pointee=t)

    identifier_dict = {
        scope('T'): StructDefinition(full_name=scope('T'), members={}, size=7)
    }
    identifiers = IdentifierManager.from_dict(identifier_dict)

    simplify_type_system_test('cast(fp, felt*)[3]', '[fp + 3 * 1]', TypeFelt())
    simplify_type_system_test('cast(fp, felt***)[0]', '[fp + 0 * 1]',
                              felt_star_star)
    simplify_type_system_test('[cast(fp, T****)][ap][ap]',
                              '[[[fp] + ap * 1] + ap * 1]', t_star)
    simplify_type_system_test('cast(fp, T**)[1][2]',
                              '[[fp + 1 * 1] + 2 * 7]',
                              t,
                              identifiers=identifiers)

    # Test that 'cast(fp, T*)[2 * ap + 3]' simplifies into '[fp + (2 * ap + 3) * 7]', but without
    # the parentheses.
    assert simplify_type_system(
        mark_types_in_expr_resolved(parse_expr('cast(fp, T*)[2 * ap + 3]')),
        identifiers=identifiers) == (remove_parentheses(
            parse_expr('[fp + (2 * ap + 3) * 7]')), t)

    # Test subscript operator for tuples.
    simplify_type_system_test('(cast(fp, felt**), fp, cast(fp, T*))[2]', 'fp',
                              t_star)
    simplify_type_system_test('(cast(fp, felt**), fp, cast(fp, T*))[0]', 'fp',
                              felt_star_star)
    simplify_type_system_test('(cast(fp, felt**), ap, cast(fp, T*))[3*4 - 11]',
                              'ap', TypeFelt())
    simplify_type_system_test('[cast(ap, (felt, felt)*)][0]', '[ap + 0]',
                              TypeFelt())
    simplify_type_system_test('[cast(ap, (T*, T, felt, T*, felt*)*)][3]',
                              '[ap + 9]',
                              t_star,
                              identifiers=identifiers)

    # Test failures.

    verify_exception(
        '(fp, fp, fp)[cast(ap, felt*)]', """
file:?:?: Cannot apply subscript-operator with offset of non-felt type 'felt*'.
(fp, fp, fp)[cast(ap, felt*)]
             ^*************^
""")

    verify_exception(
        '(fp, fp, fp)[[ap]]', """
file:?:?: Subscript-operator for tuples supports only constant offsets, found 'ExprDeref'.
(fp, fp, fp)[[ap]]
             ^**^
""")

    # The simplifier in TypeSystemVisitor cannot access PRIME, so PyConsts are unsimplified.
    verify_exception(
        '(fp, fp, fp)[%[1%]]', """
file:?:?: Subscript-operator for tuples supports only constant offsets, found 'ExprPyConst'.
(fp, fp, fp)[%[1%]]
             ^***^
""")

    verify_exception(
        '(fp, fp, fp)[3]', """
file:?:?: Tuple index 3 is out of range [0, 3).
(fp, fp, fp)[3]
^*************^
""")

    verify_exception(
        '[cast(fp, (T*, T, felt)*)][-1]', """
file:?:?: Tuple index -1 is out of range [0, 3).
[cast(fp, (T*, T, felt)*)][-1]
^****************************^
""")

    verify_exception(
        'cast(fp, felt)[0]', """
file:?:?: Cannot apply subscript-operator to non-pointer, non-tuple type 'felt'.
cast(fp, felt)[0]
^***************^
""")

    verify_exception(
        '[cast(fp, T*)][0]', """
file:?:?: Cannot apply subscript-operator to non-pointer, non-tuple type 'T'.
[cast(fp, T*)][0]
^***************^
""")

    verify_exception(
        'cast(fp, felt*)[[cast(ap, T*)]]', """
file:?:?: Cannot apply subscript-operator with offset of non-felt type 'T'.
cast(fp, felt*)[[cast(ap, T*)]]
                ^************^
""")

    verify_exception('cast(fp, Z*)[0]',
                     """
file:?:?: Unknown identifier 'Z'.
cast(fp, Z*)[0]
^*************^
""",
                     identifiers=identifiers)

    verify_exception('cast(fp, T*)[0]',
                     """
file:?:?: Unknown identifier 'T'.
cast(fp, T*)[0]
^*************^
""",
                     identifiers=None)
示例#22
0
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
示例#23
0
def test_offset_reference_definition_typed_members():
    t = TypeStruct(scope=scope('T'), is_fully_resolved=True)
    t_star = TypePointer(pointee=t)
    s_star = TypePointer(
        pointee=TypeStruct(scope=scope('S'), is_fully_resolved=True))
    reference_manager = ReferenceManager()
    identifiers = IdentifierManager.from_dict({
        scope('T'):
        StructDefinition(
            full_name='T',
            members={
                'x': MemberDefinition(offset=3, cairo_type=s_star),
                'flt': MemberDefinition(offset=4, cairo_type=TypeFelt()),
            },
            size=5,
        ),
        scope('S'):
        StructDefinition(
            full_name='S',
            members={
                'x': MemberDefinition(offset=10, cairo_type=t),
            },
            size=15,
        ),
    })
    main_reference = ReferenceDefinition(full_name=scope('a'),
                                         cairo_type=t_star,
                                         references=[])
    references = {
        scope('a'):
        reference_manager.alloc_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,
                                               identifiers=identifiers,
                                               member_path=scope(member_path))
        definition.eval(
            reference_manager=reference_manager,
            flow_tracking_data=flow_tracking_data).format() == expected_result

    definition = OffsetReferenceDefinition(parent=main_reference,
                                           identifiers=identifiers,
                                           member_path=scope('x.x.flt.x'))
    with pytest.raises(
            DefinitionError,
            match='Member access requires a type of the form Struct*.'):
        definition.eval(reference_manager=reference_manager,
                        flow_tracking_data=flow_tracking_data)

    definition = OffsetReferenceDefinition(parent=main_reference,
                                           identifiers=identifiers,
                                           member_path=scope('x.y'))
    with pytest.raises(DefinitionError, match="'y' is not a member of 'S'."):
        definition.eval(reference_manager=reference_manager,
                        flow_tracking_data=flow_tracking_data)
示例#24
0
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