The Allegro compiler won't compile some iterate forms that expand to a tagbody form that has several nil tags. At first I thought that it was a bug with allegro, since it worked fine in sbcl, and in allegros own interpreter. But on second thought and some reading of the hyperspec, I think it is the allegro compiler that is right:
hyperspec: ...The statements in a tagbody are evaluated in order from left to right, and their values are discarded. If at any time there are no remaining statements, tagbody returns nil. However, if (go tag) is evaluated, control jumps to the part of the body labeled with the tag. (Tags are compared with eql.) ...
and since tags are compared with eql, how can we allow several nils? If tags with the same label was allowed, the description should say something about "the first" or "the last" tag. Now it says labeled with THE tag, singularis.
I have attached two bundled darcs-patches, first a testcase that shows the problem, then a solution. I have run all tests with sbcl and allegro. As usual it turns out it was more difficult to write a test than to fix the bug.
/Henrik Hjelte
(TAGBODY (print "hi") NIL (print "ciao") LOOP-TOP-NIL (print "hello") NIL (print "second nil") )
; the Allegro error is :
;;Tag NIL is used more than once ;;Problem detected when processing ;; (TAGBODY (PRINT "hi") NIL...) ;;inside (BLOCK MYTEST (TAGBODY (PRINT "hi") NIL...)) ;;inside (PROGN (BLOCK MYTEST (TAGBODY # NIL...))) ;; ;; [Condition of type PARSE-ERROR]
And why these nils turn up in iterate, see the testcase in the patch for an example.
Henrik Hjelte wrote:
The Allegro compiler won't compile some iterate forms that expand to a tagbody form that has several nil tags.
Probably Allegro would complain the same about any two EQL tags in the body. You're right, that's a bug in Iterate. Actually, it's two bugs, and you fixed only one of them ;)
1. Iterate must protect the TAGBODY it generates against inadvertent tags. Probably, only NIL is problematic as a result of macroexpansion. You found and correctly fixed this one.
That's why some people recommend against having macros ever expand to NIL.
2. The code walker for TAGBODY is incorrect. CLHS says: "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." Iterates macroexpands everything without that distinction. As a result (macrolet ((foo () nil)) (iterate (repeat 1) (tagbody (foo) (foo)))) is not expanded correctly, and Allegro would complain.
The situation could be worse from the presence of macros with implicit tagbodies, such as DO and PROG etc. Luckily, Iterate does not special-case them, and relies on the implementation to provide correct macro expanders eventually based on special forms. A nice example of good tower construction (cf. "growing a language"). Of course, the TAGBODY special form need be handled correctly.
Thank you for your bug report.
Regards, Jorg Hohle.
I have attached two bundled darcs-patches, first a testcase that shows the problem, then a solution. I have run all tests with sbcl and allegro. As usual it turns out it was more difficult to write a test than to fix the bug.
after testing it locally for quite some time now, i've pushed this fix because it's preventing actual code from running on acl.
i hope nobody minds,
Attila Lendvai wrote:
after testing it locally for quite some time now, i've pushed this fix because it's preventing actual code from running on acl.
The patch looked clean, so it's ok.
I've written a patch to fix the other issue that I mentioned:
- The code walker for TAGBODY is incorrect.
But I've not yet added testcases and released my patch.
Regards, Jörg Höhle.