Ticket #1112 (assigned defect)

Opened 2 years ago

Last modified 2 years ago

#[-+] reader macros don't nest correctly

Reported by: dkatzman Owned by: gb
Priority: normal Milestone:
Component: ANSI CL Compliance Version: trunk
Keywords: Cc:


This function prints (C), (B), (B), (A) as tested under SBCL and CLISP on x86/darwin.

(defun test ()
  (print (read-from-string "#-x86 #-darwin (a) (b) (c)"))
  (print (read-from-string "#-x86 #+darwin (a) (b) (c)"))
  (print (read-from-string "#+x86 #-darwin (a) (b) (c)"))
  (print (read-from-string "#+x86 #+darwin (a) (b) (c)"))

CCL prints (B), (C), (B), (A) by the following rationale:

In the first test, 'x86' is true so a form must be discarded. 'darwin' is true so the '(a)' reads as NIL due to read-suppress being T. NIL is the expression skipped by the #-x86 making (b) the next expression. etc.

This is probably what you want:

Index: l1-reader.lisp
--- l1-reader.lisp	(revision 15900)
+++ l1-reader.lisp	(working copy)
@@ -2950,7 +2950,7 @@
 (defun read-feature (stream)
-  (let* ((f (let* ((*package* *keyword-package*))
+  (let* ((f (let* ((*package* *keyword-package*) (*read-suppress* nil))
               (read stream t nil t))))
     (labels ((eval-feature (form)
                (cond ((atom form)

Change History

comment:1 Changed 2 years ago by gb

  • Owner set to gb
  • Status changed from new to assigned

I don't know of anything in the spec that says anything about how nested conditionals like those in your example should be handled. If you know of such things, I'd be interested in hearing of them.

You can certainly say that CCL differs from other implementations in its handling of cases like this; as I said, I'm not sure that that either behavior is any more or less correct than the other (or than other plausible behaviors.)

< http://www.franz.com/support/documentation/8.2/doc/implementation.htm#nested-conditionals-3> discusses how Franz addressed the fact that their implementation had different behavior than other implementations (and than CCL), and I think that their solution is probably reasonable. (There's no compelling reason to be arbitrarily different from other implementations in this case, but changing an implementation's behavior could break existing code and there likely needs to be some simple way to revert to traditional behavior.)

If we don't do this, it's likely only a matter of time before someone says "this behavior is incorrect, because it's not what I see in Acme Common Lisp", and it's not worth having that argument.

Note: See TracTickets for help on using tickets.