예제 #1
0
    def test_intrinsics(self) -> None:
        env = bytecode.EvalEnv()
        runner.add_intrinsics(env)

        self.assertEqual(run(env, '(inst/typeof 42)'), SSym('number'))
        self.assertEqual(run(env, '(inst/typeof [1 2 3])'), SSym('vector'))
        self.assertEqual(run(env, "(inst/typeof 'hi)"), SSym('symbol'))
        with self.assertRaises(errors.Trap, msg="(trap)"):
            run(env, '(inst/trap)')
        self.assertEqual(run(env, '(inst/length (inst/alloc 42))'), SNum(42))
        self.assertEqual(
            run(env, '(inst/load (inst/store (inst/alloc 8) 3 42) 3)'),
            SNum(42))

        self.assertEqual(run(env, '(inst/+ 18 24)'), SNum(18 + 24))
        self.assertEqual(run(env, '(inst/- 18 24)'), SNum(18 - 24))
        self.assertEqual(run(env, '(inst/* 18 24)'), SNum(18 * 24))
        self.assertEqual(run(env, '(inst// 18 24)'), SNum(18 // 24))
        self.assertEqual(run(env, '(inst/% 18 24)'), SNum(18 % 24))

        self.assertEqual(run(env, '(inst/number= 18 18)'), SBool(True))
        self.assertEqual(run(env, '(inst/number= 18 -18)'), SBool(False))
        self.assertEqual(run(env, "(inst/symbol= 'hi 'hey)"), SBool(False))
        self.assertEqual(run(env, "(inst/symbol= 'hi 'hi)"), SBool(True))
        self.assertEqual(run(env, "(inst/pointer= [] 0)"), 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)),
                '((lambda (x) (inst/pointer= x x)) [1])'), SBool(True))
        self.assertEqual(run(env, '(inst/number< -1 0)'), SBool(True))
예제 #2
0
 def test_dataflow_unstable_type(self) -> None:
     func, blocks = make_branch_func_object()
     bb0, bb1, bb2, bb3 = blocks
     opt = FunctionOptimizer(func)
     opt.dataflow(bytecode.EvalEnv())
     after_0 = (TypeMap({Var('v0'):
                         SchemeNum}), ValueMap({Var('v0'): SNum(42)}))
     self.assertEqual(opt.block_input_maps(bb1), after_0)
     self.assertEqual(opt.block_input_maps(bb2), after_0)
     self.assertEqual(
         opt.block_input_maps(bb3),
         (TypeMap({Var('v0'): SchemeObject}), ValueMap()),
     )
     self.assertEqual(
         opt.info, {
             id(bb0): [(TypeMap(), ValueMap()), after_0, after_0, after_0],
             id(bb1): [
                 after_0,
                 (TypeMap({Var('v0'): SchemeNum
                           }), ValueMap({Var('v0'): SNum(69)})),
                 (TypeMap({Var('v0'): SchemeNum
                           }), ValueMap({Var('v0'): SNum(69)})),
             ],
             id(bb2): [
                 after_0,
                 (TypeMap({Var('v0'): SchemeSym
                           }), ValueMap({Var('v0'): SSym('hi')})),
                 (TypeMap({Var('v0'): SchemeSym
                           }), ValueMap({Var('v0'): SSym('hi')})),
             ],
             id(bb3): [
                 (TypeMap({Var('v0'): SchemeObject}), ValueMap()),
                 (TypeMap({Var('v0'): SchemeObject}), ValueMap()),
             ],
         })
예제 #3
0
 def test_parse_atoms(self) -> None:
     self.assertEqual(sexp.parse("hi"), [SSym("hi")])
     self.assertEqual(sexp.parse("hi hey hoi"), [
         SSym("hi"),
         SSym("hey"),
         SSym("hoi"),
     ])
     self.assertEqual(sexp.parse("42 foo"), [SNum(42), SSym("foo")])
