diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-02-22 15:19:46 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-02-22 15:19:46 -0800 |
commit | 1dabce1358de135b82bf0831f045352b3ff9ab1c (patch) | |
tree | 0400704259197cb7fc7ac901d347234cff860458 | |
parent | 452cd7ca4ff07009402d618a02d439bdbbfa71a4 (diff) | |
download | txr-1dabce1358de135b82bf0831f045352b3ff9ab1c.tar.gz txr-1dabce1358de135b82bf0831f045352b3ff9ab1c.tar.bz2 txr-1dabce1358de135b82bf0831f045352b3ff9ab1c.zip |
* eval.c (eval_intrinsic): We don't need to make an environment
here if the env parameter is nil. The low level environment
lookup functions already handle nil.
(do_eval): Do not type check the env argument for the ENV type.
(expand_forms, expand): No need to default a missing menv to a
blank environment; just use nil.
(macro_form_p): Take menv parameter and switch to lookup_mac
from gethash.
(macroexpand_1, macroexpand): Use the environment parameter
by using lookup_mac rather than gethash.
(eval_init): Fix registration of macro_form_p to reflect new
optional argument.
* txr.1: Documented optional environment parameters in macro-form-p,
macroexpand-1 and macroexpand.
Documented macrolet.
-rw-r--r-- | eval.c | 17 | ||||
-rw-r--r-- | txr.1 | 108 |
2 files changed, 112 insertions, 13 deletions
@@ -738,7 +738,7 @@ val interp_fun(val env, val fun, val args) val eval_intrinsic(val form, val env) { form = expand(form, nil); - return eval(form, default_arg(env, make_env(nil, nil, env)), form); + return eval(form, default_bool_arg(env), form); } static val do_eval(val form, val env, val ctx_form, @@ -746,7 +746,6 @@ static val do_eval(val form, val env, val ctx_form, { debug_enter; - type_check(env, ENV); debug_check(consp(form) ? form : ctx_form, env, nil, nil, nil, nil); if (nilp(form)) { @@ -1767,8 +1766,6 @@ static val op_with_saved_vars(val form, val env) val expand_forms(val form, val menv) { - menv = default_arg(menv, make_env(nil, nil, nil)); - if (atom(form)) { return form; } else { @@ -2166,7 +2163,7 @@ val expand(val form, val menv) { val macro = nil; - menv = default_arg(menv, make_env(nil, nil, nil)); + menv = default_bool_arg(menv); tail: if (atom(form)) { @@ -2375,11 +2372,11 @@ tail: } } -static val macro_form_p(val form) +static val macro_form_p(val form, val menv) { if (!consp(form)) return nil; - if (!gethash(top_mb, car(form))) + if (!lookup_mac(menv, car(form))) return nil; return t; } @@ -2388,11 +2385,11 @@ static val macroexpand_1(val form, val menv) { val macro; - menv = default_arg(menv, make_env(nil, nil, nil)); + menv = default_bool_arg(menv); if (atom(form)) { return form; - } else if ((macro = gethash(top_mb, car(form)))) { + } else if ((macro = lookup_mac(menv, car(form)))) { val mac_expand = expand_macro(form, macro, menv); if (mac_expand == form) return form; @@ -3104,7 +3101,7 @@ void eval_init(void) reg_fun(intern(lit("lisp-parse"), user_package), func_n2o(lisp_parse, 0)); reg_fun(intern(lit("read"), user_package), func_n2o(lisp_parse, 0)); reg_fun(intern(lit("expand"), system_package), func_n2o(expand, 1)); - reg_fun(intern(lit("macro-form-p"), user_package), func_n1(macro_form_p)); + reg_fun(intern(lit("macro-form-p"), user_package), func_n2o(macro_form_p, 1)); reg_fun(intern(lit("macroexpand-1"), user_package), func_n2o(macroexpand_1, 1)); reg_fun(intern(lit("macroexpand"), user_package), @@ -12785,12 +12785,51 @@ Examples: (let ((,var (car i))) ,*body)))) +.SS Operator macrolet + +.TP +Syntax: + + (macrolet ({(<name> <macro-style-params> <macro-body-form>*)}*) + <body-form>*) + +.TP +Description: + +The macrolet binding operator extends the macro-time lexical environment +by making zero or more new local macros visible. + +The operator symbol is followed by a list of macro definitions. +Each definition is a form which begins with a name, followed by a macro +parameter list, and zero or more forms. These macro definitions are similar +to those globally defined by the defmacro operator, except that they +are in a local environment, and do not capture any regular lexical scope. + +The macro definitions are followed by optional forms. + +The macros thus defined are visible to the the <body-form>-s. + +Forms inside the macro definitions such as the <macro-body-form>-s, +and initializer forms appearing in <macro-style-params> are subject +to macro-expansion in a scope in which none of the new macros being +defined are yet visible. Once the macro definitions are themselves +macro-expanded, they are placed into a new macro environment, which +is then used for macro expanding the <body-form>-s. + +A macrolet form is fully processed in the expansion phase of a form, and is +effectively replaced by progn form which contains expanded versions of +<body-forms>-s, only. This expanded structure shows no evidence that any +macrolet forms ever existed in it. Therefore, it is impossible for the code +evaluated in the bodies and parameter lists of macrolet macros to have any +visibility to any surrounding lexical variable bindings, which are only +instantiated in the evaluation phase, after expansion is done. + .SS Function macro-form-p .TP Syntax: - (macro-form-p <obj>) + (macro-form-p <obj> [<env>]) .TP Description: @@ -12801,13 +12840,44 @@ a form which is a macro form. Otherwise it returns nil. A macro form will transform under macroexpand-1 or macroexpand; an object which isn't a macro form will not undergo expansion. +The optional <env> parameter is a macroexpansion environment. +A macroexpansion environment is passed down to macros and can be received +via their special :env parameter. A macro can use this environment to +determine whether a piece of syntax <obj> is a macro form in that +environment. + +.TP +Example: + + ;; macro which translates form to the form 'yes if it is a macro + ;; form, otherwise to the form 'no. + + (defmacro global (:env menv form) + (if (macro-form-p form menv) + ''yes ''no)) + + (macrolet ((local ())) + (global (local))) ;; yields yes + + (global (local)) ;; yields no + + +During macroexpansion, the global macro is handed the environment which +it receives via :env menv. When the macro is invoked within the macrolet, +this environment includes the macro-time lexical scope in which the +local macro is defined. So when global checks whether the argument form +(local) is a macro, the conclusion is yes: the (local) form is a macro +call in that environment: macro-form-p yields t. When (global (local)) is +invoked outside of the macrolet, no local macro is visible, and so macro-form-p +yields nil. + .SS Functions macroexpand-1 and macroexpand .TP Syntax: - (macroexpand-1 <obj>) - (macroexpand <obj>) + (macroexpand-1 <obj> [<env>]) + (macroexpand <obj> [<env>]) .TP Description: @@ -12825,6 +12895,38 @@ a macro form, then it expands that form, and keeps repeating this process until the expansion yields a non-macro-form. That non-macro-form is then returned. +The optional <env> parameter is a macroexpansion environment. +A macroexpansion environment is passed down to macros and can be received +via their special :env parameter. The environment they receive is their +lexically apparent macro-time environment in which local macros may be +visible. A macro can use this environment to "manually" expand some +form in the context of that environment. + +.TP +Example: + + ;; (foo x) expands x, and if x begins with a number, it removes + ;; the number and returns the resulting form. Otherwise, it + ;; returns the entire form. + + (defmacro rem-num (:env menv some-form) + (let ((expanded (macroexpand some-form menv))) + (if (numberp (car expanded)) + (cdr expanded) + some-form))) + + ;; The following yields (42 a). + + (macrolet ((foo () '(1 list 42)) + (bar () '(list 'a))) + (list (rem-num (foo)) (rem-num (bar))))) + +The rem-num macro is able to expand the (foo) and (bar) forms it receives as +the some-form argument, using the local macro that is lexically apparent +where those forms are passed, and is correctly able to work with the +expansions (1 list 42) and (list 'a) to produce (list 42) and (list 'a) +which evaluate to 42 and a respectively. + .SS Operator tree-bind .TP |