Next: Signaling errors in macro transformers, Previous: Binding constructs for syntactic keywords, Up: Macros [Index]
A ⟨transformer spec⟩ has one of the following forms:
(syntax-rules (
⟨pattern literal⟩ …)
⟨syntax rule⟩ …)
(syntax-rules
⟨ellipsis⟩(
⟨pattern literal⟩ …)
⟨syntax rule⟩ …)
Syntax: It is an error if any of the ⟨pattern literal⟩s, or the ⟨ellipsis⟩ in the second form, is not an identifier. It is also an error if ⟨syntax rule⟩ is not of the form
(⟨pattern⟩ ⟨template⟩)
The ⟨pattern⟩ in a ⟨syntax rule⟩ is a list ⟨pattern⟩ whose first element is an identifier.
A ⟨pattern⟩ is either an identifier, a constant, or one of the following
(
⟨pattern⟩ …)
(
⟨pattern⟩ ⟨pattern⟩ ….
⟨pattern⟩)
(
⟨pattern⟩ … ⟨pattern⟩ ⟨ellipsis⟩ ⟨pattern⟩ …)
(
⟨pattern⟩ … ⟨pattern⟩ ⟨ellipsis⟩ ⟨pattern⟩ ….
⟨pattern⟩)
#(
⟨pattern⟩ …)
#(
⟨pattern⟩ … ⟨pattern⟩ ⟨ellipsis⟩ ⟨pattern⟩ …)
and a ⟨template⟩ is either an identifier, a constant, or one of the following
(
⟨element⟩ …)
(
⟨element⟩ ⟨element⟩ ….
⟨template⟩)
(
⟨ellipsis⟩ ⟨template⟩)
#(
⟨element⟩ …)
where an ⟨element⟩ is a ⟨template⟩ optionally followed by
an ⟨ellipsis⟩. An ⟨ellipsis⟩ is the identifier specified
in the second form of syntax-rules
, or the default identifier
…
(three consecutive periods) otherwise.
Semantics: An instance of syntax-rules
produces a new macro
transformer by specifying 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 rule⟩s, beginning with the leftmost ⟨syntax rule⟩. When
a match is found, the macro use is transcribed hygienically according
to the template.
An identifier appearing within a ⟨pattern⟩ can be an underscore
(_
), a literal identifier listed in the list of ⟨pattern
literal⟩s, or the ⟨ellipsis⟩. All other identifiers appearing within
a ⟨pattern⟩ are pattern variables.
The keyword at the beginning of the pattern in a ⟨syntax rule⟩ is not involved in the matching and is considered neither a pattern variable nor a literal identifier.
Pattern variables match arbitrary input elements and are used to refer to elements of the input in the template. It is an error for the same pattern variable to appear more than once in a ⟨pattern⟩.
Underscores also match arbitrary input elements but are not pattern variables and so cannot be used to refer to those elements. If an underscore appears in the ⟨pattern literal⟩s list, then that takes precedence and underscores in the ⟨pattern⟩ match as literals. Multiple underscores can appear in a ⟨pattern⟩.
Identifiers that appear in (
⟨pattern literal⟩ …)
are interpreted as literal identifiers to be matched against corresponding
elements of the input. An element in the input matches a literal
identifier if and only if it is an identifier and either both its
occurrence in the macro expression and its occurrence in the macro
definition have the same lexical binding, or the two identifiers are
the same and both have no lexical binding.
A subpattern followed by ⟨ellipsis⟩ can match zero or more elements of the input, unless ⟨ellipsis⟩ appears in the ⟨pattern literal⟩s, in which case it is matched as a literal.
More formally, an input expression E matches a pattern P if and only if:
_
).
(
P1 … Pn)
and E is a list of n elements that match P1
through Pn, respectively; or
(
P1 P2 … Pn .
Pn+1)
and E is a list or
improper list of n or more elements that match P1
through Pn respectively, and whose nth tail matches
Pn+1; or
(
P1 … Pk Pe
⟨ellipsis⟩ Pm+1 … Pn)
where E is a proper list of n elements, the first k
of which match P1 through Pk, respectively,
whose next m - k elements each match Pe,
whose remaining n - m elements match Pm+1
through Pn; or
(
P1 … Pk Pe
⟨ellipsis⟩ Pm+1 … Pn .
Px)
where E is a list or improper list of
n elements, the first k of which match P1 through
Pk, whose next m - k elements each match
Pe, whose remaining n - m elements match
Pm+1 through Pn, and whose nth and final cdr
matches Px; or
#(
P1 …
Pn)
and E is a vector of n elements that
match P1 through Pn; or
#(
P1 … Pk
Pe ⟨ellipsis⟩ Pm+1 …
Pn)
where E is a vector of n elements the
first k of which match P1 through Pk, whose
next m - k elements each match Pe, and
whose remaining n - m elements match Pm+1
through Pn; or
equal?
procedure.
It is an error to use a macro keyword, within the scope of its binding, in an expression that does not match any of the patterns.
When a macro use is transcribed according to the template of the matching ⟨syntax rule⟩, pattern variables that occur in the template are replaced by the elements they match in the input. Pattern variables that occur in subpatterns followed by one or more instances of the identifier ⟨ellipsis⟩ are allowed only in subtemplates that are followed by as many instances of ⟨ellipsis⟩. They are replaced in the output by all of the elements they match in the input, distributed as indicated. It is an error if the output cannot be built up as specified.
Identifiers that appear in the template but are not pattern variables or
the identifier ⟨ellipsis⟩ are inserted into the output as literal
identifiers. If a literal identifier is inserted as a free identifier
then it refers to the binding of that identifier within whose scope
the instance of syntax-rules
appears. If a literal identifier is
inserted as a bound identifier then it is in effect renamed to prevent
inadvertent captures of free identifiers.
A template of the form (
⟨ellipsis⟩ ⟨template⟩)
is identical to ⟨template⟩, except that ellipses within the
template have no special meaning. That is, any ellipses contained within
⟨template⟩ are treated as ordinary identifiers. In particular,
the template (
⟨ellipsis⟩ ⟨ellipsis⟩⟨)⟩ produces
a single ⟨ellipsis⟩. This allows syntactic abstractions to expand
into code containing ellipses.
(define-syntax be-like-begin (syntax-rules () ((be-like-begin name) (define-syntax name (syntax-rules () ((name expr (... ...)) (begin expr (... ...)))))))) (be-like-begin sequence) (sequence 1 2 3 4) ⇒ 4
As an example, if let
and cond
are defined as in
Derived expression types then they are hygienic (as
required) and the following is not an error.
(let ((=> #f)) (cond (#t => 'ok))) ⇒ ok
The macro transformer for cond
recognizes =>
as a local
variable, and hence an expression, and not as the base identifier
=>
, which the macro transformer treats as a syntactic keyword. Thus
the example expands into
(let ((=> #f)) (if #t (begin => 'ok)))
instead of
(let ((=> #f)) (let ((temp #t)) (if temp ('ok temp))))
which would result in an invalid procedure call.
Next: Signaling errors in macro transformers, Previous: Binding constructs for syntactic keywords, Up: Macros [Index]