def test_parse_if_else_statement(): expected = nodes.if_( nodes.ref("b"), [nodes.ret(nodes.ref("x"))], [nodes.ret(nodes.ref("y"))], ) _assert_statement_parse(expected, "if b:\n return x\nelse:\n return y")
def method_can_call_method_on_same_instance_defined_later_in_body(): node = nodes.class_("User", [ nodes.func( name="f", args=nodes.args([nodes.arg("self_f")]), body=[ nodes.ret(nodes.call(nodes.attr(nodes.ref("self_f"), "g"), [])) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ), nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[ nodes.ret(nodes.call(nodes.attr(nodes.ref("self_g"), "f"), [])) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ) ]) _infer_class_type(node, ["f", "g"])
def has_unconditional_return_is_true_if_both_branches_of_if_statement_return(): assert returns.has_unconditional_return([ nodes.if_( nodes.int_literal(1), [nodes.ret(nodes.int_literal(1))], [nodes.ret(nodes.int_literal(2))], ) ])
def function_definitions_in_statement_lists_can_be_mutually_recursive(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("f"), [])) ]) _update_context([f, g])
def function_definitions_can_be_mutually_recursive(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("f"), [])) ]) _updated_bindings(nodes.module([f, g]))
def test_condition_is_transformed_using_bool_builtin(self): _assert_transform( nodes.if_( nodes.ref("x"), [nodes.ret(nodes.ref("y"))], [nodes.ret(nodes.ref("z"))], ), cc.if_( cc.call(cc.builtin("bool"), [cc.ref("x")]), [cc.ret(cc.ref("y"))], [cc.ret(cc.ref("z"))], ) )
def test_statements_in_bodies_are_transformed(self): _assert_transform( nodes.try_( [nodes.ret(nodes.ref("x"))], handlers=[nodes.except_(nodes.ref("Exception"), nodes.ref("error"), [nodes.ref("y")])], finally_body=[nodes.ret(nodes.ref("z"))], ), cc.try_( [cc.ret(cc.ref("x"))], handlers=[cc.except_(cc.ref("Exception"), cc.ref("error"), [cc.ref("y")])], finally_body=[cc.ret(cc.ref("z"))], ), )
def exception_handler_targets_cannot_be_accessed_from_nested_function(): target_node = nodes.ref("error") ref_node = nodes.ref("error") body = [nodes.ret(ref_node)] func_node = nodes.func("f", nodes.arguments([]), body, type=None) try_node = nodes.try_( [], handlers=[ nodes.except_(nodes.none(), target_node, [func_node]) ], ) declaration = name_declaration.ExceptionHandlerTargetNode("error") references = References([ (target_node, declaration), (ref_node, declaration), (func_node, name_declaration.VariableDeclarationNode("f")), ]) try: _updated_bindings(try_node, references=references) assert False, "Expected error" except errors.UnboundLocalError as error: assert_equal(ref_node, error.node) assert_is("error", error.name)
def test_parse_with_statement_single_context_manager_with_target(): expected_node = nodes.with_( nodes.ref("x"), nodes.ref("x2"), [nodes.ret(nodes.ref("y"))], ) _assert_statement_parse(expected_node, "with x as x2:\n return y")
def attributes_assigned_in_init_can_be_used_in_methods_when_init_method_is_defined_after_other_method(): init_func = nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign( [nodes.attr(nodes.ref("self_init"), "message")], nodes.str_literal("Hello"), type=nodes.ref("str"), ) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ) node = nodes.class_("User", [ nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[nodes.ret(nodes.attr(nodes.ref("self_g"), "message"))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("str") ), ), init_func, ]) _infer_class_type(node, ["__init__", "g"], [(init_func, ["self_init"])])
def function_definitions_in_statement_lists_can_be_defined_out_of_order(): f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(nodes.ref("g"), [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) _updated_bindings(nodes.module([f, g]))
def function_definitions_in_statement_lists_are_type_checked_even_if_not_invoked(): node = nodes.func("f", type=None, args=nodes.Arguments([]), body=[nodes.ret(nodes.int_literal(42))]) try: _update_context([node]) assert False, "Expected error" except errors.UnexpectedValueTypeError as error: assert_equal(types.int_type, error.actual) assert_equal(types.none_type, error.expected)
def has_unconditional_return_is_false_if_only_false_branch_of_if_statement_returns(): assert not returns.has_unconditional_return([ nodes.if_( nodes.int_literal(1), [], [nodes.ret(nodes.int_literal(2))], ) ])
def test_condition_is_not_transformed_using_bool_builtin_if_already_a_bool(self): condition_node = nodes.ref("x") _assert_transform( nodes.if_( condition_node, [nodes.ret(nodes.ref("y"))], [nodes.ret(nodes.ref("z"))], ), cc.if_( cc.ref("x"), [cc.ret(cc.ref("y"))], [cc.ret(cc.ref("z"))], ), type_lookup=[ (condition_node, types.bool_type), ], )
def test_parse_for_loop_with_else_body(): expected = nodes.for_( nodes.ref("x"), nodes.ref("xs"), [], [nodes.ret(nodes.ref("x"))], ) _assert_statement_parse(expected, "for x in xs:\n pass\nelse:\n return x")
def function_adds_arguments_to_context(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) assert_equal(types.func([types.int_type], types.int_type), _infer_func_type(node))
def error_if_type_signature_is_missing_from_function_with_args(): args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=None) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("signature is missing from function definition", str(error))
def type_mismatch_if_return_type_is_incorrect(): return_node = nodes.ret(nodes.str_literal("!")) node = nodes.func( "f", args=nodes.arguments([]), body=[return_node], type=nodes.signature(returns=nodes.ref("int")), ) assert_type_mismatch(lambda: _infer_func_type(node), expected=types.int_type, actual=types.str_type, node=return_node)
def test_transform_while_loop_with_else_branch(self): _assert_transform( nodes.while_( nodes.ref("x"), [nodes.ret(nodes.ref("y"))], [nodes.ret(nodes.ref("z"))] ), """ var __nope_u_normal_exit0 = False while True: if not $builtins.bool(x): __nope_u_normal_exit0 = True break return y if __nope_u_normal_exit0: return z """ )
def function_definitions_bodies_can_access_variables_from_outer_scope(): args = nodes.arguments([]) ref = nodes.ref("x") body = [nodes.ret(ref)] node = nodes.func("f", args, body, type=None) declarations = _create_declarations(["x", "f"]) references = resolve(node, declarations) assert_is(declarations.declaration("x"), references.referenced_declaration(ref))
def can_infer_type_of_function_with_no_args_and_return_annotation(): node = nodes.func( "f", args=nodes.arguments([]), body=[ nodes.ret(nodes.int_literal(4)) ], type=nodes.signature(returns=nodes.ref("int")), ) assert_equal(types.func([], types.int_type), _infer_func_type(node))
def method_can_reference_later_function_if_class_is_not_used_in_the_interim(): g_ref = nodes.ref("g") f = nodes.func("f", type=None, args=nodes.Arguments([]), body=[ nodes.ret(nodes.call(g_ref, [])) ]) g = nodes.func("g", type=None, args=nodes.Arguments([]), body=[]) _updated_bindings(nodes.module([ nodes.class_("a", [f]), g, ]))
def test_transform_while_loop(self): _assert_transform( nodes.while_( nodes.ref("x"), [nodes.ret(nodes.ref("y"))], ), cc.while_( cc.call(cc.builtin("bool"), [cc.ref("x")]), [cc.ret(cc.ref("y"))], ) )
def class_definition_functions_ignore_class_scope_when_resolving_references(): ref = nodes.ref("x") node = nodes.class_("User", [ nodes.assign([nodes.ref("x")], nodes.none()), nodes.func("f", nodes.args([]), [nodes.ret(ref)], type=None), ]) declarations = _create_declarations(["x", "User"]) references = resolve(node, declarations) assert_is(declarations.declaration("x"), references.referenced_declaration(ref))
def function_definitions_adds_argument_names_to_body_context(): arg = nodes.argument("x") args = nodes.arguments([arg]) ref = nodes.ref("x") body = [nodes.ret(ref)] node = nodes.func("f", args, body, type=None) declarations = _create_declarations(["f"]) references = resolve(node, declarations) assert not declarations.is_declared("x") assert_is(references.referenced_declaration(arg), references.referenced_declaration(ref))
def test_variables_are_declared(self): _assert_transform( nodes.func("f", nodes.args([]), [ nodes.assign([nodes.ref("x")], nodes.ref("y")), nodes.ret(nodes.ref("value")), ], type=None), cc.func("f", [], [ cc.declare("x"), cc.assign(cc.ref("x"), cc.ref("y")), cc.ret(cc.ref("value")), ]), )
def function_definitions_arguments_shadow_variables_of_same_name_in_outer_scope(): arg = nodes.argument("x") args = nodes.arguments([arg]) ref = nodes.ref("x") body = [nodes.ret(ref)] node = nodes.func("f", args, body, type=None) declarations = _create_declarations(["x", "f"]) references = resolve(node, declarations) assert_is(references.referenced_declaration(arg), references.referenced_declaration(ref)) assert_is_not(declarations.declaration("x"), references.referenced_declaration(ref))
def error_if_type_signature_has_different_number_of_args_from_def(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int")), nodes.signature_arg(nodes.ref("int"))], returns=nodes.ref("int") ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("args length mismatch: def has 1, signature has 2", str(error))
def error_if_type_signature_argument_is_optional_but_def_argument_is_not_optional(): signature = nodes.signature( args=[nodes.signature_arg(nodes.ref("int"), optional=True)], returns=nodes.type_union([nodes.ref("int"), nodes.ref("none")]) ) args = nodes.arguments([nodes.argument("x")]) body = [nodes.ret(nodes.ref("x"))] node = nodes.func("f", args, body, type=signature) try: _infer_func_type(node) assert False, "Expected error" except errors.ArgumentsError as error: assert_equal("optional argument 'x' must have default value", str(error))
def test_parse_with_statement_with_multiple_context_managers(): expected_node = nodes.with_( nodes.ref("x"), nodes.ref("x2"), [ nodes.with_( nodes.ref("y"), None, [nodes.ret(nodes.ref("z"))], ) ] ) _assert_statement_parse(expected_node, "with x as x2, y:\n return z")