@node Interpretation of unclear parts of the specification
@chapter Interpretation of unclear parts of the specification

@cindex specification interpretation

This chapter describes @sysname{}'s interpretation of passages in the
@commonlisp{} specification that do not describe the behavior of a
conforming reader completely unambiguously.

@menu
* Interpretation of Sharpsign C and Sharpsign S::
* Interpretation of Backquote and Sharpsign Single Quote::
* Circular objects and custom reader macros::
@end menu

@node Interpretation of Sharpsign C and Sharpsign S
@section Interpretation of Sharpsign C and Sharpsign S

@cindex reader macro
@cindex complex literal
@cindex structure literal

At first glance, Sharpsign C and Sharpsign S seem to follow the same
syntactic structure: the dispatch macro character followed by the
sub-character followed by a list of a specific structure.  However, the
actual descriptions of the respective syntax is different.  For
Sharpsign C, the specification states:

@quotation
@t{#C} reads a following object, which must be a list of length two
whose elements are both reals.
@end quotation

For Sharpsign S, on the other hand, the specification describes the
syntax as:

@quotation
@t{#s(@var{name} @var{slot1} @var{value1} @var{slot2} @var{value2} ...)} denotes a structure.
@end quotation

Note how the description for Sharpsign C relies on a recursive @t{read}
invocation while the description for Sharpsign S gives a character-level
pattern with meta-syntactic variables.  It is possible that this is an
oversight and the syntax was intended to be uniform between the two
reader macros.  Whatever the case may be, in order to handle existing
code without inconveniencing clients, @sysname{} implements both
Sharpsign C and Sharpsign S with a recursive @t{read} invocation which
corresponds to permissive behavior.

More concretely, @sysname{} behaves as summarized in the following table:

@multitable @columnfractions .5 .5
@headitem Input                                        @tab Behavior
@item @t{#C(1 2)}                                      @tab Read as @t{#C(1 2)}
@item @t{#C (1 2)}                                     @tab Read as @t{#C(1 2)}
@item @t{#C#||#(1 2)}                                  @tab Read as @t{#C(1 2)}
@item @t{#C#.(list 1 (+ 2 3))}                         @tab Read as @t{#C(1 5)}
@item @t{#C[1 2]} for left-parenthesis syntax on @t{[} @tab Read as @t{#C(1 2)}

@item @t{#S(foo)}                                      @tab Read as @t{#S(foo)}
@item @t{#S (foo)}                                     @tab Read as @t{#S(foo)}
@item @t{#S#||#(foo)}                                  @tab Read as @t{#S(foo)}
@item @t{#S#.(list 'foo)}                              @tab Read as @t{#S(foo)}
@item @t{#S[foo]} for left-parenthesis syntax on @t{[} @tab Read as @t{#S(foo)}
@end multitable

@sysname{} provides a strict version of the Sharpsign C macro function
under the name @t{@readerpackage{}:strict-sharpsign-c} which behaves as
follows:

@multitable @columnfractions .5 .5
@headitem Input                                        @tab Behavior
@item @t{#C(1 2)}                                      @tab Read as @t{#C(1 2)}
@item @t{#C (1 2)}                                     @tab Rejected
@item @t{#C#||#(1 2)}                                  @tab Rejected
@item @t{#C#.(list 1 (+ 2 3))}                         @tab Rejected
@item @t{#C[1 2]} for left-parenthesis syntax on @t{[} @tab Read as @t{#C(1 2)}
@end multitable

@sysname{} provides a strict version of the Sharpsign S macro function
under the name @t{@readerpackage{}:strict-sharpsign-s} which behaves as
follows:

@multitable @columnfractions .5 .5
@headitem Input                                        @tab Behavior
@item @t{#S(foo)}                                      @tab Read as @t{#S(foo)}
@item @t{#S (foo)}                                     @tab Rejected
@item @t{#S#||#(foo)}                                  @tab Rejected
@item @t{#S#.(list 'foo)}                              @tab Rejected
@item @t{#S[foo]} for left-parenthesis syntax on @t{[} @tab Rejected
@end multitable

@node Interpretation of Backquote and Sharpsign Single Quote
@section Interpretation of Backquote and Sharpsign Single Quote

@cindex reader macro
@cindex quasiquote
@cindex function

The @commonlisp{} specification is very specific about the contexts in
which the quasiquotation mechanism can be used.  Explicit descriptions
of the behavior of the quasiquotation mechanism are given for
expressions which @emph{are} lists or vectors and it is implied that
unquote is not allowed in other expressions.  From this description, it
is clear that @t{`#S(foo :bar ,x)} is not valid syntax, for example.
However, whether @t{`#',foo} is valid syntax depends on whether
@t{#'@var{thing}} is considered to @emph{be} a list.  Since @t{`#',foo}
is a relatively common idiom, @sysname{} accepts it by default.

@sysname{} provides a strict version of the Sharpsign Single Quote macro
function under the name
@t{@readerpackage{}:strict-sharpsign-single-quote} which does not accept
unquote in the function name.

@node Circular objects and custom reader macros
@section Circular objects and custom reader macros

The @commonlisp{} specification describes the behavior of the @t{##}
reader macro as follows:

@quotation
@t{#@var{n}#}, where @var{n} is a required unsigned decimal integer,
provides a reference to some object labeled by @t{#@var{n}=}; that is,
@t{#@var{n}#} represents a pointer to the same (@t{eq}) object labeled
by @t{#@var{n}=}.
@end quotation

The vague phrasing ``represents a pointer to the same (@t{eq}) object''
is probably chosen to cover the situation in which the object in
question is not yet defined when the reader encounters the @t{#@var{n}#}
reference as is the case with input of the form
@t{#@var{n}=(…#@var{n}#…)}.  The fact that the object is not yet defined
when the reference is encountered is not a problem in general except for
one situation: assume @t{#_} is a custom reader macro in the current
readtable which calls @t{read}.  In this situation, reading an
expression of the form @t{#@var{n}=(…#_#@var{n}#…)} causes the reader
macro function for @t{#_} to be called which calls @t{read} to read the
following object which encounters the reference. This chain of calls
leads to a potential problem: the @t{read} call made by the reader macro
function has to return some object but it cannot return the object
labeled @var{n} since that object has not been read yet.  The reader
macro function must therefore receive some sort of
implementation-dependent @footnote{We use ``implementation-dependent''
in the sense defined in the @commonlisp{} specification except that
@sysname{} is the implementation in question.} object which stands in
for the object labeled @var{n} and gets replaced at some later time
after the object labeled @var{n} has been read.  Since the stand-in
object is implementation-dependent, the reader macro function must not
make any assumptions regarding the type of the object or operate on it
in any way other than returning the object or using the object as a part
of a compound object.

The following example violates this principle since the reader macro
function in @t{custom-macro-readtable} calls @speclink{f,first} on the
object returned by @funref{read,@readerpackage{}}:

@lisp
(defun custom-macro-readtable ()
  (let ((readtable (eclector.readtable:copy-readtable
                    eclector.reader:*readtable*)))
    (eclector.readtable:set-dispatch-macro-character
     readtable #\# #\_ (lambda (stream char sub-char)
                         (declare (ignore char sub-char))
                         (second (eclector.reader:read stream t nil t))))
    readtable))

(let ((eclector.reader:*readtable* (custom-macro-readtable)))
  (eclector.reader:read-from-string "#1=(:a #_#1#)"))
@result{} undefined
@end lisp

To handle the problem described above, @sysname{} imposes the following
restriction on custom reader macro functions which call @t{read}:

@quotation
A reader macro function which reads an object by calling @t{read} must
account for the object being of an implementation-dependent type and
must not operate on the object in any way other than returning the
object or using the object as a part of a compound object.
@end quotation
