From 2f7e42ed9c16324fb2ae61c4dc0089541573b0ec Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Sat, 19 Nov 2016 10:56:40 -0800 Subject: Handle interpreted macros through function. All macros are function bindings now. * eval.c (me_interp_macro): New function. Body is a copy of block from expand_macro. (op_defmacro): Hoist the me_interp_macro function into the object domain, installing the macro material as the environment. This function is the expander. (expand_macro): Assume that the binding is a function and call it. The cons case is gone. (expand_macrolet): Similar change to the one in op_defmacro: a macrolet is also a function. * txr.1: Documentation under symbol-macro updated. --- eval.c | 61 ++++++++++++++++++++++++++++++++----------------------------- txr.1 | 30 +++++++++++++++++++++--------- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/eval.c b/eval.c index d96a02ce..5e0ad221 100644 --- a/eval.c +++ b/eval.c @@ -1634,6 +1634,28 @@ static val op_defun(val form, val env) } } +static val me_interp_macro(val expander, val form, val menv) +{ + debug_enter; + val name = car(form); + val arglist = rest(form); + val env = car(expander); + val params = cadr(expander); + val body = cddr(expander); + val saved_de = set_dyn_env(make_env(nil, nil, dyn_env)); + val exp_env = bind_macro_params(env, menv, params, arglist, nil, form); + val result; + args_decl_list(args, ARGS_MIN, arglist); + + debug_frame(name, args, nil, env, nil, nil, nil); + result = eval_progn(body, exp_env, body); + debug_end; + set_dyn_env(saved_de); + set_origin(result, form); + debug_return(result); + debug_leave; +} + static val op_defmacro(val form, val env) { val args = rest(form); @@ -1650,7 +1672,8 @@ static val op_defmacro(val form, val env) /* defmacro captures lexical environment, so env is passed */ sethash(top_mb, name, - rlcp_tree(cons(name, cons(env, cons(params, cons(block, nil)))), + rlcp_tree(cons(name, func_f2(cons(env, cons(params, cons(block, nil))), + me_interp_macro)), block)); if (eval_initing) sethash(builtin, name, defmacro_s); @@ -1660,31 +1683,9 @@ static val op_defmacro(val form, val env) static val expand_macro(val form, val mac_binding, val menv) { val expander = cdr(mac_binding); - - if (functionp(expander)) { - val expanded = funcall2(expander, form, menv); - set_origin(expanded, form); - return expanded; - } else { - debug_enter; - val name = car(form); - val arglist = rest(form); - val env = car(expander); - val params = cadr(expander); - val body = cddr(expander); - val saved_de = set_dyn_env(make_env(nil, nil, dyn_env)); - val exp_env = bind_macro_params(env, menv, params, arglist, nil, form); - val result; - args_decl_list(args, ARGS_MIN, arglist); - - debug_frame(name, args, nil, env, nil, nil, nil); - result = eval_progn(body, exp_env, body); - debug_end; - set_dyn_env(saved_de); - set_origin(result, form); - debug_return(result); - debug_leave; - } + val expanded = funcall2(expander, form, menv); + set_origin(expanded, form); + return expanded; } static val maybe_progn(val forms) @@ -1751,11 +1752,13 @@ static val expand_macrolet(val form, val menv) builtin_reject_test(op, name, form); /* We store the macrolet in the same form as a top level defmacro, - * so they can be treated uniformly. The nil after the name is - * the ordinary lexical environment: a macrolet doesn't capture that. + * so they can be treated uniformly. The nil at the head of the + * environment object is the ordinary lexical environment: a macrolet + * doesn't capture that. */ rlcp_tree(env_fbind(new_env, name, - cons(nil, cons(params, cons(block, nil)))), block); + func_f2(cons(nil, cons(params, cons(block, nil))), + me_interp_macro)), block); } return rlcp_tree(maybe_progn(expand_forms(body, new_env)), body); diff --git a/txr.1 b/txr.1 index e17536cc..b3831fbb 100644 --- a/txr.1 +++ b/txr.1 @@ -14873,15 +14873,7 @@ The .code symbol-macro function retrieves the value of the global macro binding of .meta symbol -if it has one. The value of a macro binding isn't a function object, but a -list of the following form: - -.cblk -.mets (# < macro-parameter-list << body-form *) -.cble - -This representation is likely to change or expand to include other -forms in future \*(TX versions. +if it has one. Note: the name of this function has nothing to do with symbol macros; it is named for consistency with @@ -14890,6 +14882,26 @@ and .codn symbol-value , referring to the "macro-expander binding of the symbol cell". +The value of a macro binding is a function object. +Intrinsic macros are C functions in the \*(TX kernel, which receive +the entire macro call form and macro environment, performing their +own destructuring. Currently, macros written in \*(TL are represented +as curried C functions which carry the following list object in their +environment cell: + +.cblk +.mets (# < macro-parameter-list << body-form *) +.cble + +Local macros created by +.code macrolet +have +.code nil +in place of the environment object. + +This representation is likely to change or expand to include other +forms in future \*(TX versions. + The .code symbol-value function retrieves the value stored in the dynamic binding of -- cgit v1.2.3