Replace the selfcall opcode with "self" to get ref to current fun
This commit is contained in:
parent
00c874957b
commit
ab9377fe33
5 changed files with 30 additions and 31 deletions
|
@ -127,7 +127,7 @@ struct Context {
|
|||
// If parent has no variable with name <sym>, then we need to propagate
|
||||
// the closure to it. The variable may be defined somewhere in outer
|
||||
// scope.
|
||||
if (!maybe_var.has_value()) {
|
||||
if (!maybe_var.has_value() && TRY(fname.cmp(sym)) != 0) {
|
||||
TRY(parent->get_closure(sym));
|
||||
}
|
||||
}
|
||||
|
@ -798,6 +798,14 @@ Result<Expression> Compiler::compile_fn(Context& context, Symbol& op,
|
|||
continue;
|
||||
}
|
||||
|
||||
// If this is a reference to current function name - use a special opcode
|
||||
// "self" to get the value of the function
|
||||
if (TRY(sym.cmp(context.fname)) == 0) {
|
||||
uint64_t vr = context.alloc_reg();
|
||||
TRY(ex_res.add_opcode(Oc::Self, {0, (int64_t)vr}));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise this can be a variable we get from the intermediate closure
|
||||
// (such as in case of 3 nested functions where a var we close over is
|
||||
// defined in the outermost function.
|
||||
|
@ -966,18 +974,9 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
|||
auto first_unwrapped = TRY(syntax_unwrap(first));
|
||||
auto param = TRY(expr.rest());
|
||||
|
||||
bool is_self_call = false;
|
||||
uint64_t firstreg = context.maxreg;
|
||||
if (first_unwrapped.is<Symbol>() &&
|
||||
TRY(first_unwrapped.cmp(context.fname)) == 0) {
|
||||
int64_t r = context.alloc_reg();
|
||||
int64_t c = TRY(context.add_const(TRY(Nil::create())));
|
||||
TRY(ex.add_opcode(Oc::Mov, {0, (int64_t)r}, {1, (int64_t)c}));
|
||||
is_self_call = true;
|
||||
} else {
|
||||
auto fun_ex = TRY(compile_expr(context, first));
|
||||
TRY(ex.add_code(fun_ex.code));
|
||||
}
|
||||
auto fun_ex = TRY(compile_expr(context, first));
|
||||
TRY(ex.add_code(fun_ex.code));
|
||||
|
||||
int64_t maxreg = context.maxreg;
|
||||
while (!param.is<Nil>()) {
|
||||
|
@ -989,13 +988,8 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
|||
param = TRY(param.rest());
|
||||
}
|
||||
|
||||
if (is_self_call) {
|
||||
TRY(ex.add_opcode(Oc::SelfCall, {0, (int64_t)firstreg},
|
||||
{0, (int64_t)context.maxreg}));
|
||||
} else {
|
||||
TRY(ex.add_opcode(Oc::Call, {0, (int64_t)firstreg},
|
||||
{0, (int64_t)context.maxreg}));
|
||||
}
|
||||
TRY(ex.add_opcode(Oc::Call, {0, (int64_t)firstreg},
|
||||
{0, (int64_t)context.maxreg}));
|
||||
|
||||
ex.reg = firstreg;
|
||||
context.maxreg = maxreg;
|
||||
|
@ -1093,6 +1087,14 @@ Result<Expression> Compiler::compile_symbol(Context& context,
|
|||
return std::move(ex);
|
||||
}
|
||||
|
||||
if (TRY(unwrapped.cmp(context.fname)) == 0) {
|
||||
uint64_t reg = context.alloc_reg();
|
||||
TRY(ex.add_opcode(Oc::Self, {0, (int64_t)reg}));
|
||||
|
||||
ex.reg = reg;
|
||||
return std::move(ex);
|
||||
}
|
||||
|
||||
if (unwrapped.is<Symbol>()) {
|
||||
auto maybe_stdlib_fun = get_stdlib_function(*unwrapped.to<Symbol>());
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ op_t get_op(Oc op) {
|
|||
return op_t{"less-equal", OpcodeType::Reg2I};
|
||||
case Oc::Call:
|
||||
return op_t{"call", OpcodeType::Reg2};
|
||||
case Oc::SelfCall:
|
||||
return op_t{"selfcall", OpcodeType::Reg2};
|
||||
case Oc::Self:
|
||||
return op_t{"self", OpcodeType::Reg1};
|
||||
case Oc::TailCall:
|
||||
return op_t{"tailcall", OpcodeType::Reg1I};
|
||||
case Oc::Ret:
|
||||
|
|
|
@ -33,7 +33,7 @@ enum class Oc : uint8_t {
|
|||
LessEqual,
|
||||
// Function calls
|
||||
Call,
|
||||
SelfCall,
|
||||
Self,
|
||||
TailCall,
|
||||
// Return from function call
|
||||
Ret,
|
||||
|
|
13
src/vm.cpp
13
src/vm.cpp
|
@ -161,16 +161,13 @@ Result<void> VM::vm_call(Opcode& oc) {
|
|||
return ERROR(TypeMismatch);
|
||||
}
|
||||
|
||||
Result<void> VM::vm_selfcall(Opcode& oc) {
|
||||
Result<void> VM::vm_self(Opcode& oc) {
|
||||
auto fun = TRY(_stack.fun());
|
||||
if (!fun.is<Function>()) return ERROR(TypeMismatch);
|
||||
Function& lisp_fun = *fun.to<Function>();
|
||||
uint64_t reg = (uint64_t)oc.arg1().arg;
|
||||
|
||||
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||
_stack = TRY(setreg(reg, fun));
|
||||
|
||||
_stack = TRY(_stack.incpc());
|
||||
_stack = TRY(_stack.call(fun, reg_start, reg_end));
|
||||
|
||||
return Result<void>();
|
||||
}
|
||||
|
@ -280,8 +277,8 @@ Result<void> VM::step_bytecode() {
|
|||
case Oc::Call:
|
||||
TRY(vm_call(oc));
|
||||
break;
|
||||
case Oc::SelfCall:
|
||||
TRY(vm_selfcall(oc));
|
||||
case Oc::Self:
|
||||
TRY(vm_self(oc));
|
||||
break;
|
||||
case Oc::MakeClosure:
|
||||
TRY(vm_make_closure(oc));
|
||||
|
|
|
@ -46,7 +46,7 @@ class VM {
|
|||
Result<void> vm_sub(Opcode& oc);
|
||||
Result<void> vm_div(Opcode& oc);
|
||||
Result<void> vm_call(Opcode& oc);
|
||||
Result<void> vm_selfcall(Opcode& oc);
|
||||
Result<void> vm_self(Opcode& oc);
|
||||
Result<void> vm_call_lisp(Opcode& oc, Function& fun);
|
||||
Result<void> vm_call_stdlib(Opcode& oc, StdlibFunction& fun);
|
||||
Result<void> vm_call_cont(Opcode& oc, Continuation& fun);
|
||||
|
|
Loading…
Reference in a new issue