Version: 4.2.1
4 Reader Helpers
Creates and raises an
exn:fail:read exception, using
msg-string as the base error message.
Source-location information is added to the error message using the
last five arguments (if the error-print-source-location
parameter is set to #t). The source argument is an
arbitrary value naming the source location – usually a file path
string. Each of the line, pos arguments is
#f or a positive exact integer representing the location
within source-name (as much as known), col is a
non-negative exact integer for the source column (if known), and
span is #f or a non-negative exact integer for an
item range starting from the indicated position.
The usual location values should point at the beginning of whatever it
is you were reading, and the span usually goes to the point the error
was discovered.
4.2 Module Reader
The syntax/module-reader language provides support for
defining #lang readers. In its simplest form, the only thing
that is needed in the body of a syntax/module-reader
is the name of the module that will be used in the language position
of read modules; using keywords, the resulting readers can be
customized in a number of ways.
(#%module-begin module-path) |
(#%module-begin module-path reader-option ... body ....) |
(#%module-begin reader-option ... body ....) |
|
reader-option | | = | | #:language lang-expr | | | | | | #:read read-expr | | | | | | #:read-syntax read-syntax-expr | | | | | | #:wrapper1 wrapper1-expr | | | | | | #:wrapper2 wrapper2-expr | | | | | | #:whole-body-readers? whole?-expr |
|
Causes a module written in the
syntax/module-reader
language to define and provide
read and
read-syntax functions, making the module an
implementation of a reader. In particular, the exported reader
functions read all S-expressions until an end-of-file, and package
them into a new module in the
module-path language.
That is, a module something/lang/reader implemented
as
(module reader syntax/module-reader |
module-path) |
creates a reader that converts #lang something
into
(module name-id module-path |
....) |
where name-id is derived from the name of the port used by
the reader.
For example, scheme/base/lang/reader is implemented as
(module reader syntax/module-reader |
scheme/base) |
The reader functions can be customized in a number of ways, using
keyword markers in the syntax of the reader module. A #:read
and #:read-syntax keywords can be used to specify functions
other than read and read-syntax to perform the
reading. For example, you can implement a
Honu reader
using:
You can also use the (optional) module body to provide more
definitions that might be needed to implement your reader functions.
For example, here is a case-insensitive reader for the
scheme/base language:
In many cases, however, the standard read and
read-syntax are fine, as long as you can customize the
dynamic context they’re invoked at. For this, #:wrapper1 can
specify a function that can control the dynamic context in which the
reader functions are called. It should evaluate to a function that
consumes a thunk and invokes it in the right context. Here is an
alternative definition of the case-insensitive language using
#:wrapper1:
Note that using a readtable, you can implement
languages that are extensions of plain S-expressions.
In addition to this wrapper, there is also #:wrapper2 that
has more control over the resulting reader functions. If specified,
this wrapper is handed the input port and a (one-argumet) reader
function that expects the input port as an argument. This allows this
wrapper to hand a different port value to the reader function, for
example, it can divert the read to use different file (if given a port
that corresponds to a file). Here is the case-insensitive implemented
using this option:
In some cases, the reader functions read the whole file, so there is
no need to iterate them (e.g., Scribble’s read-inside and
read-syntax-inside). In these cases you can specify
#:whole-body-readers? as #t – the readers are
expected to return a list of expressions in this case.
In addition, the two wrappers can return a different value than the
wrapped function. This introduces two more customization points for
the resulting readers:
The thunk that is passed to a #:wrapper1 function
reads the file contents and returns a list of read expressions
(either syntax values or S-expressions). For example, the
following reader defines a “language” that ignores the contents
of the file, and simply reads files as if they were empty:
(module ignored syntax/module-reader |
scheme/base |
#:wrapper1 (lambda (t) (t) '())) |
Note that it is still performing the read, otherwise the module
loader will complain about extra expressions.
The reader function that is passed to a #:wrapper2
function returns the final reault of the reader (a module
expression). You can return a different value, for example,
making it use a different language module.
In some rare cases, it is more convenient to know whether a reader is
invoked for a
read or for a
read-syntax. To
accommodate these cases, both wrappers can accept an additional
argument, and in this case, they will be handed a boolean value that
indicates whether the reader is expected to read syntax (
#t)
or not (
#f). For example, here is a reader that uses the
scribble syntax, and the first datum in the file determines the actual
language (which means that the library specification is effectively
ignored):
This ability to change the language position in the resulting module
expression can be useful in cases such as the above, where the base
language module is chosen based on the input. To make this more
convenient, you can omit the
module-path and instead specify
it via a
#:language expression. This expression can evaluate
to a datum which is used as a language, or it can evaluate to a thunk.
In the latter case, the thunk will be invoked to return such a datum
before reading the module body begins, in a dynamic extent where
current-input-port is the source input. Using this, the last
example above can be written more concisely:
[Note: this function is deprecated;
syntax/module-reader can be adapted using the various
keywords to arbitrary readers, please use it instead.]
Repeatedly calls read on in until an end of file,
collecting the results in order into lst, and derives a
name-id from (object-name in). The last five
arguments are used to construct the syntax object for the language
position of the module. The result is roughly
`(module ,name-id ,mod-path ,@lst)