Common Lisp the Language, 2nd Edition
The macroexpand function is the conventional means for expanding a macro call. A hook is provided for a user function to gain control during the expansion process.
[Function]
macroexpand form &optional env
macroexpand-1 form &optional env
If form is a macro call, then macroexpand-1 will expand the macro call once and return two values: the expansion and t. If form is not a macro call, then the two values form and nil are returned.
A form is considered to be a macro call only if it is a cons whose car is a symbol that names a macro. The environment env is similar to that used within the evaluator (see evalhook); it defaults to a null environment. Any local macro definitions established within env by macrolet will be considered. If only form is given as an argument, then the environment is effectively null, and only global macro definitions (as established by defmacro) will be considered.
Macro expansion is carried out as follows. Once macroexpand-1 has determined that a symbol names a macro, it obtains the expansion function for that macro. The value of the variable *macroexpand-hook* is then called as a function of three arguments: the expansion function, the form, and the environment env. The value returned from this call is taken to be the expansion of the macro call. The initial value of *macroexpand-hook* is funcall, and the net effect is to invoke the expansion function, giving it form and env as its two arguments.
X3J13 voted in June 1988 (FUNCTION-TYPE) to specify
that the value of *macroexpand-hook* is first coerced to a
function before being called as the expansion interface hook.
Therefore its value may be a symbol, a lambda-expression, or any
object of type function.
X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT)
to specify that macro environment objects received
by a *macroexpand-hook* function
have only dynamic extent. The consequences are undefined if such objects are
referred to outside the dynamic extent of that particular invocation of the hook
function. This allows implementations to use somewhat more efficient techniques
for representing environment objects.
(The purpose of
*macroexpand-hook* is to facilitate various techniques
for improving interpretation speed by caching macro expansions.)
X3J13 voted in June 1989 (MACRO-CACHING) to clarify that, while
*macroexpand-hook* may be useful for debugging purposes, despite
the original design intent there is
currently no correct portable way to use it for caching macro expansions.
X3J13 voted in March 1989
(SYMBOL-MACROLET-SEMANTICS)
to specify that macroexpand-1 will also expand symbol macros
defined by symbol-macrolet; therefore a form may also be
a macro call if it is a symbol. The vote did not address the interaction
of this feature with the *macroexpand-hook* function. An obvious
implementation choice is that the hook function is indeed called
and given a special expansion function that, when applied to the
form (a symbol) and env, will produce the expansion,
just as for an ordinary macro; but this is only my suggestion.
The evaluator expands macro calls as if through the use of macroexpand-1; the point is that eval also uses *macroexpand-hook*.
macroexpand is similar to macroexpand-1, but repeatedly expands form until it is no longer a macro call. (In effect, macroexpand simply calls macroexpand-1 repeatedly until the second value returned is nil.) A second value of t or nil is returned as for macroexpand-1, indicating whether the original form was a macro call.
[Variable]
*macroexpand-hook*
The value of *macroexpand-hook* is used as the expansion interface hook by macroexpand-1.