#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)])) ]}