Some random work
This commit is contained in:
225
src/lisp.c
225
src/lisp.c
@ -680,7 +680,8 @@ size_t list_length(LispVal *obj) {
|
||||
|
||||
StackFrame *the_stack = NULL;
|
||||
DEF_STATIC_SYMBOL(toplevel, "toplevel");
|
||||
DEF_STATIC_SYMBOL(parent_lexenv, "parent-lexenv");
|
||||
DEF_STATIC_SYMBOL(parent_lexenv, "parent-lexenv"); // DO NOT INTERN
|
||||
DEF_STATIC_SYMBOL(return_signal, "return-signal"); // DO NOT INTERN
|
||||
|
||||
void stack_enter(LispVal *name, LispVal *detail, bool inherit) {
|
||||
StackFrame *frame = lisp_malloc(sizeof(StackFrame));
|
||||
@ -1045,6 +1046,10 @@ void lisp_init(void) {
|
||||
"Set each of a number of variables to their respective values.");
|
||||
REGISTER_FUNCTION(progn, "(&rest forms)", "Evaluate each of FORMS.");
|
||||
REGISTER_FUNCTION(symbol_function, "(sym &opt resolve)", "");
|
||||
REGISTER_FUNCTION(symbol_value, "(sym)", "Return the global value of SYM.");
|
||||
REGISTER_FUNCTION(symbol_plist, "(sym)", "Return the plist of SYM.");
|
||||
REGISTER_FUNCTION(setplist, "(sym plist)",
|
||||
"Set the plist of SYM to PLIST.");
|
||||
REGISTER_FUNCTION(fset, "(sym new-func)", "");
|
||||
REGISTER_FUNCTION(defun, "(name args &rest body)",
|
||||
"Define NAME to be a new function.");
|
||||
@ -1062,15 +1067,23 @@ void lisp_init(void) {
|
||||
"Return a new un-interned symbol named NAME.");
|
||||
REGISTER_FUNCTION(macroexpand_1, "(form)",
|
||||
"Return the form which FORM expands to.");
|
||||
REGISTER_FUNCTION(macroexpand_toplevel, "(form)", "");
|
||||
REGISTER_FUNCTION(macroexpand_all, "(form)", "");
|
||||
REGISTER_FUNCTION(stringp, "(val)", "Return non-nil if VAL is a string.");
|
||||
REGISTER_FUNCTION(symbolp, "(val)", "Return non-nil if VAL is a symbol.");
|
||||
REGISTER_FUNCTION(pairp, "(val)", "Return non-nil if VAL is a pair.");
|
||||
REGISTER_FUNCTION(integerp, "(val)", "Return non-nil if VAL is a integer.");
|
||||
REGISTER_FUNCTION(floatp, "(val)", "Return non-nil if VAL is a float.");
|
||||
REGISTER_FUNCTION(vectorp, "(val)", "Return non-nil if VAL is a vector.");
|
||||
REGISTER_FUNCTION(functionp, "(val)",
|
||||
"Return non-nil if VAL is a function.");
|
||||
REGISTER_FUNCTION(macrop, "(val)", "Return non-nil if VAL is a macro.");
|
||||
REGISTER_FUNCTION(
|
||||
functionp, "(val)",
|
||||
"Return non-nil if VAL is a non-macro function (includes buitlins).");
|
||||
REGISTER_FUNCTION(macrop, "(val)",
|
||||
"Return non-nil if VAL is a non-builtin macro.");
|
||||
REGISTER_FUNCTION(builtinp, "(val)",
|
||||
"Return non-nil if VAL is a non-macro builtin.");
|
||||
REGISTER_FUNCTION(special_form_p, "(val)",
|
||||
"Return non-nil if VAL is a macro-builtin.");
|
||||
REGISTER_FUNCTION(hashtablep, "(val)",
|
||||
"Return non-nil if VAL is a hashtable.");
|
||||
REGISTER_FUNCTION(user_pointer_p, "(val)",
|
||||
@ -1080,6 +1093,9 @@ void lisp_init(void) {
|
||||
REGISTER_FUNCTION(keywordp, "(val)", "Return non-nil if VAL is a keyword.");
|
||||
REGISTER_FUNCTION(numberp, "(val)", "Return non-nil if VAL is a number.");
|
||||
REGISTER_FUNCTION(list_length, "(list)", "Return the length of LIST.");
|
||||
REGISTER_FUNCTION(copy_list, "(list)", "Return a shallow copy of LIST.");
|
||||
REGISTER_FUNCTION(copy_tree, "(tree)",
|
||||
"Return a deep copy of TREE and all sublists in it.");
|
||||
REGISTER_FUNCTION(num_eq, "(n1 n2)",
|
||||
"Return non-nil if N1 and N2 are equal numerically.")
|
||||
REGISTER_FUNCTION(num_gt, "(n1 n2)",
|
||||
@ -1158,6 +1174,19 @@ DEFUN(symbol_value, "symbol-value", (LispVal * symbol)) {
|
||||
return refcount_ref(((LispSymbol *) symbol)->value);
|
||||
}
|
||||
|
||||
DEFUN(symbol_plist, "symbol-plist", (LispVal * symbol)) {
|
||||
CHECK_TYPE(TYPE_SYMBOL, symbol);
|
||||
return refcount_ref(((LispSymbol *) symbol)->plist);
|
||||
}
|
||||
|
||||
DEFUN(setplist, "setplist", (LispVal * symbol, LispVal *plist)) {
|
||||
CHECK_TYPE(TYPE_SYMBOL, symbol);
|
||||
LispSymbol *real = (LispSymbol *) symbol;
|
||||
refcount_unref(real->plist);
|
||||
real->plist = refcount_ref(plist);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static inline LispVal *eval_function_args(LispVal *args, LispVal *lexenv) {
|
||||
LispVal *final_args = Qnil;
|
||||
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||
@ -1521,6 +1550,55 @@ DEFUN(funcall, "funcall", (LispVal * function, LispVal *rest)) {
|
||||
return call_function(function, rest, Qnil, false, false);
|
||||
}
|
||||
|
||||
DEFUN(copy_tree, "copy-tree", (LispVal * tree)) {
|
||||
if (NILP(tree)) {
|
||||
return Qnil;
|
||||
}
|
||||
CHECK_TYPE(TYPE_PAIR, tree);
|
||||
LispPair *tortise = (LispPair *) tree;
|
||||
LispPair *hare = (LispPair *) tortise->tail;
|
||||
LispVal *copy = Qnil;
|
||||
LispVal *copy_end;
|
||||
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||
the_stack->hidden = true;
|
||||
void *cl_handle = register_cleanup(&unref_double_ptr, ©);
|
||||
while (!NILP(tortise)) {
|
||||
if (!LISTP(LISPVAL(tortise))) {
|
||||
break;
|
||||
} else if (tortise == hare) {
|
||||
refcount_unref(copy);
|
||||
Fthrow(Qcircular_error, Qnil);
|
||||
}
|
||||
LispVal *elt = tortise->head;
|
||||
if (PAIRP(elt)) {
|
||||
elt = Fcopy_tree(elt);
|
||||
} else {
|
||||
refcount_ref(elt);
|
||||
}
|
||||
if (NILP(copy)) {
|
||||
copy = Fpair(elt, Qnil);
|
||||
copy_end = copy;
|
||||
} else {
|
||||
LispVal *new_end = Fpair(elt, Qnil);
|
||||
Fsettail(copy_end, new_end);
|
||||
refcount_unref(new_end);
|
||||
copy_end = new_end;
|
||||
}
|
||||
refcount_unref(elt);
|
||||
tortise = (LispPair *) tortise->tail;
|
||||
if (PAIRP(hare)) {
|
||||
if (PAIRP(((LispPair *) hare)->tail)) {
|
||||
hare = (LispPair *) ((LispPair *) hare->tail)->tail;
|
||||
} else if (NILP(((LispPair *) hare)->tail)) {
|
||||
hare = (LispPair *) Qnil;
|
||||
}
|
||||
}
|
||||
}
|
||||
cancel_cleanup(cl_handle);
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
DEFUN(macroexpand_1, "macroexpand-1", (LispVal * form)) {
|
||||
if (PAIRP(form)) {
|
||||
LispFunction *fobj = (LispFunction *) Fsymbol_function(Fhead(form), Qt);
|
||||
@ -1543,6 +1621,45 @@ DEFUN(macroexpand_1, "macroexpand-1", (LispVal * form)) {
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(macroexpand_toplevel, "macroexpand-toplevel", (LispVal * form)) {
|
||||
if (PAIRP(form)) {
|
||||
LispVal *out = refcount_ref(form);
|
||||
void *cl_handler = register_cleanup(&unref_double_ptr, &out);
|
||||
while (PAIRP(out) && !NILP(Fmacrop(HEAD(out)))) {
|
||||
LispVal *new_out = Fmacroexpand_1(out);
|
||||
refcount_unref(out);
|
||||
out = new_out;
|
||||
}
|
||||
cancel_cleanup(cl_handler);
|
||||
return out;
|
||||
} else {
|
||||
return refcount_ref(form);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(macroexpand_all, "macroexpand-all", (LispVal * form)) {
|
||||
if (PAIRP(form)) {
|
||||
LispVal *toplevel_orig = Fmacroexpand_toplevel(form);
|
||||
LispVal *toplevel;
|
||||
WITH_CLEANUP(toplevel_orig, {
|
||||
toplevel = Fcopy_list(toplevel_orig); //
|
||||
});
|
||||
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||
void *cl_handler = register_cleanup(&unref_double_ptr, &toplevel);
|
||||
if (PAIRP(toplevel) && NILP(Feq(Qquote, HEAD(toplevel)))) {
|
||||
FOREACH_TAIL(tail, TAIL(toplevel)) {
|
||||
Fsethead(tail, Fmacroexpand_all(HEAD(tail)));
|
||||
}
|
||||
}
|
||||
cancel_cleanup(cl_handler);
|
||||
});
|
||||
return toplevel;
|
||||
} else {
|
||||
return refcount_ref(form);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN(apply, "apply", (LispVal * function, LispVal *rest)) {
|
||||
LispVal *args = Qnil;
|
||||
LispVal *end;
|
||||
@ -1788,7 +1905,13 @@ DEFMACRO(defmacro, "defmacro", (LispVal * name, LispVal *args, LispVal *body)) {
|
||||
}
|
||||
|
||||
DEFMACRO(lambda, "lambda", (LispVal * args, LispVal *body)) {
|
||||
return make_lisp_function(args, the_stack->lexenv, body, false);
|
||||
LispVal *expanded_body = Fmacroexpand_all(body);
|
||||
LispVal *retval = Qnil;
|
||||
WITH_CLEANUP(expanded_body, {
|
||||
retval =
|
||||
make_lisp_function(args, the_stack->lexenv, expanded_body, false);
|
||||
});
|
||||
return retval;
|
||||
}
|
||||
|
||||
DEFMACRO(while, "while", (LispVal * cond, LispVal *body)) {
|
||||
@ -1842,12 +1965,44 @@ DEFUN(functionp, "functionp", (LispVal * val)) {
|
||||
}
|
||||
|
||||
DEFUN(macrop, "macrop", (LispVal * val)) {
|
||||
if (FUNCTIONP(val) && ((LispFunction *) val)->is_macro) {
|
||||
if (FUNCTIONP(val) && !((LispFunction *) val)->is_builtin
|
||||
&& ((LispFunction *) val)->is_macro) {
|
||||
return Qt;
|
||||
} else if (SYMBOLP(val)) {
|
||||
LispVal *res = Fsymbol_function(val, Qt);
|
||||
LispVal *retval =
|
||||
LISP_BOOL(FUNCTIONP(res) && ((LispFunction *) res)->is_macro);
|
||||
LISP_BOOL(FUNCTIONP(res) && !((LispFunction *) res)->is_builtin
|
||||
&& ((LispFunction *) res)->is_macro);
|
||||
refcount_unref(res);
|
||||
return retval;
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN(builtinp, "builtinp", (LispVal * val)) {
|
||||
if (FUNCTIONP(val) && ((LispFunction *) val)->is_builtin
|
||||
&& !((LispFunction *) val)->is_macro) {
|
||||
return Qt;
|
||||
} else if (SYMBOLP(val)) {
|
||||
LispVal *res = Fsymbol_function(val, Qt);
|
||||
LispVal *retval =
|
||||
LISP_BOOL(FUNCTIONP(res) && ((LispFunction *) res)->is_builtin
|
||||
&& !((LispFunction *) res)->is_macro);
|
||||
refcount_unref(res);
|
||||
return retval;
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN(special_form_p, "special-form-p", (LispVal * val)) {
|
||||
if (FUNCTIONP(val) && ((LispFunction *) val)->is_builtin
|
||||
&& ((LispFunction *) val)->is_macro) {
|
||||
return Qt;
|
||||
} else if (SYMBOLP(val)) {
|
||||
LispVal *res = Fsymbol_function(val, Qt);
|
||||
LispVal *retval =
|
||||
LISP_BOOL(FUNCTIONP(res) && ((LispFunction *) res)->is_builtin
|
||||
&& ((LispFunction *) res)->is_macro);
|
||||
refcount_unref(res);
|
||||
return retval;
|
||||
}
|
||||
@ -1882,6 +2037,31 @@ DEFUN(list_length, "list-length", (LispVal * list)) {
|
||||
return make_lisp_integer(list_length(list));
|
||||
}
|
||||
|
||||
DEFUN(copy_list, "copy-list", (LispVal * list)) {
|
||||
if (NILP(list)) {
|
||||
return Qnil;
|
||||
}
|
||||
CHECK_TYPE(TYPE_PAIR, list);
|
||||
LispVal *copy = Qnil;
|
||||
LispVal *copy_end;
|
||||
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||
void *cl_cleanup = register_cleanup(&unref_double_ptr, ©);
|
||||
FOREACH(elt, list) {
|
||||
if (NILP(copy)) {
|
||||
copy = Fpair(elt, Qnil);
|
||||
copy_end = copy;
|
||||
} else {
|
||||
LispVal *new_end = Fpair(elt, Qnil);
|
||||
Fsettail(copy_end, new_end);
|
||||
refcount_unref(new_end);
|
||||
copy_end = new_end;
|
||||
}
|
||||
}
|
||||
cancel_cleanup(cl_cleanup);
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
DEFMACRO(and, "and", (LispVal * rest)) {
|
||||
LispVal *retval = Qnil;
|
||||
FOREACH(cond, rest) {
|
||||
@ -1915,6 +2095,7 @@ DEFUN(type_of, "type-of", (LispVal * obj)) {
|
||||
make_lisp_string((char *) LISP_TYPE_NAMES[obj->type].name,
|
||||
LISP_TYPE_NAMES[obj->type].len, true, true);
|
||||
LispVal *sym = Fintern(name);
|
||||
refcount_unref(name);
|
||||
return sym;
|
||||
}
|
||||
|
||||
@ -2033,3 +2214,33 @@ static bool debug_print_tree_callback(void *obj, const RefcountList *trail,
|
||||
void debug_print_tree(FILE *stream, void *obj) {
|
||||
refcount_debug_walk_tree(obj, debug_print_tree_callback, stream);
|
||||
}
|
||||
|
||||
void debug_dump_lexenv(FILE *stream, LispVal *lexenv) {
|
||||
if (!the_stack) {
|
||||
fprintf(stream, "debug_dump_lexenv: No stack frames...\n");
|
||||
}
|
||||
if (!lexenv) {
|
||||
lexenv = the_stack->lexenv;
|
||||
}
|
||||
bool first = true;
|
||||
while (!NILP(lexenv)) {
|
||||
if (first) {
|
||||
fprintf(stream, "Lexical variables (most recent frame first):\n");
|
||||
} else {
|
||||
fprintf(stream, "\nNext parent:\n");
|
||||
}
|
||||
first = false;
|
||||
LispVal *next_lexenv = Qnil;
|
||||
HASHTABLE_FOREACH(var, val, lexenv, {
|
||||
if (var == Qparent_lexenv) {
|
||||
next_lexenv = val;
|
||||
} else {
|
||||
fprintf(stream, " - ");
|
||||
debug_dump(stream, var, false);
|
||||
fprintf(stream, " -> ");
|
||||
debug_dump(stream, val, true);
|
||||
}
|
||||
});
|
||||
lexenv = next_lexenv;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user