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_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(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_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 primary(self): if self.match(TokenType.FALSE): return Literal(False) elif self.match(TokenType.TRUE): return Literal(True) elif self.match(TokenType.NIL): return Literal(None) elif self.match(TokenType.NUMBER, TokenType.STRING): return Literal(self.previous().literal) elif self.match(TokenType.LEFT_PAREN): expr = self.expression() self.consume(TokenType.RIGHT_PAREN, "Expect ')' after expression") else: self.error(self.peek(), "Expect expression")
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_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_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 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_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): 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_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_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_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_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_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 visitBinaryExpr(self, expr_instance): return self.parenthesize(expr_instance.operator.lexeme, expr_instance.left, expr_instance.right) def visitGroupingExpr(self, expr_instance): return self.parenthesize('group', expr_instance.expression); def visitLiteralExpr(self, expr_instance): if expr_instance.value == None: return 'nil' else: return str(expr_instance.value) def visitUnaryExpr(self, expr_instance): return self.parenthesize(expr_instance.operator, expr_instance.right) def parenthesize(self, name, *expressions): output = '' output += f'({name}' for expression in expressions: output += ' ' output += expression.accept(self) output += ')' return output if __name__ == '__main__': # Test to see if AstPrinter does what it should expression = Binary(Unary(Token(TokenType.MINUS, '-', '', 1), Literal(123)), Token(TokenType.STAR, '*', '', 1), Grouping(Literal(45.67))) print(AstPrinter().print(expression))
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_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.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()