Add basic lexenv support

This commit is contained in:
2026-01-28 16:07:48 -08:00
parent 76b28c1dc0
commit 22ffac9321
12 changed files with 141 additions and 37 deletions

View File

@ -57,7 +57,23 @@ void lisp_shutdown(void) {
lisp_teardown_stack();
}
DEFUN(eval, "eval", (LispVal * form), "(form)", "") {
static inline LispVal *lookup_variable(LispSymbol *name, LispVal *lexenv) {
LispVal *lexval = Fplist_get(lexenv, name, Qunbound);
if (lexval != Qunbound) {
return lexval;
}
if (name->value == Qunbound) {
// TODO better error
printf("Unbound symbol: ");
debug_print(stdout, name);
fputc('\n', stdout);
abort();
}
return name->value;
}
DEFUN(eval, "eval", (LispVal * form, LispVal *lexenv),
"(form &optional lexenv)", "") {
if (!OBJECTP(form)) {
// fixnum or float
return form;
@ -75,21 +91,12 @@ DEFUN(eval, "eval", (LispVal * form), "(form)", "") {
out_data[i] = Qnil;
}
for (size_t i = 0; i < vec->length; ++i) {
out_data[i] = Feval(vec->data[i]);
out_data[i] = Feval(vec->data[i], lexenv);
}
return newvec;
}
case TYPE_SYMBOL: {
// TODO local bindings
LispSymbol *sym = form;
if (sym->value == Qunbound) {
printf("Unbound symbol: ");
debug_print(stdout, form);
fputc('\n', stdout);
abort();
}
return sym->value;
}
case TYPE_SYMBOL:
return lookup_variable(form, lexenv);
case TYPE_CONS: {
return Ffuncall(XCAR(form), XCDR(form));
}
@ -131,7 +138,7 @@ void debug_print(FILE *file, LispVal *obj) {
}
case TYPE_CONS: {
fputc('(', file);
FOREACH_TAIL(obj, tail) {
DOTAILS(tail, obj) {
if (CONSP(tail)) {
debug_print(file, XCAR(tail));
if (!NILP(XCDR(tail))) {
@ -162,6 +169,32 @@ void debug_print(FILE *file, LispVal *obj) {
}
}
DEFSPECIAL(progn, "progn", (LispVal * forms), "(&rest forms)", "") {
LispVal *rval = Qnil;
DOLIST(form, forms) {
rval = Feval(form, TOP_LEXENV());
}
return rval;
}
DEFSPECIAL(let, "let", (LispVal * bindings, LispVal *body),
"(bindings &rest body)", "") {
CHECK_LISTP(bindings);
copy_parent_lexenv();
DOLIST(binding, bindings) {
if (SYMBOLP(binding)) {
new_lexical_variable(binding, Qnil);
} else if (CONSP(binding) && list_length_eq(binding, 2)) {
new_lexical_variable(FIRST(binding),
Feval(SECOND(binding), TOP_LEXENV()));
} else {
// TODO better error
abort();
}
}
return Fprogn(body);
}
void debug_obj_info(FILE *file, LispVal *obj) {
fprintf(file, "%s -> ", LISP_TYPE_NAMES[TYPE_OF(obj)]);
debug_print(file, obj);