more reference work on syntax transformers

svn: r6890
This commit is contained in:
Matthew Flatt 2007-07-11 09:49:48 +00:00
parent 9a21c13be1
commit dba44c0b1e
4 changed files with 592 additions and 75 deletions

View File

@ -14,4 +14,4 @@ called.
@include-section["stx-patterns.scrbl"]
@include-section["stx-ops.scrbl"]
@include-section["stx-comp.scrbl"]
@include-section["stx-trans.scrbl"]

View File

@ -0,0 +1,414 @@
#reader(lib "docreader.ss" "scribble")
@require["mz.ss"]
@require-for-syntax[mzscheme]
@define[(transform-time) @t{This procedure must be called during the
dynamic extent of a @tech{syntax transformer} application by the
expander, otherwise the @exnraise[exn:fail:contract].}]
@title[#:tag "mz:stxtrans"]{Syntax Transformers}
@defproc[(make-set!-transformer [proc (syntax? . -> . syntax?)])
set!-transformer?]{
Creates a @tech{syntax transformer} that cooperates with
@scheme[set!]. If the result of @scheme[make-set!-transformer] is
bound to @scheme[identifier] as a @tech{transformer binding}, then
@scheme[proc] is applied as a transformer when @scheme[identifier] is
used in an expression position, or when it is used as the target of a
@scheme[set!] assignment as @scheme[(set! identifier _expr)]. When the
identifier appears as a @scheme[set!] target, the entire @scheme[set!]
expression is provided to the transformer.
@examples[
(let ([x 1]
[y 2])
(let-syntax ([x (make-set!-transformer
(lambda (stx)
(syntax-case stx (set!)
(code:comment #, @t{Redirect mutation of x to y})
[(set! id v) (syntax (set! y v))]
(code:comment #, @t{Normal use of @scheme[x] really gets @scheme[x]})
[id (identifier? (syntax id)) (syntax x)])))])
(begin
(set! x 3)
(list x y))))
]}
@defproc[(set!-transformer? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a value created by
@scheme[make-set!-transformer], @scheme[#f] otherwise.}
@defproc[(set!-transformer-procedure [transformer set!-transformer?])
(syntax? . -> . syntax?)]{
Returns the procedure that was passed to
@scheme[make-set!-transformer] to create @scheme[transformer].}
@defproc[(make-rename-transformer [id-stx syntax?])
rename-transformer?]{
Creates a value that, when used as a @tech{transformer binding},
inserts the identifier @scheme[id-stx] in place of whatever identifier
binds the transformer, including in non-application positions, and in
@scheme[set!] expressions. Such a transformer could be written
manually, but the one created by @scheme[make-rename-transformer]
cooperates specially with @scheme[syntax-local-value] (see below).}
@defproc[(rename-transformer? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a value created by
@scheme[make-rename-transformer], @scheme[#f] otherwise.}
@defproc[(rename-transformer-target [transformer rename-transformer?])
syntax?]{
Returns the identifier passed to @scheme[make-rename-transformer] to
create @scheme[transformer].}
@defproc[(local-expand [stx syntax?]
[context-v (or/c (one-of 'expression 'top-level 'module
'module-begin)
list?)]
[stop-ids (or/c (listof identifier?) false/c)]
[intdef-ctx (or/c internal-definition-context?
false/c)
#f])
syntax?]{
Expands @scheme[stx] in the lexical context of the expression
currently being expanded. The @scheme[context-v] argument is used as
the result of @scheme[syntax-local-context] for immediate expansions;
for a particular @tech{internal-definition context}, generate a unique
value and @scheme[cons] it onto the current result of
@scheme[syntax-local-context] if it is a list.
When an identifier in @scheme[stop-ids] is encountered by the expander
in a subexpression, expansions stops for the subexpression. If
@scheme[#%app], @scheme[#%top], or @scheme[#%datum] (see
@secref["mz:stxspecial"]) appears in @scheme[stop-ids], then
application, top-level variable reference, and literal data
expressions without the respective explicit form are not wrapped with
the explicit form. If @scheme[stop-ids] is @scheme[#f] instead of a
list, then @scheme[stx] is expanded only as long as the outermost form
of @scheme[stx] is a macro (i.e., expansion does not proceed to
sub-expressions).
The optional @scheme[intdef-ctx] argument must be either @scheme[#f]
or the result of @scheme[syntax-local-make-definition-context]. In the
latter case, lexical information for internal definitions is added to
@scheme[stx] before it is expanded. The lexical information is also
added to the expansion result (because the expansion might introduce
bindings or references to internal-definition bindings).
Expansion of @scheme[stx] can use certificates for the expression
already being expanded (see @secref["mz:stxprotect"]) , and inactive
certificates associated with @scheme[stx] are activated for
@scheme[stx] (see @secref["mz:stxinactivecerts"]). Furthermore, if the
transformer is defined within a module (i.e., the current expansion
was triggered by a use of a module-defined identifier with a
@tech{transformer binding}) or if the current expression is being
expanded for the body of a module, then the expansion of @scheme[stx]
can use any identifier defined by the module.
@transform-time[]}
@defproc[(syntax-local-expand-expression [stx syntax?])
(values syntax? syntax?)]{
Like @scheme[local-expand] given @scheme['expression] and an empty
stop list, but with two results: a syntax object for the fully
expanded expression, and a syntax object whose content is opaque. The
latter can be used in place of the former (perhaps in a larger
expression produced by a macro transformer), and when the macro
expander encouters the opaque object, it substitutes the fully
expanded expression without re-expanding it; the
@exnraise[exn:fail:syntax] if the expansion context includes bindings
or marks that were not present for the original expansion, in which
case re-expansion might produce different results. Consistent use of
@scheme[syntax-local-expand-expression] and the opaque object thus
avoids quadratic expansion times when local expansions are nested.
@transform-time[]}
@defproc[(local-transformer-expand [stx syntax?]
[context-v (or/c (one-of 'expression 'top-level 'module
'module-begin)
list?)]
[stop-ids (or/c (listof identifier?) false/c)]
[intdef-ctx (or/c internal-definition-context?
false/c)
#f])
syntax?]{
Like @scheme[local-expand], but @scheme[stx] is expanded as a
transformer expression instead of a run-time expression.}
@defproc[(local-expand/capture-lifts [stx syntax?]
[context-v (or/c (one-of 'expression 'top-level 'module
'module-begin)
list?)]
[stop-ids (or/c (listof identifier?) false/c)]
[intdef-ctx (or/c internal-definition-context?
false/c)
#f])
syntax?]{
Like @scheme[local-expand], but if
@scheme[syntax-local-lift-expression] is called during the expansion
of @scheme[stx], the result is a syntax object that represents a
@scheme[begin] expression; lifted expression appear with their
identifiers in @scheme[define-values] forms, and the expansion of
@scheme[stx] is the last expression in the @scheme[begin]. The lifted
expressions are not expanded.}
@defproc[(local-transformer-expand/capture-lifts [stx syntax?]
[context-v (or/c (one-of 'expression 'top-level 'module
'module-begin)
list?)]
[stop-ids (or/c (listof identifier?) false/c)]
[intdef-ctx (or/c internal-definition-context?
false/c)
#f])
syntax?]{
Like @scheme[local-expand/capture-lifts], but @scheme[stx] is expanded
as a transformer expression instead of a run-time expression. Lifted
expressions are reported as @scheme[define-values] forms (in the
transformer environment).}
@defproc[(syntax-local-make-definition-context) internal-definition-context?]{
Creates an opaque internal-definition context value to be used with
@scheme[local-expand] and other functions. A transformer should create
one context for each set of internal definitions to be expanded, and
use it when expanding any form whose lexical context should include
the definitions. After discovering an internal @scheme[define-values]
or @scheme[define-syntaxes] form, use
@scheme[syntax-local-bind-syntaxes] to add bindings to the context.
@transform-time[]}
@defproc[(syntax-local-bind-syntaxes [id-list (listof identifier?)]
[expr (or/c syntax? false/c)]
[intdef-ctx internal-definition-context?])
void?]{
Binds each identifier in @scheme[id-list] within the
internal-definition context represented by @scheme[intdef-ctx], where
@scheme[intdef-ctx] is the result of
@scheme[syntax-local-make-definition-context]. Supply @scheme[#f] for
@scheme[expr] when the identifiers correspond to
@scheme[define-values] bindings, and supply a compile-time expression
when the identifiers correspond to @scheme[define-syntaxes] bindings;
the later case, the number of values produces by the expression should
match the number of identifiers, otherwise the
@exnraise[exn:fail:contract:arity].
@transform-time[]}
@defproc[(syntax-local-value [id-stx syntax?]
[failure-thunk (or/c (-> any) false/c)
#f]
[intdef-ctx (or/c internal-definition-context?
false/c)
#f])
any]{
Returns the @tech{transformer binding} value of @scheme[id-stx] in
either the context asscoiated with @scheme[intdef-ctx] (if not
@scheme[#f]) or the context of the expression being expanded (if
@scheme[indef-ctx] is @scheme[#f]). If @scheme[intdef-ctx] is
provided, it must be an extension of the context of the expression
being expanded.
If @scheme[id-stx] is bound to a rename transformer created with
@scheme[make-rename-transformer], @scheme[syntax-local-value]
effectively calls itself with the target of the rename and returns
that result, instead of the rename transformer.
If @scheme[id-stx] has no @tech{transformer binding} (via
@scheme[define-syntax], @scheme[let-syntax], etc.) in that
environment, the result is obtained by applying @scheme[failure-thunk]
if not @scheme[#f]. If @scheme[failure-thunk] is @scheme[false], the
@exnraise[exn:fail:contract].
Resolving @scheme[id-stx] can use certificates for the expression
being transformed (see @secref["mz:stxprotect"]) as well as inactive
certificates associated with @scheme[id-stx] (see
@secref["mz:stxinactivecerts"]). Furthermore, if the transformer is
defined within a module (i.e., the current transformation was
triggered by a use of a module-defined identifier) or if the current
expression is being expanded for the body of a module, then resolving
@scheme[id-stx] can access any identifier defined by the module.
@transform-time[]}
@defproc[(syntax-local-lift-expression [stx syntax?])
identifier?]{
Returns a fresh identifier, and cooperates with the @scheme[module],
@scheme[letrec-syntaxes+values], @scheme[define-syntaxes],
@scheme[begin-for-syntax], and top-level expanders to bind the
generated identifier to the expression @scheme[stx].
A run-time expression within a module is lifted to the module's top
level, just before the expression whose expansion requests the
lift. Similarly, a run-time expression outside of a module is lifted
to a top-level definition. A compile-time expression in a
@scheme[letrec-syntaxes+values] or @scheme[define-syntaxes] binding is
lifted to a @scheme[let] wrapper around the corresponding right-hand
side of the binding. A compile-time expression within
@scheme[begin-for-syntax] is lifted to a @scheme[define-for-syntax]
declaration just before the requesting expression.
Other syntactic forms can capture lifts by using
@scheme[local-expand/capture-lifts] or
@scheme[local-transformer-expand/capture-lifts].
@transform-time[]}
@defproc[(syntax-local-lift-module-end-declaration [stx syntax?])
void?]{
Cooperates with the @scheme[module] form to insert @scheme[stx] as
a top-level declaration at the end of the module currently being
expanded. If the current expression being transformed is not within a
@scheme[module] form, or if it is not a run-time expression, then the
@exnraise[exn:fail:contract]. If the current expression being
transformed is not in the module top-level, then @scheme[stx] is
eventually expanded in an expression context.
@transform-time[]}
@defproc[(syntax-local-name) (or/c symbol? false/c)]{
Returns an inferred name for the expression position being
transformed, or @scheme[#f] if no such name is available. See also
@secref["mz:infernames"].
@transform-time[]}
@defproc[(syntax-local-context)
(or/c (one-of 'expression 'top-level 'module 'module-begin)
list?)]{
Returns an indication of the context for expansion that triggered a
@tech{syntax transformer} call. See @secref["mz:expand-context-model"]
for more information on contexts.
The symbol results indicate that the expression is being expanded for
an @tech{expression context}, a @tech{top-level context}, a
@tech{module context}, or a @tech{module-begin context}.
A list result indicates expansion in an @tech{internal-definition
context}. The identity of the lists's first element (i.e., its
@scheme[eq?]ness) reflects the identity of the internal-definition
context; in particular two transformer expansions receive the same
first value if and only if they are invoked for the same
internal-definition context. Later values in the list similarly
identify internal-definition contexts that are still being expanded,
and that required the expansion of nested internal-definition
contexts.
@transform-time[]}
@defproc[(syntax-local-get-shadower [id-stx identifier?]) identifier?]{
Returns @scheme[id-stx] if no binding in the current expansion context
shadows @scheme[id-stx], if @scheme[id-stx] has no module bindings in
its lexical information, and if the current expansion context is not a
@tech{module context}.
If a binding of @scheme[inner-identifier] shadows @scheme[id-stx], the
result is the same as @scheme[(syntax-local-get-shadower
@scheme[inner-identifier])], except that it has the location and
properties of @scheme[id-stx].
Otherwise, the result is the same as @scheme[id-stx] with its module
bindings (if any) removed from its lexical information, and the
lexical information of the current @tech{module context} (if any)
added.
Thus, the result is an identifier corresponding to the innermost
shadowing of @scheme[id-stx] in the current context if its shadowed,
and a module-contextless version of @scheme[id-stx] otherwise.
@transform-time[]}
@defproc[(syntax-local-certifier [active? boolean? #f])
(syntax? (any/c (or/c procedure? false/c))
. opt-> . syntax?)]{
Returns a procedure that captures any certificates currently available
for @scheme[syntax-local-value] or @scheme[local-expand]. The
procedure accepts one to three arguments: @scheme[_stx] (required),
@scheme[_key] (optional), and @scheme[_intro] (optional). The
procedure's result is a syntax object like @scheme[stx], except that
it includes the captured certificates as inactive (see
@secref["mz:stxinactivecerts"]) if @scheme[active?] is @scheme[#f]
(the default) or active otherwise. If @scheme[key] is supplied and
not @scheme[#f], it is associated with each captured certificate for
later use through @scheme[syntax-recertify] (see
@secref["mz:stxtransfer"]). If @scheme[_intro] is supplied, and if it
is not @scheme[#f] (the default), then it must be a procedure created
by @scheme[make-syntax-introducer], in which case the certificate
applies only to parts of @scheme[stx] that are marked as introduced by
@scheme[_intro].
Supply @scheme[#t] for @scheme[active?] when the syntax to be
certified can be safely used in any context by any party, and where
access to the syntax object should not confer any additional
access. Supply @scheme[#f] for @scheme[active?] when the syntax to be
certified is not accessible to parties that might abuse the access
that the certificate provides, and when the certified syntax
eventually appears (via macro expansion) within a larger expression
from which it cannot be safely extracted by other parties.
@transform-time[]}
@defproc[(syntax-transforming?) boolean?]{
Returns @scheme[#t] during the dynamic extent of a @tech{syntax
transformer} application by the expander, @scheme[#f] otherwise.}
@defproc[(syntax-local-introduce [stx syntax?]) syntax?]{
Produces a syntax object that is like @scheme[stx], except that a
@tech{syntax mark} for the current expansion is added (possibly
canceling an existing mark in parts of @scheme[stx]). See
@secref["mz:transformer-model"] for information on @tech{syntax
marks}.
@transform-time[]}
@defproc[(make-syntax-introducer) (syntax? . -> . syntax?)]{
Produces a procedure that behaves like
@scheme[syntax-local-introduce], but using a fresh @tech{syntax
mark}. Multiple applications of the same
@scheme[make-syntax-introducer] result procedure use the same mark,
and different result procedures use distinct marks.}

View File

@ -72,17 +72,25 @@ variable}. A hyperlinked @tech{identifier} @scheme[cons] is a
reference to a specific @tech{top-level variable}.
Every binding has a @deftech{phase level} in which it can be
referenced, where a phase level corresponds to an integer. Phase level
0 corresponds to the run time of the enclosing module (or the run time
of top-level expression); phase level 1 corresponds to the time during
which the enclosing module (or top-level expression) is expanded;
phase level -1 corresponds to the run time of a different module for
which the enclosing module is imported for use at phase level 1
(relative to the importing module). If an identifier has a @tech{local
binding}, then it is the same for all phase levels, though the
reference is allowed only at a particular phase level. If an
identifier has a @tech{top-level binding} or @tech{module binding},
then it can have different such bindings in different phase levels.
referenced, where a @tech{phase level} corresponds to an
integer. @tech{Phase level} 0 corresponds to the run time of the
enclosing module (or the run time of top-level expression). bindings
in @tech{phase level} 0 constitute the @deftech{base environment}.
@tech{Phase level} 1 corresponds to the time during which the
enclosing module (or top-level expression) is expanded; bindings in
@tech{phase level} 0 constitute the @deftech{transformer environment}.
Phase level -1 corresponds to the run time of a different module for
which the enclosing module is imported for use at @tech{phase level} 1
(relative to the importing module); bindings in @tech{phase level} -1
constitute the @deftech{template environment}.
If an identifier has a @tech{local binding}, then it is the same for
all phase levels, though the reference is allowed only at a particular
phase level. Attempting to reference a @tech{local binding} in a
different @tech{phase level} than the binding's context produces a
syntax error. If an identifier has a @tech{top-level binding} or
@tech{module binding}, then it can have different such bindings in
different phase levels.
@;------------------------------------------------------------------------
@section[#:tag "mz:stxobj-model"]{Syntax Objects}
@ -161,7 +169,7 @@ A complete expansion produces a @tech{syntax object} matching the
following grammar:
@schemegrammar*[
#:literals (#%expression module #%plain-module-begin begin provide
#:literals (#%expression module #%module-begin begin provide
define-values define-syntaxes define-values-for-syntax
require require-for-syntax require-for-template
#%plain-lambda case-lambda if begin begin0 let-values letrec-values
@ -170,7 +178,7 @@ following grammar:
[top-level-form general-top-level-form
(#%expression expr)
(module id name-id
(#%plain-module-begin
(#%module-begin
module-level-form ...))
(begin top-level-form ...)]
[module-level-form general-top-level-form
@ -219,20 +227,21 @@ one whose binding is @scheme[define-values]). In all cases,
identifiers above typeset as syntactic-form names refer to the
bindings defined in @secref["mz:syntax"].
Only @tech{phase levels} 0 and 1 are relevant for following the parse of a
Only @tech{phase levels} 0 and 1 are relevant for the parse of a
program (though the @scheme[_datum] in a @scheme[quote-syntax] form
preserves its information for all phase levels). In particular, the
relevant phase level is 0, except for the @scheme[_expr]s in a
@scheme[define-syntaxes] @scheme[define-values-for-syntax], in which
case the relevant phase is 1 (for which comparisons are made using
@scheme[free-transformer-identifier=?] instead of
@scheme[free-identifier=?]).
preserves its information for all @tech{phase level}s). In particular,
the relevant @tech{phase level} is 0, except for the @scheme[_expr]s
in a @scheme[define-syntax], @scheme[define-syntaxes],
@scheme[define-for-syntax], or @scheme[define-values-for-syntax] form,
in which case the relevant @tech{phase level} is 1 (for which
comparisons are made using @scheme[free-transformer-identifier=?]
instead of @scheme[free-identifier=?]).
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "mz:expand-steps"]{Expansion Steps}
In a recursive expansion, each single step in expanding a @tech{syntax
object} at a particular phase level depends on the immediate shape of
object} at a particular @tech{phase level} depends on the immediate shape of
the @tech{syntax object} being expanded:
@itemize{
@ -317,7 +326,7 @@ things:
}
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection{Expansion Context}
@subsection[#:tag "mz:expand-context-model"]{Expansion Context}
Each expansion step occurs in a particular @deftech{context}, and
transformers and core syntactic forms may expand differently for
@ -362,28 +371,32 @@ core syntactic forms are encountered:
@item{When a @scheme[require] form is encountered at the top level or
module level, all lexical information derived from the top
level or the specific module's level are extended with bindings
from the specified modules, and at the phase levels (normally
0) specified by the exporting modules.}
from the specified modules, and at the @tech{phase level}s
(normally 0) specified by the exporting modules.}
@item{When a @scheme[require-for-syntax] form is encountered at the
top level or module level, it is treated like @scheme[require],
except that the phase level for all bindings is incremented by
except that the @tech{phase level} for all bindings is incremented by
1.}
@item{When a @scheme[require-for-template] form is encountered at the
top level or module level, it is treated like @scheme[require],
except that the phase level for all bindings is decremented by
except that the @tech{phase level} for all bindings is decremented by
1.}
@item{When a @scheme[define-values] or @scheme[define-syntaxes] form
is encountered at the top level or module level, all lexical
@item{When a @scheme[define], @scheme[define-values],
@scheme[define-syntax], or @scheme[define-syntaxes] form is
encountered at the top level or module level, all lexical
information derived from the top level or the specific module's
level are extended with bindings for the specified identifiers
at phase level 0.}
level is extended with bindings for the specified identifiers
at @tech{phase level} 0 (i.e., the @tech{base environment} is
extended).}
@item{When a @scheme[define-values-for-syntax] form is encountered at
the top level or module level, bindings are introduced as for
@scheme[define-values], but at phase level 1.}
@item{When a @scheme[define-for-syntax] or
@scheme[define-values-for-syntax] form is encountered at the
top level or module level, bindings are introduced as for
@scheme[define-values], but at @tech{phase level} 1 (i.e., the
@tech{transformer environment} is extended).}
@item{When a @scheme[let-values] form is encountered, the body of the
@scheme[let-values] form is extended (by creating new
@ -391,7 +404,7 @@ core syntactic forms are encountered:
identifiers. The same bindings are added to the identifiers
themselves, so that the identifiers in binding position are
@scheme[bound-identifier=?] to uses in the fully expanded form,
and so they are not @scheme[bound-identifier=?] t other
and so they are not @scheme[bound-identifier=?] to other
identifiers. The bindings are available for use at the
@tech{phase level} at which the @scheme[let-values] form is
expanded.}
@ -432,19 +445,21 @@ expander encounters a @scheme[define-syntaxes] form, the binding that
it introduces for the defined identifiers is a @deftech{transformer
binding}. The @tech{value} of the @tech{binding} exists at expansion
time, rather than run time (though the two times can overlap), though
the binding itself is introduced with phase level 0.
the binding itself is introduced with @tech{phase level} 0 (i.e., in
the @tech{base environment}).
The @deftech{value} for the binding is obtained by evaluating the
expression in the @scheme[define-syntaxes] form. This expression must
be @tech{expand}ed (i.e. parsed) before it can be evaluated, and it is
expanded at @tech{phase level} 1 instead of @tech{phase level} 0.
expanded at @tech{phase level} 1 (i.e., in the @tech{transformer
environment}) instead of @tech{phase level} 0.
The if resulting @scheme[value] is a procedure of one argument, then
is it used as a @deftech{syntax transformer}. The procedure is
expected to accept a syntax object and return a syntax object. A use
of the binding (at @tech{phase level} 0) triggers a call of the
@tech{syntax transformer} by the expander; see
@secref["mz:expand-steps"].
The if resulting @scheme[value] is a procedure of one argument or as
the result of @scheme[make-set!-transformer] on a procedure, then is
it used as a @deftech{syntax transformer}. The procedure is expected
to accept a syntax object and return a syntax object. A use of the
binding (at @tech{phase level} 0) triggers a call of the @tech{syntax
transformer} by the expander; see @secref["mz:expand-steps"].
Before the expander passes a @tech{syntax object} to a transformer,
the @tech{syntax object} is extend with a @deftech{syntax mark} (that
@ -493,16 +508,26 @@ that transformer @scheme[set!] expression. @tech{Assignment
transformers} are applied by @scheme[set!] in the same way as a normal
transformer by the macro expander.
The @scheme[make-rename-transformer] procedure creates a value that is
also handled specially by the expander and by @scheme[set!] as a
transformer binding's value. When @scheme[_id] is bound to a
@deftech{rename transformer} produced by
@scheme[make-rename-transformer], it is replaced with the identifier
passed to @scheme[make-rename-transformer]. Furthermore, the binding
is also specially handled by @scheme[syntax-local-value] as used by
@tech{syntax transformer}s.
The expander's handling of @scheme[letrec-values+syntaxes] is similar
to its handling of @scheme[define-syntaxes]. A
@scheme[letrec-values+syntaxes] mist be expanded in an arbitrary phase
level @math{n} (not just 0), in which case the expression for the
@tech{transformer binding} is expanded at phase level @math{n+1}.
@tech{transformer binding} is expanded at @tech{phase level} @math{n+1}.
The expression in a @scheme[define-values-for-syntax] form is expanded
and evaluated in the same way as for @scheme[syntax]. However, the
introduced binding is a normal binding at phase level 1 (not a
@tech{transformer binding} at phase level 0).
The expression in a @scheme[define-for-syntax] or
@scheme[define-values-for-syntax] form is expanded and evaluated in
the same way as for @scheme[syntax]. However, the introduced binding
is a variable binding at @tech{phase level} 1 (not a @tech{transformer
binding} at @tech{phase level} 0).
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "mz:partial-expansion"]{Partial Expansion}
@ -587,7 +612,8 @@ the required module to be merely visited at @tech{phase} 0, not
When the expander encounters @scheme[require-for-syntax], it
immediately instantiates the required module at @tech{phase} 1, in
addition to adding bindings scheme @tech{phase level} 1.
addition to adding bindings scheme @tech{phase level} 1 (i.e., the
@tech{transformer enviornment}).
When the expander encounters @scheme[require] and
@scheme[require-for-syntax] within a @tech{module context}, the
@ -626,8 +652,8 @@ namespace is also the starting point evaluating expanded code, where
the first step in evaluation is linking the code to specific module
instances and top-level variables.
For expansion purposes, a namespace maps each symbol in each phase
level to one of three possible bindings:
For expansion purposes, a namespace maps each symbol in each
@tech{phase level} to one of three possible bindings:
@itemize{
@ -648,18 +674,21 @@ variable (in addition to installing a value into the variable).
A namespace also has a @deftech{module registry} that maps module
names to module declarations (see @secref["mz:module-eval-model"]).
This registry is shared by all phase levels, though instances of
declared modules are not.
This registry is shared by all @tech{phase level}s.
For evaluation, each namespace encapsulates a distinct set of
top-level variables, as well as a potentially distinct set of module
instances in each phase. After a namespace is created, module
instances from existing namespaces can be attached to the new
namespace. In terms of the evaluation model, top-level variables from
different namespaces essentially correspond to definitions with
different prefixes. Furthermore, the first step in evaluating any
compiled expression is to link its top-level variable and module-level
variable references to specific variables in the namespace.
instances in each @tech{phase}. That is, even though module
declarations are shared for all @tech{phase levels}, module instances
are distinct for each @tech{phase}.
After a namespace is created, module instances from existing
namespaces can be attached to the new namespace. In terms of the
evaluation model, top-level variables from different namespaces
essentially correspond to definitions with different prefixes.
Furthermore, the first step in evaluating any compiled expression is
to link its top-level variable and module-level variable references to
specific variables in the namespace.
At all times during evaluation, some namespace is designated as the
@deftech{current namespace}. The current namespace has no particular

View File

@ -356,7 +356,7 @@ Like @scheme[lambda], but without support for keyword or optional arguments.
}
@;------------------------------------------------------------------------
@section[#:tag "mz:let"]{Local Binding: @scheme[let], @scheme[let*], and @scheme[letrec]}
@section[#:tag "mz:let"]{Local Binding: @scheme[let], @scheme[let*], @scheme[letrec], ...}
@guideintro["guide:let"]{local binding}
@ -590,7 +590,7 @@ position with respect to the original @scheme[or] form.
]}
@;------------------------------------------------------------------------
@section[#:tag "mz:define"]{Definitions: @scheme[define] and @scheme[define-values]}
@section[#:tag "mz:define"]{Definitions: @scheme[define], @scheme[define-syntax], ...}
@guideintro["guide:define"]{definitions}
@ -660,8 +660,45 @@ z
]
}
@defform*[[(define-syntax id expr)
(define-syntax (head args) body ...+)]]{
The first form creates a @tech{transformer binding} (see
@secref["mz:transformer-model"]) of @scheme[id] with the value of
@scheme[expr], which is an expression at @tech{phase level} 1 relative
to the surrounding context. (See @secref["mz:id-model"] for
information on @tech{phase levels}.)
The second form is a shorthand the same as for @scheme[define]; it
expands to a definition of the first form where the @scheme[expr] is a
@scheme[lambda] form.}
@defform[(define-syntaxes (id ...) expr)]{
Like @scheme[define-syntax], but creates a @tech{transformer binding}
for each @scheme[id]. The @scheme[expr] should produce as many values
as @scheme[id]s, and each value is bound to the corresponding
@scheme[id].}
@defform*[[(define-for-syntax id expr)
(define-for-syntax (head args) body ...+)]]{
Like @scheme[define], except that the binding is at @tech{phase level}
1 instead of @tech{phase level} 0 relative to its context. The
expression for the binding is also at @tech{phase level} 1. (See
@secref["mz:id-model"] for information on @tech{phase levels}.)}
@defform[(define-values-for-syntax (id ...) expr)]{
Like @scheme[define-for-syntax], but @scheme[expr] must produce as
many value as supplied @scheme[id]s, and all of the @scheme[id]s are
bound (at @tech{phase level} 1).}
@;------------------------------------------------------------------------
@section[#:tag "mz:begin"]{Sequencing: @scheme[begin] and @scheme[begin0]}
@section[#:tag "mz:begin"]{Sequencing: @scheme[begin], @scheme[begin0], and @scheme[begin-for-syntax]}
@guideintro["guide:begin"]{@scheme[begin] and @scheme[begin0]}
@ -706,6 +743,34 @@ in tail position only if no @scheme[body]s are present.
(printf "hi\n"))
]}
@defform[(begin-for-syntax form ...)]{
Allowed only in a @tech{top-level context} or @tech{module context}.
Each @scheme[form] is partially expanded (see
@secref["mz:partial-expansion"]) to determine one of the following
classifications:
@itemize{
@item{@scheme[define] or @scheme[define-values] form: converted to
a @scheme[define-for-syntax] form.}
@item{@scheme[require] form: converted to a
@scheme[require-for-syntax] form.}
@item{@scheme[require-for-template] form: converted to a
@scheme[require].}
@item{expression form @scheme[_expr]: converted to
@scheme[(define-values () (begin _expr (values)))], which
effectively evaluates the expression at expansion time and, in
the case of a @tech{module context}, preserves the expression
for future @tech{visit}s of the module.}
}
}
@;------------------------------------------------------------------------
@section[#:tag "mz:when+unless"]{Guarded Evaluation: @scheme[when] and @scheme[unless]}
@ -745,10 +810,14 @@ Equivalent to @scheme[(when (not test-expr) expr ...)].
@defform[(set! id expr)]{
If @scheme[id] is bound as syntax to an @tech{assignment transformer},
as produced by @scheme[make-set!-transformer], then this form is
expanded by calling the assignment transformer with the full
expressions.
If @scheme[id] has a @tech{transformer bounding} to an
@tech{assignment transformer}, as produced by
@scheme[make-set!-transformer], then this form is expanded by calling
the assignment transformer with the full expressions. If @scheme[id]
has a @tech{transformer bounding} to a @tech{rename transformer} as
produced by @scheme[make-rename-transformer], then this form is
expanded by replacing @scheme[id] with the one provided to
@scheme[make-rename-transformer].
Otherwise, evaluates @scheme[expr] and installs the result into the
location for @scheme[id], which must be bound as a local variable or
@ -830,7 +899,7 @@ information} and source-location information attached to
}
@;------------------------------------------------------------------------
@section[#:tag "mz:module"]{Modules: @scheme[module]}
@section[#:tag "mz:module"]{Modules: @scheme[module], ...}
@defform[(module id require-spec form ...)]{
@ -843,16 +912,16 @@ is treated like a @scheme[(require require-spec)] prefix on
If a single @scheme[form] is provided, then it is partially expanded
in a @tech{module-begin context}. If the expansion leads to
@scheme[#%plain-module-begin], then the body of the
@scheme[#%plain-module-begin] is the body of the module. If partial
expansion leads to any other primitive form, then the form is wrapped
with @schemeidfont{#%module-begin} using the lexical context of the
module body; this identifier must be bound by the initial
@scheme[#%module-begin], then the body of the @scheme[#%module-begin]
is the body of the module. If partial expansion leads to any other
primitive form, then the form is wrapped with
@schemeidfont{#%module-begin} using the lexical context of the module
body; this identifier must be bound by the initial
@scheme[require-spec] import, and its expansion must produce a
@scheme[#%plain-module-begin] to supply the module body. Finally, if
@scheme[#%module-begin] to supply the module body. Finally, if
multiple @scheme[form]s are provided, they are wrapped with
@schemeidfont{#%module-begin}, as in the case where a single
@scheme[form] does not expand to @scheme[#%plain-module-begin].
@scheme[form] does not expand to @scheme[#%module-begin].
Each @scheme[form] is partially expanded (see
@secref["mz:partial-expansion"]) in a @tech{module context}. Further
@ -919,6 +988,11 @@ error, just like accessing an undefined global variable.
See also @secref["mz:module-eval-model"] and @secref["mz:mod-parse"].}
@defform[(#%module-begin form ...)]{
Legal only in a @tech{module begin context}, and handled by the
@scheme[module] form.}
@;------------------------------------------------------------------------
@section[#:tag "mz:require"]{Importing: @scheme[require], @scheme[require-for-syntax], @scheme[require-for-template]}