def test_access_modifier_changes_function_access_level(self): funcdeclaration = FuncDeclaration() modifier = AccessModifier() tree = SemanticParseTree(funcdeclaration, [modifier]) tree.annotate() self.assertEqual(funcdeclaration.annotations["access"], modifier.annotations["access"])
def test_block_creates_child_scope(self): scope = Scope() block = Block() subtree = SemanticParseTree(block) tree = SemanticParseTree("parent", [subtree]) block.annotate(scope, subtree) self.assertEqual(scope, scope.next_scope.parent) tree._run_deferred() self.assertEqual(scope, scope.next_scope)
def test_declaration_adds_variable_to_scope_later(self): scope = Scope() dec = Declaration(Int) subtree = SemanticParseTree(dec) tree = SemanticParseTree(Assignment(None), [subtree]) dec.annotate(scope, subtree) self.assertEqual(len(scope.variables), 0) tree._run_deferred() self.assertEqual(len(scope.variables), 1)
def test_blocks_indent_in_tree(self): myeol = EOL() tree = SemanticParseTree(Nonterminal("foo"), [ SemanticParseTree(Block()), SemanticParseTree(Nonterminal("foo"), [SemanticParseTree(myeol)]) ]) tree.annotate(scope=Scope()) self.assertEqual(tree.string(), "\n\t")
def test_enum_in_scope(self): outer_scope = Scope() tree = SemanticParseTree( EnumDeclaration(), [Enum(), SemanticParseTree(case_statements, [ Case(), Case(), ])]) tree.annotate(scope=outer_scope) self.assertEqual(len(outer_scope.children), 1) enumscope = outer_scope.children[0] enumtype = enumscope.value self.assertEqual(len(enumtype.cases), 2) self.assertIn(enumtype, outer_scope.accessible_types())
def writetests(file): from swiftsmith.expression import FunctionCall from swiftsmith.semantics import SemanticParseTree f.write(f"\n// Generated by Swiftsmith {version}\n\n") modulename = args.output.split("/")[-1] f.write(f"import {modulename}A\n") f.write(f"import {modulename}B\n\n") for _ in range(50): fname, ftype = rootscope.choose_function( at_least=swiftsmith.AccessLevel.public) call = SemanticParseTree(FunctionCall(fname, ftype), []) call.annotate() # TODO: handle prefix, infix, and postfix functions f.write( f"assert(ModuleA.{call.string()}.hashValue == ModuleB.{call.string()}.hashValue)\n" )
def test_function_parameters_in_scope(self): outer_scope = Scope() outer_scope.add_child(Scope(None, Int)) function = Function() interceptor = Interceptor(None) tree = SemanticParseTree( FuncDeclaration(), [function, SemanticParseTree(block, [Block(), interceptor])]) def testclosure(inner_scope: Scope, context): arguments = function.annotations["arguments"] self.assertGreater(len(arguments), 0, "useless test") for argument in arguments: self.assertIsNotNone( inner_scope.choose_variable(name=argument)) interceptor.testclosure = testclosure tree.annotate(scope=outer_scope)
def test_deferred_actions_run_in_insertion_order(self): a = SemanticParseTree("foo") x = 0 def closure1(): nonlocal x x += 1 a.defer(closure1) def closure2(): nonlocal x x *= 2 a.defer(closure2) # If closure1 runs first, then x == (0+1)*2 which is 2. # If closure2 runs first, then x == (0*2)+1 which is 1. self.assertEqual(x, 0) a._run_deferred() self.assertEqual(x, 2)
def test_deferred_actions_run_later(self): a = SemanticParseTree("foo") x = 0 def closure(): nonlocal x x += 1 a.defer(closure) self.assertEqual(x, 0) a._run_deferred() self.assertEqual(x, 1)
def test_static_function_declared_static(self): T = DataType("T") scope = Scope(None, T) funcdeclaration = FuncDeclaration(binding=Binding.static) tree = SemanticParseTree(funcdeclaration, [ BindingModifier(), Function(), SemanticParseTree(block, [Block()]) ]) tree.annotate(scope=scope) declaration = tree.string() self.assertTrue(declaration.startswith("static"))
def test_failable_initializer(self): A = EnumType("A") A.add_case("b", []) tree = SemanticParseTree(statement, [ SemanticParseTree(EnumDeclaration(), [ "enum ", Enum(), " {", EOL(), SemanticParseTree(case_statements, ["case ", Case()]), EOL(), "}" ]), Expression(A) ]) tree.annotate() failable_initializer(tree) self.assertEqual( "enum A {\n\tinit?() { self = A.b }\n\n\tcase b\n}.init()!", tree.string())
def test_unnecessary_addition(self): tree = SemanticParseTree(Expression(Int)) tree.annotate() original = tree.string() unnecessary_addition(tree) self.assertEqual(tree.string(), f"({original}) + 0")
def test_unnecessary_multiplication_no_int_expr(self): tree = SemanticParseTree("asdf") original = tree.string() unnecessary_multiplication(tree) self.assertEqual(tree.string(), original)
def test_expression_infers_type_from_ancestors(self): class A(SemanticNonterminal): def __init__(self, datatype): self.datatype = datatype def annotate(self, scope, context): pass exp = Expression(None) tree = SemanticParseTree(A(Int), [exp]) tree.annotate() self.assertEqual(exp.datatype, Int) exp = Expression(None) tree = SemanticParseTree( A(Bool), [SemanticParseTree(Nonterminal("foo"), [exp])]) tree.annotate() self.assertEqual(exp.datatype, Bool) exp = Expression(None) tree = SemanticParseTree(A(Int), [ SemanticParseTree(Nonterminal("foo"), [SemanticParseTree(Nonterminal("foo"), [exp])]) ]) tree.annotate() self.assertEqual(exp.datatype, Int)
def test_bool_annotated_by_tree(self): tree = SemanticParseTree(Value(Bool)) tree.annotate() self.assertIn(tree.string(), ["true", "false"])
def test_variable_annotated_by_tree(self): scope = Scope() scope.declare("foo", Int, False) tree = SemanticParseTree(Variable(Int)) tree.annotate(scope=scope) self.assertEqual(tree.string(), "foo")