Skip to content

Commit 6cef0e5

Browse files
author
Keegan McAllister
committed
Rewrite the macros chapter
This is a more introductory document, suitable for Part II. The arcane details move to an "Advanced macros" chapter in Part III.
1 parent 342ab53 commit 6cef0e5

File tree

3 files changed

+512
-524
lines changed

3 files changed

+512
-524
lines changed

src/doc/trpl/SUMMARY.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@
2828
* [Generics](generics.md)
2929
* [Traits](traits.md)
3030
* [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md)
31+
* [Macros](macros.md)
3132
* [Concurrency](concurrency.md)
3233
* [Error Handling](error-handling.md)
3334
* [Documentation](documentation.md)
3435
* [III: Advanced Topics](advanced.md)
3536
* [FFI](ffi.md)
3637
* [Unsafe Code](unsafe.md)
37-
* [Macros](macros.md)
38+
* [Advanced Macros](advanced-macros.md)
3839
* [Compiler Plugins](plugins.md)
3940
* [Conclusion](conclusion.md)

src/doc/trpl/advanced-macros.md

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
% Advanced macros
2+
3+
This chapter picks up where the [introductory macro chapter](macros.html) left
4+
off.
5+
6+
# Syntactic requirements
7+
8+
Even when Rust code contains un-expanded macros, it can be parsed as a full
9+
syntax tree. This property can be very useful for editors and other tools that
10+
process code. It also has a few consequences for the design of Rust's macro
11+
system.
12+
13+
One consequence is that Rust must determine, when it parses a macro invocation,
14+
whether the macro stands in for
15+
16+
* zero or more items,
17+
* zero or more methods,
18+
* an expression,
19+
* a statement, or
20+
* a pattern.
21+
22+
A macro invocation within a block could stand for some items, or for an
23+
expression / statement. Rust uses a simple rule to resolve this ambiguity. A
24+
macro invocation that stands for items must be either
25+
26+
* delimited by curly braces, e.g. `foo! { ... }`, or
27+
* terminated by a semicolon, e.g. `foo!(...);`
28+
29+
Another consequence of pre-expansion parsing is that the macro invocation must
30+
consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
31+
must be balanced within a macro invocation. For example, `foo!([)` is
32+
forbidden. This allows Rust to know where the macro invocation ends.
33+
34+
More formally, the macro invocation body must be a sequence of *token trees*.
35+
A token tree is defined recursively as either
36+
37+
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
38+
* any other single token.
39+
40+
Within a matcher, each metavariable has a *fragment specifier*, identifying
41+
which syntactic form it matches.
42+
43+
* `ident`: an identifier. Examples: `x`; `foo`.
44+
* `path`: a qualified name. Example: `T::SpecialA`.
45+
* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`.
46+
* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`.
47+
* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`.
48+
* `stmt`: a single statement. Example: `let x = 3`.
49+
* `block`: a brace-delimited sequence of statements. Example:
50+
`{ log(error, "hi"); return 12; }`.
51+
* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
52+
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
53+
* `tt`: a single token tree.
54+
55+
There are additional rules regarding the next token after a metavariable:
56+
57+
* `expr` variables must be followed by one of: `=> , ;`
58+
* `ty` and `path` variables must be followed by one of: `=> , : = > as`
59+
* `pat` variables must be followed by one of: `=> , =`
60+
* Other variables may be followed by any token.
61+
62+
These rules provide some flexibility for Rust's syntax to evolve without
63+
breaking existing macros.
64+
65+
The macro system does not deal with parse ambiguity at all. For example, the
66+
grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would
67+
be forced to choose between parsing `$t` and parsing `$e`. Changing the
68+
invocation syntax to put a distinctive token in front can solve the problem. In
69+
this case, you can write `$(T $t:ty)* E $e:exp`.
70+
71+
[item]: ../reference.html#items
72+
73+
# Scoping and macro import/export
74+
75+
Macros are expanded at an early stage in compilation, before name resolution.
76+
One downside is that scoping works differently for macros, compared to other
77+
constructs in the language.
78+
79+
Definition and expansion of macros both happen in a single depth-first,
80+
lexical-order traversal of a crate's source. So a macro defined at module scope
81+
is visible to any subsequent code in the same module, which includes the body
82+
of any subsequent child `mod` items.
83+
84+
A macro defined within the body of a single `fn`, or anywhere else not at
85+
module scope, is visible only within that item.
86+
87+
If a module has the `macro_use` attribute, its macros are also visible in its
88+
parent module after the child's `mod` item. If the parent also has `macro_use`
89+
then the macros will be visible in the grandparent after the parent's `mod`
90+
item, and so forth.
91+
92+
The `macro_use` attribute can also appear on `extern crate`. In this context
93+
it controls which macros are loaded from the external crate, e.g.
94+
95+
```rust,ignore
96+
#[macro_use(foo, bar)]
97+
extern crate baz;
98+
```
99+
100+
If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
101+
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
102+
defined with the `#[macro_export]` attribute may be loaded.
103+
104+
To load a crate's macros *without* linking it into the output, use `#[no_link]`
105+
as well.
106+
107+
An example:
108+
109+
```rust
110+
macro_rules! m1 { () => (()) }
111+
112+
// visible here: m1
113+
114+
mod foo {
115+
// visible here: m1
116+
117+
#[macro_export]
118+
macro_rules! m2 { () => (()) }
119+
120+
// visible here: m1, m2
121+
}
122+
123+
// visible here: m1
124+
125+
macro_rules! m3 { () => (()) }
126+
127+
// visible here: m1, m3
128+
129+
#[macro_use]
130+
mod bar {
131+
// visible here: m1, m3
132+
133+
macro_rules! m4 { () => (()) }
134+
135+
// visible here: m1, m3, m4
136+
}
137+
138+
// visible here: m1, m3, m4
139+
# fn main() { }
140+
```
141+
142+
When this library is loaded with `#[macro_use] extern crate`, only `m2` will
143+
be imported.
144+
145+
The Rust Reference has a [listing of macro-related
146+
attributes](../reference.html#macro--and-plugin-related-attributes).
147+
148+
# The variable `$crate`
149+
150+
A further difficulty occurs when a macro is used in multiple crates. Say that
151+
`mylib` defines
152+
153+
```rust
154+
pub fn increment(x: u32) -> u32 {
155+
x + 1
156+
}
157+
158+
#[macro_export]
159+
macro_rules! inc_a {
160+
($x:expr) => ( ::increment($x) )
161+
}
162+
163+
#[macro_export]
164+
macro_rules! inc_b {
165+
($x:expr) => ( ::mylib::increment($x) )
166+
}
167+
# fn main() { }
168+
```
169+
170+
`inc_a` only works within `mylib`, while `inc_b` only works outside the
171+
library. Furthermore, `inc_b` will break if the user imports `mylib` under
172+
another name.
173+
174+
Rust does not (yet) have a hygiene system for crate references, but it does
175+
provide a simple workaround for this problem. Within a macro imported from a
176+
crate named `foo`, the special macro variable `$crate` will expand to `::foo`.
177+
By contrast, when a macro is defined and then used in the same crate, `$crate`
178+
will expand to nothing. This means we can write
179+
180+
```rust
181+
#[macro_export]
182+
macro_rules! inc {
183+
($x:expr) => ( $crate::increment($x) )
184+
}
185+
# fn main() { }
186+
```
187+
188+
to define a single macro that works both inside and outside our library. The
189+
function name will expand to either `::increment` or `::mylib::increment`.
190+
191+
To keep this system simple and correct, `#[macro_use] extern crate ...` may
192+
only appear at the root of your crate, not inside `mod`. This ensures that
193+
`$crate` is a single identifier.
194+
195+
# A final note
196+
197+
Macros, as currently implemented, are not for the faint of heart. Even
198+
ordinary syntax errors can be more difficult to debug when they occur inside a
199+
macro, and errors caused by parse problems in generated code can be very
200+
tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
201+
states, invoking `trace_macros!(true)` will automatically print those
202+
intermediate states out, and passing the flag `--pretty expanded` as a
203+
command-line argument to the compiler will show the result of expansion.
204+
205+
If Rust's macro system can't do what you need, you may want to write a
206+
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
207+
macros, this is significantly more work, the interfaces are much less stable,
208+
and the warnings about debugging apply ten-fold. In exchange you get the
209+
flexibility of running arbitrary Rust code within the compiler. Syntax
210+
extension plugins are sometimes called *procedural macros* for this reason.

0 commit comments

Comments
 (0)