コード例 #1
0
def verify_exception(expr_str: str, error: str):
    """
    Verifies that calling simplify_type_system() on the code results in the given error.
    """
    with pytest.raises(CairoTypeError) as e:
        simplify_type_system(parse_expr(expr_str))
    # Remove line and column information from the error using a regular expression.
    assert re.sub(':[0-9]+:[0-9]+: ', 'file:?:?: ', str(e.value)) == error.strip()
コード例 #2
0
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())
コード例 #3
0
ファイル: vm_consts.py プロジェクト: LexiccLabs/BeamNet
    def handle_ReferenceDefinition(self, name: str,
                                   identifier: ReferenceDefinition,
                                   scope: ScopedName,
                                   set_value: Optional[MaybeRelocatable]):
        # In set mode, take the address of the given reference instead.
        reference = self._context.flow_tracking_data.resolve_reference(
            reference_manager=self._context.reference_manager,
            name=identifier.full_name)

        if set_value is None:
            expr = reference.eval(self._context.flow_tracking_data.ap_tracking)
            expr, expr_type = simplify_type_system(expr)
            if isinstance(expr_type, TypeStruct):
                # If the reference is of type T, take its address and treat it as T*.
                assert isinstance(expr, ExprDeref), \
                    f"Expected expression of type '{expr_type.format()}' to have an address."
                expr = expr.addr
                expr_type = TypePointer(pointee=expr_type)
            val = self._context.evaluator(expr)

            # Check if the type is felt* or any_type**.
            is_pointer_to_felt_or_pointer = (
                isinstance(expr_type, TypePointer)
                and isinstance(expr_type.pointee, (TypePointer, TypeFelt)))
            if isinstance(expr_type,
                          TypeFelt) or is_pointer_to_felt_or_pointer:
                return val
            else:
                # Typed reference, return VmConstsReference which allows accessing members.
                assert isinstance(expr_type, TypePointer) and \
                    isinstance(expr_type.pointee, TypeStruct), \
                    'Type must be of the form T*.'
                return VmConstsReference(
                    context=self._context,
                    accessible_scopes=[expr_type.pointee.scope],
                    reference_value=val,
                    add_addr_var=True)
        else:
            assert str(scope[-1:]) == name, 'Expecting scope to end with name.'
            value, value_type = simplify_type_system(reference.value)
            assert isinstance(value, ExprDeref), f"""\
{scope} (= {value.format()}) does not reference memory and cannot be assigned."""

            value_ref = Reference(
                pc=reference.pc,
                value=ExprCast(expr=value.addr, dest_type=value_type),
                ap_tracking_data=reference.ap_tracking_data,
            )

            addr = self._context.evaluator(
                value_ref.eval(self._context.flow_tracking_data.ap_tracking))
            self._context.memory[addr] = set_value
コード例 #4
0
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)
コード例 #5
0
def verify_exception(expr_str: str,
                     error: str,
                     identifiers: Optional[IdentifierManager] = None,
                     resolve_types=True):
    """
    Verifies that calling simplify_type_system() on the code results in the given error.
    """
    with pytest.raises(CairoTypeError) as e:
        parsed_expr = parse_expr(expr_str)
        if resolve_types:
            parsed_expr = mark_types_in_expr_resolved(parsed_expr)
        simplify_type_system(parsed_expr, identifiers)
    # Remove line and column information from the error using a regular expression.
    assert re.sub(':[0-9]+:[0-9]+: ', 'file:?:?: ',
                  str(e.value)) == error.strip()
コード例 #6
0
 def get_reference_type(name):
     identifier_definition = program.identifiers.get_by_full_name(
         ScopedName.from_string(name))
     assert isinstance(identifier_definition, ReferenceDefinition)
     assert len(identifier_definition.references) == 1
     _, expr_type = simplify_type_system(
         identifier_definition.references[0].value)
     return expr_type
コード例 #7
0
def simplify_type_system_test(orig_expr: str,
                              simplified_expr: str,
                              simplified_type: CairoType,
                              identifiers: Optional[IdentifierManager] = None):
    parsed_expr = mark_types_in_expr_resolved(parse_expr(orig_expr))
    assert simplify_type_system(
        parsed_expr, identifiers=identifiers) == (parse_expr(simplified_expr),
                                                  simplified_type)
コード例 #8
0
def test_typed_references():
    scope = TEST_SCOPE
    program = preprocess_str(code="""
func main():
    struct T:
        member pad0 : felt
        member pad1 : felt
        member pad2 : felt
        member b : T*
    end

    struct Struct:
        member pad0 : felt
        member pad1 : felt
        member a : T*
    end

    let x : Struct* = cast(ap + 10, Struct*)
    let y : Struct = [x]

    [fp] = x.a
    assert [fp] = cast(x.a.b, felt)
    assert [fp] = cast(x.a.b.b, felt)

    [fp] = y.a + 1
    ret
end
""", prime=PRIME, main_scope=scope)

    def get_reference(name):
        scoped_name = scope + name
        assert isinstance(program.identifiers.get_by_full_name(scoped_name), ReferenceDefinition)

        return program.instructions[-1].flow_tracking_data.resolve_reference(
            reference_manager=program.reference_manager, name=scoped_name)

    expected_type_x = mark_type_resolved(parse_type(f'{scope}.main.Struct*'))
    assert simplify_type_system(get_reference('main.x').value)[1] == expected_type_x

    expected_type_y = mark_type_resolved(parse_type(f'{scope}.main.Struct'))
    reference = get_reference('main.y')
    assert simplify_type_system(reference.value)[1] == expected_type_y

    assert reference.value.format() == f'cast([ap + 10], {scope}.main.Struct)'
    assert program.format() == """\
コード例 #9
0
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])],
        )
    )
コード例 #10
0
def test_return_value_reference():
    program = preprocess_str(code="""
