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_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 test_block_transfer(self) -> None: func = make_func() opt = FunctionOptimizer(func) data = opt.block_transfer(bytecode.EvalEnv(), func.start, TypeMap(), ValueMap()) self.assertEqual(data, [ (TypeMap(), ValueMap()), (TypeMap({Var('v0'): SchemeNum}), ValueMap({Var('v0'): SNum(42)})), (TypeMap({ Var('v0'): SchemeNum, Var('v1'): SchemeNum }), ValueMap({ Var('v0'): SNum(42), Var('v1'): SNum(111) })), (TypeMap({ Var('v0'): SchemeNum, Var('v1'): SchemeNum }), ValueMap({ Var('v0'): SNum(42), Var('v1'): SNum(111) })), ])
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_builtins(self) -> None: env = bytecode.EvalEnv() runner.add_intrinsics(env) runner.add_builtins(env) with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(trap)') with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(assert false)') self.assertEqual(run(env, '(typeof 42)'), SSym('number')) self.assertEqual(run(env, '(typeof [1 2 3])'), SSym('vector')) self.assertEqual(run(env, "(typeof 'hi)"), SSym('symbol')) self.assertEqual(run(env, '(not true)'), SBool(False)) self.assertEqual(run(env, '(not false)'), SBool(True)) with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(not 42)') self.assertEqual(run(env, '(number? 42)'), SBool(True)) self.assertEqual(run(env, '(number? [])'), SBool(False)) self.assertEqual(run(env, "(symbol? 'hi)"), SBool(True)) self.assertEqual(run(env, '(symbol? 42)'), SBool(False)) self.assertEqual(run(env, '(vector? [])'), SBool(True)) self.assertEqual(run(env, '(vector? 42)'), SBool(False)) # Use a copy of the environment, since (lambda) adds a name to # the environment. self.assertEqual( run(bytecode.EvalEnv({}, dict(env._global_env)), '(function? (lambda () []))'), SBool(True)) self.assertEqual(run(env, '(function? 42)'), SBool(False)) self.assertEqual(run(env, '(bool? true)'), SBool(True)) self.assertEqual(run(env, '(bool? false)'), SBool(True)) self.assertEqual(run(env, '(bool? 42)'), SBool(False)) self.assertEqual(run(env, '(pair? 42)'), SBool(False)) self.assertEqual(run(env, '(pair? [])'), SBool(False)) self.assertEqual(run(env, '(pair? [1])'), SBool(False)) self.assertEqual(run(env, '(pair? [1 2])'), SBool(True)) self.assertEqual(run(env, '(nil? [1 2])'), SBool(False)) self.assertEqual(run(env, '(nil? [])'), SBool(True)) self.assertEqual(run(env, '(+ 39 13)'), SNum(39 + 13)) self.assertEqual(run(env, '(- 39 13)'), SNum(39 - 13)) self.assertEqual(run(env, '(* 39 13)'), SNum(39 * 13)) self.assertEqual(run(env, '(/ 39 13)'), SNum(39 // 13)) self.assertEqual(run(env, '(% 39 13)'), SNum(39 % 13)) for op in '+-*/%': with self.assertRaises(errors.Trap, msg="(trap)"): run(env, f'({op} 39 [])') with self.assertRaises(errors.Trap, msg="(trap)"): run(env, f'({op} [] 13)') with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(/ 1 0)') with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(% 1 0)') with self.assertRaises(errors.Trap, msg="(trap)"): run(env, '(symbol= 1 0)') self.assertEqual(run(env, "(symbol= 'a 'b)"), SBool(False)) self.assertEqual(run(env, "(symbol= 'a 'a)"), SBool(True)) # Use a copy of the environment, since (lambda) adds a name to # the environment. self.assertEqual( run(bytecode.EvalEnv({}, dict(env._global_env)), "(pointer= (lambda () 0) (lambda () 0))"), SBool(False)) self.assertEqual(run(env, "(define (func) 42) (pointer= func func)"), SBool(True)) self.assertEqual(run(env, "(pointer= 0 0)"), SBool(True)) with self.assertRaises(errors.Trap, msg="(trap)"): run(env, "(number= 'num 1)") self.assertEqual(run(env, "(number= 42 43)"), SBool(False)) self.assertEqual(run(env, "(number= 42 42)"), SBool(True)) with self.assertRaises(errors.Trap, msg="(trap)"): run(env, "(number< 'num 1)") self.assertEqual(run(env, "(number< 42 42)"), SBool(False)) self.assertEqual(run(env, "(number< 42 43)"), SBool(True)) self.assertEqual(run(env, '(vector-length [1 2 3])'), SNum(3)) self.assertEqual(run(env, '(vector-index [1 2 3] 1)'), SNum(2)) self.assertEqual(run(env, '(vector-set! [1 2 3] 1 42)'), SVect([SNum(1), SNum(42), SNum(3)])) self.assertEqual(run(env, '(vector-make 4 9)'), SVect([SNum(9), SNum(9), SNum(9), SNum(9)]))
def run(self, env: EvalEnv) -> None: func = env[self.func] assert isinstance(func, sexp.SFunction), func env[self.dest] = SNum(len(func.params))
def run(self, env: EvalEnv) -> None: vect = env[self.addr] assert isinstance(vect, SVect), vect env[self.dest] = SNum(len(vect.items))
def test_example_inlined(self) -> None: """ function list? (v0) entry=bb0 bb0: v1 = typeof v0 v2 = sym_eq v1 'vector brn v2 false v3 = length v0 v4 = num_eq v3 0 br v4 true v5 = num_eq v3 2 brn v5 false v0 = load v0 [1] jmp bb0 true: return 'true false: return 'false """ bb0 = bytecode.BasicBlock("bb0") true = bytecode.BasicBlock("true") false = bytecode.BasicBlock("false") is_list = bytecode.Function([Var("v0")], bb0) # These tests are just to test the API bb0.add_inst(bytecode.TypeofInst(Var("v1"), Var("v0"))) bb0.add_inst( bytecode.BinopInst(Var("v2"), Binop.SYM_EQ, Var("v1"), SymLit(SSym("vector")))) bb0.add_inst(bytecode.BrnInst(Var("v2"), false)) bb0.add_inst(bytecode.LengthInst(Var("v3"), Var("v0"))) bb0.add_inst( bytecode.BinopInst(Var("v4"), Binop.NUM_EQ, Var("v3"), NumLit(SNum(0)))) bb0.add_inst(bytecode.BrInst(Var("v4"), true)) bb0.add_inst( bytecode.BinopInst(Var("v5"), Binop.NUM_EQ, Var("v3"), NumLit(SNum(2)))) bb0.add_inst(bytecode.BrnInst(Var("v5"), false)) bb0.add_inst(bytecode.LoadInst(Var("v0"), Var("v0"), NumLit(SNum(1)))) bb0.add_inst(bytecode.JmpInst(bb0)) true.add_inst(bytecode.ReturnInst(BoolLit(SBool(True)))) false.add_inst(bytecode.ReturnInst(BoolLit(SBool(False)))) env = bytecode.EvalEnv(local_env={Var("v0"): SNum(42)}) gen = bytecode.ResultGenerator(is_list.run(env)) gen.run() self.assertEqual(gen.value, SBool(False)) env = bytecode.EvalEnv(local_env={ Var("v0"): SVect([SNum(42), SVect([SNum(69), SVect([])])]) }) gen = bytecode.ResultGenerator(is_list.run(env)) gen.run() self.assertEqual(gen.value, SBool(True))
def test_conditional(self) -> None: prog = '(if true 42 43) (if false 44 45)' self.assertEqual([ SConditional(SBool(True), SNum(42), SNum(43)), SConditional(SBool(False), SNum(44), SNum(45)), ], sexp.parse(prog))
def test_vector(self) -> None: self.assertEqual(sexp.parse("[]"), [SVect([])]) self.assertEqual( sexp.parse("[1 [2 [3 []]]]"), [SVect([SNum(1), SVect([SNum(2), SVect([SNum(3), SVect([])])])])])
def test_parse_list(self) -> None: self.assertEqual(sexp.parse("()"), [Nil]) self.assertEqual( sexp.parse("(func 2 3)"), [SCall(SSym('func'), [SNum(2), SNum(3)])], )