Expanding nested macro calls during code compilation/evaluation

I have a next piece of code:

(in-package :cl-user)

(defmacro test0 (form)
  (format t "test0: Expander phase: ~s" form)
  `(format t "test0: Expansion phase: ~s" ,form))

(defmacro test1 (form)
  (format t "test1: Expander phase: ~s" form)
  (test0 form)
  `(format t "test1: Expansion phase: ~s" ,form))

Common Lisp implementation: "SBCL 1.3.16".

  1. Results of (compile-file "source.lisp"): ; compiling (IN-PACKAGE :CL-USER) ; compiling (DEFMACRO TEST0 ...) ; compiling (DEFMACRO TEST1 ...)test0: Expander phase: FORMtest0: Expander phase: FORM

  2. Results of (load "source.lisp"): ; #<PACKAGE "COMMON-LISP-USER"> ; TEST0 test0: Expander phase: FORM ; TEST1

And I just can't understand next things:

  1. Why is nested subform (test0 form) expanded and processed in the definition of test1 macro? Why isn't it processed in the macro call instead?

  2. Where is Common Lisp standard specify such a behavior? eval-when? Files compilation? Forms evaluation?

  3. Finally, why is "test0: Expander phase: FORM" printed twice during compilation(compile-file) and only once during evaluation(load)?

I think the answers are pretty obvious but I can't find them out.

Upvotes: 0

Views: 219

Answers (1)

sds
sds

Reputation: 60004

A macro is a function which operates on code. Since in Lisp code is just a list, macro functions look like ordinary functions.

Your defmacro test1 is treated as a definition of a function, so all the code is processed appropriately and (test0 form) is macroexpanded when the SBCL compiles defmacro test1. This answers q1.

load "sequentially executes each form it encounters", so to answer your q2, you need to read 3.1 Evaluation, specifically, 3.1.2.1.2.2 Macro Forms.

As for how many times a macro is expanded, this is not specified by the standard (an implementation can expand it on every call of the user function!), and this is a reason why it is not a good idea for a macro to have side effects (e.g., to do output). In your case, loading requires expansion when test1 is defined. Compilation expands when it defines test1 and then again when it compiles it. Remember, defmacro arranges that the macro can be used in the following code (including in itself recursively), so is has to be defined immediately.

Upvotes: 5

Related Questions