Exemplo n.º 1
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)
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
Exemplo n.º 3
0
def test_reference_to_structs():
    t = TypeStruct(scope=scope('T'), is_fully_resolved=True)
    t_star = TypePointer(pointee=t)
    identifier_values = {
        scope('ref'): ReferenceDefinition(full_name=scope('ref'),
                                          references=[]),
        scope('T.x'): MemberDefinition(offset=3, cairo_type=t_star),
    }
    reference_manager = ReferenceManager()
    flow_tracking_data = FlowTrackingDataActual(ap_tracking=RegTrackingData())
    flow_tracking_data = flow_tracking_data.add_reference(
        reference_manager=reference_manager,
        name=scope('ref'),
        ref=Reference(
            pc=0,
            value=mark_types_in_expr_resolved(parse_expr('cast([100], T)')),
            ap_tracking_data=RegTrackingData(group=0, offset=2),
        ))
    consts = get_vm_consts(identifier_values,
                           reference_manager,
                           flow_tracking_data,
                           memory={103: 200})

    assert consts.ref.address_ == 100
    assert consts.ref.x == 200
Exemplo n.º 4
0
    def add_struct_definition(
            self, members_list: List[MemberInfo], struct_name: ScopedName,
            location: Optional[Location]):

        offset = 0
        members: Dict[str, MemberDefinition] = {}
        for member_info in members_list:
            cairo_type = self.resolve_type(member_info.cairo_type)

            name = member_info.name
            if name in members:
                raise PreprocessorError(
                    f"Redefinition of '{struct_name + name}'.",
                    location=member_info.location)

            members[name] = MemberDefinition(
                offset=offset, cairo_type=cairo_type, location=member_info.location)
            offset += self.get_size(cairo_type)

        self.add_name_definition(
            struct_name,
            StructDefinition(
                full_name=struct_name,
                members=members,
                size=offset,
                location=location,
            ),
            location=location)
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_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 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_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)
Exemplo n.º 9
0
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')
Exemplo n.º 10
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())),
    ]
Exemplo n.º 11
0
def test_reference_to_structs():
    t = TypeStruct(scope=scope('T'), is_fully_resolved=True)
    t_star = TypePointer(pointee=t)
    identifier_values = {
        scope('ref'): ReferenceDefinition(
            full_name=scope('ref'), cairo_type=t, references=[]
        ),
        scope('T'): StructDefinition(
            full_name=scope('T'),
            members={
                'x': MemberDefinition(offset=3, cairo_type=t_star),
            },
            size=4,
        ),
    }
    reference_manager = ReferenceManager()
    flow_tracking_data = FlowTrackingDataActual(ap_tracking=RegTrackingData())
    flow_tracking_data = flow_tracking_data.add_reference(
        reference_manager=reference_manager,
        name=scope('ref'),
        ref=Reference(
            pc=0,
            value=mark_types_in_expr_resolved(parse_expr('[cast(100, T*)]')),
            ap_tracking_data=RegTrackingData(group=0, offset=2),
        ),
    )
    memory = {103: 200}
    consts = get_vm_consts(
        identifier_values, reference_manager, flow_tracking_data, memory=memory)

    assert consts.ref.address_ == 100
    assert consts.ref.x.address_ == 200
    # Set the pointer ref.x.x to 300.
    consts.ref.x.x = 300
    assert memory[203] == 300
    assert consts.ref.x.x.address_ == 300

    assert consts.ref.type_ == consts.T
Exemplo n.º 12
0
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)
Exemplo n.º 13
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
Exemplo n.º 14
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
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)