racket/collects/stxclass/scribblings/parsing-syntax.scrbl
Ryan Culpepper 44efc7cb48 stxclass:
fixed scoping of attributes (wrt declare)
  added 'attribute' form
  added internal/external literals form

svn: r13574
2009-02-14 12:17:14 +00:00

266 lines
8.7 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/struct
scribble/decode
(for-label scheme/base
scheme/contract
stxclass
stxclass/util))
@(define ellipses @scheme[...])
@(define (TODO . pre-flow)
(make-splice
(cons (bold "TODO: ")
(decode-content pre-flow))))
@title{Parsing Syntax}
@declare-exporting[stxclass]
This section describes @schememodname[stxclass]'s facilities for
parsing syntax.
@defform/subs[(syntax-parse stx-expr maybe-literals clause ...)
([maybe-literals code:blank
(code:line #:literals (literal ...))]
[literal id
(internal-id external-id)]
[clause (syntax-pattern pattern-directive ... expr)])]{
Evaluates @scheme[stx-expr], which should produce a syntax object, and
matches it against the patterns in order. If some pattern matches, its
pattern variables 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 syntax error indicates the first specific subterm
for which no pattern matches.
A literal in the literals list has two components: the identifier used
within the pattern to signify the positions to be matched, and the
identifier expected to occur in those positions. If the
single-identifier form is used, the same identifier is used for both
purposes.
}
@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 patterns accepted by @scheme[syntax-parse] and
@scheme[syntax-parser] follows:
@schemegrammar*[#:literals (_ ...*)
[syntax-pattern
pvar-id
pvar-id:syntax-class-id
literal-id
atomic-datum
(syntax-pattern . syntax-pattern)
(syntax-pattern #,ellipses . syntax-pattern)
((head ...+) ...* . syntax-pattern)]
[pvar-id
_
id]]
Here are the variants of @scheme[syntax-pattern]:
@specsubform[pvar-id]{
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.
}
@specsubform[pvar-id:syntax-class-id]{
Matches only subterms specified by the @scheme[_syntax-class-id]. The
syntax class's attributes are computed for the subterm and bound to
the pattern variables formed by prefixing @scheme[_pvar-id.] to the
name of the attribute. @scheme[_pvar-id] is typically bound to the
matched subterm, but the syntax class can substitute a transformed
subterm instead.
@;{(for example, @scheme[expr/c] wraps the matched
subterm in a @scheme[contract] expression).}
If @scheme[_pvar-id] is @scheme[_], no pattern variables are bound.
}
@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 ``internal'' name of an
entry in the literals list, then it represents a pattern that matches
only identifiers @scheme[free-identifier=?] to the ``external''
name. These identifiers are often the same.
}
@specsubform[atomic-datum]{
The empty list, numbers, strings, booleans, and keywords match as
literals.
}
@specsubform[(syntax-pattern . syntax-pattern)]{
Matches a syntax pair whose head matches the first pattern and whose
tail matches the second.
}
@;{
@specsubform[(syntax-splice-pattern . syntax-pattern)]{
Matches a syntax object which consists of any sequence of syntax
objects matching the splice pattern followed by a tail matching the
given tail pattern.
}
}
@specsubform[(syntax-pattern #,ellipses . syntax-pattern)]{
Matches a sequence of the first pattern ending in a tail matching the
second pattern.
That is, the sequence pattern matches either the second pattern (which
need not be a list) or a pair whose head matches the first pattern and
whose tail recursively matches the whole sequence pattern.
}
@specsubform/subs[#:literals (...*)
((head ...+) ...* . syntax-pattern)
([head
(code:line (syntax-pattern ...+) head-directive ...)]
[head-directive
(code:line #:min min-reps)
(code:line #:max max-reps)
(code:line #:mand)
#| (code:line #:opt)
(code:line #:occurs occurs-pvar-id)
(code:line #:default default-form)
|#])]{
Matches a sequence of any combination of the heads ending in a tail
matching the final pattern. The match is subject to constraints
specified on the heads.
@specsubform[(code:line #:min min-reps)]{
Requires at least @scheme[min-reps] occurrences of the preceding head
to match. @scheme[min-reps] must be a literal exact nonnegative
integer.
}
@specsubform[(code:line #:max max-reps)]{
Requires that no more than @scheme[max-reps] occurrences of the
preceeding head to match. @scheme[max-reps] must be a literal exact
nonnegative integer, and it must be greater than or equal to
@scheme[min-reps].
}
@specsubform[#:mand]{
Requires that the preceding head occur exactly once. Pattern variables
in the preceding head are not bound at a higher ellipsis nesting
depth.
}
@;{
@specsubform[#:opt]{
(Probably a bad idea.)
}
}
}
@;{
The variants of @scheme[_syntax-splice-pattern] follow:
@specsubform[pvar-id:syntax-splice-class-id]{
Matches a sequence of syntax objects described by
@scheme[_syntax-splice-class-id].
The name @scheme[_pvar-id] is bound, but not allowed within
expressions or @scheme[syntax] templates (since it does not refer to a
particular syntax object). Only the prefixed attributes of the splice
class are usable.
}
}
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 #:when 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
@scheme[_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 the pattern variable bindings.
}
@specsubform[(code:line #:with syntax-pattern expr)]{
Evaluates the @scheme[expr] in the context of all previous pattern
variable bindings and matches it against the pattern. If the match
succeeds, the new pattern variables are added to the 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 #:when expr)]{
Evaluates the @scheme[expr] in the context of all previous pattern
variable bindings. If it produces a false value, the matching process
backtracks as described above; otherwise, it continues.
}
@defidform[...*]{
Keyword recognized by @scheme[syntax-parse] etc as notation for
generalized sequences. It may not be used as an expression.
}
@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.
}