Does Common Lisp fully expand macros at compile time?

Problem with Macroexpansions

I encountered a problem with macroexpansions which I have managed to reduce to the following code snippet:

(defmacro tester (f &rest args)
  (cond
    ((not (listp args))  `(,f ,args))
    ((= (length args) 1) `(,f ,(car args)))
    (t (loop for arg in args
             collect `(tester ,f ,@arg) into results
             finally (return `(list ,@results))))))

When I evaluate the expression (tester (lambda (a) (+ 1 a)) (1 2) 2 3) in the REPL, I get the expected result ((2 3) 3 4). However, if I try to wrap the code in a function or compile it, I get the following error:

Execution of a form compiled with errors.
Form:
  (TESTER (LAMBDA (A) (+ 1 A)) . 1)
Compile-time error:
  (TESTER (LAMBDA (A) (+ 1 A)) . 1) is not a proper list.
   [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

Why does this happen even though evaluating the expression works as expected?

The issue occurs because when the code is compiled, the compiler tries to evaluate (1 2) as a function call, but it is not a proper list. However, when you evaluate the expression in the REPL, it is treated as a macro call and expands correctly.

To fix this issue, you can modify the macro definition to handle the case when args is not a list. Here’s an updated version of the tester macro:

(defmacro tester (f &rest args)
  (cond
    ((not (listp args))  `(,f ,args))
    ((= (length args) 1) `(,f ,(car args)))
    ((not (proper-list-p args)) `(apply #',f ,args))
    (t (loop for arg in args
             collect `(tester ,f ,@arg) into results
             finally (return `(list ,@results))))))

With this updated version, the code should compile without any errors, and you will get the expected result when evaluating (tester (lambda (a) (+ 1 a)) (1 2) 2 3).