def Start() -> None: env = object.NewEnvironment() macroEnv = object.NewEnvironment() while True: try: line = input(PROMPT) except KeyboardInterrupt: print('\nKeyboardInterrupt') continue if line == 'exit()': break lex = lexer.New(line) p = parser.New(lex) program = p.ParseProgram() if len(p.Errors()) is not 0: printParserErrors(p.Errors()) continue evaluator.DefineMacros(program, macroEnv) expanded = evaluator.ExpandMacros(program, macroEnv) evaluator.Eval(expanded, env)
def test_define_macros(self): input = ''' let number = 1; let function = fn(x, y) { x + y }; let mymacro = macro(x, y) { x + y; }; ''' env = object.NewEnvironment() program = testParseProgram(input) evaluator.DefineMacros(program, env) if len(program.Statements) != 2: print(program.String()) self.fail('Wrong number of statements. got=%s' % len(program.Statements)) ok = env.Get('number') if ok: self.fail('number should not be defined') ok = env.Get("function") if ok: self.fail('function should not be defined') obj = env.Get("mymacro") if not obj: self.fail('macro not in environment.') macro = obj if not macro: self.fail('object is not Macro. got=%s (%s)' % (obj, obj)) if len(macro.Parameters) != 2: self.fail('Wrong number of macro parameters. got=%s' % len(macro.Parameters)) if macro.Parameters[0].String() != 'x': self.fail('parameter is not \'x\'. got=%s' % macro.Parameters[0]) if macro.Parameters[1].String() != 'y': self.fail('parameter is not \'y\'. got=%s' % macro.Parameters[1]) expectedBody = '(x + y)' if macro.Body.String() != expectedBody: self.fail('body is not %s. got=%s' % (expectedBody, macro.Body.String()))
def main() -> None: argparser = argparse.ArgumentParser(description='') argparser.add_argument('infile', nargs='?', type=argparse.FileType('r')) args = argparser.parse_args() if args.infile: body = args.infile.read() if body: env = object.NewEnvironment() lex = lexer.New(body) p = parser.New(lex) program = p.ParseProgram() if len(p.Errors()) is not 0: for msg in p.Errors(): print('\t' + msg) return evaluator.Eval(program, env) else: user = getpass.getuser() print('Hello {}! This is the Monkey programming language!\n'.format( user), end='') print('Feel free to type in commands\n', end='') repl.Start()
def test_expand_macros(self): @dataclass class Test: input: str expected: str tests: List[Test] = [ Test( '''let infixExpression = macro() { quote(1 + 2); }; infixExpression();''', '(1 + 2)'), Test( '''let reverse = macro(a, b) { quote(unquote(b) - unquote(a)); }; reverse(2 + 2, 10 - 5);''', '(10 - 5) - (2 + 2)'), Test( ''' let unless = macro(condition, consequence, alternative) { quote(if (!(unquote(condition))) { unquote(consequence); } else { unquote(alternative); }); }; unless(10 > 5, puts("not greater"), puts("greater")); ''', 'if (!(10 > 5)) { puts("not greater") } else { puts("greater") }'), ] for tt in tests: expected = testParseProgram(tt.expected) program = testParseProgram(tt.input) env = object.NewEnvironment() evaluator.DefineMacros(program, env) expanded = evaluator.ExpandMacros(program, env) if expanded.String() != expected.String(): self.fail('not equal. want=%s, got=%s' % (expected.String(), expanded.String()))
def testEval(input: str) -> object.Object: lex = lexer.New(input) p = parser.New(lex) program = p.ParseProgram() env = object.NewEnvironment() return evaluator.Eval(program, env)