Labels, flet, and macrolet!
This commit is contained in:
@ -257,3 +257,82 @@
|
|||||||
(and negate (not (funcall pred cur))))
|
(and negate (not (funcall pred cur))))
|
||||||
(return-from find-if cur)))
|
(return-from find-if cur)))
|
||||||
default)
|
default)
|
||||||
|
|
||||||
|
(defun mapconcat (func list)
|
||||||
|
(let (start end)
|
||||||
|
(dolist (elt list)
|
||||||
|
(if (not start)
|
||||||
|
(setq start (copy-list (funcall func elt))
|
||||||
|
end (lasttail start))
|
||||||
|
(settail end (copy-list (funcall func elt)))
|
||||||
|
(setq end (lasttail end))))
|
||||||
|
start))
|
||||||
|
|
||||||
|
(defun identity (e) e)
|
||||||
|
|
||||||
|
(defun append (&rest lists)
|
||||||
|
;; another implementation
|
||||||
|
;; (mapconcat 'identity lists)
|
||||||
|
(let* ((start (copy-list (head lists)))
|
||||||
|
(end (lasttail start)))
|
||||||
|
(dolist (list (tail lists))
|
||||||
|
(settail end (copy-list list))
|
||||||
|
(setq end (lasttail end)))
|
||||||
|
start))
|
||||||
|
|
||||||
|
(defmacro macrolet (macros &rest body)
|
||||||
|
(let* ((found-macros (make-hashtable))
|
||||||
|
(macro-fns (mapconcat (lambda (entry)
|
||||||
|
(let ((name (first entry))
|
||||||
|
(args (second entry))
|
||||||
|
(body (tail (tail entry))))
|
||||||
|
(when (gethash found-macros name)
|
||||||
|
(throw 'argument-error))
|
||||||
|
(puthash found-macros name t)
|
||||||
|
(list name
|
||||||
|
(eval (apply 'list 'lambda args
|
||||||
|
(list 'declare (list 'name name))
|
||||||
|
body)))))
|
||||||
|
macros)))
|
||||||
|
(macroexpand-all (pair 'progn body) macro-fns)))
|
||||||
|
|
||||||
|
(defmacro flet (functions &rest body)
|
||||||
|
(let ((macros (maphead (lambda (entry)
|
||||||
|
(let* ((name (first entry))
|
||||||
|
(args (second entry))
|
||||||
|
(body (tail (tail entry)))
|
||||||
|
(the-func
|
||||||
|
(eval (apply 'list 'lambda args
|
||||||
|
(list 'declare (list 'name name))
|
||||||
|
body)))
|
||||||
|
(the-sym (make-symbol (symbol-name name))))
|
||||||
|
(fset the-sym the-func)
|
||||||
|
(list name '(&rest args)
|
||||||
|
(list 'apply ''list (list '\' the-sym) 'args))))
|
||||||
|
functions)))
|
||||||
|
(apply 'list 'macrolet macros body)))
|
||||||
|
|
||||||
|
(defmacro labels (functions &rest body)
|
||||||
|
(let ((syms (make-hashtable)))
|
||||||
|
(dolist (entry functions)
|
||||||
|
(when (gethash syms (first entry))
|
||||||
|
(throw 'argument-error))
|
||||||
|
(puthash syms (first entry) (make-symbol (symbol-name (first entry)))))
|
||||||
|
(let* ((macros (mapconcat
|
||||||
|
(lambda (entry)
|
||||||
|
(list (first entry)
|
||||||
|
(eval (list 'lambda '(&rest args)
|
||||||
|
(list 'apply ''list
|
||||||
|
(list '\' (gethash syms (first entry)))
|
||||||
|
'args)))))
|
||||||
|
functions)))
|
||||||
|
(dolist (entry functions)
|
||||||
|
(let ((name (first entry))
|
||||||
|
(args (second entry))
|
||||||
|
(body (tail (tail entry))))
|
||||||
|
(fset (gethash syms name)
|
||||||
|
(eval (apply 'list 'lambda args
|
||||||
|
(list 'declare (list 'name name))
|
||||||
|
(tail (macroexpand-all (pair 'progn body)
|
||||||
|
macros)))))))
|
||||||
|
(macroexpand-all (pair 'progn body) macros))))
|
||||||
|
91
src/lisp.c
91
src/lisp.c
@ -422,6 +422,23 @@ LispVal *make_user_pointer(void *data, void (*free_func)(void *)) {
|
|||||||
return LISPVAL(self);
|
return LISPVAL(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN(make_hashtable, "make-hashtable", (LispVal * hash_fn, LispVal *eq_fn)) {
|
||||||
|
return make_lisp_hashtable(eq_fn, hash_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(vector, "vector", (LispVal * elems)) {
|
||||||
|
struct UnrefListData uld = {.vals = NULL, .len = 0};
|
||||||
|
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||||
|
void *cl_handler = register_cleanup(&unref_free_list_double_ptr, &uld);
|
||||||
|
FOREACH(elt, elems) {
|
||||||
|
uld.vals = lisp_realloc(uld.vals, sizeof(LispVal *) * (++uld.len));
|
||||||
|
uld.vals[uld.len - 1] = elt;
|
||||||
|
}
|
||||||
|
cancel_cleanup(cl_handler);
|
||||||
|
});
|
||||||
|
return make_lisp_vector(uld.vals, uld.len);
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN(pair, "pair", (LispVal * head, LispVal *tail)) {
|
DEFUN(pair, "pair", (LispVal * head, LispVal *tail)) {
|
||||||
return make_lisp_pair(head, tail);
|
return make_lisp_pair(head, tail);
|
||||||
}
|
}
|
||||||
@ -1068,6 +1085,11 @@ void lisp_init(void) {
|
|||||||
REGISTER_STATIC_FUNCTION(set_for_return, "(entry dest)", "");
|
REGISTER_STATIC_FUNCTION(set_for_return, "(entry dest)", "");
|
||||||
REGISTER_STATIC_FUNCTION(internal_real_return, "(name tag value)", "");
|
REGISTER_STATIC_FUNCTION(internal_real_return, "(name tag value)", "");
|
||||||
|
|
||||||
|
REGISTER_FUNCTION(make_hashtable, "(&opt hash-fn eq-fn)", "");
|
||||||
|
REGISTER_FUNCTION(puthash, "(table key value)", "");
|
||||||
|
REGISTER_FUNCTION(gethash, "(table key &opt def)", "");
|
||||||
|
REGISTER_FUNCTION(remhash, "(table key)", "");
|
||||||
|
REGISTER_FUNCTION(vector, "(&rest elements)", "");
|
||||||
REGISTER_FUNCTION(breakpoint, "(&opt id)", "Do nothing...");
|
REGISTER_FUNCTION(breakpoint, "(&opt id)", "Do nothing...");
|
||||||
REGISTER_FUNCTION(sethead, "(pair newval)",
|
REGISTER_FUNCTION(sethead, "(pair newval)",
|
||||||
"Set the head of PAIR to NEWVAL.");
|
"Set the head of PAIR to NEWVAL.");
|
||||||
@ -1100,6 +1122,7 @@ void lisp_init(void) {
|
|||||||
setq, "(&rest name-value-pairs)",
|
setq, "(&rest name-value-pairs)",
|
||||||
"Set each of a number of variables to their respective values.");
|
"Set each of a number of variables to their respective values.");
|
||||||
REGISTER_FUNCTION(progn, "(&rest forms)", "Evaluate each of FORMS.");
|
REGISTER_FUNCTION(progn, "(&rest forms)", "Evaluate each of FORMS.");
|
||||||
|
REGISTER_FUNCTION(symbol_name, "(sym)", "");
|
||||||
REGISTER_FUNCTION(symbol_function, "(sym &opt resolve)", "");
|
REGISTER_FUNCTION(symbol_function, "(sym &opt resolve)", "");
|
||||||
REGISTER_FUNCTION(symbol_value, "(sym)", "Return the global value of SYM.");
|
REGISTER_FUNCTION(symbol_value, "(sym)", "Return the global value of SYM.");
|
||||||
REGISTER_FUNCTION(symbol_plist, "(sym)", "Return the plist of SYM.");
|
REGISTER_FUNCTION(symbol_plist, "(sym)", "Return the plist of SYM.");
|
||||||
@ -1120,10 +1143,10 @@ void lisp_init(void) {
|
|||||||
"Return non-nil if OBJ1 and OBJ2 are equal");
|
"Return non-nil if OBJ1 and OBJ2 are equal");
|
||||||
REGISTER_FUNCTION(make_symbol, "(name)",
|
REGISTER_FUNCTION(make_symbol, "(name)",
|
||||||
"Return a new un-interned symbol named NAME.");
|
"Return a new un-interned symbol named NAME.");
|
||||||
REGISTER_FUNCTION(macroexpand_1, "(form)",
|
REGISTER_FUNCTION(macroexpand_1, "(form &opt lexical-macros)",
|
||||||
"Return the form which FORM expands to.");
|
"Return the form which FORM expands to.");
|
||||||
REGISTER_FUNCTION(macroexpand_toplevel, "(form)", "");
|
REGISTER_FUNCTION(macroexpand_toplevel, "(form &opt lexical-macros)", "");
|
||||||
REGISTER_FUNCTION(macroexpand_all, "(form)", "");
|
REGISTER_FUNCTION(macroexpand_all, "(form &opt lexical-macros)", "");
|
||||||
REGISTER_FUNCTION(stringp, "(val)", "Return non-nil if VAL is a string.");
|
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(symbolp, "(val)", "Return non-nil if VAL is a symbol.");
|
||||||
REGISTER_FUNCTION(pairp, "(val)", "Return non-nil if VAL is a pair.");
|
REGISTER_FUNCTION(pairp, "(val)", "Return non-nil if VAL is a pair.");
|
||||||
@ -1133,7 +1156,7 @@ void lisp_init(void) {
|
|||||||
REGISTER_FUNCTION(
|
REGISTER_FUNCTION(
|
||||||
functionp, "(val)",
|
functionp, "(val)",
|
||||||
"Return non-nil if VAL is a non-macro function (includes buitlins).");
|
"Return non-nil if VAL is a non-macro function (includes buitlins).");
|
||||||
REGISTER_FUNCTION(macrop, "(val)",
|
REGISTER_FUNCTION(macrop, "(val &opt lexical-macros)",
|
||||||
"Return non-nil if VAL is a non-builtin macro.");
|
"Return non-nil if VAL is a non-builtin macro.");
|
||||||
REGISTER_FUNCTION(builtinp, "(val)",
|
REGISTER_FUNCTION(builtinp, "(val)",
|
||||||
"Return non-nil if VAL is a non-macro builtin.");
|
"Return non-nil if VAL is a non-macro builtin.");
|
||||||
@ -1210,6 +1233,11 @@ DEFUN(breakpoint, "breakpoint", (LispVal * id)) {
|
|||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN(symbol_name, "symbol-name", (LispVal * symbol)) {
|
||||||
|
CHECK_TYPE(TYPE_SYMBOL, symbol);
|
||||||
|
return refcount_ref(((LispSymbol *) symbol)->name);
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN(symbol_function, "symbol-function",
|
DEFUN(symbol_function, "symbol-function",
|
||||||
(LispVal * symbol, LispVal *resolve)) {
|
(LispVal * symbol, LispVal *resolve)) {
|
||||||
CHECK_TYPE(TYPE_SYMBOL, symbol);
|
CHECK_TYPE(TYPE_SYMBOL, symbol);
|
||||||
@ -1707,10 +1735,32 @@ DEFUN(copy_tree, "copy-tree", (LispVal * tree)) {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(macroexpand_1, "macroexpand-1", (LispVal * form)) {
|
static LispVal *lookup_lexical_macro(LispVal *name, LispVal *lexical_macros) {
|
||||||
|
if (!SYMBOLP(name)) {
|
||||||
|
return Qunbound;
|
||||||
|
}
|
||||||
|
LispVal *res = Fplist_get(lexical_macros, name, Qunbound, Qnil);
|
||||||
|
if (FUNCTIONP(res)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
refcount_unref(res);
|
||||||
|
return Qunbound;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline LispVal *expand_function_as_macro(LispFunction *fobj,
|
||||||
|
LispVal *args) {
|
||||||
|
return Ffuncall((LispVal *) fobj, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(macroexpand_1, "macroexpand-1",
|
||||||
|
(LispVal * form, LispVal *lexical_macros)) {
|
||||||
if (PAIRP(form)) {
|
if (PAIRP(form)) {
|
||||||
LispFunction *fobj;
|
LispVal *lex_res = lookup_lexical_macro(HEAD(form), lexical_macros);
|
||||||
if (FUNCTIONP(HEAD(form))) {
|
LispFunction *fobj = (LispFunction *) Qunbound;
|
||||||
|
if (lex_res != Qunbound) {
|
||||||
|
return expand_function_as_macro((LispFunction *) lex_res,
|
||||||
|
TAIL(form));
|
||||||
|
} else if (FUNCTIONP(HEAD(form))) {
|
||||||
fobj = refcount_ref(HEAD(form));
|
fobj = refcount_ref(HEAD(form));
|
||||||
} else {
|
} else {
|
||||||
fobj = (LispFunction *) Fsymbol_function(HEAD(form), Qt);
|
fobj = (LispFunction *) Fsymbol_function(HEAD(form), Qt);
|
||||||
@ -1748,12 +1798,13 @@ DEFUN(macroexpand_1, "macroexpand-1", (LispVal * form)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(macroexpand_toplevel, "macroexpand-toplevel", (LispVal * form)) {
|
DEFUN(macroexpand_toplevel, "macroexpand-toplevel",
|
||||||
|
(LispVal * form, LispVal *lexical_macros)) {
|
||||||
if (PAIRP(form)) {
|
if (PAIRP(form)) {
|
||||||
LispVal *out = refcount_ref(form);
|
LispVal *out = refcount_ref(form);
|
||||||
void *cl_handler = register_cleanup(&unref_double_ptr, &out);
|
void *cl_handler = register_cleanup(&unref_double_ptr, &out);
|
||||||
while (PAIRP(out) && !NILP(Fmacrop(HEAD(out)))) {
|
while (PAIRP(out) && !NILP(Fmacrop(HEAD(out), lexical_macros))) {
|
||||||
LispVal *new_out = Fmacroexpand_1(out);
|
LispVal *new_out = Fmacroexpand_1(out, lexical_macros);
|
||||||
refcount_unref(out);
|
refcount_unref(out);
|
||||||
out = new_out;
|
out = new_out;
|
||||||
}
|
}
|
||||||
@ -1942,12 +1993,15 @@ static LispVal *filter_body_tree(LispVal *body,
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LispVal *macroexpand_toplevel_as_callback(LispVal *form, void *ignored) {
|
static LispVal *macroexpand_toplevel_as_callback(LispVal *form,
|
||||||
return Fmacroexpand_toplevel(form);
|
void *lexical_macros) {
|
||||||
|
return Fmacroexpand_toplevel(form, lexical_macros);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(macroexpand_all, "macroexpand-all", (LispVal * form)) {
|
DEFUN(macroexpand_all, "macroexpand-all",
|
||||||
return filter_body_form(form, macroexpand_toplevel_as_callback, NULL);
|
(LispVal * form, LispVal *lexical_macros)) {
|
||||||
|
return filter_body_form(form, macroexpand_toplevel_as_callback,
|
||||||
|
lexical_macros);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(apply, "apply", (LispVal * function, LispVal *rest)) {
|
DEFUN(apply, "apply", (LispVal * function, LispVal *rest)) {
|
||||||
@ -2257,7 +2311,7 @@ struct NameAndReturnTag {
|
|||||||
|
|
||||||
static LispVal *expand_function_body_callback(LispVal *body, void *data) {
|
static LispVal *expand_function_body_callback(LispVal *body, void *data) {
|
||||||
struct NameAndReturnTag *name_and_return_tag = data;
|
struct NameAndReturnTag *name_and_return_tag = data;
|
||||||
LispVal *expansion = Fmacroexpand_toplevel(body);
|
LispVal *expansion = Fmacroexpand_toplevel(body, Qnil);
|
||||||
// this mess checks that the call is exactly one of
|
// this mess checks that the call is exactly one of
|
||||||
// - (return-from 'symbol)
|
// - (return-from 'symbol)
|
||||||
// - (return-from 'symbol val)
|
// - (return-from 'symbol val)
|
||||||
@ -2292,7 +2346,7 @@ static inline LispVal *expand_function_body(LispVal *name, LispVal *return_tag,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LispVal *macroexpand_all_as_callback(LispVal *form, void *ignored) {
|
static LispVal *macroexpand_all_as_callback(LispVal *form, void *ignored) {
|
||||||
return Fmacroexpand_all(form);
|
return Fmacroexpand_all(form, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void expand_lambda_list_for_toplevel(LispVal *list) {
|
static inline void expand_lambda_list_for_toplevel(LispVal *list) {
|
||||||
@ -2432,11 +2486,14 @@ DEFUN(functionp, "functionp", (LispVal * val)) {
|
|||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(macrop, "macrop", (LispVal * val)) {
|
DEFUN(macrop, "macrop", (LispVal * val, LispVal *lexical_macros)) {
|
||||||
if (FUNCTIONP(val) && !((LispFunction *) val)->is_builtin
|
if (FUNCTIONP(val) && !((LispFunction *) val)->is_builtin
|
||||||
&& ((LispFunction *) val)->is_macro) {
|
&& ((LispFunction *) val)->is_macro) {
|
||||||
return Qt;
|
return Qt;
|
||||||
} else if (SYMBOLP(val)) {
|
} else if (SYMBOLP(val)) {
|
||||||
|
if (lookup_lexical_macro(val, lexical_macros) != Qunbound) {
|
||||||
|
return Qt;
|
||||||
|
}
|
||||||
LispVal *res = Fsymbol_function(val, Qt);
|
LispVal *res = Fsymbol_function(val, Qt);
|
||||||
LispVal *retval =
|
LispVal *retval =
|
||||||
LISP_BOOL(FUNCTIONP(res) && !((LispFunction *) res)->is_builtin
|
LISP_BOOL(FUNCTIONP(res) && !((LispFunction *) res)->is_builtin
|
||||||
|
11
src/lisp.h
11
src/lisp.h
@ -333,6 +333,7 @@ LispVal *make_user_pointer(void *data, void (*free_func)(void *));
|
|||||||
// ########################
|
// ########################
|
||||||
bool strings_equal_nocase(const char *s1, const char *s2, size_t n);
|
bool strings_equal_nocase(const char *s1, const char *s2, size_t n);
|
||||||
|
|
||||||
|
DECLARE_FUNCTION(make_hashtable, (LispVal * hash_fn, LispVal *eq_fn));
|
||||||
DECLARE_FUNCTION(pair, (LispVal * head, LispVal *tail));
|
DECLARE_FUNCTION(pair, (LispVal * head, LispVal *tail));
|
||||||
DECLARE_FUNCTION(hash_string, (LispVal * obj));
|
DECLARE_FUNCTION(hash_string, (LispVal * obj));
|
||||||
DECLARE_FUNCTION(strings_equal, (LispVal * obj1, LispVal *obj2));
|
DECLARE_FUNCTION(strings_equal, (LispVal * obj1, LispVal *obj2));
|
||||||
@ -565,6 +566,7 @@ extern LispVal *Qcomma_at;
|
|||||||
DECLARE_FUNCTION(quote, (LispVal * form));
|
DECLARE_FUNCTION(quote, (LispVal * form));
|
||||||
|
|
||||||
DECLARE_FUNCTION(breakpoint, (LispVal * id));
|
DECLARE_FUNCTION(breakpoint, (LispVal * id));
|
||||||
|
DECLARE_FUNCTION(symbol_name, (LispVal * symbol));
|
||||||
DECLARE_FUNCTION(symbol_function, (LispVal * symbol, LispVal *resolve));
|
DECLARE_FUNCTION(symbol_function, (LispVal * symbol, LispVal *resolve));
|
||||||
DECLARE_FUNCTION(symbol_value, (LispVal * symbol));
|
DECLARE_FUNCTION(symbol_value, (LispVal * symbol));
|
||||||
DECLARE_FUNCTION(symbol_plist, (LispVal * symbol));
|
DECLARE_FUNCTION(symbol_plist, (LispVal * symbol));
|
||||||
@ -593,9 +595,10 @@ DECLARE_FUNCTION(defmacro, (LispVal * name, LispVal *args, LispVal *body));
|
|||||||
DECLARE_FUNCTION(lambda, (LispVal * args, LispVal *body));
|
DECLARE_FUNCTION(lambda, (LispVal * args, LispVal *body));
|
||||||
DECLARE_FUNCTION(while, (LispVal * condition, LispVal *body));
|
DECLARE_FUNCTION(while, (LispVal * condition, LispVal *body));
|
||||||
DECLARE_FUNCTION(make_symbol, (LispVal * name));
|
DECLARE_FUNCTION(make_symbol, (LispVal * name));
|
||||||
DECLARE_FUNCTION(macroexpand_1, (LispVal * form));
|
DECLARE_FUNCTION(macroexpand_1, (LispVal * form, LispVal *lexical_macros));
|
||||||
DECLARE_FUNCTION(macroexpand_toplevel, (LispVal * form));
|
DECLARE_FUNCTION(macroexpand_toplevel,
|
||||||
DECLARE_FUNCTION(macroexpand_all, (LispVal * form));
|
(LispVal * form, LispVal *lexical_macros));
|
||||||
|
DECLARE_FUNCTION(macroexpand_all, (LispVal * form, LispVal *lexical_macros));
|
||||||
DECLARE_FUNCTION(stringp, (LispVal * val));
|
DECLARE_FUNCTION(stringp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(symbolp, (LispVal * val));
|
DECLARE_FUNCTION(symbolp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(pairp, (LispVal * val));
|
DECLARE_FUNCTION(pairp, (LispVal * val));
|
||||||
@ -603,7 +606,7 @@ DECLARE_FUNCTION(integerp, (LispVal * val));
|
|||||||
DECLARE_FUNCTION(floatp, (LispVal * val));
|
DECLARE_FUNCTION(floatp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(vectorp, (LispVal * val));
|
DECLARE_FUNCTION(vectorp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(functionp, (LispVal * val));
|
DECLARE_FUNCTION(functionp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(macrop, (LispVal * val));
|
DECLARE_FUNCTION(macrop, (LispVal * val, LispVal *lexical_macros));
|
||||||
DECLARE_FUNCTION(builtinp, (LispVal * val));
|
DECLARE_FUNCTION(builtinp, (LispVal * val));
|
||||||
DECLARE_FUNCTION(special_form_p, (LispVal * val));
|
DECLARE_FUNCTION(special_form_p, (LispVal * val));
|
||||||
DECLARE_FUNCTION(hashtablep, (LispVal * val));
|
DECLARE_FUNCTION(hashtablep, (LispVal * val));
|
||||||
|
Reference in New Issue
Block a user