Next: stdlib syntax-case parsing, Previous: stdlib syntax-case objects, Up: stdlib syntax-case [Index]
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.
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: stdlib syntax-case parsing, Previous: stdlib syntax-case objects, Up: stdlib syntax-case [Index]