Next: , Previous: Compiler Terminology, Up: Compilation


3.2.2 Compilation Semantics

Conceptually, compilation is a process that traverses code, performs certain kinds of syntactic and semantic analyses using information (such as proclamations and macro definitions) present in the compilation environment, and produces equivalent, possibly more efficient code.

3.2.2.1 Compiler Macros

A compiler macro can be defined for a name that also names a function or macro. That is, it is possible for a function name to name both a function and a compiler macro.

A function name names a compiler macro if compiler-macro-function is true of the function name in the lexical environment in which it appears. Creating a lexical binding for the function name not only creates a new local function or macro definition, but also shadows2 the compiler macro.

The function returned by compiler-macro-function is a function of two arguments, called the expansion function. To expand a compiler macro, the expansion function is invoked by calling the macroexpand hook with the expansion function as its first argument, the entire compiler macro form as its second argument, and the current compilation environment (or with the current lexical environment, if the form is being processed by something other than compile-file) as its third argument. The macroexpand hook, in turn, calls the expansion function with the form as its first argument and the environment as its second argument. The return value from the expansion function, which is passed through by the macroexpand hook, might either be the same form, or else a form that can, at the discretion of the code doing the expansion, be used in place of the original form.

*macroexpand-hook* compiler-macro-function define-compiler-macro

Figure 3.6: Defined names applicable to compiler macros

3.2.2.1.1 Purpose of Compiler Macros

The purpose of the compiler macro facility is to permit selective source code transformations as optimization advice to the compiler. When a compound form is being processed (as by the compiler), if the operator names a compiler macro then the compiler macro function may be invoked on the form, and the resulting expansion recursively processed in preference to performing the usual processing on the original form according to its normal interpretation as a function form or macro form.

A compiler macro function, like a macro function, is a function of two arguments: the entire call form and the environment. Unlike an ordinary macro function, a compiler macro function can decline to provide an expansion merely by returning a value that is the same as the original form. The consequences are undefined if a compiler macro function destructively modifies any part of its form argument.

The form passed to the compiler macro function can either be a list whose car is the function name, or a list whose car is funcall and whose cadr is a list (function name); note that this affects destructuring of the form argument by the compiler macro function. define-compiler-macro arranges for destructuring of arguments to be performed correctly for both possible formats.

When compile-file chooses to expand a top level form that is a compiler macro form, the expansion is also treated as a top level form for the purposes of eval-when processing; see Section 3.2.3.1 (Processing of Top Level Forms).

3.2.2.1.2 Naming of Compiler Macros

Compiler macros may be defined for function names that name macros as well as functions.

Compiler macro definitions are strictly global. There is no provision for defining local compiler macros in the way that macrolet defines local macros. Lexical bindings of a function name shadow any compiler macro definition associated with the name as well as its global function or macro definition.

Note that the presence of a compiler macro definition does not affect the values returned by functions that access function definitions (e.g., fboundp) or macro definitions (e.g., macroexpand). Compiler macros are global, and the function compiler-macro-function is sufficient to resolve their interaction with other lexical and global definitions.

3.2.2.1.3 When Compiler Macros Are Used

The presence of a compiler macro definition for a function or macro indicates that it is desirable for the compiler to use the expansion of the compiler macro instead of the original function form or macro form. However, no language processor (compiler, evaluator, or other code walker) is ever required to actually invoke compiler macro functions, or to make use of the resulting expansion if it does invoke a compiler macro function.

When the compiler encounters a form during processing that represents a call to a compiler macro name (that is not declared notinline), the compiler might expand the compiler macro, and might use the expansion in place of the original form.

When eval encounters a form during processing that represents a call to a compiler macro name (that is not declared notinline), eval might expand the compiler macro, and might use the expansion in place of the original form.

There are two situations in which a compiler macro definition must not be applied by any language processor:

It is unspecified whether compiler macros are expanded or used in any other situations.

3.2.2.1.3.1 Notes about the Implementation of Compiler Macros

Although it is technically permissible, as described above, for eval to treat compiler macros in the same situations as compiler might, this is not necessarily a good idea in interpreted implementations.

Compiler macros exist for the purpose of trading compile-time speed for run-time speed. Programmers who write compiler macros tend to assume that the compiler macros can take more time than normal functions and macros in order to produce code which is especially optimal for use at run time. Since eval in an interpreted implementation might perform semantic analysis of the same form multiple times, it might be inefficient in general for the implementation to choose to call compiler macros on every such evaluation.

Nevertheless, the decision about what to do in these situations is left to each implementation.

3.2.2.2 Minimal Compilation

Minimal compilation is defined as follows:

3.2.2.3 Semantic Constraints

All conforming programs must obey the following constraints, which are designed to minimize the observable differences between compiled and interpreted programs:

Conforming programs should not be written using any additional assumptions about consistency between the run-time environment and the startup, evaluation, and compilation environments.

Except where noted, when a compile-time and a run-time definition are different, one of the following occurs at run time:

If the compiler processes a function form whose operator is not defined at compile time, no error is signaled at compile time.