<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Here's a patch that makes CCL behave like SBCL for Ron's examples.
The issue is that during the act of reading the feature expression
itself (the symbol or list that immediately follows the #\+ or #\-
character) , *read-suppress* must be nil [or else some low-level
reader that ignores *read-suppress* must be called]. SBCL does bind
*read-suppress* to nil during this read; this patch makes CCL do so
too.<br>
<br>
(See <font face="monospace">#'sb-impl::sharp-plus-minus</font> in
the SBCL source.)<br>
<br>
I hesitate to submit this patch because I don't know that it's a
complete solution, and it's also likely that existing code depended
on the old, non-SBCL-like behavior.<br>
<br>
<font face="monospace">(in-package :ccl)<br>
(defun read-feature (stream)<br>
(let* ((f (let* ((*package* *keyword-package*)<br>
(*read-suppress* nil)) ;;; <-- This is the
change<br>
(read stream t nil t))))<br>
(labels ((eval-feature (form)<br>
(cond ((atom form) <br>
(member form *features*))<br>
((eq (car form) :not) <br>
(not (eval-feature (cadr form))))<br>
((eq (car form) :and) <br>
(dolist (subform (cdr form) t)<br>
(unless (eval-feature subform) (return))))<br>
((eq (car form) :or) <br>
(dolist (subform (cdr form) nil)<br>
(when (eval-feature subform) (return t))))<br>
(t (%err-disp $XRDFEATURE form)))))<br>
(if (eval-feature f) #\+ #\-))))<br>
<br>
</font>
<div class="moz-cite-prefix">-SS<br>
<br>
On 3/13/23 4:07 PM, phoebe Goldman wrote:<br>
</div>
<blockquote type="cite"
cite="mid:5C1F621B-3C5D-498C-A4B2-CE17BBDD4406@goldman-tribe.org">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
Yes, you're right, good catch; in the second case, at step 2, I
meant for the feature expression to be false.
<div><br>
</div>
<div>I agree that you should not do this, and Robert's linked
thread from Allegro is evidence that implementations may
mis-read nested read conditionals.<br>
<div><br>
<blockquote type="cite">
<div>On Mar 13, 2023, at 6:05 PM, Arthur Cater
<a class="moz-txt-link-rfc2396E" href="mailto:arthur.cater@ucd.ie"><arthur.cater@ucd.ie></a> wrote:</div>
<br class="Apple-interchange-newline">
<div>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<div style="word-wrap: break-word; -webkit-nbsp-mode:
space; line-break: after-white-space;">Thank you for
that thorough explanation, I appreciate it.
<div>Permit me to make a minor correction, I believe in
the “:FOO not in” part, step 2, you mean evaluate
feature expression to false.
<div><br>
</div>
<div>fwiw I’d hate to find in code (even my own)
anything more complex than that doubled-up test of
the same feature expression. I was experimenting
because</div>
<div>(a) it was the first time I’d seen such a
construction and I wasn’t sure it would do what it
was clearly intended to do. I thought it was neat.</div>
<div>(b) I was just curious about what such syntax
would mean in a mixed case.</div>
<div><br>
</div>
<div>Arthur<br>
<div><br>
<blockquote type="cite">
<div>On 13 Mar 2023, at 21:30, phoebe Goldman
<<a href="mailto:phoebe@goldman-tribe.org"
moz-do-not-send="true"
class="moz-txt-link-freetext">phoebe@goldman-tribe.org</a>>
wrote:</div>
<br class="Apple-interchange-newline">
<div>
<meta http-equiv="content-type"
content="text/html; charset=UTF-8">
<div style="overflow-wrap: break-word;
-webkit-nbsp-mode: space; line-break:
after-white-space;">2.4.8.17 Sharpsign
Plus, <a
href="http://www.lispworks.com/documentation/HyperSpec/Body/02_dhq.htm"
moz-do-not-send="true"
class="moz-txt-link-freetext">http://www.lispworks.com/documentation/HyperSpec/Body/02_dhq.htm</a> ,
says:
<div><br>
</div>
<div>
<blockquote type="cite">#+ operates by
first reading the feature expression and
then skipping over the form if
the feature expression fails. While
reading the test, the current package is
the KEYWORD package. Skipping over
the form is accomplished
by binding *read-suppress* to true and
then calling read.</blockquote>
</div>
<div><br>
</div>
<div>This means that a series of #+ or #-
read-conditionals will result in recursive
calls to READ with a stack of T bindings
on *READ-SUPPRESS*. Note that neither
reader macro ever binds *READ-SUPPRESS* to
NIL, only either introduces a binding of T
or uses the existing value.</div>
<div><br>
</div>
<div>Assume that *READ-SUPPRESS* is globally
NIL. Consider reading:</div>
<div><br>
</div>
<div>#+foo #+foo a b</div>
<div><br>
</div>
<div>If :FOO is in *FEATURES*, the reader
will:</div>
<div><br>
</div>
<div>1. Read the first #+FOO, evaluate its
feature expression to true, and call READ
recursively with no new *READ-SUPPRESS*
binding.</div>
<div> 2. Read the second #+FOO, evaluate
its feature expression to true, and call
READ recursively with no new
*READ-SUPPRESS* binding.</div>
<div> 3. Read A with the root
*READ-SUPPRESS* binding of NIL, and return
the symbol A.</div>
<div>4. Your initial call to READ has now
returned, but there's more input. Call
READ again to get another object.</div>
<div>5. Read B the root *READ-SUPPRESS*
binding of NIL, and return the symbol B.</div>
<div><br>
</div>
<div>If :FOO is not in *FEATURES*, the
reader will:</div>
<div><br>
</div>
<div>1. Read the first #+FOO, evaluate its
feature expression to false, and call READ
recursively with *READ-SUPPRESS* bound to
T.</div>
<div> 2. Within that binding, read the
second #+FOO, evaluate its feature
expression to true, and call READ
recursively with an additional layer of
*READ-SUPPRESS* = T binding.</div>
<div> 3. Within both bindings, read A
with *READ-SUPPRESS* true, and return
nothing.</div>
<div> 4. Within the outer binding, read A
with *READ-SUPPRESS* true, and return
nothing.</div>
<div>5. Your initial call to READ has now
returned, and you didn't get anything.</div>
<div><br>
</div>
<div>When you're dealing with multiple
distinct feature expressions which are not
uniformly all true or false, the behavior
gets more complicated, but it's always
defined by the spec as recursive calls to
READ with a stack of *READ-SUPPRESS*
bindings. I haven't looked carefully at
the cases that spawned this discussion to
see if CCL's behavior is compliant, but I
don't believe there's any ambiguity in the
spec.</div>
<div><br>
</div>
<div>Cheers,</div>
<div>phoebe</div>
<div><span id="x-apple-selection:end"></span><span><br>
<blockquote type="cite">On Mar 13, 2023,
at 5:06 PM, Tim McNerney <<a
href="mailto:mc@media.mit.edu"
moz-do-not-send="true"
class="moz-txt-link-freetext">mc@media.mit.edu</a>>
wrote:<br>
<br class="Apple-interchange-newline">
Would someone mind quoting “chapter
and verse”? <br>
<br>
Somehow, even those of us with decades
of Common Lisp experience, all trying
to follow the drama of the X3J13
committee, a bunch of us “missed the
memo” about this convenient, allegedly
legal, but “buyer beware” syntax. <br>
<br>
Yes, I absolutely hate <br>
#+foo :keyword #+foo argument
too. <br>
<br>
--Tim<br>
<br>
<blockquote type="cite">On Mar 13,
2023, at 14:00, Robert Goldman <<a
href="mailto:rpgoldman@sift.info"
moz-do-not-send="true"
class="moz-txt-link-freetext">rpgoldman@sift.info</a>>
wrote:<br>
<br>
</blockquote>
<blockquote type="cite">
On 13 Mar 2023, at 12:42, Ron Garret
wrote:<br>
Oh, forgot to add...<br>
On Mar 13, 2023, at 10:20 AM, Arthur
Cater <<a
href="mailto:arthur.cater@ucd.ie"
moz-do-not-send="true"
class="moz-txt-link-freetext">arthur.cater@ucd.ie</a>>
wrote:<br>
It never previously occurred to me
that read time conditionals could be
nested.<br>
Just because you can do something
doesn't mean you should.<br>
rg<br>
I was surprised myself to see<br>
#+foo #+foo<br>
<br>
used to make two s-expressions
(in)visible in the presence
(absence) of the :foo feature. But
it's clearly dictated by the spec,
and is often handy when, for example
one might want to have something
conditionally in a property list<br>
(list :prop1 12<br>
#+foo #+foo<br>
:foo 'bar)<br>
<br>
In my opinion, that's clearer than<br>
(list :prop1 12<br>
#+foo :foo #+foo 'bar)<br>
<br>
which obscures reading this as a
property list and obscures the fact
that the two elements of the list
are going to be swapped in or out
based on a single feature.<br>
(append (list :prop 12) #+foo (list
:foo 'bar) )<br>
<br>
is not an alternative particularly
pleasing to me, but YMMV. It's
certainly very busy.<br>
</blockquote>
</blockquote>
</span><br>
</div>
</div>
</div>
</blockquote>
</div>
<br>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br>
</div>
</blockquote>
<br>
</body>
</html>