update docs for syntax, template
This commit is contained in:
parent
8d607b83f9
commit
72a7bbcefc
|
@ -1,5 +1,5 @@
|
||||||
#lang scribble/doc
|
#lang scribble/doc
|
||||||
@(require "mz.rkt")
|
@(require "mz.rkt" (for-label syntax/parse))
|
||||||
|
|
||||||
@(define lit-ellipsis (racket ...))
|
@(define lit-ellipsis (racket ...))
|
||||||
|
|
||||||
|
@ -270,30 +270,37 @@ the individual @racket[stx-expr].
|
||||||
(math 3 1 4 1 5 9)
|
(math 3 1 4 1 5 9)
|
||||||
]}
|
]}
|
||||||
|
|
||||||
@defform/subs[(syntax template)
|
@defform[#:literals (?? ?@) (syntax template)
|
||||||
|
#:grammar
|
||||||
([template id
|
([template id
|
||||||
(template-elem ...)
|
(head-template ...)
|
||||||
(template-elem ...+ . template)
|
(head-template ...+ . template)
|
||||||
(code:line #,(tt "#")(template-elem ...))
|
(code:line #,(tt "#")(head-template ...))
|
||||||
(code:line #,(tt "#&")template)
|
(code:line #,(tt "#&")template)
|
||||||
(code:line #,(tt "#s")(key-datum template-elem ...))
|
(code:line #,(tt "#s")(key-datum head-template ...))
|
||||||
|
(?? template template)
|
||||||
(ellipsis stat-template)
|
(ellipsis stat-template)
|
||||||
const]
|
const]
|
||||||
[template-elem (code:line template ellipsis ...)]
|
[head-template template
|
||||||
[stat-template id
|
(code:line head-template ellipsis ...+)
|
||||||
(stat-template ...)
|
(?@ . template)
|
||||||
(stat-template ... . stat-template)
|
(?? head-template head-template)
|
||||||
(code:line #,(tt "#")(stat-template ...))
|
(?? head-template)]
|
||||||
(code:line #,(tt "#&")stat-template)
|
[stat-template @#,elem{like @svar{template}, but without @|lit-ellipsis|,
|
||||||
(code:line #,(tt "#s")(key-datum stat-template ...))
|
@racket[??], and @racket[?@]}]
|
||||||
const]
|
|
||||||
[ellipsis #,lit-ellipsis])]{
|
[ellipsis #,lit-ellipsis])]{
|
||||||
|
|
||||||
Constructs a syntax object based on a @racket[template], which can
|
Constructs a syntax object based on a @racket[template], which can
|
||||||
include @tech{pattern variables} bound by @racket[syntax-case] or
|
include @tech{pattern variables} bound by @racket[syntax-case] or
|
||||||
@racket[with-syntax].
|
@racket[with-syntax].
|
||||||
|
|
||||||
Template forms produce a syntax object as follows:
|
A @svar[template] produces a single syntax object. A
|
||||||
|
@svar[head-template] produces a sequence of zero or more syntax
|
||||||
|
objects. A @svar[stat-template] is like a @svar[template], except that
|
||||||
|
@|lit-ellipsis|, @racket[??], and @racket[?@] are interpreted as
|
||||||
|
constants instead of template forms.
|
||||||
|
|
||||||
|
A @svar[template] produces a syntax object as follows:
|
||||||
|
|
||||||
@specsubform[id]{
|
@specsubform[id]{
|
||||||
|
|
||||||
|
@ -314,54 +321,21 @@ Template forms produce a syntax object as follows:
|
||||||
If @racket[id] is not bound as a pattern variable, then @racket[id]
|
If @racket[id] is not bound as a pattern variable, then @racket[id]
|
||||||
as a template produces @racket[(quote-syntax id)].}
|
as a template produces @racket[(quote-syntax id)].}
|
||||||
|
|
||||||
@specsubform[(template-elem ...)]{
|
@specsubform[(head-template ...)]{
|
||||||
|
|
||||||
Produces a syntax object whose datum is a list, and where the
|
Produces a syntax object whose datum is a list, and where the
|
||||||
elements of the list correspond to syntax objects produced by the
|
elements of the list correspond to syntax objects produced by the
|
||||||
@racket[template-elem]s.
|
@racket[head-template]s.}
|
||||||
|
|
||||||
A @racket[template-elem] is a sub-@racket[template] replicated by any
|
@specsubform[(head-template ... . template)]{
|
||||||
number of @racket[ellipsis]es:
|
|
||||||
|
|
||||||
@itemize[
|
|
||||||
|
|
||||||
@item{If the sub-@racket[template] is replicated by no
|
|
||||||
@racket[ellipsis]es, then it generates a single syntax object to
|
|
||||||
incorporate into the result syntax object.}
|
|
||||||
|
|
||||||
@item{If the sub-@racket[template] is replicated by one
|
|
||||||
@racket[ellipsis], then it generates a sequence of syntax objects
|
|
||||||
that is ``inlined'' into the resulting syntax object.
|
|
||||||
|
|
||||||
The number of generated elements depends on the values of
|
|
||||||
@tech{pattern variables} referenced within the
|
|
||||||
sub-@racket[template]. There must be at least one @tech{pattern
|
|
||||||
variable} whose value has a @tech{depth marker} less than the
|
|
||||||
number of @racket[ellipsis]es after the pattern variable within the
|
|
||||||
sub-@racket[template].
|
|
||||||
|
|
||||||
If a @tech{pattern variable} is replicated by more
|
|
||||||
@racket[ellipsis]es in a @racket[template] than the @tech{depth
|
|
||||||
marker} of its binding, then the @tech{pattern variable}'s result
|
|
||||||
is determined normally for inner @racket[ellipsis]es (up to the
|
|
||||||
binding's @tech{depth marker}), and then the result is replicated
|
|
||||||
as necessary to satisfy outer @racket[ellipsis]es.}
|
|
||||||
|
|
||||||
@item{For each @racket[ellipsis] after the first one, the preceding
|
|
||||||
element (with earlier replicating @racket[ellipsis]es) is
|
|
||||||
conceptually wrapped with parentheses for generating output, and
|
|
||||||
then the wrapping parentheses are removed in the resulting syntax
|
|
||||||
object.}]}
|
|
||||||
|
|
||||||
@specsubform[(template-elem ... . template)]{
|
|
||||||
|
|
||||||
Like the previous form, but the result is not necessarily a list;
|
Like the previous form, but the result is not necessarily a list;
|
||||||
instead, the place of the empty list in the resulting syntax object's
|
instead, the place of the empty list in the resulting syntax object's
|
||||||
datum is taken by the syntax object produced by @racket[template].}
|
datum is taken by the syntax object produced by @racket[template].}
|
||||||
|
|
||||||
@specsubform[(code:line #,(tt "#")(template-elem ...))]{
|
@specsubform[(code:line #,(tt "#")(head-template ...))]{
|
||||||
|
|
||||||
Like the @racket[(template-elem ...)] form, but producing a syntax
|
Like the @racket[(head-template ...)] form, but producing a syntax
|
||||||
object whose datum is a vector instead of a list.}
|
object whose datum is a vector instead of a list.}
|
||||||
|
|
||||||
@specsubform[(code:line #,(tt "#&")template)]{
|
@specsubform[(code:line #,(tt "#&")template)]{
|
||||||
|
@ -369,18 +343,37 @@ Template forms produce a syntax object as follows:
|
||||||
Produces a syntax object whose datum is a box holding the
|
Produces a syntax object whose datum is a box holding the
|
||||||
syntax object produced by @racket[template].}
|
syntax object produced by @racket[template].}
|
||||||
|
|
||||||
@specsubform[(code:line #,(tt "#s")(key-datum template-elem ...))]{
|
@specsubform[(code:line #,(tt "#s")(key-datum head-template ...))]{
|
||||||
|
|
||||||
Like the @racket[(template-elem ...)] form, but producing a syntax
|
Like the @racket[(head-template ...)] form, but producing a syntax
|
||||||
object whose datum is a @tech{prefab} structure instead of a list.
|
object whose datum is a @tech{prefab} structure instead of a list.
|
||||||
The @racket[key-datum] must correspond to a valid first argument of
|
The @racket[key-datum] must correspond to a valid first argument of
|
||||||
@racket[make-prefab-struct].}
|
@racket[make-prefab-struct].}
|
||||||
|
|
||||||
|
@specsubform[#:literals (??) (?? template1 template2)]{
|
||||||
|
|
||||||
|
Produces the result of @racket[template1] if @racket[template1] has no
|
||||||
|
pattern variables with ``missing values''; otherwise, produces the result of
|
||||||
|
@racket[template2].
|
||||||
|
|
||||||
|
A pattern variable bound by @racket[syntax-case] never has a missing value, but
|
||||||
|
pattern variables bound by @racket[syntax-parse] (for example, @racket[~or] or
|
||||||
|
@racket[~optional] patterns) can.
|
||||||
|
|
||||||
|
@examples[#:eval (let ([ev (syntax-eval)]) (ev '(require syntax/parse/pre)) ev)
|
||||||
|
(syntax-parse #'(m 1 2 3)
|
||||||
|
[(_ (~optional (~seq #:op op:expr)) arg:expr ...)
|
||||||
|
#'((?? op +) arg ...)])
|
||||||
|
(syntax-parse #'(m #:op max 1 2 3)
|
||||||
|
[(_ (~optional (~seq #:op op:expr)) arg:expr ...)
|
||||||
|
#'((?? op +) arg ...)])
|
||||||
|
]}
|
||||||
|
|
||||||
@specsubform[(ellipsis stat-template)]{
|
@specsubform[(ellipsis stat-template)]{
|
||||||
|
|
||||||
Produces the same result as @racket[stat-template], which is like a
|
Produces the same result as @racket[stat-template], which is like a
|
||||||
@racket[template], but @racket[...] is treated like an @racket[id]
|
@racket[template], but @racket[...], @racket[??], and @racket[?@]
|
||||||
(with no pattern binding).}
|
are treated like an @racket[id] (with no pattern binding).}
|
||||||
|
|
||||||
@specsubform[const]{
|
@specsubform[const]{
|
||||||
|
|
||||||
|
@ -388,11 +381,74 @@ Template forms produce a syntax object as follows:
|
||||||
preceding cases, and it produces the result @racket[(quote-syntax
|
preceding cases, and it produces the result @racket[(quote-syntax
|
||||||
const)].}
|
const)].}
|
||||||
|
|
||||||
|
A @racket[head-template] produces a sequence of syntax objects; that sequence is
|
||||||
|
``inlined'' into the result of the enclosing @racket[template]. The result of a
|
||||||
|
@racket[head-template] is defined as follows:
|
||||||
|
|
||||||
|
@specsubform[template]{
|
||||||
|
|
||||||
|
Produces one syntax object, according to the rules for @svar[template]
|
||||||
|
above.}
|
||||||
|
|
||||||
|
@specsubform[(code:line head-template ellipsis ...+)]{
|
||||||
|
|
||||||
|
Generates a sequence of syntax objects by ``@racket[map]ping'' the
|
||||||
|
@racket[head-template] over the values of its pattern variables. The number of
|
||||||
|
iterations depends on the values of the @tech{pattern variables} referenced
|
||||||
|
within the sub-template.
|
||||||
|
|
||||||
|
To be more precise: Let @racket[_outer] be @racket[_inner] followed by one
|
||||||
|
ellipsis. A @tech{pattern variable} is an @deftech{iteration pattern variable}
|
||||||
|
for @racket[_outer] if occurs at a depth equal to its @tech{depth
|
||||||
|
marker}. There must be at least one; otherwise, an error is raised. If there
|
||||||
|
are multiple iteration variables, then all of their values must be lists of
|
||||||
|
the same length. The result for @racket[_outer] is produced by
|
||||||
|
@racket[map]ping the @racket[_inner] template over the @tech{iteration pattern
|
||||||
|
variable} values and decreasing their effective @tech{depth markers} by 1
|
||||||
|
within @racket[_inner]. The @racket[_outer] result is formed by appending the
|
||||||
|
@racket[_inner] results.
|
||||||
|
|
||||||
|
Consequently, if a @tech{pattern variable} occurs at a depth greater than its
|
||||||
|
@tech{depth marker}, it is used as an @tech{iteration pattern variable} for
|
||||||
|
the innermost ellipses but not the outermost. A @tech{pattern variable} must
|
||||||
|
not occur at a depth less than its @tech{depth marker}; otherwise, an error is
|
||||||
|
raised.}
|
||||||
|
|
||||||
|
@specsubform[#:literals (?@) (?@ . template)]{
|
||||||
|
|
||||||
|
Produces the sequence of elements in the syntax list produced by
|
||||||
|
@racket[template]. If @racket[template] does not produce a proper syntax list,
|
||||||
|
an exception is raised.
|
||||||
|
|
||||||
|
@examples[#:eval (syntax-eval)
|
||||||
|
(with-syntax ([(key ...) #'('a 'b 'c)]
|
||||||
|
[(val ...) #'(1 2 3)])
|
||||||
|
#'(hash (?@ key val) ...))
|
||||||
|
(with-syntax ([xs #'(2 3 4)])
|
||||||
|
#'(list 1 (?@ . xs) 5))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@specsubform[#:literals (??) (?? head-template1 head-template2)]{
|
||||||
|
|
||||||
|
Produces the result of @racket[head-template1] if none of its pattern
|
||||||
|
variables have ``missing values''; otherwise produces the result of
|
||||||
|
@racket[head-template2]. }
|
||||||
|
|
||||||
|
@specsubform[#:literals (??) (?? head-template)]{
|
||||||
|
|
||||||
|
Produces the result of @racket[head-template] if none of its pattern
|
||||||
|
variables have ``missing values''; otherwise produces nothing.
|
||||||
|
|
||||||
|
Equivalent to @racket[(?? head-template (?@))]. }
|
||||||
|
|
||||||
A @racket[(#,(racketkeywordfont "syntax") template)] form is normally
|
A @racket[(#,(racketkeywordfont "syntax") template)] form is normally
|
||||||
abbreviated as @racket[#'template]; see also
|
abbreviated as @racket[#'template]; see also
|
||||||
@secref["parse-quote"]. If @racket[template] contains no pattern
|
@secref["parse-quote"]. If @racket[template] contains no pattern
|
||||||
variables, then @racket[#'template] is equivalent to
|
variables, then @racket[#'template] is equivalent to
|
||||||
@racket[(quote-syntax template)].}
|
@racket[(quote-syntax template)].
|
||||||
|
|
||||||
|
@history[#:changed "6.90.0.18" @elem{Added @racket[?@] and @racket[??].}]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@defform[(quasisyntax template)]{
|
@defform[(quasisyntax template)]{
|
||||||
|
@ -512,6 +568,16 @@ used as an expression. This binding is useful only in syntax patterns,
|
||||||
where it indicates a pattern that matches any syntax object. See
|
where it indicates a pattern that matches any syntax object. See
|
||||||
@racket[syntax-case].}
|
@racket[syntax-case].}
|
||||||
|
|
||||||
|
@deftogether[[
|
||||||
|
@defidform[??]
|
||||||
|
@defidform[?@]
|
||||||
|
]]{
|
||||||
|
|
||||||
|
The @racket[??] and @racket[?@] transformer bindings prohibit these forms from
|
||||||
|
being used as an expression. The bindings are useful only in syntax templates.
|
||||||
|
See @racket[syntax].
|
||||||
|
|
||||||
|
@history[#:added "6.90.0.18"]}
|
||||||
|
|
||||||
@defproc[(syntax-pattern-variable? [v any/c]) boolean?]{
|
@defproc[(syntax-pattern-variable? [v any/c]) boolean?]{
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ Here's one way to do it:
|
||||||
@interaction[#:eval the-eval
|
@interaction[#:eval the-eval
|
||||||
(define-syntax (mycond stx)
|
(define-syntax (mycond stx)
|
||||||
(syntax-parse stx
|
(syntax-parse stx
|
||||||
[(mycond (~or* (~seq #:error-on-fallthrough who:expr) (~seq))
|
[(mycond (~or* (~seq #:error-on-fallthrough who:expr)
|
||||||
|
(~seq))
|
||||||
clause ...)
|
clause ...)
|
||||||
(with-syntax ([error? (if (attribute who) #'#t #'#f)]
|
(with-syntax ([error? (if (attribute who) #'#t #'#f)]
|
||||||
[who (or (attribute who) #'#f)])
|
[who (or (attribute who) #'#f)])
|
||||||
|
@ -43,11 +44,11 @@ Here's one way to do it:
|
||||||
(void)]))
|
(void)]))
|
||||||
]
|
]
|
||||||
|
|
||||||
We cannot write @racket[#'who] in the macro's right-hand side, because
|
We cannot simply write @racket[#'who] in the macro's right-hand side,
|
||||||
the @racket[who] attribute does not receive a value if the keyword
|
because the @racket[who] attribute does not receive a value if the
|
||||||
argument is omitted. Instead we must write @racket[(attribute who)],
|
keyword argument is omitted. Instead we must first check the attribute
|
||||||
which produces @racket[#f] if matching did not assign a value to the
|
using @racket[(attribute who)], which produces @racket[#f] if matching
|
||||||
attribute.
|
did not assign a value to the attribute.
|
||||||
|
|
||||||
@interaction[#:eval the-eval
|
@interaction[#:eval the-eval
|
||||||
(mycond [(even? 13) 'blue]
|
(mycond [(even? 13) 'blue]
|
||||||
|
@ -62,8 +63,48 @@ There's a simpler way of writing the @racket[~or*] pattern above:
|
||||||
(~optional (~seq #:error-on-fallthrough who:expr))
|
(~optional (~seq #:error-on-fallthrough who:expr))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@section{Optional Arguments with @racket[??]}
|
||||||
|
|
||||||
|
The @racket[??] template form provides a compact alternative to
|
||||||
|
explicitly testing attribute values. Here's one way to do it:
|
||||||
|
|
||||||
|
@interaction[#:eval the-eval
|
||||||
|
(define-syntax (mycond stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(mycond (~optional (~seq #:error-on-fallthrough who:expr))
|
||||||
|
clause ...)
|
||||||
|
#'(mycond* (?? (?@ #t who) (?@ #f #f)) clause ...)]))
|
||||||
|
]
|
||||||
|
|
||||||
|
If @racket[who] matched, then the @racket[??] subtemplate splices in
|
||||||
|
the two terms @racket[#t who] into the enclosing template (@racket[?@]
|
||||||
|
is the template splicing form). Otherwise, it splices in @racket[#f #f].
|
||||||
|
|
||||||
|
Here's an alternative definition that re-uses Racket's @racket[cond] macro:
|
||||||
|
|
||||||
|
@interaction[#:eval the-eval
|
||||||
|
(define-syntax (mycond stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(mycond (~optional (~seq #:error-on-fallthrough who:expr))
|
||||||
|
clause ...)
|
||||||
|
#'(cond clause ... (?? [else (error 'who "no clause matched")] (?@)))]))
|
||||||
|
]
|
||||||
|
|
||||||
|
In this version, we optionally insert an @racket[else] clause at the
|
||||||
|
end to signal the error; otherwise we use @racket[cond]'s fall-through
|
||||||
|
behavior (that is, returning @racket[(void)]).
|
||||||
|
|
||||||
|
If the second subtemplate of a @racket[??] template is
|
||||||
|
@racket[(?@)]---that is, it produces no terms at all---the second
|
||||||
|
subtemplate can be omitted.
|
||||||
|
|
||||||
|
|
||||||
|
@section{Optional Arguments with @racket[define-splicing-syntax-class]}
|
||||||
|
|
||||||
Yet another way is to introduce a @tech{splicing syntax class}, which
|
Yet another way is to introduce a @tech{splicing syntax class}, which
|
||||||
is like an ordinary syntax class but for head patterns.
|
is like an ordinary syntax class but for head patterns.
|
||||||
|
|
||||||
@interaction[#:eval the-eval
|
@interaction[#:eval the-eval
|
||||||
(define-syntax (mycond stx)
|
(define-syntax (mycond stx)
|
||||||
|
|
||||||
|
@ -82,9 +123,9 @@ is like an ordinary syntax class but for head patterns.
|
||||||
Defining a splicing syntax class also makes it easy to eliminate the
|
Defining a splicing syntax class also makes it easy to eliminate the
|
||||||
case analysis we did before using @racket[attribute] by defining
|
case analysis we did before using @racket[attribute] by defining
|
||||||
@racket[error?] and @racket[who] as attributes within both of the
|
@racket[error?] and @racket[who] as attributes within both of the
|
||||||
syntax class's variants. (This is possible to do in the inline pattern
|
syntax class's variants. This is possible to do in the inline pattern
|
||||||
version too, using @racket[~and] and @racket[~parse], just less
|
version too, using @racket[~and] and @racket[~parse], but it is less
|
||||||
convenient.) Splicing syntax classes also closely parallel the style
|
convenient. Splicing syntax classes also closely parallel the style of
|
||||||
of grammars in macro documentation.
|
grammars in macro documentation.
|
||||||
|
|
||||||
@(close-eval the-eval)
|
@(close-eval the-eval)
|
||||||
|
|
|
@ -277,136 +277,20 @@ patterns as @racket[target-stxclass-id] but with the given
|
||||||
|
|
||||||
@defmodule[syntax/parse/experimental/template]
|
@defmodule[syntax/parse/experimental/template]
|
||||||
|
|
||||||
@(define literal-ellipsis (racket ...))
|
|
||||||
|
|
||||||
@defform[#:literals (?? ?@)
|
|
||||||
(template tmpl)
|
|
||||||
#:grammar
|
|
||||||
([tmpl pattern-variable-id
|
|
||||||
(head-tmpl . tmpl)
|
|
||||||
(head-tmpl ellipsis ...+ . tmpl)
|
|
||||||
(metafunction-id . tmpl)
|
|
||||||
(?? tmpl tmpl)
|
|
||||||
#(@#,svar[head-tmpl] ...)
|
|
||||||
#s(prefab-struct-key @#,svar[head-tmpl] ...)
|
|
||||||
#&@#,svar[tmpl]
|
|
||||||
constant-term]
|
|
||||||
[head-templ tmpl
|
|
||||||
(?? head-tmpl)
|
|
||||||
(?? head-tmpl head-tmpl)
|
|
||||||
(?@ . tmpl)]
|
|
||||||
[ellipsis @#,literal-ellipsis])]{
|
|
||||||
|
|
||||||
Constructs a syntax object from a syntax template, like
|
|
||||||
@racket[syntax], but provides additional templating forms for dealing
|
|
||||||
with optional terms and splicing sequences of terms. Only the
|
|
||||||
additional forms are described here; see @racket[syntax] for
|
|
||||||
descriptions of pattern variables, etc.
|
|
||||||
|
|
||||||
As in @racket[syntax], a template can be ``escaped'' with ellipses,
|
|
||||||
like @racket[(... _escaped-tmpl)]. Within the escaped template,
|
|
||||||
ellipses (@racket[...]), the @racket[??] and @racket[?@] forms, and
|
|
||||||
metafunctions are treated as constants rather than interpreted as
|
|
||||||
template forms.
|
|
||||||
|
|
||||||
@specsubform[#:literals (??)
|
|
||||||
(?? tmpl alt-tmpl)]{
|
|
||||||
|
|
||||||
Produces @racket[tmpl] unless any attribute used in @racket[tmpl] has
|
|
||||||
an absent value; in that case, @racket[alt-tmpl] is used instead.
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(syntax-parse #'(m 1 2 3)
|
|
||||||
[(_ (~optional (~seq #:op op:expr)) arg:expr ...)
|
|
||||||
(template ((?? op +) arg ...))])
|
|
||||||
(syntax-parse #'(m #:op max 1 2 3)
|
|
||||||
[(_ (~optional (~seq #:op op:expr)) arg:expr ...)
|
|
||||||
(template ((?? op +) arg ...))])
|
|
||||||
]
|
|
||||||
|
|
||||||
If @racket[??] is used as a head-template, then its sub-templates may
|
|
||||||
also be head-templates.
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(syntax-parse #'(m 1)
|
|
||||||
[(_ x:expr (~optional y:expr))
|
|
||||||
(template (m2 x (?? (?@ #:y y) (?@ #:z 0))))])
|
|
||||||
(syntax-parse #'(m 1 2)
|
|
||||||
[(_ x:expr (~optional y:expr))
|
|
||||||
(template (m2 x (?? (?@ #:y y) (?@ #:z 0))))])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[#:literals (??)
|
|
||||||
(?? head-tmpl)]{
|
|
||||||
|
|
||||||
Produces @racket[head-tmpl] unless any attribute used in
|
|
||||||
@racket[head-tmpl] has an absent value; in that case, the term is
|
|
||||||
omitted. Can only occur in head position in a template.
|
|
||||||
|
|
||||||
Equivalent to @racket[(?? head-tmpl (?@))].
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(syntax-parse #'(m 1)
|
|
||||||
[(_ x:expr (~optional y:expr))
|
|
||||||
(template (m2 x (?? y)))])
|
|
||||||
(syntax-parse #'(m 1 2)
|
|
||||||
[(_ x:expr (~optional y:expr))
|
|
||||||
(template (m2 x (?? y)))])
|
|
||||||
(syntax-parse #'(m 1 2)
|
|
||||||
[(_ x:expr (~optional y:expr))
|
|
||||||
(template (m2 x (?? (?@ #:y y))))])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[#:literals (?@)
|
|
||||||
(?@ . tmpl)]{
|
|
||||||
|
|
||||||
Similar to @racket[unquote-splicing], splices the result of
|
|
||||||
@racket[tmpl] (which must produce a syntax list) into the surrounding
|
|
||||||
template. Can only occur in head position in a template.
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(syntax-parse #'(m #:a 1 #:b 2 3 4 #:e 5)
|
|
||||||
[(_ (~alt pos:expr (~seq kw:keyword kwarg:expr)) ...)
|
|
||||||
(template (m2 (?@ kw kwarg) ... pos ...))])
|
|
||||||
]
|
|
||||||
|
|
||||||
The @racket[tmpl] must produce a proper syntax list, but it does not
|
|
||||||
need to be expressed as a proper list. For example, to unpack pattern
|
|
||||||
variables that contain syntax lists, use a ``dotted'' template:
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(with-syntax ([x #'(a b c)])
|
|
||||||
(template ((?@ . x) d)))
|
|
||||||
(with-syntax ([(x ...) #'((1 2 3) (4 5))])
|
|
||||||
(template ((?@ . x) ...)))
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@specsubform[(metafunction-id . tmpl)]{
|
|
||||||
|
|
||||||
Applies the template metafunction named @racket[metafunction-id] to
|
|
||||||
the result of the template (including @racket[metafunction-id]
|
|
||||||
itself). See @racket[define-template-metafunction] for examples.
|
|
||||||
}
|
|
||||||
|
|
||||||
The @racket[??] and @racket[?@] forms and metafunction applications
|
|
||||||
are disabled in an ``escaped template'' (see @racket[_stat-template]
|
|
||||||
under @racket[syntax]).
|
|
||||||
|
|
||||||
@examples[#:eval the-eval
|
|
||||||
(template (... ((?@ a b c) d)))
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
@deftogether[[
|
@deftogether[[
|
||||||
@defidform[??]
|
@defform[(template tmpl)]
|
||||||
@defidform[?@]
|
@defform[(template/loc loc-expr tmpl)]
|
||||||
|
@defform[(quasitemplate tmpl)]
|
||||||
|
@defform[(quasitemplate/loc loc-expr tmpl)]
|
||||||
]]{
|
]]{
|
||||||
|
|
||||||
Auxiliary forms used by @racket[template]. They may not be used as
|
Equivalent to @racket[syntax], @racket[syntax/loc],
|
||||||
expressions.
|
@racket[quasisyntax], and @racket[quasisyntax/loc], respectively.
|
||||||
|
}
|
||||||
|
|
||||||
|
@defform[(datum-template tmpl)]{
|
||||||
|
|
||||||
|
Equivalent to @racket[datum].
|
||||||
}
|
}
|
||||||
|
|
||||||
@defform*[[(define-template-metafunction metafunction-id expr)
|
@defform*[[(define-template-metafunction metafunction-id expr)
|
||||||
|
@ -453,23 +337,4 @@ the context above; instead, @racket[let-values] would report an
|
||||||
invalid binding list.
|
invalid binding list.
|
||||||
}
|
}
|
||||||
|
|
||||||
@deftogether[[
|
|
||||||
@defform[(template/loc loc-expr tmpl)]
|
|
||||||
@defform[(quasitemplate tmpl)]
|
|
||||||
@defform[(quasitemplate/loc loc-expr tmpl)]
|
|
||||||
]]{
|
|
||||||
|
|
||||||
Like @racket[syntax/loc], @racket[quasisyntax], and
|
|
||||||
@racket[quasisyntax/loc], respectively, but with the additional
|
|
||||||
features of @racket[template].
|
|
||||||
}
|
|
||||||
|
|
||||||
@defform[(datum-template tmpl)]{
|
|
||||||
|
|
||||||
Like @racket[datum] but with some of the additional features of
|
|
||||||
@racket[template]: @racket[?@] and @racket[??] are supported (although
|
|
||||||
@racket[??] is useless, since @racket[datum-case] cannot bind
|
|
||||||
``absent'' variables), but template metafunctions are not allowed.
|
|
||||||
}
|
|
||||||
|
|
||||||
@(close-eval the-eval)
|
@(close-eval the-eval)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user