Re: multiple read-time conditionals, puzzlement
Arthur Cater <[email protected]> Mon, 13 Mar 2023 17:20:16 +0000
| Newsgroups | gmane.lisp.openmcl.devel |
|---|---|
| Message-ID | <[email protected]> |
Just guessing, maybe READ-CONDITIONAL is inlined. It never previously occurred to me that read time conditionals could be nested. Didn’t memorise the CL spec quite thouroughy enough. When I saw it done I became curious as to how it would behave. I guess I’m not alone. Arthur > On 13 Mar 2023, at 16:14, Ron Garret <[email protected]> wrote: > > Yep, definitely a bug. CCL's behavior is inconsistent: > > Clozure Common Lisp Version 1.12 (v1.12) DarwinX8664 > ? (list #+ccl #-ccl #+ccl 1 2 3) > (3) > ? (list #-nil #+nil #-nil 1 2 3) > (2 3) > > It's a really weird bug too: > > ? (get-dispatch-macro-character #\# #\+) > #<Compiled-function CCL::READ-CONDITIONAL #x300000562BFF> > ? (get-dispatch-macro-character #\# #\-) > #<Compiled-function CCL::READ-CONDITIONAL #x300000562BFF> > ? (trace CCL::READ-CONDITIONAL) > NIL > ? #+ccl 1 > 1 > ? (trace ccl::read-feature) > NIL > ? #+ccl 1 > > 0> Calling (CCL::READ-FEATURE #<CCL::RECORDING-CHARACTER-INPUT-STREAM #x3020004F2E6D>) > <0 CCL::READ-FEATURE returned #\+ > 1 > > If you look at the source, the only place READ-FEATURE is called is in READ-CONDITIONAL, and yet the former is running but the latter is not. We can even double-check to see that this is not a problem with TRACE: > > ? (in-package :ccl) > #<Package "CCL"> > ? (defun read-conditional (stream subchar int) > (print "Entering READ-CONDITIONAL") > (cond ((eq subchar (read-feature stream)) > (multiple-value-bind (form note) (read-internal stream t nil t) > (values form (and note (list note))))) > (t (let* ((*read-suppress* t)) > (read stream t nil t) > (values))))) > ;Compiler warnings : > ; In READ-CONDITIONAL: Unused lexical variable INT > READ-CONDITIONAL > ? #+ccl 1 > > 0> Calling (READ-FEATURE #<RECORDING-CHARACTER-INPUT-STREAM #x3020004E03BD>) > <0 READ-FEATURE returned #\+ > 1 > > This is apparently a common bug. ECL gets it wrong too: > > ECL (Embeddable Common-Lisp) 21.2.1 (git:UNKNOWN) > > (list #+ecl #-ecl #+ecl 1 2 3) > (3) > > (list #-nil #+nil #-nil 1 2 3) > (3) > > > At least ECL is consistent. SBCL gets it right: > > This is SBCL 2.3.2, an implementation of ANSI Common Lisp. > * (list #+sbcl #-sbcl #+sbcl 1 2 3) > (2 3) > * (list #-nil #+nil #-nil 1 2 3) > (2 3) > > Allegro warns that its behavior changed between implementations, and that you should double-check to make sure that your code does what you intend. > > Personally, I think this situation is a tar pit, and that nested #+ and #- reader macros should just be avoided. > > rg > >> On Mar 13, 2023, at 5:51 AM, Tim McNerney <[email protected] <mailto:[email protected]>> wrote: >> >> Nice investigating. If you want my educated opinion, I think you found a misleading example (#+f #+f x y), explored it to a reasonable extent, and discovered a CCL reader bug: >> >> (setf *features* '(:a :b :c)) followed by '(#+a #-b #+c a b c) reading as (C) >> >> --Tim >> >>> On Mar 13, 2023, at 06:06, Arthur Cater <[email protected] <mailto:[email protected]>> wrote: >>> >>> Reading a bit of ccl’s sources I came across something that surprised me, and I thought it was neat. It was of the form >>> >>> #+feat #+feat >>> :keyword argument >>> >>> which I thought nicer than the sort of thing I’d been doing, namely #+feat :keyword #+feat argument >>> >>> >>> But it set me thinking, and experimenting, and now I’m puzzled, and I wonder if anyone can explain this to me. >>> >>> >>> >>> ? >>> NIL >>> ? (setf *features* '(:a :b :c)) >>> (:A :B :C) >>> >>> ? '(#+a #+a a b c) >>> (A B C) >>> >>> ? '(#+a #-b a b c) >>> (B C) >>> >>> ? '(#+a #+b #-c a b c) >>> (B C) >>> >>> ? '(#+a #-b #+c a b c) >>> (C) >>> ? >>> >>> >>> I thought I understood what was going on until this last one. Why does #-b cause both A and B to be skipped? >>> >>> Arthur >> >