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 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:seq HPBase ListPattern)
(make-hpat:and HPBase HeadPattern SinglePattern) (make-hpat:and HPBase HeadPattern SinglePattern)
(make-hpat:or HPBase (listof HeadPattern)) (make-hpat:or HPBase (listof HeadPattern))

View File

@ -283,7 +283,8 @@ form, syntax patterns, and attributes.
(pattern-id literal-id)] (pattern-id literal-id)]
[literal-set literal-set-id [literal-set literal-set-id
[literal-set-id #:at context-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 Evaluates @scheme[stx-expr], which should produce a syntax object, and
matches it against the @scheme[clause]s in order. If some clause's 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)) #:context #'(lambda (a b 3) (+ a b))
[(x:id ...) 'ok])) [(x:id ...) 'ok]))
The @scheme[#:literals] option specifies identifiers that should match The @scheme[#:literals] option specifies identifiers that should be
as @tech{literals}, rather than simply being @tech{pattern treated as @tech{literals} rather than @tech{pattern variables}. An
variables}. A literal in the literals list has two components: the entry in the literals list has two components: the identifier used
identifier used within the pattern to signify the positions to be within the pattern to signify the positions to be matched
matched (@scheme[pattern-id]), and the identifier expected to occur in (@scheme[pattern-id]), and the identifier expected to occur in those
those positions (@scheme[literal-id]). If the single-identifier form positions (@scheme[literal-id]). If the entry is a single identifier,
is used, the same identifier is used for both purposes. that identifier is used for both purposes.
@bold{Note:} Unlike @scheme[syntax-case], @scheme[syntax-parse] @bold{Note:} Unlike @scheme[syntax-case], @scheme[syntax-parse]
requires all literals to have a binding. To match identifiers by their 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 @scheme[syntax-parse] and @scheme[syntax-parser] is given in the
following table: 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) ~rest ~struct ~! ~describe ~bind ~fail)
[S-pattern [S-pattern
pvar-id pvar-id
pvar-id:syntax-class-id pvar-id:syntax-class-id
literal-id literal-id
(~var id)
(~var id syntax-class)
(~literal literal-id)
atomic-datum atomic-datum
(H-pattern . S-pattern) (H-pattern . S-pattern)
((~or EH-pattern ...+) #,ellipses . S-pattern) ((~or EH-pattern ...+) #,ellipses . S-pattern)
(EH-pattern #,ellipses . S-pattern) (EH-pattern #,ellipses . S-pattern)
(~and S-pattern ...+) (~and S-pattern ...+)
(~or S-pattern ...+) (~or S-pattern ...+)
(~not S-pattern)
#((unsyntax @svar[pattern-part]) ...) #((unsyntax @svar[pattern-part]) ...)
#s(prefab-struct-key (unsyntax @svar[pattern-part]) ...) #s(prefab-struct-key (unsyntax @svar[pattern-part]) ...)
(~rest S-pattern) (~rest S-pattern)
@ -365,9 +371,12 @@ following table:
(~rest L-pattern) (~rest L-pattern)
(~! . L-pattern)] (~! . L-pattern)]
[H-pattern [H-pattern
pvar-id:splicing-syntax-class-id
(~var id splicing-syntax-class)
(~seq . L-pattern) (~seq . L-pattern)
(~and H-pattern ...+)
(~or H-pattern ...+) (~or H-pattern ...+)
(~optional H-pattern optional-option ...) (~optional H-pattern maybe-optional-option)
(~describe expr H-pattern) (~describe expr H-pattern)
S-pattern] S-pattern]
[EH-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}: 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 An identifier can be either a @tech{pattern variable}, an
@scheme[#:convention]), the pattern matches anything. The @tech{annotated pattern variable}, or a @tech{literal}:
@deftech{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 @itemize[
like the following form.
@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]{ @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
Matches only subterms specified by the @svar[syntax-class-id]. The @tech{annotated pattern variable}, and the pattern is equivalent to
syntax class's @tech{attributes} are computed for the subterm and @scheme[(~var pvar-id syntax-class-id)].
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.
@myexamples[ @myexamples[
(syntax-parse #'a (syntax-parse #'a
@ -435,34 +450,72 @@ bound, but their names are not prefixed first.
(syntax-parse #'(a b) (syntax-parse #'(a b)
[t [t
#:declare t two #: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 @specsubform[#:literals (~var) (~var pvar-id)]{
variable; instead, it is a @deftech{literal} that matches any
identifier @scheme[free-identifier=?] to it.
Specifically, if @scheme[literal-id] is the ``pattern'' name of an A @deftech{pattern variable}. If @scheme[pvar-id] has no syntax class
entry in the literals list, then it represents a pattern that matches (by @scheme[#:convention]), the pattern variable matches anything. The
only identifiers @scheme[free-identifier=?] to the ``literal'' pattern variable is bound to the matched subterm, unless the pattern
name. These identifiers are often the same. 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[ @myexamples[
(syntax-parse #'(define x 12) (syntax-parse #'(define x 12)
#:literals (define) [((~literal define) var:id body:expr) 'ok])
[(define var:id body:expr) 'ok])
(syntax-parse #'(lambda x 12) (syntax-parse #'(lambda x 12)
#:literals (define) [((~literal define) var:id body:expr) 'ok])
[(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])
] ]
} }
@ -477,7 +530,6 @@ literals.
(syntax-parse #'(a foo bar) (syntax-parse #'(a foo bar)
[(x #:foo y) (syntax->datum #'y)]) [(x #:foo y) (syntax->datum #'y)])
] ]
} }
@specsubform[(H-pattern . S-pattern)]{ @specsubform[(H-pattern . S-pattern)]{
@ -496,8 +548,7 @@ and whose rest matches the second.
See @tech{H-patterns} for more information. See @tech{H-patterns} for more information.
} }
@specsubform[#:literals (~or) ((~or EH-pattern ...+) #,ellipses . S-pattern)] @specsubform[#:literals (~or) ((~or EH-pattern ...+) #,ellipses . S-pattern)]{
@specsubform[(EH-pattern #,ellipses . S-pattern)]{
Matches any term that can be decomposed into a list head matching some Matches any term that can be decomposed into a list head matching some
number of repetitions of the @tech{EH-pattern} alternatives (subject 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 alternatives of the first pattern and whose tail recursively matches
the whole sequence pattern. 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. 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 ...)]{ @specsubform[#:literals (~and) (~and S-pattern ...)]{
Matches any term that matches all of the subpatterns. 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] ...)]{ @specsubform[#(#, @svar[pattern-part] ...)]{
Matches a term that is a vector whose elements, when considered as a 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 ...)]{ @specsubform[#:literals (~or) (~or H-pattern ...)]{
Like the S-pattern version of @scheme[~or], but matches a term head 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 ...) @specsubform/subs[#:literals (~optional) (~optional H-pattern maybe-optional-option)
([optional-option (code:line #:defaults ([attr-id expr] ...))])]{ ([maybe-optional-option
(code:line)
(code:line #:defaults ([attr-id expr] ...))])]{
Matches either the given head subpattern or an empty head. If the 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 are used if the subpattern does not match. The default attributes must
be a subset of the subpattern's attributes. 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) (syntax-parse #'(m a b c)
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...) [(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
(attribute x)]) (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 #:declare pattern-id (syntax-class-id expr ...))
(code:line #:with syntax-pattern expr) (code:line #:with syntax-pattern expr)
(code:line #:attr attr-id 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-unless condition-expr message-expr)
(code:line #:fail-when condition-expr message-expr)
(code:line #:when condition-expr)] (code:line #:when condition-expr)]
@specsubform[(code:line #:declare pvar-id syntax-class-id)] @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. 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)]{ @specsubform[(code:line #:fail-unless condition-expr message-expr)]{
Evaluates the @scheme[condition-expr] in the context of all previous Evaluates the @scheme[condition-expr] in the context of all previous
attribute bindings. If the value is any non-false value for attribute bindings. If the value is any @scheme[#f], the matching
@scheme[#:fail-when] or if the value is @scheme[#f] for process backtracks (with the given message); otherwise, it continues.
@scheme[#:fail-unless], 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)]{ @specsubform[(code:line #:when condition-expr)]{
@ -908,8 +1014,11 @@ backtracks. In other words, @scheme[#:when] is like
} }
@deftogether[[ @deftogether[[
@defidform[~var]
@defidform[~literal]
@defidform[~or] @defidform[~or]
@defidform[~and] @defidform[~and]
@defidform[~not]
@defidform[~seq] @defidform[~seq]
@defidform[~once] @defidform[~once]
@defidform[~optional] @defidform[~optional]