def test_expr_comma_seq(self): self._assert_parse_fails("", "expr_comma_seq") parse.quiet_parse("1", "expr_comma_seq").should.equal([self.one]) parse.quiet_parse("1, 2", "expr_comma_seq").should.equal( [self.one, self.two] )
def test_simple_pattern_seq(self): self._assert_parse_fails("", "simple_pattern_seq") red, blue = ast.Pattern("Red"), ast.Pattern("Blue") parse.quiet_parse("Red", "simple_pattern_seq").should.equal([red]) parse.quiet_parse("Red Blue", "simple_pattern_seq").should.equal( [red, blue] )
def test_quiet_parse(self): mock = error.LoggerMock() p1 = parse.Parser(logger=mock) (parse.quiet_parse("")).should.equal(p1.parse("")) p2 = parse.Parser(start='type') (parse.quiet_parse("int", start='type')).should.equal(p2.parse("int"))
def test_if_expr(self): parse.quiet_parse("if true then 1 else 2", "expr").should.equal( ast.IfExpression(self.true, self.one, self.two) ) parse.quiet_parse("if true then ()", "expr").should.equal( ast.IfExpression(self.true, self.unit) )
def test_constr(self): parse.quiet_parse("Node", "constr").should.equal( ast.Constructor("Node", []) ) parse.quiet_parse("Node of int", "constr").should.equal( ast.Constructor("Node", [ast.Int()]) )
def test_simple_variable_def(self): foo_var = ast.VariableDef("foo") parse.quiet_parse("mutable foo : int", "def").should.equal( ast.VariableDef("foo", ast.Ref(ast.Int())) ) parse.quiet_parse("mutable foo", "def").should.equal(foo_var)
def test_constr_pipe_seq(self): self._assert_parse_fails("", "constr_pipe_seq") parse.quiet_parse("Black | White", "constr_pipe_seq").should.equal( [ast.Constructor("Black"), ast.Constructor("White")] )
def test_simple_expr_seq(self): self._assert_parse_fails("", "simple_expr_seq") parse.quiet_parse("1", "simple_expr_seq").should.equal([self.one]) parse.quiet_parse("1 2", "simple_expr_seq").should.equal( [self.one, self.two] )
def test_constant_def(self): parse.quiet_parse("let x = 1", "def").should.equal( ast.ConstantDef("x", self.one) ) parse.quiet_parse("let x : int = 1", "def").should.equal( ast.ConstantDef("x", self.one, ast.Int()) )
def test_tdef(self): parse.quiet_parse("color = Red", "tdef").should.equal( ast.TDef(ast.User("color"), [ast.Constructor("Red")]) ) parse.quiet_parse("int = Red", "tdef").should.equal( ast.TDef(ast.Int(), [ast.Constructor("Red")]) )
def test_param(self): parse.quiet_parse("my_parameter", "param").should.equal( ast.Param("my_parameter") ) parse.quiet_parse("(my_parameter: int)", "param").should.equal( ast.Param("my_parameter", ast.Int()) ) self._assert_parse_fails("my_parameter: int", "param")
def test_dim_expr(self): parsed = parse.quiet_parse("dim name", "expr") parsed.should.be.an(ast.DimExpression) parsed.name.should.equal("name") parsed = parse.quiet_parse("dim 2 name", "expr") parsed.should.be.an(ast.DimExpression) parsed.name.should.equal("name") parsed.dimension.should.equal(2)
def test_param_seq(self): self._assert_parse_fails("", "param_seq") parse.quiet_parse("my_param", "param_seq").should.equal( [ast.Param("my_param")] ) parse.quiet_parse("a b", "param_seq").should.equal( [ast.Param("a"), ast.Param("b")] )
def test_clause_seq(self): self._assert_parse_fails("", "clause_seq") clause1 = ast.Clause(self.one, self.two) clause2 = ast.Clause(self.true, self.false) parse.quiet_parse( "1 -> 2 | true -> false", "clause_seq" ).should.equal( [clause1, clause2] )
def test_letdef(self): parse.quiet_parse("let x = 1", "letdef").should.equal( ast.LetDef( [ast.FunctionDef("x", [], self.one)] ) ) parse.quiet_parse("let rec x = 1", "letdef").should.equal( ast.LetDef( [ast.FunctionDef("x", [], self.one)], True ) )
def test_tdef_and_seq(self): self._assert_parse_fails("", "tdef_and_seq") parse.quiet_parse( "color = Red and shoes = Slacks", "tdef_and_seq" ).should.equal( [ ast.TDef(ast.User("color"), [ast.Constructor("Red")]), ast.TDef(ast.User("shoes"), [ast.Constructor("Slacks")]) ] )
def _assert_non_equivalent(self, expr1, expr2=None, start="expr"): """ Assert that two expressions are not parsed as equivalent ASTs. The API is similar to _assert_equivalent. """ if expr2 is None: # sequence of expressions exprs = expr1 for expr1, expr2 in exprs: self._assert_non_equivalent(expr1, expr2, start) else: parsed1 = parse.quiet_parse(expr1, start) parsed2 = parse.quiet_parse(expr2, start) parsed1.shouldnt.equal(parsed2)
def test_function_def(self): parse.quiet_parse("let x y (z:int) = 1", "def").should.equal( ast.FunctionDef( "x", [ast.Param("y"), ast.Param("z", ast.Int())], self.one ) ) parse.quiet_parse("let x y z:int = 1", "def").should.equal( ast.FunctionDef( "x", [ast.Param("y"), ast.Param("z")], self.one, ast.Int() ) )
def test_for_expr(self): parse.quiet_parse("for i = 1 to 2 do () done", "expr").should.equal( ast.ForExpression( "i", self.one, self.two, self.unit ) ) parse.quiet_parse( "for i = 2 downto 1 do () done", "expr" ).should.equal( ast.ForExpression( "i", self.two, self.one, self.unit, True ) )
def _check_binary_operator(self, operator): expr = "1 %s 2" % operator parsed = parse.quiet_parse(expr, "expr") parsed.should.be.an(ast.BinaryExpression) parsed.operator.should.equal(operator) parsed.leftOperand.should.equal(self.one) parsed.rightOperand.should.equal(self.two)
def test_type_process_wrong(self): wrong_testcases = ( ( ( "type bool = BoolCon", "type char = CharCon", "type float = FloatCon", "type int = IntCon", "type unit = UnitCon", ), type.RedefBuiltinTypeError, 1 ), ( ( "type dup = ConDup | ConDup", """ type one = Con type two = Con """, ), type.RedefConstructorError, 2 ), ( ( """ type same = Foo1 type same = Foo2 """, ), type.RedefUserTypeError, 2 ), ( ( "type what = What of undeftype", ), type.UndefTypeError, 1 ) ) for cases, error, exc_node_count in wrong_testcases: for case in cases: table = type.Table() tree = parse.quiet_parse(case) with self.assertRaises(error) as context: for typeDefList in tree: table.process(typeDefList) exc = context.exception exc.should.have.property("node") self._assert_node_lineinfo(exc.node) if exc_node_count == 2: exc.should.have.property("prev") exc.prev.shouldnt.be(exc.node) self._assert_node_lineinfo(exc.prev)
def setUpClass(cls): cls.one = parse.quiet_parse("1", "expr") cls.two = parse.quiet_parse("2", "expr") cls.true = parse.quiet_parse("true", "expr") cls.false = parse.quiet_parse("false", "expr") cls.unit = parse.quiet_parse("()", "expr") cls.xfunc = parse.quiet_parse("let x = 1", "letdef") cls.yfunc = parse.quiet_parse("let y = 2", "letdef")
def _assert_equivalent(self, expr1, expr2=None, start="expr"): """ Assert that two expressions are parsed into equivalent ASTs. You can pass either two expressions (expr1, expr2) or a sequence of expression tuples as expr1, leaving expr2 to None. """ if expr2 is None: # sequence of expressions exprs = expr1 for expr1, expr2 in exprs: self._assert_equivalent(expr1, expr2, start) else: # self.assertEqual( # parse.quiet_parse(expr1, "expr"), # parse.quiet_parse(expr2, "expr"), # "'%s' must equal '%s'" % (expr1, expr2) # ) parsed1 = parse.quiet_parse(expr1, start) parsed2 = parse.quiet_parse(expr2, start) parsed1.should.equal(parsed2)
def test_def_list(self): parse.quiet_parse("", "def_list").should.equal([]) parse.quiet_parse("let x = 1", "def_list").should.equal([self.xfunc]) parse.quiet_parse("let x = 1 let y = 2", "def_list").should.equal( [self.xfunc, self.yfunc] )
def test_is_array(self): for typecon in ast.builtin_types_map.values(): self.assertFalse(typesem.is_array(typecon())) right_testcases = ( "array of int", "array of foo", "array [*, *] of int" ) for case in right_testcases: tree = parse.quiet_parse(case, "type") self.assertTrue(typesem.is_array(tree)) wrong_testcases = ( "foo", "int ref", "int -> int", ) for case in wrong_testcases: tree = parse.quiet_parse(case, "type") self.assertFalse(typesem.is_array(tree))
def test_param_list(self): parse.quiet_parse("", "param_list").should.equal([]) parse.quiet_parse("my_param", "param_list").should.equal( [ast.Param("my_param")] ) parse.quiet_parse("a b", "param_list").should.equal( [ast.Param("a"), ast.Param("b")] )
def test_type_process_correct(self): right_testcases = ( "type color = Red | Green | Blue", "type list = Nil | Cons of int list", """ type number = Integer of int | Real of float | Complex of float float """, """ type tree = Leaf | Node of int forest and forest = Empty | NonEmpty of tree forest """ ) table = type.Table() proc = table.process for case in right_testcases: tree = parse.quiet_parse(case, "typedef") proc.when.called_with(tree).shouldnt.throw(type.InvalidTypeError)
def test_validate(self): """Test the validating of types.""" table = typesem.Table() foo_tree = parse.quiet_parse("type foo = Foo") for typeDefList in foo_tree: table.process(typeDefList) proc = table.validate error = typesem.InvalidTypeError for typecon in ast.builtin_types_map.values(): proc.when.called_with(typecon()).shouldnt.throw(error) right_testcases = ( "foo", "int ref", "foo ref", "(int -> int) ref", "(int ref) ref", "array of int", "array of foo", "array of (int ref)", "array of (foo ref)", "array [*, *] of int", "int -> int", "foo -> int", "int -> foo", "int ref -> int", "int -> (int ref)", "(array of int) -> int", "int -> (array of int -> int)", "(int -> int) -> int" ) for case in right_testcases: tree = parse.quiet_parse(case, "type") proc.when.called_with(tree).shouldnt.throw(error) wrong_testcases = ( ( ( "array of (array of int)", "(array of (array of int)) -> int", "((array of (array of int)) -> int) ref", ), typesem.ArrayOfArrayError ), ( ( "(array of int) ref", "((array of int) ref) -> int", "array of ((array of int) ref)", ), typesem.RefOfArrayError ), ( ( "int -> array of int", "int -> (int -> array of int)", "(int -> array of int) ref", ), typesem.ArrayReturnError ), ( ( "undeftype", ), typesem.UndefTypeError ) ) for cases, error in wrong_testcases: for case in cases: tree = parse.quiet_parse(case, "type") with self.assertRaises(error) as context: proc(tree) exc = context.exception exc.should.have.property("node") self._assert_node_lineinfo(exc.node)
def test_process(self): right_testcases = ( "type color = Red | Green | Blue", "type list = Nil | Cons of int list", """ type number = Integer of int | Real of float | Complex of float float """, """ type tree = Leaf | Node of int forest and forest = Empty | NonEmpty of tree forest """ ) table = typesem.Table() proc = table.process for case in right_testcases: tree = parse.quiet_parse(case, "typedef") proc.when.called_with(tree).shouldnt.throw( typesem.InvalidTypeError ) wrong_testcases = ( ( ( "type bool = BoolCon", "type char = CharCon", "type float = FloatCon", "type int = IntCon", "type unit = UnitCon", ), typesem.RedefBuiltinTypeError, 1 ), ( ( "type dup = ConDup | ConDup", """ type one = Con type two = Con """, ), typesem.RedefConstructorError, 2 ), ( ( """ type same = Foo1 type same = Foo2 """, ), typesem.RedefUserTypeError, 2 ), ( ( "type what = What of undeftype", ), typesem.UndefTypeError, 1 ), ( ( "type invalid = Foo of (array of int) ref", ), typesem.RefOfArrayError, 1 ) ) for cases, error, exc_node_count in wrong_testcases: for case in cases: table = typesem.Table() tree = parse.quiet_parse(case) with self.assertRaises(error) as context: for typeDefList in tree: table.process(typeDefList) exc = context.exception exc.should.have.property("node") self._assert_node_lineinfo(exc.node) if exc_node_count == 2: exc.should.have.property("prev") exc.prev.shouldnt.be(exc.node) self._assert_node_lineinfo(exc.prev)
def test_table_process(self): tree = parse.quiet_parse("type foo = Foo of int", "typedef") typesem.Table().process(tree)