(syntax-rules (pattern literal ...) syntax rule ...)
- syntax
(syntax-rules custom ellipsis (pattern literal ...) syntax rule ...)
- syntax
_
- auxiliary syntax
...
- auxiliary syntax
Syntax: Each pattern literal must be an identifier. If a custom ellipsis is provided, it must be an identifier. Each syntax rule has the form
(rule pattern template)
A template has the same form as in the definition of syntax
. A
rule pattern must have one of the following four forms:
(identifier pattern ...)
(identifier pattern ... . pattern)
(identifier pattern ... pattern ellipsis pattern ...)
(identifier pattern ... pattern ellipsis pattern ... . pattern)
Pattern has the same form as in the definition of syntax-case
.
Custom ellipsis, if provided, must be an identifier. Within a
rule pattern, pattern, and template, ellipsis refers
to an identifier which is bound-identifier=?
to this custom ellipsis
identifier, if it is provided, or to the auxiliary syntax keyword
...
otherwise.
Semantics: An instance of syntax-rules
evaluates to a transformer
procedure which operates according to a sequence of hygienic rewrite
rules. A use of a macro whose keyword is associated with a transformer
specified by syntax-rules
is matched against the patterns contained
in the syntax rules, beginning with the leftmost syntax rule.
When a match is found, the macro use is transcribed hygienically
according to the template. It is a syntax violation when no match is
found.
The identifier at the beginning of a rule pattern is not
involved in the matching and is considered neither a pattern variable
nor a literal identifier. Thus, rule patterns are like
syntax-case
patterns, but are restricted to matching uses of macros
which are not identifier macros.
Excluding the initial identifier, which is treated as if it were the
auxiliary syntax keyword _
, a macro use defined using syntax-rules
is transcribed according to the template of the matching syntax
rule as if the pattern had been matched using syntax-case
with the
same given list of pattern literals, and a syntax
expression
containing the template were the only content of that
syntax-case
clause’s output expression.
Examples:
The following macro destructively swaps the values associated with the identifiers it is given.
(define-syntax swap!
(syntax-rules ()
((_ a b)
(let ((temp a))
(set! a b)
(set! b temp)))))
Because hygiene is automatically maintained, the use of temp
as an
identifier internal to the expansion does not conflict with any
existing binding called temp
which exists in the place where the
macro is used:
(define temp 37)
(define fever-temp 38)
(swap! fever-temp temp)
(values temp fever-temp)
38
37
Further, local redefinitions or re-bindings of let
or set!
at the
place the macro is used do not affect the meaning of the macro
expansion:
(let-syntax
((let (erroneous-syntax "let is not allowed here")))
(swap! x y))
x
and y
without raising an errorBecause the identifiers introduced by each macro transcription step
receive a unique time-stamp, a recursively-expanding syntax-rules
macro can generate an arbitrary number of distinct identifiers. The
following example uses this together with the guaranteed evaluation
order of let*
to define a macro which expands into a normal Scheme
procedure call, but guarantees that the procedure and its operands
will be evaluated in left-to-right order.
(define-syntax call*
(syntax-rules ()
((_ args ...)
(call*-aux (args ...) ()))))
(define-syntax call*-aux
(syntax-rules ()
((_ (expr . more-exprs) (exprs-w/gen-ids ...))
(call*-aux more-exprs (exprs-w/gen-ids ... (gen-id expr))))
((_ () ((gen-id expr) ...))
(let* ((gen-id expr) ...)
(gen-id ...)))))
If the body of the let
expression in the following example were
simply (cons (read source) (read source))
, an implementation of
Scheme would be allowed to return ((then this) . this-first)
. Using
this call*
macro guarantees the intended result.
(let ((source (open-input-string "this-first (then this)")))
(call* cons (read source)
(read source)))
(this-first then this)
Implementation:
(define-syntax syntax-rules
(lambda (x)
(syntax-case x ()
((_ ell (lit ...) ((k . p) t) ...)
(and (identifier? #'ell)
(every identifier? #'(lit ... k ...)))
#'(lambda (x)
(syntax-case (custom-ellipsis ell) x (lit ...)
((_ . p) (syntax (custom-ellipsis ell) t)) ...)))
((_ (lit ...) ((k . p) t) ...)
(every identifier? #'(lit ... k ...))
#'(lambda (x)
(syntax-case x (lit ...)
((_ . p) #'t) ...))))))
Note: The syntax-rules
of this report is a compatible extension to
that of the small language, and the (scheme base)
library must
export the same binding [Editorial note: as whichever large language library this
ends up in ]. Compared to the small language version, the ability to
match macro uses of the form (keyword datum ... .
datum)
, to use multiple ellipses after a subtemplate, and to use
ellipsized subtemplates which include pattern variables with
mismatching levels of ellipsis nesting in the pattern have been added.
Compared to the R6RS version of syntax-rules
, the ability to rename
the ellipsis and to use the ellipsis and underscore as literals have
been added.
Compared to the R5RS version of syntax-rules
, the pattern language
has been extended to allow further patterns after an ellipsis, and
the special identifier _
to match any input form without creating a
pattern variable and the ability to rename the ellipsis have been
added. As in the small language version, the R5RS version also did not
allow macro uses of the form (keyword datum ... .
datum)
, nor multiple ellipses after a subtemplate, nor ellipsized
subtemplates with pattern variables at different levels of nesting in
the pattern.