#lang scribble/doc @(require "mz.rkt" (for-label syntax/parse)) @(define lit-ellipsis (racket ...)) @(define syntax-eval (lambda () (let ([the-eval (make-base-eval)]) (the-eval '(require (for-syntax racket/base))) the-eval))) @title[#:tag "stx-patterns"]{Pattern-Based Syntax Matching} @defform/subs[(syntax-case stx-expr (literal-id ...) clause ...) ([clause [pattern result-expr] [pattern fender-expr result-expr]] [pattern _ id (pattern ...) (pattern ...+ . pattern) (pattern ... pattern ellipsis pattern ...) (pattern ... pattern ellipsis pattern ... . pattern) (code:line #,(tt "#")(pattern ...)) (code:line #,(tt "#")(pattern ... pattern ellipsis pattern ...)) (code:line #,(tt "#&")pattern) (code:line #,(tt "#s")(key-datum pattern ...)) (code:line #,(tt "#s")(key-datum pattern ... pattern ellipsis pattern ...)) (ellipsis stat-pattern) const] [stat-pattern id (stat-pattern ...) (stat-pattern ...+ . stat-pattern) (code:line #,(tt "#")(stat-pattern ...)) const] [ellipsis #,lit-ellipsis])]{ Finds the first @racket[pattern] that matches the syntax object produced by @racket[stx-expr], and for which the corresponding @racket[fender-expr] (if any) produces a true value; the result is from the corresponding @racket[result-expr], which is in tail position for the @racket[syntax-case] form. If no @racket[clause] matches, then the @exnraise[exn:fail:syntax]; the exception is generated by calling @racket[raise-syntax-error] with @racket[#f] as the ``name'' argument, a string with a generic error message, and the result of @racket[stx-expr]. A syntax object matches a @racket[pattern] as follows: @specsubform[_]{ A @racket[_] pattern (i.e., an identifier with the same binding as @racket[_]) matches any syntax object.} @specsubform[id]{ An @racket[id] matches any syntax object when it is not bound to @racket[...] or @racket[_] and does not have the same binding as any @racket[literal-id]. The @racket[id] is further bound as @deftech{pattern variable} for the corresponding @racket[fender-expr] (if any) and @racket[result-expr]. A pattern-variable binding is a transformer binding; the pattern variable can be referenced only through forms like @racket[syntax]. The binding's value is the syntax object that matched the pattern with a @deftech{depth marker} of @math{0}. An @racket[id] that has the same binding as a @racket[literal-id] matches a syntax object that is an identifier with the same binding in the sense of @racket[free-identifier=?]. The match does not introduce any @tech{pattern variables}.} @specsubform[(pattern ...)]{ A @racket[(pattern ...)] pattern matches a syntax object whose datum form (i.e., without lexical information) is a list with as many elements as sub-@racket[pattern]s in the pattern, and where each syntax object that corresponds to an element of the list matches the corresponding sub-@racket[pattern]. Any @tech{pattern variables} bound by the sub-@racket[pattern]s are bound by the complete pattern; the bindings must all be distinct.} @specsubform[(pattern ...+ . pattern)]{ The last @racket[pattern] must not be a @racket/form[(pattern ...)], @racket/form[(pattern ...+ . pattern)], @racket/form[(pattern ... pattern ellipsis pattern ...)], or @racket/form[(pattern ... pattern ellipsis pattern ... . pattern)] form. Like the previous kind of pattern, but matches syntax objects that are not necessarily lists; for @math{n} sub-@racket[pattern]s before the last sub-@racket[pattern], the syntax object's datum must be a pair such that @math{n-1} @racket[cdr]s produce pairs. The last sub-@racket[pattern] is matched against the syntax object corresponding to the @math{n}th @racket[cdr] (or the @racket[datum->syntax] coercion of the datum using the nearest enclosing syntax object's lexical context and source location).} @specsubform[(pattern ... pattern ellipsis pattern ...)]{ Like the @racket[(pattern ...)] kind of pattern, but matching a syntax object with any number (zero or more) elements that match the sub-@racket[pattern] followed by @racket[ellipsis] in the corresponding position relative to other sub-@racket[pattern]s. For each pattern variable bound by the sub-@racket[pattern] followed by @racket[ellipsis], the larger pattern binds the same pattern variable to a list of values, one for each element of the syntax object matched to the sub-@racket[pattern], with an incremented @tech{depth marker}. (The sub-@racket[pattern] itself may contain @racket[ellipsis], leading to a pattern variables bound to lists of lists of syntax objects with a @tech{depth marker} of @math{2}, and so on.)} @specsubform[(pattern ... pattern ellipsis pattern ... . pattern)]{ Like the previous kind of pattern, but with a final sub-@racket[pattern] as for @racket[(pattern ...+ . pattern)]. The final @racket[pattern] never matches a syntax object whose datum is a pair.} @specsubform[(code:line #,(tt "#")(pattern ...))]{ Like a @racket[(pattern ...)] pattern, but matching a vector syntax object whose elements match the corresponding sub-@racket[pattern]s.} @specsubform[(code:line #,(tt "#")(pattern ... pattern ellipsis pattern ...))]{ Like a @racket[(pattern ... pattern ellipsis pattern ...)] pattern, but matching a vector syntax object whose elements match the corresponding sub-@racket[pattern]s.} @specsubform[(code:line #,(tt "#&")pattern)]{ Matches a box syntax object whose content matches the @racket[pattern].} @specsubform[(code:line #,(tt "#s")(key-datum pattern ...))]{ Like a @racket[(pattern ...)] pattern, but matching a @tech{prefab} structure syntax object whose fields match the corresponding sub-@racket[pattern]s. The @racket[key-datum] must correspond to a valid first argument to @racket[make-prefab-struct].} @specsubform[(code:line #,(tt "#s")(key-datum pattern ... pattern ellipsis pattern ...))]{ Like a @racket[(pattern ... pattern ellipsis pattern ...)] pattern, but matching a @tech{prefab} structure syntax object whose elements match the corresponding sub-@racket[pattern]s.} @specsubform[(ellipsis stat-pattern)]{ Matches the same as @racket[stat-pattern], which is like a @racket[pattern], but identifiers with the binding @racket[...] are treated the same as other @racket[id]s.} @specsubform[const]{ A @racket[const] is any datum that does not match one of the preceding forms; a syntax object matches a @racket[const] pattern when its datum is @racket[equal?] to the @racket[quote]d @racket[const].} If @racket[stx-expr] produces a non-@tech{syntax object}, then its result is converted to a syntax object using @racket[datum->syntax] and the lexical context and source location of the @racket[stx-expr]. If @racket[stx-expr] produces a syntax object that is @tech{tainted} or @tech{armed}, then any syntax object bound by a @racket[pattern] are @tech{tainted}---unless the binding corresponds to the whole syntax object produced by @racket[stx-expr], in which case it remains @tech{tainted} or @tech{armed}. @mz-examples[ (require (for-syntax racket/base)) (define-syntax (swap stx) (syntax-case stx () [(_ a b) #'(let ([t a]) (set! a b) (set! b t))])) (let ([x 5] [y 10]) (swap x y) (list x y)) (syntax-case #'(ops 1 2 3 => +) (=>) [(_ x ... => op) #'(op x ...)]) (syntax-case #'(let ([x 5] [y 9] [z 12]) (+ x y z)) (let) [(let ([var expr] ...) body ...) (list #'(var ...) #'(expr ...))]) ]} @defform[(syntax-case* stx-expr (literal-id ...) id-compare-expr clause ...)]{ Like @racket[syntax-case], but @racket[id-compare-expr] must produce a procedure that accepts two arguments. A @racket[literal-id] in a @racket[_pattern] matches an identifier for which the procedure returns true when given the identifier to match (as the first argument) and the identifier in the @racket[_pattern] (as the second argument). In other words, @racket[syntax-case] is like @racket[syntax-case*] with an @racket[id-compare-expr] that produces @racket[free-identifier=?].} @defform[(with-syntax ([pattern stx-expr] ...) body ...+)]{ Similar to @racket[syntax-case], in that it matches a @racket[pattern] to a syntax object. Unlike @racket[syntax-case], all @racket[pattern]s are matched, each to the result of a corresponding @racket[stx-expr], and the pattern variables from all matches (which must be distinct) are bound with a single @racket[body] sequence. The result of the @racket[with-syntax] form is the result of the last @racket[body], which is in tail position with respect to the @racket[with-syntax] form. If any @racket[pattern] fails to match the corresponding @racket[stx-expr], the @exnraise[exn:fail:syntax]. A @racket[with-syntax] form is roughly equivalent to the following @racket[syntax-case] form: @racketblock[ (syntax-case (list stx-expr ...) () [(pattern ...) (let () body ...+)]) ] However, if any individual @racket[stx-expr] produces a non-@tech{syntax object}, then it is converted to one using @racket[datum->syntax] and the lexical context and source location of the individual @racket[stx-expr]. @examples[#:eval (syntax-eval) (define-syntax (hello stx) (syntax-case stx () [(_ name place) (with-syntax ([print-name #'(printf "~a\n" 'name)] [print-place #'(printf "~a\n" 'place)]) #'(begin (define (name times) (printf "Hello\n") (for ([i (in-range 0 times)]) print-name)) (define (place times) (printf "From\n") (for ([i (in-range 0 times)]) print-place))))])) (hello jon utah) (jon 2) (utah 2) (define-syntax (math stx) (define (make+1 expression) (with-syntax ([e expression]) #'(+ e 1))) (syntax-case stx () [(_ numbers ...) (with-syntax ([(added ...) (map make+1 (syntax->list #'(numbers ...)))]) #'(begin (printf "got ~a\n" added) ...))])) (math 3 1 4 1 5 9) ]} @defform[#:literals (~? ~@) (syntax template) #:grammar ([template id (head-template ...) (head-template ...+ . template) (code:line #,(tt "#")(head-template ...)) (code:line #,(tt "#&")template) (code:line #,(tt "#s")(key-datum head-template ...)) (~? template template) (ellipsis stat-template) const] [head-template template (code:line head-template ellipsis ...+) (~@ . template) (~? head-template head-template) (~? head-template)] [stat-template @#,elem{like @svar{template}, but without @|lit-ellipsis|, @racket[~?], and @racket[~@]}] [ellipsis #,lit-ellipsis])]{ Constructs a syntax object based on a @racket[template], which can include @tech{pattern variables} bound by @racket[syntax-case] or @racket[with-syntax]. A @svar[template] produces a single syntax object. A @svar[head-template] produces a sequence of zero or more syntax objects. A @svar[stat-template] is like a @svar[template], except that @|lit-ellipsis|, @racket[~?], and @racket[~@] are interpreted as constants instead of template forms. A @svar[template] produces a syntax object as follows: @specsubform[id]{ If @racket[id] is bound as a @tech{pattern variable}, then @racket[id] as a template produces the @tech{pattern variable}'s match result. Unless the @racket[id] is a sub-@racket[template] that is replicated by @racket[ellipsis] in a larger @racket[template], the @tech{pattern variable}'s value must be a syntax object with a @tech{depth marker} of @math{0} (as opposed to a list of matches). More generally, if the @tech{pattern variable}'s value has a depth marker @math{n}, then it can only appear within a template where it is replicated by at least @math{n} @racket[ellipsis]es. In that case, the template will be replicated enough times to use each match result at least once. If @racket[id] is not bound as a pattern variable, then @racket[id] as a template produces @racket[(quote-syntax id)].} @specsubform[(head-template ...)]{ Produces a syntax object whose datum is a list, and where the elements of the list correspond to syntax objects produced by the @racket[head-template]s.} @specsubform[(head-template ... . template)]{ Like the previous form, but the result is not necessarily a list; instead, the place of the empty list in the resulting syntax object's datum is taken by the syntax object produced by @racket[template].} @specsubform[(code:line #,(tt "#")(head-template ...))]{ Like the @racket[(head-template ...)] form, but producing a syntax object whose datum is a vector instead of a list.} @specsubform[(code:line #,(tt "#&")template)]{ Produces a syntax object whose datum is a box holding the syntax object produced by @racket[template].} @specsubform[(code:line #,(tt "#s")(key-datum head-template ...))]{ Like the @racket[(head-template ...)] form, but producing a syntax object whose datum is a @tech{prefab} structure instead of a list. The @racket[key-datum] must correspond to a valid first argument of @racket[make-prefab-struct].} @specsubform[#:literals (~?) (~? template1 template2)]{ Produces the result of @racket[template1] if @racket[template1] has no pattern variables with ``missing values''; otherwise, produces the result of @racket[template2]. A pattern variable bound by @racket[syntax-case] never has a missing value, but pattern variables bound by @racket[syntax-parse] (for example, @racket[~or] or @racket[~optional] patterns) can. @examples[#:eval (let ([ev (syntax-eval)]) (ev '(require syntax/parse/pre)) ev) (syntax-parse #'(m 1 2 3) [(_ (~optional (~seq #:op op:expr)) arg:expr ...) #'((~? op +) arg ...)]) (syntax-parse #'(m #:op max 1 2 3) [(_ (~optional (~seq #:op op:expr)) arg:expr ...) #'((~? op +) arg ...)]) ]} @specsubform[(ellipsis stat-template)]{ Produces the same result as @racket[stat-template], which is like a @racket[template], but @racket[...], @racket[~?], and @racket[~@] are treated like an @racket[id] (with no pattern binding).} @specsubform[const]{ A @racket[const] template is any form that does not match the preceding cases, and it produces the result @racket[(quote-syntax const)].} A @racket[head-template] produces a sequence of syntax objects; that sequence is ``inlined'' into the result of the enclosing @racket[template]. The result of a @racket[head-template] is defined as follows: @specsubform[template]{ Produces one syntax object, according to the rules for @svar[template] above.} @specsubform[(code:line head-template ellipsis ...+)]{ Generates a sequence of syntax objects by ``@racket[map]ping'' the @racket[head-template] over the values of its pattern variables. The number of iterations depends on the values of the @tech{pattern variables} referenced within the sub-template. To be more precise: Let @racket[_outer] be @racket[_inner] followed by one ellipsis. A @tech{pattern variable} is an @deftech{iteration pattern variable} for @racket[_outer] if occurs at a depth equal to its @tech{depth marker}. There must be at least one; otherwise, an error is raised. If there are multiple iteration variables, then all of their values must be lists of the same length. The result for @racket[_outer] is produced by @racket[map]ping the @racket[_inner] template over the @tech{iteration pattern variable} values and decreasing their effective @tech{depth markers} by 1 within @racket[_inner]. The @racket[_outer] result is formed by appending the @racket[_inner] results. Consequently, if a @tech{pattern variable} occurs at a depth greater than its @tech{depth marker}, it is used as an @tech{iteration pattern variable} for the innermost ellipses but not the outermost. A @tech{pattern variable} must not occur at a depth less than its @tech{depth marker}; otherwise, an error is raised.} @specsubform[#:literals (~@) (~@ . template)]{ Produces the sequence of elements in the syntax list produced by @racket[template]. If @racket[template] does not produce a proper syntax list, an exception is raised. @examples[#:eval (syntax-eval) (with-syntax ([(key ...) #'('a 'b 'c)] [(val ...) #'(1 2 3)]) #'(hash (~@ key val) ...)) (with-syntax ([xs #'(2 3 4)]) #'(list 1 (~@ . xs) 5)) ]} @specsubform[#:literals (~?) (~? head-template1 head-template2)]{ Produces the result of @racket[head-template1] if none of its pattern variables have ``missing values''; otherwise produces the result of @racket[head-template2]. } @specsubform[#:literals (~?) (~? head-template)]{ Produces the result of @racket[head-template] if none of its pattern variables have ``missing values''; otherwise produces nothing. Equivalent to @racket[(~? head-template (~@))]. } A @racket[(#,(racketkeywordfont "syntax") template)] form is normally abbreviated as @racket[#'template]; see also @secref["parse-quote"]. If @racket[template] contains no pattern variables, then @racket[#'template] is equivalent to @racket[(quote-syntax template)]. @history[#:changed "6.90.0.25" @elem{Added @racket[~@] and @racket[~?].}] } @defform[(quasisyntax template)]{ Like @racket[syntax], but @racket[(#,(racketkeywordfont "unsyntax") _expr)] and @racket[(#,(racketkeywordfont "unsyntax-splicing") _expr)] escape to an expression within the @racket[template]. The @racket[_expr] must produce a syntax object (or syntax list) to be substituted in place of the @racket[unsyntax] or @racket[unsyntax-splicing] form within the quasiquoting template, just like @racket[unquote] and @racket[unquote-splicing] within @racket[quasiquote]. (If the escaped expression does not generate a syntax object, it is converted to one in the same way as for the right-hand side of @racket[with-syntax].) Nested @racket[quasisyntax]es introduce quasiquoting layers in the same way as nested @racket[quasiquote]s. Also analogous to @racket[quasiquote], the reader converts @litchar{#`} to @racket[quasisyntax], @litchar{#,} to @racket[unsyntax], and @litchar["#,@"] to @racket[unsyntax-splicing]. See also @secref["parse-quote"].} @defform[(unsyntax expr)]{ Illegal as an expression form. The @racket[unsyntax] form is for use only with a @racket[quasisyntax] template.} @defform[(unsyntax-splicing expr)]{ Illegal as an expression form. The @racket[unsyntax-splicing] form is for use only with a @racket[quasisyntax] template.} @defform[(syntax/loc stx-expr template) #:contracts ([stx-expr syntax?])]{ Like @racket[syntax], except that the immediate resulting syntax object takes its source-location information from the result of @racket[stx-expr] (which must produce a syntax object). Only the source location of the immediate result---the ``outermost'' syntax object---is adjusted. The source location is @emph{not} adjusted if both the source and position of @racket[stx-expr] are @racket[#f]. The source location is adjusted only if the resulting syntax object comes from the template itself rather than the value of a syntax pattern variable. For example, if @racket[_x] is a syntax pattern variable, then @racket[(syntax/loc stx-expr _x)] does not use the location of @racket[stx-expr]. @history[#:changed "6.90.0.25" @elem{Previously, @racket[syntax/loc] did not enforce the contract on @racket[stx-expr] if @racket[template] was just a pattern variable.}]} @defform[(quasisyntax/loc stx-expr template) #:contracts ([stx-expr syntax?])]{ Like @racket[quasisyntax], but with source-location assignment like @racket[syntax/loc].} @defform[(quote-syntax/prune id)]{ Like @racket[quote-syntax], but the lexical context of @racket[id] is pruned via @racket[identifier-prune-lexical-context] to including binding only for the symbolic name of @racket[id] and for @racket['#%top]. Use this form to quote an identifier when its lexical information will not be transferred to other syntax objects (except maybe to @racket['#%top] for a top-level binding).} @defform[(syntax-rules (literal-id ...) [(id . pattern) template] ...)]{ Equivalent to @racketblock/form[ (lambda (stx) (syntax-case stx (literal-id ...) [(_generated-id . pattern) (syntax-protect (syntax template))] ...)) ] where each @racket[_generated-id] binds no identifier in the corresponding @racket[template].} @defform[(syntax-id-rules (literal-id ...) [pattern template] ...)]{ Equivalent to @racketblock[ (make-set!-transformer (lambda (stx) (syntax-case stx (literal-id ...) [pattern (syntax-protect (syntax template))] ...))) ]} @defform[(define-syntax-rule (id . pattern) template)]{ Equivalent to @racketblock/form[ (define-syntax id (syntax-rules () [(id . pattern) template])) ] but with syntax errors potentially phrased in terms of @racket[pattern].} @defidform[...]{ The @racket[...] transformer binding prohibits @racket[...] from being used as an expression. This binding is useful only in syntax patterns and templates (or other unrelated expression forms that treat it specially like @racket[->]), where it indicates repetitions of a pattern or template. See @racket[syntax-case] and @racket[syntax].} @defidform[_]{ The @racket[_] transformer binding prohibits @racket[_] from being used as an expression. This binding is useful only in syntax patterns, where it indicates a pattern that matches any syntax object. See @racket[syntax-case].} @deftogether[[ @defidform[~?] @defidform[~@] ]]{ The @racket[~?] and @racket[~@] transformer bindings prohibit these forms from being used as an expression. The bindings are useful only in syntax templates. See @racket[syntax]. @history[#:added "6.90.0.25"]} @defproc[(syntax-pattern-variable? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a value that, as a transformer-binding value, makes the bound variable as pattern variable in @racket[syntax] and other forms. To check whether an identifier is a pattern variable, use @racket[syntax-local-value] to get the identifier's transformer value, and then test the value with @racket[syntax-pattern-variable?]. The @racket[syntax-pattern-variable?] procedure is provided @racket[for-syntax] by @racketmodname[racket/base].}