def test_functions_recursion(self): # fun f(a,b) {if a = 0 {ret b} else {ret f(a-1,b+1)}}\nx:=f(5,0) tree = \ Program([ Fun(Identifier('f'), [Identifier('a'), Identifier('b')], Program([ If(Comparison(Identifier('a'), TokenType.EQUAL, Literal(0)), Program([Ret(Identifier('b'))]), Program([Ret(FunCall(Identifier('f'), [Binary(Identifier('a'), TokenType.MINUS, Literal(1)), Binary(Identifier('b'), TokenType.PLUS, Literal(1))]))]) ) ])), Assign(Identifier('x'), FunCall(Identifier('f'), [Literal(5), Literal(0)])) ]) interpreter = Interpreter() self.assertEqual(5, interpreter.interpret(tree)['x']) # fun odd(n) { # if n = 0 { # ret false # } # ret even(n-1) # } # # fun even(n) { # if n = 0 { # ret true # } # ret odd(n-1) # } # # a := even(5) # b := odd(5) # c := even(10) # d := odd(10) tree = \ Program([ Fun(Identifier('odd'), [Identifier('n')], Program([ If(Comparison(Identifier('n'), TokenType.EQUAL, Literal(0)), Program([Ret(Literal(False))]), Program([])), Ret(FunCall(Identifier('even'), [Binary(Identifier('n'), TokenType.MINUS, Literal(1))])) ])), Fun(Identifier('even'), [Identifier('n')], Program([ If(Comparison(Identifier('n'), TokenType.EQUAL, Literal(0)), Program([Ret(Literal(True))]), Program([])), Ret(FunCall(Identifier('odd'), [Binary(Identifier('n'), TokenType.MINUS, Literal(1))])) ])), Assign(Identifier('a'), FunCall(Identifier('even'), [Literal(5)])), Assign(Identifier('b'), FunCall(Identifier('odd'), [Literal(5)])), Assign(Identifier('c'), FunCall(Identifier('even'), [Literal(10)])), Assign(Identifier('d'), FunCall(Identifier('odd'), [Literal(10)])) ]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(False, env['a']) self.assertEqual(True, env['b']) self.assertEqual(True, env['c']) self.assertEqual(False, env['d'])
def test_higher_order_functions(self): # fun f(g, x) {ret g(g(x))}\nfun g(x) {ret x+1}\ny:=f(g, 3) tree = \ Program([Fun(Identifier('f'), [Identifier('g'), Identifier('x')], Program([Ret(FunCall(Identifier('g'), [FunCall(Identifier('g'), [Identifier('x')])]))])), Fun(Identifier('g'), [Identifier('x')], Program([Ret(Binary(Identifier('x'), TokenType.PLUS, Literal(1)))])), Assign(Identifier('y'), FunCall(Identifier('f'), [Identifier('g'), Literal(3)]))]) interpreter = Interpreter() self.assertEqual(5, interpreter.interpret(tree)['y']) # fun f() {fun g() {ret 1}\nret g}\nx := f()() tree = \ Program([Fun(Identifier('f'), [], Program([Fun(Identifier('g'), [], Program([Ret(Literal(1))])), Ret(Identifier('g'))])), Assign(Identifier('x'), FunCall(FunCall(Identifier('f'), []), []))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(1, env['x']) self.assertFalse('g' in env) # fun double(f) {fun g(x) {ret f(f(x))}\n ret g}\nfun g(x) {ret x+1}\nd:= double(g)\na:=d(3)\nb:=d(5) tree = \ Program([Fun(Identifier('double'), [Identifier('f')], Program([Fun(Identifier('g'), [Identifier('x')], Program([Ret(FunCall(Identifier('f'), [ FunCall(Identifier('f'), [Identifier('x')])]))])), Ret(Identifier('g'))])), Fun(Identifier('g'), [Identifier('x')], Program([Ret(Binary(Identifier('x'), TokenType.PLUS, Literal(1)))])), Assign(Identifier('d'), FunCall(Identifier('double'), [Identifier('g')])), Assign(Identifier('a'), FunCall(Identifier('d'), [Literal(3)])), Assign(Identifier('b'), FunCall(Identifier('d'), [Literal(5)]))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(5, env['a']) self.assertEqual(7, env['b']) # fun counter() {i := 0\nfun count() {i := i+1\nret i}\n ret count}\nc := counter()\na := c()\nb := c() tree = \ Program([Fun(Identifier('counter'), [], Program([Assign(Identifier('i'), Literal(0)), Fun(Identifier('count'), [], Program([Assign( Identifier('i'), Binary(Identifier('i'), TokenType.PLUS, Literal(1))), Ret(Identifier( 'i'))])), Ret(Identifier('count'))])), Assign(Identifier('c'), FunCall(Identifier('counter'), [])), Assign(Identifier('a'), FunCall(Identifier('c'), [])), Assign(Identifier('b'), FunCall(Identifier('c'), []))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(1, env['a']) self.assertEqual(2, env['b'])
def test_expression_statements(self): # fun f() {print(5)}\n10+4\nf() tree = \ Program([Fun(Identifier('f'), [], Program([ExprStmt(FunCall(Identifier('print'), [Literal(5)]))])), ExprStmt(Binary(Literal(10), TokenType.PLUS, Literal(4))), ExprStmt(FunCall(Identifier('f'), []))]) interpreter = Interpreter() saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out interpreter.interpret(tree) output = out.getvalue().strip() self.assertEqual('5', output) finally: sys.stdout = saved_stdout
def test_assignment(self): tree = \ Program([Assign(Identifier('x'), Literal(5.2)), Assign(Identifier('y'), LogicalBinary(LogicalUnary(TokenType.NOT, Literal(True)), TokenType.OR, Literal(True))), Assign(Identifier('z'), StringBinary(Literal('asd'), TokenType.HASH, Identifier('y')))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertAlmostEqual(5.2, env['x']) self.assertEqual(True, env['y']) self.assertEqual('asdtrue', env['z'])
def test_control_structures(self): # x := 0\nif 2 < 3 {x := 5} tree = \ Program([Assign(Identifier('x'), Literal(0)), If(Comparison(Literal(2), TokenType.L, Literal(3)), Program([Assign(Identifier('x'), Literal(5))]), Program([]))]) interpreter = Interpreter() self.assertEqual(5, interpreter.interpret(tree)['x']) # x := 0\nif 2 > 3 {x := 5} tree = \ Program([Assign(Identifier('x'), Literal(0)), If(Comparison(Literal(3), TokenType.L, Literal(2)), Program([Assign(Identifier('x'), Literal(5))]), Program([]))]) interpreter = Interpreter() self.assertEqual(0, interpreter.interpret(tree)['x']) # x := 0\nwhile x < 10 {x := x + 1}\nb := x = 10 tree = \ Program([Assign(Identifier('x'), Literal(0)), While(Comparison(Identifier('x'), TokenType.L, Literal(10)), Program([Assign(Identifier('x'), Binary(Identifier('x'), TokenType.PLUS, Literal(1)))])), Assign(Identifier('b'), Comparison(Identifier('x'), TokenType.EQUAL, Literal(10)))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(10, env['x']) self.assertEqual(True, env['b'])
def test_print(self): tree = \ Program([ExprStmt(FunCall(Identifier('print'), [Identifier('x')])), ExprStmt(FunCall(Identifier('print'),[ LogicalBinary(Identifier('y'), TokenType.AND, Literal(False))])), ExprStmt(FunCall(Identifier('print'), [Literal('asd')]))]) env = {'x': 5, 'y': True} interpreter = Interpreter(env) saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out self.assertEqual(env, interpreter.interpret(tree)) output = out.getvalue().strip() self.assertEqual(output, '5\nfalse\nasd') finally: sys.stdout = saved_stdout
def run(src: str) -> None: global env #tokenization tkz = Tokenizer() tokens, err = tkz.tokenize(src) if tok_debug: for i in tokens: print(i) if display_errors(err, "LOX: SYNTAX ERROR"): return #don't send single EOF token to parser #this allows parser to make stricter assertions while generating the AST if tokens[0].type == TokenType.EOF: return #parsing prs = Parser() program, err = prs.parse(tokens) if parse_debug: for tree in program: print(tree) if display_errors(err, "LOX: GRAMMAR ERROR"): return #interpretation itr = Interpreter(env) exit_status, err, env = itr.interpret(program) display_errors(err, "LOX: RUNTIME ERROR") if env_debug: print(env.map)
def test_functions_basics(self): # x:=2\nfun f(x) {y:=1\nret x ^ 2\nret x}\nx := f(x + 1) tree = \ Program([Assign(Identifier('x'), Literal(2)), Fun(Identifier('f'), [Identifier('x')], Program([ Assign(Identifier('y'), Literal(1)), Ret(Binary(Identifier('x'), TokenType.POW, Literal(2))), Ret(Identifier('x'))])), Assign(Identifier('x'), FunCall(Identifier('f'), [Binary(Identifier('x'), TokenType.PLUS, Literal(1))]))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(9, env['x']) self.assertEqual(9, env['f'].env['x']) self.assertFalse('y' in env) # x:=1\nfun f() {ret x}\nx:=2\ny := f() tree = \ Program([Assign(Identifier('x'), Literal(1)), Fun(Identifier('f'), [], Program([Ret(Identifier('x'))])), Assign(Identifier('x'), Literal(2)), Assign(Identifier('y'), FunCall(Identifier('f'), []))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(2, env['y']) # x:=1\nfun f() {x := 2}\nf() tree = \ Program([Assign(Identifier('x'), Literal(1)), Fun(Identifier('f'), [], Program([ Assign(Identifier('x'), Literal(2)) ])),ExprStmt(FunCall(Identifier('f'), []))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(2, env['x']) # a := 'global'\nb1 := '1'\n b2 := '2'\nfun outer() {fun showA() {ret a}\nb1 := showA()\na := 'inner'\nb2 := showA()}\nouter() tree = \ Program([Assign(Identifier('a'), Literal( 'global')), Assign(Identifier('b1'), Literal( '1')),Assign(Identifier('b2'), Literal( '2')),Fun(Identifier('outer'), [], Program([Fun(Identifier('showA'), [], Program([Ret(Identifier('a'))])), Assign(Identifier('b1'), FunCall(Identifier('showA'), [])), Assign(Identifier('a'), Literal('inner')), Assign(Identifier('b2'), FunCall(Identifier('showA'), []))])), ExprStmt(FunCall(Identifier('outer'), []))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual('global', env['b1']) self.assertEqual('inner', env['b2']) # fun f() {print(a)\na:=10}\na:=20\nf()\nprint(a) tree = \ Program([Fun(Identifier('f'), [], Program( [ExprStmt(FunCall(Identifier('print'), [Identifier('a')])), Assign(Identifier('a'), Literal(10))])), Assign(Identifier('a'), Literal(20)), ExprStmt(FunCall(Identifier('f'), [])), ExprStmt(FunCall(Identifier('print'), [Identifier('a')]))]) interpreter = Interpreter() saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out env = interpreter.interpret(tree) output = out.getvalue().strip() self.assertEqual('20\n10', output) finally: sys.stdout = saved_stdout # fun f(x) {x := 10\nret x}\n x:=5\ny := f(x) tree = \ Program([Fun(Identifier('f'), [Identifier('x')], Program([ Assign(Identifier('x'), Literal(10)), Ret(Identifier('x')) ])), Assign(Identifier('x'), Literal(5)), Assign(Identifier('y'), FunCall(Identifier('f'), [Identifier('x')]))]) interpreter = Interpreter() env = interpreter.interpret(tree) self.assertEqual(5, env['x']) self.assertEqual(10, env['y'])
from src.lexer import Lexer from src.parser import Parser from src.interpreter import Interpreter from src.semantic_analyzer import SemanticAnalyzer __all__ = ("Lexer", "Parser", "Interpreter", "SemanticAnalyzer") if __name__ == "__main__": import sys with open(sys.argv[1]) as f: text = f.read() lexer = Lexer(text) parser = Parser(lexer) tree = parser.parse() semantic_analyzer = SemanticAnalyzer() semantic_analyzer.visit(tree) interpreter = Interpreter(tree) result = interpreter.interpret() print() print("Runtime GLOBAL_MEMORY contents:") for k, v in sorted(interpreter.GLOBAL_SCOPE.items()): print("%s = %s" % (k, v))
def process_file(filename): with open(filename, "r") as file: text = file.read() interpreter = Interpreter(text) result = interpreter.interpret() print(interpreter.GLOBAL_VARS)