improved reader documentation

svn: r11673

original commit: a3930ea08846d9eef84bb3763b7a78f8c0341195
This commit is contained in:
Eli Barzilay 2008-09-12 13:22:31 +00:00
commit 916eaca8fa

View File

@ -20,20 +20,28 @@ You can use the reader via MzScheme's @schemefont{#reader} form:
@schemeblock[
#, @schemefont|{
#reader(lib "reader.ss" "scribble")@{This is free-form text!}
#reader scribble/reader @foo{This is free-form text!}
}|]
Note that the reader will only read @"@"-forms as S-expressions. The
meaning of these S-expressions depends on the rest of your own code.
Note that the Scribble reader reads @"@"-forms as S-expressions. This
means that it is up to you to give meanings for these expressions in
the usual way: use Scheme functions, define your functions, or require
functions. For example, typing the above into MzScheme is likely
going to produce a ``reference to undefined identifier'' error --- you
can use @scheme[string-append] instead, or you can define @scheme[foo]
as a function (with variable arity).
A PLT Scheme manual more likely starts with
A common use of the Scribble @"@"-reader is when using Scribble as a
documentation system for producing manuals. In this case, the manual
text is likely to start with
@schememod[scribble/doc]
which installs a reader, wraps the file content afterward into a
MzScheme module, and parses the body into a document using
@schememodname[scribble/decode]. See @secref["docreader"] for more
information.
which installs the @"@" reader starting in ``text mode'', wraps the
file content afterward into a MzScheme module where many useful Scheme
and documentation related functions are available, and parses the body
into a document using @schememodname[scribble/decode]. See
@secref["docreader"] for more information.
Another way to use the reader is to use the @scheme[use-at-readtable]
function to switch the current readtable to a readtable that parses
@ -44,6 +52,8 @@ function to switch the current readtable to a readtable that parses
@;--------------------------------------------------------------------
@section{Concrete Syntax}
@subsection{The Scribble Syntax at a Glance}
Informally, the concrete syntax of @"@"-forms is
@schemeblock[
@ -55,50 +65,136 @@ Informally, the concrete syntax of @"@"-forms is
where all three parts after @litchar["@"] are optional, but at least
one should be present. (Note that spaces are not allowed between the
three parts.) @litchar["@"] is set as a non-terminating reader macro,
so it can be used as usual in Scheme identifiers unless you want to
use it as a first character of an identifier; in this case you need to
quote with a backslash (@schemefont["\\@foo"]) or quote the whole
identifier with bars (@schemefont["|@foo|"]).
three parts.) Roughly, a form matching the above grammar is read as
@schemeblock[
#, @schemefont|!{
(define |@foo| '\@bar@baz)
}!|]
Of course, @litchar["@"] is not treated specially in Scheme strings,
character constants, etc.
Roughly, a form matching the above grammar is read as
@schemeblock[
(#, @nonterm{cmd}
#, @kleenestar{@nonterm{datum}}
#, @kleenestar{@nonterm{parsed-body}})
(#, @nonterm{cmd} #, @kleenestar{@nonterm{datum}} #, @kleenestar{@nonterm{parsed-body}})
]
where @nonterm{parsed-body} is the translation of each
@nonterm{text-body} in the input. Thus, the initial @nonterm{cmd}
determines the Scheme code that the input is translated into. The
common case is when @nonterm{cmd} is a Scheme identifier, which
generates a plain Scheme form.
A @nonterm{text-body} is made of text, newlines, and nested
@"@"-forms. Note that the syntax for @"@"-forms is the same in a
@nonterm{text-body} context as in a Scheme context. A
@nonterm{text-body} that isn't an @"@"-form is converted to a string
expression for its @nonterm{parsed-body}, and newlines are converted
to @scheme["\n"] expressions.
common case is when @nonterm{cmd} is a Scheme identifier, which reads
as a plain Scheme form, with datum arguments and/or string arguments.
@scribble-examples|==={
@foo{blah blah blah}
@foo{blah "blah" (`blah'?)}
@foo[1 2]{3 4}
@foo[1 2 3 4]
@foo[#:width 2]{blah blah}
@foo{blah blah
yada yada}
@foo{
blah blah
yada yada
}
}===|
(Note that these examples show how an input syntax is read as Scheme
syntax, not what it evaluates to.)
As seen in the last example, multiple lines and the newlines that
separate them are parsed to multiple Scheme strings. More generally,
a @nonterm{text-body} is made of text, newlines, and nested
@"@"-forms, where the syntax for @"@"-forms is the same whether it's
in a @nonterm{text-body} context as in a Scheme context. A
@nonterm{text-body} that isn't an @"@"-form is converted to a string
expression for its @nonterm{parsed-body}; newlines and following
indentations are converted to @scheme["\n"] and all-space string
expressions.
@scribble-examples|==={
@foo{bar baz
blah}
@foo{bar @baz[3]
blah}
@foo{bar @baz{3}
blah}
@foo{bar @baz[2 3]{4 5}
@foo{@b{@u[3] @u{4}}
blah}
@C{while (*(p++))
*p = '\n';}
}===|
The command part of an @"@"-form is optional as well, which is read as
a list, usually a function application, but also useful when quoted
with the usual Scheme @scheme[quote]:
@scribble-examples|==={
@{blah blah}
@{blah @[3]}
'@{foo
bar
baz}
}===|
But we can also drop the datum and text parts, which leaves us with
only the command --- which is read as is, not within a parenthesized
form. This is not useful when reading Scheme code, but it can be used
inside a text block to escape a Scheme identifier. A vertical bar
(@litchar{|}) can be used to delimit the escaped identifier when
needed.
@scribble-examples|==={
@foo
@{blah @foo blah}
@{blah @foo: blah}
@{blah @|foo|: blah}
}===|
Actually, the command part can be any Scheme expression, which is
particularly useful with such escapes since they can be used with any
expression.
@scribble-examples|==={
@foo{(+ 1 2) -> @(+ 1 2)!}
@foo{A @"string" escape}
}===|
Note that an escaped Scheme string is merged with the surrounding text
as a special case. This is useful if you want to use the special
characters in your string (but note that escaping braces is not
necessary if they are balanced).
@scribble-examples|==={
@foo{eli@"@"barzilay.org}
@foo{A @"{" begins a block}
@C{while (*(p++)) {
*p = '\n';
}}
}===|
In some cases a @"@"-rich text can become cumbersome to quote. For
this, the braces have an alternative syntax --- a block of text can
begin with a ``@litchar["|{"]'' and terminated accordingly with a
``@litchar["}|"]''. Furthermore, any nested @"@" forms must begin
with a ``@litchar["|@"]''.
@scribble-examples|==={
@foo|{bar}@{baz}|
@foo|{bar |@x{X} baz}|
@foo|{bar |@x|{@}| baz}|
}===|
In cases when even this is not convenient enough, punctuation
characters can be added between the @litchar{|} and the braces and the
@"@" in nested forms. (The punctuation is mirrored for parentheses
and @litchar{<>}s.) With this, the Scribble syntax can be used as a
here-string replacement.
@scribble-examples|==={
@foo|--{bar}@|{baz}--|
@foo|<<{bar}@|{baz}>>|
}===|
The flip side of this is: how can an @"@" sign be used in Scheme code?
This is almost never an issue, because Scheme strings and characters
are still read the same, and because @litchar["@"] is set as a
non-terminating reader macro so it can be used in Scheme identifiers
as usual except when it is the first character of an identifier. In
the last case, you need to quote the identifier like other
non-standard characters --- with a backslash or with vertical bars:
@scribble-examples|==={
(define \@email "foo@bar.com")
(define |@atchar| #\@)
}===|
Note that spaces are not allowed before a @litchar{[} or a
@ -109,9 +205,13 @@ code). (More on using braces in body texts below.)
@foo{bar @baz[2 3] {4 5}}
}===|
When the above @"@"-forms appear in a Scheme expression context, the
lexical environment must provide bindings for @scheme[foo] (as a procedure or
a macro).
Finally, remember that the Scribble is just an alternate for
S-expressions --- identifiers still get their meaning, as in any
Scheme code, through the lexical context in which they appear.
Specifically, when the above @"@"-form appears in a Scheme expression
context, the lexical environment must provide bindings for
@scheme[foo] as a procedure or a macro; it can be defined, required,
or bound locally (with @scheme[let], for example).
@; FIXME: unfortunate code duplication
@interaction[
@ -132,12 +232,16 @@ a macro).
@text{@it{Note}: @bf{This is @ul{not} a pipe}.}))
]
If you want to see the expression that is actually being read, you can
use Scheme's @scheme[quote].
When you first experiment with the Scribble syntax, it is often useful
to use Scheme's @scheme[quote] to inspect how some concrete syntax is
being read.
@scribble-examples|==={
'@foo{bar}
}===|
@; FIXME: unfortunate code duplication
@interaction[
(eval:alts
#,(tt "'@foo{bar}")
'@foo{bar})
]
@;--------------------------------------------------------------------
@subsection{The Command Part}