func foo() -> (val, x, y):
    ret
end

func main():
    let x = call foo
    [ap] = 0; ap++
    x.val = 9

    let y : main.Return = call foo

    let z = call abs 0
    ret
end
""",
                             prime=PRIME)
    scope = ScopedName.from_string

    assert isinstance(program.identifiers.get_by_full_name(scope('main.x')),
                      ReferenceDefinition)
    expected_type = mark_type_resolved(
        parse_type(f'foo.{CodeElementFunction.RETURN_SCOPE}'))
    reference = program.instructions[-1].flow_tracking_data.resolve_reference(
        reference_manager=program.reference_manager, name=scope('main.x'))
    assert simplify_type_system(reference.value)[1] == expected_type

    assert isinstance(program.identifiers.get_by_full_name(scope('main.y')),
                      ReferenceDefinition)
    expected_type = mark_type_resolved(
        parse_type(f'main.{CodeElementFunction.RETURN_SCOPE}'))
    reference = program.instructions[-1].flow_tracking_data.resolve_reference(
        reference_manager=program.reference_manager, name=scope('main.y'))
    assert simplify_type_system(reference.value)[1] == expected_type

    assert isinstance(program.identifiers.get_by_full_name(scope('main.z')),
                      ReferenceDefinition)
    expected_type = parse_type('felt')
    reference = program.instructions[-1].flow_tracking_data.resolve_reference(
        reference_manager=program.reference_manager, name=scope('main.z'))
    assert simplify_type_system(reference.value)[1] == expected_type

    assert program.format() == """\
コード例 #11
0
def test_typed_references():
    program = preprocess_str(code="""
func main():
    struct T:
        member b : T* = 3
    end

    struct Struct:
        member a : T* = 2
    end

    let x : Struct* = cast(ap + 10, Struct*)
    let y : Struct = [x]

    [fp] = x.a
    assert [fp] = x.a.b
    assert [fp] = x.a.b.b

    [fp] = y.a + 1
    ret
end
""",
                             prime=PRIME)
    scope = ScopedName.from_string

    assert isinstance(program.identifiers.get_by_full_name(scope('main.x')),
                      ReferenceDefinition)
    expected_type_x = mark_type_resolved(parse_type('main.Struct*'))
    reference = program.instructions[-1].flow_tracking_data.resolve_reference(
        reference_manager=program.reference_manager, name=scope('main.x'))
    assert simplify_type_system(reference.value)[1] == \
        expected_type_x

    assert isinstance(program.identifiers.get_by_full_name(scope('main.y')),
                      ReferenceDefinition)
    expected_type_y = mark_type_resolved(parse_type('main.Struct'))
    reference = program.instructions[-1].flow_tracking_data.resolve_reference(
        reference_manager=program.reference_manager, name=scope('main.y'))
    assert simplify_type_system(reference.value)[1] == \
        expected_type_y

    assert reference.value.format() == \
        'cast([ap + 10], main.Struct)'
    assert program.format() == """\
コード例 #12
0
 def eval(self, expr: Expression) -> int:
     expr, expr_type = simplify_type_system(expr)
     assert isinstance(expr_type, (TypeFelt, TypePointer)), \
         f"Unable to evaluate expression of type '{expr_type.format()}'."
     res = self.visit(expr)
     assert isinstance(
         res,
         ExprConst), f"Unable to evaluate expression '{expr.format()}'."
     assert self.prime is not None
     return res.val % self.prime
コード例 #13
0
ファイル: tracer_data.py プロジェクト: LexiccLabs/BeamNet
 def eval(self, expr):
     if expr == 'null':
         return ''
     expr, expr_type = simplify_type_system(
         substitute_identifiers(parse_expr(expr), self.get_variable))
     if isinstance(expr_type, TypeStruct):
         raise NotImplementedError('Structs are not supported.')
     res = self.visit(expr)
     if isinstance(res, ExprConst):
         return field_element_repr(res.val, self.tracer_data.program.prime)
     return res.format()
コード例 #14
0
    def eval(
            self, reference_manager: ReferenceManager, flow_tracking_data: FlowTrackingData) -> \
            Expression:
        reference = flow_tracking_data.resolve_reference(
            reference_manager=reference_manager,
            name=self.parent.full_name)
        assert isinstance(flow_tracking_data, FlowTrackingDataActual), \
            'Resolved references can only come from FlowTrackingDataActual.'
        expr, expr_type = simplify_type_system(reference.eval(flow_tracking_data.ap_tracking))
        for member_name in self.member_path.path:
            if isinstance(expr_type, TypeStruct):
                expr_type = expr_type.get_pointer_type()
                # In this case, take the address of the reference value.
                to_addr = lambda expr: ExprAddressOf(expr=expr)
            else:
                to_addr = lambda expr: expr

            if not isinstance(expr_type, TypePointer) or \
                    not isinstance(expr_type.pointee, TypeStruct):
                raise DefinitionError('Member access requires a type of the form Struct*.')

            qualified_member = expr_type.pointee.resolved_scope + member_name
            if qualified_member not in self.identifier_values:
                raise DefinitionError(f"Member '{qualified_member}' was not found.")
            member_definition = self.identifier_values[qualified_member]

            if not isinstance(member_definition, MemberDefinition):
                raise DefinitionError(
                    f"Expected reference offset '{qualified_member}' to be a member, "
                    f'found {member_definition.TYPE}.')
            offset_value = member_definition.offset
            expr_type = member_definition.cairo_type

            expr = ExprDeref(addr=ExprOperator(a=to_addr(expr), op='+', b=ExprConst(offset_value)))

        return ExprCast(
            expr=expr,
            dest_type=expr_type,
        )
コード例 #15
0
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)