racket/collects/scribblings/reference/macros.scrbl
Matthew Flatt 4736768878 doc and scribble work
svn: r6431
2007-06-01 06:28:46 +00:00

155 lines
5.7 KiB
Racket

#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@title[#:tag "mz:expansion"]{Syntax Expansion}
Expansion recursively processes a syntax-wrapped datum to parse it. In
general, the parsing of a datum depends on its outermost shape:
@itemize{
@item{If it is a (syntax-wrapped) symbol, also known as an
@defterm{identifier}, then a binding is determined using symbol
along with the lexical information in the symbol's syntax
wrapper. The binding determines the next parsing step.}
@item{If it is a (syntax-wrapped) pair whose first element is an
identifier, then the identifier's binding is used (as in the
preceding case).}
@item{If it is a (syntax-wrapped) pair, then the symbol
@scheme['#%app] is wrapped with the lexical context of the
pair's syntax wrapper. If the resulting @scheme[#%app]
identifier has no binding, parsing fails with an
@scheme[exn:fail:syntax] exception. Otherwise, the new
identifier is @scheme[cons]ed with the pair, and then the pair
is wrapped using the same context as the @scheme[#%app]
identifier, and parsing starts again (i.e., it continues with
the preceding case).}
@item{If it is any other (syntax-wrapped) value, then the symbol
@scheme['#%datum] is wrapped with the lexical context of the
values syntax wrapper. If the resulting @scheme[#%datum]
identifier has no binding, parsing fails with an
@scheme[exn:fail:syntax] exception. Otherwise, the new
identifier is @scheme[cons]ed with the pair, and then the pair
is wrapped using the same context; parsing starts again (i.e.,
it continues with the second case above).}
}
For either of the first two steps, if the identifier has no binding,
then the symbol @scheme['#%top] is wrapped with the same lexical
context as the identifier; is this @scheme[#%top] identifier has no
binding, then parsing fails with an @scheme[exn:fail:syntax]
exception. Otherwise, parsing starts again, using the binding for
@scheme[#%top].
Thus, the possibilities that do not fail lead to an identifier with a
particular binding. This binding refers to one of three things:
@itemize{
@item{A transformer binding, such as introduced by
@scheme[define-syntax] or @scheme[let-syntax]. If the
associated value is to a procedure of one argument, the
procedure is called as a syntax transformer (see
@secref["transformers"]), and parsing starts again with the
syntax result. If the transformer binding is to any other kind
of value, parsing fails with an @scheme[exn:fail:syntax]
exception.}
@item{A variable binding, such as introduced by a module-level
@scheme[define] or by @scheme[let]. In this case, if the form
being parsed is just an identifier, then it is parsed as a
run-time reference to the location of the corersponding
variable. If the form being parsed is a (syntax-wrapped) list,
then an @scheme[#%app] is added to the from of the list in the
same way as when the kfirst thing in the list is not an
identifier (third case in the prvious enumeration), and parsing
continues.}
@item{Core syntax, which is parsed as described in the reminder of
this section. Parsing core syntactic forms typically involves
recursive parsing of sub-forms, and may introduce bindings that
control the parsing of sub-forms.}
}
Each expansion step occurs in a particular context, and transformers
and core-syntax parsing can depend on the context. For example, a
@scheme[module] form is allowed only in a top-level context. The
possible contexts are as follows:
@itemize{
@item{@defterm{top level} : outside of any module, definition, or
expression, except that sub-expressions of a top-level
@scheme[begin] form are also expanded as top-level forms.}
@item{@defterm{module begin} : inside the body of a module, as the
only form within the module.}
@item{@defterm{module body} : in the body of a module (inside the
moudule-begin layer).}
@item{@defterm{internal definition} : in a nested context that allows
both definitions and expressions.}
@item{@defterm{expression} : in a context where only expressions are
allowed.}
}
A fully expanded program---that is, a parsed program---is represented
in the same way as an unparsed program: as a syntax-wrapped
combination of symbols, pairs, and other values. However, a fully
expanded program fits a specific grammar.
@schemeblock[
#, @is-one-of[@scheme[_top-level-expr]]
_general-top-level-expr
(#%expression _expr)
(module _id _name-id
(#%plain-module-begin _module-level-expr ...))
(begin _top-level-expr ...)
code:blank
#, @is-one-of[@scheme[_module-level-expr]]
_general-top-level-expr
(provide _provide-spec ...)
code:blank
#, @is-one-of[@scheme[_general-top-level-expr]]
_expr
(define-values (_id ...) _expr)
(define-syntaxes (_id ...) _expr)
(define-values-for-syntax (_id ...) _expr)
(require _require-spec ...)
(require-for-syntax _require-spec ...)
(require-for-template _require-spec ...)
code:blank
#, @is-one-of[@scheme[_expr]]
_id
(lambda _formals _expr ...+)
(case-lambda (_formals _expr ...+) ...)
(if _expr _expr)
(if _expr _expr _expr)
(begin _expr ...+)
(begin0 _expr _expr ...)
(let-values (((_id ...) _expr) ...) _expr ...+)
(letrec-values (((_id ...) _expr) ...) _expr ...+)
(set! _id _expr)
(#, @scheme[quote] _datum)
(quote-syntax _datum)
(with-continuation-mark _expr _expr _expr)
(#%app _expr ...+)
(#%datum . _datum)
(#%top . _id)
(#%variable-reference _id)
(#%variable-reference (#%top . _id))
code:blank
#, @is-one-of[@scheme[_formals]]
(_id ...)
(_id ...+ . _id)
_id
]