7
7
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
- use self :: LockstepIterSize :: * ;
11
10
12
11
use ast:: Ident ;
13
12
use errors:: Handler ;
@@ -41,6 +40,13 @@ enum Frame {
41
40
} ,
42
41
}
43
42
43
+ impl Frame {
44
+ fn new ( tts : Vec < TokenTree > ) -> Frame {
45
+ let forest = Rc :: new ( tokenstream:: Delimited { delim : token:: NoDelim , tts : tts } ) ;
46
+ Frame :: Delimited { forest : forest, idx : 0 , span : DUMMY_SP }
47
+ }
48
+ }
49
+
44
50
impl Iterator for Frame {
45
51
type Item = TokenTree ;
46
52
@@ -75,143 +81,42 @@ impl Iterator for Frame {
75
81
}
76
82
}
77
83
78
- struct TtReader < ' a > {
79
- sp_diag : & ' a Handler ,
80
- /// the unzipped tree:
81
- stack : SmallVector < Frame > ,
82
- /* for MBE-style macro transcription */
83
- interpolations : HashMap < Ident , Rc < NamedMatch > > ,
84
-
85
- repeat_idx : Vec < usize > ,
86
- repeat_len : Vec < usize > ,
87
- }
88
-
89
84
/// This can do Macro-By-Example transcription. On the other hand, if
90
85
/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
91
86
/// (and should) be None.
92
87
pub fn transcribe ( sp_diag : & Handler ,
93
88
interp : Option < HashMap < Ident , Rc < NamedMatch > > > ,
94
89
src : Vec < tokenstream:: TokenTree > )
95
90
-> Vec < TokenTree > {
96
- let mut r = TtReader {
97
- sp_diag : sp_diag,
98
- stack : SmallVector :: one ( Frame :: Delimited {
99
- forest : Rc :: new ( tokenstream:: Delimited { delim : token:: NoDelim , tts : src } ) ,
100
- idx : 0 ,
101
- span : DUMMY_SP ,
102
- } ) ,
103
- interpolations : match interp { /* just a convenience */
104
- None => HashMap :: new ( ) ,
105
- Some ( x) => x,
106
- } ,
107
- repeat_idx : Vec :: new ( ) ,
108
- repeat_len : Vec :: new ( ) ,
109
- } ;
110
-
111
- let mut tts = Vec :: new ( ) ;
112
- let mut prev_span = DUMMY_SP ;
113
- while let Some ( tt) = tt_next_token ( & mut r, prev_span) {
114
- prev_span = tt. span ( ) ;
115
- tts. push ( tt) ;
116
- }
117
- tts
118
- }
119
-
120
- fn lookup_cur_matched_by_matched ( r : & TtReader , start : Rc < NamedMatch > ) -> Rc < NamedMatch > {
121
- r. repeat_idx . iter ( ) . fold ( start, |ad, idx| {
122
- match * ad {
123
- MatchedNonterminal ( _) => {
124
- // end of the line; duplicate henceforth
125
- ad. clone ( )
126
- }
127
- MatchedSeq ( ref ads, _) => ads[ * idx] . clone ( )
128
- }
129
- } )
130
- }
131
-
132
- fn lookup_cur_matched ( r : & TtReader , name : Ident ) -> Option < Rc < NamedMatch > > {
133
- let matched_opt = r. interpolations . get ( & name) . cloned ( ) ;
134
- matched_opt. map ( |s| lookup_cur_matched_by_matched ( r, s) )
135
- }
136
-
137
- #[ derive( Clone ) ]
138
- enum LockstepIterSize {
139
- LisUnconstrained ,
140
- LisConstraint ( usize , Ident ) ,
141
- LisContradiction ( String ) ,
142
- }
91
+ let mut stack = SmallVector :: one ( Frame :: new ( src) ) ;
92
+ let interpolations = interp. unwrap_or_else ( HashMap :: new) ; /* just a convenience */
93
+ let mut repeat_idx = Vec :: new ( ) ;
94
+ let mut repeat_len = Vec :: new ( ) ;
95
+ let mut result = Vec :: new ( ) ;
143
96
144
- impl Add for LockstepIterSize {
145
- type Output = LockstepIterSize ;
146
-
147
- fn add ( self , other : LockstepIterSize ) -> LockstepIterSize {
148
- match self {
149
- LisUnconstrained => other,
150
- LisContradiction ( _) => self ,
151
- LisConstraint ( l_len, ref l_id) => match other {
152
- LisUnconstrained => self . clone ( ) ,
153
- LisContradiction ( _) => other,
154
- LisConstraint ( r_len, _) if l_len == r_len => self . clone ( ) ,
155
- LisConstraint ( r_len, r_id) => {
156
- LisContradiction ( format ! ( "inconsistent lockstep iteration: \
157
- '{}' has {} items, but '{}' has {}",
158
- l_id, l_len, r_id, r_len) )
159
- }
160
- } ,
161
- }
162
- }
163
- }
164
-
165
- fn lockstep_iter_size ( t : & TokenTree , r : & TtReader ) -> LockstepIterSize {
166
- match * t {
167
- TokenTree :: Delimited ( _, ref delimed) => {
168
- delimed. tts . iter ( ) . fold ( LisUnconstrained , |size, tt| {
169
- size + lockstep_iter_size ( tt, r)
170
- } )
171
- } ,
172
- TokenTree :: Sequence ( _, ref seq) => {
173
- seq. tts . iter ( ) . fold ( LisUnconstrained , |size, tt| {
174
- size + lockstep_iter_size ( tt, r)
175
- } )
176
- } ,
177
- TokenTree :: Token ( _, SubstNt ( name) ) | TokenTree :: Token ( _, MatchNt ( name, _) ) =>
178
- match lookup_cur_matched ( r, name) {
179
- Some ( matched) => match * matched {
180
- MatchedNonterminal ( _) => LisUnconstrained ,
181
- MatchedSeq ( ref ads, _) => LisConstraint ( ads. len ( ) , name) ,
182
- } ,
183
- _ => LisUnconstrained
184
- } ,
185
- TokenTree :: Token ( ..) => LisUnconstrained ,
186
- }
187
- }
188
-
189
- /// Return the next token from the TtReader.
190
- /// EFFECT: advances the reader's token field
191
- fn tt_next_token ( r : & mut TtReader , prev_span : Span ) -> Option < TokenTree > {
192
97
loop {
193
- let tree = match r. stack . last_mut ( ) {
194
- Some ( frame) => frame. next ( ) ,
195
- None => return None ,
196
- } ;
197
-
198
- let tree = if let Some ( tree) = tree {
98
+ let tree = if let Some ( tree) = stack. last_mut ( ) . unwrap ( ) . next ( ) {
199
99
tree
200
100
} else {
201
- if let Frame :: Sequence { ref mut idx, ref sep, .. } = * r . stack . last_mut ( ) . unwrap ( ) {
202
- if * r . repeat_idx . last ( ) . unwrap ( ) < * r . repeat_len . last ( ) . unwrap ( ) - 1 {
203
- * r . repeat_idx . last_mut ( ) . unwrap ( ) += 1 ;
101
+ if let Frame :: Sequence { ref mut idx, ref sep, .. } = * stack. last_mut ( ) . unwrap ( ) {
102
+ if * repeat_idx. last ( ) . unwrap ( ) < * repeat_len. last ( ) . unwrap ( ) - 1 {
103
+ * repeat_idx. last_mut ( ) . unwrap ( ) += 1 ;
204
104
* idx = 0 ;
205
105
if let Some ( sep) = sep. clone ( ) {
206
- return Some ( TokenTree :: Token ( prev_span, sep) ) ; // repeat same span, I guess
106
+ // repeat same span, I guess
107
+ let prev_span = result. last ( ) . map ( TokenTree :: span) . unwrap_or ( DUMMY_SP ) ;
108
+ result. push ( TokenTree :: Token ( prev_span, sep) ) ;
207
109
}
208
110
continue
209
111
}
210
112
}
211
113
212
- if let Frame :: Sequence { .. } = r. stack . pop ( ) . unwrap ( ) {
213
- r. repeat_idx . pop ( ) ;
214
- r. repeat_len . pop ( ) ;
114
+ if let Frame :: Sequence { .. } = stack. pop ( ) . unwrap ( ) {
115
+ repeat_idx. pop ( ) ;
116
+ repeat_len. pop ( ) ;
117
+ }
118
+ if stack. is_empty ( ) {
119
+ return result;
215
120
}
216
121
continue
217
122
} ;
@@ -220,73 +125,143 @@ fn tt_next_token(r: &mut TtReader, prev_span: Span) -> Option<TokenTree> {
220
125
TokenTree :: Sequence ( sp, seq) => {
221
126
// FIXME(pcwalton): Bad copy.
222
127
match lockstep_iter_size ( & TokenTree :: Sequence ( sp, seq. clone ( ) ) ,
223
- r) {
224
- LisUnconstrained => {
225
- panic ! ( r. sp_diag. span_fatal(
128
+ & interpolations,
129
+ & repeat_idx) {
130
+ LockstepIterSize :: Unconstrained => {
131
+ panic ! ( sp_diag. span_fatal(
226
132
sp. clone( ) , /* blame macro writer */
227
133
"attempted to repeat an expression \
228
134
containing no syntax \
229
135
variables matched as repeating at this depth") ) ;
230
136
}
231
- LisContradiction ( ref msg) => {
137
+ LockstepIterSize :: Contradiction ( ref msg) => {
232
138
// FIXME #2887 blame macro invoker instead
233
- panic ! ( r . sp_diag. span_fatal( sp. clone( ) , & msg[ ..] ) ) ;
139
+ panic ! ( sp_diag. span_fatal( sp. clone( ) , & msg[ ..] ) ) ;
234
140
}
235
- LisConstraint ( len, _) => {
141
+ LockstepIterSize :: Constraint ( len, _) => {
236
142
if len == 0 {
237
143
if seq. op == tokenstream:: KleeneOp :: OneOrMore {
238
144
// FIXME #2887 blame invoker
239
- panic ! ( r . sp_diag. span_fatal( sp. clone( ) ,
240
- "this must repeat at least once" ) ) ;
145
+ panic ! ( sp_diag. span_fatal( sp. clone( ) ,
146
+ "this must repeat at least once" ) ) ;
241
147
}
242
-
243
- return tt_next_token ( r, prev_span) ;
148
+ } else {
149
+ repeat_len. push ( len) ;
150
+ repeat_idx. push ( 0 ) ;
151
+ stack. push ( Frame :: Sequence {
152
+ idx : 0 ,
153
+ sep : seq. separator . clone ( ) ,
154
+ forest : seq,
155
+ } ) ;
244
156
}
245
- r. repeat_len . push ( len) ;
246
- r. repeat_idx . push ( 0 ) ;
247
- r. stack . push ( Frame :: Sequence {
248
- idx : 0 ,
249
- sep : seq. separator . clone ( ) ,
250
- forest : seq,
251
- } ) ;
252
157
}
253
158
}
254
159
}
255
160
// FIXME #2887: think about span stuff here
256
161
TokenTree :: Token ( sp, SubstNt ( ident) ) => {
257
- match lookup_cur_matched ( r, ident) {
258
- None => {
259
- return Some ( TokenTree :: Token ( sp, SubstNt ( ident) ) ) ;
260
- // this can't be 0 length, just like TokenTree::Delimited
261
- }
162
+ match lookup_cur_matched ( ident, & interpolations, & repeat_idx) {
163
+ None => result. push ( TokenTree :: Token ( sp, SubstNt ( ident) ) ) ,
262
164
Some ( cur_matched) => if let MatchedNonterminal ( ref nt) = * cur_matched {
263
165
match * * nt {
264
166
// sidestep the interpolation tricks for ident because
265
167
// (a) idents can be in lots of places, so it'd be a pain
266
168
// (b) we actually can, since it's a token.
267
169
NtIdent ( ref sn) => {
268
- return Some ( TokenTree :: Token ( sn. span , token:: Ident ( sn. node ) ) ) ;
170
+ result . push ( TokenTree :: Token ( sn. span , token:: Ident ( sn. node ) ) ) ;
269
171
}
270
- NtTT ( ref tt) => return Some ( tt. clone ( ) ) ,
172
+ NtTT ( ref tt) => result . push ( tt. clone ( ) ) ,
271
173
_ => {
272
174
// FIXME(pcwalton): Bad copy
273
- return Some ( TokenTree :: Token ( sp, token:: Interpolated ( nt. clone ( ) ) ) ) ;
175
+ result . push ( TokenTree :: Token ( sp, token:: Interpolated ( nt. clone ( ) ) ) ) ;
274
176
}
275
177
}
276
178
} else {
277
- panic ! ( r . sp_diag. span_fatal(
179
+ panic ! ( sp_diag. span_fatal(
278
180
sp, /* blame the macro writer */
279
181
& format!( "variable '{}' is still repeating at this depth" , ident) ) ) ;
280
182
}
281
183
}
282
184
}
283
185
TokenTree :: Delimited ( span, delimited) => {
284
- r . stack . push ( Frame :: Delimited { forest : delimited, idx : 0 , span : span } ) ;
186
+ stack. push ( Frame :: Delimited { forest : delimited, idx : 0 , span : span } ) ;
285
187
}
286
188
TokenTree :: Token ( span, MatchNt ( name, kind) ) => {
287
- r . stack . push ( Frame :: MatchNt { name : name, kind : kind, idx : 0 , span : span } ) ;
189
+ stack. push ( Frame :: MatchNt { name : name, kind : kind, idx : 0 , span : span } ) ;
288
190
}
289
- tt @ TokenTree :: Token ( ..) => return Some ( tt) ,
191
+ tt @ TokenTree :: Token ( ..) => result . push ( tt) ,
290
192
}
291
193
}
292
194
}
195
+
196
+ fn lookup_cur_matched ( ident : Ident ,
197
+ interpolations : & HashMap < Ident , Rc < NamedMatch > > ,
198
+ repeat_idx : & [ usize ] )
199
+ -> Option < Rc < NamedMatch > > {
200
+ interpolations. get ( & ident) . map ( |matched| {
201
+ repeat_idx. iter ( ) . fold ( matched. clone ( ) , |ad, idx| {
202
+ match * ad {
203
+ MatchedNonterminal ( _) => {
204
+ // end of the line; duplicate henceforth
205
+ ad. clone ( )
206
+ }
207
+ MatchedSeq ( ref ads, _) => ads[ * idx] . clone ( )
208
+ }
209
+ } )
210
+ } )
211
+ }
212
+
213
+ #[ derive( Clone ) ]
214
+ enum LockstepIterSize {
215
+ Unconstrained ,
216
+ Constraint ( usize , Ident ) ,
217
+ Contradiction ( String ) ,
218
+ }
219
+
220
+ impl Add for LockstepIterSize {
221
+ type Output = LockstepIterSize ;
222
+
223
+ fn add ( self , other : LockstepIterSize ) -> LockstepIterSize {
224
+ match self {
225
+ LockstepIterSize :: Unconstrained => other,
226
+ LockstepIterSize :: Contradiction ( _) => self ,
227
+ LockstepIterSize :: Constraint ( l_len, ref l_id) => match other {
228
+ LockstepIterSize :: Unconstrained => self . clone ( ) ,
229
+ LockstepIterSize :: Contradiction ( _) => other,
230
+ LockstepIterSize :: Constraint ( r_len, _) if l_len == r_len => self . clone ( ) ,
231
+ LockstepIterSize :: Constraint ( r_len, r_id) => {
232
+ let msg = format ! ( "inconsistent lockstep iteration: \
233
+ '{}' has {} items, but '{}' has {}",
234
+ l_id, l_len, r_id, r_len) ;
235
+ LockstepIterSize :: Contradiction ( msg)
236
+ }
237
+ } ,
238
+ }
239
+ }
240
+ }
241
+
242
+ fn lockstep_iter_size ( tree : & TokenTree ,
243
+ interpolations : & HashMap < Ident , Rc < NamedMatch > > ,
244
+ repeat_idx : & [ usize ] )
245
+ -> LockstepIterSize {
246
+ match * tree {
247
+ TokenTree :: Delimited ( _, ref delimed) => {
248
+ delimed. tts . iter ( ) . fold ( LockstepIterSize :: Unconstrained , |size, tt| {
249
+ size + lockstep_iter_size ( tt, interpolations, repeat_idx)
250
+ } )
251
+ } ,
252
+ TokenTree :: Sequence ( _, ref seq) => {
253
+ seq. tts . iter ( ) . fold ( LockstepIterSize :: Unconstrained , |size, tt| {
254
+ size + lockstep_iter_size ( tt, interpolations, repeat_idx)
255
+ } )
256
+ } ,
257
+ TokenTree :: Token ( _, SubstNt ( name) ) | TokenTree :: Token ( _, MatchNt ( name, _) ) =>
258
+ match lookup_cur_matched ( name, interpolations, repeat_idx) {
259
+ Some ( matched) => match * matched {
260
+ MatchedNonterminal ( _) => LockstepIterSize :: Unconstrained ,
261
+ MatchedSeq ( ref ads, _) => LockstepIterSize :: Constraint ( ads. len ( ) , name) ,
262
+ } ,
263
+ _ => LockstepIterSize :: Unconstrained
264
+ } ,
265
+ TokenTree :: Token ( ..) => LockstepIterSize :: Unconstrained ,
266
+ }
267
+ }
0 commit comments