8.4 Compiler Macros

X3J13 voted in June 1989 to add a facility for defining compiler macros that take effect only when compiling code, not when interpreting it.

The purpose of this facility is to permit selective source-code transformations only when the compiler is processing the code. When the compiler is about to compile a non-atomic form, it first calls compiler-macroexpand-1 repeatedly until there is no more expansion (there might not be any to begin with). Then it continues its remaining processing, which may include calling macroexpand-1 and so on.

The compiler is required to expand compiler macros. It is unspecified whether the interpreter does so. The intention is that only the compiler will do so, but the range of possible “compiled-only” implementation strategies precludes any firm specification.

[Макрос] define-compiler-macro name lambda-list{declaration | doc-string}* {form}*

This is just like defmacro except the definition is not stored in the symbol function cell of name and is not seen by macroexpand-1. It is, however, seen by compiler-macroexpand-1. As with defmacro, the lambda-list may include &environment and &whole and may include destructuring. The definition is global. (There is no provision for defining local compiler macros in the way that macrolet defines local macros.)

A top-level call to define-compiler-macro in a file being compiled by compile-file has an effect on the compilation environment similar to that of a call to defmacro, except it is noticed as a compiler macro (see section 24.1).

Note that compiler macro definitions do not appear in information returned by function-information; they are global, and their interaction with other lexical and global definitions can be reconstructed by compiler-macro-function. It is up to code-walking programs to decide whether to invoke compiler macro expansion.

X3J13 voted in March 1988 to specify that the body of the expander function defined by defmacro is implicitly enclosed in a block construct whose name is the same as the name of the defined macro; presumably this applies also to define-compiler-macro. Therefore return-from may be used to exit from the function.


[Function] compiler-macro-function name &optional env

The name must be a symbol. If it has been defined as a compiler macro, then compiler-macro-function returns the macro expansion function; otherwise it returns nil. The lexical environment env may override any global definition for name by defining a local function or local macro (such as by flet, labels, or macrolet) in which case nil is returned.

setf may be used with compiler-macro-function to install a function as the expansion function for the compiler macro name, in the same manner as for macro-function. Storing the value nil removes any existing compiler macro definition. As with macro-function, a non-nil stored value must be a function of two arguments, the entire macro call and the environment. The second argument to compiler-macro-function must be omitted when it is used with setf.


[Function] compiler-macroexpand form &optional env
[Function] compiler-macroexpand-1 form &optional env

These are just like macroexpand and macroexpand-1 except that the expander function is obtained as if by a call to compiler-macro-function on the car of the form rather than by a call to macro-function. Note that compiler-macroexpand performs repeated expansion but compiler-macroexpand-1 performs at most one expansion. Two values are returned, the expansion (or the original form) and a value that is true if any expansion occurred and nil otherwise.

There are three cases where no expansion happens:

Note that if there is no expansion, the original form is returned as the first value, and nil as the second value.

Any macro expansion performed by the function compiler-macroexpand or by the function compiler-macroexpand-1 is carried out by calling the function that is the value of *macroexpand-hook*.

A compiler macro may decline to provide any expansion merely by returning the original form. This is useful when using the facility to put “compiler optimizers” on various function names. For example, here is a compiler macro that “optimizes” (one would hope) the zero-argument and one-argument cases of a function called plus:

(define-compiler-macro plus (&whole form &rest args)
  (case (length args)
    (0 0)
    (1 (car args))
    (t form)))