def test_lambda(self) -> None: prog = '(lambda (spam egg) (+ spam egg)) (lambda () 42)' self.assertEqual([ SFunction( SSym('__lambda0'), [SSym('spam'), SSym('egg')], sexp.to_slist([SCall(SSym('+'), [SSym('spam'), SSym('egg')])]), is_lambda=True), SFunction(SSym('__lambda1'), [], sexp.to_slist([SNum(42)]), is_lambda=True), ], sexp.parse(prog))
def test_function_def(self) -> None: prog = '(define (funcy spam egg) (+ spam egg)) (funcy 42 43)' self.assertEqual([ SFunction( SSym('funcy'), [SSym('spam'), SSym('egg')], sexp.to_slist([SCall(SSym('+'), [SSym('spam'), SSym('egg')])])), SCall(SSym('funcy'), [SNum(42), SNum(43)]) ], sexp.parse(prog))
def test_quote(self) -> None: self.assertEqual([Quote(SSym('spam'))], sexp.parse("'spam")) self.assertEqual([Quote(Nil)], sexp.parse("'()")) self.assertEqual([Quote(Nil)], sexp.parse("(quote ())")) self.assertEqual([ Quote(sexp.to_slist( [SSym('if'), SBool(True), SNum(2), SNum(3)])) ], sexp.parse("'(if true 2 3)")) self.assertEqual( [Quote(sexp.to_slist([SNum(1), SNum(2), SNum(3)]))], sexp.parse("(quote (1 2 3))")) self.assertEqual(sexp.parse("'(1 2 3)"), sexp.parse("(quote (1 2 3))")) self.assertEqual(str(sexp.parse("(quote (1 2 3))")[0]), "'(1 2 3)")
def test_lambda_called_inline(self) -> None: self.maxDiff = None prog = '((lambda (spam egg) (+ spam egg)) 42 43)' self.assertEqual([ SCall( SFunction(SSym('__lambda0'), [SSym('spam'), SSym('egg')], sexp.to_slist( [SCall(SSym('+'), [SSym('spam'), SSym('egg')])]), is_lambda=True), [SNum(42), SNum(43)]) ], sexp.parse(prog))
def test_to_slist(self) -> None: self.assertEqual( sexp.to_slist([SNum(1), SNum(2), SNum(3)]), SPair( SNum(1), SPair( SNum(2), SPair( SNum(3), Nil, ), ), ))
def test_comments(self) -> None: prog = """ ;;; We want to define a cool function here! (define ; hi ;; A function name (cool-func x y) ; wow ;; branches are cheaper than subtraction, right? :P (if (= x y) 0 (- x y))) """ self.assertEqual([ SFunction( SSym('cool-func'), [SSym('x'), SSym('y')], sexp.to_slist([ SConditional( SCall(SSym('='), [SSym('x'), SSym('y')]), SNum(0), SCall(SSym('-'), [SSym('x'), SSym('y')])) ])) ], sexp.parse(prog))
def test_call_specialized(self) -> None: bb0 = bytecode.BasicBlock("bb0") bb0.add_inst(bytecode.ReturnInst(BoolLit(SBool(False)))) byte_func = bytecode.Function([Var("x")], bb0) bb0_specialized = bytecode.BasicBlock("bb0") bb0_specialized.add_inst(bytecode.ReturnInst(BoolLit(SBool(True)))) byte_func_specialized = bytecode.Function([Var("x")], bb0_specialized) func = sexp.SFunction( SSym("func"), [SSym("x")], sexp.to_slist([]), code=byte_func, is_lambda=False, specializations={ (scheme_types.SchemeSym, ): byte_func_specialized }, ) env = bytecode.EvalEnv(local_env={Var('f'): func}) bytecode.CallInst(Var('y'), Var('f'), [NumLit(SNum(42))]).run(env) assert env[Var('y')] == SBool(False) bytecode.CallInst(Var('y'), Var('f'), [SymLit(SSym('x'))]).run(env) assert env[Var('y')] == SBool(True) bytecode.CallInst(Var('y'), Var('f'), [SymLit(SSym('x'))], specialization=(scheme_types.SchemeSym, )).run(env) assert env[Var('y')] == SBool(True) # If specialization not found, fall back to dynamic dispatch bytecode.CallInst(Var('y'), Var('f'), [SymLit(SSym('x'))], specialization=(scheme_types.SchemeNum, )).run(env) self.assertEqual(env[Var('y')], SBool(True)) bytecode.CallInst(Var('y'), Var('f'), [NumLit(SNum(42))], specialization=(scheme_types.SchemeNum, )).run(env) self.assertEqual(env[Var('y')], SBool(False))
def run_code(env: EvalEnv, code: SExp, context: str = "top-level") -> Value: """Run a piece of code in an environment, returning its result.""" if isinstance(code, sexp.SFunction): tail_calls = None if env.optimize_tail_calls: tail_call_finder = TailCallFinder() tail_call_finder.visit(code) tail_calls = tail_call_finder.tail_calls type_analyzer = None if env.jit: type_analyzer = scheme_types.FunctionTypeAnalyzer( {}, env._global_env) type_analyzer.visit(code) emitter = FunctionEmitter( env._global_env, tail_calls=tail_calls, expr_types=type_analyzer) emitter.visit(code) _add_func_to_env(code, emitter, env) assert code.code if env.bytecode_jit: if env.print_optimizations: print(f"Optimizing {context} function {code.name}...") opt = FunctionOptimizer(code.code) opt.optimize(env) return env._global_env[code.name] else: name = SSym(f'{next(eval_names)}') code = sexp.SFunction( name, [], sexp.to_slist([code]), is_lambda=True) emitter = FunctionEmitter(env._global_env) emitter.visit(code) function = emitter.get_emitted_func() gen = bytecode.ResultGenerator(function.run(env)) gen.run() assert gen.value is not None return gen.value