def test_scope_failures(): verify_exception(""" func f(): const x = 5 ret end func g(): [ap] = x; ap++ ret end """, """ file:?:?: Unknown identifier 'x'. [ap] = x; ap++ ^ """) verify_exception(""" func f(): label: ret end func g(): call label ret end """, """ file:?:?: Unknown identifier 'label'. call label ^***^ """)
def test_func_args_failures(): verify_exception(""" func f(x): [ap] = [x] + 1 end """, """ file:?:?: While expanding the reference 'x' in: [ap] = [x] + 1 ^ file:?:?: Expected a register. Found: [fp + (-3)]. func f(x): ^ Preprocessed instruction: [ap] = [[fp + (-3)]] + 1 """, exc_type=InstructionBuilderError) verify_exception( """ func f(x): g(x=x) end func g(x): ret end """, """ file:?:?: The called function must be defined before the call site. g(x=x) ^****^ """)
def test_error_scope_redefinition(): verify_exception(""" from a import b from a.b import c """, """ Scope 'a.b' collides with a different identifier of type 'const'. """, files={'a': 'const b = 0', 'a.b': 'const c = 1'})
def test_func_by_value_args_failures(test_line, expected_type, actual_type, arrow): verify_exception( f""" struct T: member s = 0 member t = 1 const SIZE = 2 end struct S: member s = 0 member t = 1 const SIZE = 2 end func f(x, y : {expected_type}): local t : {actual_type} alloc_locals {test_line} ret end """, f""" file:?:?: Expected expression of type '{expected_type}', got '{actual_type}'. {test_line} {arrow} """)
def test_tempvar_modifier_failures(): verify_exception( """ func main(): tempvar local x = 5 end """, """ file:?:?: Unexpected modifier 'local'. tempvar local x = 5 ^***^ """) verify_exception(""" tempvar x = [ap - 1] + [fp - 3] [x] = [[ap]] """, """ file:?:?: While expanding the reference 'x' in: [x] = [[ap]] ^ file:?:?: Expected a register. Found: [ap + (-1)]. tempvar x = [ap - 1] + [fp - 3] ^ Preprocessed instruction: [[ap + (-1)]] = [[ap]] """, exc_type=InstructionBuilderError)
def test_hints_failures(): verify_exception(""" %{ hint %} """, """ file:?:?: Found a hint at the end of a code block. Hints must be followed by an instruction. %{ ^^ """) verify_exception(""" func f(): %{ hint %} end [ap] = 1 """, """ file:?:?: Found a hint at the end of a code block. Hints must be followed by an instruction. %{ ^^ """) verify_exception(""" %{ hint1 %} %{ hint2 %} """, """ file:?:?: Only one hint is allowed per instruction. %{ ^^ """) verify_exception(""" [fp] = [fp] %{ hint %} label: [fp] = [fp] """, """ file:?:?: Hints before labels are not allowed. %{ ^^ """) verify_exception(""" [fp] = [fp] %{ hint %} const x = 5 [fp] = [fp] """, """ file:?:?: Hints before constant definitions are not allowed. %{ ^^ """)
def test_builtins_failures(): verify_exception(""" %builtins a %builtins b """, """ file:?:?: Redefinition of builtins directive. %builtins b ^*********^ """)
def test_directives_failures(): verify_exception(""" [fp] = [fp] %builtins ab cd ef """, """ file:?:?: Directives must appear at the top of the file. %builtins ab cd ef ^****************^ """)
def test_import_errors(): # Inaccessible import. verify_exception(""" from foo import bar """, """ file:?:?: Could not load module 'foo'. Error: 'foo' from foo import bar ^*^ """, files={}, exc_type=LocationError) # Ignoring aliasing. verify_exception(""" from foo import bar as notbar [ap] = bar """, """ file:?:?: Unknown identifier 'bar'. [ap] = bar ^*^ """, files={'foo': 'const bar = 3'}) # Identifier redefinition. verify_exception(""" const bar = 0 from foo import bar """, """ file:?:?: Redefinition of 'bar'. from foo import bar ^*^ """, files={'foo': 'const bar=0'}) verify_exception(""" const lambda = 0 from foo import bar as lambda """, """ file:?:?: Redefinition of 'lambda'. from foo import bar as lambda ^****^ """, files={'foo': 'const bar=0'}) verify_exception('from foo import bar', """ \ file:?:?: Scope 'foo' does not include identifier 'bar'. from foo import bar ^*^ """, files={'foo': ''})
def test_ellipsis_failures(): # Ellipsis in a wrong place. verify_exception( """ func f() -> (a, b, c): return (1, ...) end """, """ file:?:?: Ellipsis ("...") can only be used at the beginning of the list. return (1, ...) ^*^ """) # Wrong place, with ellipsis. verify_exception( """ func f() -> (a, b, c): return (..., a=1, c=[fp] + 1) end """, """ file:?:?: Expected named arg 'b' found 'a'. return (..., a=1, c=[fp] + 1) ^ """) # Missing arg, with ellipsis. verify_exception( """ func f() -> (a, b, c): return (..., a=1, b=[fp] + 1) end """, """ file:?:?: Expected named arg 'b' found 'a'. return (..., a=1, b=[fp] + 1) ^ """) # Wrong place, without ellipsis. verify_exception( """ func f() -> (a, b, c): return (a=1, c=[fp] + 1, b=0) end """, """ file:?:?: Expected named arg 'b' found 'c'. return (a=1, c=[fp] + 1, b=0) ^ """) # Compound expressions with ellipsis. verify_exception( """ func f(x, y) -> (a, b, c, d, e): return (..., c=x + y, d=(x + y) * 2, e=x * y) end """, """ file:?:?: Compound expressions cannot be used with an ellipsis ("..."). return (..., c=x + y, d=(x + y) * 2, e=x * y) ^*********^ """)
def test_member_def_failure(): verify_exception(""" struct T: member t = ap + 5 end """, """ file:?:?: Expected a constant expression. member t = ap + 5 ^****^ """)
def test_rebind_reference_failures(): verify_exception(""" let x = cast(ap, felt*) let x = cast(ap, felt**) """, """ file:?:?: Reference rebinding must preserve the reference type. Previous type: 'felt*', \ new type: 'felt**'. let x = cast(ap, felt**) ^ """)
def test_bad_struct(): verify_exception(""" struct T: return() end """, """ file:?:?: Unexpected statement inside a struct definition. return() ^******^ """)
def test_redefinition_failures(): verify_exception( """ name: local name = [ap] """, """ file:?:?: Redefinition of 'test_scope.name'. local name = [ap] ^**^ """)
def test_member_def_modifier_failure(): verify_exception(""" struct T: member local t = 17 end """, """ file:?:?: Unexpected modifier 'local'. member local t = 17 ^***^ """)
def test_references_revoked(revoking_instruction): verify_exception(f""" label: let x = ap {revoking_instruction} [x] = 0 """, """ file:?:?: Reference 'x' was revoked. [x] = 0 ^ """)
def test_local_variable_modifier_failures(): verify_exception( """ func main(): local local x end """, """ file:?:?: Unexpected modifier 'local'. local local x ^***^ """)
def test_unpacking_modifier_failure(): verify_exception(""" func foo() -> (a, b): ret end let (a, local b) = foo() """, """ file:?:?: Unexpected modifier 'local'. let (a, local b) = foo() ^***^ """)
def test_temporary_variable_failures(): verify_exception(""" struct T: member t = 100 end tempvar x : T = 0 """, """ file:?:?: tempvar type annotation must be 'felt' or a pointer. tempvar x : T = 0 ^ """)
def test_local_variable_failures(): verify_exception( """ func main(SIZEOF_LOCALS): static_assert SIZEOF_LOCALS == SIZEOF_LOCALS local x end """, """ file:?:?: The name 'SIZEOF_LOCALS' is reserved and cannot be used as an argument name. func main(SIZEOF_LOCALS): ^***********^ """) verify_exception( """ func main(): local x end """, """ file:?:?: A function with local variables must use alloc_locals. local x ^*****^ """) verify_exception( """ func main(): alloc_locals local x = x + x end """, """ file:?:?: Identifier 'x' referenced before definition. local x = x + x ^ """) for inst in ['tempvar a = 0', 'ret', 'ap += [ap]']: verify_exception( f""" func main(): {inst} alloc_locals end """, """ file:?:?: alloc_locals must be used before any instruction that changes the ap register. alloc_locals ^**********^ """) verify_exception( f""" alloc_locals """, """ file:?:?: alloc_locals cannot be used outside of a function. alloc_locals ^**********^ """)
def test_func_failures(last_statement): verify_exception(f""" func f(x): body: ret {last_statement} end """, """ file:?:?: Function must end with a return instruction or a jump. func f(x): ^ """)
def test_compound_expressions_failures(): verify_exception( """\ assert [ap + [ap]] = [ap] """, """ file:?:?: ap may only be used in an expression of the form [ap + <const>]. assert [ap + [ap]] = [ap] ^^ """) verify_exception( """\ assert [[ap]] = ap """, """ file:?:?: ap may only be used in an expression of the form [ap + <const>]. assert [[ap]] = ap ^^ """) verify_exception( """\ assert [[fp]] = fp """, """ file:?:?: Using the value of fp directly, requires defining a variable named __fp__. assert [[fp]] = fp ^^ """) verify_exception( """\ assert [ap] = [ap + 32768] # Offset is out of bounds. """, """ file:?:?: ap may only be used in an expression of the form [ap + <const>]. assert [ap] = [ap + 32768] # Offset is out of bounds. ^^ """)
def test_return_failures(): # Named after positional. verify_exception(""" func f() -> (a, b, c): return (a=1, b=1, [fp] + 1) end """, """ file:?:?: Positional arguments must not appear after named arguments. return (a=1, b=1, [fp] + 1) ^******^ """) # Wrong num. verify_exception(""" func f() -> (a, b, c, d): return (1, [fp] + 1) end """, """ file:?:?: Expected exactly 4 expressions, got 2. return (1, [fp] + 1) ^******************^ """) # Wrong num. verify_exception(""" func f() -> (a, b): return () end """, """ file:?:?: Expected exactly 2 expressions, got 0. return () ^*******^ """) # Unknown name. verify_exception(""" func f() -> (a, b, c): return (a=1, d=1, [fp] + 1) end """, """ file:?:?: Expected named arg 'b' found 'd'. return (a=1, d=1, [fp] + 1) ^ """) # Not in func. verify_exception(""" return (a=1, [fp] + 1) """, """ file:?:?: return cannot be used outside of a function. return (a=1, [fp] + 1) ^********************^ """)
def test_redefinition_failures(): verify_exception( """ name: const name = 0 """, """ file:?:?: Redefinition of 'name'. const name = 0 ^**^ """) verify_exception( """ const name = 0 let name = ap """, """ file:?:?: Redefinition of 'name'. let name = ap ^**^ """) verify_exception(""" let name = ap name: """, """ file:?:?: Redefinition of 'name'. name: ^**^ """) verify_exception( """ func f(name, x, name): [ap + name] = 1 [ap + x] = 2 end """, """ file:?:?: Redefinition of 'f.Args.name'. func f(name, x, name): ^**^ """) verify_exception( """ func f() -> (name, x, name): [ap + name] = 1 [ap + x] = 2 end """, """ file:?:?: Redefinition of 'f.Return.name'. func f() -> (name, x, name): ^**^ """)
def test_func_args_failures(): verify_exception(""" func f(x): [ap] = [x] + 1 end """, """ file:?:?: While expanding the reference 'x' in: [ap] = [x] + 1 ^ file:?:?: Expected a register. Found: [fp + (-3)]. func f(x): ^ Preprocessed instruction: [ap] = [[fp + (-3)]] + 1 """, exc_type=InstructionBuilderError)
def test_func_by_value_discontinuous_struct_failures(): verify_exception(""" struct T: member s = 0 member t = 2 const SIZE = 3 end func f(x, y : T): f(1, y=y) ret end """, """ file:?:?: Discontinuous structs are not supported. f(1, y=y) ^ """)
def test_func_named_args_failures(): verify_exception(""" func f(x, y, z): ret end let f_args = cast(ap, f.Args*) f_args.z = 2; ap++ f_args.x = 0; ap++ static_assert f_args + f.Args.SIZE == ap call f """, """ file:?:?: Static assert failed: ap + 1 != ap. static_assert f_args + f.Args.SIZE == ap ^**************************************^ """)
def test_nested_function_failure(): verify_exception(""" func foo(): func bar(): return() end return() end """, """ file:?:?: Nested functions are not supported. func bar(): ^*^ Outer function was defined here: file:?:? func foo(): ^*^ """)
def test_labels_failures(): verify_exception(""" jmp x.y.z """, """ file:?:?: Unknown identifier 'x'. jmp x.y.z ^***^ """) verify_exception(""" const x = 0 jmp x """, """ file:?:?: Expected a label name. Identifier 'x' is of type const. jmp x ^ """)
def test_namespace_inside_function_failure(): verify_exception(""" func foo(): namespace MyNamespace: end return() end """, """ file:?:?: Cannot define a namespace inside a function. namespace MyNamespace: ^*********^ Outer function was defined here: file:?:? func foo(): ^*^ """)