3
3
> ` librustc_ast ` , ` librustc_expand ` , and ` librustc_builtin_macros ` are all undergoing
4
4
> refactoring, so some of the links in this chapter may be broken.
5
5
6
- Macro expansion happens during parsing. ` rustc ` has two parsers, in fact: the
7
- normal Rust parser, and the macro parser. During the parsing phase, the normal
6
+ Rust has a very powerful macro system. There are two major types of macros:
7
+ ` macro_rules! ` macros (a.k.a. "Macros By Example" (MBE)) and procedural macros
8
+ ("proc macros"; including custom derives). During the parsing phase, the normal
8
9
Rust parser will set aside the contents of macros and their invocations. Later,
9
10
before name resolution, macros are expanded using these portions of the code.
10
- The macro parser, in turn, may call the normal Rust parser when it needs to
11
- bind a metavariable (e.g. ` $my_expr ` ) while parsing the contents of a macro
11
+ In this chapter, we will discuss MBEs, proc macros, and hygiene. Both types of
12
+ macros are expanded during parsing, but they happen in different ways.
13
+
14
+ ## Macros By Example
15
+
16
+ MBEs have their own parser distinct from the normal Rust parser. When macros
17
+ are expanded, we may invoke the MBE parser to parse and expand a macro. The
18
+ MBE parser, in turn, may call the normal Rust parser when it needs to bind a
19
+ metavariable (e.g. ` $my_expr ` ) while parsing the contents of a macro
12
20
invocation. The code for macro expansion is in
13
- [ ` src/librustc_expand/mbe/ ` ] [ code_dir ] . This chapter aims to explain how macro
14
- expansion works.
21
+ [ ` src/librustc_expand/mbe/ ` ] [ code_dir ] .
15
22
16
23
### Example
17
24
@@ -56,7 +63,7 @@ The process of expanding the macro invocation into the syntax tree
56
63
` println!("{}", foo) ` and then expanding that into a call to ` Display::fmt ` is
57
64
called _ macro expansion_ , and it is the topic of this chapter.
58
65
59
- ### The macro parser
66
+ ### The MBE parser
60
67
61
68
There are two parts to macro expansion: parsing the definition and parsing the
62
69
invocations. Interestingly, both are done by the macro parser.
@@ -70,33 +77,32 @@ The interface of the macro parser is as follows (this is slightly simplified):
70
77
71
78
``` rust,ignore
72
79
fn parse_tt(
73
- parser: &mut Cow<Parser>,
80
+ parser: &mut Cow<Parser>,
74
81
ms: &[TokenTree],
75
82
) -> NamedParseResult
76
83
```
77
84
78
85
We use these items in macro parser:
79
86
80
- - ` sess ` is a "parsing session", which keeps track of some metadata. Most
81
- notably, this is used to keep track of errors that are generated so they can
82
- be reported to the user.
83
- - ` tts ` is a stream of tokens. The macro parser's job is to consume the raw
84
- stream of tokens and output a binding of metavariables to corresponding token
85
- trees.
87
+ - ` parser ` is a reference to the state of a normal Rust parser, including the
88
+ token stream and parsing session. The token stream is what we are about to
89
+ ask the MBE parser to parse. We will consume the raw stream of tokens and
90
+ output a binding of metavariables to corresponding token trees. The parsing
91
+ session can be used to report parser errros.
86
92
- ` ms ` a _ matcher_ . This is a sequence of token trees that we want to match
87
- ` tts ` against.
93
+ the token stream against.
88
94
89
- In the analogy of a regex parser, ` tts ` is the input and we are matching it
90
- against the pattern ` ms ` . Using our examples, ` tts ` could be the stream of
95
+ In the analogy of a regex parser, the token stream is the input and we are matching it
96
+ against the pattern ` ms ` . Using our examples, the token stream could be the stream of
91
97
tokens containing the inside of the example invocation ` print foo ` , while ` ms `
92
98
might be the sequence of token (trees) ` print $mvar:ident ` .
93
99
94
100
The output of the parser is a ` NamedParseResult ` , which indicates which of
95
101
three cases has occurred:
96
102
97
- - Success: ` tts ` matches the given matcher ` ms ` , and we have produced a binding
103
+ - Success: the token stream matches the given matcher ` ms ` , and we have produced a binding
98
104
from metavariables to the corresponding token trees.
99
- - Failure: ` tts ` does not match ` ms ` . This results in an error message such as
105
+ - Failure: the token stream does not match ` ms ` . This results in an error message such as
100
106
"No rule expected token _ blah_ ".
101
107
- Error: some fatal error has occurred _ in the parser_ . For example, this
102
108
happens if there are more than one pattern match, since that indicates
@@ -143,7 +149,38 @@ error.
143
149
For more information about the macro parser's implementation, see the comments
144
150
in [ ` src/librustc_expand/mbe/macro_parser.rs ` ] [ code_mp ] .
145
151
146
- ### Hygiene
152
+ ### ` macro ` s and Macros 2.0
153
+
154
+ There is an old and mostly undocumented effort to improve the MBE system, give
155
+ it more hygiene-related features, better scoping and visibility rules, etc. There
156
+ hasn't been a lot of work on this recently, unfortunately. Internally, ` macro `
157
+ macros use the same machinery as today's MBEs; they just have additional
158
+ syntactic sugar and are allowed to be in namespaces.
159
+
160
+ ## Procedural Macros
161
+
162
+ Precedural macros are also expanded during parsing, as mentioned above.
163
+ However, they use a rather different mechanism. Rather than having a parser in
164
+ the compiler, procedural macros are implemented as custom, third-party crates.
165
+ The compiler will compile the proc macro crate and specially annotated
166
+ functions in them (i.e. the proc macro itself), passing them a stream of tokens.
167
+
168
+ The proc macro can then transform the token stream and output a new token
169
+ stream, which is synthesized into the AST.
170
+
171
+ It's worth noting that the token stream type used by proc macros is _ stable_ ,
172
+ so ` rustc ` does not use it internally (since our internal data structures are
173
+ unstable).
174
+
175
+ TODO: more here.
176
+
177
+ ### Custom Derive
178
+
179
+ Custom derives are a special type of proc macro.
180
+
181
+ TODO: more?
182
+
183
+ ## Hygiene
147
184
148
185
If you have ever used C/C++ preprocessor macros, you know that there are some
149
186
annoying and hard-to-debug gotchas! For example, consider the following C code:
@@ -190,21 +227,7 @@ a macro author may want to introduce a new name to the context where the macro
190
227
was called. Alternately, the macro author may be defining a variable for use
191
228
only within the macro (i.e. it should not be visible outside the macro).
192
229
193
- In rustc, this "context" is tracked via `Span`s.
194
-
195
- TODO: what is call-site hygiene? what is def-site hygiene?
196
-
197
- TODO
198
-
199
- ### Procedural Macros
200
-
201
- TODO
202
-
203
- ### Custom Derive
204
-
205
- TODO
206
-
207
- TODO: maybe something about macros 2.0?
230
+ This section is about how that context is tracked.
208
231
209
232
210
233
[code_dir]: https://github.com/rust-lang/rust/tree/master/src/librustc_expand/mbe
@@ -221,135 +244,6 @@ The rest of this chapter is a dump of a discussion between `mark-i-m` and
221
244
it never gets lost until we can make it into a proper chapter.
222
245
223
246
```txt
224
- mark-i-m: @Vadim Petrochenkov Hi :wave:
225
- I was wondering if you would have a chance sometime in the next month or so to
226
- just have a zulip discussion where you tell us (WG-learning) everything you
227
- know about macros/expansion/hygiene. We were thinking this could be less formal
228
- (and less work for you) than compiler lecture series lecture... thoughts?
229
-
230
- mark-i-m: The goal is to fill out that long-standing gap in the rustc-dev-guide
231
-
232
- Vadim Petrochenkov: Ok, I'm at UTC+03:00 and generally available in the
233
- evenings (or weekends).
234
-
235
- mark-i-m: @Vadim Petrochenkov Either of those works for me (your evenings are
236
- about lunch time for me :) ) Is there a particular date that would work best
237
- for you?
238
-
239
- mark-i-m: @WG-learning Does anyone else have a preferred date?
240
-
241
- Vadim Petrochenkov:
242
-
243
- Is there a particular date that would work best for you?
244
-
245
- Nah, not much difference. (If something changes for a specific day, I'll
246
- notify.)
247
-
248
- Santiago Pastorino: week days are better, but I'd say let's wait for @Vadim
249
- Petrochenkov to say when they are ready for it and we can set a date
250
-
251
- Santiago Pastorino: also, we should record this so ... I guess it doesn't
252
- matter that much when :)
253
-
254
- mark-i-m:
255
-
256
- also, we should record this so ... I guess it doesn't matter that much when
257
- :)
258
-
259
- @Santiago Pastorino My thinking was to just use zulip, so we would have the log
260
-
261
- mark-i-m: @Vadim Petrochenkov @WG-learning How about 2 weeks from now: July 24
262
- at 5pm UTC time (if I did the math right, that should be evening for Vadim)
263
-
264
- Amanjeev Sethi: i can try and do this but I am starting a new job that week so
265
- cannot promise.
266
-
267
- Santiago Pastorino:
268
-
269
- Vadim Petrochenkov @WG-learning How about 2 weeks from now: July 24 at 5pm
270
- UTC time (if I did the math right, that should be evening for Vadim)
271
-
272
- works perfect for me
273
-
274
- Santiago Pastorino: @mark-i-m I have access to the compiler calendar so I can
275
- add something there
276
-
277
- Santiago Pastorino: let me know if you want to add an event to the calendar, I
278
- can do that
279
-
280
- Santiago Pastorino: how long it would be?
281
-
282
- mark-i-m:
283
-
284
- let me know if you want to add an event to the calendar, I can do that
285
-
286
- mark-i-m: That could be good :+1:
287
-
288
- mark-i-m:
289
-
290
- how long it would be?
291
-
292
- Let's start with 30 minutes, and if we need to schedule another we cna
293
-
294
- Vadim Petrochenkov:
295
-
296
- 5pm UTC
297
-
298
- 1-2 hours later would be better, 5pm UTC is not evening enough.
299
-
300
- Vadim Petrochenkov: How exactly do you plan the meeting to go (aka how much do
301
- I need to prepare)?
302
-
303
- Santiago Pastorino:
304
-
305
- 5pm UTC
306
-
307
- 1-2 hours later would be better, 5pm UTC is not evening enough.
308
-
309
- Scheduled for 7pm UTC then
310
-
311
- Santiago Pastorino:
312
-
313
- How exactly do you plan the meeting to go (aka how much do I need to
314
- prepare)?
315
-
316
- /cc @mark-i-m
317
-
318
- mark-i-m: @Vadim Petrochenkov
319
-
320
- How exactly do you plan the meeting to go (aka how much do I need to
321
- prepare)?
322
-
323
- My hope was that this could be less formal than for a compiler lecture series,
324
- but it would be nice if you could have in your mind a tour of the design and
325
- the code
326
-
327
- That is, imagine that a new person was joining the compiler team and needed to
328
- get up to speed about macros/expansion/hygiene. What would you tell such a
329
- person?
330
-
331
- mark-i-m: @Vadim Petrochenkov Are we still on for tomorrow at 7pm UTC?
332
-
333
- Vadim Petrochenkov: Yes.
334
-
335
- Santiago Pastorino: @Vadim Petrochenkov @mark-i-m I've added an event on rust
336
- compiler team calendar
337
-
338
- mark-i-m: @WG-learning @Vadim Petrochenkov Hello!
339
-
340
- mark-i-m: We will be starting in ~7 minutes
341
-
342
- mark-i-m: :wave:
343
-
344
- Vadim Petrochenkov: I'm here.
345
-
346
- mark-i-m: Cool :)
347
-
348
- Santiago Pastorino: hello @Vadim Petrochenkov
349
-
350
- mark-i-m: Shall we start?
351
-
352
- mark-i-m: First off, @Vadim Petrochenkov Thanks for doing this!
353
247
354
248
Vadim Petrochenkov: Here's some preliminary data I prepared.
355
249
0 commit comments