@@ -13,7 +13,6 @@ use syntax_pos::DUMMY_SP;
1313use rustc_data_structures:: fx:: FxHashMap ;
1414use rustc_data_structures:: sync:: Lrc ;
1515use std:: mem;
16- use std:: ops:: Add ;
1716use std:: rc:: Rc ;
1817
1918/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
@@ -23,6 +22,7 @@ enum Frame {
2322}
2423
2524impl Frame {
25+ /// Construct a new frame around the delimited set of tokens.
2626 fn new ( tts : Vec < quoted:: TokenTree > ) -> Frame {
2727 let forest = Lrc :: new ( quoted:: Delimited { delim : token:: NoDelim , tts : tts } ) ;
2828 Frame :: Delimited { forest : forest, idx : 0 , span : DelimSpan :: dummy ( ) }
@@ -46,30 +46,72 @@ impl Iterator for Frame {
4646 }
4747}
4848
49- /// This can do Macro-By-Example transcription. On the other hand, if `src` contains no
50- /// `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can (and should) be `None`.
49+ /// This can do Macro-By-Example transcription.
50+ /// - `interp` is a map of meta-variables to the tokens (non-terminals) they matched in the
51+ /// invocation. We are assuming we already know there is a match.
52+ /// - `src` is the RHS of the MBE, that is, the "example" we are filling in.
53+ ///
54+ /// For example,
55+ ///
56+ /// ```rust
57+ /// macro_rules! foo {
58+ /// ($id:ident) => { println!("{}", stringify!($id)); }
59+ /// }
60+ ///
61+ /// foo!(bar);
62+ /// ```
63+ ///
64+ /// `interp` would contain `$id => bar` and `src` would contain `println!("{}", stringify!($id));`.
65+ ///
66+ /// `transcribe` would return a `TokenStream` containing `println!("{}", stringify!(bar));`.
67+ ///
68+ /// Along the way, we do some additional error checking.
5169pub fn transcribe (
5270 cx : & ExtCtxt < ' _ > ,
53- interp : Option < FxHashMap < Ident , Rc < NamedMatch > > > ,
71+ interp : & FxHashMap < Ident , Rc < NamedMatch > > ,
5472 src : Vec < quoted:: TokenTree > ,
5573) -> TokenStream {
74+ assert ! ( src. len( ) > 0 ) ;
75+
76+ // We descend into the RHS (`src`), expanding things as we go. This stack contains the things
77+ // we have yet to expand/are still expanding. We start the stack off with the whole RHS.
5678 let mut stack: SmallVec < [ Frame ; 1 ] > = smallvec ! [ Frame :: new( src) ] ;
57- let interpolations = interp. unwrap_or_else ( FxHashMap :: default) ; /* just a convenience */
79+
80+ // As we descend in the RHS, we will need to be able to match nested sequences of matchers.
81+ // `repeats` keeps track of where we are in matching at each level, with the last element being
82+ // the most deeply nested sequence. This is used as a stack.
5883 let mut repeats = Vec :: new ( ) ;
84+
85+ // `result` contains resulting token stream from the TokenTree we just finished processing. At
86+ // the end, this will contain the full result of transcription, but at arbitrary points during
87+ // `transcribe`, `result` will contain subsets of the final result.
88+ //
89+ // Specifically, as we descend into each TokenTree, we will push the existing results onto the
90+ // `result_stack` and clear `results`. We will then produce the results of transcribing the
91+ // TokenTree into `results`. Then, as we unwind back out of the `TokenTree`, we will pop the
92+ // `result_stack` and append `results` too it to produce the new `results` up to that point.
93+ //
94+ // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level
95+ // again, and we are done transcribing.
5996 let mut result: Vec < TreeAndJoint > = Vec :: new ( ) ;
6097 let mut result_stack = Vec :: new ( ) ;
6198
6299 loop {
100+ // Look at the last frame on the stack.
63101 let tree = if let Some ( tree) = stack. last_mut ( ) . unwrap ( ) . next ( ) {
102+ // If it still has a TokenTree we have not looked at yet, use that tree.
64103 tree
65- } else {
104+ }
105+ // The else-case never produces a value for `tree` (it `continue`s or `return`s).
106+ else {
107+ // Otherwise, if we have just reached the end of a sequence and we can keep repeating,
108+ // go back to the beginning of the sequence.
66109 if let Frame :: Sequence { ref mut idx, ref sep, .. } = * stack. last_mut ( ) . unwrap ( ) {
67110 let ( ref mut repeat_idx, repeat_len) = * repeats. last_mut ( ) . unwrap ( ) ;
68111 * repeat_idx += 1 ;
69112 if * repeat_idx < repeat_len {
70113 * idx = 0 ;
71114 if let Some ( sep) = sep. clone ( ) {
72- // repeat same span, I guess
73115 let prev_span = match result. last ( ) {
74116 Some ( ( tt, _) ) => tt. span ( ) ,
75117 None => DUMMY_SP ,
@@ -80,14 +122,25 @@ pub fn transcribe(
80122 }
81123 }
82124
125+ // We are done with the top of the stack. Pop it. Depending on what it was, we do
126+ // different things. Note that the outermost item must be the delimited, wrapped RHS
127+ // that was passed in originally to `transcribe`.
83128 match stack. pop ( ) . unwrap ( ) {
129+ // Done with a sequence. Pop from repeats.
84130 Frame :: Sequence { .. } => {
85131 repeats. pop ( ) ;
86132 }
133+
134+ // We are done processing a Delimited. If this is the top-level delimited, we are
135+ // done. Otherwise, we unwind the result_stack to append what we have produced to
136+ // any previous results.
87137 Frame :: Delimited { forest, span, .. } => {
88138 if result_stack. is_empty ( ) {
139+ // No results left to compute! We are back at the top-level.
89140 return TokenStream :: new ( result) ;
90141 }
142+
143+ // Step back into the parent Delimited.
91144 let tree =
92145 TokenTree :: Delimited ( span, forest. delim , TokenStream :: new ( result) . into ( ) ) ;
93146 result = result_stack. pop ( ) . unwrap ( ) ;
@@ -97,35 +150,54 @@ pub fn transcribe(
97150 continue ;
98151 } ;
99152
153+ // At this point, we know we are in the middle of a TokenTree (the last one on `stack`).
154+ // `tree` contains the next `TokenTree` to be processed.
100155 match tree {
156+ // We are descending into a sequence. We first make sure that the matchers in the RHS
157+ // and the matches in `interp` have the same shape. Otherwise, either the caller or the
158+ // macro writer has made a mistake.
101159 seq @ quoted:: TokenTree :: Sequence ( ..) => {
102160 match lockstep_iter_size ( & seq, interp, & repeats) {
103161 LockstepIterSize :: Unconstrained => {
104162 cx. span_fatal (
105163 seq. span ( ) , /* blame macro writer */
106- "attempted to repeat an expression \
107- containing no syntax \
108- variables matched as repeating at this depth",
164+ "attempted to repeat an expression containing no syntax variables \
165+ matched as repeating at this depth",
109166 ) ;
110167 }
168+
111169 LockstepIterSize :: Contradiction ( ref msg) => {
170+ // FIXME: this should be impossible. I (mark-i-m) believe it would
171+ // represent a bug in the macro_parser.
112172 // FIXME #2887 blame macro invoker instead
113173 cx. span_fatal ( seq. span ( ) , & msg[ ..] ) ;
114174 }
175+
115176 LockstepIterSize :: Constraint ( len, _) => {
177+ // We do this to avoid an extra clone above. We know that this is a
178+ // sequence already.
116179 let ( sp, seq) = if let quoted:: TokenTree :: Sequence ( sp, seq) = seq {
117180 ( sp, seq)
118181 } else {
119182 unreachable ! ( )
120183 } ;
121184
185+ // Is the repetition empty?
122186 if len == 0 {
123187 if seq. op == quoted:: KleeneOp :: OneOrMore {
188+ // FIXME: this should be impossible because we check for this in
189+ // macro_parser.rs
124190 // FIXME #2887 blame invoker
125191 cx. span_fatal ( sp. entire ( ) , "this must repeat at least once" ) ;
126192 }
127193 } else {
194+ // 0 is the initial counter (we have done 0 repretitions so far). `len`
195+ // is the total number of reptitions we should generate.
128196 repeats. push ( ( 0 , len) ) ;
197+
198+ // The first time we encounter the sequence we push it to the stack. It
199+ // then gets reused (see the beginning of the loop) until we are done
200+ // repeating.
129201 stack. push ( Frame :: Sequence {
130202 idx : 0 ,
131203 sep : seq. separator . clone ( ) ,
@@ -135,10 +207,16 @@ pub fn transcribe(
135207 }
136208 }
137209 }
138- // FIXME #2887: think about span stuff here
210+
211+ // Replace the meta-var with the matched token tree from the invocation.
139212 quoted:: TokenTree :: MetaVar ( mut sp, ident) => {
140- if let Some ( cur_matched) = lookup_cur_matched ( ident, & interpolations, & repeats) {
213+ // Find the matched nonterminal from the macro invocation, and use it to replace
214+ // the meta-var.
215+ if let Some ( cur_matched) = lookup_cur_matched ( ident, interp, & repeats) {
141216 if let MatchedNonterminal ( ref nt) = * cur_matched {
217+ // FIXME #2887: why do we apply a mark when matching a token tree meta-var
218+ // (e.g. `$x:tt`), but not when we are matching any other type of token
219+ // tree?
142220 if let NtTT ( ref tt) = * * nt {
143221 result. push ( tt. clone ( ) . into ( ) ) ;
144222 } else {
@@ -147,35 +225,55 @@ pub fn transcribe(
147225 result. push ( token. into ( ) ) ;
148226 }
149227 } else {
228+ // We were unable to descend far enough. This is an error.
150229 cx. span_fatal (
151230 sp, /* blame the macro writer */
152231 & format ! ( "variable '{}' is still repeating at this depth" , ident) ,
153232 ) ;
154233 }
155234 } else {
235+ // If we aren't able to match the meta-var, we push it back into the result but
236+ // with modified syntax context. (I believe this supports nested macros).
156237 let ident =
157238 Ident :: new ( ident. name , ident. span . apply_mark ( cx. current_expansion . mark ) ) ;
158239 sp = sp. apply_mark ( cx. current_expansion . mark ) ;
159240 result. push ( TokenTree :: Token ( sp, token:: Dollar ) . into ( ) ) ;
160241 result. push ( TokenTree :: Token ( sp, token:: Token :: from_ast_ident ( ident) ) . into ( ) ) ;
161242 }
162243 }
244+
245+ // If we are entering a new delimiter, we push its contents to the `stack` to be
246+ // processed, and we push all of the currently produced results to the `result_stack`.
247+ // We will produce all of the results of the inside of the `Delimited` and then we will
248+ // jump back out of the Delimited, pop the result_stack and add the new results back to
249+ // the previous results (from outside the Delimited).
163250 quoted:: TokenTree :: Delimited ( mut span, delimited) => {
164251 span = span. apply_mark ( cx. current_expansion . mark ) ;
165252 stack. push ( Frame :: Delimited { forest : delimited, idx : 0 , span : span } ) ;
166253 result_stack. push ( mem:: replace ( & mut result, Vec :: new ( ) ) ) ;
167254 }
255+
256+ // Nothing much to do here. Just push the token to the result, being careful to
257+ // preserve syntax context.
168258 quoted:: TokenTree :: Token ( sp, tok) => {
169259 let mut marker = Marker ( cx. current_expansion . mark ) ;
170260 let mut tt = TokenTree :: Token ( sp, tok) ;
171261 noop_visit_tt ( & mut tt, & mut marker) ;
172262 result. push ( tt. into ( ) ) ;
173263 }
264+
265+ // There should be no meta-var declarations in the invocation of a macro.
174266 quoted:: TokenTree :: MetaVarDecl ( ..) => panic ! ( "unexpected `TokenTree::MetaVarDecl" ) ,
175267 }
176268 }
177269}
178270
271+ /// Lookup the meta-var named `ident` and return the matched token tree from the invocation using
272+ /// the set of matches `interpolations`.
273+ ///
274+ /// See the definition of `repeats` in the `transcribe` function. `repeats` is used to descend
275+ /// into the right place in nested matchers. If we attempt to descend too far, the macro writer has
276+ /// made a mistake, and we return `None`.
179277fn lookup_cur_matched (
180278 ident : Ident ,
181279 interpolations : & FxHashMap < Ident , Rc < NamedMatch > > ,
@@ -195,14 +293,29 @@ fn lookup_cur_matched(
195293 } )
196294}
197295
296+ /// An accumulator over a TokenTree to be used with `fold`. During transcription, we need to make
297+ /// sure that the size of each sequence and all of its nested sequences are the same as the sizes
298+ /// of all the matched (nested) sequences in the macro invocation. If they don't match, somebody
299+ /// has made a mistake (either the macro writer or caller).
198300#[ derive( Clone ) ]
199301enum LockstepIterSize {
302+ /// No constraints on length of matcher. This is true for any TokenTree variants except a
303+ /// `MetaVar` with an actual `MatchedSeq` (as opposed to a `MatchedNonterminal`).
200304 Unconstrained ,
305+
306+ /// A `MetaVar` with an actual `MatchedSeq`. The length of the match and the name of the
307+ /// meta-var are returned.
201308 Constraint ( usize , Ident ) ,
309+
310+ /// Two `Constraint`s on the same sequence had different lengths. This is an error.
202311 Contradiction ( String ) ,
203312}
204313
205314impl LockstepIterSize {
315+ /// Find incompatibilities in matcher/invocation sizes.
316+ /// - `Unconstrained` is compatible with everything.
317+ /// - `Contradiction` is incompatible with everything.
318+ /// - `Constraint(len)` is only compatible with other constraints of the same length.
206319 fn with ( self , other : LockstepIterSize ) -> LockstepIterSize {
207320 match self {
208321 LockstepIterSize :: Unconstrained => other,
@@ -224,6 +337,12 @@ impl LockstepIterSize {
224337 }
225338}
226339
340+ /// Given a `tree`, make sure that all sequences have the same length as the matches for the
341+ /// appropriate meta-vars in `interpolations`.
342+ ///
343+ /// Note that if `repeats` does not match the exact correct depth of a meta-var,
344+ /// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of
345+ /// multiple nested matcher sequences.
227346fn lockstep_iter_size (
228347 tree : & quoted:: TokenTree ,
229348 interpolations : & FxHashMap < Ident , Rc < NamedMatch > > ,
@@ -233,12 +352,12 @@ fn lockstep_iter_size(
233352 match * tree {
234353 TokenTree :: Delimited ( _, ref delimed) => {
235354 delimed. tts . iter ( ) . fold ( LockstepIterSize :: Unconstrained , |size, tt| {
236- size + lockstep_iter_size ( tt, interpolations, repeats)
355+ size. with ( lockstep_iter_size ( tt, interpolations, repeats) )
237356 } )
238357 }
239358 TokenTree :: Sequence ( _, ref seq) => {
240359 seq. tts . iter ( ) . fold ( LockstepIterSize :: Unconstrained , |size, tt| {
241- size + lockstep_iter_size ( tt, interpolations, repeats)
360+ size. with ( lockstep_iter_size ( tt, interpolations, repeats) )
242361 } )
243362 }
244363 TokenTree :: MetaVar ( _, name) | TokenTree :: MetaVarDecl ( _, name, _) => {
0 commit comments