def test_hints_unindent(): before = """\ %{ hint1 hint2 %} [fp] = [fp] func f(): %{ if a: b %} [fp] = [fp] ret end """ after = """\ %{ hint1 hint2 %} [fp] = [fp] %{ if a: b %} [fp] = [fp] ret """ program = preprocess_str(code=before, prime=PRIME) assert program.format() == after
def test_labels(): scope = ScopedName.from_string('my.cool.scope') program = preprocess_str(""" const x = 7 a0: [ap] = x; ap++ # Size: 2. [ap] = [fp] + 123 # Size: 2. a1: [ap] = [fp] # Size: 1. jmp rel [fp] # Size: 1. a2: jmp rel x # Size: 2. jmp a3 # Size: 2. jmp a3 if [ap] != 0 # Size: 2. call a3 # Size: 2. a3: """, prime=PRIME, main_scope=scope) program_labels = { name: identifier_definition.pc for name, identifier_definition in program.identifiers.get_scope( scope).identifiers.items() if isinstance(identifier_definition, LabelDefinition) } assert program_labels == {'a0': 0, 'a1': 4, 'a2': 6, 'a3': 14}
def test_reference_type_deduction(): program = preprocess_str(code=""" struct T: const SIZE = 0 end func foo(): let a = cast(0, T***) tempvar b = [a] tempvar c : felt* = [a] let d = [b] let e : felt* = [b] return () end """, prime=PRIME) 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 assert get_reference_type('foo.a').format() == 'T***' assert get_reference_type('foo.b').format() == 'T**' assert get_reference_type('foo.c').format() == 'felt*' assert get_reference_type('foo.d').format() == 'T*' assert get_reference_type('foo.e').format() == 'felt*'
def test_local_variable(): code = """\ struct Mystruct: member a = 0 member b = 1 const SIZE = 2 end func main(): ap += 5 + SIZEOF_LOCALS local x local y : Mystruct local z = x * y.a x = y.a y.b = z local w : Mystruct* = 17 z = w.b ret end func no_locals(): ap += SIZEOF_LOCALS ret end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_func_args(): code = """\ struct T: member s = 0 member t = 1 const SIZE = 2 end func f(x, y : T, z : T*): x = 1; ap++ y.s = 2; ap++ z.t = y.t; ap++ ret end """ program = preprocess_str(code=code, prime=PRIME) reference_x = program.instructions[ -1].flow_tracking_data.resolve_reference( reference_manager=program.reference_manager, name=ScopedName.from_string('f.x')) assert reference_x.value.format() == 'cast([fp + (-6)], felt)' reference_y = program.instructions[ -1].flow_tracking_data.resolve_reference( reference_manager=program.reference_manager, name=ScopedName.from_string('f.y')) assert reference_y.value.format() == 'cast([fp + (-5)], T)' reference_z = program.instructions[ -1].flow_tracking_data.resolve_reference( reference_manager=program.reference_manager, name=ScopedName.from_string('f.z')) assert reference_z.value.format() == 'cast([fp + (-3)], T*)' assert program.format() == """\
def test_compound_expressions_args(): code = """\ func foo(a, b, c, d) -> (x, y): return (a + b, c * c + d) end tempvar x = 5 foo(x + x, x + x * x, x, 3 * x + x * x) """ program = preprocess_str(code=code, prime=PRIME) expected_result = """\ [ap] = [fp + (-4)] * [fp + (-4)]; ap++ # Compute c * c. [ap] = [fp + (-6)] + [fp + (-5)]; ap++ # Push a + b. [ap] = [ap + (-2)] + [fp + (-3)]; ap++ # Push c * c + d. ret [ap] = 5; ap++ [ap] = [ap + (-1)] * [ap + (-1)]; ap++ # Compute x * x. [ap] = 3; ap++ [ap] = [ap + (-1)] * [ap + (-3)]; ap++ # Compute 3 * x. [ap] = [ap + (-4)] * [ap + (-4)]; ap++ # Compute x * x. [ap] = [ap + (-5)] + [ap + (-5)]; ap++ # Push x + x. [ap] = [ap + (-6)] + [ap + (-5)]; ap++ # Push x + x * x. [ap] = [ap + (-7)]; ap++ # Push x. [ap] = [ap + (-5)] + [ap + (-4)]; ap++ # Push 3 * x + x * x. call rel -15 """ assert program.format() == re.sub(r'\s*#.*\n', '\n', expected_result).replace('\n\n', '\n')
def test_references(): program = preprocess_str(code=""" call label1 label1: ret let x = ap + 1 label2: [x] = 1; ap++ [x + 3] = 2; ap++ [x - 2] = 3; ap++ [x - 2] = 3; ap++ jmp label1 if [x] != 0; ap++ jmp label3 if [x] != 0 [x - 2] = 4 [x - 4] = 5 [x - 6] = 6; ap++ [ap] = [ap]; ap++ ap += 4 [x] = 7 call label3 label3: ret let y = ap [y] = 0; ap++ [y] = 0; ap++ """, prime=PRIME) assert program.format() == """\
def test_static_assert(): code = """\ static_assert 3 + fp + 10 == 0 + fp + 13 let x = ap ap += 3 static_assert x + 7 == ap + 4 """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_process_file_scope(): # Verify the good scenario. valid_scope = ScopedName.from_string('some.valid.scope') program = preprocess_str('const x = 4', prime=PRIME, main_scope=valid_scope) module = CairoModule(cairo_file=program, module_name=valid_scope) assert program.identifiers.as_dict() == { valid_scope + 'x': ConstDefinition(4) }
def test_n_locals_used_in_static_assert(): code = """\ func main(): static_assert 3 == SIZEOF_LOCALS + 2 local x ret end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_directives(): program = preprocess_str(code="""\ # This is a comment. %builtins ab cd ef [fp] = [fp] """, prime=PRIME) assert program.builtins == ['ab', 'cd', 'ef'] assert program.format() == """\
def test_reference_flow_converge(): program = preprocess_str(""" if [ap] != 0: tempvar a = 1 else: tempvar a = 2 end assert a = a """, prime=PRIME) assert program.format() == """\
def test_assign_future_label(): code = """\ [ap] = future_label2 - future_label1; ap++ [ap] = future_label1; ap++ future_label1: [ap] = future_label2; ap++ future_label2: [ap] = 8; ap++ """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_hints(): code = """\ %{ hint0 %} [fp] = [fp] %{ hint1 hint2 %} [fp] = [fp] """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == code
def test_function_call(): code = """\ func foo(a, b) -> (c): return (1) end foo(2, 3) foo(2, b=3) let res = foo(..., b=3) res.c = 1 """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_temporary_variable(): code = """\ struct T: member t = 100 end tempvar x = [ap - 1] + [fp - 3] ap += 3 tempvar y : T* = cast(x, T*) ap += 4 [fp] = y.t """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_local_rebinding(): code = """\ func main(): alloc_locals local x = 5 local x = x * x local x = x + x local x = x * x ret end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_compound_expressions_tempvars(): code = """\ tempvar x = [ap - 1] * [ap - 1] + [ap - 1] * [ap - 2] tempvar y = x + x """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\ [ap] = [ap + (-1)] * [ap + (-1)]; ap++ [ap] = [ap + (-2)] * [ap + (-3)]; ap++ [ap] = [ap + (-2)] + [ap + (-1)]; ap++ [ap] = [ap + (-1)] + [ap + (-1)]; ap++ """.replace('\n\n', '\n')
def test_return(): code = """\ func f() -> (a, b, c): return (1, [fp], c=[fp + 1] + 2) return (..., c=3) return (...) end func g(): return () end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_reference_flow_revokes(valid, has0, has1, has2): def0 = 'let ref = [fp]' if has0 else '' def1 = 'let ref = [fp + 1]' if has1 else '' def2 = 'let ref = [fp + 2]' if has2 else '' code = f""" {def0} jmp b if [ap] != 0 a: {def1} jmp c b: {def2} c: [ref] = [fp + 3] """ if valid: preprocess_str(code, prime=PRIME) else: verify_exception(code, """ file:?:?: Reference 'ref' was revoked. [ref] = [fp + 3] ^*^ """)
def test_func_by_value_return(): code = """\ struct T: member s = 0 member t = 1 const SIZE = 2 end func f(s : T) -> (x : T, y : T): let t : T = cast([ap - 100], T) return(x=s, y=t) end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_compound_expressions(): code = """\ assert [ap] = [ap + 1] * [ap + 2] assert 5 = [[ap - 1]] assert [[ap - 1]] = 5 assert [ap - 2] = [[ap - 1] - 5] assert [ap - 2] = [[ap - 1] + 999999] assert [[ap + 5 + 5]] = [ap - 1] assert [ap - 1] = [[[ap + 5 + 5]]] assert [[ap - 1]] = [[ap - 2]] tempvar __fp__ = 100 assert [fp] = fp + [fp + [fp]] let __fp__ = [ap - 1] + [ap - 1] assert [fp] = fp + fp """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\ [ap] = [ap + 1] * [ap + 2] [ap] = [[ap + (-1)]]; ap++ 5 = [ap + (-1)] [ap] = 5; ap++ [[ap + (-2)]] = [ap + (-1)] [ap + (-2)] = [[ap + (-1)] + (-5)] [ap] = [ap + (-1)] + 999999; ap++ [ap + (-3)] = [[ap + (-1)]] [[ap + 10]] = [ap + (-1)] [ap] = [[ap + 10]]; ap++ [ap + (-2)] = [[ap + (-1)]] [ap] = [[ap + (-2)]]; ap++ [[ap + (-2)]] = [ap + (-1)] [ap] = 100; ap++ [ap] = [ap + (-1)] + [fp]; ap++ [ap] = [[ap + (-1)]]; ap++ [fp] = [ap + (-3)] + [ap + (-1)] [ap] = [ap + (-1)] + [ap + (-1)]; ap++ [ap] = [ap + (-2)] + [ap + (-2)]; ap++ [fp] = [ap + (-2)] + [ap + (-1)] """.replace('\n\n', '\n')
def test_function_call_by_value_args(): code = """\ struct T: member s = 0 member t = 1 const SIZE = 2 end func f(x, y : T, z : T): let t : T = cast([ap], T) let res = f(x=2, y=z, z=t) return() end """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_func_named_args(): code = """\ func f(x, y, z): ret end let f_args = cast(ap, f.Args*) f_args.z = 2; ap++ f_args.x = 0; ap++ f_args.y = 1; ap++ static_assert f_args + f.Args.SIZE == ap call f """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_func_args_scope(): code = """\ const x = 1234 [ap] = x; ap++ func f(x, y, z): x = 1; ap++ y = 2; ap++ z = 3; ap++ ret end [ap + 4] = x; ap++ [ap + 5] = f.Args.z; ap++ """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_scope_const(): code = """\ const x = 5 [ap] = x; ap++ func f(): const x = 1234 [ap + 1] = x; ap++ [ap + 2] = f.x; ap++ ret end [ap + 3] = x; ap++ [ap + 4] = f.x; ap++ """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_rebind_reference(): program = preprocess_str(code=""" struct T: member t = 100 end struct S: member s = 1000 end let x : T* = cast(ap + 1, T*) let y = &x.t [cast(x, felt)] = x.t let x : S* = cast(fp - 3, S*) [cast(x, felt)] = x.s [y] = [y] """, prime=PRIME) assert program.format() == """\
def test_func_args_and_rets_scope(): code = """\ const x = 1234 [ap] = x; ap++ func f(x, y, z) -> (a, b, x): x = 1; ap++ y = 2; ap++ [ap] = Return.b; ap++ ret end [ap + 4] = x; ap++ [ap + 5] = f.Args.x; ap++ [ap + 6] = f.Return.x; ap++ """ program = preprocess_str(code=code, prime=PRIME) assert program.format() == """\
def test_label_resolution(): program = preprocess_str(code=""" [ap] = 7; ap++ # Size: 2. loop: [ap] = [ap - 1] + 1 # Size: 2. jmp future_label # Size: 2. jmp future_label if [ap] != 0 # Size: 2. call future_label # Size: 2. [fp] = [fp] # Size: 1. future_label: jmp loop # Size: 2. jmp loop if [ap] != 0 # Size: 2. call loop # Size 2. """, prime=PRIME) assert program.format() == """\
def test_compiler(): program = preprocess_str(code=""" const x = 5 const y = 2 * x [ap] = [[fp + 2 * 3] + ((7 - 1 + y))]; ap++ ap += 4 + %[ 2**10 %] # An empty line with a comment. [ap] = [fp] # This is a comment. let z = ap - 3 [ap] = [ap - x] jmp rel 2 - 3 ret label: jmp label if [fp + 3 + 1] != 0 """, prime=PRIME) assert program.format() == """\