When something goes wrong with a Scheme program, the user will want to know how to fix it. This starts with identifying where the error occurred: we want to associate a source location with each component part of source code, and propagate that source location information through to the compiler or interpreter.
For that, Guile provides read-syntax
.
Read an s-expression from the input port port, or from the current input port if port is not specified.
If, after skipping white space and comments, no more bytes are available from port, return the end-of-file object. See Binary I/O. Otherwise, return an annotated datum. An annotated datum is a syntax object which associates a source location with a datum. For example:
(call-with-input-string " foo" read-syntax) ; ⇒ #<syntax:unknown file:1:2 foo> (call-with-input-string "(foo)" read-syntax) ; ⇒ ; #<syntax:unknown file:1:0 ; (#<syntax unknown file:1:1 foo>)>
As the second example shows, all fields of pairs and vectors are also annotated, recursively.
Most users are familiar with syntax objects in the context of macros,
which use syntax objects to associate scope information with
identifiers. See Macros. Here we use syntax objects to associate
source location information with any datum, but without attaching scope
information. The Scheme compiler (compile
) and the interpreter
(eval
) can accept syntax objects directly as input, allowing them
to associate source information with resulting code.
See Compiling Scheme Code, and See Procedures for On the Fly Evaluation.
Note that there is a legacy interface for getting source locations into
the Scheme compiler or interpreter, which is to use a side table that
associates “source properties” with each subdatum returned by
read
, instead of wrapping the datums directly as in
read-syntax
. This has the disadvantage of not being able to
annotate all kinds of datums. See Source Properties, for more
information.