On this page:
8.2.1 Parsing syntax
syntax-parse
syntax-parser
8.2.2 Classifying syntax
define-syntax-class
define-splicing-syntax-class
pattern
8.2.3 Pattern directives
8.2.4 Pattern variables and attributes
attribute
8.2.5 Inspection tools
syntax-class-attributes
syntax-class-parse

8.2 Parsing and classifying syntax

This section describes syntax/parse’s facilities for parsing and classifying syntax. These facilities use a common language of syntax patterns, which is described in detail in the next section, Syntax patterns.

8.2.1 Parsing syntax

Two parsing forms are provided: syntax-parse and syntax-parser.

(syntax-parse stx-expr parse-option ... clause ...+)
 
parse-option = #:context context-expr
  | #:literals (literal ...)
  | #:literal-sets (literal-set ...)
  | #:conventions (convention-id ...)
  | #:local-conventions (convention-rule ...)
     
literal = literal-id
  | (pattern-id literal-id)
  | (pattern-id literal-id #:phase phase-expr)
     
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 ... expr ...+)
 
  stx-expr : syntax?
Evaluates stx-expr, which should produce a syntax object, and matches it against the clauses 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 expr is evaluated. The result is the result of 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 following options are supported:

#:context context-expr
 
  context-expr : syntax?

When present, context-expr is used in reporting parse failures; otherwise stx-expr is used.

