add macro support

This commit is contained in:
Lobo 2026-01-13 18:27:02 -03:00
parent c63c1eaf6e
commit 2e7d05f783
6 changed files with 95 additions and 20 deletions

View file

@ -177,7 +177,7 @@ static int nested_p(Cm *c, O body) {
}
// Compile a closure with `args` and `body`.
static V compile_fn(Cm *c, O args, O body) {
static V compile_fn(Cm *c, O args, O body, I macro) {
// Create an inner compiler context for compiling the closure's body.
Cm ic;
memset(&ic, 0, sizeof(Cm));
@ -204,14 +204,14 @@ static V compile_fn(Cm *c, O args, O body) {
if (rest == NIL && !nested) {
// If the function has no rest argument, and has no nested closures inside
// it, compile using stack locals as an optimization for tail-calls
ic.use_stack_locals = 1;
ic.use_locals = 1;
curr = args;
for (O next = list_next(c->in, &curr); next != NIL;
next = list_next(c->in, &curr))
add_local(&ic, next);
} else {
// Otherwise, fallback to using environment bindings for locals
ic.use_stack_locals = 0;
ic.use_locals = 0;
if (rest != NIL) {
emit(&ic, OP_BIND_REST);
emit16(&ic, add_constant(&ic, rest));
@ -231,7 +231,7 @@ static V compile_fn(Cm *c, O args, O body) {
Z args_idx = add_constant(c, args);
// Compile pushing the closure to the stack.
emit(c, OP_CLOS);
emit(c, macro ? OP_MAC : OP_CLOS);
emit16(c, code_idx);
emit16(c, args_idx);
@ -256,6 +256,8 @@ static V compile_def(Cm *c, O args, I tail) {
emit(c, OP_RET);
}
O vm_apply(In *in, O macro, O args);
// Compile a function application/special form
static V compile_apply(Cm *co, O expr, I tail) {
Pa *p = pair_unwrap(co->in, expr);
@ -278,7 +280,13 @@ static V compile_apply(Cm *co, O expr, I tail) {
return;
} else if (head == co->specials.fn) {
Pa *args = pair_unwrap(co->in, p->tail);
compile_fn(co, args->head, args->tail);
compile_fn(co, args->head, args->tail, 0);
if (tail)
emit(co, OP_RET);
return;
} else if (head == co->specials.mac) {
Pa *args = pair_unwrap(co->in, p->tail);
compile_fn(co, args->head, args->tail, 1);
if (tail)
emit(co, OP_RET);
return;
@ -286,6 +294,17 @@ static V compile_apply(Cm *co, O expr, I tail) {
compile_def(co, p->tail, tail);
return;
}
if (find_local(co, head) == -1) {
O obj = list_assoc(co->in, head, co->in->env);
if (obj != NIL) {
obj = pair_unwrap(co->in, obj)->tail;
if (type(obj) == TYPE_MAC) {
O exp = vm_apply(co->in, obj, p->tail);
compile(co, exp, tail);
return;
}
}
}
}
compile_call(co, head, p->tail, tail);
}
@ -303,6 +322,8 @@ V compile(Cm *co, O expr, I tail) {
co->specials.fn = symbol_make(co->in, "fn");
if (co->specials.def == NIL)
co->specials.def = symbol_make(co->in, "def");
if (co->specials.mac == NIL)
co->specials.mac = symbol_make(co->in, "mac");
switch (ty) {
case TYPE_NIL:
@ -314,7 +335,7 @@ V compile(Cm *co, O expr, I tail) {
emit(co, OP_RET);
break;
case TYPE_SYM:
if (co->use_stack_locals) {
if (co->use_locals) {
int idx = find_local(co, expr);
if (idx >= 0) {
emit(co, OP_GET_LOCAL);