Next: stdlib syntax-case violations, Previous: stdlib syntax-case temporaries, Up: stdlib syntax-case [Index]
The forms and procedures described in this section can be defined in terms of the forms and procedures described in earlier sections of this chapter.
The with-syntax form is used to bind pattern variables, just as
let is used to bind variables.  This allows a transformer to
construct its output in separate pieces, then put the pieces together.
Each ?pattern is identical in form to a syntax-case
pattern.  The value of each ?expression is computed and
destructured according to the corresponding ?pattern, and pattern
variables within the ?pattern are bound as with
syntax-case to the corresponding portions of the value within
?body.
The with-syntax form may be defined in terms of
syntax-case as follows.
(define-syntax with-syntax
  (lambda (x)
    (syntax-case x ()
      ((_ ((p e0) ...) e1 e2 ...)
       (syntax (syntax-case (list e0 ...) ()
                 ((p ...) (let () e1 e2 ...))))))))
As example of deconstructing a syntax object:
(define stx (datum->syntax #'display '(1 2 3))) (with-syntax (((a b ...) stx)) (syntax->datum #'a)) ⇒ 1
The following definition of cond demonstrates the use of
with-syntax to support transformers that employ recursion
internally to construct their output.  It handles all cond clause
variations and takes care to produce one-armed if expressions
where appropriate.
(define-syntax cond
  (lambda (x)
    (syntax-case x ()
      ((_ c1 c2 ...)
       (let f ((c1 #'c1) (c2* #'(c2 ...)))
         (syntax-case c2* ()
           (()
            (syntax-case c1 (else =>)
              ((else e1 e2 ...) #'(begin e1 e2 ...))
              ((e0) #'e0)
              ((e0 => e1)
               #'(let ((t e0)) (if t (e1 t))))
              ((e0 e1 e2 ...)
               #'(if e0 (begin e1 e2 ...)))))
           ((c2 c3 ...)
            (with-syntax ((rest (f #'c2 #'(c3 ...))))
              (syntax-case c1 (=>)
                ((e0) #'(let ((t e0)) (if t t rest)))
                ((e0 => e1)
                 #'(let ((t e0)) (if t (e1 t) rest)))
                ((e0 e1 e2 ...)
                 #'(if e0
                       (begin e1 e2 ...)
                     rest)))))))))))
The quasisyntax form is similar to syntax, but it allows
parts of the quoted text to be evaluated, in a manner similar to the
operation of quasiquote (see baselib quasiquotation).
Within a quasisyntax template, subforms of unsyntax
and unsyntax-splicing forms are evaluated, and everything else is
treated as ordinary template material, as with syntax.
The value of each unsyntax subform is inserted into the output in
place of the unsyntax form, while the value of each
unsyntax-splicing subform is spliced into the surrounding list or
vector structure.  Uses of unsyntax and unsyntax-splicing
are valid only within quasisyntax expressions.
A quasisyntax expression may be nested, with each
quasisyntax introducing a new level of syntax quotation and each
unsyntax or unsyntax-splicing taking away a level of
quotation.  An expression nested within n quasisyntax
expressions must be within n unsyntax or
unsyntax-splicing expressions to be evaluated.
As noted in scheme lex datum abbreviations:
#`?template ≡ (quasisyntax ?template) #,?template ≡ (unsyntax ?template) #,@?template ≡ (unsyntax-splicing ?template)
The quasisyntax keyword can be used in place of
with-syntax in many cases.  For example, the definition of
case shown under the description of with-syntax above can
be rewritten using quasisyntax as follows.
(define-syntax case
  (lambda (x)
    (syntax-case x ()
      ((_ e c1 c2 ...)
       #`(let ((t e))
           #,(let f ((c1 #'c1) (cmore #'(c2 ...)))
               (if (null? cmore)
                   (syntax-case c1 (else)
                     ((else e1 e2 ...)
                      #'(begin e1 e2 ...))
                     (((k ...) e1 e2 ...)
                      #'(when (memv t '(k ...))
                          (begin e1 e2 ...))))
                   (syntax-case c1 ()
                     (((k ...) e1 e2 ...)
                      #`(if (memv t '(k ...))
                            (begin e1 e2 ...)
                          #,(f (car cmore)
                               (cdr cmore))))))))))))
Uses of unsyntax and unsyntax-splicing with zero or more
than one subform are valid only in splicing (list or vector) contexts.
(unsyntax template …) is equivalent to
(unsyntax template) ..., and (unsyntax-splicing
template ...) is equivalent to (unsyntax-splicing
template) ....  These forms are primarily useful as intermediate
forms in the output of the quasisyntax expander.
NOTE Uses of
unsyntaxandunsyntax-splicingwith zero or more than one subform enable certain idioms, such as ‘#,@#,@’, which has the effect of a doubly indirect splicing when used within a doubly nested and doubly evaluatedquasisyntaxexpression, as with the nestedquasiquoteexamples shown in section baselib quasiquotation.
Next: stdlib syntax-case violations, Previous: stdlib syntax-case temporaries, Up: stdlib syntax-case [Index]