Skip to content

Commit d0c2d6c

Browse files
paulstansifercatamorphism
authored andcommitted
Update macro tutorial to recognize item/statement macros and be clearer
about invocation location vs. interpolation location.
1 parent 14a7be3 commit d0c2d6c

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

doc/tutorial-macros.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,44 @@ To take as an argument a fragment of Rust code, write `$` followed by a name
8484
* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
8585
a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
8686
* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
87-
87+
8888
The parser interprets any token that's not preceded by a `$` literally. Rust's usual
8989
rules of tokenization apply,
9090

9191
So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
9292
that could be invoked like: `my_macro!(i->(( 2+2 )))`.
9393

94+
## Invocation location
95+
96+
A macro invocation may take the place of (and therefore expand to) either an
97+
expression, an item, or a statement. The Rust parser will parse the macro
98+
invocation as a "placeholder" for whichever of those three nonterminals is
99+
appropriate for the location.
100+
101+
At expansion time, the output of the macro will be parsed as whichever of the
102+
three nonterminals it stands in for. This means that a single macro might,
103+
for example, expand to an item or an expression, depending on its arguments
104+
(and cause a syntax error if it is called with the wrong argument for its
105+
location). Although this behavior sounds excessively dynamic, it is known to
106+
be useful under some circumstances.
107+
108+
94109
# Transcription syntax
95110

96111
The right-hand side of the `=>` follows the same rules as the left-hand side,
97112
except that a `$` need only be followed by the name of the syntactic fragment
98113
to transcribe into the macro expansion; its type need not be repeated.
99114

100-
The right-hand side must be enclosed by delimiters, and must be
101-
an expression. Currently, invocations of user-defined macros can only appear in a context
102-
where the Rust grammar requires an expression, even though `macro_rules!` itself can appear
103-
in a context where the grammar requires an item.
115+
The right-hand side must be enclosed by delimiters, which are ignored by the
116+
transcriber (therefore `() => ((1,2,3))` is a macro that expands to a tuple
117+
expression, `() => (let $x=$val)` is a macro that expands to a statement, and
118+
`() => (1,2,3)` is a macro that expands to a syntax errror).
119+
120+
## Interpolation location
121+
122+
The interpolation `$argument_name` may appear in any location consistent with
123+
its fragment specifier (i.e., if it is specified as `ident`, it may be used
124+
anywhere an identifier is permitted).
104125

105126
# Multiplicity
106127

@@ -163,7 +184,7 @@ fragments by the macro parser:
163184
fragment. For example, if the comma were omitted from the syntax of
164185
`early_return!` above, `input_1 [` would've been interpreted as the beginning
165186
of an array index. In fact, invoking the macro would have been impossible.
166-
2. The parser must have eliminated all ambiguity by the time it reaches a
187+
2. The parser must have eliminated all ambiguity by the time it reaches a
167188
`$name:fragment_specifier` declaration. This limitation can result in parse
168189
errors when declarations occur at the beginning of, or immediately after,
169190
a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to

0 commit comments

Comments
 (0)