11.4 Syntax Transformers
The property value must be an exact integer or procedure of one or two
arguments. In the former case, the integer designates a field within
the structure that should contain a procedure; the integer must be
between 0 (inclusive) and the number of non-automatic fields
in the structure type (exclusive, not counting supertype fields), and
the designated field must also be specified as immutable.
If the property value is a procedure of one argument, then the
procedure serves as a syntax transformer and for set!
transformations. If the property value is a procedure of two
arguments, then the first argument is the structure whose type has
prop:set!-transformer property, and the second argument is a
syntax object as for a syntax transformer and for set!
transformations; set!-transformer-procedure applied to the
structure produces a new function that accepts just the syntax object
and calls the procedure associated through the property. Finally, if the
property value is an integer, the target identifier is extracted from
the structure instance; if the field value is not a procedure of one
argument, then a procedure that always calls
raise-syntax-error is used, instead.
If a value has both the prop:set!-transformer and
prop:rename-transformer properties, then the latter takes
precedence. If a structure type has the prop:set!-transformer
and prop:procedure properties, then the former takes
precedence for the purposes of macro expansion.
Creates a
rename transformer that, when used as a
transformer binding, acts as a transformer that inserts the
identifier
id-stx in place of whatever identifier binds the
transformer, including in non-application positions, in
set!
expressions.
Such a transformer could be written manually, but the one created by
make-rename-transformer triggers special cooperation with the
parser and other syntactic forms when id is bound to the
rename transformer:
The property value must be an exact integer or an identifier
syntax object. In the former case, the integer designates a
field within the structure that should contain an identifier; the
integer must be between 0 (inclusive) and the number of
non-automatic fields in the structure type (exclusive, not counting
supertype fields), and the designated field must also be specified as
immutable.
If the property value is an identifier, the identifier serves as the
target for renaming, just like the first argument to
make-rename-transformer. If the property value is an integer,
the target identifier is extracted from the structure instance; if the
field value is not an identifier, then an identifier ?
with an empty context is used, instead.
Expands
stx in the lexical context of the expression
currently being expanded. The
context-v argument is used as
the result of
syntax-local-context for immediate expansions;
a list indicates an
internal-definition context, and more
information on the form of the list is below.
When an identifier in stop-ids is encountered by the expander
in a sub-expression, expansions stops for the sub-expression. If
stop-ids is a non-empty list, then
begin, quote, set!, lambda,
case-lambda, let-values, letrec-values,
if, begin0, with-continuation-mark,
letrec-syntaxes+values, #%app,
#%expression, #%top, and
#%variable-reference are added to stop-ids. If
#%app, #%top, or #%datum appears in
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 stop-ids is #f
instead of a list, then stx is expanded only as long as the
outermost form of stx is a macro (i.e., expansion does not
proceed to sub-expressions). A fully expanded form can include the
bindings listed in Fully Expanded Programs plus the
letrec-syntaxes+values form and #%expression
in any expression position.
The optional intdef-ctx argument must be either #f,
the result of syntax-local-make-definition-context, or a list
of such results. In the latter two cases, lexical information for
internal definitions is added to stx before it is expanded
(in reverse order relative to the list). The lexical information is
also added to the expansion result (because the expansion might
introduce bindings or references to internal-definition bindings).
For a particular internal-definition context, generate a unique
value and put it into a list for context-v. To allow
liberal expansion of define forms, the generated value
should be an instance of a structure with a true value for
prop:liberal-define-context. If the internal-definition
context is meant to be self-contained, the list for context-v
should contain only the generated value; if the internal-definition
context is meant to splice into an immediately enclosing context, then
when syntax-local-context produces a list, cons the
generated value onto that list.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Examples: |
| | | | | | > (show 1) | partly expanded: (do-print "hello ~a" 1) | fully expanded: (printf "hello ~a" 1) | hello 1 |
| |
|
Like
local-expand given
'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 encounters the opaque object, it substitutes the fully
expanded expression without re-expanding it; the
exn:fail:syntax exception is raised 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
syntax-local-expand-expression and the opaque object thus
avoids quadratic expansion times when local expansions are nested.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Like
local-expand, but the result is a syntax object that
represents a
begin expression. Lifted expressions—
from
calls to
syntax-local-lift-expression during the expansion of
stx—
appear with their identifiers in
define-values
forms, and the expansion of
stx is the last expression in the
begin. The
lift-ctx value is reported by
syntax-local-lift-context during local expansion. The lifted
expressions are not expanded, but instead left as provided in the
begin form.
Like
local-expand/capture-lifts, but
stx is expanded
as a transformer expression instead of a run-time expression. Lifted
expressions are reported as
define-values forms (in the
transformer environment).
If intdef-ctx is not #f, then the new
internal-definition context extends the given one. That is, expanding
in the new internal-definition context can use bindings previously
introduced into intdef-ctx.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Removes
intdef-ctx (or each identifier in the list) from the
lexical information of
id-stx. This operation is
useful for correlating an identifier that is bound in an
internal-definition context with its binding before the
internal-definition context was created.
If simply removing the contexts produces a different binding than
completely ignoring the contexts (due to nested internal definition
contexts, for example), then the resulting identifier is given a
syntax mark to simulate a non-existent lexical context. The
intdef-ctx argument can be a list because removing
internal-definition contexts one at a time can produce a different
intermediate binding than removing them all at once.
Returns the
transformer binding value of
id-stx in
either the context associated with
intdef-ctx (if not
#f) or the context of the expression being expanded (if
intdef-ctx is
#f). If
intdef-ctx is
provided, it must be an extension of the context of the expression
being expanded.
If id-stx is bound to a rename transformer created
with make-rename-transformer, syntax-local-value
effectively calls itself with the target of the rename and returns
that result, instead of the rename transformer.
If id-stx has no transformer binding (via
define-syntax, let-syntax, etc.) in that
environment, the result is obtained by applying failure-thunk
if not #f. If failure-thunk is false, the
exn:fail:contract exception is raised.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
If id-stx has no transformer binding, then
failure-thunk is called (and it can return any number of
values), or an exception is raised if failure-thunk is
#f.
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
letrec-syntaxes+values or define-syntaxes binding is
lifted to a let wrapper around the corresponding right-hand
side of the binding. A compile-time expression within
begin-for-syntax is lifted to a define
declaration just before the requesting expression within the
begin-for-syntax.
Other syntactic forms can capture lifts by using
local-expand/capture-lifts or
local-transformer-expand/capture-lifts.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Returns a value that represents the target for expressions lifted via
syntax-local-lift-expression. That is, for different
transformer calls for which this procedure returns the same value (as
determined by
eq?), lifted expressions for the two
transformer are moved to the same place. Thus, the result is useful
for caching lift information to avoid redundant lifts.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Cooperates with the
module form to insert
stx as
a top-level declaration at the end of the module currently being
expanded. If the current expression being
transformed is in
phase level 0 and not in the module top-level, then
stx is
eventually expanded in an expression context. If the current expression being
transformed is in a higher
phase level (i.e., nested within some
number of
begin-for-syntaxes within a module top-level), then the lifted declaration
is placed at the very end of the module (under a suitable number of
begin-for-syntaxes), instead of merely the end of the
enclosing
begin-for-syntax.
Lifts a
#%require form corresponding to
raw-require-spec (either as a
syntax object or datum)
to the top-level or to the top of the module currently being expanded
or to an enclosing
begin-for-syntax..
The resulting syntax object is the same as stx, except that a
fresh syntax mark is added. The same syntax mark is
added to the lifted #%require form, so that the
#%require form can bind uses of imported identifiers in the
resulting syntax object (assuming that the lexical information of
stx includes the binding environment into which the
#%require is lifted).
If raw-require-spec and stx are part of the input to
a transformer, then typically syntax-local-introduce should be
applied to each before passing them to
syntax-local-lift-require, and then
syntax-local-introduce should be applied to the result of
syntax-local-lift-require. Otherwise, marks added
by the macro expander can prevent access to the new imports.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Lifts a
#%provide form corresponding to
raw-provide-spec-stx to the top of the module currently being
expanded or to an enclosing
begin-for-syntax.
Returns an inferred name for the expression position being
transformed, or
#f if no such name is available. A name is
normally a symbol or an identifier. See also
Inferred Value Names.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
The symbol results indicate that the expression is being expanded for
an expression context, a top-level context, a
module context, or a module-begin context.
A list result indicates expansion in an internal-definition
context. The identity of the list’s first element (i.e., its
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.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
During the dynamic extent of a
syntax transformer application
by the expander, the result is the
phase level of the form
being expanded. Otherwise, the result is
0.
Returns three lists of symbols that represent the
provided
bindings of the module named by
mod-path. The first list
corresponds to the
phase level 0 exports of the module, the
second list corresponds to the
phase level -1 exports of the
module, and the last list corresponds to the
label phase level
exports of the module.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Returns
id-stx if no binding in the current expansion context
shadows
id-stx (ignoring unsealed
internal-definition
contexts and identifiers that had the
'unshadowable
syntax property), if
id-stx has no module bindings in
its lexical information, and if the current expansion context is not a
module context.
If a binding of inner-identifier shadows id-stx, the
result is the same as (syntax-local-get-shadower inner-identifier), except that it has the location and properties of
id-stx. When searching for a shadowing binding, bindings from
unsealed internal-definition contexts are ignored.
Otherwise, the result is the same as id-stx with its module
bindings (if any) removed from its lexical information, and the
lexical information of the current module context (if any)
added.
Thus, the result is an identifier corresponding to the innermost
shadowing of id-stx in the current context if it is shadowed,
and a module-contextless version of id-stx otherwise.
If id-stx is tainted or armed, then the
resulting identifier is tainted.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
For backward compatibility only; returns a procedure that returns its
first argument.
Returns
#t during the dynamic extent of a
syntax
transformer application by the expander and while a module is being
visited,
#f otherwise.
Returns
#t during the dynamic extent of a
syntax
transformer application by the expander for an expression
within a
module form,
#f otherwise.
Produces a syntax object that is like
stx, except that a
syntax mark for the current expansion is added (possibly
canceling an existing mark in parts of
stx). See
Transformer Bindings for information on
syntax
marks.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
Produces a procedure that behaves like
syntax-local-introduce, but using the
syntax marks of
ext-stx that are not shared with
base-stx. If
ext-stx does not extend the set of marks in
base-stx
or if
base-stx is
#f, and if
ext-stx has a
module binding in the
phase level indicated by
phase-level, then any marks of
ext-stx that would be
needed to preserve its binding are not transferred in an introduction.
This procedure is potentially useful when m-id has a
transformer binding that records some orig-id, and a use of
m-id introduces a binding of orig-id. In that
case, the syntax marks in the use of m-id since the
binding of m-id should be transferred to the binding
instance of orig-id, so that it captures uses with the same
lexical context as the use of m-id.
More typically, however, syntax-local-make-delta-introducer
should be used, since it cooperates with rename transformers.
If ext-stx is tainted or armed, then an
identifier result from the created procedure is tainted.
The exn:fail:contract exception is raised if id or any identifier in
its rename-transformer chain has no binding.
This procedure must be called during the
dynamic extent of a syntax transformer application by the
expander or while a module is visited (see
syntax-transforming?), otherwise the
exn:fail:contract exception is raised.
It returns a hash table mapping a phase-level number (such as
0) to a list of all definitions at that phase level
within the module being expanded. This information is used for
implementing provide sub-forms like all-defined-out.
Beware that the phase-level keys are absolute relative to the
enclosing module, and not relative to the current transformer phase
level as reported by syntax-local-phase-level.
It returns an association list mapping phase levels to lists of
identifiers. Each list of identifiers includes all bindings imported
(into the module being expanded) using the module path
mod-path, or all modules if mod-path is
#f. The association list includes all identifiers imported
with a phase-level shift, of all shifts if
phase-level is #t.
When an identifier is renamed on import, the result association list
includes the identifier by its internal name. Use
identifier-binding to obtain more information about the
identifier.
Beware that the phase-level keys are absolute relative to the
enclosing module, and not relative to the current transformer phase
level as reported by syntax-local-phase-level.
The liberal-define-context? predicate returns #t if
v is an instance of a structure with a true value for the
prop:liberal-define-context property, #f otherwise.
11.4.1 require Transformers
A transformer binding whose value is a structure with the
prop:require-transformer property implements a derived
require-spec for require as a require
transformer.
A require transformer is called with the syntax object representing its use
as a require-spec within a require form, and the
result must be two lists: a list of imports and a list of
import-sources.
If the derived form contains a sub-form that is a
require-spec, then it can call expand-import to
transform the sub-require-spec to lists of imports and
import sources.
See also define-require-syntax, which supports macro-style
require transformers.
Expands the given
require-spec to lists of imports and
import sources. The latter specifies modules to be
instantiated or
visited, so the modules that it
represents should be a superset of the modules represented in the
former list (so that a module will be
instantiated or
visited even if all of imports are eventually filtered from the
former list).
A property to identify
require transformers. The property
value must be a procedure that takes a syntax object and returns
import and import-source lists.
A structure representing a single imported identifier:
local-id — the identifier to be bound within the
importing module.
src-sym — the external name of the binding as
exported from its source module.
src-mod-path — a module path (relative to the
importing module) for the source of the imported binding.
orig-stx — a syntax object for the source of
the import, used for error reporting.
mode — the phase level of the binding in the
importing module.
req-mode — the phase level shift of the
import relative to the exporting module.
orig-mode — the phase level of the
binding as exported by the exporting module.
A structure representing an imported module, which must be
instantiated or
visited even if no binding is imported
into a module.
For backward compatibility only; returns a procedure that returns its
first argument.
11.4.2 provide Transformers
A transformer binding whose value is a structure with the
prop:provide-transformer property implements a derived
provide-spec for provide as a provide transformer.
A provide transformer is applied as part of the last phase of
a module’s expansion, after all other declarations and expressions within
the module are expanded.
A transformer binding whose value is a structure with the
prop:provide-pre-transformer property implements a derived
provide-spec for provide as a provide
pre-transformer. A provide pre-transformer is applied as part
of the first phase of a module’s expansion. Since it is used in the
first phase, a provide pre-transformer can use functions such
as syntax-local-lift-expression to introduce expressions and
definitions in the enclosing module.
An identifier can have a transformer binding to a value that
acts both as a provide transformer and provide
pre-transformer. The result of a provide
pre-transformer is not automatically re-expanded, so a
provide pre-transformer can usefully expand to itself in that case.
A transformer is called with the syntax object representing its use as
a provide-spec within a provide form and a list of
symbols representing the export modes specified by enclosing
provide-specs. The result of a provide transformer
must be a list of exports, while the result of a
provide pre-transformer is a syntax object to be used as a
provide-spec in the last phase of module expansion.
If a derived form contains a sub-form that is a
provide-spec, then it can call expand-export or
pre-expand-export to transform the sub-provide-spec
sub-form.
See also define-provide-syntax, which supports macro-style
provide transformers.
Expands the given
provide-spec to a list of exports. The
modes list controls the expansion of
sub-
provide-specs; for example, an identifier refers to a
binding in the
phase level of the enclosing
provide
form, unless the
modes list specifies otherwise. Normally,
modes is either empty or contains a single element.
A property to identify
provide transformers. The property
value must be a procedure that takes a syntax object and mode list and
returns an export list.
A property to identify
provide pre-transformers. The property
value must be a procedure that takes a syntax object and mode list and
returns a syntax object.
A structure representing a single imported identifier:
local-id — the identifier that is bound within the
exporting module.
out-sym — the external name of the binding.
orig-stx — a syntax object for the source of
the export, used for error reporting.
protect? — indicates whether the identifier should
be protected (see Code Inspectors).
mode — the phase level of the binding in the
exporting module.
For backward compatibility only; returns a procedure that returns its
first argument.