Chapter 10
Macros
Patterns
Approximately speaking, a pattern looks like the construct that it matches, but contains
pattern variables that bind to portions of the construct. Hence, a left-hand side in
the main-rule-set looks like a macro call. However, the grammar of patterns is
not the same as the grammar of programs, but contains just what is required to match the
portions of the Dylan grammar that are extensible by macros. Patterns have a simple nested
grammar, with semicolons, commas, and brackets used to indicate levels of nesting. See the
definition of pattern in Appendix A, BNF.
A pattern matches a fragment (a sequence of elementary fragments) by executing the following algorithm from left to right. It is easy to create patterns that are ambiguous when considered as grammars. This ambiguity is resolved by the left to right processing order and the specified try-shortest-first order for matching wildcards. Pattern matching succeeds only if all sub-patterns match. If pattern matching fails, the current rule fails and control passes to the next rule in the current rule set. If all patterns in a rule set fail to match, the macro call is invalid.
Multiple occurrences of the same pattern variable name in a single rule's left-hand side are not valid.
A pattern matches a fragment as follows:
- If the pattern consists of just one pattern-list, go to the next step. Otherwise, divide the pattern into subpatterns and the fragment into subfragments at semicolons, and match subpatterns to subfragments individually in order. The subpatterns and subfragments do not include the semicolons that separate them. Suppose the pattern consists of N + 1 pattern-lists separated by N semicolons. Locate the first N semicolons in the fragment (without looking inside of elementary fragments) and divide up the fragment into subfragments accordingly. The match fails if the fragment contains fewer than N - 1 semicolons. As a special case, if the fragment contains N - 1 semicolons, the match still succeeds and the last subfragment is empty. If the fragment contains more than N semicolons, the extra semicolons will be in the last subfragment.
A pattern-list matches a fragment as follows:
- If the pattern-list consists of just a pattern-sequence, go to the next step. If the pattern-list consists of just a property-list-pattern, go to that step. Otherwise divide the pattern-list into subpatterns and the fragment into subfragments at commas, and match subpatterns to subfragments individually in order. The subpatterns and subfragments do not include the commas that separate them. Suppose the pattern consists of N + 1 subpatterns separated by N commas. Locate the first N commas in the fragment (without looking inside of elementary fragments) and divide up the fragment into subfragments accordingly. The match fails if the fragment contains fewer than N - 1 commas. As a special case, if the fragment contains N - 1 commas, the match still succeeds and the last subfragment is empty. If the fragment contains more than N commas, the extra commas will be in the last subfragment. Note that the subdivision algorithms for commas and semicolons are identical.
A pattern-sequence matches a fragment as follows:
- Consider each simple-pattern in the pattern-sequence in turn from left to right. Each simple-pattern matches an initial subsequence of the fragment and consumes that subsequence, or fails. The entire pattern match fails if any simple-pattern fails, if the fragment is empty and the simple-pattern requires one or more elementary fragments, or if the fragment is not entirely consumed after all simple-patterns have been matched. There is a special backup and retry rule for wildcards, described below.
A simple-pattern matches a fragment as follows:
- A name or
=>
consumes one elementary fragment, which must be identical to the simple-pattern. A name matches a name that is spelled the same, independent of modules, lexical scoping issues, alphabetic case, and backslash quoting. As a special case, after the wordotherwise
, an=>
is optional in both the pattern and the fragment. Presence or absence of the arrow in either place makes no difference to matching. - A bracketed-pattern matches and consumes
a bracketed-fragment. If the enclosed pattern is omitted, the
enclosed body-fragment must be empty, otherwise the enclosed pattern
must match the enclosed body-fragment (which can be empty). The type of
brackets (
()
,[]
, or{}
) in the bracketed-fragment must be the same as the type of brackets in the bracketed-pattern.
A binding-pattern matches a fragment as follows:
- pattern-variable
::
pattern-variable consumes as much of the fragment as can be parsed by the grammar for variable. It matches the first pattern-variable to the variable-name and the second to the type, a parsed expression fragment. If no specializer is present, it matches the second pattern-variable to a parsed expression fragment that is a named value reference to<object>
in the Dylan module. This matching checks the constraints on the pattern variable, fails if the constraint is not satisfied, and binds the pattern variable to the fragment. - pattern-variable
=
pattern-variable consumes as much of the fragment as can be parsed by the grammar for variable=
expression. It matches the first pattern-variable to the variable, a fragment, and the second to the expression, a parsed expression fragment. - pattern-variable
::
pattern-variable=
pattern-variable consumes as much of the fragment as can be parsed by the grammar for variable=
expression. It matches the first two pattern-variables the same as the first kind of binding-pattern and it matches the third pattern-variable the same as the second kind of binding-pattern.
A pattern-variable matches a fragment as follows:
- When the constraint is a wildcard constraint
(see
Pattern Variable Constraints
on page 157), the pattern variable consumes some initial subsequence of the fragment, using a backup and retry algorithm. First, the wildcard consumes no elementary fragments, and matching continues with the next simple-pattern in the pattern-sequence. If any simple-pattern in the current pattern-sequence fails to match, back up to the wildcard, consume one more elementary fragment than before, and retry matching the rest of the pattern-sequence, starting one elementary fragment to the right of the previous start point. Once the entire pattern-sequence has successfully matched, the pattern variable binds to a fragment consisting of the sequence of elementary fragments that it consumed. - It is an error for more than one of the simple-patterns directly contained in a pattern-sequence to be a wildcard.
- When the constraint is other than a wildcard constraint, the pattern variable consumes
as much of the fragment as can be parsed by the grammar specified for the constraint
in
Pattern Variable Constraints
on page 157. If the parsing fails, the pattern match fails. The pattern variable binds to the fragment specified inPattern Variable Constraints.
This can be a parsed fragment rather than the original sequence of elementary fragments. - The ellipsis pattern-variable,
...
, can only be used in an auxiliary rule set. It represents a pattern variable with the same name as the current rule set and a wildcard constraint.
A property-list-pattern matches a fragment as follows:
- Parse the fragment using the grammar for property-listopt. If the parsing fails or does not consume the entire fragment, the pattern match fails.
- If the property-list-pattern
contains
#key
and does not contain#all-keys
, the match fails if the symbol part of any property is not the name in some pattern-keyword in the property-list-pattern. Comparison of a symbol to a name is case-insensitive, ignores backslash quoting, and is unaffected by the lexical context of the name. - If the property-list-pattern
contains
#rest
, bind the pattern variable immediately following#rest
to the entire fragment. If the pattern variable has a non-wildcard constraint, parse the value part of each property according to this constraint, fail if the parsing fails or does not consume the entire value part, and substitute the fragment specified inPattern Variable Constraints
on page 157 for the value part. - Each pattern-keyword in the property-list-pattern binds a pattern
variable as follows:
- A single question mark finds the first property
whose symbol is the name of
the pattern-keyword. Comparison of a symbol to
a name is case-insensitive, ignores backslash quoting, and is
unaffected by the lexical context of the name. If
the pattern-keyword has a non-wildcard constraint, parse the
property's value according to this constraint, fail if the parsing fails or
does not consume the entire value , and bind the pattern variable to the
fragment specified in
Pattern Variable Constraints
on page 157. If the pattern-keyword has a wildcard constraint, bind the pattern variable to the property's value. - A double question mark finds every property with a matching symbol, processes each property's value as for a single question mark, and binds the pattern variable to a sequence of the values, preserving the order of properties in the input fragment. This sequence can only be used with double question mark in a template. Constraint-directed parsing applies to each property value individually.
- A single question mark finds the first property
whose symbol is the name of
the pattern-keyword. Comparison of a symbol to
a name is case-insensitive, ignores backslash quoting, and is
unaffected by the lexical context of the name. If
the pattern-keyword has a non-wildcard constraint, parse the
property's value according to this constraint, fail if the parsing fails or
does not consume the entire value , and bind the pattern variable to the
fragment specified in
- If a single question mark pattern-keyword does not find any matching property, then if a default is present, the pattern variable binds to the default expression, otherwise the property is required so the pattern match fails.
- If a double question mark pattern-keyword does not find any matching property, then if a default is present, the pattern variable binds to a sequence of one element, the default expression, otherwise the pattern variable binds to an empty sequence.
- Note: the default expression in a pattern-keyword is not evaluated during macro expansion; it is a parsed expression fragment that is used instead of a fragment from the macro call. The default is not subject to a pattern variable constraint.
Special Rules for Definitions
A list-style definition parses as the core reserved word define
, an optional
sequence of modifiers, a define-list-word, and a
possibly-empty list-fragment. The left-hand side of
a list-style-definition-rule matches this by treating
the definition-head as a pattern-sequence and matching it to the
sequence of modifiers, and then matching the pattern to
the list-fragment. If no definition-head is present, the sequence of
modifiers must be empty. If no pattern is present,
the list-fragment must be empty. The word define
and
the define-list-word do not participate in the pattern match
because they were already used to identify the macro being called and because the spelling
of the define-list-word might have been changed by renaming the
macro during module importing.
A body-style definition parses as the core reserved word define
, an optional
sequence of modifiers, a define-body-word, a
possibly-empty body-fragment, the core reserved word end
, and
optional repetitions of the define-body-word and
the name (if any) that is the first token of
the body-fragment. The left-hand side of a body-style-definition-rule
matches this by treating the definition-head as a pattern-sequence and
matching it to the sequence of modifiers, and then matching the pattern to
the body-fragment. If no definition-head is present, the sequence of
modifiers must be empty. If no pattern is present,
the body-fragment must be empty. If the body-fragment ends in a
semicolon, this semicolon is removed before matching. The optional semicolon in the rule is
just decoration and does not participate in the pattern match. The word define
and the define-body-word do not participate in the pattern match
because they were already used to identify the macro being called and because the spelling
of the define-body-word might have been changed by renaming the
macro during module importing. The word end
and the two optional items
following it in the macro call are checked during parsing, and so do not participate in the
pattern match.
It is an error for a definition-head to contain more than one wildcard.
Special Rules for Statements
A statement parses as a begin-word, a
possibly-empty body-fragment, the core reserved word end
, and an
optional repetition of the begin-word. The left-hand side of
a statement-rule matches this by matching the pattern to
the body-fragment. If the rule does not contain a pattern,
the body-fragment must be empty. If the body-fragment ends in a
semicolon, this semicolon is removed before matching. The optional semicolon in the rule is
just decoration and does not participate in the pattern
match. The begin-word does not participate in the pattern match
because it was already used to identify the macro being called and because its spelling
might have been changed by renaming the macro during module importing. The
word end
and the optional item following it in the macro call are checked
during parsing, and so do not participate in the pattern match.
Special Rules for Function Macros
A call to a function macro parses as a function-word followed by a parenthesized, possibly-empty body-fragment. The left-hand side of a function-rule matches this by matching the pattern to the body-fragment. If the rule does not contain a pattern, the body-fragment must be empty. The function-word does not participate in the pattern match because it was already used to identify the macro being called and because its spelling might have been changed by renaming the macro during module importing. The parentheses in the rule are just decoration and do not participate in the pattern match.
A function macro can also be invoked by any of the shorthand syntax constructs available for invoking functions. In this case, the arguments are always parsed expression fragments, as described on page 146. However, the left-hand side of a function-rule has to use function-macro-call syntax even if the macro is intended to be called by operator, slot reference, or element reference syntax.