On this page:
attribute

8.3 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 coming from the syntax class of some 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. If attr-id is an attribute with a nonzero ellipsis depth, then the result has the corresponding level of list nesting.

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:41: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 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