Replace the selfcall opcode with "self" to get ref to current fun

This commit is contained in:
Konstantin Nazarov 2024-11-03 00:51:48 +00:00
parent 00c874957b
commit ab9377fe33
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
5 changed files with 30 additions and 31 deletions

View file

@ -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>());

View file

@ -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:

View file

@ -33,7 +33,7 @@ enum class Oc : uint8_t {
LessEqual,
// Function calls
Call,
SelfCall,
Self,
TailCall,
// Return from function call
Ret,

View file

@ -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));

View file

@ -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);