diff --git a/collects/syntax/scribblings/parse-patterns.scrbl b/collects/syntax/scribblings/parse-patterns.scrbl new file mode 100644 index 0000000000..103d707716 --- /dev/null +++ b/collects/syntax/scribblings/parse-patterns.scrbl @@ -0,0 +1,711 @@ +#lang scribble/doc +@(require scribble/manual + scribble/struct + scribble/decode + scribble/eval + scheme/sandbox + (for-label scheme/base + scheme/contract + syntax/parse + syntax/kerncase)) + +@(define ellipses @scheme[...]) +@(define-syntax-rule (defhere id) (defidentifier #'id #:form? #t)) + +@(begin + (define-syntax ref + (syntax-rules () + [(ref id suffix ...) + (elemref (list 'pattern-link (list 'id 'suffix ...)) + (schemekeywordfont (symbol->string 'id)) + (superscript (symbol->string 'suffix)) ... + #:underline? #f)])) + (define-syntax def + (syntax-rules () + [(def id suffix ...) + (elemtag (list 'pattern-link (list 'id 'suffix ...)) + (scheme id) + #|(superscript (symbol->string 'suffix)) ...|# )]))) + +@(begin + (define (fixup exn) + (let ([src (ormap values (exn:fail:syntax-exprs exn))]) + (if src + (make-exn:fail:syntax + (format "~a at: ~a" (exn-message exn) (syntax->datum src)) + (exn-continuation-marks exn) + (exn:fail:syntax-exprs exn)) + exn))) + (define the-eval + (parameterize ((sandbox-output 'string) + (sandbox-error-output 'string) + (sandbox-make-code-inspector current-code-inspector) + (sandbox-eval-handlers + (list #f + (lambda (thunk) + (with-handlers ([exn:fail:syntax? + (lambda (e) (raise (fixup e)))]) + (thunk)))))) + (make-evaluator 'scheme/base + #:requires '(syntax/parse (for-syntax scheme/base))))) + (the-eval '(error-print-source-location #f)) + (define-syntax-rule (myexamples e ...) + (examples #:eval the-eval e ...))) + +@title[#:tag "syntax-patterns"]{Syntax patterns} + +The grammar of @deftech{syntax patterns} used by +@schememodname[syntax/parse] facilities is given in the following +table. There are three main kinds of syntax pattern: @tech{S-patterns} +(for ``single-term patterns''), @tech{H-patterns} (for ``head +patterns''), and @tech{EH-patterns} (for ``ellipsis head +patterns''). A fourth kind, @tech{L-patterns} (for ``list patterns''), +is a restricted subset of @tech{S-patterns}. + +When a special form in this manual refers to @svar[syntax-pattern] +(eg, the description of the @scheme[syntax-parse] special form), it +means specifically @tech{S-pattern}. + +@schemegrammar*[#:literals (_ ~var ~literal ~or ~and ~not ~seq + ~rep ~once ~optional + ~rest ~struct ~! ~describe ~bind ~fail) + [S-pattern + pvar-id + pvar-id:syntax-class-id + literal-id + (@#,ref[~var s-] id) + (@#,ref[~var s+] id syntax-class) + (~literal literal-id) + atomic-datum + (H-pattern . S-pattern) + ((@#,ref[~or eh] EH-pattern ...+) #,ellipses . S-pattern) + (EH-pattern #,ellipses . S-pattern) + (@#,ref[~and s] S-pattern ...+) + (@#,ref[~or s] S-pattern ...+) + (~not S-pattern) + #((unsyntax @svar[pattern-part]) ...) + #s(prefab-struct-key (unsyntax @svar[pattern-part]) ...) + (~rest S-pattern) + (@#,ref[~describe s] expr S-pattern) + (~! . S-pattern) + (~bind [attr-id expr] ...) + (~fail maybe-fail-condition message-expr)] + [L-pattern + () + (H-pattern . L-pattern) + ((@#,ref[~or eh] EH-pattern ...+) #,ellipses . L-pattern) + (EH-pattern #,ellipses . L-pattern) + (~rest L-pattern) + (~! . L-pattern)] + [H-pattern + pvar-id:splicing-syntax-class-id + (@#,ref[~var h] id splicing-syntax-class) + (~seq . L-pattern) + (@#,ref[~and h] strict-H-pattern ...+) + (@#,ref[~or h] H-pattern ...+) + (@#,ref[~optional h] H-pattern maybe-optional-option) + (@#,ref[~describe h] expr H-pattern) + S-pattern] + [EH-pattern + (~once H-pattern once-option ...) + (@#,ref[~optional eh] H-pattern optional-option ...) + H-pattern]] + +The following pattern keywords can be used in multiple pattern +variants: + +@defidform[~var]{ + +Pattern keyword; see @ref[~var s-], @ref[~var s+], or @ref[~var h]. +} + +@defidform[~and]{ + +Pattern keyword; see @ref[~and s] or @ref[~and h]. +} + +@defidform[~or]{ + +Pattern keyword; see @ref[~or s], @ref[~or h]), or @ref[~or eh]. +} + +@defidform[~describe]{ + +Pattern keyword; see @ref[~describe s] or @ref[~describe h]. +} + +@defidform[~optional]{ + +Pattern keyword; see @ref[~optional h] or @ref[~optional eh]. +} + + +@;{--------} + +@section{S-pattern variants} + +An @deftech{S-pattern} (for ``single-term pattern'') is a pattern that +describes a single term. The pattern may, of course, consist of other +parts. For example, @scheme[(17 ...)] is an @tech{S-pattern} +that matches any term that is a proper list of repeated +@schemeresult[17] numerals. The @deftech{L-pattern}s (for ``list +pattern'') are @tech{S-pattern} having a restricted structure that +constrains it to match only terms that are proper lists. + +Here are the variants of @tech{S-pattern}: + +@specsubform[id]{ + +An identifier can be either a @tech{pattern variable}, an +@tech{annotated pattern variable}, or a @tech{literal}: + +@itemize[ + +@item{If @scheme[id] is the ``pattern'' name of an entry in the + literals list, it is a @tech{literal} pattern that behaves + like @scheme[(~literal id)]. + + @myexamples[ + (syntax-parse #'(define x 12) + #:literals (define) + [(define var:id body:expr) 'ok]) + (syntax-parse #'(lambda x 12) + #:literals (define) + [(define var:id body:expr) 'ok]) + (syntax-parse #'(define x 12) + #:literals ([def define]) + [(def var:id body:expr) 'ok]) + (syntax-parse #'(lambda x 12) + #:literals ([def define]) + [(def var:id body:expr) 'ok]) + ] +} + +@item{If @scheme[id] is of the form @scheme[_pvar-id:syntax-class-id] + (that is, two names joined by a colon character), it is an + @tech{annotated pattern variable}, and the pattern is equivalent to + @scheme[(~var pvar-id syntax-class-id)]. + + @myexamples[ + (syntax-parse #'a + [var:id (syntax-e #'var)]) + (syntax-parse #'12 + [var:id (syntax-e #'var)]) + (define-syntax-class two + #:attributes (x y) + (pattern (x y))) + (syntax-parse #'(a b) + [t:two (syntax->datum #'(t t.x t.y))]) + (syntax-parse #'(a b) + [t + #:declare t two + (syntax->datum #'(t t.x t.y))]) + ] +} + +@item{Otherwise, @scheme[id] is a @tech{pattern variable}, and the +pattern is equivalent to @scheme[(~var id)]. +} +] +} + +@specsubform[(@#,def[~var s-] pvar-id)]{ + +A @deftech{pattern variable}. If @scheme[pvar-id] has no syntax class +(by @scheme[#:convention]), the pattern variable 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. + +If @scheme[pvar-id] does have an associated syntax class, it behaves +like an @tech{annotated pattern variable} with the implicit syntax +class inserted. +} + +@specsubform/subs[(@#,def[~var s+] pvar-id syntax-class) + ([syntax-class syntax-class-id + (syntax-class-id arg-expr ...)])]{ + +An @deftech{annotated pattern variable}. The pattern matches only +terms accepted by @svar[syntax-class-id] (parameterized by the +@scheme[arg-expr]s, if present). + +In addition to binding @svar[pvar-id], an annotated pattern +variable also binds @deftech{nested attributes} from the syntax +class. The names of the nested attributes are formed by prefixing +@svar[pvar-id.] (that is, @svar[pvar-id] followed by a ``dot'' +character) to the name of the syntax class's attribute. + +If @svar[pvar-id] is @scheme[_], no attributes are bound. + +@myexamples[ +(syntax-parse #'a + [(~var var id) (syntax-e #'var)]) +(syntax-parse #'12 + [(~var var id) (syntax-e #'var)]) +(define-syntax-class two + #:attributes (x y) + (pattern (x y))) +(syntax-parse #'(a b) + [(~var t two) (syntax->datum #'(t t.x t.y))]) +(define-syntax-class (nat-less-than n) + (pattern x:nat #:when (< (syntax-e #'x) n))) +(syntax-parse #'(1 2 3 4 5) + [((~var small (nat-less-than 4)) ... large:nat ...) + (list #'(small ...) #'(large ...))]) +] +} + +@specsubform[(@#,defhere[~literal] literal-id)]{ + +A @deftech{literal} identifier pattern. Matches any identifier +@scheme[free-identifier=?] to @scheme[literal-id]. + +@myexamples[ +(syntax-parse #'(define x 12) + [((~literal define) var:id body:expr) 'ok]) +(syntax-parse #'(lambda x 12) + [((~literal define) var:id body:expr) 'ok]) +] +} + +@specsubform[atomic-datum]{ + +Numbers, strings, booleans, keywords, and the empty list match as +literals. + +@myexamples[ +(syntax-parse #'(a #:foo bar) + [(x #:foo y) (syntax->datum #'y)]) +(syntax-parse #'(a foo bar) + [(x #:foo y) (syntax->datum #'y)]) +] +} + +@specsubform[(H-pattern . S-pattern)]{ + +Matches any term that can be decomposed into a list prefix matching +the @tech{H-pattern} and a suffix matching the S-pattern. + +Note that the pattern may match terms that are not even improper +lists; if the head pattern can match a zero-length head, then the +whole pattern matches whatever the tail pattern accepts. + +The first pattern can be an @tech{S-pattern}, in which case the whole +pattern matches any pair whose first element matches the first pattern +and whose rest matches the second. + +See @tech{H-patterns} for more information. +} + +@specsubform[((@#,def[~or eh] EH-pattern ...+) #,ellipses . S-pattern)]{ + +Matches any term that can be decomposed into a list head matching some +number of repetitions of the @tech{EH-pattern} alternatives (subject +to its repetition constraints) followed by a list tail matching the +S-pattern. + +In other words, the whole pattern matches either the second pattern +(which need not be a list) or a term whose head matches one of the +alternatives of the first pattern and whose tail recursively matches +the whole sequence pattern. + +See @tech{EH-patterns} for more information. +} + +@specsubform[(EH-pattern #,ellipses . S-pattern)]{ + +The @scheme[~or]-free variant of ellipses (@ellipses) pattern is +equivalent to the @scheme[~or] variant with just one alternative. +} + +@specsubform[(@#,def[~and s] S-pattern ...)]{ + +Matches any term that matches all of the subpatterns. + +Attributes bound in subpatterns are available to subsequent +subpatterns. The whole pattern binds all of the subpatterns' +attributes. + +One use for @scheme[~and]-patterns is preserving a whole +term (including its lexical context, source location, etc) while also +examining its structure. Syntax classes are useful for the same +purpose, but @scheme[~and] can be lighter weight. + +@myexamples[ +(define-syntax (import stx) + (raise-syntax-error #f "illegal use of import" stx)) +(eval:alts + (define (check-imports stx) ....) + (define (check-imports . _) #f)) +(syntax-parse #'(m (import one two)) + #:literals (import) + [(_ (~and import-clause (import i ...))) + (let ([bad (check-imports + (syntax->list #'(i ...)))]) + (when bad + (raise-syntax-error + #f "bad import" #'import-clause bad)) + 'ok)]) +] + +} + +@specsubform[(@#,def[~or s] S-pattern ...)]{ + +Matches any term that matches one of the included patterns. The +alternatives are tried in order. + +The whole pattern binds @emph{all} of the subpatterns' attributes. An +attribute that is not bound by the ``chosen'' subpattern has a value +of @scheme[#f]. The same attribute may be bound by multiple +subpatterns, and if it is bound by all of the subpatterns, it is sure +to have a value if the whole pattern matches. + +@myexamples[ +(syntax-parse #'a + [(~or x:id (~and x #f)) (syntax->datum #'x)]) +(syntax-parse #'#f + [(~or x:id (~and x #f)) (syntax->datum #'x)]) +] +} + +@specsubform[(@#,defhere[~not] S-pattern)]{ + +Matches any term that does not match the subpattern. The subpattern's +attributes are @emph{not} bound outside of the @scheme[~not]-pattern. + +@myexamples[ +(syntax-parse #'(x y z => u v) + #:literals (=>) + [((~and before (~not =>)) ... => after ...) + (list #'(before ...) #'(after ...))]) +] +} + +@specsubform[#(#, @svar[pattern-part] ...)]{ + +Matches a term that is a vector whose elements, when considered as a +list, match the @tech{S-pattern} corresponding to +@scheme[(pattern-part ...)]. + +@myexamples[ +(syntax-parse #'#(1 2 3) + [#(x y z) (syntax->datum #'z)]) +(syntax-parse #'#(1 2 3) + [#(x y ...) (syntax->datum #'(y ...))]) +(syntax-parse #'#(1 2 3) + [#(x ~rest y) (syntax->datum #'y)]) +] + +} + +@specsubform[#s(prefab-struct-key #, @svar[pattern-part] ...)]{ + +Matches a term that is a prefab struct whose key is exactly the given +key and whose sequence of fields, when considered as a list, match the +@tech{S-pattern} corresponding to @scheme[(pattern-part ...)]. + +@myexamples[ +(syntax-parse #'#s(point 1 2 3) + [#s(point x y z) 'ok]) +(syntax-parse #'#s(point 1 2 3) + [#s(point x y ...) (syntax->datum #'(y ...))]) +(syntax-parse #'#s(point 1 2 3) + [#s(point x ~rest y) (syntax->datum #'y)]) +] +} + +@specsubform[(#, @defhere[~rest] S-pattern)]{ + +Matches just like the inner @scheme[S-pattern]. The @scheme[~rest] +pattern form is useful in positions where improper lists (``dots'') +are not allowed by the reader, such as vector and structure patterns +(see above). + +@myexamples[ +(syntax-parse #'(1 2 3) + [(x ~rest y) (syntax->datum #'y)]) +(syntax-parse #'#(1 2 3) + [#(x ~rest y) (syntax->datum #'y)]) +] +} + +@specsubform[(@#,def[~describe s] expr S-pattern)]{ + +The @scheme[~describe] pattern form annotates a pattern with a +description, a string expression that is evaluated in the scope of all +prior attribute bindings. If parsing the inner pattern fails, then the +description is used to synthesize the error message. + +A describe-pattern also affects backtracking in two ways: + +@itemize{ + +@item{A cut-pattern (@scheme[~!]) within a describe-pattern only +eliminates choice-points created within the describe-pattern.} + +@item{If a describe-pattern succeeds, then all choice points created +within the describe-pattern are discarded, and a failure @emph{after} +the describe-pattern backtracks to a choice point @emph{before} the +describe-pattern, never one @emph{within} it.}}} + +@specsubform[(@#,defhere[~!] . S-pattern)]{ + +The @scheme[~!] operator, pronounced ``cut'', eliminates backtracking +choice points and commits parsing to the current branch of the pattern +it is exploring. + +Common opportunities for cut-patterns come from recognizing special +forms based on keywords. Consider the following expression: + +@interaction[#:eval the-eval +(syntax-parse #'(define-values a 123) + #:literals (define-values define-syntaxes) + [(define-values (x:id ...) e) 'define-values] + [(define-syntaxes (x:id ...) e) 'define-syntaxes] + [e 'expression])] + +Given the ill-formed term @scheme[(define-values a 123)], the +expression tries the first clause, fails to match @scheme[a] against +the pattern @scheme[(x:id ...)], and then backtracks to the second +clause and ultimately the third clause, producing the value +@scheme['expression]. But the term is not an expression; it is an +ill-formed use of @scheme[define-values]! The proper way to write the +@scheme[syntax-parse] expression follows: + +@interaction[#:eval the-eval +(syntax-parse #'(define-values a 123) + #:literals (define-values define-syntaxes) + [(define-values ~! (x:id ...) e) 'define-values] + [(define-syntaxes ~! (x:id ...) e) 'define-syntaxes] + [e 'expression])] + +Now, given the same term, @scheme[syntax-parse] tries the first +clause, and since the keyword @scheme[define-values] matches, the +cut-pattern commits to the current pattern, eliminating the choice +points for the second and third clauses. So when the clause fails to +match, the @scheme[syntax-parse] expression raises an error. + +The effect of a @scheme[~!] pattern is delimited by the nearest +enclosing @scheme[~describe] pattern. If there is no enclosing +@scheme[~describe] pattern but the cut occurs within a syntax class +definition, then only choice points within the syntax class definition +are discarded. +} + +@specsubform[(@#,defhere[~bind] [attr-id expr] ...)]{ + +This pattern matches any term. Its effect is to evaluate the +@scheme[expr]s and bind them to the given @scheme[attr-id]s as +attributes. +} + +@specsubform/subs[(@#,defhere[~fail] maybe-fail-condition message-expr) + ([maybe-fail-condition (code:line) + (code:line #:when condition-expr) + (code:line #:unless condition-expr)])]{ + +This pattern succeeds or fails independent of the term being matched +against. If the condition is absent, or if the @scheme[#:when] +condition evaluates to a true value, or if the @scheme[#:unless] +condition evaluates to @scheme[#f], then the pattern fails with the +given message. Otherwise the pattern succeeds. + +Fail patterns can be used together with cut patterns to recognize +specific ill-formed terms and address them with specially-created +failure messages. +} + + +@section{H-pattern variants} + +An @deftech{H-pattern} (for ``head pattern'') is a pattern that +describes some number of terms that occur at the head of some list +(possibly an improper list). An H-pattern's usefulness comes from +being able to match heads of different lengths. H-patterns are useful +for specifying optional forms such as keyword arguments. + +Here are the variants of @tech{H-pattern}: + +@specsubform[pvar-id:splicing-syntax-class-id]{ + +Equivalent to @scheme[(~var pvar-id +splicing-syntax-class-id)]. + +} + +@specsubform/subs[(@#,def[~var h] pvar-id splicing-syntax-class) + ([splicing-syntax-class splicing-syntax-class-id + (splicing-syntax-class-id arg-expr ...)])]{ + +Pattern variable annotated with a @tech{splicing syntax +class}. Similar to a normal @tech{annotated pattern variable}, except +matches a head pattern. +} + +@specsubform[(@#,defhere[~seq] . L-pattern)]{ + +Matches a head whose elements, if put in a list, would match the given +@tech{L-pattern}. + +@myexamples[ +(syntax-parse #'(1 2 3 4) + [((~seq 1 2 3) 4) 'ok]) +] + +See also the section on @tech{EH-patterns} for more interesting +examples of @scheme[~seq]. + +} + +@specsubform[(@#,def[~and h] H-pattern ...)]{ + +Like the S-pattern version of @scheme[~and], but matches a term head +instead. + +@myexamples[ +(syntax-parse #'(#:a 1 #:b 2 3 4 5) + [((~and (~seq (~seq k:keyword e:expr) ...) + (~seq keyword-stuff ...)) + positional-stuff ...) + (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) +] + +The H-pattern variant of @scheme[~and] requires that all of the +subpatterns be strictly @tech{H-patterns} and not +@tech{S-patterns}. This is to prevent typos like the following, a +variant of the previous example with the second @scheme[~seq] omitted: + +@myexamples[ +(syntax-parse #'(#:a 1 #:b 2 3 4 5) + [((~and (~seq (~seq k:keyword e:expr) ...) + (keyword-stuff ...)) + positional-stuff ...) + (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) +(code:comment "If the example above were allowed, it would be equivalent to this:") +(syntax-parse #'(#:a 1 #:b 2 3 4 5) + [((~and (~seq (~seq k:keyword e:expr) ...) + (~seq (keyword-stuff ...))) + positional-stuff ...) + (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) +] +} + +@specsubform[(@#,def[~or h] H-pattern ...)]{ + +Like the S-pattern version of @scheme[~or], but matches a term head +instead. + +@myexamples[ +(syntax-parse #'(m #:foo 2 a b c) + [(_ (~or (~seq #:foo x) (~seq)) y:id ...) + (attribute x)]) +(syntax-parse #'(m a b c) + [(_ (~or (~seq #:foo x) (~seq)) y:id ...) + (attribute x)]) +] +} + +@specsubform/subs[(@#,def[~optional h] H-pattern maybe-optional-option) + ([maybe-optional-option + (code:line) + (code:line #:defaults ([attr-id expr] ...))])]{ + +Matches either the given head subpattern or an empty head. If the +@scheme[#:defaults] option is given, the subsequent attribute bindings +are used if the subpattern does not match. The default attributes must +be a subset of the subpattern's attributes. + +@myexamples[ +(syntax-parse #'(m #:foo 2 a b c) + [(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...) + (attribute x)]) +(syntax-parse #'(m a b c) + [(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...) + (attribute x)]) +(syntax-parse #'(m a b c) + [(_ (~optional (~seq #:foo x)) y:id ...) + (attribute x)]) +] + +} + +@specsubform[(@#,def[~describe h] expr H-pattern)]{ + +Like the S-pattern version of @scheme[~describe], but matches a head +pattern instead. +} + +@specsubform[S-pattern]{ + +Matches a head of one element, which must be a term matching the given +@tech{S-pattern}. +} + + +@;{--------} + +@section{EH-pattern forms} + +An @deftech{EH-pattern} (for ``ellipsis-head pattern'') is pattern +that describes some number of terms, like an @tech{H-pattern}, but may +also place contraints on the number of times it occurs in a +repetition. EH-patterns (and ellipses) are useful for matching keyword +arguments where the keywords may come in any order. + +@myexamples[ +(define parser1 + (syntax-parser + [((~or (~once (~seq #:a x) #:name "#:a keyword") + (~optional (~seq #:b y) #:name "#:b keyword") + (~seq #:c z)) ...) + 'ok])) +(parser1 #'(#:a 1)) +(parser1 #'(#:b 2 #:c 3 #:c 25 #:a 'hi)) +(parser1 #'(#:a 1 #:a 2)) +] + +The pattern requires exactly one occurrence of the @scheme[#:a] +keyword and argument, at most one occurrence of the @scheme[#:b] +keyword and argument, and any number of @scheme[#:c] keywords and +arguments. The ``pieces'' can occur in any order. + +Here are the variants of @tech{EH-pattern}: + +@specsubform/subs[(@#,defhere[~once] H-pattern once-option ...) + ([once-option (code:line #:name name-expr) + (code:line #:too-few too-few-message-expr) + (code:line #:too-many too-many-message-expr)])]{ + +Matches if the inner H-pattern matches. This pattern must be selected +exactly once in the match of the entire repetition sequence. + +If the pattern is not chosen in the repetition sequence, then an error +is raised with a message, either @scheme[too-few-message-expr] or +@schemevalfont{"missing required occurrence of @scheme[name-expr]"}. + +If the pattern is chosen more than once in the repetition sequence, +then an error is raised with a message, either +@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences +of @scheme[name-expr]"}. +} + +@specsubform/subs[(@#,def[~optional eh] H-pattern optional-option ...) + ([optional-option (code:line #:name name-expr) + (code:line #:too-many too-many-message-expr) + (code:line #:defaults ([attr-id expr] ...))])]{ + +Matches if the inner H-pattern matches. This pattern may be used at +most once in the match of the entire repetition. + +If the pattern is chosen more than once in the repetition sequence, +then an error is raised with a message, either +@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences +of @scheme[name-expr]"}. + +If the @scheme[#:defaults] option is given, the following attribute +bindings are used if the subpattern does not match at all in the +sequence. The default attributes must be a subset of the subpattern's +attributes. +} diff --git a/collects/syntax/scribblings/parse.scrbl b/collects/syntax/scribblings/parse.scrbl index 4bc43d56be..a0f58b63ee 100644 --- a/collects/syntax/scribblings/parse.scrbl +++ b/collects/syntax/scribblings/parse.scrbl @@ -183,10 +183,9 @@ Here's how the syntax class would change: ] @bold{Note: } The @scheme[(require (for-template scheme/base))] is -needed for the @scheme[quote] expression. - -If the syntax class definition were a local definition in the same -module, the @scheme[for-template] would be unnecessary. +needed for the @scheme[quote] expression. If the syntax class +definition were a local definition in the same module, the +@scheme[for-template] would be unnecessary. The second pattern matches unparenthesized identifiers. The @scheme[e] attribute is bound using a @scheme[#:with] clause, which matches the @@ -269,10 +268,17 @@ examples of @schememodname[syntax/parse] features. @;{----------} -@section{Parsing syntax} +@section{Parsing and classifying syntax} -This section describes the @scheme[syntax-parse] pattern matching -form, syntax patterns, and attributes. +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{syntax-patterns}. + +@subsection{Parsing syntax} + +Two parsing forms are provided: @scheme[syntax-parse] and +@scheme[syntax-parser]. @defform/subs[(syntax-parse stx-expr parse-option ... clause ...+) ([parse-option (code:line #:context context-expr) @@ -283,7 +289,7 @@ form, syntax patterns, and attributes. (pattern-id literal-id)] [literal-set literal-set-id [literal-set-id #:at context-id]] - [clause (syntax-pattern pattern-directive ... expr)]) + [clause (syntax-pattern pattern-directive ... expr ...+)]) #:contracts ([stx-expr syntax?])]{ Evaluates @scheme[stx-expr], which should produce a syntax object, and @@ -294,9 +300,15 @@ subterms of the syntax object and that clause's side conditions and 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. If the @scheme[#:context] argument is given, -@scheme[context-expr] is used in reporting the error; otherwise -@scheme[stx-expr] is used. +error is raised. + +The following options are supported: + +@specsubform[(code:line #:context context-expr) + #:contracts ([context-expr syntax?])]{ + +When present, @scheme[context-expr] is used in reporting parse +failures; otherwise @scheme[stx-expr] is used. @(myexamples (syntax-parse #'(a b 3) @@ -304,6 +316,11 @@ error is raised. If the @scheme[#:context] argument is given, (syntax-parse #'(a b 3) #:context #'(lambda (a b 3) (+ a b)) [(x:id ...) 'ok])) +} + +@specsubform/subs[(code:line #:literals (literal ...)) + ([literal literal-id + [pattern-id literal-id]])]{ The @scheme[#:literals] option specifies identifiers that should be treated as @tech{literals} rather than @tech{pattern variables}. An @@ -317,637 +334,166 @@ that identifier is used for both purposes. requires all literals to have a binding. To match identifiers by their symbolic names, consider using the @scheme[atom-in-list] syntax class instead. +} + +@specsubform/subs[(code:line #:literal-sets (literal-set ...)) + ([literal-set literal-set-id + [literal-set-id #:at context-id]])]{ Many literals can be declared at once via one or more @tech{literal sets}, imported with the @scheme[#:literal-sets] option. The literal-set definition determines the literal identifiers to recognize and the names used in the patterns to recognize those literals. +} -The @scheme[#:conventions] option imports @tech{convention}s that give -default syntax classes to pattern variables that do not explicitly -specify a syntax class. +@specsubform[(code:line #:conventions (conventions-id ...))]{ + +Imports @tech{convention}s that give default syntax classes to pattern +variables that do not explicitly specify a syntax class. +} + +Each clause consists of a @tech{syntax pattern}, an optional sequence +of @tech{pattern directives}, and a non-empty sequence of body +expressions. } @defform[(syntax-parser parse-option ... 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 @deftech{syntax patterns} accepted by -@scheme[syntax-parse] and @scheme[syntax-parser] is given in the -following table: +@;{----------} -@schemegrammar*[#:literals (_ ~var ~literal ~or ~and ~not ~seq - ~rep ~once ~optional - ~rest ~struct ~! ~describe ~bind ~fail) - [S-pattern - pvar-id - pvar-id:syntax-class-id - literal-id - (~var id) - (~var id syntax-class) - (~literal literal-id) - atomic-datum - (H-pattern . S-pattern) - ((~or EH-pattern ...+) #,ellipses . S-pattern) - (EH-pattern #,ellipses . S-pattern) - (~and S-pattern ...+) - (~or S-pattern ...+) - (~not S-pattern) - #((unsyntax @svar[pattern-part]) ...) - #s(prefab-struct-key (unsyntax @svar[pattern-part]) ...) - (~rest S-pattern) - (~describe expr S-pattern) - (~! . S-pattern) - (~bind [attr-id expr] ...) - (~fail maybe-fail-condition message-expr)] - [L-pattern - () - (H-pattern . L-pattern) - ((~or EH-pattern ...+) #,ellipses . L-pattern) - (EH-pattern #,ellipses . L-pattern) - (~rest L-pattern) - (~! . L-pattern)] - [H-pattern - pvar-id:splicing-syntax-class-id - (~var id splicing-syntax-class) - (~seq . L-pattern) - (~and H-pattern ...+) - (~or H-pattern ...+) - (~optional H-pattern maybe-optional-option) - (~describe expr H-pattern) - S-pattern] - [EH-pattern - (~once H-pattern once-option ...) - (~optional H-pattern optional-option ...) - H-pattern]] +@subsection{Classifying syntax} -There are three main kinds of syntax pattern: @tech{S-patterns} (for -``single patterns''), @tech{H-patterns} (for ``head patterns''), and -@tech{EH-patterns} (for ``ellipsis head patterns''). A fourth kind, -@tech{L-patterns} (for ``list patterns''), is a restricted subset of -@tech{S-patterns}. When a special form in this manual refers to -@svar[syntax-pattern] (eg, the description of the -@scheme[syntax-parse] special form), it means specifically -@tech{S-pattern}. +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. -@subsection{S-pattern variants} +@defform*/subs[#:literals (pattern) + [(define-syntax-class name-id stxclass-option ... + stxclass-variant ...+) + (define-syntax-class (name-id arg-id ...) stxclass-option ... + stxclass-variant ...+)] + ([stxclass-option + (code:line #:attributes (attr-arity-decl ...)) + (code:line #:description description-expr) + (code:line #:opaque) + (code:line #:literals (literal-entry ...)) + (code:line #:literal-sets (literal-set ...)) + (code:line #:conventions (convention-id ...))] + [attr-arity-decl + attr-name-id + (attr-name-id depth)] + [stxclass-variant + (pattern syntax-pattern pattern-directive ...)])]{ -An @deftech{S-pattern} (for ``single pattern'') is a pattern that -describes a single term. The pattern may, of course, consist of other -parts. For example, @scheme[(17 ...)] is an @tech{S-pattern} -that matches any term that is a proper list of repeated -@schemeresult[17] numerals. The @deftech{L-pattern}s (for ``list -pattern'') are @tech{S-pattern} having a restricted structure that -constrains it to match only terms that are proper lists. +Defines @scheme[name-id] as a @deftech{syntax class}, which +encapsulates one or more @tech{S-patterns}. -Here are the variants of @tech{S-pattern}: +When the @scheme[arg-id]s are present, they are bound as variables in +the body. The body of the syntax-class definition contains a non-empty +sequence of @scheme[pattern] variants. -@specsubform[id]{ +The following options are supported: -An identifier can be either a @tech{pattern variable}, an -@tech{annotated pattern variable}, or a @tech{literal}: +@specsubform/subs[(code:line #:attributes (attr-arity-decl ...)) + ([attr-arity-decl attr-id + (attr-id depth)])]{ -@itemize[ +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). -@item{If @scheme[id] is the ``pattern'' name of an entry in the - literals list, it is a @tech{literal} pattern that behaves - like @scheme[(~literal id)]. - - @myexamples[ - (syntax-parse #'(define x 12) - #:literals (define) - [(define var:id body:expr) 'ok]) - (syntax-parse #'(lambda x 12) - #:literals (define) - [(define var:id body:expr) 'ok]) - (syntax-parse #'(define x 12) - #:literals ([def define]) - [(def var:id body:expr) 'ok]) - (syntax-parse #'(lambda x 12) - #:literals ([def define]) - [(def var:id body:expr) 'ok]) - ] +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}. } -@item{If @scheme[id] is of the form @scheme[_pvar-id:syntax-class-id] - (that is, two names joined by a colon character), it is an - @tech{annotated pattern variable}, and the pattern is equivalent to - @scheme[(~var pvar-id syntax-class-id)]. +@specsubform[(code:line #:description description-expr)]{ - @myexamples[ - (syntax-parse #'a - [var:id (syntax-e #'var)]) - (syntax-parse #'12 - [var:id (syntax-e #'var)]) - (define-syntax-class two - #:attributes (x y) - (pattern (x y))) - (syntax-parse #'(a b) - [t:two (syntax->datum #'(t t.x t.y))]) - (syntax-parse #'(a b) - [t - #:declare t two - (syntax->datum #'(t t.x t.y))]) - ] +The @scheme[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 @schemevalfont{"expected @scheme[description]"} may +be synthesized. + +If absent, the name of the syntax class is used instead. } -@item{Otherwise, @scheme[id] is a @tech{pattern variable}, and the -pattern is equivalent to @scheme[(~var id)]. -} -] +@specsubform[#:opaque]{ + +Indicates that errors should not be reported with respect to the +internal structure of the syntax class. } -@specsubform[#:literals (~var) (~var pvar-id)]{ +@specsubform[(code:line #:literals (literal-entry))] +@specsubform[(code:line #:literal-sets (literal-set ...))] +@specsubform[(code:line #:conventions (convention-id ...))]{ -A @deftech{pattern variable}. If @scheme[pvar-id] has no syntax class -(by @scheme[#:convention]), the pattern variable 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. +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. -If @scheme[pvar-id] does have an associated syntax class, it behaves -like an @tech{annotated pattern variable} with the implicit syntax -class inserted. +These options have the same meaning as in @scheme[syntax-parse]. } -@specsubform/subs[#:literals (~var) (~var pvar-id syntax-class) - ([syntax-class syntax-class-id - (syntax-class-id arg-expr ...)])]{ - -An @deftech{annotated pattern variable}. The pattern matches only -terms accepted by @svar[syntax-class-id] (parameterized by the -@scheme[arg-expr]s, if present). - -The syntax class's @tech{attributes} are computed for the term and -bound to the names formed by prefixing @svar[pvar-id.] to the name of -the attribute. The name @svar[pvar-id] itself is bound to the whole -term. - -If @svar[pvar-id] is @scheme[_], no attributes are bound. - -@myexamples[ -(syntax-parse #'a - [(~var var id) (syntax-e #'var)]) -(syntax-parse #'12 - [(~var var id) (syntax-e #'var)]) -(define-syntax-class two - #:attributes (x y) - (pattern (x y))) -(syntax-parse #'(a b) - [(~var t two) (syntax->datum #'(t t.x t.y))]) -(define-syntax-class (nat-less-than n) - (pattern x:nat #:when (< (syntax-e #'x) n))) -(syntax-parse #'(1 2 3 4 5) - [((~var small (nat-less-than 4)) ... large:nat ...) - (list #'(small ...) #'(large ...))]) -] +Each variant of a syntax class is specified as a separate +@scheme[pattern]-form whose syntax pattern is an @tech{S-pattern}. } -@specsubform[#:literals (~literal) (~literal literal-id)]{ +@defform*[#:literals (pattern) + [(define-splicing-syntax-class name-id stxclass-option ... + stxclass-variant ...+) + (define-splicing-syntax-class (name-id arg-id ...) stxclass-option ... + stxclass-variant ...+)]]{ -A @deftech{literal} identifier pattern. Matches any identifier -@scheme[free-identifier=?] to @scheme[literal-id]. +Defines @scheme[name-id] as a @deftech{splicing syntax class}, +analogous to a @tech{syntax class} but encapsulating @tech{H-patterns} +rather than @tech{S-patterns}. -@myexamples[ -(syntax-parse #'(define x 12) - [((~literal define) var:id body:expr) 'ok]) -(syntax-parse #'(lambda x 12) - [((~literal define) var:id body:expr) 'ok]) -] +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 an @tech{H-pattern}. } -@specsubform[atomic-datum]{ +@defform[#:literals (pattern) + (pattern syntax-pattern pattern-directive ...)]{ -Numbers, strings, booleans, keywords, and the empty list match as -literals. +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}. -@myexamples[ -(syntax-parse #'(a #:foo bar) - [(x #:foo y) (syntax->datum #'y)]) -(syntax-parse #'(a foo bar) - [(x #:foo y) (syntax->datum #'y)]) -] -} - -@specsubform[(H-pattern . S-pattern)]{ - -Matches any term that can be decomposed into a list prefix matching -the @tech{H-pattern} and a suffix matching the S-pattern. - -Note that the pattern may match terms that are not even improper -lists; if the head pattern can match a zero-length head, then the -whole pattern matches whatever the tail pattern accepts. - -The first pattern can be an @tech{S-pattern}, in which case the whole -pattern matches any pair whose first element matches the first pattern -and whose rest matches the second. - -See @tech{H-patterns} for more information. -} - -@specsubform[#:literals (~or) ((~or EH-pattern ...+) #,ellipses . S-pattern)]{ - -Matches any term that can be decomposed into a list head matching some -number of repetitions of the @tech{EH-pattern} alternatives (subject -to its repetition constraints) followed by a list tail matching the -S-pattern. - -In other words, the whole pattern matches either the second pattern -(which need not be a list) or a term whose head matches one of the -alternatives of the first pattern and whose tail recursively matches -the whole sequence pattern. - -See @tech{EH-patterns} for more information. -} - -@specsubform[(EH-pattern #,ellipses . S-pattern)]{ - -The @scheme[~or]-free variant of ellipses (@ellipses) pattern is -equivalent to the @scheme[~or] variant with just one alternative. -} - -@specsubform[#:literals (~and) (~and S-pattern ...)]{ - -Matches any term that matches all of the subpatterns. - -Attributes bound in subpatterns are available to subsequent -subpatterns. The whole pattern binds all of the subpatterns' -attributes. - -One use for @scheme[~and]-patterns is preserving a whole -term (including its lexical context, source location, etc) while also -examining its structure. Syntax classes are useful for the same -purpose, but @scheme[~and] can be lighter weight. - -@myexamples[ -(define-syntax (import stx) - (raise-syntax-error #f "illegal use of import" stx)) -(eval:alts - (define (check-imports stx) ....) - (define (check-imports . _) #f)) -(syntax-parse #'(m (import one two)) - #:literals (import) - [(_ (~and import-clause (import i ...))) - (let ([bad (check-imports - (syntax->list #'(i ...)))]) - (when bad - (raise-syntax-error - #f "bad import" #'import-clause bad)) - 'ok)]) -] - -} - -@specsubform[#:literals (~or) (~or S-pattern ...)]{ - -Matches any term that matches one of the included patterns. The -alternatives are tried in order. - -The whole pattern binds @emph{all} of the subpatterns' attributes. An -attribute that is not bound by the ``chosen'' subpattern has a value -of @scheme[#f]. The same attribute may be bound by multiple -subpatterns, and if it is bound by all of the subpatterns, it is sure -to have a value if the whole pattern matches. - -@myexamples[ -(syntax-parse #'a - [(~or x:id (~and x #f)) (syntax->datum #'x)]) -(syntax-parse #'#f - [(~or x:id (~and x #f)) (syntax->datum #'x)]) -] -} - -@specsubform[#:literals (~not) (~not S-pattern)]{ - -Matches any term that does not match the subpattern. The subpattern's -attributes are @emph{not} bound outside of the @scheme[~not]-pattern. - -@myexamples[ -(syntax-parse #'(x y z => u v) - #:literals (=>) - [((~and before (~not =>)) ... => after ...) - (list #'(before ...) #'(after ...))]) -] -} - -@specsubform[#(#, @svar[pattern-part] ...)]{ - -Matches a term that is a vector whose elements, when considered as a -list, match the @tech{S-pattern} corresponding to -@scheme[(pattern-part ...)]. - -@myexamples[ -(syntax-parse #'#(1 2 3) - [#(x y z) (syntax->datum #'z)]) -(syntax-parse #'#(1 2 3) - [#(x y ...) (syntax->datum #'(y ...))]) -(syntax-parse #'#(1 2 3) - [#(x ~rest y) (syntax->datum #'y)]) -] - -} - -@specsubform[#s(prefab-struct-key #, @svar[pattern-part] ...)]{ - -Matches a term that is a prefab struct whose key is exactly the given -key and whose sequence of fields, when considered as a list, match the -@tech{S-pattern} corresponding to @scheme[(pattern-part ...)]. - -@myexamples[ -(syntax-parse #'#s(point 1 2 3) - [#s(point x y z) 'ok]) -(syntax-parse #'#s(point 1 2 3) - [#s(point x y ...) (syntax->datum #'(y ...))]) -(syntax-parse #'#s(point 1 2 3) - [#s(point x ~rest y) (syntax->datum #'y)]) -] -} - -@specsubform[#:literals (~rest) (~rest S-pattern)]{ - -Matches just like the inner @scheme[S-pattern]. The @scheme[~rest] -pattern form is useful in positions where improper lists (``dots'') -are not allowed by the reader, such as vector and structure patterns -(see above). - -@myexamples[ -(syntax-parse #'(1 2 3) - [(x ~rest y) (syntax->datum #'y)]) -(syntax-parse #'#(1 2 3) - [#(x ~rest y) (syntax->datum #'y)]) -] -} - -@specsubform[#:literals (~describe) (~describe expr S-pattern)]{ - -The @scheme[~describe] pattern form annotates a pattern with a -description, a string expression that is evaluated in the scope of all -prior attribute bindings. If parsing the inner pattern fails, then the -description is used to synthesize the error message. - -A describe-pattern also affects backtracking in two ways: - -@itemize{ - -@item{A cut-pattern (@scheme[~!]) within a describe-pattern only -eliminates choice-points created within the describe-pattern.} - -@item{If a describe-pattern succeeds, then all choice points created -within the describe-pattern are discarded, and a failure @emph{after} -the describe-pattern backtracks to a choice point @emph{before} the -describe-pattern, never one @emph{within} it.}}} - -@specsubform[#:literals (~!) (~! . S-pattern)]{ - -The @scheme[~!] operator, pronounced ``cut'', eliminates backtracking -choice points and commits parsing to the current branch of the pattern -it is exploring. - -Common opportunities for cut-patterns come from recognizing special -forms based on keywords. Consider the following expression: - -@interaction[#:eval the-eval -(syntax-parse #'(define-values a 123) - #:literals (define-values define-syntaxes) - [(define-values (x:id ...) e) 'define-values] - [(define-syntaxes (x:id ...) e) 'define-syntaxes] - [e 'expression])] - -Given the ill-formed term @scheme[(define-values a 123)], the -expression tries the first clause, fails to match @scheme[a] against -the pattern @scheme[(x:id ...)], and then backtracks to the second -clause and ultimately the third clause, producing the value -@scheme['expression]. But the term is not an expression; it is an -ill-formed use of @scheme[define-values]! The proper way to write the -@scheme[syntax-parse] expression follows: - -@interaction[#:eval the-eval -(syntax-parse #'(define-values a 123) - #:literals (define-values define-syntaxes) - [(define-values ~! (x:id ...) e) 'define-values] - [(define-syntaxes ~! (x:id ...) e) 'define-syntaxes] - [e 'expression])] - -Now, given the same term, @scheme[syntax-parse] tries the first -clause, and since the keyword @scheme[define-values] matches, the -cut-pattern commits to the current pattern, eliminating the choice -points for the second and third clauses. So when the clause fails to -match, the @scheme[syntax-parse] expression raises an error. - -The effect of a @scheme[~!] pattern is delimited by the nearest -enclosing @scheme[~describe] pattern. If there is no enclosing -@scheme[~describe] pattern but the cut occurs within a syntax class -definition, then only choice points within the syntax class definition -are discarded. -} - -@specsubform[#:literals (~bind) (~bind [attr-id expr] ...)]{ - -This pattern matches any term. Its effect is to evaluate the -@scheme[expr]s and bind them to the given @scheme[attr-id]s as -attributes. -} - -@specsubform/subs[#:literals (~fail) (~fail maybe-fail-condition message-expr) - ([maybe-fail-condition (code:line) - (code:line #:when condition-expr) - (code:line #:unless condition-expr)])]{ - -This pattern succeeds or fails independent of the term being matched -against. If the condition is absent, or if the @scheme[#:when] -condition evaluates to a true value, or if the @scheme[#:unless] -condition evaluates to @scheme[#f], then the pattern fails with the -given message. Otherwise the pattern succeeds. - -Fail patterns can be used together with cut patterns to recognize -specific ill-formed terms and address them with specially-created -failure messages. -} - - -@subsection{H-pattern variants} - -An @deftech{H-pattern} (for ``head pattern'') is a pattern that -describes some number of terms that occur at the head of some list -(possibly an improper list). An H-pattern's usefulness comes from -being able to match heads of different lengths. H-patterns are useful -for specifying optional forms such as keyword arguments. - -Here are the variants of @tech{H-pattern}: - -@specsubform[#:literals (~seq) (~seq . L-pattern)]{ - -Matches a head whose elements, if put in a list, would match the given -@tech{L-pattern}. - -@myexamples[ -(syntax-parse #'(1 2 3 4) - [((~seq 1 2 3) 4) 'ok]) -] - -See also the section on @tech{EH-patterns} for more interesting -examples of @scheme[~seq]. - -} - -@specsubform[#:literals (~and) (~and H-pattern ...)]{ - -Like the S-pattern version of @scheme[~and], but matches a term head -instead. - -@myexamples[ -(syntax-parse #'(#:a 1 #:b 2 3 4 5) - [((~and (~seq (~seq k:keyword e:expr) ...) - (~seq keyword-stuff ...)) - positional-stuff ...) - (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) -] - -The H-pattern of @scheme[~and] requires that all of the subpatterns be -strictly @tech{H-patterns} and not @tech{S-patterns}. This is to -prevent typos like the following, a variant of the previous example -with the second @scheme[~seq] omitted: - -@myexamples[ -(syntax-parse #'(#:a 1 #:b 2 3 4 5) - [((~and (~seq (~seq k:keyword e:expr) ...) - (keyword-stuff ...)) - positional-stuff ...) - (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) -(code:comment "If the example above were allowed, it would be equivalent to this:") -(syntax-parse #'(#:a 1 #:b 2 3 4 5) - [((~and (~seq (~seq k:keyword e:expr) ...) - (~seq (keyword-stuff ...))) - positional-stuff ...) - (syntax->datum #'((k ...) (e ...) (keyword-stuff ...)))]) -] -} - -@specsubform[#:literals (~or) (~or H-pattern ...)]{ - -Like the S-pattern version of @scheme[~or], but matches a term head -instead. - -@myexamples[ -(syntax-parse #'(m #:foo 2 a b c) - [(_ (~or (~seq #:foo x) (~seq)) y:id ...) - (attribute x)]) -(syntax-parse #'(m a b c) - [(_ (~or (~seq #:foo x) (~seq)) y:id ...) - (attribute x)]) -] -} - -@specsubform/subs[#:literals (~optional) (~optional H-pattern maybe-optional-option) - ([maybe-optional-option - (code:line) - (code:line #:defaults ([attr-id expr] ...))])]{ - -Matches either the given head subpattern or an empty head. If the -@scheme[#:defaults] option is given, the subsequent attribute bindings -are used if the subpattern does not match. The default attributes must -be a subset of the subpattern's attributes. - -@myexamples[ -(syntax-parse #'(m #:foo 2 a b c) - [(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...) - (attribute x)]) -(syntax-parse #'(m a b c) - [(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...) - (attribute x)]) -(syntax-parse #'(m a b c) - [(_ (~optional (~seq #:foo x)) y:id ...) - (attribute x)]) -] - -} - -@specsubform[#:literals (~describe) (~describe expr H-pattern)]{ - -Like the S-pattern version of @scheme[~describe], but matches a head -pattern instead. -} - -@specsubform[S-pattern]{ - -Matches a head of one element, which must be a term matching the given -@tech{S-pattern}. -} - - -@subsection{EH-pattern forms} - -An @deftech{EH-pattern} (for ``ellipsis-head pattern'') is pattern -that describes some number of terms, like an @tech{H-pattern}, but may -also place contraints on the number of times it occurs in a -repetition. EH-patterns (and ellipses) are useful for matching keyword -arguments where the keywords may come in any order. - -@myexamples[ -(define parser1 - (syntax-parser - [((~or (~once (~seq #:a x) #:name "#:a keyword") - (~optional (~seq #:b y) #:name "#:b keyword") - (~seq #:c z)) ...) - 'ok])) -(parser1 #'(#:a 1)) -(parser1 #'(#:b 2 #:c 3 #:c 25 #:a 'hi)) -(parser1 #'(#:a 1 #:a 2)) -] - -The pattern requires exactly one occurrence of the @scheme[#:a] -keyword and argument, at most one occurrence of the @scheme[#:b] -keyword and argument, and any number of @scheme[#:c] keywords and -arguments. The ``pieces'' can occur in any order. - -Here are the variants of @tech{EH-pattern}: - -@specsubform/subs[#:literals (~once) (~once H-pattern once-option ...) - ([once-option (code:line #:name name-expr) - (code:line #:too-few too-few-message-expr) - (code:line #:too-many too-many-message-expr)])]{ - -Matches if the inner H-pattern matches. This pattern must be selected -exactly once in the match of the entire repetition sequence. - -If the pattern is not chosen in the repetition sequence, then an error -is raised with a message, either @scheme[too-few-message-expr] or -@schemevalfont{"missing required occurrence of @scheme[name-expr]"}. - -If the pattern is chosen more than once in the repetition sequence, -then an error is raised with a message, either -@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences -of @scheme[name-expr]"}. -} - -@specsubform/subs[#:literals (~optional) (~optional H-pattern optional-option ...) - ([optional-option (code:line #:name name-expr) - (code:line #:too-many too-many-message-expr) - (code:line #:defaults ([attr-id expr] ...))])]{ - -Matches if the inner H-pattern matches. This pattern may be used at -most once in the match of the entire repetition. - -If the pattern is chosen more than once in the repetition sequence, -then an error is raised with a message, either -@scheme[too-many-message-expr] or @schemevalfont{"too many occurrences -of @scheme[name-expr]"}. - -If the @scheme[#:defaults] option is given, the following attribute -bindings are used if the subpattern does not match at all in the -sequence. The default attributes must be a subset of the subpattern's -attributes. +When used within @scheme[define-syntax-class], @scheme[syntax-pattern] +should be an @tech{S-pattern}; within +@scheme[define-splicing-syntax-class], it should be an +@tech{H-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 @scheme[syntax-parse] and @scheme[syntax-parser] support -directives for annotating the pattern and specifying side -conditions. The grammar for pattern directives follows: +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) @@ -962,10 +508,8 @@ conditions. The grammar for pattern directives follows: @specsubform[(code:line #:declare pvar-id (syntax-class-id expr ...))]{ 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 a single pattern variable). The -@scheme[#:declare] form may be preferred when writing macro-defining -macros or to avoid dealing with structured identifiers. +@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[expr]s @@ -1013,48 +557,27 @@ backtracks. In other words, @scheme[#:when] is like } -@deftogether[[ -@defidform[~var] -@defidform[~literal] -@defidform[~or] -@defidform[~and] -@defidform[~not] -@defidform[~seq] -@defidform[~once] -@defidform[~optional] -@defidform[~rest] -@defidform[~describe] -@defidform[~!] -@defidform[~bind] -@defidform[~fail]]]{ - -Syntax pattern keywords, recognized by @scheme[syntax-parse]. - -} @;{----------} -@section{Pattern Variables and Attributes} +@subsection{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 -@deftech{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). +@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 +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. If @scheme[attr-id] is an attribute with a nonzero -ellipsis depth, then the result has the corresponding level of list -nesting. - +error is raised. } The value of an attribute need not be syntax. Non-syntax-valued @@ -1126,149 +649,8 @@ than expected levels of list nesting. [(~or (x:id ...) _) (attribute x)])) -@;{----------} - -@section{Syntax Classes} - -Syntax classes provide an abstraction mechanism for the specification -of syntax. 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. The structure -of syntax classes and patterns also allows @scheme[syntax-parse] to -automatically generate error messages for syntax errors. - -When a syntax class accepts (matches) a syntax object, it computes and -provides attributes based on the contents of the matched syntax. While -the values of the attributes depend on the matched syntax, the set of -attributes and each attribute's ellipsis nesting depth is fixed for -each syntax class. - -@defform*/subs[#:literals (pattern basic-syntax-class) - [(define-syntax-class name-id stxclass-option ... - stxclass-variant ...+) - (define-syntax-class (name-id arg-id ...) stxclass-option ... - stxclass-variant ...+)] - ([stxclass-option - (code:line #:attributes (attr-arity-decl ...)) - (code:line #:description description) - (code:line #:transparent) - (code:line #:literals (literal-entry ...)) - (code:line #:literal-sets (literal-set ...)) - (code:line #:conventions (convention-id ...))] - [attr-arity-decl - attr-name-id - (attr-name-id depth)] - [stxclass-variant - (pattern syntax-pattern stxclass-pattern-directive ...)])]{ - -Defines @scheme[name-id] as a syntax class. When the @scheme[arg-id]s -are present, they are bound as variables (not pattern variables) in -the body. The body of the syntax-class definition contains a non-empty -sequence of @scheme[pattern] variants. - -@specsubform[(code:line #:attributes (attr-arity-decl ...))]{ - -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. Only nested attributes from previously declared syntax -classes are included. -} - -@specsubform[(code:line #:description description)]{ - -The @scheme[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 @schemevalfont{"expected @scheme[description]"} may -be synthesized. - -If absent, the name of the syntax class is used instead. - -} - -@specsubform[#:transparent]{ - -Indicates that errors may be reported with respect to the internal -structure of the syntax class. -} - -@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 under @scheme[syntax-parse]. -} - -@specsubform/subs[#:literals (pattern) - (pattern syntax-pattern stxclass-pattern-directive ...) - ([stxclass-pattern-directive - pattern-directive - (code:line #:rename internal-id external-id)])]{ - -Accepts syntax matching the given syntax pattern with the accompanying -pattern directives as in @scheme[syntax-parse]. - -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. -} -} - -@defform*/subs[#:literals (pattern) - [(define-splicing-syntax-class name-id stxclass-option ... - stxclass-variant ...+) - (define-splicing-syntax-class (name-id arg-id ...) stxclass-option ... - stxclass-variant ...+)] - ()]{ - -Defines @scheme[name-id] as a splicing syntax class. A splicing syntax -class encapsulates @tech{H-patterns} as an ordinary syntax class -encapsulates @tech{S-patterns}. - -} - -@defidform[pattern]{ - -Keyword recognized by @scheme[define-syntax-class]. It may not be -used as an expression. -} - -@subsection{Attributes} - -A syntax class has a set of @tech{attributes}. Each attribute has a -name, an ellipsis depth, and a set of nested attributes. When an -instance of the syntax class is parsed and bound to a pattern -variable, additional pattern variables are bound for each of the -syntax class's attributes. The name of these additional pattern -variables is the dotted concatenation of the primary pattern -variable with the name of the attribute. - -For example, if pattern variable @scheme[p] is bound to an instance of -a syntax class with attribute @scheme[a], then the pattern variable -@scheme[p.a] is bound to the value of that attribute. The ellipsis -depth of @scheme[p.a] is the sum of the depths of @scheme[p] and -attribute @scheme[a]. - -The attributes of a syntax class are either given explicitly with an -@scheme[#:attributes] option or inferred from the pattern variables of -the syntax class's variants. +@;{--------} @subsection{Inspection tools} @@ -1276,8 +658,8 @@ The following special forms are for debugging syntax classes. @defform[(syntax-class-attributes syntax-class-id)]{ -Returns a list of the syntax class's attributes in flattened -form. Each attribute is listed by its name and ellipsis depth. +Returns a list of the syntax class's attributes. Each attribute is +listed by its name and ellipsis depth. } @defform[(syntax-class-parse syntax-class-id stx-expr arg-expr ...)]{ @@ -1291,6 +673,11 @@ the result is some internal representation of the failure. } +@;{----------} + +@include-section["parse-patterns.scrbl"] + + @;{----------} @section{Literal sets and Conventions} @@ -1321,7 +708,6 @@ identifiers the literal matches. [(define-values (x:id ...) e:expr) 'v] [(define-syntaxes (x:id ...) e:expr) 's]) ] - } @defform/subs[(define-conventions name-id (id-pattern syntax-class) ...)