def test_precedence(self): buf = """ fn prec() -> int { 2 + 3 * 2 + 2 / 8; } """ exprs = [ ast.Function( "prec", [], [ ast.ExprStatement( ast.BinaryOp( ast.BinaryOp( ast.Number(2), ast.BinaryOp(ast.Number(3), ast.Number(2), Token(TokenType.MULTIPLY, "*")), Token(TokenType.ADD, "+"), ), ast.BinaryOp(ast.Number(2), ast.Number(8), Token(TokenType.DIVIDE, "/")), Token(TokenType.ADD, "+"), )) ], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_constructor(self): buf = """ fn constructorTest() -> int { let foo = new Foo(name, age); return 0; } """ exprs = [ ast.Function( "constructorTest", [], [ ast.LetStatement( "foo", ast.Constructor( "Foo", [ast.VariableRef("name"), ast.VariableRef("age")]), ), ast.ReturnStatement(ast.Number(0)), ], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_struct_with_member_functions(self): buf = """ struct Foo { string name; int age; fn memberFunc() -> int { return age; } }; """ exprs = [ ast.Structure( "Foo", [ ast.Member("name", ast.Type(ast.TypeKind.STRING)), ast.Member("age", ast.Type(ast.TypeKind.INT)), ], [ ast.Function( "memberFunc", [("this", ast.Type(ast.TypeKind.USER, "Foo"))], [ast.ReturnStatement(ast.VariableRef("age"))], ast.Type(ast.TypeKind.INT), ) ], ) ] self._test_parse_impl(buf, exprs)
def test_while_loop(self): buf = """ fn loopTest(int x) -> int { while (x < 5) { print("blah"); } return 0; } """ exprs = [ ast.Function( "loopTest", [("x", ast.Type(ast.TypeKind.INT))], [ ast.WhileLoop( ast.BinaryOp(ast.VariableRef("x"), ast.Number(5), Token(TokenType.LESS_THAN, "<")), [ ast.ExprStatement( ast.FunctionCall("print", [ast.String("blah")])) ], ), ast.ReturnStatement(ast.Number(0)), ], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_if_statements(self): buf = """ fn foo() -> string { if (3 == 3) { return "foo"; } return "bar"; } """ exprs = [ ast.Function( "foo", [], [ ast.IfStatement( ast.BinaryOp(ast.Number(3), ast.Number(3), Token(TokenType.EQUALS, "==")), [ast.ReturnStatement(ast.String("foo"))], list(), ), ast.ReturnStatement(ast.String("bar")), ], ast.Type(ast.TypeKind.STRING), ) ] self._test_parse_impl(buf, exprs)
def _parse_function(self, this=None): f_name = self.cur_tok.value self._expect_token(TokenType.IDENTIFIER) self._expect_token(TokenType.L_BRACKET) # Parse function arguments. args = list() while not self._consume_token(TokenType.R_BRACKET): if args: self._expect_token(TokenType.COMMA) arg_type = self._parse_type() arg_name = self.cur_tok.value self._expect_token(TokenType.IDENTIFIER) args.append((arg_name, arg_type)) # Parse return type. self._expect_token(TokenType.ARROW) return_type = self._parse_type() self._expect_token(TokenType.L_BRACE) statements = list() while not self._consume_token(TokenType.R_BRACE): statements.append(self._parse_statement()) if this is not None: args.insert(0, this) return ast.Function(f_name, args, statements, return_type)
def _do_FunctionDefinition(self, node): decorators = self.transform_decorator(node.Decorators) name = str(node.Name) argnames, defaults, flags = self.function_info(node) doc = node.Documentation code = self.transform_suite(node.Body) if doc: del code.nodes[0] return ast.Function(decorators, name, argnames, defaults, flags, doc, code)
def test_string_literals(self): buf = """ fn fooString() -> string { return "string_literal_value"; } """ exprs = [ ast.Function( "fooString", [], [ast.ReturnStatement(ast.String("string_literal_value"))], ast.Type(ast.TypeKind.STRING), ) ] self._test_parse_impl(buf, exprs)
def test_function_call(self): buf = """ fn funcCall() -> int { return otherFunc(); } """ exprs = [ ast.Function( "funcCall", [], [ast.ReturnStatement(ast.FunctionCall("otherFunc", []))], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_function(self): buf = """ fn fooFunc(string name, int age) -> int { return 1; } """ exprs = [ ast.Function( "fooFunc", [("name", ast.Type(ast.TypeKind.STRING)), ("age", ast.Type(ast.TypeKind.INT))], [ast.ReturnStatement(ast.Number(1))], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_member_access(self): buf = """ fn foo() -> int { return bar.age; } """ exprs = [ ast.Function( "foo", [], [ ast.ReturnStatement( ast.MemberAccess(ast.VariableRef("bar"), "age")) ], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_let_statement(self): buf = """ fn letFunc() -> int { let x = 1; return x; } """ exprs = [ ast.Function( "letFunc", [], [ ast.LetStatement("x", ast.Number(1)), ast.ReturnStatement(ast.VariableRef("x")) ], ast.Type(ast.TypeKind.INT), ) ] self._test_parse_impl(buf, exprs)
def test_simple_expression(): source = """ export function Main(): void { let a = 1 + 2 * 3; } """ result = get_semantic_analysis(source) assert_equal_programs( result, ast.Program( imports=[], traits=[], data_defs=[], functions=[ ast.Function( name="Main", is_exported=True, params=[], type=types.Function(name="Main", params=[], result=types.Void()), body=[ ast.Let( name="a", value=ast.BinaryOperation( operator=ast.BinaryOperator.ADD, left=ast.Number(value=1), right=ast.BinaryOperation( operator=ast.BinaryOperator.MULTIPLY, left=ast.Number(value=2), right=ast.Number(value=3), ), ), ) ], ) ], ), )
def p_funcdef(p): "funcdef : DEF NAME parameters COLON suite" p[0] = ast.Function(None, p[2], tuple(p[3]), (), 0, None, p[5])
def test_simple_predicates(): source = """ function isGreaterThan(left: i32, right: i32): boolean { left > right; } function isLessThan(left: i32, right: i32): boolean { left < right; } function and(left: boolean, right: boolean): boolean { left && right; } function or(left: boolean, right: boolean): boolean { left || right; } """ result = get_semantic_analysis(source) assert_equal_programs( result, ast.Program( imports=[], traits=[], data_defs=[], functions=[ ast.Function( name="isGreaterThan", is_exported=False, params=[ ast.Param(name="left", type=types.Param(name="left", type=types.I32())), ast.Param( name="right", type=types.Param(name="right", type=types.I32()), ), ], type=types.Function( name="isGreaterThan", params=[ types.Param(name="left", type=types.I32()), types.Param(name="right", type=types.I32()), ], result=types.Boolean(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.GREATER_THAN, left=ast.Variable(name="left"), right=ast.Variable(name="right"), ) ], ), ast.Function( name="isLessThan", is_exported=False, params=[ ast.Param(name="left", type=types.Param(name="left", type=types.I32())), ast.Param( name="right", type=types.Param(name="right", type=types.I32()), ), ], type=types.Function( name="isLessThan", params=[ types.Param(name="left", type=types.I32()), types.Param(name="right", type=types.I32()), ], result=types.Boolean(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.LESS_THAN, left=ast.Variable(name="left"), right=ast.Variable(name="right"), ) ], ), ast.Function( name="and", is_exported=False, params=[ ast.Param( name="left", type=types.Param(name="left", type=types.Boolean()), ), ast.Param( name="right", type=types.Param(name="right", type=types.Boolean()), ), ], type=types.Function( name="and", params=[ types.Param(name="left", type=types.Boolean()), types.Param(name="right", type=types.Boolean()), ], result=types.Boolean(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.AND, left=ast.Variable(name="left"), right=ast.Variable(name="right"), ) ], ), ast.Function( name="or", is_exported=False, params=[ ast.Param( name="left", type=types.Param(name="left", type=types.Boolean()), ), ast.Param( name="right", type=types.Param(name="right", type=types.Boolean()), ), ], type=types.Function( name="or", params=[ types.Param(name="left", type=types.Boolean()), types.Param(name="right", type=types.Boolean()), ], result=types.Boolean(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.OR, left=ast.Variable(name="left"), right=ast.Variable(name="right"), ) ], ), ], ), )
def test_trait_with_multiple_implementations(): source = """ trait List { function length(self: List): i32; function sum(self: List): i32; } data EmptyList() implements List { function length(self: List): i32 { 0; } function sum(self: List): i32 { 0; } } data Cons(head: i32, tail: List) implements List { function length(self: List): i32 { 1 + self.tail.length(); } function sum(self: List): i32 { self.head + self.tail.sum(); } } """ result = get_semantic_analysis(source) assert_equal_programs( result, ast.Program( imports=[], traits=[ ast.Trait( name="List", is_exported=False, functions=[ ast.Function( name="length", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="length", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=None, ), ast.Function( name="sum", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="sum", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=None, ), ], type=types.Trait(name="List", functions=[]), ) ], data_defs=[ ast.DataDef( name="EmptyList", is_exported=False, implements=["List"], params=[], functions=[ ast.Function( name="length", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="length", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=[ast.Number(value=0)], ), ast.Function( name="sum", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="sum", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=[ast.Number(value=0)], ), ], type=types.Data( name="EmptyList", implements=[types.TypeRef("List")], fields=[], functions=[], ), ), ast.DataDef( name="Cons", is_exported=False, implements=["List"], params=[ ast.Param(name="head", type=types.Field(name="head", type=types.I32())), ast.Param( name="tail", type=types.Field(name="tail", type=types.TypeRef(name="List")), ), ], functions=[ ast.Function( name="length", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="length", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.ADD, left=ast.Number(value=1), right=ast.FunctionCall( name="self.tail.length", arguments=[]), ) ], ), ast.Function( name="sum", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="List")), ) ], type=types.Function( name="sum", params=[ types.Param( name="self", type=types.TypeRef(name="List")) ], result=types.I32(), ), body=[ ast.BinaryOperation( operator=ast.BinaryOperator.ADD, left=ast.MemberAccess( value=ast.Variable(name="self"), member="head"), right=ast.FunctionCall( name="self.tail.sum", arguments=[]), ) ], ), ], type=types.Data( name="Cons", implements=[types.TypeRef("List")], fields=[ types.Field(name="head", type=types.I32()), types.Field(name="tail", type=types.TypeRef(name="List")), ], functions=[], ), ), ], functions=[], ), )
def test_data_vector_with_complex_function(): source = """ import System::Output; export data Vector(x: i32, y: i32) { function add(self: Vector, other: Vector): Vector { Vector(x = self.x + other.x, y = self.y + other.y); } } export function Main(): void { } """ result = get_semantic_analysis(source) assert_equal_programs( result, ast.Program( imports=[ast.Import(value="System::Output")], traits=[], data_defs=[ ast.DataDef( name="Vector", implements=[], is_exported=True, params=[ ast.Param(name="x", type=types.Field(name="x", type=types.I32())), ast.Param(name="y", type=types.Field(name="y", type=types.I32())), ], functions=[ ast.Function( name="add", is_exported=False, params=[ ast.Param( name="self", type=types.Param( name="self", type=types.TypeRef(name="Vector")), ), ast.Param( name="other", type=types.Param( name="other", type=types.TypeRef(name="Vector")), ), ], type=types.Function( name="add", params=[ types.Param( name="self", type=types.TypeRef(name="Vector")), types.Param( name="other", type=types.TypeRef(name="Vector")), ], result=types.TypeRef(name="Vector"), ), body=[ ast.FunctionCall( name="Vector", arguments=[ ast.Argument( name="x", value=ast.BinaryOperation( operator=ast.BinaryOperator. ADD, left=ast.MemberAccess( value=ast.Variable( name="self"), member="x", ), right=ast.MemberAccess( value=ast.Variable( name="other"), member="x", ), ), ), ast.Argument( name="y", value=ast.BinaryOperation( operator=ast.BinaryOperator. ADD, left=ast.MemberAccess( value=ast.Variable( name="self"), member="y", ), right=ast.MemberAccess( value=ast.Variable( name="other"), member="y", ), ), ), ], ) ], ) ], type=types.Data( name="Vector", implements=[], fields=[ types.Field(name="x", type=types.I32()), types.Field(name="y", type=types.I32()), ], functions=[], ), ) ], functions=[ ast.Function( name="Main", is_exported=True, params=[], type=types.Function(name="Main", params=[], result=types.Void()), body=[], ) ], ), )
def astFunction(*args): return ast.Function(None, *args)
def funcdef(self, nodelist): if len(nodelist) == 6: assert nodelist[0][0] == symbol.decorators decorators = self.decorators(nodelist[0][1:]) else: assert len(nodelist) == 5 decorators = None lineno = nodelist[-4][2] name = nodelist[-4][1] args = nodelist[-3][2] if not re.match('_q_((html|plain)_)?template_', name): # just a normal function, let base class handle it self.__template_type.append(None) n = transformer.Transformer.funcdef(self, nodelist) else: if name.startswith(PLAIN_TEMPLATE_PREFIX): name = name[len(PLAIN_TEMPLATE_PREFIX):] template_type = "plain" elif name.startswith(HTML_TEMPLATE_PREFIX): name = name[len(HTML_TEMPLATE_PREFIX):] template_type = "html" elif name.startswith(TEMPLATE_PREFIX): name = name[len(TEMPLATE_PREFIX):] template_type = "plain" else: raise RuntimeError, 'unknown prefix on %s' % name self.__template_type.append(template_type) # Add "IO_INSTANCE = IO_CLASS()" statement at the beginning of # the function and a "return IO_INSTANCE" at the end. if args[0] == symbol.varargslist: names, defaults, flags = self.com_arglist(args[1:]) else: names = defaults = () flags = 0 doc = None # self.get_docstring(nodelist[-1]) # code for function code = self.com_node(nodelist[-1]) # create an instance, assign to IO_INSTANCE klass = ast.Name(IO_CLASS) args = [ast.Const(template_type == "html")] instance = ast.CallFunc(klass, args) assign_name = ast.AssName(IO_INSTANCE, OP_ASSIGN) assign = ast.Assign([assign_name], instance) # return the IO_INSTANCE.getvalue(...) func = ast.Getattr(ast.Name(IO_INSTANCE), "getvalue") ret = ast.Return(ast.CallFunc(func, [])) # wrap original function code code = ast.Stmt([assign, code, ret]) if sys.hexversion >= 0x20400a2: n = ast.Function(decorators, name, names, defaults, flags, doc, code) else: n = ast.Function(name, names, defaults, flags, doc, code) n.lineno = lineno self.__template_type.pop() return n