#lang scribble/doc
@(require "mz.ss")

@(define lit-ellipses (scheme ...))

@(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 ellipses pattern ...)
                        (pattern ... pattern ellipses pattern ... . pattern)
                        (code:line #,(tt "#")(pattern ...))
                        (code:line #,(tt "#")(pattern ... pattern ellipses pattern ...))
                        (code:line #,(tt "#s")(key-datum pattern ...))
                        (code:line #,(tt "#s")(key-datum pattern ... pattern ellipses pattern ...))
                        (ellipses stat-pattern)
                        const]
               [stat-pattern id
                             (stat-pattern ...)
                             (stat-pattern ...+ . stat-pattern)
                             (code:line #,(tt "#")(stat-pattern ...))
                             const]
               [ellipses #,lit-ellipses])]{

Finds the first @scheme[pattern] that matches the syntax object
produced by @scheme[stx-expr], and for which the corresponding
@scheme[fender-expr] (if any) produces a true value; the result is
from the corresponding @scheme[result-expr], which is in tail position
for the @scheme[syntax-case] form. If no @scheme[clause] matches, then
the @exnraise[exn:fail:syntax]; the exception is generated by calling
@scheme[raise-syntax-error] with @scheme[#f] as the ``name'' argument,
a string with a generic error message, and the result of @scheme[stx-expr].

A syntax object matches a @scheme[pattern] as follows:

 @specsubform[_]{

 A @scheme[_] pattern (i.e., an identifier with the same binding as
 @scheme[_]) matches any syntax object.}

 @specsubform[id]{

 An @scheme[id] matches any syntax object when it is not bound to
 @scheme[...] or @scheme[_] and does not have the same binding as
 any @scheme[literal-id]. The @scheme[id] is further bound as
 @deftech{pattern variable} for the corresponding @scheme[fender-expr]
 (if any) and @scheme[result-expr]. A pattern-variable binding is a
 transformer binding; the pattern variable can be reference only
 through forms like @scheme[syntax]. The binding's value is the syntax
 object that matched the pattern with a @deftech{depth marker} of
 @math{0}.

 An @scheme[id] that has the same binding as a @scheme[literal-id]
 matches a syntax object that is an identifier with the same binding
 in the sense of @scheme[free-identifier=?].  The match does not
 introduce any @tech{pattern variables}.}

 @specsubform[(pattern ...)]{

 A @scheme[(pattern ...)] pattern matches a syntax object whose datum
 form (i.e., without lexical information) is a list with as many
 elements as sub-@scheme[pattern]s in the pattern, and where each
 syntax object that corresponding to an element of the list matches
 the corresponding sub-@scheme[pattern].

 Any @tech{pattern variables} bound by the sub-@scheme[pattern]s are
 bound by the complete pattern; the bindings must all be distinct.}

 @specsubform[(pattern ...+ . pattern)]{

 The last @scheme[pattern] must not be a @racket/form[(pattern ...)],
 @racket/form[(pattern ...+ . pattern)], @racket/form[(pattern ... pattern
 ellipses pattern ...)], or @racket/form[(pattern ... pattern ellipses
 pattern ... . pattern)] form.

 Like the previous kind of pattern, but matches syntax objects that
 are not necessarily lists; for @math{n} sub-@scheme[pattern]s before
 the last sub-@scheme[pattern], the syntax object's datum must be a
 pair such that @math{n-1} @scheme[cdr]s produce pairs. The last
 sub-@scheme[pattern] is matched against the syntax object
 corresponding to the @math{n}th @scheme[cdr] (or the
 @scheme[datum->syntax] coercion of the datum using the nearest
 enclosing syntax object's lexical context and source location).}

 @specsubform[(pattern ... pattern ellipses pattern ...)]{

 Like the @scheme[(pattern ...)] kind of pattern, but matching a
 syntax object with any number (zero or more) elements that match the
 sub-@scheme[pattern] followed by @scheme[ellipses] in the
 corresponding position relative to other sub-@scheme[pattern]s.

 For each pattern variable bound by the sub-@scheme[pattern] followed
 by @scheme[ellipses], 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-@scheme[pattern], with an incremented
 @tech{depth marker}. (The sub-@scheme[pattern] itself may contain
 @scheme[ellipses], 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 ellipses pattern ... . pattern)]{

 Like the previous kind of pattern, but with a final
 sub-@scheme[pattern] as for @scheme[(pattern ...+ . pattern)].  The
 final @scheme[pattern] never matches a syntax object whose datum is a
 pair.}

 @specsubform[(code:line #,(tt "#")(pattern ...))]{

 Like a @scheme[(pattern ...)] pattern, but matching a vector syntax object
 whose elements match the corresponding sub-@scheme[pattern]s.}

 @specsubform[(code:line #,(tt "#")(pattern ... pattern ellipses pattern ...))]{

 Like a @scheme[(pattern ... pattern ellipses pattern ...)] pattern,
 but matching a vector syntax object whose elements match the
 corresponding sub-@scheme[pattern]s.}

 @specsubform[(code:line #,(tt "#s")(key-datum pattern ...))]{

 Like a @scheme[(pattern ...)] pattern, but matching a @tech{prefab}
 structure syntax object whose fields match the corresponding
 sub-@scheme[pattern]s. The @scheme[key-datum] must correspond to a
 valid first argument to @scheme[make-prefab-struct].}

 @specsubform[(code:line #,(tt "#s")(key-datum pattern ... pattern ellipses pattern ...))]{

 Like a @scheme[(pattern ... pattern ellipses pattern ...)] pattern,
 but matching a @tech{prefab} structure syntax object whose elements
 match the corresponding sub-@scheme[pattern]s.}

 @specsubform[(ellipses stat-pattern)]{

 Matches the same as @scheme[stat-pattern], which is like a @scheme[pattern],
 but identifiers with the binding @scheme[...] are treated the same as
 other @scheme[id]s.}

 @specsubform[const]{

 A @scheme[const] is any datum that does not match one of the
 preceding forms; a syntax object matches a @scheme[const] pattern
 when its datum is @scheme[equal?] to the @scheme[quote]d
 @scheme[const].}

@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 ...)])
]}

@defform[(syntax-case* stx-expr (literal-id ...) id-compare-expr
           clause ...)]{

Like @scheme[syntax-case], but @scheme[id-compare-expr] must produce a
procedure that accepts two arguments. A @scheme[literal-id] in a
@scheme[_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 @scheme[_pattern] (as the second argument).

In other words, @scheme[syntax-case] is like @scheme[syntax-case*] with
an @scheme[id-compare-expr] that produces @scheme[free-identifier=?].}


@defform[(with-syntax ([pattern stx-expr] ...)
           body ...+)]{

Similar to @scheme[syntax-case], in that it matches a @scheme[pattern]
to a syntax object. Unlike @scheme[syntax-case], all @scheme[pattern]s
are matched, each to the result of a corresponding @scheme[stx-expr],
and the pattern variables from all matches (which must be distinct)
are bound with a single @scheme[body] sequence. The result of the
@scheme[with-syntax] form is the result of the last @scheme[body],
which is in tail position with respect to the @scheme[with-syntax]
form.

If any @scheme[pattern] fails to match the corresponding
@scheme[stx-expr], the @exnraise[exn:fail:syntax].

A @scheme[with-syntax] form is roughly equivalent to the following
@scheme[syntax-case] form:

@schemeblock[
(syntax-case (list stx-expr ...) ()
  [(pattern ...) (let () body ...+)])
]

However, if any individual @scheme[stx-expr] produces a
non-@tech{syntax object}, then it is converted to one using
@scheme[datum->syntax] and the lexical context and source location of
the individual @scheme[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/subs[(syntax template)
              ([template id
                         (template-elem ...)
                         (template-elem ...+ . template)
                         (code:line #,(tt "#")(template-elem ...))
                         (code:line #,(tt "#s")(key-datum template-elem ...))
                         (ellipses stat-template)
                         const]
               [template-elem (code:line template ellipses ...)]
               [stat-template id
                              (stat-template ...)
                              (stat-template ... . stat-template)
                              (code:line #,(tt "#")(stat-template ...))
                              (code:line #,(tt "#s")(key-datum stat-template ...))
                              const]
               [ellipses #,lit-ellipses])]{

Constructs a syntax object based on a @scheme[template],which can
inlude @tech{pattern variables} bound by @scheme[syntax-case] or
@scheme[with-syntax].

Template forms produce a syntax object as follows:

 @specsubform[id]{

 If @scheme[id] is bound as a @tech{pattern variable}, then
 @scheme[id] as a template produces the @tech{pattern variable}'s
 match result. Unless the @scheme[id] is a sub-@scheme[template] that is
 replicated by @scheme[ellipses] in a larger @scheme[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} @scheme[ellipses]es. In that case,
 the template will be replicated enough times to use each match result
 at least once.

 If @scheme[id] is not bound as a pattern variable, then @scheme[id]
 as a template produces @scheme[(quote-syntax id)].}

 @specsubform[(template-elem ...)]{

 Produces a syntax object whose datum is a list, and where the
 elements of the list correspond to syntax objects producesd by the
 @scheme[template-elem]s.

 A @scheme[template-elem] is a sub-@scheme[template] replicated by any
 number of @scheme[ellipses]es:

 @itemize[

  @item{If the sub-@scheme[template] is replicated by no
   @scheme[ellipses]es, then it generates a single syntax object to
   incorporate into the result syntax object.}

  @item{If the sub-@scheme[template] is replicated by one
   @scheme[ellipses], then it generates a sequence of syntax objects
   that is ``inlined'' into the resulting syntax object.

   The number of generated elements depends the values of
   @tech{pattern variables} referenced within the
   sub-@scheme[template]. There must be at least one @tech{pattern
   variable} whose value is has a @tech{depth marker} less than the
   number of @scheme[ellipses]es after the pattern variable within the
   sub-@scheme[template].

   If a @tech{pattern variable} is replicated by more
   @scheme[ellipses]es in a @scheme[template] than the @tech{depth
   marker} of its binding, then the @tech{pattern variable}'s result
   is determined normally for inner @scheme[ellipses]es (up to the
   binding's @tech{depth marker}), and then the result is replicated
   as necessary to satisfy outer @scheme[ellipses]es.}

 @item{For each @scheme[ellipses] after the first one, the preceding
   element (with earlier replicating @scheme[ellipses]s) is
   conceptually wrapped with parentheses for generating output, and
   then the wrapping parentheses are removed in the resulting syntax
   object.}]}

 @specsubform[(template-elem ... . template)]{

  Like the previous form, but the result is not necessarily a list;
  instead, the place of the empty list in resulting syntax object's
  datum is taken by the syntax object produced by @scheme[template].}

 @specsubform[(code:line #,(tt "#")(template-elem ...))]{

   Like the @scheme[(template-elem ...)] form, but producing a syntax
   object whose datum is a vector instead of a list.}

 @specsubform[(code:line #,(tt "#s")(key-datum template-elem ...))]{

   Like the @scheme[(template-elem ...)] form, but producing a syntax
   object whose datum is a @tech{prefab} structure instead of a list.
   The @scheme[key-datum] must correspond to a valid first argument of
   @scheme[make-prefab-struct].}

 @specsubform[(ellipses stat-template)]{

  Produces the same result as @scheme[stat-template], which is like a
  @scheme[template], but @scheme[...] is treated like a @scheme[id]
  (with no pattern binding).}

 @specsubform[const]{

  A @scheme[const] template is any form that does not match the
  preceding cases, and it produces the result @scheme[(quote-syntac
  const)].}

A @scheme[(#,(schemekeywordfont "syntax") template)] form is normally
abbreviated as @scheme[#'template]; see also
@secref["parse-quote"]. If @scheme[template] contains no pattern
variables, then @scheme[#'template] is equivalent to
@scheme[(quote-syntax template)].}


@defform[(quasisyntax template)]{

Like @scheme[syntax], but @scheme[(#,(schemekeywordfont "unsyntax")
_expr)] and @scheme[(#,(schemekeywordfont "unsyntax-splicing") _expr)]
escape to an expression within the @scheme[template].

The @scheme[_expr] must produce a syntax object (or syntax list) to be
substituted in place of the @scheme[unsyntax] or
@scheme[unsyntax-splicing] form within the quasiquoting template, just
like @scheme[unquote] and @scheme[unquote-splicing] within
@scheme[quasiquote]. (If the escaped expression does not generate a
syntax object, it is converted to one in the same was as for the
right-hand sides of @scheme[with-syntax].)  Nested
@scheme[quasisyntax]es introduce quasiquoting layers in the same way
as nested @scheme[quasiquote]s.

Also analogous @scheme[quasiquote], the reader converts @litchar{#`}
to @scheme[quasisyntax], @litchar{#,} to @scheme[unsyntax], and
@litchar["#,@"] to @scheme[unsyntax-splicing]. See also
@secref["parse-quote"].}



@defform[(unsyntax expr)]{

Illegal as an expression form. The @scheme[unsyntax] form is for use
only with a @scheme[quasisyntax] template.}


@defform[(unsyntax-splicing expr)]{

Illegal as an expression form. The @scheme[unsyntax-splicing] form is
for use only with a @scheme[quasisyntax] template.}


@defform[(syntax/loc stx-expr template)]{

Like @scheme[syntax], except that the immediate resulting syntax
object takes its source-location information from the result of
@scheme[stx-expr] (which must produce a syntax object), unless the
@scheme[template] is just a pattern variable or both the source and
position of @scheme[stx-expr] are @scheme[#f].}


@defform[(quasisyntax/loc stx-expr template)]{

Like @scheme[quasisyntax], but with source-location assignment like
@scheme[syntax/loc].}


@defform[(quote-syntax/prune id)]{

Like @scheme[quote-syntax], but the lexical context of @scheme[id] is
pruned via @scheme[identifier-prune-lexical-context] to including
binding only for the symbolic name of @scheme[id] and for
@scheme['#%top]. Use this form to quote an identifier when its lexical
information will not be transferred to other syntax objects (except
maybe to @scheme['#%top] for a top-level binding).}


@defform[(syntax-rules (literal-id ...)
           [(id . pattern) template] ...)]{

Equivalent to

@schemeblock/form[
(lambda (stx)
  (syntax-case stx (literal-id ...)
    [(_generated-id . pattern) (syntax template)] ...))
]

where each @scheme[_generated-id] binds no identifier in the
corresponding @scheme[template].}


@defform[(syntax-id-rules (literal-id ...)
           [pattern template] ...)]{

Equivalent to

@schemeblock[
(lambda (stx)
  (make-set!-transformer
   (syntax-case stx (literal-id ...)
     [pattern (syntax template)] ...)))
]}


@defform[(define-syntax-rule (id . pattern) template)]{

Equivalent to

@schemeblock/form[
(define-syntax id
  (syntax-rules ()
   [(id . pattern) template]))
]
}


@defidform[...]{

The @scheme[...] transformer binding prohibits @scheme[...] from
being used as an expression. This binding useful only in syntax
patterns and templates, where it indicates repetitions of a pattern or
template. See @scheme[syntax-case] and @scheme[syntax].}

@defidform[_]{

The @scheme[_] transformer binding prohibits @scheme[_] from being
used as an expression. This binding useful only in syntax patterns,
where it indicates a pattern that matches any syntax object. See
@scheme[syntax-case].}


@defproc[(syntax-pattern-variable? [v any/c]) boolean?]{

Return @scheme[#t] if @scheme[v] is a value that, as a
transformer-binding value, makes the bound variable as pattern
variable in @scheme[syntax] and other forms. To check whether an
identifier is a pattern variable, use @scheme[syntax-local-value] to
get the identifier's transformer value, and then test the value with
@scheme[syntax-pattern-variable?].

The @scheme[syntax-pattern-variable?] procedure is provided
@scheme[for-syntax] by @schememodname[racket/base].}
