11.4 Syntax Transformers
(set!-transformer? v) → boolean? |
v : any/c |
(make-set!-transformer proc) → set!-transformer? |
proc : (syntax? . -> . syntax?) |
Example: | ||||||||||||||
|
(set!-transformer-procedure transformer) |
→ (syntax? . -> . syntax?) |
transformer : set!-transformer? |
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.
(rename-transformer? v) → boolean? |
v : any/c |
| ||||||||||||||
id-stx : syntax? | ||||||||||||||
|
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 parser to installs a free-identifier=? and identifier-binding equivalence between id and id-stx, as long as id-stx does not have a true value for the 'not-free-identifier=? syntax property.
A provide of id provides the binding indicated by id-stx instead of id, as long as id-stx does not have a true value for the 'not-free-identifier=? syntax property and as long as id-stx has a binding.
If provide exports id, it uses a symbol-valued 'nominal-id property of id-stx to specify the “nominal source identifier” of the binding as reported by identifier-binding.
If id-stx has a true value for the 'not-provide-all-defined syntax property, then id (or its target) is not exported by all-defined-out.
The syntax-local-value and syntax-local-make-delta-introducer functions recognize rename-transformer bindings and consult their targets.
(rename-transformer-target transformer) → identifier? |
transformer : 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.
| ||||||||||||||||||||||||||||
stx : syntax? | ||||||||||||||||||||||||||||
context-v : (or/c 'expression 'top-level 'module 'module-begin list?) | ||||||||||||||||||||||||||||
stop-ids : (or/c (listof identifier?) #f) | ||||||||||||||||||||||||||||
|
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.
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).
Expansion of stx can use certificates for the expression already being expanded (see Syntax Certificates), and inactive certificates associated with stx are activated for stx (see Syntax Certificates). 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 transformer binding) or if the current expression is being expanded for the body of a module, then the expansion of stx can use any identifier defined by the module.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
Examples: | ||||||||||||||||||||||||||
|
| ||||||||
stx : syntax? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
| ||||||||||||||||||||||||||||
stx : syntax? | ||||||||||||||||||||||||||||
context-v : (or/c 'expression 'top-level 'module 'module-begin list?) | ||||||||||||||||||||||||||||
stop-ids : (or/c (listof identifier?) #f) | ||||||||||||||||||||||||||||
intdef-ctx : (or/c internal-definition-context? #f) = #f |
| |||||||||||||||||||||||||||||||||||
stx : syntax? | |||||||||||||||||||||||||||||||||||
context-v : (or/c 'expression 'top-level 'module 'module-begin list?) | |||||||||||||||||||||||||||||||||||
stop-ids : (or/c (listof identifier?) #f) | |||||||||||||||||||||||||||||||||||
intdef-ctx : (or/c internal-definition-context? #f) = #f | |||||||||||||||||||||||||||||||||||
lift-ctx : any/c = (gensym 'lifts) |
| ||||||||||||||||||||||||||||
stx : syntax? | ||||||||||||||||||||||||||||
context-v : (or/c 'expression 'top-level 'module 'module-begin list?) | ||||||||||||||||||||||||||||
stop-ids : (or/c (listof identifier?) #f) | ||||||||||||||||||||||||||||
intdef-ctx : (or/c internal-definition-context? #f) = #f |
(internal-definition-context? v) → boolean? |
v : any/c |
(syntax-local-make-definition-context [intdef-ctx]) |
→ internal-definition-context? |
intdef-ctx : (or/c internal-definition-context? #f) = #f |
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, otherwise the exn:fail:contract exception is raised.
| |||||||||||||||||||||
id-list : (listof identifier?) | |||||||||||||||||||||
expr : (or/c syntax? #f) | |||||||||||||||||||||
intdef-ctx : internal-definition-context? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(internal-definition-context-seal intdef-ctx) → void? |
intdef-ctx : internal-definition-context? |
| ||||||||
→ identifier? | ||||||||
id-stx : identifier? | ||||||||
|
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.
| |||||||||||||||||||||
id-stx : syntax? | |||||||||||||||||||||
failure-thunk : (or/c (-> any) #f) = #f | |||||||||||||||||||||
|
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.
Resolving id-stx can use certificates for the expression being transformed (see Syntax Certificates) as well as inactive certificates associated with id-stx (see Syntax Certificates). 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 id-stx can access any identifier defined by the module.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
| |||||||||||||||||||||
id-stx : syntax? | |||||||||||||||||||||
failure-thunk : (or/c (-> any) #f) = #f | |||||||||||||||||||||
|
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.
(syntax-local-lift-expression stx) → identifier? |
stx : syntax? |
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-for-syntax declaration just before the requesting expression.
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, otherwise the exn:fail:contract exception is raised.
(syntax-local-lift-values-expression n stx) |
→ (listof identifier?) |
n : exact-nonnegative-integer? |
stx : syntax? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, 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, otherwise the exn:fail:contract exception is raised.
(syntax-local-lift-module-end-declaration stx) → void? |
stx : syntax? |
| ||||||||||||||
raw-require-spec : any/c | ||||||||||||||
stx : 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, otherwise the exn:fail:contract exception is raised.
(syntax-local-lift-provide raw-provide-spec-stx) → void? |
raw-provide-spec-stx : syntax? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(syntax-local-context) |
→ (or/c 'expression 'top-level 'module 'module-begin list?) |
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, otherwise the exn:fail:contract exception is raised.
(syntax-local-phase-level) → (or/c exact-integer? #f) |
| ||||||||
mod-path : module-path? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(syntax-local-get-shadower id-stx) → identifier? |
id-stx : identifier? |
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.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(syntax-local-certifier [active?]) | ||||||
| ||||||
active? : boolean? = #f |
Supply #t for 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 #f for 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.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(syntax-local-introduce stx) → syntax? |
stx : syntax? |
This procedure must be called during the dynamic extent of a syntax transformer application by the expander, otherwise the exn:fail:contract exception is raised.
(make-syntax-introducer) → (syntax? . -> . syntax?) |
| ||||||||||||
→ (syntax? . -> . syntax?) | ||||||||||||
ext-stx : syntax? | ||||||||||||
base-stx : (or/c syntax? #f) | ||||||||||||
|
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.
(syntax-local-make-delta-introducer id) |
→ (identifier? . -> . identifier?) |
id : identifier? |
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, otherwise the exn:fail:contract exception is raised.
It returns two lists of identifiers corresponding to all definitions within the module being expanded. This information is used for implementing provide sub-forms like all-defined-out.
The first result list corresponds to phase 0 (i.e., normal) definitions, and the second corresponds to phase -1 (i.e., for-syntax) definitions.
| ||||||||
| ||||||||
mod-path : (or/c module-path? #f) | ||||||||
phase-level : (or/c exact-integer? #f #t) |
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.
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.
The 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.
| ||||||||
stx : syntax? |
(make-require-transformer proc) → require-transformer? | |||||||||
|
(require-transformer? v) → boolean? |
v : any/c |
| ||||||||||||||||||||||||||||||||||||||||
local-id : identifier? | ||||||||||||||||||||||||||||||||||||||||
src-sym : symbol? | ||||||||||||||||||||||||||||||||||||||||
src-mod-path : module-path? | ||||||||||||||||||||||||||||||||||||||||
mode : (or/c exact-integer? #f) | ||||||||||||||||||||||||||||||||||||||||
req-mode : (or/c exact-integer? #f) | ||||||||||||||||||||||||||||||||||||||||
orig-mode : (or/c exact-integer? #f) | ||||||||||||||||||||||||||||||||||||||||
orig-stx : syntax? |
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.
| |||||||||
| |||||||||
mode : (or/c exact-integer? #f) |
mod-path-stx —
a module path (relative to the importing module) for the source of the imported binding. mode —
the phase level shift of the import.
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.
The 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 must be a list of exports.
If the derived form contains a sub-form that is a provide-spec, then it can call expand-export to transform the sub-provide-spec to a list of exports.
See also define-provide-syntax, which supports macro-style provide transformers.
(expand-export stx modes) → (listof export?) |
stx : syntax? |
modes : (listof (or/c exact-integer? #f)) |
(make-provide-transformer proc) → provide-transformer? | ||||||||
|
(provide-transformer? v) → boolean? |
v : any/c |
| ||||||
local-id : identifier? | ||||||
out-sym : symbol? | ||||||
mode : (or/c exact-integer? #f) | ||||||
protect? : any/c | ||||||
orig-stx : syntax? |
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.