12.1 Pattern-Based Syntax Matching
syntax
(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) | #(pattern ...) | #(pattern ... pattern ellipsis pattern ...) | #&pattern | #s(key-datum pattern ...) | #s(key-datum pattern ... pattern ellipsis pattern ...) | (ellipsis stat-pattern) | const stat-pattern = id | (stat-pattern ...) | (stat-pattern ...+ . stat-pattern) | #(stat-pattern ...) | const ellipsis = ...
A syntax object matches a pattern as follows:
_ A _ pattern (i.e., an identifier with the same binding as _) matches any syntax object.
id An id matches any syntax object when it is not bound to ... or _ and does not have the same binding as any literal-id. The id is further bound as pattern variable for the corresponding fender-expr (if any) and result-expr. A pattern-variable binding is a transformer binding; the pattern variable can be referenced only through forms like syntax. The binding’s value is the syntax object that matched the pattern with a depth marker of 0.
An id that has the same binding as a literal-id matches a syntax object that is an identifier with the same binding in the sense of free-identifier=?. The match does not introduce any pattern variables.
(pattern ...) A (pattern ...) pattern matches a syntax object whose datum form (i.e., without lexical information) is a list with as many elements as sub-patterns in the pattern, and where each syntax object that corresponds to an element of the list matches the corresponding sub-pattern.
Any pattern variables bound by the sub-patterns are bound by the complete pattern; the bindings must all be distinct.
(pattern ...+ . pattern) The last pattern must not be a (pattern ...), (pattern ...+ . pattern), (pattern ... pattern ellipsis pattern ...), or (pattern ... pattern ellipsis pattern ... . pattern) form.
Like the previous kind of pattern, but matches syntax objects that are not necessarily lists; for n sub-patterns before the last sub-pattern, the syntax object’s datum must be a pair such that n-1 cdrs produce pairs. The last sub-pattern is matched against the syntax object corresponding to the nth cdr (or the datum->syntax coercion of the datum using the nearest enclosing syntax object’s lexical context and source location).
(pattern ... pattern ellipsis pattern ...) Like the (pattern ...) kind of pattern, but matching a syntax object with any number (zero or more) elements that match the sub-pattern followed by ellipsis in the corresponding position relative to other sub-patterns.
For each pattern variable bound by the sub-pattern followed by 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-pattern, with an incremented depth marker. (The sub-pattern itself may contain ellipsis, leading to a pattern variables bound to lists of lists of syntax objects with a depth marker of 2, and so on.)
(pattern ... pattern ellipsis pattern ... . pattern) Like the previous kind of pattern, but with a final sub-pattern as for (pattern ...+ . pattern). The final pattern never matches a syntax object whose datum is a pair.
#(pattern ...) Like a (pattern ...) pattern, but matching a vector syntax object whose elements match the corresponding sub-patterns.
#(pattern ... pattern ellipsis pattern ...) Like a (pattern ... pattern ellipsis pattern ...) pattern, but matching a vector syntax object whose elements match the corresponding sub-patterns.
#&pattern Matches a box syntax object whose content matches the pattern.
#s(key-datum pattern ...) Like a (pattern ...) pattern, but matching a prefab structure syntax object whose fields match the corresponding sub-patterns. The key-datum must correspond to a valid first argument to make-prefab-struct.
#s(key-datum pattern ... pattern ellipsis pattern ...) Like a (pattern ... pattern ellipsis pattern ...) pattern, but matching a prefab structure syntax object whose elements match the corresponding sub-patterns.
(ellipsis stat-pattern) Matches the same as stat-pattern, which is like a pattern, but identifiers with the binding ... are treated the same as other ids.
const A const is any datum that does not match one of the preceding forms; a syntax object matches a const pattern when its datum is equal? to the quoted const.
If stx-expr produces a non-syntax object, then its result is converted to a syntax object using datum->syntax and the lexical context and source location of the stx-expr.
If stx-expr produces a syntax object that is tainted
or armed, then any syntax object bound by a pattern
are tainted—
> (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)) '(10 5)
> (syntax-case #'(ops 1 2 3 => +) (=>) [(_ x ... => op) #'(op x ...)]) #<syntax:572:0 (+ 1 2 3)>
> (syntax-case #'(let ([x 5] [y 9] [z 12]) (+ x y z)) (let) [(let ([var expr] ...) body ...) (list #'(var ...) #'(expr ...))]) '(#<syntax:573:0 (x y z)> #<syntax:573:0 (5 9 12)>)
syntax
(syntax-case* stx-expr (literal-id ...) id-compare-expr clause ...)
In other words, syntax-case is like syntax-case* with an id-compare-expr that produces free-identifier=?.
syntax
(with-syntax ([pattern stx-expr] ...) body ...+)
If any pattern fails to match the corresponding stx-expr, the exn:fail:syntax exception is raised.
A with-syntax form is roughly equivalent to the following syntax-case form:
(syntax-case (list stx-expr ...) () [(pattern ...) (let () body ...+)])
However, if any individual stx-expr produces a non-syntax object, then it is converted to one using datum->syntax and the lexical context and source location of the individual stx-expr.
> (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)
Hello
jon
jon
> (utah 2)
From
utah
utah
> (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)
got 4
got 2
got 5
got 2
got 6
got 10
syntax
(syntax template)
template = id | (template-elem ...) | (template-elem ...+ . template) | #(template-elem ...) | #&template | #s(key-datum template-elem ...) | (ellipsis stat-template) | const template-elem = template ellipsis ... stat-template = id | (stat-template ...) | (stat-template ... . stat-template) | #(stat-template ...) | #&stat-template | #s(key-datum stat-template ...) | const ellipsis = ...
Template forms produce a syntax object as follows:
id If id is bound as a pattern variable, then id as a template produces the pattern variable’s match result. Unless the id is a sub-template that is replicated by ellipsis in a larger template, the pattern variable’s value must be a syntax object with a depth marker of 0 (as opposed to a list of matches).
More generally, if the pattern variable’s value has a depth marker n, then it can only appear within a template where it is replicated by at least n ellipsises. In that case, the template will be replicated enough times to use each match result at least once.
If id is not bound as a pattern variable, then id as a template produces (quote-syntax id).
(template-elem ...) Produces a syntax object whose datum is a list, and where the elements of the list correspond to syntax objects produced by the template-elems.
A template-elem is a sub-template replicated by any number of ellipsises:
If the sub-template is replicated by no ellipsises, then it generates a single syntax object to incorporate into the result syntax object.
If the sub-template is replicated by one ellipsis, then it generates a sequence of syntax objects that is “inlined” into the resulting syntax object.
The number of generated elements depends on the values of pattern variables referenced within the sub-template. There must be at least one pattern variable whose value has a depth marker less than the number of ellipsises after the pattern variable within the sub-template.
If a pattern variable is replicated by more ellipsises in a template than the depth marker of its binding, then the pattern variable’s result is determined normally for inner ellipsises (up to the binding’s depth marker), and then the result is replicated as necessary to satisfy outer ellipsises.
For each ellipsis after the first one, the preceding element (with earlier replicating ellipsises) is conceptually wrapped with parentheses for generating output, and then the wrapping parentheses are removed in the resulting syntax object.
(template-elem ... . 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 template.
#(template-elem ...) Like the (template-elem ...) form, but producing a syntax object whose datum is a vector instead of a list.
#&template Produces a syntax object whose datum is a box holding the syntax object produced by template.
#s(key-datum template-elem ...) Like the (template-elem ...) form, but producing a syntax object whose datum is a prefab structure instead of a list. The key-datum must correspond to a valid first argument of make-prefab-struct.
(ellipsis stat-template) Produces the same result as stat-template, which is like a template, but ... is treated like an id (with no pattern binding).
const A const template is any form that does not match the preceding cases, and it produces the result (quote-syntax const).
A (syntax template) form is normally abbreviated as #'template; see also Reading Quotes. If template contains no pattern variables, then #'template is equivalent to (quote-syntax template).
syntax
(quasisyntax template)
The expr must produce a syntax object (or syntax list) to be substituted in place of the unsyntax or unsyntax-splicing form within the quasiquoting template, just like unquote and unquote-splicing within 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 with-syntax.) Nested quasisyntaxes introduce quasiquoting layers in the same way as nested quasiquotes.
Also analogous to quasiquote, the reader converts #` to quasisyntax, #, to unsyntax, and #,@ to unsyntax-splicing. See also Reading Quotes.
syntax
(unsyntax expr)
syntax
(unsyntax-splicing expr)
syntax
(syntax/loc stx-expr template)
syntax
(quasisyntax/loc stx-expr template)
syntax
(quote-syntax/prune id)
syntax
(syntax-rules (literal-id ...) [(id . pattern) template] ...)
(lambda (stx) (syntax-case stx (literal-id ...) [(generated-id . pattern) (syntax-protect #'template)] ...))
where each generated-id binds no identifier in the corresponding template.
syntax
(syntax-id-rules (literal-id ...) [pattern template] ...)
(make-set!-transformer (lambda (stx) (syntax-case stx (literal-id ...) [pattern (syntax-protect #'template)] ...)))
syntax
(define-syntax-rule (id . pattern) template)
(define-syntax id (syntax-rules () [(id . pattern) template]))
but with syntax errors potentially phrased in terms of pattern.
syntax
syntax
procedure
v : any/c
The syntax-pattern-variable? procedure is provided for-syntax by racket/base.