Next: , Previous: , Up: stdlib syntax-case   [Index]


5.12.4 Transformers

In define-syntax, let-syntax, and letrec-syntax forms, a binding for a syntactic keyword is an expression that evaluates to a transformer.

A transformer is a transformation procedure or a variable transformer. A transformation procedure is a procedure that must accept one argument, a wrapped syntax object representing the input, and return a syntax object representing the output. The transformer is called by the expander whenever a reference to a keyword with which it has been associated is found. If the keyword appears in the car of a list–structured input form, the transformer receives the entire list–structured form, and its output replaces the entire form.

Except with variable transformers (see below), if the keyword is found in any other definition or expression context, the transformer receives a wrapped syntax object representing just the keyword reference, and its output replaces just the reference. Except with variable transformers, an exception with condition type &syntax is raised if the keyword appears on the left–hand side of a set! expression.

Let’s set what this means with an example:

(import (rnrs))

(define a 1)
(define (b arg) (list 2 arg))

(define-syntax doit
  (lambda (stx)
    (syntax-case stx ()
      (?x
       (identifier? #'?x)
       #'a)
      ((?x ?arg)
       #'(b ?arg)))))

doit            ⇒ 1
(doit 3)        ⇒ (2 3)
(set! doit 5)   error→ &syntax

when the macro use (doit 3) is expanded: the transformer receives the whole form (doit 3) in the syntax object argument; when the macro use doit is expanded: the transformer receives only the identifier doit in the syntax object argument; when the keyword doit is used in set! doit 1: the expander recognises this situation as invalid, rather than a reference to doit, and it raises an exception.

Procedure: make-variable-transformer proc

proc should accept one argument, a wrapped syntax object, and return a syntax object.

The make-variable-transformer procedure creates a variable transformer. A variable transformer is like an ordinary transformer except that, if a keyword associated with a variable transformer appears on the left–hand side of a set! expression, an exception is not raised. Instead, proc is called with a wrapped syntax object representing the entire set! expression as its argument, and its return value replaces the entire set! expression.

Implementation responsibilities: The implementation must check the restrictions on proc only to the extent performed by applying it as described. An implementation may check whether proc is an appropriate argument before applying it.

The following example shows the difference between a common transformer and a transformer wrapped by make-variable-transformer:

(import (rnrs))

(define a 1)
(define (b arg) (list 2 arg))
(define (c arg) (list 4 arg))

(define-syntax doit
  (make-variable-transformer
    (lambda (stx)
      (syntax-case stx (set!)
        (?x
         (identifier? #'?x)
         #'a)
        ((?x ?arg)
         #'(b ?arg))
        ((set! ?x ?expr)
         #'(c ?expr))
        ))))

doit            ⇒ 1
(doit 3)        ⇒ (2 3)
(set! doit 5)   ⇒ (4 5)

The following is another meaningless example using the unwrap function defined in stdlib syntax-case intro:

(import (rnrs) (for (syntax-utilities) expand))

(define-syntax alpha
  (make-variable-transformer
   (lambda (use)
     (write (unwrap use))
     (newline)
     #f)))

(set! alpha 123)
-| (#<syntax set!> #<syntax alpha> 123)

alpha
-| #<syntax alpha>

Notice that syntax-rules accepts only patterns being lists or vectors; the following definition will raise a syntax violation:

(define-syntax doit
  (syntax-rules () (x a))) error→ &syntax

Next: , Previous: , Up: stdlib syntax-case   [Index]