update docs for syntax, template

This commit is contained in:
Ryan Culpepper 2018-02-28 14:37:41 +01:00
parent 8d607b83f9
commit 72a7bbcefc
3 changed files with 191 additions and 219 deletions

View File

@ -1,5 +1,5 @@
#lang scribble/doc
@(require "mz.rkt")
@(require "mz.rkt" (for-label syntax/parse))
@(define lit-ellipsis (racket ...))
@ -270,30 +270,37 @@ the individual @racket[stx-expr].
(math 3 1 4 1 5 9)
]}
@defform/subs[(syntax template)
([template id
(template-elem ...)
(template-elem ...+ . template)
(code:line #,(tt "#")(template-elem ...))
(code:line #,(tt "#&")template)
(code:line #,(tt "#s")(key-datum template-elem ...))
(ellipsis stat-template)
const]
[template-elem (code:line template ellipsis ...)]
[stat-template id
(stat-template ...)
(stat-template ... . stat-template)
(code:line #,(tt "#")(stat-template ...))
(code:line #,(tt "#&")stat-template)
(code:line #,(tt "#s")(key-datum stat-template ...))
const]
[ellipsis #,lit-ellipsis])]{
@defform[#:literals (?? ?@) (syntax template)
#:grammar
([template id
(head-template ...)
(head-template ...+ . template)
(code:line #,(tt "#")(head-template ...))
(code:line #,(tt "#&")template)
(code:line #,(tt "#s")(key-datum head-template ...))
(?? template template)
(ellipsis stat-template)
const]
[head-template template
(code:line head-template ellipsis ...+)
(?@ . template)
(?? head-template head-template)
(?? head-template)]
[stat-template @#,elem{like @svar{template}, but without @|lit-ellipsis|,
@racket[??], and @racket[?@]}]
[ellipsis #,lit-ellipsis])]{
Constructs a syntax object based on a @racket[template], which can
include @tech{pattern variables} bound by @racket[syntax-case] or
@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]{
@ -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]
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
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
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)]{
@specsubform[(head-template ... . template)]{
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
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.}
@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
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.
The @racket[key-datum] must correspond to a valid first argument of
@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)]{
Produces the same result as @racket[stat-template], which is like a
@racket[template], but @racket[...] is treated like an @racket[id]
(with no pattern binding).}
@racket[template], but @racket[...], @racket[??], and @racket[?@]
are treated like an @racket[id] (with no pattern binding).}
@specsubform[const]{
@ -388,11 +381,74 @@ Template forms produce a syntax object as follows:
preceding cases, and it produces the result @racket[(quote-syntax
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
abbreviated as @racket[#'template]; see also
@secref["parse-quote"]. If @racket[template] contains no pattern
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)]{
@ -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
@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?]{

View File

@ -27,7 +27,8 @@ Here's one way to do it:
@interaction[#:eval the-eval
(define-syntax (mycond stx)
(syntax-parse stx
[(mycond (~or* (~seq #:error-on-fallthrough who:expr) (~seq))
[(mycond (~or* (~seq #:error-on-fallthrough who:expr)
(~seq))
clause ...)
(with-syntax ([error? (if (attribute who) #'#t #'#f)]
[who (or (attribute who) #'#f)])
@ -43,11 +44,11 @@ Here's one way to do it:
(void)]))
]
We cannot write @racket[#'who] in the macro's right-hand side, because
the @racket[who] attribute does not receive a value if the keyword
argument is omitted. Instead we must write @racket[(attribute who)],
which produces @racket[#f] if matching did not assign a value to the
attribute.
We cannot simply write @racket[#'who] in the macro's right-hand side,
because the @racket[who] attribute does not receive a value if the
keyword argument is omitted. Instead we must first check the attribute
using @racket[(attribute who)], which produces @racket[#f] if matching
did not assign a value to the attribute.
@interaction[#:eval the-eval
(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))
]
@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
is like an ordinary syntax class but for head patterns.
@interaction[#:eval the-eval
(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
case analysis we did before using @racket[attribute] by defining
@racket[error?] and @racket[who] as attributes within both of the
syntax class's variants. (This is possible to do in the inline pattern
version too, using @racket[~and] and @racket[~parse], just less
convenient.) Splicing syntax classes also closely parallel the style
of grammars in macro documentation.
syntax class's variants. This is possible to do in the inline pattern
version too, using @racket[~and] and @racket[~parse], but it is less
convenient. Splicing syntax classes also closely parallel the style of
grammars in macro documentation.
@(close-eval the-eval)

View File

@ -277,136 +277,20 @@ patterns as @racket[target-stxclass-id] but with the given
@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[[
@defidform[??]
@defidform[?@]
@defform[(template tmpl)]
@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
expressions.
Equivalent to @racket[syntax], @racket[syntax/loc],
@racket[quasisyntax], and @racket[quasisyntax/loc], respectively.
}
@defform[(datum-template tmpl)]{
Equivalent to @racket[datum].
}
@defform*[[(define-template-metafunction metafunction-id expr)
@ -453,23 +337,4 @@ the context above; instead, @racket[let-values] would report an
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)