more reference work on syntax transformers
svn: r6890
This commit is contained in:
parent
9a21c13be1
commit
dba44c0b1e
|
@ -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"]
|
||||
|
|
414
collects/scribblings/reference/stx-trans.scrbl
Normal file
414
collects/scribblings/reference/stx-trans.scrbl
Normal 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.}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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]}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user