#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. }