Clozure / ccl

Clozure Common Lisp
http://ccl.clozure.com
Apache License 2.0
855 stars 103 forks source link

`ccl:macroexpand-all` and `tagbody` #523

Open Gleefre opened 3 weeks ago

Gleefre commented 3 weeks ago

There are two problems caused by not treating forms in the tagbody correctly.

1) ccl:macroexpand-all expands symbols that have a symbol-macro definition in tagbody when they are in the tag position. 2) ccl:macroexpand-all doesn't "protect" macroexpansion of the macros in tagbody that can becom a tag (symbols and integers).

(ccl:macroexpand-all
 '(symbol-macrolet ((tag (tag-expanded)))
   (tagbody tag)))
; => (PROGN (TAGBODY (TAG-EXPANDED)))

(ccl:macroexpand-all
 '(macrolet ((not-tag () 'tag-expanded))
   (tagbody (not-tag))))
; => (PROGN (TAGBODY TAG-EXPANDED))

The determination of which elements of the body are tags and which are statements is made prior to any macro expansion of that element. If a statement is a macro form and its macro expansion is an atom, that atom is treated as a statement, not a tag.

-- CLHS, tagbody: https://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm

That means that 1) tag in tagbody should not be expanded. 2) (not-tag) expansion should be "protected" so that it doesn't become a tag, for example via progn.

Tested on CCL 1.13

(lisp-implementation-version)  ; => "Version 1.13 (v1.13) LinuxX8664"

This affects quite a few other implementations, see this table (two last columns): https://plaster.tymoon.eu/view/4637.