Skip to content

Commit ee0059a

Browse files
committed
some cleanup in the macros chapter
1 parent 0a3ac2d commit ee0059a

File tree

1 file changed

+58
-164
lines changed

1 file changed

+58
-164
lines changed

src/macro-expansion.md

Lines changed: 58 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@
33
> `librustc_ast`, `librustc_expand`, and `librustc_builtin_macros` are all undergoing
44
> refactoring, so some of the links in this chapter may be broken.
55
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
89
Rust parser will set aside the contents of macros and their invocations. Later,
910
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
1220
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].
1522

1623
### Example
1724

@@ -56,7 +63,7 @@ The process of expanding the macro invocation into the syntax tree
5663
`println!("{}", foo)` and then expanding that into a call to `Display::fmt` is
5764
called _macro expansion_, and it is the topic of this chapter.
5865

59-
### The macro parser
66+
### The MBE parser
6067

6168
There are two parts to macro expansion: parsing the definition and parsing the
6269
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):
7077

7178
```rust,ignore
7279
fn parse_tt(
73-
parser: &mut Cow<Parser>,
80+
parser: &mut Cow<Parser>,
7481
ms: &[TokenTree],
7582
) -> NamedParseResult
7683
```
7784

7885
We use these items in macro parser:
7986

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.
8692
- `ms` a _matcher_. This is a sequence of token trees that we want to match
87-
`tts` against.
93+
the token stream against.
8894

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
9197
tokens containing the inside of the example invocation `print foo`, while `ms`
9298
might be the sequence of token (trees) `print $mvar:ident`.
9399

94100
The output of the parser is a `NamedParseResult`, which indicates which of
95101
three cases has occurred:
96102

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
98104
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
100106
"No rule expected token _blah_".
101107
- Error: some fatal error has occurred _in the parser_. For example, this
102108
happens if there are more than one pattern match, since that indicates
@@ -143,7 +149,38 @@ error.
143149
For more information about the macro parser's implementation, see the comments
144150
in [`src/librustc_expand/mbe/macro_parser.rs`][code_mp].
145151

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
147184

148185
If you have ever used C/C++ preprocessor macros, you know that there are some
149186
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
190227
was called. Alternately, the macro author may be defining a variable for use
191228
only within the macro (i.e. it should not be visible outside the macro).
192229
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.
208231
209232
210233
[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
221244
it never gets lost until we can make it into a proper chapter.
222245
223246
```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!
353247
354248
Vadim Petrochenkov: Here's some preliminary data I prepared.
355249

0 commit comments

Comments
 (0)