class ExpressionTest(unittest.TestCase): def setUp(self): self._rules = TestingRules() self._registry = Registry() def test_variable_repr(self): self.assertEqual('Variable(foo)', repr(Variable('foo'))) def test_variable(self): scoped_id = 'var_foo_1' self._registry.push_new_scope({'foo': (scoped_id, False)}) v = Variable('foo') v_id = v.add_to_rules(self._rules, self._registry) self.assertEqual(v_id, scoped_id) self.assertEqual([], self._rules.instance_of_calls) def test_polymorphic_variable(self): scoped_id = 'var_foo_1' self._registry.push_new_scope({'foo': (scoped_id, True)}) v = Variable('foo') v_id = v.add_to_rules(self._rules, self._registry) self.assertIn((v_id, scoped_id), self._rules.instance_of_calls) def test_literal_repr(self): self.assertEqual('Literal(Int, 123)', repr(Literal('Int', 123))) def test_literal(self): l = Literal('Int', 123) l_id = l.add_to_rules(self._rules, self._registry) self.assertTrue(l_id > 0) self.assertEqual([(l_id, 'Int')], self._rules.specify_calls) def test_typed_expression(self): l = Literal('Int', 123) te = TypedExpression('Num', l) self.assertEqual('TypedExpression(Num, Literal(Int, 123))', repr(te)) te_id = te.add_to_rules(self._rules, self._registry) l_id = self._registry.get_id_for(l) self.assertNotEqual(l_id, te_id) self.assertSetEqual( set([(te_id, 'Num'), (l_id, 'Int')]), set(self._rules.specify_calls) ) def test_application(self): scoped_id = 'var_times2_1' self._registry.push_new_scope({'times2': (scoped_id, True)}) v = Variable('times2') l = Literal('Int', 123) a = Application(v, [l]) a_id = a.add_to_rules(self._rules, self._registry) v_id = self._registry.get_id_for(v) l_id = self._registry.get_id_for(l) self.assertIn((v_id, scoped_id), self._rules.instance_of_calls) self.assertIn((v_id, ('Fn_1', l_id, a_id)), self._rules.specify_calls) def test_simple_let(self): l1 = Literal('Int', 123) l2 = Literal('Int', 456) lt = Let([('x', l1)], l2) lt_id = lt.add_to_rules(self._rules, self._registry) l1_id = self._registry.get_id_for(l1) l2_id = self._registry.get_id_for(l2) # TODO: the test is dependent on order for the name of var_x_1 self.assertIn(('var_x_2', l1_id), self._rules.equal_calls) self.assertIn((lt_id, l2_id), self._rules.equal_calls) self.assertEqual([], self._rules.instance_of_calls) self.assertIn((l1_id, 'Int'), self._rules.specify_calls) self.assertIn((l2_id, 'Int'), self._rules.specify_calls) def _has_call_matching(self, test, calls): return any(test(call) for call in calls) def _has_equal_call_matching(self, test): return self._has_call_matching(test, self._rules.equal_calls) def test_let(self): l = Literal('Int', 123) var_x = Variable('x') var_y = Variable('y') lt = Let([('x', var_y), ('y', l)], var_x) lt_id = lt.add_to_rules(self._rules, self._registry) l_id = self._registry.get_id_for(l) var_x_id = self._registry.get_id_for(var_x) var_y_id = self._registry.get_id_for(var_y) self.assertIn((lt_id, var_x_id), self._rules.equal_calls) self.assertIn(('var_x_2', var_y_id), self._rules.equal_calls) self.assertIn(('var_y_3', l_id), self._rules.equal_calls) def test_simple_lambda_expression(self): lit = Literal('Int', 123) lm = Lambda(['x'], lit) # The `x` argument is unused lm_id = lm.add_to_rules(self._rules, self._registry) lit_id = self._registry.get_id_for(lit) # TODO: test is dependant on order for the name of var_x_2 self.assertIn( (1, ('Fn_1', 'var_x_2', lit_id)), self._rules.specify_calls ) self.assertIn((lit_id, 'Int'), self._rules.specify_calls) def test_lambda_exprssion(self): lm = Lambda(['x'], Variable('x')) lmid = lm.add_to_rules(self._rules, self._registry) self.assertEqual( [(1, ('Fn_1', 'var_x_2', 'var_x_2'))], self._rules.specify_calls ) def test_let_with_lambda(self): lm = Lambda(['x'], Variable('x')) var_id = Variable('id') app = Application(var_id, [Literal('Int', 123)]) lt = Let([('id', lm)], app) lt_id = lt.add_to_rules(self._rules, self._registry) app_id = self._registry.get_id_for(app) self.assertIn((lt_id, app_id), self._rules.equal_calls)
def setUp(self): self._rules = TestingRules() self._registry = Registry()
def setUp(self): self._rules = Rules() self._registry = Registry()
class InferenceTest(unittest.TestCase): def setUp(self): self._rules = Rules() self._registry = Registry() def test_nonpolymorphic_variable(self): self._registry.push_new_scope({'foo': ('var_foo_1', False)}) v = Variable('foo') v_id = v.add_to_rules(self._rules, self._registry) self.assertEqual(Result({}, {}), self._rules.infer()) def test_polymorphic_variable(self): self._registry.push_new_scope({'foo': ('var_foo_1', True)}) v = Variable('foo') v_id = v.add_to_rules(self._rules, self._registry) self.assertEqual(Result({}, {}), self._rules.infer()) def test_literal(self): l = Literal('Int', 123) l_id = l.add_to_rules(self._rules, self._registry) self.assertEqual(Result({l_id: 'Int'}, {}), self._rules.infer()) def test_typed_expression_mismatch(self): te = TypedExpression('String', Literal('Int', 123)) te_id = te.add_to_rules(self._rules, self._registry) with self.assertRaises(InferenceError): self._rules.infer() def test_typed_expression_match(self): lit = Literal('Int', 123) te = TypedExpression('Int', lit) te_id = te.add_to_rules(self._rules, self._registry) lit_id = self._registry.get_id_for(lit) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(te_id)) self.assertEqual('Int', result.get_type_by_id(lit_id)) def test_application(self): self._registry.push_new_scope({'times2': ('var_times2_1', True)}) v = Variable('times2') l = Literal('Int', 123) a = Application(v, [l]) a_id = a.add_to_rules(self._rules, self._registry) v_id = self._registry.get_id_for(v) l_id = self._registry.get_id_for(l) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(l_id)) self.assertEqual(None, result.get_type_by_id(a_id)) def test_let(self): l = Literal('Int', 123) lt = Let([('x', l)], Variable('x')) lt_id = lt.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(lt_id)) def test_multi_let(self): l = Literal('Int', 123) lt = Let([('x', Variable('y')), ('y', l)], Variable('x')) lt_id = lt.add_to_rules(self._rules, self._registry) l_id = self._registry.get_id_for(l) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(lt_id)) def test_lambda_exprssion(self): lm = Lambda(['x'], Variable('x')) lmid = lm.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual( ('Fn_1', 'var_x_2', 'var_x_2'), result.get_type_by_id(lmid) ) def test_let_with_lambda(self): ''' ML code: let id = \\x -> x in id 'foo' ''' lm = Lambda(['x'], Variable('x')) var_id = Variable('id') app = Application(var_id, [Literal('String', 'foo')]) lt = Let([('id', lm)], app) lt_id = lt.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual('String', result.get_type_by_id(lt_id)) def test_polymorphism(self): ''' ML code: let id = \\x -> x in (id id) 123 ''' lm = Lambda(['x'], Variable('x')) app1 = Application(Variable('id'), [Variable('id')]) app2 = Application(app1, [Literal('Int', 123)]) lt = Let([('id', lm)], app2) lt_id = lt.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(lt_id)) def test_if_statement(self): test = Literal('Bool', True) if_case = Literal('Int', 123) else_case = Literal('Int', 456) if_block = If(test, if_case, else_case) if_id = if_block.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual('Int', result.get_type_by_id(if_id)) def test_if_statement_requires_branches_to_equal(self): test = Literal('Bool', True) if_case = Literal('Int', 123) else_case = Literal('Float', 456) if_block = If(test, if_case, else_case) if_id = if_block.add_to_rules(self._rules, self._registry) with self.assertRaises(InferenceError): self._rules.infer() def test_if_statement_requires_test_to_be_boolean(self): test = Literal('String', 'not a boolean') if_case = Literal('Int', 123) else_case = Literal('Int', 456) if_block = If(test, if_case, else_case) if_id = if_block.add_to_rules(self._rules, self._registry) with self.assertRaises(InferenceError): self._rules.infer() def test_mutual_recursion(self): ''' Equivalent ML: let-rec f = if True then 123 else g g = f in f ''' test = Literal('Bool', True) if_case = Literal('Int', 123) else_case = Application(Variable('g'), []) if_block = If(test, if_case, else_case) f_func = Lambda([], if_block) g_body = Application(Variable('f'), []) g_func = Lambda([], g_body) let_body = Variable('f') let_expr = Let([('f', f_func), ('g', g_func)], let_body) let_id = let_expr.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual(('Fn_0', 'Int'), result.get_full_type_by_id(let_id)) def test_generic_mutual_recursion(self): ''' Equivalent ML: let-rec f x = if True then x else g x g y = f y in g ''' test = Literal('Bool', True) if_case = Variable('x') else_case = Application(Variable('g'), [Variable('x')]) if_block = If(test, if_case, else_case) f_func = Lambda(['x'], if_block) g_body = Application(Variable('f'), [Variable('y')]) g_func = Lambda(['y'], g_body) let_body = Variable('f') let_expr = Let([('f', f_func), ('g', g_func)], let_body) let_id = let_expr.add_to_rules(self._rules, self._registry) result = self._rules.infer() self.assertEqual(('Fn_1', 'a0', 'a0'), result.get_full_type_by_id(let_id))
def test_add_and_get_from_registry(self): registry = Registry() id1 = registry.add_to_registry('x') id2 = registry.add_to_registry('y') self.assertEqual('x', registry.get_registered()[id1]) self.assertEqual('y', registry.get_registered()[id2])
def test_catches_duplicate_use_of_ids(self): registry = Registry() registry.register_for_id(1, 'x') with self.assertRaises(Exception): registry.register_for_id(1, 'x')
def test_generates_new_ids(self): registry = Registry() self.assertEqual([1, 2, 3, 4], [registry.generate_new_id() for _ in range(4)])