File compilation is defined in Common Lisp: CLHS Section 3.2.3 File Compilation
At compilation: To use a form using a read macro, you must make this implementation of the read macros available to the compiler.
Typically, these dependencies are processed using the defsystem , which describes the dependencies between the various files of the system (something like a project). To compile a specific file, another file (preferably a compiled version) must be loaded into Lisp compilation.
Now, if you want to define a read macro and have forms using its notation in the same file, you need to make sure again that the compiler knows about the read macro and its implementation. The file compiler has a compilation environment. It does not load compiled functions of the same file into this environment by default.
To make the compiler aware of specific code in the file, it compiles Common Lisp provides EVAL-WHEN .
See an example of a read macro:
(set-syntax-from-char #\] #\)) (defun reader-example (stream char) (declare (ignore char)) (let ((class (read stream t nil t)) (args (read-delimited-list #\] stream t))) (apply #'make-instance class args))) (set-macro-character #\[ 'reader-example) (defclass example () ((name :initarg :name))) (defvar *examples* (list [example :name e1] [example :name e2] [example :name e3]))
If you download the above source, everything is in order. But if we use a file compiler, it does not compile without loading it in the first place. For example, a file compiler is called by calling the COMPILE-FILE function with the path name.
Now compile the file:
(set-syntax-from-char #\] #\))
The above will not be executed at compile time. A new syntax change will not be available at compile time.
(defun reader-example (stream char) (declare (ignore char)) (let ((class (read stream t nil t)) (args (read-delimited-list
The above function compiles but does not load. This implementation is not available to the compiler in subsequent steps.
(set-macro-character
Again, the above form is not executed - only the code for it is generated.
(defclass example () ((name :initarg :name)))
The compiler notices the class, but cannot do it later.
(defvar *examples* (list [example :name e1] [example :name e2] [example :name e3]))
The above code throws an error because the read macro is not available at compile time - unless it has been loaded before.
Now there are two simple solutions:
put the implementation of the read macro in a separate file and make sure that it is compiled and loaded before any file that uses the read macro.
put EVAL-WHEN around the code, which should have an effect at compile time:
Example:
(EVAL-WHEN (:compile-toplevel :load-toplevel :execute) (do-something-also-at-compile-time))
The compiler will be visible above, and then it will be executed. Now you need to make sure that the code has everything that it calls (all necessary definitions) at compile time.
Needless to say: this is a good style to reduce such compilation dependencies as much as possible. Usually add the necessary functions to a separate file and make sure that this file is compiled and loaded into the Lisp compilation before compiling the file that uses it.