@@ -87,17 +87,6 @@ use rustc_data_structures::sync::Lrc;
87
87
use rustc_span:: symbol:: Ident ;
88
88
use std:: borrow:: Cow ;
89
89
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
90
- use std:: mem;
91
-
92
- /// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have
93
- /// descended into.
94
- #[ derive( Clone ) ]
95
- struct MatcherPosFrame < ' tt > {
96
- /// The "parent" matcher that we have descended from.
97
- tts : & ' tt [ TokenTree ] ,
98
- /// The position of the "dot" in `tt` at the time we descended.
99
- idx : usize ,
100
- }
101
90
102
91
// One element is enough to cover 95-99% of vectors for most benchmarks. Also,
103
92
// vectors longer than one frequently have many elements, not just two or
@@ -108,6 +97,33 @@ type NamedMatchVec = SmallVec<[NamedMatch; 1]>;
108
97
#[ cfg( all( target_arch = "x86_64" , target_pointer_width = "64" ) ) ]
109
98
rustc_data_structures:: static_assert_size!( NamedMatchVec , 48 ) ;
110
99
100
+ #[ derive( Clone ) ]
101
+ enum MatcherKind < ' tt > {
102
+ TopLevel ,
103
+ Delimited ( Box < DelimitedSubmatcher < ' tt > > ) ,
104
+ Sequence ( Box < SequenceSubmatcher < ' tt > > ) ,
105
+ }
106
+
107
+ #[ derive( Clone ) ]
108
+ struct DelimitedSubmatcher < ' tt > {
109
+ parent : Parent < ' tt > ,
110
+ }
111
+
112
+ #[ derive( Clone ) ]
113
+ struct SequenceSubmatcher < ' tt > {
114
+ parent : Parent < ' tt > ,
115
+ seq : & ' tt SequenceRepetition ,
116
+ }
117
+
118
+ /// Data used to ascend from a submatcher back to its parent matcher. A subset of the fields from
119
+ /// `MathcherPos`.
120
+ #[ derive( Clone ) ]
121
+ struct Parent < ' tt > {
122
+ tts : & ' tt [ TokenTree ] ,
123
+ idx : usize ,
124
+ kind : MatcherKind < ' tt > ,
125
+ }
126
+
111
127
/// A single matcher position, which could be within the top-level matcher, a submatcher, a
112
128
/// subsubmatcher, etc. For example:
113
129
/// ```text
@@ -140,17 +156,14 @@ struct MatcherPos<'tt> {
140
156
/// stream. Should not be used if there are no metavars.
141
157
match_cur : usize ,
142
158
143
- /// This field is only used if we are matching a sequence.
144
- sequence : Option < MatcherPosSequence < ' tt > > ,
145
-
146
- /// When we are within a `Delimited` submatcher (or subsubmatcher), this tracks the parent
147
- /// matcher(s). The bottom of the stack is the top-level matcher.
148
- stack : SmallVec < [ MatcherPosFrame < ' tt > ; 1 ] > ,
159
+ /// What kind of matcher we are in. For submatchers, this contains enough information to
160
+ /// reconstitute a `MatcherPos` within the parent once we ascend out of the submatcher.
161
+ kind : MatcherKind < ' tt > ,
149
162
}
150
163
151
164
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
152
165
#[ cfg( all( target_arch = "x86_64" , target_pointer_width = "64" ) ) ]
153
- rustc_data_structures:: static_assert_size!( MatcherPos <' _>, 96 ) ;
166
+ rustc_data_structures:: static_assert_size!( MatcherPos <' _>, 64 ) ;
154
167
155
168
impl < ' tt > MatcherPos < ' tt > {
156
169
fn top_level ( matcher : & ' tt [ TokenTree ] , empty_matches : Lrc < NamedMatchVec > ) -> Self {
@@ -160,24 +173,26 @@ impl<'tt> MatcherPos<'tt> {
160
173
matches : empty_matches,
161
174
seq_depth : 0 ,
162
175
match_cur : 0 ,
163
- stack : smallvec ! [ ] ,
164
- sequence : None ,
176
+ kind : MatcherKind :: TopLevel ,
165
177
}
166
178
}
167
179
168
180
fn sequence (
169
- parent : Box < MatcherPos < ' tt > > ,
181
+ parent_mp : Box < MatcherPos < ' tt > > ,
170
182
seq : & ' tt SequenceRepetition ,
171
183
empty_matches : Lrc < NamedMatchVec > ,
172
184
) -> Self {
185
+ let seq_kind = box SequenceSubmatcher {
186
+ parent : Parent { tts : parent_mp. tts , idx : parent_mp. idx , kind : parent_mp. kind } ,
187
+ seq,
188
+ } ;
173
189
let mut mp = MatcherPos {
174
190
tts : & seq. tts ,
175
191
idx : 0 ,
176
- matches : parent. matches . clone ( ) ,
177
- seq_depth : parent. seq_depth ,
178
- match_cur : parent. match_cur ,
179
- sequence : Some ( MatcherPosSequence { parent, seq } ) ,
180
- stack : smallvec ! [ ] ,
192
+ matches : parent_mp. matches ,
193
+ seq_depth : parent_mp. seq_depth ,
194
+ match_cur : parent_mp. match_cur ,
195
+ kind : MatcherKind :: Sequence ( seq_kind) ,
181
196
} ;
182
197
// Start with an empty vec for each metavar within the sequence. Note that `mp.seq_depth`
183
198
// must have the parent's depth at this point for these `push_match` calls to work.
@@ -222,16 +237,6 @@ impl<'tt> MatcherPos<'tt> {
222
237
}
223
238
}
224
239
225
- #[ derive( Clone ) ]
226
- struct MatcherPosSequence < ' tt > {
227
- /// The parent matcher position. Effectively gives a linked list of matches all the way to the
228
- /// top-level matcher.
229
- parent : Box < MatcherPos < ' tt > > ,
230
-
231
- /// The sequence itself.
232
- seq : & ' tt SequenceRepetition ,
233
- }
234
-
235
240
enum EofMatcherPositions < ' tt > {
236
241
None ,
237
242
One ( Box < MatcherPos < ' tt > > ) ,
@@ -499,15 +504,17 @@ impl<'tt> TtParser<'tt> {
499
504
}
500
505
501
506
TokenTree :: Delimited ( _, delimited) => {
502
- // To descend into a delimited submatcher, we push the current matcher onto
503
- // a stack and push a new mp containing the submatcher onto `cur_mps`. When
504
- // we reach the closing delimiter, we will pop the stack to backtrack out
505
- // of the descent. Note that we use `all_tts` to include the open and close
506
- // delimiter tokens.
507
- let tts = mem:: replace ( & mut mp. tts , & delimited. all_tts ) ;
508
- let idx = mp. idx ;
509
- mp. stack . push ( MatcherPosFrame { tts, idx } ) ;
507
+ // To descend into a delimited submatcher, we update `mp` appropriately,
508
+ // including enough information to re-ascend afterwards, and push it onto
509
+ // `cur_mps`. Later, when we reach the closing delimiter, we will recover
510
+ // the parent matcher position to ascend. Note that we use `all_tts` to
511
+ // include the open and close delimiter tokens.
512
+ let kind = MatcherKind :: Delimited ( box DelimitedSubmatcher {
513
+ parent : Parent { tts : mp. tts , idx : mp. idx , kind : mp. kind } ,
514
+ } ) ;
515
+ mp. tts = & delimited. all_tts ;
510
516
mp. idx = 0 ;
517
+ mp. kind = kind;
511
518
self . cur_mps . push ( mp) ;
512
519
}
513
520
@@ -528,9 +535,14 @@ impl<'tt> TtParser<'tt> {
528
535
if let TokenKind :: CloseDelim ( _) = token. kind {
529
536
// Ascend out of the delimited submatcher.
530
537
debug_assert_eq ! ( idx, len - 1 ) ;
531
- let frame = mp. stack . pop ( ) . unwrap ( ) ;
532
- mp. tts = frame. tts ;
533
- mp. idx = frame. idx ;
538
+ match mp. kind {
539
+ MatcherKind :: Delimited ( submatcher) => {
540
+ mp. tts = submatcher. parent . tts ;
541
+ mp. idx = submatcher. parent . idx ;
542
+ mp. kind = submatcher. parent . kind ;
543
+ }
544
+ _ => unreachable ! ( ) ,
545
+ }
534
546
}
535
547
mp. idx += 1 ;
536
548
self . next_mps . push ( mp) ;
@@ -540,45 +552,44 @@ impl<'tt> TtParser<'tt> {
540
552
// These cannot appear in a matcher.
541
553
TokenTree :: MetaVar ( ..) | TokenTree :: MetaVarExpr ( ..) => unreachable ! ( ) ,
542
554
}
543
- } else if let Some ( sequence ) = & mp. sequence {
555
+ } else if let MatcherKind :: Sequence ( box SequenceSubmatcher { parent , seq } ) = & mp. kind {
544
556
// We are past the end of a sequence.
545
557
// - If it has no separator, we must be only one past the end.
546
558
// - If it has a separator, we may be one past the end, in which case we must
547
559
// look for a separator. Or we may be two past the end, in which case we have
548
560
// already dealt with the separator.
549
- debug_assert ! ( idx == len || idx == len + 1 && sequence . seq. separator. is_some( ) ) ;
561
+ debug_assert ! ( idx == len || idx == len + 1 && seq. separator. is_some( ) ) ;
550
562
551
563
if idx == len {
552
564
// Sequence matching may have finished: move the "dot" past the sequence in
553
565
// `parent`. This applies whether a separator is used or not. If sequence
554
566
// matching hasn't finished, this `new_mp` will fail quietly when it is
555
567
// processed next time around the loop.
556
- let mut new_mp = sequence. parent . clone ( ) ;
557
- new_mp. matches = mp. matches . clone ( ) ;
558
- new_mp. match_cur = mp. match_cur ;
559
- new_mp. idx += 1 ;
568
+ let new_mp = box MatcherPos {
569
+ tts : parent. tts ,
570
+ idx : parent. idx + 1 ,
571
+ matches : mp. matches . clone ( ) , // a cheap clone
572
+ seq_depth : mp. seq_depth - 1 ,
573
+ match_cur : mp. match_cur ,
574
+ kind : parent. kind . clone ( ) , // an expensive clone
575
+ } ;
560
576
self . cur_mps . push ( new_mp) ;
561
577
}
562
578
563
- if sequence . seq . separator . is_some ( ) && idx == len {
579
+ if seq. separator . is_some ( ) && idx == len {
564
580
// Look for the separator.
565
- if sequence
566
- . seq
567
- . separator
568
- . as_ref ( )
569
- . map_or ( false , |sep| token_name_eq ( token, sep) )
570
- {
581
+ if seq. separator . as_ref ( ) . map_or ( false , |sep| token_name_eq ( token, sep) ) {
571
582
// The matcher has a separator, and it matches the current token. We can
572
583
// advance past the separator token.
573
584
mp. idx += 1 ;
574
585
self . next_mps . push ( mp) ;
575
586
}
576
- } else if sequence . seq . kleene . op != mbe:: KleeneOp :: ZeroOrOne {
587
+ } else if seq. kleene . op != mbe:: KleeneOp :: ZeroOrOne {
577
588
// We don't need to look for a separator: either this sequence doesn't have
578
589
// one, or it does and we've already handled it. Also, we are allowed to have
579
590
// more than one repetition. Move the "dot" back to the beginning of the
580
591
// matcher and try to match again.
581
- mp. match_cur -= sequence . seq . num_captures ;
592
+ mp. match_cur -= seq. num_captures ;
582
593
mp. idx = 0 ;
583
594
self . cur_mps . push ( mp) ;
584
595
}
0 commit comments