예제 #4
0
    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)")
예제 #5
0
 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))
예제 #6
0
    def test_example_tail_call(self) -> None:
        """
        function list? (v0) entry=bb0
        bb0:
            v1 = lookup 'nil?
            v2 = call v1 (v0)
            br v2 bb1
            v3 = lookup 'pair?
            v4 = call v3 (v0)
            brn v4 bb2
            v5 = lookup 'cdr
            v0 = call v5 (v0)
            jmp bb0

        bb1:
            return 'true

        bb2:
            return 'false
        """
        bb0 = bytecode.BasicBlock("bb0")
        bb1 = bytecode.BasicBlock("bb1")
        bb2 = bytecode.BasicBlock("bb2")
        is_list = bytecode.Function([Var("v0")], bb0)

        bb0.add_inst(bytecode.LookupInst(Var("v1"), SymLit(SSym("nil?"))))
        bb0.add_inst(bytecode.CallInst(Var("v2"), Var("v1"), [Var("v0")]))
        bb0.add_inst(bytecode.BrInst(Var("v2"), bb1))
        bb0.add_inst(bytecode.LookupInst(Var("v3"), SymLit(SSym("pair?"))))
        bb0.add_inst(bytecode.CallInst(Var("v4"), Var("v3"), [Var("v0")]))
        bb0.add_inst(bytecode.BrnInst(Var("v4"), bb2))
        bb0.add_inst(bytecode.LookupInst(Var("v5"), SymLit(SSym("global"))))
        bb0.add_inst(bytecode.CallInst(Var("v0"), Var("v5"), [Var("v0")]))
        bb0.add_inst(bytecode.JmpInst(bb0))

        bb1.add_inst(bytecode.ReturnInst(SymLit(SSym("true"))))

        bb2.add_inst(bytecode.ReturnInst(SymLit(SSym("false"))))

        assert is_list
예제 #7
0
    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))
예제 #8
0
 def inst_function(
         name: SSym, params: List[Var],
         return_val: Optional[bytecode.Parameter], *insts: Inst,
         ) -> SFunction:
     """Create a function out of the instructions in insts."""
     begin = BasicBlock('bb0')
     for inst in insts:
         begin.add_inst(inst)
     if return_val is not None:
         begin.add_inst(bytecode.ReturnInst(return_val))
     code = Function(params, begin)
     param_syms = [SSym(p.name) for p in params]
     return SFunction(name, param_syms, Nil, code, False)
예제 #9
0
 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))
예제 #10
0
 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))
예제 #11
0
def make_branch_func_object() -> Tuple[Function, Tuple[BasicBlock, ...]]:
    bb0 = BasicBlock("bb0")
    bb1 = BasicBlock("bb1")
    bb2 = BasicBlock("bb2")
    bb3 = BasicBlock("bb3")
    bb0.add_inst(bytecode.CopyInst(Var('v0'), NumLit(SNum(42))))
    bb0.add_inst(bytecode.BrInst(Var('x'), bb1))
    bb0.add_inst(bytecode.JmpInst(bb2))
    bb1.add_inst(
        bytecode.BinopInst(Var('v0'), Binop.ADD, Var('v0'), NumLit(SNum(27))))
    bb1.add_inst(bytecode.JmpInst(bb3))
    bb2.add_inst(bytecode.CopyInst(Var('v0'), SymLit(SSym('hi'))))
    bb2.add_inst(bytecode.JmpInst(bb3))
    bb3.add_inst(bytecode.ReturnInst(Var('v0')))
    return Function([Var('x')], bb0), (bb0, bb1, bb2, bb3)
예제 #12
0
 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))
예제 #13
0
    def test_specialize_value(self) -> None:
        env = get_builtins()
        func = env._global_env[SSym('+')]
        assert isinstance(func, sexp.SFunction)
        assert func.code

        code = copy.deepcopy(func.code)
        opt = FunctionOptimizer(code)
        opt.specialization = (SchemeNum, SchemeNum)
        opt.inputs = (SNum(42), SNum(27))
        opt.optimize(env)

        self.assertEqual(
            str(code), '''
function (? a b) entry=bb0
bb0:
  return 69
        '''.strip())
