Next: Syntactic Closures, Previous: Binding Constructs for Syntactic Keywords, Up: Macros [Contents][Index]
MIT/GNU Scheme supports a high-level pattern language for specifying macro
transformers. This pattern language is defined by the Revised^4 Report
and is portable to other conforming Scheme implementations. To use the
pattern language, specify a transformer-spec as a
syntax-rules
form:
Ellipsis is an identifier, and if omitted defaults to
...
. Literals is a list of identifiers and each
syntax-rule should be of the form
(pattern template)
The pattern in a syntax-rule is a list pattern that begins with the keyword for the macro.
A pattern is either an identifier, a constant, or one of the following
(pattern …) (pattern pattern … . pattern) (pattern … pattern ellipsis)
and a template is either an identifier, a constant, or one of the following
(element …) (element element … . template)
where an element is a template optionally followed by an ellipsis and an ellipsis is the identifier ‘...’ (which cannot be used as an identifier in either a template or a pattern).
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-rules, beginning with the leftmost syntax-rule. When
a match is found, the macro use is transcribed hygienically according to
the template.
An identifier that appears in the pattern of a syntax-rule is a pattern-variable, unless it is the keyword that begins the pattern, is listed in literals, or is the 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.
The keyword at the beginning of the pattern in a syntax-rule is not involved in the matching and is not considered a pattern variable or literal identifier.
Identifiers that appear in literals are interpreted as literal identifiers to be matched against corresponding subforms of the input. A subform 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 equal and both have no lexical binding.
A subpattern followed by ‘...’ can match zero or more elements of the input. It is an error for ‘...’ to appear in literals. Within a pattern the identifier ‘...’ must follow the last element of a nonempty sequence of subpatterns.
More formally, an input form F matches a pattern P if and only if:
(P_1 … P_n)
and F is a
list of n forms that match P_1 through P_n,
respectively; or
(P_1 P_2 … P_n
. P_n+1)
and F is a list or improper list of n or
more forms that match P_1 through P_n, respectively, and
whose nth “cdr” matches P_n+1; or
(P_1 … P_n P_n+1
ellipsis)
where ellipsis is the identifier ‘...’ and
F is a proper list of at least n forms, the first n of
which match P_1 through P_n, respectively, and each
remaining element of F matches P_n+1; 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 subforms they match in the input. Pattern variables that occur in subpatterns followed by one or more instances of the identifier ‘...’ are allowed only in subtemplates that are followed by as many instances of ‘...’. They are replaced in the output by all of the subforms 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 ‘...’ 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.
(let ((=> #f)) (cond (#t => 'ok))) ⇒ ok
The macro transformer for cond
recognizes =>
as a local variable, and hence an expression, and not as the
top-level 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: Syntactic Closures, Previous: Binding Constructs for Syntactic Keywords, Up: Macros [Contents][Index]