100 lines
4.8 KiB
Racket
100 lines
4.8 KiB
Racket
#lang scribble/doc
|
|
@(require "common.ss"
|
|
(for-label syntax/template))
|
|
|
|
@title[#:tag "template"]{Controlling Syntax Templates}
|
|
|
|
@defmodule[syntax/template]
|
|
|
|
@defproc[(transform-template [template-stx syntax?]
|
|
[#:save save-proc (syntax? . -> . any/c)]
|
|
[#:restore-stx restore-proc-stx syntax?]
|
|
[#:leaf-save leaf-save-proc (syntax? . -> . any/c) save-proc]
|
|
[#:leaf-restore-stx leaf-restore-proc-stx syntax? #'(lambda (data stx) stx)]
|
|
[#:leaf-datum-stx leaf-datum-proc-stx syntax? #'(lambda (v) v)]
|
|
[#:pvar-save pvar-save-proc (identifier? . -> . any/c) (lambda (x) #f)]
|
|
[#:pvar-restore-stx pvar-restore-stx syntax? #'(lambda (d stx) stx)]
|
|
[#:cons-stx cons-proc-stx syntax? cons]
|
|
[#:ellipses-end-stx ellipses-end-stx syntax? #'values]
|
|
[#:constant-as-leaf? constant-as-leaf? boolean? #f])
|
|
syntax?]{
|
|
|
|
Produces an representation of an expression similar to
|
|
@SCHEME[#`((UNSYNTAX @scheme[syntax]) #,template-stx)], but functions like
|
|
@scheme[save-proc] can collect information that might otherwise be
|
|
lost by @scheme[syntax] (such as properties when the syntax object is
|
|
marshaled within bytecode), and run-time functions like the one
|
|
specified by @scheme[restore-proc-stx] can use the saved information or
|
|
otherwise process the syntax object that is generated by the template.
|
|
|
|
The @scheme[save-proc] is applied to each syntax object in the
|
|
representation of the original template (i.e., in
|
|
@scheme[template-stx]). If @scheme[constant-as-leaf?] is @scheme[#t],
|
|
then @scheme[save-proc] is applied only to syntax objects that contain
|
|
at least one pattern variable in a sub-form. The result of
|
|
@scheme[save-proc] is provided back as the first argument to
|
|
@scheme[restore-proc-stx], which indicates a function with a contract
|
|
@scheme[(any/c syntax any/c . -> . any/c)]; the second argument to
|
|
@scheme[restore-proc-stx] is the syntax object that @scheme[syntax]
|
|
generates, and the last argument is a datum that have been processed
|
|
recursively (by functions such as @scheme[restore-proc-stx]) and that
|
|
normally would be converted back to a syntax object using the second
|
|
argument's context, source, and properties. Note that
|
|
@scheme[save-proc] works at expansion time (with respect to the
|
|
template form), while @scheme[restore-proc-stx] indicates a function
|
|
that is called at run time (for the template form), and the data that
|
|
flows from @scheme[save-proc] to @scheme[restore-proc-stx] crosses
|
|
phases via @scheme[quote].
|
|
|
|
The @scheme[leaf-save-proc] and @scheme[leaf-restore-proc-stx] procedures
|
|
are analogous to @scheme[save-proc] and
|
|
@scheme[restore-proc-stx], but they are applied to leaves, so
|
|
there is no third argument for recursively processed sub-forms. The
|
|
function indicated by @scheme[leaf-restore-proc-stx] should have the
|
|
contract @scheme[(any/c syntax? . -> . any/c)].
|
|
|
|
The @scheme[leaf-datum-proc-stx] procedure is applied to leaves that
|
|
are not syntax objects, which can happen because pairs and the empty
|
|
list are not always individually wrapped as syntax objects. The
|
|
function should have the contract @scheme[(any/c . -> . any/c)]. When
|
|
@scheme[constant-as-leaf?] is @scheme[#f], the only possible argument
|
|
to the procedure is @scheme[null].
|
|
|
|
The @scheme[pvar-save] and @scheme[pvar-restore-stx] procedures are
|
|
analogous to @scheme[save-proc] and @scheme[restore-proc-stx],
|
|
but they are applied to pattern variables. The
|
|
@scheme[pvar-restore-stx] procedure should have the contract
|
|
@scheme[(any/c syntax? . -> . any/c)], where the second argument
|
|
corresponds to the substitution of the pattern variable.
|
|
|
|
The @scheme[cons-proc-stx] procedure is used to build intermediate
|
|
pairs, including pairs passed to @scheme[restore-proc-stx] and pairs
|
|
that do not correspond to syntax objects.
|
|
|
|
The @scheme[ellipses-end-stx] procedure is an extra filter on the
|
|
syntax object that follows a sequence of @scheme[...] ellipses in the
|
|
template. The procedure should have the contract @scheme[(any/c . ->
|
|
. any/c)].
|
|
|
|
The following example illustrates a use of @scheme[transform-template]
|
|
to implement a @scheme[syntax/shape] form that preserves the
|
|
@scheme['paren-shape] property from the original template, even if the
|
|
template code is marshaled within bytecode.
|
|
|
|
@schemeblock[
|
|
(define-for-syntax (get-shape-prop stx)
|
|
(syntax-property stx 'paren-shape))
|
|
|
|
(define (add-shape-prop v stx datum)
|
|
(syntax-property (datum->syntax stx datum stx stx stx)
|
|
'paren-shape
|
|
v))
|
|
|
|
(define-syntax (syntax/shape stx)
|
|
(syntax-case stx ()
|
|
[(_ tmpl)
|
|
(transform-template #'tmpl
|
|
#:save get-shape-prop
|
|
#:restore-stx #'add-shape-prop)]))
|
|
]}
|