예제 #14
0
    def test_optimize(self) -> None:
        env = get_builtins()
        func = env._global_env[SSym('+')]
        assert isinstance(func, sexp.SFunction)
        assert func.code

        code = copy.deepcopy(func.code)
        self.assertEqual(
            str(code), '''
function (? a b) entry=bb0
bb0:
  inl4@inl1@inl0@result = typeof a
  inl4@inl0@inl0@result = Binop.SYM_EQ inl4@inl1@inl0@result 'number
  brn inl4@inl0@inl0@result bb0.split5
  inl2@inl1@inl0@result = typeof b
  inl2@inl0@inl0@result = Binop.SYM_EQ inl2@inl1@inl0@result 'number
  brn inl2@inl0@inl0@result bb0.split6
  inl0@result = Binop.ADD a b
  return inl0@result

bb0.split5:
  trap '(trap)'

bb0.split6:
  trap '(trap)'
'''.strip())

        opt = FunctionOptimizer(code)
        opt.specialization = (SchemeNum, SchemeNum)
        opt.optimize(env)

        self.assertEqual(
            str(code), '''
function (? a b) entry=bb0
bb0:
  inl0@result = Binop.ADD a b
  return inl0@result
'''.strip())
예제 #15
0
    def test_example_recursive(self) -> None:
        """
        function list? (v0) entry=bb0
        bb0:
            v1 = lookup 'nil?
            v2 = call v1 (v0)
            br v2 bb1
            v3 = lookup 'pair?
            v4 = call v3 (v0)
            brn v4 bb2
            v5 = lookup 'cdr
            v6 = call v5 (v0)
            v7 = lookup 'list?
            v8 = call v7 (v6)
            return v8

        bb1:
            return 'true

        bb2:
            return 'false
        """
        bb0 = bytecode.BasicBlock("bb0")
        bb1 = bytecode.BasicBlock("bb1")
        bb2 = bytecode.BasicBlock("bb2")
        is_list = bytecode.Function([Var("v0")], bb0)

        bb0.add_inst(bytecode.LookupInst(Var("v1"), SymLit(SSym("nil?"))))
        bb0.add_inst(bytecode.CallInst(Var("v2"), Var("v1"), [Var("v1")]))
        bb0.add_inst(bytecode.BrInst(Var("v2"), bb1))
        bb0.add_inst(bytecode.LookupInst(Var("v3"), SymLit(SSym("pair?"))))
        bb0.add_inst(bytecode.CallInst(Var("v4"), Var("v3"), [Var("v0")]))
        bb0.add_inst(bytecode.BrnInst(Var("v4"), bb2))
        bb0.add_inst(bytecode.LookupInst(Var("v5"), SymLit(SSym("cdr"))))
        bb0.add_inst(bytecode.CallInst(Var("v6"), Var("v5"), [Var("v0")]))
        bb0.add_inst(bytecode.LookupInst(Var("v7"), SymLit(SSym("list?"))))
        bb0.add_inst(bytecode.CallInst(Var("v8"), Var("v7"), [Var("v6")]))
        bb0.add_inst(bytecode.ReturnInst(Var("v8")))

        bb1.add_inst(bytecode.ReturnInst(SymLit(SSym("true"))))

        bb2.add_inst(bytecode.ReturnInst(SymLit(SSym("false"))))

        # These tests are just to test the API
        assert is_list
예제 #16
0
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
예제 #17
0
 def symbol(self) -> Optional[sexp.SSym]:
     return SSym('vector')
예제 #18
0
 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)])],
     )
