The compiler is a program that may make code run faster by translating programs into an implementation-dependent form that can be executed more eﬃciently by the computer. Most of the time you can write programs without worrying about the compiler; compiling a ﬁle of code should produce an equivalent but more eﬃcient program. When doing more esoteric things, you may need to think carefully about what happens at “compile time” and what happens at “load time.” Then the eval-when construct becomes particularly useful.
Most declarations are not used by the Common Lisp interpreter; they may be used to give advice to the compiler. The compiler may attempt to check your advice and warn you if it is inconsistent.
Unlike most other Lisp dialects, Common Lisp recognizes special declarations in interpreted code as well as compiled code.
The internal workings of a compiler will of course be highly implementation-dependent. The following functions provide a standard interface to the compiler, however.
[Function]compile name &optional deﬁnition
If deﬁnition is supplied, it should be a lambda-expression, the interpreted function to be compiled. If it is not supplied, then name should be a symbol with a deﬁnition that is a lambda-expression; that deﬁnition is compiled and the resulting compiled code is put back into the symbol as its function deﬁnition.
namemay be any function-name (a symbol or a list whose car is setf—see section 7.1). One may write (compile ’(setf cadr)) to compile the setf expansion function for cadr.
If the optional deﬁnition argument is supplied, it may be either a lambda-expression (which is coerced to a function) or a function to be compiled; if no deﬁnition is supplied, the symbol-function of the symbol is extracted and compiled. It is permissible for the symbol to have a macro deﬁnition rather than a function deﬁnition; both macros and functions may be compiled.
It is an error if the function to be compiled was deﬁned interpretively in a non-null lexical environment. (An implementation is free to extend the behavior of compile to compile such functions properly, but portable programs may not depend on this capability.) The consequences of calling compile on a function that is already compiled are unspeciﬁed.
The deﬁnition is compiled and a compiled-function object produced. If name is a non-nil symbol, then the compiled-function object is installed as the global function deﬁnition of the symbol and the symbol is returned. If name is nil, then the compiled-function object itself is returned. For example:
X3J13 voted in March 1989 to add two new keyword arguments :verbose and :print to compile-ﬁle by analogy with load. The new function deﬁnition is as follows.
[Function]compile-ﬁle input-pathname &key :output-ﬁle :verbose :print
The input-pathname must be a valid ﬁle speciﬁer, such as a pathname. The defaults for input-ﬁlename are taken from the variable *default-pathname-defaults*. The ﬁle should be a Lisp source ﬁle; its contents are compiled and written as a binary object ﬁle.
The :verbose argument (which defaults to the value of *compile-verbose*), if true, permits compile-ﬁle to print a message in the form of a comment to *standard-output* indicating what ﬁle is being compiled and other useful information.
The :print argument (which defaults to the value of *compile-print*), if true, causes information about top-level forms in the ﬁle being compiled to be printed to *standard-output*. Exactly what is printed is implementation-dependent; nevertheless something will be printed.
X3J13 voted in March 1988 to specify exactly which streams may be used as pathnames (see section 23.1.6).
The :output-ﬁle argument may be used to specify an output pathname; it defaults in a manner appropriate to the implementation’s ﬁle system conventions.
X3J13 voted in June 1989 to specify that compile-ﬁle returns three values: the truename of the output ﬁle (or nil if the ﬁle could not be created) and two values indicating whether the compiler issued any diagnostics (see section 24.1.1).
X3J13 voted in October 1988 to specify that compile-ﬁle, like load, rebinds *package* to its current value. If some form in the ﬁle changes the value of *package*, the old value will be restored when compilation is completed.
In order to guarantee that compiled ﬁles can be loaded correctly, the user must ensure that the packages referenced in the ﬁle are deﬁned consistently at compile and load time. Conforming Common Lisp programs must satisfy the following requirements.
If any of these conditions do not hold, the package in which load looks for the aﬀected symbols is unspeciﬁed. Implementations are permitted to signal an error or otherwise deﬁne this behavior.
These requirements are merely an explicit statement of the status quo, namely that users cannot depend on any particular behavior if the package environment at load time is inconsistent with what existed at compile time.
X3J13 voted in March 1989 to specify that compile-ﬁle must bind *readtable* to its current value at the time compile-ﬁle is called; the dynamic extent of the binding should encompass all of the ﬁle-loading activity. This allows a portable program to include forms such as
without performing a net global side eﬀect on the loading environment. Such statements allow the remainder of such a ﬁle to be read either as interpreted code or by compile-ﬁle in a syntax determined by an alternative readtable.
X3J13 voted in June 1989 to require that compile-ﬁle bind two new variables *compile-ﬁle-pathname* and *compile-ﬁle-truename*; the dynamic extent of the bindings should encompass all of the ﬁle-compiling activity.
This variable provides the default for the :verbose argument to compile-ﬁle. Its initial value is implementation-dependent.
This variable provides the default for the :print argument to compile-ﬁle. Its initial value is implementation-dependent.
X3J13 voted in June 1989 to introduce *compile-ﬁle-pathname*; it is initially nil but compile-ﬁle binds it to a pathname that represents the ﬁle name given as the ﬁrst argument to compile-ﬁle merged with the defaults (see merge-pathname).
This is a mechanism for delaying evaluation of a form until it can be done in the run-time environment.
If a load-time-value expression is seen by compile-ﬁle, the compiler performs its normal semantic processing (such as macro expansion and translation into machine code) on the form, but arranges for the execution of the form to occur at load time in a null lexical environment, with the result of this evaluation then being treated as an immediate quantity (that is, as if originally quoted) at run time. It is guaranteed that the evaluation of the form will take place only once when the ﬁle is loaded, but the order of evaluation with respect to the execution of top-level forms in the ﬁle is unspeciﬁed.
If a load-time-value expression appears within a function compiled with compile, the form is evaluated at compile time in a null lexical environment. The result of this compile-time evaluation is treated as an immediate quantity in the compiled code.
In interpreted code, form is evaluated (by eval) in a null lexical environment and one value is returned. Implementations that implicitly compile (or partially compile) expressions passed to eval may evaluate the form only once, at the time this compilation is performed. This is intentionally similar to the freedom that implementations are given for the time of expanding macros in interpreted code.
If the same (as determined by eq) list (load-time-value form) is evaluated or compiled more than once, it is unspeciﬁed whether the form is evaluated only once or is evaluated more than once. This can happen both when an expression being evaluated or compiled shares substructure and when the same expression is passed to eval or to compile multiple times. Since a load-time-value expression may be referenced in more than one place and may be evaluated multiple times by the interpreter, it is unspeciﬁed whether each execution returns a “fresh” object or returns the same object as some other execution. Users must use caution when destructively modifying the resulting object.
The optional read-only-p argument designates whether the result may be considered a read-only constant. If nil (the default), the result must be considered ordinary, modiﬁable data. If t, the result is a read-only quantity that may, as appropriate, be copied into read-only space and may, as appropriate, be shared with other programs. The read-only-p argument is not evaluated and only the literal symbols t and nil are permitted.
This new feature addresses the same set of needs as the now-defunct #, reader syntax but in a cleaner and more general manner. Note that #, syntax was reliably useful only inside quoted structure (though this was not explicitly mentioned in the ﬁrst edition), whereas a load-time-value form must appear outside quoted structure in a for-evaluation position.
The argument should be a function object, a lambda-expression, or a symbol with a function deﬁnition. If the relevant function is not a compiled function, it is ﬁrst compiled. In any case, the compiled code is then “reverse-assembled” and printed out in a symbolic format. This is primarily useful for debugging the compiler, but also often of use to the novice who wishes to understand the workings of compiled code. ________________________________________________
Заметка для реализации: Implementors are encouraged to make the output readable, preferably with helpful comments.
When disassemble compiles a function, it never installs the resulting
compiled-function object in the symbol-function of a symbol.
namemay be any function-name (a symbol or a list whose car is setf—see section 7.1). Thus one may write (disassemble ’(setf cadr)) to disassemble the setf expansion function for cadr.
This function allows the source code for a deﬁned function to be recovered. (The committee noted that the ﬁrst edition provided no portable way to recover a lambda-expression once it had been compiled or evaluated to produce a function.)
This function takes one argument, which must be a function, and returns three values.
The ﬁrst value is the deﬁning lambda-expression for the function, or nil if that information is not available. The lambda-expression may have been preprocessed in some ways but should nevertheless be of a form suitable as an argument to the function compile or for use in the function special operator.
The second value is nil if the function was deﬁnitely produced by closing a lambda-expression in the null lexical environment; it is some non-nil value if the function might have been closed in some non-null lexical environment.
The third value is the “name” of the function; this is nil if the name is not available or if the function had no name. The name is intended for debugging purposes only and may be any Lisp object (not necessarily one that would be valid for use as a name in a defun or function special operator, for example). _________________________________________________________________
Заметка для реализации: An implementation is always free to return the values nil, t, nil from this function but is encouraged to make more useful information available as appropriate. For example, it may not be desirable for ﬁles of compiled code to retain the source lambda-expressions for use after the ﬁle is loaded, but it is probably desirable for functions produced by “in-core” calls to eval, compile, or defun to retain the deﬁning lambda-expression for debugging purposes. The function function-lambda-expression makes this information, if retained, accessible in a standard and portable manner.
with-compilation-unit executes the body forms as an implicit progn. Within the dynamic context of this form, warnings deferred by the compiler until “the end of compilation” will be deferred until the end of the outermost call to with-compilation-unit. The results are the same as those of the last of the forms (or nil if there is no form).
Each option-name is an unevaluated keyword; each option-value is evaluated. The set of keywords permitted may be extended by the implementation, but the only standard option keyword is :override; the default value for this option is nil. If with-compilation-unit forms are nested dynamically, only the outermost such call has any eﬀect unless the :override value of an inner call is true.
The function compile-ﬁle should provide the eﬀect of
around its code.
Any implementation-dependent extensions to this behavior may be provided only as the result of an explicit programmer request by use of an implementation-dependent keyword. It is forbidden for an implementation to attach additional meaning to a conforming use of this macro.
Note that not all compiler warnings are deferred. In some implementations, it may be that none are deferred. This macro only creates an interface to the capability where it exists, it does not require the creation of the capability. An implementation that does not defer any compiler warnings may correctly implement this macro as an expansion into a simple progn.
compile and compile-ﬁle may output warning messages; any such messages should go to the stream that is the value of *error-output*.
First, note that error and warning conditions may be signaled either by the compiler itself or by code being processed by the compiler (for example, arbitrary errors may occur during compile-time macro expansion or processing of eval-when forms). Considering only those conditions signaled by the compiler (as opposed to during compilation):
Both compile and compile-ﬁle are permitted (but not required) to establish a handler for conditions of type error. Such a handler might, for example, issue a warning and restart compilation from some implementation-dependent point in order to let the compilation proceed without manual intervention.
The functions compile and compile-ﬁle each return three values. See the deﬁnitions of these functions for descriptions of the ﬁrst value. The second value is nil if no compiler diagnostics were issued, and true otherwise. The third value is nil if no compiler diagnostics other than style warnings were issued; a non-nil value indicates that there were “serious” compiler diagnostics issued or that other conditions of type error or warning (but not style-warning) were signaled during compilation.
Certain requirements are imposed on the functions produced by the compilation process.
If a function is of type compiled-function, then all macro calls appearing lexically within the function have already been expanded and will not be expanded again when the function is called. The process of compilation eﬀectively turns every macrolet or symbol-macrolet construct into a progn (or a locally) with all instances of the local macros in the body fully expanded.
If a function is of type compiled-function, then all load-time-value forms appearing lexically within the function have already been pre-evaluated and will not be evaluated again when the function is called.
Implementations are free to classify every function as a compiled-function provided that all functions satisfy the preceding requirements. Conversely, it is permissible for a function that is not a compiled-function to satisfy the preceding requirements.
If one or more functions are deﬁned in a ﬁle that is compiled with compile-ﬁle and the compiled ﬁle is subsequently loaded by the function load, the resulting loaded function deﬁnitions must be of type compiled-function.
The function compile must produce an object of type compiled-function as the value that is either returned or stored into the symbol-function of a symbol argument.
Note that none of these restrictions addresses questions of the compilation technology or target instruction set. For example, a compiled function does not necessarily consist of native machine instructions. These requirements merely specify the behavior of the type system with respect to certain actions taken by compile, compile-ﬁle, and load.
Following information must be available at compile time for correct compilation and what need not be available until run time.
The following information must be present in the compile-time environment for a program to be compiled correctly. This information need not also be present in the run-time environment.
The compiler may incorporate the following kinds of information into the code it produces, if the information is present in the compile-time environment and is referenced within the code being compiled; however, the compiler is not required to do so. When compile-time and run-time deﬁnitions diﬀer, it is unspeciﬁed which will prevail within the compiled code (unless some other behavior is explicitly speciﬁed below). It is also permissible for an implementation to signal an error at run time on detecting such a discrepancy. In all cases, the absence of the information at compile time is not an error, but its presence may enable the compiler to generate more eﬃcient code.
The compiler must not make any additional assumptions about consistency between the compile-time and run-time environments. In particular, the compiler may not assume that functions that are deﬁned in the compile-time environment will retain either the same deﬁnition or the same signature at run time, except as described above. Similarly, the compiler may not signal an error if it sees a call to a function that is not deﬁned at compile time, since that function may be provided at run time.
X3J13 voted in January 1989 to specify the compile-time side eﬀects of processing various macro forms.
Calls to deﬁning macros such as defmacro or defvar appearing within a ﬁle being processed by compile-ﬁle normally have compile-time side eﬀects that aﬀect how subsequent forms in the same ﬁle are compiled. A convenient model for explaining how these side eﬀects happen is that each deﬁning macro expands into one or more eval-when forms and that compile-time side eﬀects are caused by calls occurring in the body of an (eval-when (:compile-toplevel) ...) form.
The aﬀected deﬁning macros and their speciﬁc side eﬀects are as follows. In each case, it is identiﬁed what a user must do to ensure that a program is conforming, and what a compiler must do in order to correctly process a conforming program.
Compile-time side eﬀects may cause information about a deﬁnition to be stored in a diﬀerent manner from information about deﬁnitions processed either interpretively or by loading a compiled ﬁle. In particular, the information stored by a deﬁning macro at compile time may or may not be available to the interpreter (either during or after compilation) or during subsequent calls to compile or compile-ﬁle. For example, the following code is not portable because it assumes that the compiler stores the macro deﬁnition of foo where it is available to the interpreter.
The goal may be accomplished portably by including the macro deﬁnition within the eval-when form:
X3J13 voted in June 1989 to add a new macro declaim for making proclamations recognizable at compile time. The declaration speciﬁers in the declaim form are eﬀectively proclaimed at compile time so as to aﬀect compilation of subsequent forms. (Note that compiler processing of a call to proclaim does not have any compile-time side eﬀects, for proclaim is a function.)
X3J13 voted in June 1989 to specify the compile-time side eﬀects of processing various CLOS-related macro forms. Top-level calls to the CLOS deﬁning macros have the following compile-time side eﬀects; any other compile-time behavior is explicitly left unspeciﬁed.
The error-signaling behavior described in the speciﬁcation of defmethod in chapter 28 (if the function isn’t a generic function or if the lambda-list is not congruent) occurs only when the deﬁning form is executed, not at compile time.
The forms in eql parameter specializers are evaluated when the defmethod form is executed. The compiler is permitted to build in knowledge about what the form in an eql specializer will evaluate to in cases where the ultimate result can be syntactically inferred without actually evaluating it.
The body of a deﬁne-method-combination form is evaluated no earlier than when the deﬁning macro is executed and possibly as late as generic function invocation time. The compiler may attempt to evaluate these forms at compile time but must not depend on being able to do so.
Following paragraphs speciﬁes what objects can be in compiled constants and what relationship there must be between a constant passed to the compiler and the one that is established by compiling it and then loading its ﬁle.
The key is a deﬁnition of an equivalence relationship called “similarity as constants” between Lisp objects. Code passed through the ﬁle compiler and then loaded must behave as though quoted constants in it are similar in this sense to quoted constants in the corresponding source code. An object may be used as a quoted constant processed by compile-ﬁle if and only if the compiler can guarantee that the resulting constant established by loading the compiled ﬁle is “similar as a constant” to the original. Speciﬁc requirements are spelled out below.
Some types of objects, such as streams, are not supported in constants processed by the ﬁle compiler. Such objects may not portably appear as constants in code processed with compile-ﬁle. Conforming implementations are required to handle such objects either by having the compiler or loader reconstruct an equivalent copy of the object in some implementation-speciﬁc manner or by having the compiler signal an error.
Of the types supported in constants, some are treated as aggregate objects. For these types, being similar as constants is deﬁned recursively. We say that an object of such a type has certain “basic attributes”; to be similar as a constant to another object, the values of the corresponding attributes of the two objects must also be similar as constants.
A deﬁnition of this recursive form has problems with any circular or inﬁnitely recursive object such as a list that is an element of itself. We use the idea of depth-limited comparison and say that two objects are similar as constants if they are similar at all ﬁnite levels. This idea is implicit in the deﬁnitions below, and it applies in all the places where attributes of two objects are required to be similar as constants. The question of handling circular constants is the subject of a separate vote by X3J13 (see below).
The following terms are used throughout this section. The term constant refers to a quoted or self-evaluating constant, not a named constant deﬁned by defconstant. The term source code is used to refer to the objects constructed when compile-ﬁle calls read (or the equivalent) and to additional objects constructed by macro expansion during ﬁle compilation. The term compiled code is used to refer to objects constructed by load.
Two objects are similar as a constant if and only if they are both of one of the types listed below and satisfy the additional requirements listed for that type.
Two numbers are similar as constants if they are of the same type and represent the same mathematical value.
Two characters are similar as constants if they both represent the same character. (The intent is that this be compatible with how eql is deﬁned on characters.)
The “similar as constants” relationship for interned symbols has nothing to do with *readtable* or how the function read would parse the characters in the print name of the symbol.
An uninterned symbol in the source code is similar as a constant to an uninterned symbol in the compiled code if their print names are similar as constants.
A package in the source code is similar as a constant to a package in the compiled code if their names are similar as constants. Note that the loader ﬁnds the corresponding package object as if by calling ﬁnd-package with the package name as an argument. An error is signaled if no package of that name exists at load time.
We say that two random-state objects are functionally equivalent if applying random to them repeatedly always produces the same pseudo-random numbers in the same order.
Two random-states are similar as constants if and only if copies of them made via make-random-state are functionally equivalent. (Note that a constant random-state object cannot be used as the state argument to the function random because random performs a side eﬀect on that argument.)
Two conses are similar as constants if the values of their respective car and cdr attributes are similar as constants.
Two arrays are similar as constants if the corresponding values of each of the following attributes are similar as constants: for vectors (one-dimensional arrays), the length and element-type and the result of elt for all valid indices; for all other arrays, the array-rank, the result of array-dimension for all valid axis numbers, the array-element-type, and the result of aref for all valid indices. (The point of distinguishing vectors is to take any ﬁll pointers into account.)
If the array in the source code is a simple-array, then the corresponding array in the compiled code must also be a simple-array, but if the array in the source code is displaced, has a ﬁll pointer, or is adjustable, the corresponding array in the compiled code is permitted to lack any or all of these qualities.
Two hash tables are similar as constants if they meet three requirements. First, they must have the same test (for example, both are eql hash tables or both are equal hash tables). Second, there must be a unique bijective correspondence between the keys of the two tables, such that the corresponding keys are similar as constants. Third, for all keys, the values associated with two corresponding keys must be similar as constants.
If there is more than one possible one-to-one correspondence between the keys of the two tables, it is unspeciﬁed whether the two tables are similar as constants. A conforming program cannot use such a table as a constant.
Two pathnames are similar as constants if all corresponding pathname components are similar as constants.
Objects of these types are not supported in compiled constants.
X3J13 voted in June 1989 to specify that objects of type function are not supported in compiled constants.
X3J13 voted in March 1989 to introduce a facility based on the Common Lisp Object System whereby a user can specify how compile-ﬁle and load must cooperate to reconstruct compile-time constant objects at load time (see make-load-form).
X3J13 voted in March 1989 to specify the circumstances under which constants may be coalesced in compiled code.
Suppose A and B are two objects used as quoted constants in the source code, and that A′ and B′ are the corresponding objects in the compiled code. If A′ and B′ are eql but A and B were not eql, then we say that A and B have been coalesced by the compiler.
An implementation is permitted to coalesce constants appearing in code to be compiled if and only if they are similar as constants, except that objects of type symbol, package, structure, or standard-object obey their own rules and may not be coalesced by a separate mechanism. ____________________________
Обоснование: Objects of type symbol and package cannot be coalesced because the fact that they are named, interned objects means they are already as coalesced as it is useful for them to be. Uninterned symbols could perhaps be coalesced, but that was thought to be more dangerous than useful. Structures and objects could be coalesced if a “similar as a constant” predicate were deﬁned for them; it would be a generic function. However, at present there is no such predicate. Currently make-load-form provides a protocol by which compile-ﬁle and load work together to construct an object in the compiled code that is equivalent to the object in the source code; a diﬀerent mechanism would have to be added to permit coalescing.
Note that coalescing is possible only because it is forbidden to destructively modify constants (see quote).
Objects containing circular or inﬁnitely recursive references may legitimately appear as constants to be compiled. The compiler is required to preserve eql-ness of substructures within a ﬁle compiled by compile-ﬁle.