walker:macroexpand-all doesn't macroexpand in some cases
Description
walker:macroexpand-all
doesn't expand macros in three cases: if it is a global symbol-macro, a local symbol-macro in environment passed as a second argument, or a local macro in the form to be expanded.
"Mega" test
Here is a test for 6 possible cases where macro expansion should happen:
;; utility macro
(defmacro at-compile-time ((&optional env) &body body)
(let ((capture (gensym)))
`(macrolet ((,capture (,@(when env `(&environment ,env)))
,@body))
(,capture))))
(defmacro NO-1 () ''YES-1)
(define-symbol-macro NO-4 'YES-4)
(macrolet ((NO-3 () ''YES-3))
(symbol-macrolet ((NO-6 'YES-6))
(at-compile-time (env)
`',(walker:macroexpand-all
'(macrolet ((NO-2 () ''YES-2))
(symbol-macrolet ((NO-5 'YES-5))
(values (NO-1) (NO-2) (NO-3) NO-4 NO-5 NO-6)))
env))))
The produced expansion:
(MACROLET ((NO-2 ()
''YES-2))
(SYMBOL-MACROLET ((NO-5 'YES-5))
(VALUES 'YES-1 (NO-2) 'YES-3 NO-4 'YES-5 NO-6)))
Expected expansion:
(MACROLET ((NO-2 ()
''YES-2))
(SYMBOL-MACROLET ((NO-5 'YES-5))
(VALUES 'YES-1 'YES-2 'YES-3 'YES-4 'YES-5 'YES-6)))
"Mini" tests
Smaller tests for those three cases where macroexpansion doesn't happen:
(define-symbol-macro macroexpand-all-test-1 'expanded)
(walker:macroexpand-all 'macroexpand-all-test-1)
; => MACROEXPAND-ALL-TEST-1
(symbol-macrolet ((macroexpand-all-test-2 'expanded))
(macrolet ((thunk (&environment env)
`',(walker:macroexpand-all
'macroexpand-all-test-2
env)))
(thunk)))
; => MACROEXPAND-ALL-TEST-2
(walker:macroexpand-all
'(macrolet ((macroexpand-all-test-3 () ''expanded))
(macroexpand-all-test-3)))
; => (MACROLET ((MACROEXPAND-ALL-TEST-3 ()
; ''EXPANDED))
; (MACROEXPAND-ALL-TEST-3))
Additional information
Comparison of macroexpand-all
provided by different implementations (using a portability layer, trivial-macroexpand-all
): https://plaster.tymoon.eu/view/4009#4009
SBCL, CCL and ABCL expand (symbol-)macros in all 6 cases. Allegro CL, LispWorks and CLISP expand macros in 4 cases; not accepting an additional environment argument.
ECL version
(format t "~&~@{~12@A ~S~%~}"
:version (lisp-implementation-version)
:vcs-id (ext:lisp-implementation-vcs-id)
:os (software-type)
:os-version (software-version)
:machine-type (machine-type)
:features *features*)
VERSION "23.9.9"
VCS-ID "UNKNOWN"
OS "Linux"
OS-VERSION "6.2.0-34-generic"
MACHINE-TYPE "x86_64"
FEATURES (:NAMED-READTABLES :BORDEAUX-THREADS :64-BIT :X86-64 :GLOBAL-VARS
:SPLIT-SEQUENCE :CLOSER-MOP :THREAD-SUPPORT :QUICKLISP
:ASDF-PACKAGE-SYSTEM :ASDF3.1 :ASDF3 :ASDF2 :ASDF :OS-UNIX
:NON-BASE-CHARS-EXIST-P :ASDF-UNICODE :WALKER :CDR-6 :CDR-1
:CDR-5 :LINUX :FORMATTER :CDR-7 :ECL-WEAK-HASH :LITTLE-ENDIAN
:ECL-READ-WRITE-LOCK :LONG-LONG :UINT64-T :UINT32-T :UINT16-T
:COMPLEX-FLOAT :LONG-FLOAT :UNICODE :DFFI :CLOS-STREAMS
:CMU-FORMAT :UNIX :ECL-PDE :DLOPEN :CLOS :THREADS :BOEHM-GC
:ANSI-CL :COMMON-LISP :FLOATING-POINT-EXCEPTIONS
:IEEE-FLOATING-POINT :PACKAGE-LOCAL-NICKNAMES :CDR-14
:PREFIXED-API :FFI :X86_64 :COMMON :ECL)