syntax/parse: documented ~var, ~literal, ~not, head ~and

Do not commit to release branch.

svn: r16079
This commit is contained in:
Ryan Culpepper 2009-09-19 23:09:20 +00:00
parent fdc2eaa646
commit 5db475cab2
2 changed files with 180 additions and 71 deletions

View File

@ -60,7 +60,7 @@ A ListPattern is a subtype of SinglePattern; one of
#|
A HeadPattern is one of
(make-pat:var SPBase id id (listof stx) (listof IAttr))
(make-hpat:var SPBase id id (listof stx) (listof IAttr))
(make-hpat:seq HPBase ListPattern)
(make-hpat:and HPBase HeadPattern SinglePattern)
(make-hpat:or HPBase (listof HeadPattern))

View File

@ -283,7 +283,8 @@ form, syntax patterns, and attributes.
(pattern-id literal-id)]
[literal-set literal-set-id
[literal-set-id #:at context-id]]
[clause (syntax-pattern pattern-directive ... expr)])]{
[clause (syntax-pattern pattern-directive ... expr)])
#:contracts ([stx-expr syntax?])]{
Evaluates @scheme[stx-expr], which should produce a syntax object, and
matches it against the @scheme[clause]s in order. If some clause's
@ -304,13 +305,13 @@ error is raised. If the @scheme[#:context] argument is given,
#:context #'(lambda (a b 3) (+ a b))
[(x:id ...) 'ok]))
The @scheme[#:literals] option specifies identifiers that should match
as @tech{literals}, rather than simply being @tech{pattern
variables}. A literal in the literals list has two components: the
identifier used within the pattern to signify the positions to be
matched (@scheme[pattern-id]), and the identifier expected to occur in
those positions (@scheme[literal-id]). If the single-identifier form
is used, the same identifier is used for both purposes.
The @scheme[#:literals] option specifies identifiers that should be
treated as @tech{literals} rather than @tech{pattern variables}. An
entry in the literals list has two components: the identifier used
within the pattern to signify the positions to be matched
(@scheme[pattern-id]), and the identifier expected to occur in those
positions (@scheme[literal-id]). If the entry is a single identifier,
that identifier is used for both purposes.
@bold{Note:} Unlike @scheme[syntax-case], @scheme[syntax-parse]
requires all literals to have a binding. To match identifiers by their
@ -338,18 +339,23 @@ The grammar of @deftech{syntax patterns} accepted by
@scheme[syntax-parse] and @scheme[syntax-parser] is given in the
following table:
@schemegrammar*[#:literals (_ ~or ~and ~seq ~rep ~once ~optional
@schemegrammar*[#:literals (_ ~var ~literal ~or ~and ~not ~seq
~rep ~once ~optional
~rest ~struct ~! ~describe ~bind ~fail)
[S-pattern
pvar-id
pvar-id:syntax-class-id
literal-id
(~var id)
(~var id syntax-class)
(~literal literal-id)
atomic-datum
(H-pattern . S-pattern)
((~or EH-pattern ...+) #,ellipses . S-pattern)
(EH-pattern #,ellipses . S-pattern)
(~and S-pattern ...+)
(~or S-pattern ...+)
(~not S-pattern)
#((unsyntax @svar[pattern-part]) ...)
#s(prefab-struct-key (unsyntax @svar[pattern-part]) ...)
(~rest S-pattern)
@ -365,9 +371,12 @@ following table:
(~rest L-pattern)
(~! . L-pattern)]
[H-pattern
pvar-id:splicing-syntax-class-id
(~var id splicing-syntax-class)
(~seq . L-pattern)
(~and H-pattern ...+)
(~or H-pattern ...+)
(~optional H-pattern optional-option ...)
(~optional H-pattern maybe-optional-option)
(~describe expr H-pattern)
S-pattern]
[EH-pattern
@ -396,31 +405,37 @@ constrains it to match only terms that are proper lists.
Here are the variants of @tech{S-pattern}:
@specsubform[pvar-id]{
@specsubform[id]{
If @scheme[pvar-id] has no syntax class (by @scheme[#:declare] or
@scheme[#:convention]), the pattern matches anything. The
@deftech{pattern variable} is bound to the matched subterm, unless the
pattern variable is the wildcard (@scheme[_]), in which case no
binding occurs.
An identifier can be either a @tech{pattern variable}, an
@tech{annotated pattern variable}, or a @tech{literal}:
If @scheme[pvar-id] does have an associated syntax class, it behaves
like the following form.
@itemize[
@item{If @scheme[id] is the ``pattern'' name of an entry in the
literals list, it is a @tech{literal} pattern that behaves
like @scheme[(~literal id)].
@myexamples[
(syntax-parse #'(define x 12)
#:literals (define)
[(define var:id body:expr) 'ok])
(syntax-parse #'(lambda x 12)
#:literals (define)
[(define var:id body:expr) 'ok])
(syntax-parse #'(define x 12)
#:literals ([def define])
[(def var:id body:expr) 'ok])
(syntax-parse #'(lambda x 12)
#:literals ([def define])
[(def var:id body:expr) 'ok])
]
}
@specsubform[pvar-id:syntax-class-id]{
Matches only subterms specified by the @svar[syntax-class-id]. The
syntax class's @tech{attributes} are computed for the subterm and
bound to the pattern variables formed by prefixing @svar[pvar-id.] to
the name of the attribute. @svar[pvar-id] is bound to the matched
subterm.
If @svar[pvar-id] is @scheme[_], no attributes are bound.
If @svar[pvar-id] is empty (that is, if the pattern is of the form
@svar[:syntax-class-id]), then the syntax class's attributes are
bound, but their names are not prefixed first.
@item{If @scheme[id] is of the form @scheme[_pvar-id:syntax-class-id]
(that is, two names joined by a colon character), it is an
@tech{annotated pattern variable}, and the pattern is equivalent to
@scheme[(~var pvar-id syntax-class-id)].
@myexamples[
(syntax-parse #'a
@ -435,34 +450,72 @@ bound, but their names are not prefixed first.
(syntax-parse #'(a b)
[t
#:declare t two
(syntax->datum #'(t t.x t.y))])]
(syntax->datum #'(t t.x t.y))])
]
}
@specsubform[literal-id]{
@item{Otherwise, @scheme[id] is a @tech{pattern variable}, and the
pattern is equivalent to @scheme[(~var id)].
}
]
}
An identifier that appears in the literals list is not a pattern
variable; instead, it is a @deftech{literal} that matches any
identifier @scheme[free-identifier=?] to it.
@specsubform[#:literals (~var) (~var pvar-id)]{
Specifically, if @scheme[literal-id] is the ``pattern'' name of an
entry in the literals list, then it represents a pattern that matches
only identifiers @scheme[free-identifier=?] to the ``literal''
name. These identifiers are often the same.
A @deftech{pattern variable}. If @scheme[pvar-id] has no syntax class
(by @scheme[#:convention]), the pattern variable matches anything. The
pattern variable is bound to the matched subterm, unless the pattern
variable is the wildcard (@scheme[_]), in which case no binding
occurs.
If @scheme[pvar-id] does have an associated syntax class, it behaves
like an @tech{annotated pattern variable} with the implicit syntax
class inserted.
}
@specsubform/subs[#:literals (~var) (~var pvar-id syntax-class)
([syntax-class syntax-class-id
(syntax-class-id arg-expr ...)])]{
An @deftech{annotated pattern variable}. The pattern matches only
terms accepted by @svar[syntax-class-id] (parameterized by the
@scheme[arg-expr]s, if present).
The syntax class's @tech{attributes} are computed for the term and
bound to the names formed by prefixing @svar[pvar-id.] to the name of
the attribute. The name @svar[pvar-id] itself is bound to the whole
term.
If @svar[pvar-id] is @scheme[_], no attributes are bound.
@myexamples[
(syntax-parse #'a
[(~var var id) (syntax-e #'var)])
(syntax-parse #'12
[(~var var id) (syntax-e #'var)])
(define-syntax-class two
#:attributes (x y)
(pattern (x y)))
(syntax-parse #'(a b)
[(~var t two) (syntax->datum #'(t t.x t.y))])
(define-syntax-class (nat-less-than n)
(pattern x:nat #:when (< (syntax-e #'x) n)))
(syntax-parse #'(1 2 3 4 5)
[((~var small (nat-less-than 4)) ... large:nat ...)
(list #'(small ...) #'(large ...))])
]
}
@specsubform[#:literals (~literal) (~literal literal-id)]{
A @deftech{literal} identifier pattern. Matches any identifier
@scheme[free-identifier=?] to @scheme[literal-id].
@myexamples[
(syntax-parse #'(define x 12)
#:literals (define)
[(define var:id body:expr) 'ok])
[((~literal define) var:id body:expr) 'ok])
(syntax-parse #'(lambda x 12)
#:literals (define)
[(define var:id body:expr) 'ok])
(syntax-parse #'(define x 12)
#:literals ([def define])
[(def var:id body:expr) 'ok])
(syntax-parse #'(lambda x 12)
#:literals ([def define])
[(def var:id body:expr) 'ok])
[((~literal define) var:id body:expr) 'ok])
]
}
@ -477,7 +530,6 @@ literals.
(syntax-parse #'(a foo bar)
[(x #:foo y) (syntax->datum #'y)])
]
}
@specsubform[(H-pattern . S-pattern)]{
@ -496,8 +548,7 @@ and whose rest matches the second.
See @tech{H-patterns} for more information.
}
@specsubform[#:literals (~or) ((~or EH-pattern ...+) #,ellipses . S-pattern)]
@specsubform[(EH-pattern #,ellipses . S-pattern)]{
@specsubform[#:literals (~or) ((~or EH-pattern ...+) #,ellipses . S-pattern)]{
Matches any term that can be decomposed into a list head matching some
number of repetitions of the @tech{EH-pattern} alternatives (subject
@ -509,12 +560,15 @@ In other words, the whole pattern matches either the second pattern
alternatives of the first pattern and whose tail recursively matches
the whole sequence pattern.
The @scheme[~or]-free variant is shorthand for the @scheme[~or]
variant with just one alternative.
See @tech{EH-patterns} for more information.
}
@specsubform[(EH-pattern #,ellipses . S-pattern)]{
The @scheme[~or]-free variant of ellipses (@ellipses) pattern is
equivalent to the @scheme[~or] variant with just one alternative.
}
@specsubform[#:literals (~and) (~and S-pattern ...)]{
Matches any term that matches all of the subpatterns.
@ -566,6 +620,19 @@ to have a value if the whole pattern matches.
]
}
@specsubform[#:literals (~not) (~not S-pattern)]{
Matches any term that does not match the subpattern. The subpattern's
attributes are @emph{not} bound outside of the @scheme[~not]-pattern.
@myexamples[
(syntax-parse #'(x y z => u v)
#:literals (=>)
[((~and before (~not =>)) ... => after ...)
(list #'(before ...) #'(after ...))])
]
}
@specsubform[#(#, @svar[pattern-part] ...)]{
Matches a term that is a vector whose elements, when considered as a
@ -726,6 +793,39 @@ examples of @scheme[~seq].
}
@specsubform[#:literals (~and) (~and H-pattern ...)]{
Like the S-pattern version of @scheme[~and], but matches a term head
instead.
@myexamples[
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
[((~and (~seq (~seq k:keyword e:expr) ...)
(~seq keyword-stuff ...))
positional-stuff ...)
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
]
The H-pattern of @scheme[~and] requires that all of the subpatterns be
strictly @tech{H-patterns} and not @tech{S-patterns}. This is to
prevent typos like the following, a variant of the previous example
with the second @scheme[~seq] omitted:
@myexamples[
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
[((~and (~seq (~seq k:keyword e:expr) ...)
(keyword-stuff ...))
positional-stuff ...)
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
(code:comment "If the example above were allowed, it would be equivalent to this:")
(syntax-parse #'(#:a 1 #:b 2 3 4 5)
[((~and (~seq (~seq k:keyword e:expr) ...)
(~seq (keyword-stuff ...)))
positional-stuff ...)
(syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))])
]
}
@specsubform[#:literals (~or) (~or H-pattern ...)]{
Like the S-pattern version of @scheme[~or], but matches a term head
@ -741,11 +841,13 @@ instead.
]
}
@specsubform/subs[#:literals (~optional) (~optional H-pattern optional-option ...)
([optional-option (code:line #:defaults ([attr-id expr] ...))])]{
@specsubform/subs[#:literals (~optional) (~optional H-pattern maybe-optional-option)
([maybe-optional-option
(code:line)
(code:line #:defaults ([attr-id expr] ...))])]{
Matches either the given head subpattern or an empty head. If the
@scheme[#:defaults] option is given, the following attribute bindings
@scheme[#:defaults] option is given, the subsequent attribute bindings
are used if the subpattern does not match. The default attributes must
be a subset of the subpattern's attributes.
@ -756,6 +858,9 @@ be a subset of the subpattern's attributes.
(syntax-parse #'(m a b c)
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
(attribute x)])
(syntax-parse #'(m a b c)
[(_ (~optional (~seq #:foo x)) y:id ...)
(attribute x)])
]
}
@ -849,8 +954,8 @@ conditions. The grammar for pattern directives follows:
(code:line #:declare pattern-id (syntax-class-id expr ...))
(code:line #:with syntax-pattern expr)
(code:line #:attr attr-id expr)
(code:line #:fail-when condition-expr message-expr)
(code:line #:fail-unless condition-expr message-expr)
(code:line #:fail-when condition-expr message-expr)
(code:line #:when condition-expr)]
@specsubform[(code:line #:declare pvar-id syntax-class-id)]
@ -887,15 +992,16 @@ bindings and binds it to the attribute named by @scheme[attr-id]. The
value of @scheme[expr] need not be syntax.
}
@specsubform[(code:line #:fail-when condition-expr message-expr)]
@specsubform[(code:line #:fail-unless condition-expr message-expr)]{
Evaluates the @scheme[condition-expr] in the context of all previous
attribute bindings. If the value is any non-false value for
@scheme[#:fail-when] or if the value is @scheme[#f] for
@scheme[#:fail-unless], the matching process backtracks (with the
given message); otherwise, it continues.
attribute bindings. If the value is any @scheme[#f], the matching
process backtracks (with the given message); otherwise, it continues.
}
@specsubform[(code:line #:fail-when condition-expr message-expr)]{
Like @scheme[#:fail-unless] with the condition negated.
}
@specsubform[(code:line #:when condition-expr)]{
@ -908,8 +1014,11 @@ backtracks. In other words, @scheme[#:when] is like
}
@deftogether[[
@defidform[~var]
@defidform[~literal]
@defidform[~or]
@defidform[~and]
@defidform[~not]
@defidform[~seq]
@defidform[~once]
@defidform[~optional]