Examples:

  > (syntax-parse #'(a b 3)
      [(x:id ...) 'ok])

  a: expected identifier at: 3

  > (syntax-parse #'(a b 3)
      #:context #'(lambda (a b 3) (+ a b))
      [(x:id ...) 'ok])

  lambda: expected identifier at: 3

#:literals (literal ...)
 
literal = literal-id
  | (pattern-id literal-id)
  | (pattern-id literal-id #:phase phase-expr)

Unlike syntax-case, syntax-parse requires all literals to have a binding. To match identifiers by their symbolic names, use 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.

#:literal-sets (literal-set ...)
 
literal-set = literal-set-id
  | (literal-set-id literal-set-option ...)
     
literal-set-option = #:at context-id
  | #:phase phase-expr

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.

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

Each clause consists of a syntax pattern, an optional sequence of pattern directives, and a non-empty sequence of body expressions.

(syntax-parser parse-option ... clause ...+)
Like syntax-parse, but produces a matching procedure. The procedure accepts a single argument, which should be a syntax object.

8.2.2 Classifying syntax

Syntax classes provide an abstraction mechanism for syntax patterns. Built-in syntax classes are supplied that recognize basic classes such as identifier and keyword. 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.

(define-syntax-class name-id stxclass-option ...
  stxclass-variant ...+)
(define-syntax-class (name-id arg-id ...) stxclass-option ...
  stxclass-variant ...+)
 
stxclass-option = #:attributes (attr-arity-decl ...)
  | #:description description-expr
  | #:opaque
  | #:literals (literal-entry ...)
  | #:literal-sets (literal-set ...)
  | #:conventions (convention-id ...)
  | #:local-conventions (convention-rule ...)
     
attr-arity-decl = attr-name-id
  | (attr-name-id depth)
     
stxclass-variant = (pattern syntax-pattern pattern-directive ...)
Defines name-id as a syntax class, which encapsulates one or more single-term patterns.

When the arg-ids are present, they are bound as variables in the body. The body of the syntax-class definition contains a non-empty sequence of pattern variants.

The following options are supported:

#:attributes (attr-arity-decl ...)
 
attr-arity-decl = attr-id
  | (attr-id depth)

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 from annotated pattern variables.

#:description description-expr

The 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 "expected description" may be synthesized.

If absent, the name of the syntax class is used instead.

#:opaque

Indicates that errors should not be reported with respect to the internal structure of the syntax class.

#:literals (literal-entry)
#:literal-sets (literal-set ...)
#:conventions (convention-id ...)

Declares the literals and conventions that apply to the syntax class’s variant patterns and their immediate #:with clauses. Patterns occuring within subexpressions of the syntax class (for example, on the right-hand side of a #:fail-when clause) are not affected.

These options have the same meaning as in syntax-parse.

Each variant of a syntax class is specified as a separate pattern-form whose syntax pattern is a single-term pattern.

(define-splicing-syntax-class name-id stxclass-option ...
  stxclass-variant ...+)
(define-splicing-syntax-class (name-id arg-id ...) stxclass-option ...
  stxclass-variant ...+)
Defines name-id as a splicing syntax class, analogous to a syntax class but encapsulating head patterns rather than single-term patterns.

The options are the same as for define-syntax-class.

Each variant of a splicing syntax class is specified as a separate pattern-form whose syntax pattern is a head pattern.

(pattern syntax-pattern pattern-directive ...)
Used to indicate a variant of a syntax class or splicing syntax class. The variant accepts syntax matching the given syntax pattern with the accompanying pattern directives.

When used within define-syntax-class, syntax-pattern should be a single-term pattern; within define-splicing-syntax-class, it should be a head pattern.

The attributes of the variant are the attributes of the pattern together with all attributes bound by #:with clauses, including nested attributes produced by syntax classes associated with the pattern variables.

8.2.3 Pattern directives

Both the parsing forms and syntax class definition forms support pattern directives for annotating syntax patterns and specifying side conditions. The grammar for pattern directives follows:

  pattern-directive = #:declare pattern-id syntax-class-id
  | #:declare pattern-id (syntax-class-id expr ...)
  | #:with syntax-pattern expr
  | #:attr attr-id expr
  | #:fail-when condition-expr message-expr
  | #:fail-unless condition-expr message-expr
  | #:when condition-expr

#:declare pvar-id syntax-class-id
#:declare pvar-id (syntax-class-id expr ...)

The first form is equivalent to using the pvar-id:syntax-class-id form in the pattern (but it is illegal to use both for the same pattern variable).

The second form allows the use of parameterized syntax classes, which cannot be expressed using the “colon” notation. The exprs are evaluated outside the scope of any of the attribute bindings from pattern that the #:declare directive applies to.

#:with syntax-pattern stx-expr

Evaluates the stx-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 #: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.

#:attr attr-id expr

Evaluates the expr in the context of all previous attribute bindings and binds it to the attribute named by attr-id. The value of expr need not be syntax.

#:fail-when condition-expr message-expr

Evaluates the condition-expr in the context of all previous attribute bindings. If the value is any true value (not #f), the matching process backtracks (with the given message); otherwise, it continues. If the value of the condition expression is a syntax object, it is indicated as the cause of the error.

#:fail-unless condition-expr message-expr

Like #:fail-when with the condition negated.

#:when condition-expr

Evaluates the condition-expr in the context of all previous attribute bindings. If the value is #f, the matching process backtracks. In other words, #:when is like #:fail-unless without the message argument.

8.2.4 Pattern variables and attributes

An attribute is a name bound by a syntax pattern. An attribute can be a pattern variable itself, or it can be a nested attribute bound by an annotated pattern variable. The name of a nested attribute is computed by concatenating the pattern variable name with the syntax class’s exported attribute’s name, separated by a dot (see the example below).

Attribute names cannot be used directly as expressions; that is, attributes are not variables. Instead, an attribute’s value can be gotten using the attribute special form.

(attribute attr-id)
Returns the value associated with the attribute named attr-id. If attr-id is not bound as an attribute, an error is raised.

The value of an attribute need not be syntax. Non-syntax-valued attributes can be used to return a parsed representation of a subterm or the results of an analysis on the subterm. A non-syntax-valued attribute should be bound using the #:attr directive or a ~bind pattern.

Examples:

  > (define-syntax-class table
      (pattern ((key value) ...)
               #:attr hash
                      (for/hash ([k (syntax->datum #'(key ...))]
                                 [v (syntax->datum #'(value ...))])
                        (values k v))))
  > (syntax-parse #'((a 1) (b 2) (c 3))
      [t:table
       (attribute t.hash)])

  '#hash((b . 2) (a . 1) (c . 3))

A syntax-valued attribute is an attribute whose value is a syntax object or a syntax list of the appropriate ellipsis depth. Syntax-valued attributes can be used within syntax, quasisyntax, etc as part of a syntax template. If a non-syntax-valued attribute is used in a syntax template, a runtime error is signalled.

Examples:

  > (syntax-parse #'((a 1) (b 2) (c 3))
      [t:table
       #'(t.key ...)])

  #<syntax:6:0 (a b c)>

  > (syntax-parse #'((a 1) (b 2) (c 3))
      [t:table
       #'t.hash])

  t.hash: attribute is bound to non-syntax value: '#hash((b .

  2) (a . 1) (c . 3)) at: t.hash

Every attribute has an associated ellipsis depth that determines how it can be used in a syntax template (see the discussion of ellipses in syntax). For a pattern variable, the ellipsis depth is the number of ellipses the pattern variable “occurs under” in the pattern. For a nested attribute the depth is the sum of the pattern variable’s depth and the depth of the attribute in the syntax class. Consider the following code:

  (define-syntax-class quark
    (pattern (a b ...)))
  (syntax-parse some-term
    [(x (y:quark ...) ... z:quark)
     some-code])

The syntax class quark exports two attributes: a at depth 0 and b at depth 1. The syntax-parse pattern has three pattern variables: x at depth 0, y at depth 2, and z at depth 0. Since x and y are annotated with the quark syntax class, the pattern also binds the following nested attributes: y.a at depth 2, y.b at depth 3, z.a at depth 0, and z.b at depth 1.

An attribute’s ellipsis nesting depth is not a guarantee that its value has that level of list nesting. In particular, ~or and ~optional patterns may result in attributes with fewer than expected levels of list nesting.

Example:

  > (syntax-parse #'(1 2 3)
      [(~or (x:id ...) _)
       (attribute x)])

  #f

8.2.5 Inspection tools

The following special forms are for debugging syntax classes.

(syntax-class-attributes syntax-class-id)
Returns a list of the syntax class’s attributes. Each attribute is listed by its name and ellipsis depth.

(syntax-class-parse syntax-class-id stx-expr arg-expr ...)
Runs the parser for the syntax class (parameterized by the arg-exprs) on the syntax object produced by 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.