1.3 Parsing Syntax
This section describes syntax-parse, the syntax/parse library’s facility for parsing syntax. Both syntax-parse and the specification facility, syntax classes, use a common language of syntax patterns, which is described in detail in Syntax Patterns.
Two parsing forms are provided: syntax-parse and syntax-parser.
syntax
(syntax-parse stx-expr parse-option ... clause ...+)
parse-option = #:context context-expr | #:literals (literal ...) | #:datum-literals (datum-literal ...) | #:literal-sets (literal-set ...) | #:track-literals | #:conventions (convention-id ...) | #:local-conventions (convention-rule ...) | #:disable-colon-notation literal = literal-id | (pattern-id literal-id) | (pattern-id literal-id #:phase phase-expr) datum-literal = literal-id | (pattern-id literal-id) literal-set = literal-set-id | (literal-set-id literal-set-option ...) literal-set-option = #:at context-id | #:phase phase-expr clause = (syntax-pattern pattern-directive ... body ...+)
stx-expr : syntax?
context-expr :
(or/c syntax? symbol? #f (list/c symbol? syntax?))
phase-expr : (or/c exact-integer? #f)
Each clause consists of a syntax pattern, an optional sequence of pattern directives, and a non-empty sequence of body forms.
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 following options are supported:
#:context context-expr
context-expr :
(or/c syntax? symbol? #f (list/c symbol? syntax?)) When present, context-expr is used in reporting parse failures; otherwise stx-expr is used. If context-expr evaluates to (list who context-stx), then who appears in the error message as the form raising the error, and context-stx is used as the term. If context-expr evaluates to a symbol, it is used as who and stx-expr (the syntax to be destructured) is used as context-stx. If context-expr evaluates to a syntax object, it is used as context-stx and who is inferred as with raise-syntax-error.
The current-syntax-context parameter is also set to the syntax object context-stx.
Examples:
> (syntax-parse #'(a b 3) [(x:id ...) 'ok]) a: expected identifier
at: 3
in: (a b 3)
> (syntax-parse #'(a b 3) #:context #'(lambda (a b 3) (+ a b)) [(x:id ...) 'ok]) lambda: expected identifier
at: 3
in: (lambda (a b 3) (+ a b))
> (syntax-parse #'(a b 3) #:context 'check-id-list [(x:id ...) 'ok]) check-id-list: expected identifier
at: 3
in: (a b 3)
#:literals (literal ...)
literal = literal-id | (pattern-id literal-id) | (pattern-id literal-id #:phase phase-expr)
phase-expr : (or/c exact-integer? #f) Unlike syntax-case, syntax-parse requires all literals to have a binding. To match identifiers by their symbolic names, use #:datum-literals or the ~datum pattern form instead. The #:literals option specifies identifiers that should be treated as literals rather than pattern variables. An entry in the literals list has two components: the identifier used within the pattern to signify the positions to be matched (pattern-id), and the identifier expected to occur in those positions (literal-id). If the entry is a single identifier, that identifier is used for both purposes.
If the #:phase option is given, then the literal is compared at phase phase-expr. Specifically, the binding of the literal-id at phase phase-expr must match the input’s binding at phase phase-expr.
In other words, the syntax-patterns are interpreted as if each occurrence of pattern-id were replaced with the following pattern:(~literal literal-id #:phase phase-expr)
#:datum-literals (datum-literal ...)
datum-literal = literal-id | (pattern-id literal-id) Like #:literals, but the literals are matched as symbols instead of as identifiers.
In other words, the syntax-patterns are interpreted as if each occurrence of pattern-id were replaced with the following pattern:(~datum literal-id)
#:literal-sets (literal-set ...)
literal-set = literal-set-id | (literal-set-id literal-set-option ...) literal-set-option = #:at lctx | #:phase phase-expr
phase-expr : (or/c exact-integer? #f) Many literals can be declared at once via one or more literal sets, imported with the #:literal-sets option. See literal sets for more information.
If the #:at keyword is given, the lexical context of the lctx term is used to determine which identifiers in the patterns are treated as literals; this option is useful primarily for macros that generate syntax-parse expressions.
#:track-literals If specified, each final body expression is further constrained to produce a single value, which must be a syntax object, and its 'disappeared-use syntax property is automatically extended to include literals matched as part of pattern-matching. Literals are automatically tracked from uses of #:literals, #:literal-sets, or ~literal, but they can also be manually tracked using syntax-parse-state-cons!. The property is added or extended in the same way as a property added by syntax-parse-track-literals.
Due to the way the body forms are wrapped, specifying this option means the final body form will no longer be in tail position with respect to the enclosing syntax-parse form.
Added in version 6.90.0.29 of package base.
#:conventions (conventions-id ...) Imports conventions that give default syntax classes to pattern variables that do not explicitly specify a syntax class.
#:local-conventions (convention-rule ...) Uses the conventions specified. The advantage of #:local-conventions over #:conventions is that local conventions can be in the scope of syntax-class parameter bindings. See the section on conventions for examples.
#:disable-colon-notation Suppresses the “colon notation” for annotated pattern variables.
Examples:
> (syntax-parse #'(a b c) [(x:y ...) 'ok]) syntax-parse: not defined as syntax class (config=yes)
at: y
in: (syntax-parse (syntax (a b c)) ((x:y ...) (quote ok)))
> (syntax-parse #'(a b c) #:disable-colon-notation [(x:y ...) 'ok]) 'ok
syntax
(syntax-parser parse-option ... clause ...+)
syntax
(define/syntax-parse syntax-pattern pattern-directive ... stx-expr)
stx-expr : syntax?
> (define/syntax-parse ((~seq kw:keyword arg:expr) ...) #'(#:a 1 #:b 2 #:c 3)) > #'(kw ...) #<syntax:eval:7:0 (#:a #:b #:c)>
Compare with define/with-syntax, a similar definition form that uses the simpler syntax-case patterns.