예제 #1
0
    def visit_Quote(self, quote: sexp.Quote) -> None:
        if isinstance(quote.expr, sexp.SSym):
            self.quoted = True
            super().visit(quote.expr)
            return

        is_list = isinstance(quote.expr, sexp.SPair) and quote.expr.is_list
        assert quote.expr is sexp.Nil or is_list

        quoted_exprs = list(cast(sexp.SList, quote.expr))
        nil_var = bytecode.Var(next(self.var_names))
        nil_alloc = bytecode.AllocInst(
            nil_var, bytecode.NumLit(sexp.SNum(0)))

        cdr = nil_var
        self.parent_block.add_inst(nil_alloc)

        for expr in reversed(quoted_exprs):
            pair_var = bytecode.Var(next(self.var_names))
            pair_alloc = bytecode.AllocInst(
                pair_var, bytecode.NumLit(sexp.SNum(2)))
            self.parent_block.add_inst(pair_alloc)

            expr_emitter = ExpressionEmitter(
                self.parent_block, self.bb_names, self.var_names,
                self.local_env, self.global_env,
                quoted=True,
                function_entrypoint=self._function_entrypoint,
                tail_calls=self._tail_calls,
                expr_types=self._expr_types)
            expr_emitter.visit(expr)

            store_car = bytecode.StoreInst(
                pair_var, bytecode.NumLit(sexp.SNum(0)), expr_emitter.result)
            self.parent_block.add_inst(store_car)

            store_cdr = bytecode.StoreInst(
                pair_var, bytecode.NumLit(sexp.SNum(1)), cdr
            )
            self.parent_block.add_inst(store_cdr)

            cdr = pair_var

        self.result = cdr
예제 #2
0
    def visit_SCall(self, call: sexp.SCall) -> None:
        assert not self.quoted, 'Non-primitives in quoted list unsupported'

        if self._is_true_assertion(call):
            self.result = bytecode.NumLit(sexp.SNum(0))
            return

        tail_call_data = self._get_tail_call_data(call)
        is_known_function = self._is_known_function(call)
        arity_known_correct = self._arity_known_correct(
            call, is_known_function, tail_call_data)
        tail_call_args_compatible = self._tail_call_args_compatible(
            call, tail_call_data)

        func_to_call = self._get_func_to_call(
            call, is_known_function,
            arity_known_correct, tail_call_data, tail_call_args_compatible)

        args = self._emit_args(call)

        if tail_call_data is not None and func_to_call is None:
            for arg, param in zip(args, tail_call_data.func_params):
                local_var = self.local_env[param]
                if arg != local_var:
                    self.end_block.add_inst(bytecode.CopyInst(local_var, arg))

            assert self._function_entrypoint is not None
            self.end_block.add_inst(
                bytecode.JmpInst(self._function_entrypoint))

            # We need a placeholder result since we're jumping back
            # to the beginning of the function
            self.result = bytecode.NumLit(sexp.SNum(0))
        else:
            assert func_to_call is not None
            call_result_var = bytecode.Var(next(self.var_names))
            call_instr = bytecode.CallInst(
                call_result_var, func_to_call, args,
                specialization=self._get_arg_types(call))

            self.end_block.add_inst(call_instr)
            self.result = call_result_var
예제 #3
0
 def _add_arity_check(
         self, function_expr: bytecode.Parameter,
         add_to_block: bytecode.BasicBlock, arity: int) -> None:
     arity_var = bytecode.Var(next(self.var_names))
     add_to_block.add_inst(bytecode.ArityInst(arity_var, function_expr))
     correct_arity_var = bytecode.Var(next(self.var_names))
     add_to_block.add_inst(bytecode.BinopInst(
         correct_arity_var, bytecode.Binop.NUM_EQ,
         arity_var, bytecode.NumLit(sexp.SNum(arity))
     ))
     add_to_block.add_inst(bytecode.BrnInst(correct_arity_var, ARITY_TRAP))
예제 #4
0
    def visit_SVect(self, vect: sexp.SVect) -> None:
        var = bytecode.Var(next(self.var_names))
        instr = bytecode.AllocInst(
            var, bytecode.NumLit(sexp.SNum(len(vect.items))))
        self.parent_block.add_inst(instr)
        self.result = var

        parent_block = self.parent_block
        for (i, expr) in enumerate(vect.items):
            expr_emitter = ExpressionEmitter(
                parent_block, self.bb_names, self.var_names,
                self.local_env, self.global_env,
                function_entrypoint=self._function_entrypoint,
                tail_calls=self._tail_calls,
                expr_types=self._expr_types)
            expr_emitter.visit(expr)
            parent_block = expr_emitter.end_block

            store = bytecode.StoreInst(
                var, bytecode.NumLit(sexp.SNum(i)), expr_emitter.result)
            parent_block.add_inst(store)
예제 #5
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)
예제 #6
0
 def to_param(self) -> bytecode.NumLit:
     return bytecode.NumLit(self)
예제 #7
0
 def visit_SNum(self, num: sexp.SNum) -> None:
     self.result = bytecode.NumLit(num)