From: Adam Warner
Subject: Small read macro issue
Date: 
Message-ID: <anohuv$fl7fs$1@ID-105510.news.dfncis.de>
Hi all,

I'm just a little stuck on how to turn this syntax:

(function-name[some text]"more text")

Into this syntax:

(function-name :options "[some text]" "more text")

This allows me to distinguish whether an initial optional string has been
input. Otherwise there is no way to distinguish between these situations:

(function-name "options" "text1" "text2" ...)
(function-name "text1" "text2" ...)

(Note: I am unaware of any way to attach a particular type to the initial
optional string so that it can be tested for as different to a regular
string).

This is the best I can do so far:


(set-macro-character
 #\[ #'(lambda (in-stream char)
         (declare (ignore char))
         (let ((text-string (with-output-to-string (out-stream)
                               (write-char #\[ out-stream)
                               (loop for char = (read-char in-stream)
                                 until (char= char #\])
                                 do (write-char char out-stream))
                               (write-char #\] out-stream))))
           `(list :options ,text-string))))


Which leads to this example output:

'(function-name[some text]"more text")
(FUNCTION-NAME (LIST :OPTIONS "[some text]") "more text")

It's usable but the nested list is not required.

I have also tried values and read-from-string to try and return two
separate objects but I get the error message "macro character definition
for #\[ may not return 2 values, only one value."

So it doesn't seem possible to get exactly the result I am looking for (but
I thought I'd quickly check with you all).

Thanks,
Adam

From: Vassil Nikolov
Subject: Re: Small read macro issue
Date: 
Message-ID: <ur8f4dre1.fsf@poboxes.com>
    On Sat, 05 Oct 2002 18:33:19 -1100, "Adam Warner" <······@consulting.net.nz> said:

    AW> Hi all,
    AW> I'm just a little stuck on how to turn this syntax:

    AW> (function-name[some text]"more text")

    AW> Into this syntax:

    AW> (function-name :options "[some text]" "more text")

Common Lisp doesn't have `splicing read macros' so there isn't a
straightforward way to achieve that.

I wonder if it makes sense for you to revise the syntax.

As one approach, if you use your own macro characters instead of
parentheses to enclose the whole form, then the read macro for the
opening one would read the function name and the optional text and
cons these (without a nested list) in front of what
READ-DELIMITED-LIST would return for the input after the closing
bracket.

---Vassil.

-- 
Garbage collection is charged at 0.19e-9 cents a cons.  Bulk rates
are also available: please contact memory management for details.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <anon5h$g3v3a$1@ID-105510.news.dfncis.de>
Hi Vassil Nikolov,

>     AW> Hi all,
>     AW> I'm just a little stuck on how to turn this syntax:
> 
>     AW> (function-name[some text]"more text")
> 
>     AW> Into this syntax:
> 
>     AW> (function-name :options "[some text]" "more text")
> 
> Common Lisp doesn't have `splicing read macros' so there isn't a
> straightforward way to achieve that.

Thanks for putting a name to the missing functionality.

> I wonder if it makes sense for you to revise the syntax.
> 
> As one approach, if you use your own macro characters instead of
> parentheses to enclose the whole form, then the read macro for the
> opening one would read the function name and the optional text and cons
> these (without a nested list) in front of what READ-DELIMITED-LIST would
> return for the input after the closing bracket.

Thanks for the idea. I have just figured out an expensive way to achieve
the desired result: The [ read macro converts the string to a | | enclosed
symbol to maintain case (using read-from-string) and the function is then
able to distinguish between an optional symbol and a string. This kind of
approach would work with any object that is not a string.

(set-macro-character
 #\[ #'(lambda (in-stream char)
         (declare (ignore char))
         (let ((text-string (with-output-to-string (out-stream)
                               (write-char #\[ out-stream)
                               (loop for char = (read-char in-stream)
                                 until (char= char #\])
                                 do (write-char char out-stream))
                               (write-char #\] out-stream))))
           (first (list (read-from-string (concatenate 'string "|" text-string "|")))))))

'(function-name[some text]"more text")
(FUNCTION-NAME |[some text]| "more text")

I used (first (list ...)) to get rid of the second return value of
read-from-string. There is probably a better way that I am unaware of.

Regards,
Adam
From: Kalle Olavi Niemitalo
Subject: Re: Small read macro issue
Date: 
Message-ID: <87k7kwrm50.fsf@Astalo.y2000.kon.iki.fi>
"Adam Warner" <······@consulting.net.nz> writes:

> I have just figured out an expensive way to achieve the desired result:
> The [ read macro converts the string to a | | enclosed symbol to
> maintain case (using read-from-string) and the function is then able
> to distinguish between an optional symbol and a string.

That won't work if the original string contains | characters.
MAKE-SYMBOL or INTERN would not have this problem.

The nested list in your original article does not look too bad, either.
You also have the option of hiding the function behind a macro;
then you can have (macro-name[some text]"more text") read as
(macro-name (:options "[some text]") "more text"), which then expands
to (function-name :options "[some text]" "more text") at compile time.
Having both MACRO-NAME and FUNCTION-NAME could be confusing, though.

Alternatively, you could define a structure and have the reader macro wrap
the string in an instance of that.  The structure would be self-evaluating
so it would not need a quote, and the function could easily recognize it
by type.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <anp1vd$g8qm4$1@ID-105510.news.dfncis.de>
Hi Kalle Olavi Niemitalo,

>> I have just figured out an expensive way to achieve the desired result:
>> The [ read macro converts the string to a | | enclosed symbol to
>> maintain case (using read-from-string) and the function is then able to
>> distinguish between an optional symbol and a string.
> 
> That won't work if the original string contains | characters.
> MAKE-SYMBOL or INTERN would not have this problem.

Oh! Thanks for the tip.
 
> The nested list in your original article does not look too bad, either.
> You also have the option of hiding the function behind a macro; then you
> can have (macro-name[some text]"more text") read as (macro-name
> (:options "[some text]") "more text"), which then expands to
> (function-name :options "[some text]" "more text") at compile time.
> Having both MACRO-NAME and FUNCTION-NAME could be confusing, though.

Alternatively the function could just flatten any lists. Then I would be
able to accept both syntaxes!

> Alternatively, you could define a structure and have the reader macro
> wrap the string in an instance of that.  The structure would be
> self-evaluating so it would not need a quote, and the function could
> easily recognize it by type.

This is what I originally wanted to do. I wanted to attach a special type
to the string. Now I know how :-)

(defstruct opt options)
(type-of (make-opt :options "options text"))
OPT

This would work like a charm once the reader macro [options text] was
created to generate (make-opt :options "[options text]"). But it seems that
the longhand syntax would be worse: instead of being able to type :keyword
"text" I would have to turn the string into the OPT type using
make-opt, or type the printed representation #S(OPT :OPTIONS "options text")

Perhaps flattening any lists and accepting both syntaxes would be the best
way to proceed. Although the defstruct way seems very elegant.

The concept of a default structure might be nice:

(defstruct :set-default default x y z)

...would allow #S(:x "options text") etc. to be entered without having to
enter the name of the default structure (here called DEFAULT).

Thanks,
Adam
From: Vassil Nikolov
Subject: Re: Small read macro issue
Date: 
Message-ID: <ur8f2rir4.fsf@poboxes.com>
    On Sat, 05 Oct 2002 23:06:37 -1100, "Adam Warner" <······@consulting.net.nz> said:

    [...]
    AW> This would work like a charm once the reader macro [options text] was
    AW> created to generate (make-opt :options "[options text]"). But it seems that
    AW> the longhand syntax would be worse: instead of being able to type :keyword
    AW> "text" I would have to turn the string into the OPT type using
    AW> make-opt, or type the printed representation #S(OPT :OPTIONS "options text")

    [...]
    AW> The concept of a default structure might be nice:

    AW> (defstruct :set-default default x y z)

    AW> ...would allow #S(:x "options text") etc. to be entered without having to
    AW> enter the name of the default structure (here called DEFAULT).

Oh, no, redefining #S in this way is fraught with peril.  And what
more would it give you (apart from headaches) than defining #\[ as
a character macro such that

  [options text]

reads the same as

  #S(opt :options "options text")

Just to make quite sure there is no misunderstanding, note that the
reader macro function associated with #\[ will return the value of
(MAKE-OPT :OPTIONS "options text"), rather than the list (MAKE-OPT
:OPTIONS "options text").  In other words, the expression producing
the return value of that function will be

  (make-opt :options input-options-text)

rather than

  `(make-opt :options ,input-options-text)

---Vassil.

-- 
Garbage collection is charged at 0.19e-9 cents a cons.  Bulk rates
are also available: please contact memory management for details.
From: Paul Foley
Subject: Re: Small read macro issue
Date: 
Message-ID: <m2wuowx9jw.fsf@mycroft.actrix.gen.nz>
On Sat, 05 Oct 2002 20:02:08 -1100, Adam Warner wrote:

> Thanks for the idea. I have just figured out an expensive way to achieve
> the desired result: The [ read macro converts the string to a | | enclosed
> symbol to maintain case (using read-from-string) and the function is then
> able to distinguish between an optional symbol and a string. This kind of
> approach would work with any object that is not a string.

> (set-macro-character
>  #\[ #'(lambda (in-stream char)
>          (declare (ignore char))
>          (let ((text-string (with-output-to-string (out-stream)
>                                (write-char #\[ out-stream)
>                                (loop for char = (read-char in-stream)
>                                  until (char= char #\])
>                                  do (write-char char out-stream))
>                                (write-char #\] out-stream))))
>            (first (list (read-from-string (concatenate 'string "|" text-string "|")))))))

  (set-macro-character #\[
    (lambda (stream char)
      (declare (ignore char))
      (intern (funcall (get-macro-character #\") stream #\]))))

> '(function-name[some text]"more text")
> (FUNCTION-NAME |[some text]| "more text")

> I used (first (list ...)) to get rid of the second return value of
> read-from-string. There is probably a better way that I am unaware of.

  (values (read-from-string ...))

-- 
And ælc þara þe gehierð þas min word, and þa ne wyrcþ, se bið gelic þæm
dysigan menn...

(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3242987175062451@naggum.no>
* "Adam Warner" <······@consulting.net.nz>
| I used (first (list ...)) to get rid of the second return value of
| read-from-string. There is probably a better way that I am unaware of.

  Yes.  Use nothing.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <ans6fk$h1luv$1@ID-105510.news.dfncis.de>
Erik Naggum wrote:

> * "Adam Warner" <······@consulting.net.nz>
> | I used (first (list ...)) to get rid of the second return value of
> | read-from-string. There is probably a better way that I am unaware of.
> 
>   Yes.  Use nothing.

[1]> (set-macro-character #\[
  #'(lambda (in-stream char)
      (declare (ignore char))
        (read-from-string "'(test)"))))
T
[2]> [

*** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
#<IO SYNONYM-STREAM *TERMINAL-IO*>>:
 macro character definition for #\[ may not return 2 values, only one value.
1. Break [3]> 

[4]> (set-macro-character #\[
  #'(lambda (in-stream char)
      (declare (ignore char))
        (values (read-from-string "'(test)")))))
T
[5]> [
(TEST)

Attempting to create a splicing read macro was the whole point of the thread.
From: Dave Pearson
Subject: Re: Small read macro issue
Date: 
Message-ID: <slrnaq3cam.i0f.davep.news@hagbard.davep.org>
* Adam Warner <······@consulting.net.nz>:

> [1]> (set-macro-character #\[
>   #'(lambda (in-stream char)
>       (declare (ignore char))
>         (read-from-string "'(test)"))))
> T
> [2]> [
> 
> *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
> #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
>  macro character definition for #\[ may not return 2 values, only one value.
> 1. Break [3]> 

Isn't this just an issue with the CL implementation you're using? Testing
here it seems to be an issue for CLISP but ACL, LW, Corman and CMUCL seem to
handle it with no problems.

-- 
Dave Pearson:                   |     lbdb.el - LBDB interface.
http://www.davep.org/           |  sawfish.el - Sawfish mode.
Emacs:                          |  uptimes.el - Record emacs uptimes.
http://www.davep.org/emacs/     | quickurl.el - Recall lists of URLs.
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3242995842037739@naggum.no>
* Adam Warner
| *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
| #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
|  macro character definition for #\[ may not return 2 values, only one value.

  My goodness!  What horribly hostile implementation is this taken from?

| Attempting to create a splicing read macro was the whole point of the thread.

  It seems that you have lost track of your problem and now focus only on a
  solution that you want to make work.  If one solution does not work, look
  for another solution, do not try to force-fit it.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <ant40j$h6reg$1@ID-105510.news.dfncis.de>
Hi Erik Naggum,

> * Adam Warner
> | *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT
> | STRING-INPUT-STREAM> #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
> |  macro character definition for #\[ may not return 2 values, only one
> |  value.
> 
>   My goodness!  What horribly hostile implementation is this taken from?

It's CLISP 2.30. I take it you consider this implementation is conforming
in this respect?

I can see the long term benefit in refusing to allow a macro character to
return more than one value when it is not supported: This strict
implementation would make it easier to extend the functionality of the
ANSI Common Lisp reader to support splicing macros without breaking
existing code.

> | Attempting to create a splicing read macro was the whole point of the
> | thread.
> 
>   It seems that you have lost track of your problem and now focus only
>   on a solution that you want to make work.  If one solution does not
>   work, look for another solution, do not try to force-fit it.

Note that I wrote at the start of the thread:

   I have also tried values and read-from-string to try and return two
   separate objects but I get the error message "macro character
   definition for #\[ may not return 2 values, only one value."

I have not lost track of the problem. I only had to reply to fix your
misapprehension that I could ignore multiple return values from the reader
macro.

Regards,
Adam
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243028580124863@naggum.no>
* Adam Warner
| It's CLISP 2.30. I take it you consider this implementation is conforming
| in this respect?

  That was a reasonably mild restatement of what I mean.  To signal an
  error is just plain wrong and /will/ break conforming code.

| I can see the long term benefit in refusing to allow a macro character to
| return more than one value when it is not supported: This strict
| implementation would make it easier to extend the functionality of the
| ANSI Common Lisp reader to support splicing macros without breaking
| existing code.

  Because reader macro functions are allowed to return more than one value
  today, you would need a different mechanism to do something other than to
  ignore them.  CLISP has, however, a disturbing tradition of thinking it
  is better than the ANSI Standard, although this is being improved (i.e.,
  removed) as each of the cases receive public condemnation.

| I have not lost track of the problem. I only had to reply to fix your
| misapprehension that I could ignore multiple return values from the
| reader macro.

  One of the annoying things with languages that have very good
  specifications is that people tend to relate to the specification and
  file bug reports with implementations that deviate from them.  Newcomers
  to a language that come from a language where there is no standard or a
  bad standard such that they have to test things out in implementations,
  tend to get into trouble.  There is such a thing in Common Lisp as non-
  conforming implementations.  That concept does not exist for Python,
  Perl, PHP, etc.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <antdl8$hdh70$1@ID-105510.news.dfncis.de>
Hi Erik Naggum,

> | It's CLISP 2.30. I take it you consider this implementation is
> | conforming in this respect?
> 
>   That was a reasonably mild restatement of what I mean.  To signal an
>   error is just plain wrong and /will/ break conforming code.

I have located this statement in the HyperSpec:
http://www.lispworks.com/reference/HyperSpec/Body/02_b.htm

   The reader macro function may return zero values or one value. If one
   value is returned, then that value is returned as the result of the
   read operation; the algorithm is done. If zero values are returned,
   then step 1 is re-entered.

Only zero or one return value is defined. Any extra return values are
undefined (not illegal because "may" has been used instead of "shall" or
"may only").

As a matter of general principle should undefined behaviour never signal
an error (only a warning)?

Still, creating code with undefined consequences doesn't seem to be the
best approach. In this respect CLISP is forcing explicit compliance with
defined ANSI operations.

Regards,
Adam
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243031919607252@naggum.no>
* Adam Warner
| Only zero or one return value is defined. Any extra return values are
| undefined (not illegal because "may" has been used instead of "shall" or
| "may only").

  Extra values are always ignored in the rest of the language.  It seems
  odd to say the least not to ignore additional values in this particular
  case.

| As a matter of general principle should undefined behaviour never signal
| an error (only a warning)?

  What use could there possibly be in reporting an error for too many
  values when the entire rest of the language quietly ignore them?

| In this respect CLISP is forcing explicit compliance with defined ANSI
| operations.

  No, it is not.  There is no specification of an error if there are more
  than one value.  CLISP has invented that part on its own.  CLISP does a
  lot of that, actually, which is why I generally discommend it just like I
  discommend GCL.  CLISP also teaches totally warped performance issues by
  virtue of dramatically different performance for system and user code.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Alexey Dejneka
Subject: Re: Small read macro issue
Date: 
Message-ID: <m3smzh1tyo.fsf@comail.ru>
Hello,

Erik Naggum <····@naggum.no> writes:

> * Adam Warner
> | Only zero or one return value is defined. Any extra return values are
> | undefined (not illegal because "may" has been used instead of "shall" or
> | "may only").
> 
>   Extra values are always ignored in the rest of the language.  It seems
>   odd to say the least not to ignore additional values in this particular
>   case.

* (multiple-value-call (lambda (&optional (x nil x-p)) (list x x-p))
    (values 1 2))
debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
  invalid number of arguments: 2

It it wrong too?

-- 
Regards,
Alexey Dejneka
From: Vassil Nikolov
Subject: Re: Small read macro issue
Date: 
Message-ID: <u3crhlzpx.fsf@poboxes.com>
    On 08 Oct 2002 07:37:51 +0400, Alexey Dejneka <········@comail.ru> said:

    AD> * (multiple-value-call (lambda (&optional (x nil x-p)) (list x x-p))
    (values 1 2))
    AD> debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
    AD>   invalid number of arguments: 2

    AD> It it wrong too?

Your example is like (APPLY (LAMBDA ...) '(1 2)) which is different
from (FUNCALL (LAMBDA ...) (VALUES 1 2)).  The latter is the case
where extra returned values are ignored.

(I know FUNCALL is redundant in the above expression taken as a
literal example.)

---Vassil.

-- 
Garbage collection is charged at 0.19e-9 cents a cons.  Bulk rates
are also available: please contact memory management for details.
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243079257653604@naggum.no>
* Alexey Dejneka <········@comail.ru>
| It it wrong too?

  *sigh*

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Christophe Rhodes
Subject: Re: Small read macro issue
Date: 
Message-ID: <sqlm594arf.fsf@lambda.jcn.srcf.net>
Erik Naggum <····@naggum.no> writes:

> * Adam Warner
> | Only zero or one return value is defined. Any extra return values are
> | undefined (not illegal because "may" has been used instead of "shall" or
> | "may only").
> 
>   Extra values are always ignored in the rest of the language.  It seems
>   odd to say the least not to ignore additional values in this particular
>   case.

I don't know... if it were documented in CLISP's implementation notes
that an interpretation (say, "splicing read macro") for more than one
return value was being considered, but had not yet been implemented, I
would say that throwing an error at this point was a logical thing to
do[1], simply to point out the possibility of this behaviour changing.

I generally find that I want to know when I am invoking undefined
behaviour, if only because such behaviour may change at any time.

Christophe

[1] I might prefer a STYLE-WARNING.
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Vassil Nikolov
Subject: Re: Small read macro issue
Date: 
Message-ID: <uwuotkknw.fsf@poboxes.com>
    On 08 Oct 2002 02:11:59 +0000, Erik Naggum <····@naggum.no> said:

    EN>   Extra values are always ignored in the rest of the language.

Where the caller accepts exactly one value, certainly.  But are
there any cases where the caller accepts a variable number of
values, up to N-1, and is explicitly defined to ignore the Nth
value and beyond?  Or is there a general rule to that effect?

---Vassil.

-- 
Garbage collection is charged at 0.19e-9 cents a cons.  Bulk rates
are also available: please contact memory management for details.
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243105699171281@naggum.no>
* Vassil Nikolov
| Where the caller accepts exactly one value, certainly.  But are
| there any cases where the caller accepts a variable number of
| values, up to N-1, and is explicitly defined to ignore the Nth
| value and beyond?  Or is there a general rule to that effect?

  If you accept n values in `multiple-value-bind�, any extraneous values
  are ignored.  Missing values are even bound to `nil�.  The one exception
  to this is `multiple-value-call� where the returned values are arguments
  to another function, but that is because Common Lisp does not ignore
  extraneous arguments to functions without `&rest�, nor accept fewer
  arguments to function without `&optional� or `&key�.

  So, where is the function that accepts one optional argument and which is
  called with `multiple-value-call� of the values of reader macro functions?

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Vassil Nikolov
Subject: Re: Small read macro issue
Date: 
Message-ID: <ulm58dpg7.fsf@poboxes.com>
    On 08 Oct 2002 22:41:39 +0000, Erik Naggum <····@naggum.no> said:

    VN> Where the caller accepts exactly one value, certainly.  But are
    VN> there any cases where the caller accepts a variable number of
    VN> values, up to N-1, and is explicitly defined to ignore the Nth
    VN> value and beyond?  Or is there a general rule to that effect?

    EN>   If you accept n values in `multiple-value-bind�, any extraneous values
    EN>   are ignored.  Missing values are even bound to `nil�.  The one exception
    EN>   to this is `multiple-value-call� where the returned values are arguments
    EN>   to another function, but that is because Common Lisp does not ignore
    EN>   extraneous arguments to functions without `&rest�, nor accept fewer
    EN>   arguments to function without `&optional� or `&key�.

    EN>   So, where is the function that accepts one optional argument and which is
    EN>   called with `multiple-value-call� of the values of reader macro functions?

Well, I never suggested there was one.  (But I will suggest a
similar one below, so this question is quite anticipative.)

I admit I overlooked MULTIPLE-VALUE-BIND's ignoring excess values,
and that behavior does support the notion that if a caller is
defined to accept up to a certain number of values, then implicitly
this means that extra values are ignored.

But to make the above argument complete, it must be noted that the
reader cannot use MULTIPLE-VALUE-BIND to call the macro reader
function since if it did, it wouldn't know when zero values were
returned.  (MULTIPLE-VALUE-BIND is somewhat inappropriate when the
number of values returned can be less than the maximum number of
values consumed, i.e. than the number of vars.)  Therefore, there
are two ways to implement the reader:

(1) By using MULTIPLE-VALUE-LIST to receive the values returned by
    the reader macro function.  This is the more straightforward
    implementation, and it leads naturally to a logic where the
    list thus obtained is tested first for being empty, and then,
    if it is not, its first element is extracted, while the rest of
    the elements, if any, are silently ignored.

(2) By using MULTIPLE-VALUE-CALL, with a function whose lambda list
    is something like

      (&optional (read-value nil read-value-p) &rest ignore)

    where the implementor must be `smart enough' since the &REST
    parameter must be explicitly added.  If it isn't, then it will
    be an error for the reader macro function to return more than
    one value.

I can see how MULTIPLE-VALUE-BIND's behavior together with the
`naturalness' of (1) make the point for accepting two or more
values from the reader macro function, but I still find that part
of the standard a little underspecified^1 (MULTIPLE-VALUE-BIND does
not apply directly, and there is no explicit statement about what
happens if neither zero nor one values are returned by the reader
macro function---it `may return zero values or one value' but `may'
is not formally defined).


---Vassil.

-- 
Garbage collection is charged at 0.19e-9 cents a cons.  Bulk rates
are also available: please contact memory management for details.
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243272568030579@naggum.no>
* Vassil Nikolov
| But to make the above argument complete, it must be noted that the reader
| cannot use MULTIPLE-VALUE-BIND to call the macro reader function since if
| it did, it wouldn't know when zero values were returned.

  Correct, and a good point.

| (1) By using MULTIPLE-VALUE-LIST to receive the values returned by the
|     reader macro function.  This is the more straightforward
|     implementation, and it leads naturally to a logic where the list thus
|     obtained is tested first for being empty, and then, if it is not, its
|     first element is extracted, while the rest of the elements, if any,
|     are silently ignored.

  In this model, which I think is the most rational choice, it takes extra
  effort to check for the redundant values.

| (2) By using MULTIPLE-VALUE-CALL, with a function whose lambda list
|     is something like
| 
|       (&optional (read-value nil read-value-p) &rest ignore)
| 
|     where the implementor must be `smart enough' since the &REST
|     parameter must be explicitly added.  If it isn't, then it will be an
|     error for the reader macro function to return more than one value.

  But this model, while possible, would mean that the function so called
  would be a closure that would act on the hitherto collected elements of a
  list or other structure.  Remember,we are using this to collect datums
  from a stream to return to our caller.  It seems strange to do this with
  a downward-passing mechanism that would collect upon return.

  However, the more I think about this, the more I think that maybe the
  support for multiple-values in Common Lisp is slightly lacking.  More
  often than not, multiple values may be returned in registers, but there
  is no way to access both the values and the number of returned values
  even though most (if not all) implementations return that number with the
  returned values.  When multiple values are returned, a function should be
  able to dispatch on the number of return values.  The only way to do this
  is with `multiple-value-call� and hope that the multiple-value-return
  block and the argument block to a function are not too costly to convert
  between.

  It would be interesting to compare the various implementations on this
  point.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Frode Vatvedt Fjeld
Subject: Re: Small read macro issue
Date: 
Message-ID: <2hu1jxl0wi.fsf@vserver.cs.uit.no>
"Adam Warner" <······@consulting.net.nz> writes:

> I used (first (list ...)) to get rid of the second return value of
> read-from-string. There is probably a better way that I am unaware
> of.

The standard idiom would be (values <form>), I believe. If you need to
pick out a value other than the primary one, use nth-value.

-- 
Frode Vatvedt Fjeld
From: Kenny Tilton
Subject: Re: Small read macro issue
Date: 
Message-ID: <3DA02615.3060700@nyc.rr.com>
Adam Warner wrote:
> Hi all,
> 
> I'm just a little stuck on how to turn this syntax:
> 
> (function-name[some text]"more text")
> 
> Into this syntax:
> 
> (function-name :options "[some text]" "more text")
> 
> This allows me to distinguish whether an initial optional string has been
> input. Otherwise there is no way to distinguish between these situations:
> 
> (function-name "options" "text1" "text2" ...)
> (function-name "text1" "text2" ...)

Could you use a macro instead?

(defmacro macro-name (&optional some-text) &rest other-texts)
   ...etc)

Then the syntax would be:

    (macro-name () "aaa" "bbb") or (macro-name ("some text") "aaa" "bbb")

kenny
clinisys
From: Kaz Kylheku
Subject: Re: Small read macro issue
Date: 
Message-ID: <cf333042.0210071124.7a301bde@posting.google.com>
"Adam Warner" <······@consulting.net.nz> wrote in message news:<··············@ID-105510.news.dfncis.de>...
> Hi all,
> 
> I'm just a little stuck on how to turn this syntax:
> 
> (function-name[some text]"more text")
> 
> Into this syntax:
> 
> (function-name :options "[some text]" "more text")
> 
> This allows me to distinguish whether an initial optional string has been
> input. Otherwise there is no way to distinguish between these situations:
> 
> (function-name "options" "text1" "text2" ...)
> (function-name "text1" "text2" ...)

In these situations, you have written neither :options nor the square
brackets. They are ambiguous because you have omitted the necessary
syntax to indicate the presence of options.

I think that :options is a perfectly good indicator, and that the [ ]
idea is just unnecessary syntactic sugar, which is hard to do, given
that a reader macro can produce exactly one object (or none by using
(values)). That syntactic sugar won't help you where you forget to use
it. If the programmer is capable of forgetting to write :options, he
is also capable of forgetting to the equivalent [ ] syntax.

Nevertheless, one hack would be to use two read macros, and pass
context between them. Ugh.

Here is the idea. Have [ trigger a read macro which reads the
following string literal, squirrels it away somewhere, and returns the
symbol :options to the reader. Then ] triggers another read macro
which retrieves the stashed string. Hence, two read macro calls, two
objects.
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3242994656390587@naggum.no>
* Adam Warner
| I'm just a little stuck on how to turn this syntax:
| 
| (function-name[some text]"more text")
| 
| Into this syntax:
| 
| (function-name :options "[some text]" "more text")

  That is the wrong goal.

| This allows me to distinguish whether an initial optional string has been
| input.

  So you need a mechanism to distinguish them, not an answer to what you
  are asking for.

| Otherwise there is no way to distinguish between these situations:
| 
| (function-name "options" "text1" "text2" ...)
| (function-name "text1" "text2" ...)
| 
| (Note: I am unaware of any way to attach a particular type to the initial
| optional string so that it can be tested for as different to a regular
| string).

  A wrapper class.  The solution is so close you have probably overlooked it.

(defclass warner-option ()
  ((option :type string :reader warner-option :initarg :option)))

;; useful for debugging
(defmethod print-object ((option warner-option) stream)
  (print-unreadable-object (option stream :type t)
    (prin1 (warner-option option) stream)))

(defun option-reader (in char)
  (declare (ignore char))
  (prog1
      (make-instance 'warner-option
        :option (with-output-to-string (out)
                  (peek-char #\] (make-echo-stream in out))))
    (read-char in)))

#| ;; or if you really want the [] with the string:
(defun option-reader (in char)
  (make-instance 'warner-option
    :option (with-output-to-string (out)
              (unread-char char in)
              (with-open-stream (in (make-echo-stream in out))
                (peek-char #\] in)
                (read-char in)))))
|#

(set-macro-character #\[ 'option-reader)

  Now, reading this:

(function-name[some text]"more text")

  causes this to be returned:

(function-name #<warner-option "some text"> "more text")

  You can now distinguish the option string from other strings.

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.
From: Adam Warner
Subject: Re: Small read macro issue
Date: 
Message-ID: <ant82d$h9e3i$1@ID-105510.news.dfncis.de>
Hi Erik Naggum,

> * Adam Warner
> | I'm just a little stuck on how to turn this syntax:
> | 
> | (function-name[some text]"more text")
> | 
> | Into this syntax:
> | 
> | (function-name :options "[some text]" "more text")
> 
>   That is the wrong goal.
> 
> | This allows me to distinguish whether an initial optional string has
> | been input.
> 
>   So you need a mechanism to distinguish them, not an answer to what you
>   are asking for.

Not exactly. I want the second syntax to also be concise. If it wasn't for
the limitations of the Lisp reader a keyword syntax could have been the most
concise approach (I could still try an "Ugh" hack using a special variable
as outlined by Kaz in this thread).

I don't like the syntax. But I want to support it as I'll explain below.

> | Otherwise there is no way to distinguish between these situations:
> | 
> | (function-name "options" "text1" "text2" ...) (function-name "text1"
> | "text2" ...)
> | 
> | (Note: I am unaware of any way to attach a particular type to the
> | initial optional string so that it can be tested for as different to a
> | regular string).
> 
>   A wrapper class.  The solution is so close you have probably
>   overlooked it.

Thank you Erik. That's a very charitable interpretation :-) In fact I'm
learning about CLOS classes for the first time so the example using
defclass instead of defstruct is greatly appreciated.

Are there advantages to choosing a wrapper class instead of a struct?
It seems that a struct may be more suitable because it has a readable
representation by default. Compare:

[1]> (defclass warner-option ()
  ((option :type string :reader warner-option :initarg :option)))
#<STANDARD-CLASS WARNER-OPTION>
[2]> (make-instance 'warner-option :option "testing")
#<WARNER-OPTION #x203CCEFD>

With:

[3]> (defstruct warner-option option)
WARNER-OPTION
[4]> (make-warner-option :option "testing")
#S(WARNER-OPTION :OPTION "testing")

Finally, here's the reason I am attempting these weird things with
syntax: I am trying to emulate (La)TeX syntax as fully as possible within
some Lisp programs.

Not only does (La)TeX use different case to distinguish different markup
(\large, \Large and \LARGE are all different markup. I'm using a readtable
:invert to support this) but it also uses all three sets of brackets: (),
[] and {}. () is used to denote "positions" (e.g. pairs of coordinates,
size of an object).

As I'm out of paired brackets on a regular keyboard/ASCII character set I
am thinking of using <> for positions instead of () as the < macro
character is currently only used to denote unreadable content (this could
also cause complications with numerical comparisons). Perhaps a pair of
similar (but visually distinct) brackets from Unicode would be a better
idea.

In this syntax \documentclass[a4paper]{article} would be written
(documentclass[a4paper]{article})

Begin and end structures are represented as single S-Expressions:

(figure ...)

Compare: \begin{figure}...\end{figure}

This is an advantage and a disadvantage: it's an advantage with small
constructs like itemised lists. But it's a small disadvantage for large
constructs where everything else has to be nested. Compare:

(document 
  ...)

to

\begin{document}
...
\end{document}

If I support the majority of the current TeX syntax it is easy to
translate from the TeX syntax to its Lisp representation. But to not be
chained down to the syntax it would be nice if the Lisp syntax it is
finally translated to looks like regular function options. That's why I
considered an underlying keyword syntax. I should also give consideration
to Kenny's idea of using:

 (defmacro macro-name (&optional some-text) &rest other-texts)
    ...etc)

Regards,
Adam
From: Erik Naggum
Subject: Re: Small read macro issue
Date: 
Message-ID: <3243028258838806@naggum.no>
* Adam Warner
| Are there advantages to choosing a wrapper class instead of a struct?
| It seems that a struct may be more suitable because it has a readable
| representation by default.

  That is what they specialized method on print-object was for.

  I prefer structs only when there is no possible need to change the layout
  of the class.  Redefining a structure generally does not work, and code
  that uses structures is generally inlined.  You are much better off using
  classes until you know very precisely what you are doing.

  One reason to use a wrapper class that adds a new type to the string in
  question is that keyword arguments in Common Lisp follow a fixed number
  of arguments.  You have to write your own parser functions to find the
  options if they are flagged with keywords.  This is silly and is more of
  an abuse of the feature than reasonable use of it.  If you have to do
  some kind of dispatch, avoiding a property list that has a tail of non-
  properties is a really good thing.  Your need is to recognize options
  when something like this is passed around, and that is fully satisfied
  with a new "type" around the string.

  There are many problems when processing TeX code.  I really suggest you
  do something that is easier to accomplish than to force a bright idea
  that does not work to work.
            
-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.