diff --git a/collects/syntax/scribblings/parse.scrbl b/collects/syntax/scribblings/parse.scrbl index 7bf33733b2..3dfcbf106e 100644 --- a/collects/syntax/scribblings/parse.scrbl +++ b/collects/syntax/scribblings/parse.scrbl @@ -2,7 +2,7 @@ @(require scribble/manual (for-label syntax/parse)) -@title[#:tag "stxparse" #:style '(toc)]{Parsing and classifying syntax} +@title[#:tag "stxparse" #:style '(toc)]{Parsing and specifying syntax} The @schememodname[syntax/parse] library provides a framework for writing macros and processing syntax. The library provides a powerful @@ -18,6 +18,7 @@ messages embedded in the macro's syntax patterns. @include-section["parse/intro.scrbl"] @include-section["parse/examples.scrbl"] @include-section["parse/parsing.scrbl"] +@include-section["parse/stxclasses.scrbl"] @include-section["parse/patterns.scrbl"] @include-section["parse/litconv.scrbl"] @include-section["parse/lib.scrbl"] diff --git a/collects/syntax/scribblings/parse/lib.scrbl b/collects/syntax/scribblings/parse/lib.scrbl index 682df96143..f65c01f7f6 100644 --- a/collects/syntax/scribblings/parse/lib.scrbl +++ b/collects/syntax/scribblings/parse/lib.scrbl @@ -6,7 +6,7 @@ "parse-common.rkt" (for-label syntax/kerncase)) -@title[#:tag "stxparse-lib"]{Library syntax classes and literal sets} +@title{Library syntax classes and literal sets} @section{Syntax classes} diff --git a/collects/syntax/scribblings/parse/litconv.scrbl b/collects/syntax/scribblings/parse/litconv.scrbl index f37b87abfe..cbcdc3f090 100644 --- a/collects/syntax/scribblings/parse/litconv.scrbl +++ b/collects/syntax/scribblings/parse/litconv.scrbl @@ -5,7 +5,7 @@ scribble/eval "parse-common.rkt") -@title[#:tag "stxparse-litconv"]{Literal sets and Conventions} +@title{Literal sets and Conventions} Sometimes the same literals are recognized in a number of different places. The most common example is the literals for fully expanded diff --git a/collects/syntax/scribblings/parse/parsing.scrbl b/collects/syntax/scribblings/parse/parsing.scrbl index 3558c0a883..f140b536e5 100644 --- a/collects/syntax/scribblings/parse/parsing.scrbl +++ b/collects/syntax/scribblings/parse/parsing.scrbl @@ -5,17 +5,17 @@ scribble/eval "parse-common.rkt") -@title[#:tag "stxparse-parsing"]{Parsing and classifying syntax} +@title{Parsing syntax} -This section describes @schememodname[syntax/parse]'s facilities for -parsing and classifying syntax. These facilities use a common language -of @tech{syntax patterns}, which is described in detail in the next -section, @secref{stxparse-patterns}. +This section describes @scheme[syntax-parse], the +@schememodname[syntax/parse] library's facility for parsing +syntax. Both @scheme[syntax-parse] and the specification facility, +@seclink["stxparse-specifying"]{syntax classes}, use a common language +of @tech{syntax patterns}, which is described in detail in +@secref{stxparse-patterns}. @declare-exporting[syntax/parse] -@section{Parsing syntax} - Two parsing forms are provided: @scheme[syntax-parse] and @scheme[syntax-parser]. @@ -124,339 +124,3 @@ expressions. Like @scheme[syntax-parse], but produces a matching procedure. The procedure accepts a single argument, which should be a syntax object. } - -@;{----------} - -@section{Classifying syntax} - -Syntax classes provide an abstraction mechanism for @tech{syntax -patterns}. Built-in syntax classes are supplied that recognize basic -classes such as @scheme[identifier] and @scheme[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. - -@defform*/subs[#:literals (pattern) - [(define-syntax-class name-id stxclass-option ... - stxclass-variant ...+) - (define-syntax-class (name-id . kw-formals) stxclass-option ... - stxclass-variant ...+)] - ([stxclass-option - (code:line #:attributes (attr-arity-decl ...)) - (code:line #:description description-expr) - (code:line #:opaque) - (code:line #:commit) - (code:line #:no-delimit-cut) - (code:line #:literals (literal-entry ...)) - (code:line #:literal-sets (literal-set ...)) - (code:line #:conventions (convention-id ...)) - (code:line #:local-conventions (convention-rule ...))] - [attr-arity-decl - attr-name-id - (attr-name-id depth)] - [stxclass-variant - (pattern syntax-pattern pattern-directive ...)]) - #:contracts ([description-expr (or/c string? #f)])]{ - -Defines @scheme[name-id] as a @deftech{syntax class}, which -encapsulates one or more @tech{single-term patterns}. - -A syntax class may have formal parameters, in which case they are -bound as variables in the body. Syntax classes support optional -arguments and keyword arguments using the same syntax as -@scheme[lambda]. The body of the syntax-class definition contains a -non-empty sequence of @scheme[pattern] variants. - -The following options are supported: - -@specsubform/subs[(code:line #: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 @tech{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 -@tech{annotated pattern variables}. -} - -@specsubform[(code:line #:description description-expr) - #:contracts ([description-expr (or/c string? #f)])]{ - -The @scheme[description] argument is evaluated in a scope containing -the syntax class's parameters. If the result is 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 -@schemevalfont{"expected @scheme[description]"} may be synthesized. If -the result is @scheme[#f], the syntax class is skipped in the search -for a description to report. - -If the option is not given absent, the name of the syntax class is -used instead. -} - -@specsubform[#:opaque]{ - -Indicates that errors should not be reported with respect to the -internal structure of the syntax class. -} - -@specsubform[#:commit]{ - -Directs the syntax class to ``commit'' to the first successful -match. When a variant succeeds, all choice points within the syntax -class are discarded. See also @scheme[~commit]. -} - -@specsubform[#:no-delimit-cut]{ - -By default, a cut (@scheme[~!]) within a syntax class only discards -choice points within the syntax class. That is, the body of the syntax -class acts as though it is wrapped in a @scheme[~delimit-cut] form. If -@scheme[#:no-delimit-cut] is specified, a cut may affect choice points -of the syntax class's calling context (another syntax class's patterns -or a @scheme[syntax-parse] form). - -It is an error to use both @scheme[#:commit] and -@scheme[#:no-delimit-cut]. -} - -@specsubform[(code:line #:literals (literal-entry))] -@specsubform[(code:line #:literal-sets (literal-set ...))] -@specsubform[(code:line #:conventions (convention-id ...))]{ - -Declares the literals and conventions that apply to the syntax class's -variant patterns and their immediate @scheme[#:with] clauses. Patterns -occuring within subexpressions of the syntax class (for example, on -the right-hand side of a @scheme[#:fail-when] clause) are not -affected. - -These options have the same meaning as in @scheme[syntax-parse]. -} - -Each variant of a syntax class is specified as a separate -@scheme[pattern]-form whose syntax pattern is a @tech{single-term -pattern}. -} - -@defform*[#:literals (pattern) - [(define-splicing-syntax-class name-id stxclass-option ... - stxclass-variant ...+) - (define-splicing-syntax-class (name-id kw-formals) stxclass-option ... - stxclass-variant ...+)]]{ - -Defines @scheme[name-id] as a @deftech{splicing syntax class}, -analogous to a @tech{syntax class} but encapsulating @tech{head -patterns} rather than @tech{single-term patterns}. - -The options are the same as for @scheme[define-syntax-class]. - -Each variant of a splicing syntax class is specified as a separate -@scheme[pattern]-form whose syntax pattern is a @tech{head pattern}. -} - -@defform[#:literals (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 @tech{pattern directives}. - -When used within @scheme[define-syntax-class], @scheme[syntax-pattern] -should be a @tech{single-term pattern}; within -@scheme[define-splicing-syntax-class], it should be a @tech{head -pattern}. - -The attributes of the variant are the attributes of the pattern -together with all attributes bound by @scheme[#:with] clauses, -including nested attributes produced by syntax classes associated with -the pattern variables. -} - -@;{--------} - -@subsection{Pattern directives} - -Both the parsing forms and syntax class definition forms support -@deftech{pattern directives} for annotating syntax patterns 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 arg ...)) - (code:line #:with syntax-pattern expr) - (code:line #:attr attr-id expr) - (code:line #:fail-when condition-expr message-expr) - (code:line #:fail-unless condition-expr message-expr) - (code:line #:when condition-expr) - (code:line #:do [def-or-expr ...])] - -@specsubform[(code:line #:declare pvar-id syntax-class-id)] -@specsubform[(code:line #:declare pvar-id (syntax-class-id arg ...))]{ - -The first form is equivalent to using the -@svar[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 @scheme[arg]s -are evaluated outside the scope of any of the attribute bindings from -pattern that the @scheme[#:declare] directive applies to. Keyword -arguments are supported, using the same syntax as in @scheme[#%app]. -} - -@specsubform[(code:line #:with syntax-pattern stx-expr)]{ - -Evaluates the @scheme[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 @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 #:attr attr-id expr)]{ - -Evaluates the @scheme[expr] in the context of all previous attribute -bindings and binds it to the attribute named by @scheme[attr-id]. The -value of @scheme[expr] need not be syntax. -} - -@specsubform[(code:line #:fail-when condition-expr message-expr) - #:contracts ([message-expr (or/c string? #f)])]{ - -Evaluates the @scheme[condition-expr] in the context of all previous -attribute bindings. If the value is any true value (not @scheme[#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. - -If the @scheme[message-expr] produces a string it is used as the -failure message; otherwise the failure is reported in terms of the -enclosing descriptions. -} - -@specsubform[(code:line #:fail-unless condition-expr message-expr) - #:contracts ([message-expr (or/c string? #f)])]{ - -Like @scheme[#:fail-when] with the condition negated. -} - -@specsubform[(code:line #:when condition-expr)]{ - -Evaluates the @scheme[condition-expr] in the context of all previous -attribute bindings. If the value is @scheme[#f], the matching process -backtracks. In other words, @scheme[#:when] is like -@scheme[#:fail-unless] without the message argument. -} - -@specsubform[(code:line #:do [def-or-expr ...])]{ - -Takes a sequence of definitions and expressions, which may be -intermixed, and evaluates them in the scope of all previous attribute -bindings. The names bound by the definitions are in scope in -the expressions of subsequent patterns and clauses. - -There is currently no way to bind attributes using a @scheme[#:do] -block. It is an error to shadow an attribute binding with a definition -in a @scheme[#:do] block. -} - - -@;{----------} - -@section{Pattern variables and attributes} - -An @deftech{attribute} is a name bound by a syntax pattern. An -attribute can be a @tech{pattern variable} itself, or it can be a -@tech{nested attribute} bound by an @tech{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 @scheme[attribute] special form. - -@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. -} - -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 @scheme[#:attr] directive or a -@scheme[~bind] pattern. - -@myexamples[ -(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)]) -] - -A syntax-valued attribute is an attribute whose value is a syntax -object or a syntax list of the appropriate @tech{ellipsis -depth}. Syntax-valued attributes can be used within @scheme[syntax], -@scheme[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. - -@myexamples[ -(syntax-parse #'((a 1) (b 2) (c 3)) - [t:table - #'(t.key ...)]) -(syntax-parse #'((a 1) (b 2) (c 3)) - [t:table - #'t.hash]) -] - -Every attribute has an associated @deftech{ellipsis depth} that -determines how it can be used in a syntax template (see the discussion -of ellipses in @scheme[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: - -@schemeblock[ -(define-syntax-class quark - (pattern (a b ...))) -(syntax-parse some-term - [(x (y:quark ...) ... z:quark) - some-code]) -] - -The syntax class @scheme[quark] exports two attributes: @scheme[a] at -depth 0 and @scheme[b] at depth 1. The @scheme[syntax-parse] pattern -has three pattern variables: @scheme[x] at depth 0, @scheme[y] at -depth 2, and @scheme[z] at depth 0. Since @scheme[x] and @scheme[y] -are annotated with the @scheme[quark] syntax class, the pattern also -binds the following nested attributes: @scheme[y.a] at depth 2, -@scheme[y.b] at depth 3, @scheme[z.a] at depth 0, and @scheme[z.b] at -depth 1. - -An attribute's ellipsis nesting depth is @emph{not} a guarantee that -its value has that level of list nesting. In particular, @scheme[~or] -and @scheme[~optional] patterns may result in attributes with fewer -than expected levels of list nesting. - -@(myexamples - (syntax-parse #'(1 2 3) - [(~or (x:id ...) _) - (attribute x)])) diff --git a/collects/syntax/scribblings/parse/stxclasses.scrbl b/collects/syntax/scribblings/parse/stxclasses.scrbl new file mode 100644 index 0000000000..a34008d138 --- /dev/null +++ b/collects/syntax/scribblings/parse/stxclasses.scrbl @@ -0,0 +1,342 @@ +#lang scribble/doc +@(require scribble/manual + scribble/struct + scribble/decode + scribble/eval + "parse-common.rkt") + +@title[#:tag "stxparse-specifying"]{Specifying syntax with syntax classes} + +@declare-exporting[syntax/parse] + +Syntax classes provide an abstraction mechanism for @tech{syntax +patterns}. Built-in syntax classes are supplied that recognize basic +classes such as @scheme[identifier] and @scheme[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. + +@defform*/subs[#:literals (pattern) + [(define-syntax-class name-id stxclass-option ... + stxclass-variant ...+) + (define-syntax-class (name-id . kw-formals) stxclass-option ... + stxclass-variant ...+)] + ([stxclass-option + (code:line #:attributes (attr-arity-decl ...)) + (code:line #:description description-expr) + (code:line #:opaque) + (code:line #:commit) + (code:line #:no-delimit-cut) + (code:line #:literals (literal-entry ...)) + (code:line #:literal-sets (literal-set ...)) + (code:line #:conventions (convention-id ...)) + (code:line #:local-conventions (convention-rule ...))] + [attr-arity-decl + attr-name-id + (attr-name-id depth)] + [stxclass-variant + (pattern syntax-pattern pattern-directive ...)]) + #:contracts ([description-expr (or/c string? #f)])]{ + +Defines @scheme[name-id] as a @deftech{syntax class}, which +encapsulates one or more @tech{single-term patterns}. + +A syntax class may have formal parameters, in which case they are +bound as variables in the body. Syntax classes support optional +arguments and keyword arguments using the same syntax as +@scheme[lambda]. The body of the syntax-class definition contains a +non-empty sequence of @scheme[pattern] variants. + +The following options are supported: + +@specsubform/subs[(code:line #: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 @tech{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 +@tech{annotated pattern variables}. +} + +@specsubform[(code:line #:description description-expr) + #:contracts ([description-expr (or/c string? #f)])]{ + +The @scheme[description] argument is evaluated in a scope containing +the syntax class's parameters. If the result is 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 +@schemevalfont{"expected @scheme[description]"} may be synthesized. If +the result is @scheme[#f], the syntax class is skipped in the search +for a description to report. + +If the option is not given absent, the name of the syntax class is +used instead. +} + +@specsubform[#:opaque]{ + +Indicates that errors should not be reported with respect to the +internal structure of the syntax class. +} + +@specsubform[#:commit]{ + +Directs the syntax class to ``commit'' to the first successful +match. When a variant succeeds, all choice points within the syntax +class are discarded. See also @scheme[~commit]. +} + +@specsubform[#:no-delimit-cut]{ + +By default, a cut (@scheme[~!]) within a syntax class only discards +choice points within the syntax class. That is, the body of the syntax +class acts as though it is wrapped in a @scheme[~delimit-cut] form. If +@scheme[#:no-delimit-cut] is specified, a cut may affect choice points +of the syntax class's calling context (another syntax class's patterns +or a @scheme[syntax-parse] form). + +It is an error to use both @scheme[#:commit] and +@scheme[#:no-delimit-cut]. +} + +@specsubform[(code:line #:literals (literal-entry))] +@specsubform[(code:line #:literal-sets (literal-set ...))] +@specsubform[(code:line #:conventions (convention-id ...))]{ + +Declares the literals and conventions that apply to the syntax class's +variant patterns and their immediate @scheme[#:with] clauses. Patterns +occuring within subexpressions of the syntax class (for example, on +the right-hand side of a @scheme[#:fail-when] clause) are not +affected. + +These options have the same meaning as in @scheme[syntax-parse]. +} + +Each variant of a syntax class is specified as a separate +@scheme[pattern]-form whose syntax pattern is a @tech{single-term +pattern}. +} + +@defform*[#:literals (pattern) + [(define-splicing-syntax-class name-id stxclass-option ... + stxclass-variant ...+) + (define-splicing-syntax-class (name-id kw-formals) stxclass-option ... + stxclass-variant ...+)]]{ + +Defines @scheme[name-id] as a @deftech{splicing syntax class}, +analogous to a @tech{syntax class} but encapsulating @tech{head +patterns} rather than @tech{single-term patterns}. + +The options are the same as for @scheme[define-syntax-class]. + +Each variant of a splicing syntax class is specified as a separate +@scheme[pattern]-form whose syntax pattern is a @tech{head pattern}. +} + +@defform[#:literals (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 @tech{pattern directives}. + +When used within @scheme[define-syntax-class], @scheme[syntax-pattern] +should be a @tech{single-term pattern}; within +@scheme[define-splicing-syntax-class], it should be a @tech{head +pattern}. + +The attributes of the variant are the attributes of the pattern +together with all attributes bound by @scheme[#:with] clauses, +including nested attributes produced by syntax classes associated with +the pattern variables. +} + +@;{--------} + +@section{Pattern directives} + +Both the parsing forms and syntax class definition forms support +@deftech{pattern directives} for annotating syntax patterns 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 arg ...)) + (code:line #:with syntax-pattern expr) + (code:line #:attr attr-id expr) + (code:line #:fail-when condition-expr message-expr) + (code:line #:fail-unless condition-expr message-expr) + (code:line #:when condition-expr) + (code:line #:do [def-or-expr ...])] + +@specsubform[(code:line #:declare pvar-id syntax-class-id)] +@specsubform[(code:line #:declare pvar-id (syntax-class-id arg ...))]{ + +The first form is equivalent to using the +@svar[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 @scheme[arg]s +are evaluated outside the scope of any of the attribute bindings from +pattern that the @scheme[#:declare] directive applies to. Keyword +arguments are supported, using the same syntax as in @scheme[#%app]. +} + +@specsubform[(code:line #:with syntax-pattern stx-expr)]{ + +Evaluates the @scheme[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 @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 #:attr attr-id expr)]{ + +Evaluates the @scheme[expr] in the context of all previous attribute +bindings and binds it to the attribute named by @scheme[attr-id]. The +value of @scheme[expr] need not be syntax. +} + +@specsubform[(code:line #:fail-when condition-expr message-expr) + #:contracts ([message-expr (or/c string? #f)])]{ + +Evaluates the @scheme[condition-expr] in the context of all previous +attribute bindings. If the value is any true value (not @scheme[#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. + +If the @scheme[message-expr] produces a string it is used as the +failure message; otherwise the failure is reported in terms of the +enclosing descriptions. +} + +@specsubform[(code:line #:fail-unless condition-expr message-expr) + #:contracts ([message-expr (or/c string? #f)])]{ + +Like @scheme[#:fail-when] with the condition negated. +} + +@specsubform[(code:line #:when condition-expr)]{ + +Evaluates the @scheme[condition-expr] in the context of all previous +attribute bindings. If the value is @scheme[#f], the matching process +backtracks. In other words, @scheme[#:when] is like +@scheme[#:fail-unless] without the message argument. +} + +@specsubform[(code:line #:do [def-or-expr ...])]{ + +Takes a sequence of definitions and expressions, which may be +intermixed, and evaluates them in the scope of all previous attribute +bindings. The names bound by the definitions are in scope in +the expressions of subsequent patterns and clauses. + +There is currently no way to bind attributes using a @scheme[#:do] +block. It is an error to shadow an attribute binding with a definition +in a @scheme[#:do] block. +} + + +@;{----------} + +@section{Pattern variables and attributes} + +An @deftech{attribute} is a name bound by a syntax pattern. An +attribute can be a @tech{pattern variable} itself, or it can be a +@tech{nested attribute} bound by an @tech{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 @scheme[attribute] special form. + +@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. +} + +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 @scheme[#:attr] directive or a +@scheme[~bind] pattern. + +@myexamples[ +(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)]) +] + +A syntax-valued attribute is an attribute whose value is a syntax +object or a syntax list of the appropriate @tech{ellipsis +depth}. Syntax-valued attributes can be used within @scheme[syntax], +@scheme[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. + +@myexamples[ +(syntax-parse #'((a 1) (b 2) (c 3)) + [t:table + #'(t.key ...)]) +(syntax-parse #'((a 1) (b 2) (c 3)) + [t:table + #'t.hash]) +] + +Every attribute has an associated @deftech{ellipsis depth} that +determines how it can be used in a syntax template (see the discussion +of ellipses in @scheme[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: + +@schemeblock[ +(define-syntax-class quark + (pattern (a b ...))) +(syntax-parse some-term + [(x (y:quark ...) ... z:quark) + some-code]) +] + +The syntax class @scheme[quark] exports two attributes: @scheme[a] at +depth 0 and @scheme[b] at depth 1. The @scheme[syntax-parse] pattern +has three pattern variables: @scheme[x] at depth 0, @scheme[y] at +depth 2, and @scheme[z] at depth 0. Since @scheme[x] and @scheme[y] +are annotated with the @scheme[quark] syntax class, the pattern also +binds the following nested attributes: @scheme[y.a] at depth 2, +@scheme[y.b] at depth 3, @scheme[z.a] at depth 0, and @scheme[z.b] at +depth 1. + +An attribute's ellipsis nesting depth is @emph{not} a guarantee that +its value has that level of list nesting. In particular, @scheme[~or] +and @scheme[~optional] patterns may result in attributes with fewer +than expected levels of list nesting. + +@(myexamples + (syntax-parse #'(1 2 3) + [(~or (x:id ...) _) + (attribute x)]))