
added syntax/parse library and documentation added syntax/id-table library and documentation svn: r15376
927 lines
32 KiB
Racket
927 lines
32 KiB
Racket
#lang scribble/doc
|
|
@(require scribble/manual
|
|
scribble/struct
|
|
scribble/decode
|
|
scribble/eval
|
|
scheme/sandbox
|
|
(for-label scheme/base
|
|
scheme/contract
|
|
syntax/parse
|
|
syntax/kerncase))
|
|
|
|
@(define ellipses @scheme[...])
|
|
|
|
@(begin
|
|
(define the-eval
|
|
(parameterize ((sandbox-output 'string)
|
|
(sandbox-error-output 'string))
|
|
(make-evaluator 'scheme/base #:requires '(syntax/parse))))
|
|
(define-syntax-rule (myexamples e ...)
|
|
(parameterize ((error-print-source-location #f))
|
|
(examples #:eval the-eval e ...))))
|
|
|
|
@title[#:tag "stxparse"]{Parsing and classifying syntax}
|
|
|
|
The @schememodname[syntax/parse] library provides a framework for
|
|
describing and parsing syntax. Using @schememodname[syntax/parse],
|
|
macro writers can define new syntactic categories, specify their legal
|
|
syntax, and use them to write clear, concise, and robust macros. The
|
|
library also provides a pattern-matching form, @scheme[syntax-parse],
|
|
which offers many improvements over @scheme[syntax-case].
|
|
|
|
@defmodule[syntax/parse]
|
|
|
|
@;{----------}
|
|
|
|
@section{Parsing syntax}
|
|
|
|
This section describes the @scheme[syntax-parse] pattern matching
|
|
form, syntax patterns, and attributes.
|
|
|
|
@defform/subs[(syntax-parse stx-expr parse-option ... clause ...+)
|
|
([parse-option (code:line #:literals (literal ...))
|
|
(code:line #:literal-sets (literal-set ...))
|
|
(code:line #:conventions (convention-id ...))]
|
|
[literal literal-id
|
|
(pattern-id literal-id)]
|
|
[literal-set literal-set-id
|
|
[literal-set-id #:at context-id]]
|
|
[clause (syntax-pattern pattern-directive ... expr)])]{
|
|
|
|
Evaluates @scheme[stx-expr], which should produce a syntax object, and
|
|
matches it against the @scheme[clause]s in order. If some clause's
|
|
pattern matches, its attributes are bound to the corresponding
|
|
subterms of the syntax object and that clause's side conditions and
|
|
@scheme[expr] is evaluated. The result is the result of @scheme[expr].
|
|
|
|
If the syntax object fails to match any of the patterns (or all
|
|
matches fail the corresponding clauses' side conditions), a syntax
|
|
error is raised.
|
|
|
|
The @scheme[#:literals] option specifies identifiers that should match
|
|
as literals, rather than simply being 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.
|
|
|
|
Many literals can be declared at once via one or more @tech{literal sets},
|
|
imported with the @scheme[#:literal-sets] option. The literal-set
|
|
definition determines the literal identifiers to recognize and the
|
|
names used in the patterns to recognize those literals.
|
|
|
|
The @scheme[#:conventions] option imports @tech{convention}s that give
|
|
default syntax classes to pattern variables that do not explicitly
|
|
specify a syntax class.
|
|
}
|
|
|
|
@defform[(syntax-parser maybe-literals clause ...)]{
|
|
|
|
Like @scheme[syntax-parse], but produces a matching procedure. The
|
|
procedure accepts a single argument, which should be a syntax object.
|
|
|
|
}
|
|
|
|
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
|
|
~rest ~struct ~! ~describe ~bind ~fail)
|
|
[S-pattern
|
|
pvar-id
|
|
pvar-id:syntax-class-id
|
|
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 ...+)
|
|
#((unsyntax @svar[pattern-part]) ...)
|
|
#s(prefab-struct-key (unsyntax @svar[pattern-part]) ...)
|
|
(~rest S-pattern)
|
|
(~describe expr S-pattern)
|
|
(~! . S-pattern)
|
|
(~bind [attr-id expr] ...)
|
|
(~fail maybe-fail-condition message-expr)]
|
|
[L-pattern
|
|
()
|
|
(H-pattern . L-pattern)
|
|
((~or EH-pattern ...+) #,ellipses . L-pattern)
|
|
(EH-pattern #,ellipses . L-pattern)
|
|
(~rest L-pattern)
|
|
(~! . L-pattern)]
|
|
[H-pattern
|
|
(~or H-pattern ...+)
|
|
(~seq . L-pattern)
|
|
(~describe expr H-pattern)
|
|
S-pattern]
|
|
[EH-pattern
|
|
(~once H-pattern once-option ...)
|
|
(~optional H-pattern optional-option ...)
|
|
H-pattern]]
|
|
|
|
There are three main kinds of syntax pattern: @tech{S-patterns} (for
|
|
``single patterns''), @tech{H-patterns} (for ``head patterns''), and
|
|
@tech{EH-patterns} (for ``ellipsis head patterns''). A fourth kind,
|
|
@tech{L-patterns} (for ``list patterns''), is a restricted subset of
|
|
@tech{S-patterns}. When a special form in this manual refers to
|
|
@svar[syntax-pattern] (eg, the description of the
|
|
@scheme[syntax-parse] special form), it means specifically
|
|
@tech{S-pattern}.
|
|
|
|
@subsection{S-pattern variants}
|
|
|
|
An @deftech{S-pattern} (for ``single pattern'') is a pattern that
|
|
describes a single term. The pattern may, of course, consist of other
|
|
parts. For example, @scheme[(17 ...)] is an @tech{S-pattern}
|
|
that matches any term that is a proper list of repeated
|
|
@schemeresult[17] numerals. The @deftech{L-pattern}s (for ``list
|
|
pattern'') are @tech{S-pattern} having a restricted structure that
|
|
constrains it to match only terms that are proper lists.
|
|
|
|
Here are the variants of @tech{S-pattern}:
|
|
|
|
@specsubform[pvar-id]{
|
|
|
|
If @scheme[pvar-id] has no syntax class (by @scheme[#:declare] or
|
|
@scheme[#:convention]), the pattern 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 the following form.
|
|
}
|
|
|
|
@specsubform[pvar-id:syntax-class-id]{
|
|
|
|
Matches only subterms specified by the @svar[syntax-class-id]. The
|
|
syntax class's 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.
|
|
|
|
@myexamples[
|
|
(syntax-parse #'x
|
|
[var:id (syntax-e #'var)])
|
|
(syntax-parse #'12
|
|
[var:id (syntax-e #'var)])
|
|
(syntax-parse #'(x y z)
|
|
[var:id (syntax-e #'var)])]
|
|
}
|
|
|
|
@specsubform[literal-id]{
|
|
|
|
An identifier that appears in the literals list is not a pattern
|
|
variable; instead, it is a literal that matches any identifier
|
|
@scheme[free-identifier=?] to it.
|
|
|
|
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.
|
|
|
|
@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[atomic-datum]{
|
|
|
|
Numbers, strings, booleans, keywords, and the empty list match as
|
|
literals.
|
|
|
|
@myexamples[
|
|
(syntax-parse #'(a #:foo bar)
|
|
[(x #:foo y) (syntax->datum #'y)])
|
|
(syntax-parse #'(a foo bar)
|
|
[(x #:foo y) (syntax->datum #'y)])
|
|
]
|
|
|
|
}
|
|
|
|
@specsubform[(H-pattern . S-pattern)]{
|
|
|
|
Matches any term that can be decomposed into a list prefix matching
|
|
the @tech{H-pattern} and a suffix matching the S-pattern.
|
|
|
|
Note that the pattern may match terms that are not even improper
|
|
lists; if the head pattern can match a zero-length head, then the
|
|
whole pattern matches whatever the tail pattern accepts.
|
|
|
|
The first pattern can be an @tech{S-pattern}, in which case the whole
|
|
pattern matches any pair whose first element matches the first pattern
|
|
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)]{
|
|
|
|
Matches any term that can be decomposed into a list head matching some
|
|
number of repetitions of the @tech{EH-pattern} alternatives (subject
|
|
to its repetition constraints) followed by a list tail matching the
|
|
S-pattern.
|
|
|
|
In other words, the whole pattern matches either the second pattern
|
|
(which need not be a list) or a term whose head matches one of the
|
|
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[#:literals (~and) (~and S-pattern ...)]{
|
|
|
|
Matches any syntax that matches all of the included patterns.
|
|
|
|
Attributes bound in subpatterns are available to subsequent
|
|
subpatterns. The whole pattern binds all of the subpatterns'
|
|
attributes.
|
|
|
|
One use for @scheme[~and]-patterns is preserving a whole
|
|
term (including its lexical context, source location, etc) while also
|
|
examining its structure. Syntax classes are useful for the same
|
|
purpose, but @scheme[~and] can be lighter weight.
|
|
|
|
@(interaction-eval #:eval the-eval
|
|
(begin (define (check-imports . _) #f)))
|
|
|
|
@myexamples[
|
|
(syntax-parse #'(m (import one two))
|
|
#:literals (import)
|
|
[(_ (~and import-clause (import i ...)))
|
|
(let ([bad (check-imports
|
|
(syntax->list #'(i ...)))])
|
|
(when bad
|
|
(raise-syntax-error
|
|
#f "bad import" #'import-clause bad))
|
|
'ok)])
|
|
]
|
|
|
|
}
|
|
|
|
@specsubform[#:literals (~or) (~or S-pattern ...)]{
|
|
|
|
Matches any term that matches one of the included patterns.
|
|
|
|
The whole pattern binds @emph{all} of the subpatterns' attributes. An
|
|
attribute that is not bound by the ``chosen'' subpattern has a value
|
|
of @scheme[#f]. The same attribute may be bound by multiple
|
|
subpatterns, and if it is bound by all of the subpatterns, it is sure
|
|
to have a value if the whole pattern matches.
|
|
|
|
@myexamples[
|
|
(syntax-parse #'a
|
|
[(~or x:id (~and x #f)) (syntax->datum #'x)])
|
|
(syntax-parse #'#f
|
|
[(~or x:id (~and x #f)) (syntax->datum #'x)])
|
|
]
|
|
}
|
|
|
|
@specsubform[#(#, @svar[pattern-part] ...)]{
|
|
|
|
Matches a term that is a vector whose elements, when considered as a
|
|
list, match the @tech{S-pattern} corresponding to
|
|
@scheme[(pattern-part ...)].
|
|
|
|
@myexamples[
|
|
(syntax-parse #'#(1 2 3)
|
|
[#(x y z) (syntax->datum #'z)])
|
|
(syntax-parse #'#(1 2 3)
|
|
[#(x y ...) (syntax->datum #'(y ...))])
|
|
(syntax-parse #'#(1 2 3)
|
|
[#(x ~rest y) (syntax->datum #'y)])
|
|
]
|
|
|
|
}
|
|
|
|
@specsubform[#s(prefab-struct-key #, @svar[pattern-part] ...)]{
|
|
|
|
Matches a term that is a prefab struct whose key is exactly the given
|
|
key and whose sequence of fields, when considered as a list, match the
|
|
@tech{S-pattern} corresponding to @scheme[(pattern-part ...)].
|
|
|
|
@myexamples[
|
|
(syntax-parse #'#s(point 1 2 3)
|
|
[#s(point x y z) 'ok])
|
|
(syntax-parse #'#s(point 1 2 3)
|
|
[#s(point x y ...) (syntax->datum #'(y ...))])
|
|
(syntax-parse #'#s(point 1 2 3)
|
|
[#s(point x ~rest y) (syntax->datum #'y)])
|
|
]
|
|
}
|
|
|
|
@specsubform[#:literals (~rest) (~rest S-pattern)]{
|
|
|
|
Matches just like the inner @scheme[S-pattern]. The @scheme[~rest]
|
|
pattern form is useful in positions where improper lists (``dots'')
|
|
are not allowed by the reader, such as vector and structure patterns
|
|
(see above).
|
|
|
|
@myexamples[
|
|
(syntax-parse #'(1 2 3)
|
|
[(x ~rest y) (syntax->datum #'y)])
|
|
(syntax-parse #'#(1 2 3)
|
|
[#(x ~rest y) (syntax->datum #'y)])
|
|
]
|
|
}
|
|
|
|
@specsubform[#:literals (~describe) (~describe expr S-pattern)]{
|
|
|
|
The @scheme[~describe] pattern form annotates a pattern with a
|
|
description, a string expression that is evaluated in the scope of all
|
|
prior attribute bindings. If parsing the inner pattern fails, then the
|
|
description is used to synthesize the error message.
|
|
|
|
A describe-pattern also affects backtracking in two ways:
|
|
|
|
@itemize{
|
|
|
|
@item{A cut-pattern (@scheme[~!]) within a describe-pattern only
|
|
eliminates choice-points created within the describe-pattern.}
|
|
|
|
@item{If a describe-pattern succeeds, then all choice points created
|
|
within the describe-pattern are discarded, and a failure @emph{after}
|
|
the describe-pattern backtracks to a choice point @emph{before} the
|
|
describe-pattern, never one @emph{within} it.}}}
|
|
|
|
@specsubform[#:literals (~!) (~! . S-pattern)]{
|
|
|
|
The @scheme[~!] operator, pronounced ``cut'', eliminates backtracking
|
|
choice points and commits parsing to the current branch of the pattern
|
|
it is exploring.
|
|
|
|
Common opportunities for cut-patterns come from recognizing special
|
|
forms based on keywords. Consider the following expression:
|
|
|
|
@interaction[#:eval the-eval
|
|
(syntax-parse #'(define-values a 123)
|
|
#:literals (define-values define-syntaxes)
|
|
[(define-values (x:id ...) e) 'define-values]
|
|
[(define-syntaxes (x:id ...) e) 'define-syntaxes]
|
|
[e 'expression])]
|
|
|
|
Given the ill-formed term @scheme[(define-values a 123)], the
|
|
expression tries the first clause, fails to match @scheme[a] against
|
|
the pattern @scheme[(x:id ...)], and then backtracks to the second
|
|
clause and ultimately the third clause, producing the value
|
|
@scheme['expression]. But the term is not an expression; it is an
|
|
ill-formed use of @scheme[define-values]! The proper way to write the
|
|
@scheme[syntax-parse] expression follows:
|
|
|
|
@interaction[#:eval the-eval
|
|
(syntax-parse #'(define-values a 123)
|
|
#:literals (define-values define-syntaxes)
|
|
[(define-values ~! (x:id ...) e) 'define-values]
|
|
[(define-syntaxes ~! (x:id ...) e) 'define-syntaxes]
|
|
[e 'expression])]
|
|
|
|
Now, given the same term, @scheme[syntax-parse] tries the first
|
|
clause, and since the keyword @scheme[define-values] matches, the
|
|
cut-pattern commits to the current pattern, eliminating the choice
|
|
points for the second and third clauses. So when the clause fails to
|
|
match, the @scheme[syntax-parse] expression raises an error.
|
|
|
|
The effect of a @scheme[~!] pattern is delimited by the nearest
|
|
enclosing @scheme[~describe] pattern. If there is no enclosing
|
|
@scheme[~describe] pattern but the cut occurs within a syntax class
|
|
definition, then only choice points within the syntax class definition
|
|
are discarded.
|
|
}
|
|
|
|
@specsubform[#:literals (~bind) (~bind [attr-id expr] ...)]{
|
|
|
|
This pattern matches any term. Its effect is to evaluate the
|
|
@scheme[expr]s and bind them to the given @scheme[attr-id]s as
|
|
attributes.
|
|
}
|
|
|
|
@specsubform/subs[#:literals (~fail) (~fail maybe-fail-condition message-expr)
|
|
([maybe-fail-condition (code:line)
|
|
(code:line #:when condition-expr)
|
|
(code:line #:unless condition-expr)])]{
|
|
|
|
This pattern succeeds or fails independent of the term being matched
|
|
against. If the condition is absent, or if the @scheme[#:when]
|
|
condition evaluates to a true value, or if the @scheme[#:unless]
|
|
condition evaluates to @scheme[#f], then the pattern fails with the
|
|
given message. Otherwise the pattern succeeds.
|
|
|
|
Fail patterns can be used together with cut patterns to recognize
|
|
specific ill-formed terms and address them with specially-created
|
|
failure messages.
|
|
}
|
|
|
|
|
|
@subsection{H-pattern variants}
|
|
|
|
An @deftech{H-pattern} (for ``head pattern'') is a pattern that
|
|
describes some number of terms that occur at the head of some list
|
|
(possibly an improper list). An H-pattern's usefulness comes from
|
|
being able to match heads of different lengths. H-patterns are useful
|
|
for specifying optional forms such as keyword arguments.
|
|
|
|
Here are the variants of @tech{H-pattern}:
|
|
|
|
@specsubform[#:literals (~seq) (~seq . L-pattern)]{
|
|
|
|
Matches a head whose elements, if put in a list, would match the given
|
|
@tech{L-pattern}.
|
|
|
|
@myexamples[
|
|
(syntax-parse #'(1 2 3 4)
|
|
[((~seq 1 2 3) 4) 'ok])
|
|
]
|
|
}
|
|
|
|
@specsubform[#:literals (~or) (~or H-pattern ...)]{
|
|
|
|
Like the S-pattern version of @scheme[~or], but matches a term head
|
|
instead.
|
|
|
|
@myexamples[
|
|
(syntax-parse #'(#:foo 2 a b c)
|
|
[((~or (~seq #:foo x) (~seq)) y:id ...)
|
|
(attribute x)])
|
|
]
|
|
}
|
|
|
|
@specsubform[#:literals (~describe) (~describe expr H-pattern)]{
|
|
|
|
Like the S-pattern version of @scheme[~describe], but matches a head
|
|
pattern instead.
|
|
}
|
|
|
|
@specsubform[S-pattern]{
|
|
|
|
Matches a head of one element, which must be a term matching the given
|
|
@tech{S-pattern}.
|
|
}
|
|
|
|
|
|
@subsection{EH-pattern forms}
|
|
|
|
An @deftech{EH-pattern} (for ``ellipsis-head pattern'') is pattern
|
|
that describes some number of terms, like an @tech{H-pattern}, but may
|
|
also place contraints on the number of times it occurs in a
|
|
repetition. EH-patterns (and ellipses) are useful for matching keyword
|
|
arguments where the keywords may come in any order.
|
|
|
|
@myexamples[
|
|
(define parser1
|
|
(syntax-parser
|
|
[((~or (~once (~seq #:a x) #:name "#:a keyword")
|
|
(~optional (~seq #:b y) #:name "#:b keyword")
|
|
(~seq #:c z)) ...)
|
|
'ok]))
|
|
(parser1 #'(#:a 1))
|
|
(parser1 #'(#:b 2 #:c 3 #:c 25 #:a 'hi))
|
|
(parser1 #'(#:a 1 #:a 2))
|
|
]
|
|
|
|
The pattern requires exactly one occurrence of the @scheme[#:a]
|
|
keyword and argument, at most one occurrence of the @scheme[#:b]
|
|
keyword and argument, and any number of @scheme[#:c] keywords and
|
|
arguments. The ``pieces'' can occur in any order.
|
|
|
|
Here are the variants of @tech{EH-pattern}:
|
|
|
|
@specsubform/subs[#:literals (~once) (~once H-pattern once-option ...)
|
|
([once-option (code:line #:name name-expr)
|
|
(code:line #:too-few too-few-message-expr)
|
|
(code:line #:too-many too-many-message-expr)])]{
|
|
|
|
Matches if the inner H-pattern matches. This pattern must be selected
|
|
exactly once in the match of the entire repetition sequence.
|
|
|
|
If the pattern is not chosen in the repetition sequence, then an error
|
|
is raised with a message, either @scheme[too-few-message-expr] or
|
|
@schemevalfont{"missing required occurrence of @scheme[name-expr]"}.
|
|
|
|
If the pattern is chosen more than once in the repetition sequence,
|
|
then an error is raised with a message, either
|
|
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
|
of @scheme[name-expr]"}.
|
|
}
|
|
|
|
@specsubform/subs[#:literals (~optional) (~optional H-pattern optional-option ...)
|
|
([optional-option (code:line #:name name-expr)
|
|
(code:line #:too-many too-many-message-expr)])]{
|
|
|
|
Matches if the inner H-pattern matches. This pattern may be used at
|
|
most once in the match of the entire repetition.
|
|
|
|
If the pattern is chosen more than once in the repetition sequence,
|
|
then an error is raised with a message, either
|
|
@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences
|
|
of @scheme[name-expr]"}.
|
|
}
|
|
|
|
|
|
@subsection{Pattern directives}
|
|
|
|
Both @scheme[syntax-parse] and @scheme[syntax-parser] support
|
|
directives for annotating the pattern and specifying side
|
|
conditions. The grammar for pattern directives follows:
|
|
|
|
@schemegrammar[pattern-directive
|
|
(code:line #:declare pattern-id syntax-class-id)
|
|
(code:line #:declare pattern-id (syntax-class-id expr ...))
|
|
(code:line #:with syntax-pattern expr)
|
|
(code:line #:fail-when condition-expr message-expr)
|
|
(code:line #:fail-unless condition-expr message-expr)]
|
|
|
|
@specsubform[(code:line #:declare pvar-id syntax-class-id)]
|
|
@specsubform[(code:line #:declare pvar-id (syntax-class-id expr ...))]{
|
|
|
|
The first form is equivalent to using the
|
|
@svar[pvar-id:syntax-class-id] form in the pattern (but it is
|
|
illegal to use both for a single pattern variable). The
|
|
@scheme[#:declare] form may be preferred when writing macro-defining
|
|
macros or to avoid dealing with structured identifiers.
|
|
|
|
The second form allows the use of parameterized syntax classes, which
|
|
cannot be expressed using the ``colon'' notation. The @scheme[expr]s
|
|
are evaluated outside the scope of any of the attribute bindings from
|
|
pattern that the @scheme[#:declare] directive applies to.
|
|
|
|
}
|
|
|
|
@specsubform[(code:line #:with syntax-pattern expr)]{
|
|
|
|
Evaluates the @scheme[expr] in the context of all previous attribute
|
|
bindings and matches it against the pattern. If the match succeeds,
|
|
the pattern's attributes are added to environment for the evaluation
|
|
of subsequent side conditions. If the @scheme[#:with] match fails, the
|
|
matching process backtracks. Since a syntax object may match a pattern
|
|
in several ways, backtracking may cause the same clause to be tried
|
|
multiple times before the next clause is reached.
|
|
}
|
|
|
|
@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.
|
|
|
|
}
|
|
|
|
@deftogether[[
|
|
@defidform[~or]
|
|
@defidform[~and]
|
|
@defidform[~seq]
|
|
@defidform[~once]
|
|
@defidform[~optional]
|
|
@defidform[~rest]
|
|
@;{@defidform[~struct]}
|
|
@defidform[~describe]
|
|
@defidform[~!]
|
|
@defidform[~bind]
|
|
@defidform[~fail]]]{
|
|
|
|
Syntax pattern keywords, recognized by @scheme[syntax-parse].
|
|
|
|
}
|
|
|
|
@defform[(attribute attr-id)]{
|
|
|
|
Returns the value associated with the attribute named
|
|
@scheme[attr-id]. If @scheme[attr-id] is not bound as an attribute, an
|
|
error is raised. If @scheme[attr-id] is an attribute with a nonzero
|
|
ellipsis depth, then the result has the corresponding level of list
|
|
nesting.
|
|
|
|
The values returned by @scheme[attribute] never undergo additional
|
|
wrapping as syntax objects, unlike values produced by some uses of
|
|
@scheme[syntax], @scheme[quasisyntax], etc. Consequently, the
|
|
@scheme[attribute] form is preferred when the attribute value is used
|
|
as data, not placed in a syntax object.
|
|
|
|
}
|
|
|
|
@;{----------}
|
|
|
|
@section{Syntax Classes}
|
|
|
|
Syntax classes provide an abstraction mechanism for the specification
|
|
of syntax. Built-in syntax classes are supplied that recognize basic
|
|
classes such as @scheme[identifier]s and @scheme[keyword]s.
|
|
Programmers can compose basic syntax classes to build specifications
|
|
of more complex syntax, such as lists of distinct identifiers and
|
|
formal arguments with keywords. Macros that manipulate the same
|
|
syntactic structures can share syntax class definitions. The structure
|
|
of syntax classes and patterns also allows @scheme[syntax-parse] to
|
|
automatically generate error messages for syntax errors.
|
|
|
|
When a syntax class accepts (matches) a syntax object, it computes and
|
|
provides attributes based on the contents of the matched syntax. While
|
|
the values of the attributes depend on the matched syntax, the set of
|
|
attributes and each attribute's ellipsis nesting depth is fixed for
|
|
each syntax class.
|
|
|
|
@defform*/subs[#:literals (pattern basic-syntax-class)
|
|
[(define-syntax-class name-id stxclass-option ...
|
|
stxclass-variant ...+)
|
|
(define-syntax-class (name-id arg-id ...) stxclass-option ...
|
|
stxclass-variant ...+)]
|
|
([stxclass-option
|
|
(code:line #:attributes (attr-arity-decl ...))
|
|
(code:line #:description description)
|
|
(code:line #:transparent)
|
|
(code:line #:literals (literal-entry ...))
|
|
(code:line #:literal-sets (literal-set ...))
|
|
(code:line #:conventions (convention-id ...))]
|
|
[attr-arity-decl
|
|
attr-name-id
|
|
(attr-name-id depth)]
|
|
[stxclass-variant
|
|
(pattern syntax-pattern stxclass-pattern-directive ...)])]{
|
|
|
|
Defines @scheme[name-id] as a syntax class. When the @scheme[arg-id]s
|
|
are present, they are bound as variables (not pattern variables) in
|
|
the body. The body of the syntax-class definition contains a non-empty
|
|
sequence of @scheme[pattern] variants.
|
|
|
|
@specsubform[(code:line #:attributes (attr-arity-decl ...))]{
|
|
|
|
Declares the attributes of the syntax class. An attribute arity
|
|
declaration consists of the attribute name and optionally its ellipsis
|
|
depth (zero if not explicitly specified).
|
|
|
|
If the attributes are not explicitly listed, they are inferred as the
|
|
set of all pattern variables occurring in every variant of the syntax
|
|
class. Pattern variables that occur at different ellipsis depths are
|
|
not included, nor are nested attributes.
|
|
|
|
}
|
|
|
|
@specsubform[(code:line #:description description)]{
|
|
|
|
The @scheme[description] argument is an expression (evaluated in a
|
|
scope containing the syntax class's parameters) that should evaluate
|
|
to a string. It is used in error messages involving the syntax
|
|
class. For example, if a term is rejected by the syntax class, an
|
|
error of the form @schemevalfont{"expected @scheme[description]"} may
|
|
be synthesized.
|
|
|
|
If absent, the name of the syntax class is used instead.
|
|
|
|
}
|
|
|
|
@specsubform[#:transparent]{
|
|
|
|
Indicates that errors may be reported with respect to the internal
|
|
structure of the syntax class.
|
|
}
|
|
|
|
@specsubform[(code:line #:literals (literal-entry))]
|
|
@specsubform[(code:line #:literal-sets (literal-set ...))]
|
|
@specsubform[(code:line #:conventions (convention-id ...))]{
|
|
|
|
Declares the literals and conventions that apply to the syntax class's
|
|
variant patterns and their immediate @scheme[#:with] clauses. Patterns
|
|
occuring within subexpressions of the syntax class (for example, on
|
|
the right-hand side of a @scheme[#:fail-when] clause) are not
|
|
affected.
|
|
|
|
These options have the same meaning as under @scheme[syntax-parse].
|
|
}
|
|
|
|
@specsubform/subs[#:literals (pattern)
|
|
(pattern syntax-pattern stxclass-pattern-directive ...)
|
|
([stxclass-pattern-directive
|
|
pattern-directive
|
|
(code:line #:rename internal-id external-id)])]{
|
|
|
|
Accepts syntax matching the given syntax pattern with the accompanying
|
|
pattern directives as in @scheme[syntax-parse].
|
|
|
|
The attributes of the variant are the attributes of the pattern
|
|
together with all attributes bound by @scheme[#:with] clauses,
|
|
including nested attributes produced by syntax classes associated with
|
|
the pattern variables.
|
|
}
|
|
}
|
|
|
|
@defform*/subs[#:literals (pattern)
|
|
[(define-splicing-syntax-class name-id stxclass-option ...
|
|
stxclass-variant ...+)
|
|
(define-splicing-syntax-class (name-id arg-id ...) stxclass-option ...
|
|
stxclass-variant ...+)]
|
|
()]{
|
|
|
|
Defines @scheme[name-id] as a splicing syntax class. A splicing syntax
|
|
class encapsulates @tech{H-patterns} as an ordinary syntax class
|
|
encapsulates @tech{S-patterns}.
|
|
|
|
}
|
|
|
|
@defidform[pattern]{
|
|
|
|
Keyword recognized by @scheme[define-syntax-class]. It may not be
|
|
used as an expression.
|
|
}
|
|
|
|
|
|
@subsection{Attributes}
|
|
|
|
A syntax class has a set of @deftech{attribute}s. Each attribute has a
|
|
name, an ellipsis depth, and a set of nested attributes. When an
|
|
instance of the syntax class is parsed and bound to a pattern
|
|
variable, additional pattern variables are bound for each of the
|
|
syntax class's attributes. The name of these additional pattern
|
|
variables is the dotted concatenation of the primary pattern
|
|
variable with the name of the attribute.
|
|
|
|
For example, if pattern variable @scheme[p] is bound to an instance of
|
|
a syntax class with attribute @scheme[a], then the pattern variable
|
|
@scheme[p.a] is bound to the value of that attribute. The ellipsis
|
|
depth of @scheme[p.a] is the sum of the depths of @scheme[p] and
|
|
attribute @scheme[a].
|
|
|
|
The attributes of a syntax class are either given explicitly with an
|
|
@scheme[#:attributes] option or inferred from the pattern variables of
|
|
the syntax class's variants.
|
|
|
|
|
|
@subsection{Inspection tools}
|
|
|
|
The following special forms are for debugging syntax classes.
|
|
|
|
@defform[(syntax-class-attributes syntax-class-id)]{
|
|
|
|
Returns a list of the syntax class's attributes in flattened
|
|
form. Each attribute is listed by its name and ellipsis depth.
|
|
}
|
|
|
|
@defform[(syntax-class-parse syntax-class-id stx-expr arg-expr ...)]{
|
|
|
|
Runs the parser for the syntax class (parameterized by the
|
|
@scheme[arg-expr]s) on the syntax object produced by
|
|
@scheme[stx-expr]. On success, the result is a list of vectors
|
|
representing the attribute bindings of the syntax class. Each vector
|
|
contains the attribute name, depth, and associated value. On failure,
|
|
the result is some internal representation of the failure.
|
|
}
|
|
|
|
|
|
@;{----------}
|
|
|
|
@section{Literal sets and Conventions}
|
|
|
|
Sometimes the same literals are recognized in a number of different
|
|
places. The most common example is the literals for fully expanded
|
|
programs, which are used in many analysis and transformation
|
|
tools. Specifying literals individually is burdensome and error-prone.
|
|
As a remedy, @schememodname[syntax/parse] offers @deftech{literal
|
|
set}s. A literal set is defined via @scheme[define-literal-set] and
|
|
used via the @scheme[#:literal-set] option of @scheme[syntax-parse].
|
|
|
|
@defform/subs[(define-literal-set name-id (literal ...))
|
|
([literal literal-id
|
|
(pattern-id literal-id)])]{
|
|
|
|
Defines @scheme[name] as a @tech{literal set}. Each @scheme[literal]
|
|
can have a separate @scheme[pattern-id] and @scheme[literal-id]. The
|
|
@scheme[pattern-id] determines what identifiers in the pattern are
|
|
treated as literals. The @scheme[literal-id] determines what
|
|
identifiers the literal matches.
|
|
|
|
@myexamples[
|
|
(define-literal-set def-litset
|
|
(define-values define-syntaxes))
|
|
(syntax-parse #'(define-syntaxes (x) 12)
|
|
#:literal-sets (def-litset)
|
|
[(define-values (x:id ...) e:expr) 'v]
|
|
[(define-syntaxes (x:id ...) e:expr) 's])
|
|
]
|
|
|
|
}
|
|
|
|
@defform/subs[(define-conventions name-id (id-pattern syntax-class) ...)
|
|
([name-pattern exact-id
|
|
name-rx]
|
|
[syntax-class syntax-class-id
|
|
(syntax-class-id expr ...)])]{
|
|
|
|
Defines @deftech{conventions} that supply default syntax classes for
|
|
pattern variables. A pattern variable that has no explicit syntax
|
|
class is checked against each @scheme[id-pattern], and the first one
|
|
that matches determines the syntax class for the pattern. If no
|
|
@scheme[id-pattern] matches, then the pattern variable has no syntax
|
|
class.
|
|
|
|
@myexamples[
|
|
(define-conventions xyz-as-ids
|
|
[x id] [y id] [z id])
|
|
(syntax-parse #'(a b c 1 2 3)
|
|
#:conventions (xyz-as-ids)
|
|
[(x ... n ...) (syntax->datum #'(x ...))])
|
|
(define-conventions xn-prefixes
|
|
[#rx"^x" id]
|
|
[#rx"^n" nat])
|
|
(syntax-parse #'(a b c 1 2 3)
|
|
#:conventions (xn-prefixes)
|
|
[(x0 x ... n0 n ...) (syntax->datum #'(x0 (x ...) n0 (n ...)))])
|
|
]
|
|
|
|
}
|
|
|
|
@;{----------}
|
|
|
|
@section{Library syntax classes and literal sets}
|
|
|
|
@subsection{Syntax classes}
|
|
|
|
@(begin
|
|
(define-syntax-rule (defstxclass name . pre-flows)
|
|
(defidform name . pre-flows))
|
|
(define-syntax-rule (defstxclass* (name arg ...) . pre-flows)
|
|
(defform (name arg ...) . pre-flows)))
|
|
|
|
@defstxclass[expr]{
|
|
|
|
Matches anything except a keyword literal (to distinguish expressions
|
|
from the start of a keyword argument sequence). The term is not
|
|
otherwise inspected, and no guarantee is made that the term is
|
|
actually a valid expression.
|
|
|
|
}
|
|
|
|
@deftogether[(
|
|
@defstxclass[identifier]
|
|
@defstxclass[boolean]
|
|
@defstxclass[str]
|
|
@defstxclass[char]
|
|
@defstxclass[keyword]
|
|
@defstxclass[number]
|
|
@defstxclass[integer]
|
|
@defstxclass[exact-integer]
|
|
@defstxclass[exact-nonnegative-integer]
|
|
@defstxclass[exact-positive-integer])]{
|
|
|
|
Match syntax satisfying the corresponding predicates.
|
|
|
|
}
|
|
|
|
@defstxclass[id]{ Alias for @scheme[identifier]. }
|
|
@defstxclass[nat]{ Alias for @scheme[exact-nonnegative-integer]. }
|
|
|
|
@defform[(static-of predicate description)]{
|
|
|
|
Matches an identifier that is bound in the syntactic environment to
|
|
static information (see @scheme[syntax-local-value]) satisfying the
|
|
given @scheme[predicate]. If the term does not match, the
|
|
@scheme[description] argument is used to describe the expected syntax.
|
|
|
|
When used outside of the dynamic extend of a macro transformer (see
|
|
@scheme[syntax-transforming?]), matching fails.
|
|
|
|
The attribute @var[value] contains the value the name is bound to.
|
|
}
|
|
|
|
@defstxclass[static]{
|
|
|
|
Like @scheme[static-of], but matches any identifier bound to static
|
|
information (see @scheme[syntax-local-value]).
|
|
|
|
The attribute @var[value] contains the value the name is bound to.
|
|
}
|
|
|
|
@subsection{Literal sets}
|
|
|
|
@defidform[kernel-literals]{
|
|
|
|
Literal set containing the identifiers for fully-expanded expression
|
|
and definition forms (the same as provided by
|
|
@scheme[kernel-form-identifier-list]).
|
|
|
|
}
|