diff --git a/collects/syntax/private/stxparse/parse.ss b/collects/syntax/private/stxparse/parse.ss index c0cdffde62..e1d1fe45bd 100644 --- a/collects/syntax/private/stxparse/parse.ss +++ b/collects/syntax/private/stxparse/parse.ss @@ -144,7 +144,7 @@ #:no-duplicates? #t)) (define context (let ([c (options-select-one chunks '#:context #:default #f)]) - (if c (car c) #'#f))) + (if c (car c) #'x))) (define-values (decls0 defs) (get-decls+defs chunks)) (define (for-clause clause) (syntax-case clause () @@ -162,7 +162,7 @@ (convert-sides x #,sides (clause-success () (let () . rest)))))))])) (unless (and (stx-list? clauses-stx) (stx-pair? clauses-stx)) - (wrong-syntax clauses-stx "expected non-empty sequence of clauses")) + (raise-syntax-error #f "expected non-empty sequence of clauses" stx)) (with-syntax ([(def ...) defs] [(alternative ...) (map for-clause (stx->list clauses-stx))]) @@ -177,22 +177,6 @@ (define-for-syntax (wash-literals stx) (wash-list wash-literal stx)) -#| -;; (parse:clause id ([id id] ...) Clause) : expr -(define-syntax (parse:clause stx) - (syntax-case stx () - [(parse:clause x literals [p . rest]) - (let-values ([(rest decls sides) - (parse-pattern-directives - #'rest #:decls (new-declenv (wash-literals #'literals)))]) - (with-syntax ([rest rest] - [fc (empty-frontier #'x)] - [pattern (parse-whole-pattern #'p decls)]) - #`(parse:S x fc pattern - (convert-sides x #,sides - (clause-success () (let () . rest))))))])) -|# - ;; (clause-success (IAttr ...) expr) : expr (define-syntax (clause-success stx) (syntax-case stx () diff --git a/collects/syntax/scribblings/parse.scrbl b/collects/syntax/scribblings/parse.scrbl index bd2864fe92..1737eda1d7 100644 --- a/collects/syntax/scribblings/parse.scrbl +++ b/collects/syntax/scribblings/parse.scrbl @@ -15,7 +15,8 @@ (define the-eval (parameterize ((sandbox-output 'string) (sandbox-error-output 'string)) - (make-evaluator 'scheme/base #:requires '(syntax/parse)))) + (make-evaluator 'scheme/base + #:requires '(syntax/parse (for-syntax scheme/base))))) (define-syntax-rule (myexamples e ...) (parameterize ((error-print-source-location #f)) (examples #:eval the-eval e ...)))) @@ -81,7 +82,7 @@ default syntax classes to pattern variables that do not explicitly specify a syntax class. } -@defform[(syntax-parser maybe-literals clause ...)]{ +@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. @@ -152,9 +153,10 @@ Here are the variants of @tech{S-pattern}: @specsubform[pvar-id]{ If @scheme[pvar-id] has no syntax class (by @scheme[#:declare] or -@scheme[#:convention]), the pattern 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. +@scheme[#:convention]), the pattern matches anything. The +@deftech{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 the following form. @@ -261,7 +263,7 @@ See @tech{EH-patterns} for more information. @specsubform[#:literals (~and) (~and S-pattern ...)]{ -Matches any syntax that matches all of the included patterns. +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' @@ -272,11 +274,12 @@ 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. -@(interaction-eval #:eval the-eval - (begin (define import #f) - (define (check-imports . _) #f))) - @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 ...))) @@ -292,7 +295,8 @@ purpose, but @scheme[~and] can be lighter weight. @specsubform[#:literals (~or) (~or S-pattern ...)]{ -Matches any term that matches one of the included patterns. +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 @@ -462,6 +466,10 @@ Matches a head whose elements, if put in a list, would match the given (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 (~or) (~or H-pattern ...)]{ @@ -607,16 +615,6 @@ given message); otherwise, it continues. } -@specsubform[(code:line #:attr attr-id expr)]{ - -Evaluates the @scheme[expr] in the context of all previous attribute -bindings and binds the result to the attribute @scheme[attr-id]. The -result need not be a syntax object; attributes can be bound to any -kind of value. - -} - - @deftogether[[ @defidform[~or] @defidform[~and] @@ -637,42 +635,16 @@ Syntax pattern keywords, recognized by @scheme[syntax-parse]. @section{Pattern Variables and Attributes} -@;{ -An @deftech{attribute} is either a @tech{pattern variable}, a -@tech{nested attribute}, or a @tech{computed attribute}. +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). -A pattern consisting of an identifier not in the literals list is a -@deftech{pattern variable}. Pattern variables cannot be used as -ordinary variables; instead, they are used within @scheme[syntax], -@scheme[quasisyntax], etc as part of a syntax template. - -Pattern variables have an @deftech{ellipsis depth} based on the number -of ellipses the pattern variable occurs in front of in the -pattern. For example, in the @tech{S-pattern} @scheme[(a (b c ...) ... d)], -the pattern variable @scheme[a] has depth 0, @scheme[b] has -depth 1, @scheme[c] has depth 2, and @scheme[d] has depth 0. The -ellipsis depth of a pattern variable in a pattern determines what -ellipsis depths it may be used at in a template. - -Pattern variables annotated with syntax classes also bind -@deftech{nested attributes}, one for each attribute exported by the -syntax class. The names of the nested attributes are computed by -combining the pattern variable name with the syntax class attributes' -names. The ellipsis depth of a nested attribute is the sum of the -pattern variable's depth and the depth of the attribute in the syntax -class. @deftech{Computed attributes} are bound by @scheme[#:attr] -clauses and @scheme[~bind] patterns. - -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 #'(a b c) - [(~or (x:nat ...) _) - (attribute x)])) -} +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)]{ @@ -682,14 +654,77 @@ 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. -The values returned by @scheme[attribute] never undergo additional -wrapping as syntax objects, unlike values produced by some uses of -@scheme[syntax], @scheme[quasisyntax], etc. Therefore, use -@scheme[attribute] when the attribute value is used as data, not -placed in a syntax object. - } +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)])) + @;{----------} @section{Syntax Classes} @@ -993,8 +1028,6 @@ Literal set containing the identifiers for fully-expanded code @scheme[#%plain-module-begin], @scheme[#%require], and @scheme[#%provide]. -@;{See @secref[#:doc '(lib "scribblings/reference/reference.scrbl") "fully-expanded"].} - Note that the literal-set uses the names @scheme[#%plain-lambda] and @scheme[#%plain-app], not @scheme[lambda] and @scheme[#%app]. }