manpagez: man pages & more
info guile
Home | html | info | man
[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.10.3 Support for the syntax-case System

syntax-case macros are procedural syntax transformers, with a power worthy of Scheme.

Syntax: syntax-case syntax literals (pattern [guard] exp)...

Match the syntax object syntax against the given patterns, in order. If a pattern matches, return the result of evaluating the associated exp.

Compare the following definitions of when:

(define-syntax when
  (syntax-rules ()
    ((_ test e e* ...)
     (if test (begin e e* ...)))))

(define-syntax when
  (lambda (x)
    (syntax-case x ()
      ((_ test e e* ...)
       #'(if test (begin e e* ...))))))

Clearly, the syntax-case definition is similar to its syntax-rules counterpart, and equally clearly there are some differences. The syntax-case definition is wrapped in a lambda, a function of one argument; that argument is passed to the syntax-case invocation; and the “return value” of the macro has a #' prefix.

All of these differences stem from the fact that syntax-case does not define a syntax transformer itself – instead, syntax-case expressions provide a way to destructure a syntax object, and to rebuild syntax objects as output.

So the lambda wrapper is simply a leaky implementation detail, that syntax transformers are just functions that transform syntax to syntax. This should not be surprising, given that we have already described macros as “programs that write programs”. syntax-case is simply a way to take apart and put together program text, and to be a valid syntax transformer it needs to be wrapped in a procedure.

Unlike traditional Lisp macros (see section Lisp-style Macro Definitions), syntax-case macros transform syntax objects, not raw Scheme forms. Recall the naive expansion of my-or given in the previous section:

(let ((t #t))
  (my-or #f t))
;; naive expansion:
(let ((t #t))
  (let ((t #f))
    (if t t t)))

Raw Scheme forms simply don’t have enough information to distinguish the first two t instances in (if t t t) from the third t. So instead of representing identifiers as symbols, the syntax expander represents identifiers as annotated syntax objects, attaching such information to those syntax objects as is needed to maintain referential transparency.

Syntax: syntax form

Create a syntax object wrapping form within the current lexical context.

Syntax objects are typically created internally to the process of expansion, but it is possible to create them outside of syntax expansion:

(syntax (foo bar baz))
⇒ #<some representation of that syntax>

However it is more common, and useful, to create syntax objects when building output from a syntax-case expression.

(define-syntax add1
  (lambda (x)
    (syntax-case x ()
      ((_ exp)
       (syntax (+ exp 1))))))

It is not strictly necessary for a syntax-case expression to return a syntax object, because syntax-case expressions can be used in helper functions, or otherwise used outside of syntax expansion itself. However a syntax transformer procedure must return a syntax object, so most uses of syntax-case do end up returning syntax objects.

Here in this case, the form that built the return value was (syntax (+ exp 1)). The interesting thing about this is that within a syntax expression, any appearance of a pattern variable is substituted into the resulting syntax object, carrying with it all relevant metadata from the source expression, such as lexical identity and source location.

Indeed, a pattern variable may only be referenced from inside a syntax form. The syntax expander would raise an error when defining add1 if it found exp referenced outside a syntax form.

Since syntax appears frequently in macro-heavy code, it has a special reader macro: #'. #'foo is transformed by the reader into (syntax foo), just as 'foo is transformed into (quote foo).

The pattern language used by syntax-case is conveniently the same language used by syntax-rules. Given this, Guile actually defines syntax-rules in terms of syntax-case:

(define-syntax syntax-rules
  (lambda (x)
    (syntax-case x ()
      ((_ (k ...) ((keyword . pattern) template) ...)
       #'(lambda (x)
           (syntax-case x (k ...)
             ((dummy . pattern) #'template)

And that’s that.

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated on April 20, 2013 using texi2html 5.0.

© 2000-2019
Individual documents may contain additional copyright information.