예제 #19
0
def add_intrinsics(eval_env: EvalEnv) -> None:
    """Add intrinsics to the environment."""
    def inst_function(
            name: SSym, params: List[Var],
            return_val: Optional[bytecode.Parameter], *insts: Inst,
            ) -> SFunction:
        """Create a function out of the instructions in insts."""
        begin = BasicBlock('bb0')
        for inst in insts:
            begin.add_inst(inst)
        if return_val is not None:
            begin.add_inst(bytecode.ReturnInst(return_val))
        code = Function(params, begin)
        param_syms = [SSym(p.name) for p in params]
        return SFunction(name, param_syms, Nil, code, False)

    def binop(name: SSym, op: Binop) -> SFunction:
        return inst_function(
            name, [Var('a'), Var('b')], result,
            bytecode.BinopInst(result, op, Var('a'), Var('b')))

    result = Var('result')
    env = eval_env._global_env
    env[SSym('inst/typeof')] = inst_function(
        SSym('inst/typeof'), [Var('x')], result,
        bytecode.TypeofInst(result, Var('x')))
    env[SSym('inst/trap')] = inst_function(
        SSym('inst/trap'), [], None,
        bytecode.TrapInst("(trap)"))
    env[SSym('inst/trace')] = inst_function(
        SSym('inst/trace'), [Var('x')], Var('x'),
        bytecode.TraceInst(Var('x')))
    env[SSym('inst/display')] = inst_function(
        SSym('inst/display'), [Var('x')], bytecode.NumLit(sexp.SNum(0)),
        bytecode.DisplayInst(Var('x')))
    env[SSym('inst/newline')] = inst_function(
        SSym('inst/newline'), [], bytecode.NumLit(sexp.SNum(0)),
        bytecode.NewlineInst())
    env[SSym('inst/breakpoint')] = inst_function(
        SSym('inst/breakpoint'), [], bytecode.NumLit(sexp.SNum(0)),
        bytecode.BreakpointInst())
    # Memory operations
    env[SSym('inst/alloc')] = inst_function(
        SSym('inst/alloc'), [Var('n')], result,
        bytecode.AllocInst(result, Var('n')))
    env[SSym('inst/load')] = inst_function(
        SSym('inst/load'), [Var('v'), Var('n')], result,
        bytecode.LoadInst(result, Var('v'), Var('n')))
    env[SSym('inst/store')] = inst_function(
        SSym('inst/store'), [Var('v'), Var('n'), Var('x')], Var('v'),
        bytecode.StoreInst(Var('v'), Var('n'), Var('x')))
    env[SSym('inst/length')] = inst_function(
        SSym('inst/length'), [Var('v')], result,
        bytecode.LengthInst(result, Var('v')))
    # Binary operators
    env[SSym('inst/+')] = binop(SSym('inst/+'), Binop.ADD)
    env[SSym('inst/-')] = binop(SSym('inst/-'), Binop.SUB)
    env[SSym('inst/*')] = binop(SSym('inst/*'), Binop.MUL)
    env[SSym('inst//')] = binop(SSym('inst//'), Binop.DIV)
    env[SSym('inst/%')] = binop(SSym('inst/%'), Binop.MOD)
    env[SSym('inst/number=')] = binop(SSym('inst/number='), Binop.NUM_EQ)
    env[SSym('inst/symbol=')] = binop(SSym('inst/symbol='), Binop.SYM_EQ)
    env[SSym('inst/pointer=')] = binop(SSym('inst/pointer='), Binop.PTR_EQ)
    env[SSym('inst/number<')] = binop(SSym('inst/number<'), Binop.NUM_LT)
예제 #20
0
    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))
예제 #21
0
 def symbol(self) -> Optional[sexp.SSym]:
     return SSym('number')
예제 #22
0
 def symbol(self) -> Optional[sexp.SSym]:
     return SSym('symbol')
예제 #23
0
    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)]))
예제 #24
0
 def symbol(self) -> Optional[sexp.SSym]:
     return SSym('function')