Add basic lexenv support
This commit is contained in:
61
src/lisp.c
61
src/lisp.c
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user