@@ -3,6 +3,7 @@ use std::str::FromStr;
3
3
4
4
use crate :: {
5
5
language:: { CoreParameter , HasKind , Language } ,
6
+ parse:: parser:: left_recursion:: { CurrentState , LeftRight } ,
6
7
set,
7
8
variable:: CoreVariable ,
8
9
Downcast , DowncastFrom , Set , Upcast ,
@@ -56,8 +57,10 @@ pub struct ActiveVariant<'s, 't, L>
56
57
where
57
58
L : Language ,
58
59
{
60
+ precedence : Precedence ,
59
61
scope : & ' s Scope < L > ,
60
- text : & ' t str ,
62
+ start_text : & ' t str ,
63
+ current_text : & ' t str ,
61
64
reductions : Vec < & ' static str > ,
62
65
is_cast_variant : bool ,
63
66
}
94
97
nonterminal_name : & ' static str ,
95
98
mut op : impl FnMut ( & mut Self ) ,
96
99
) -> ParseResult < ' t , T > {
100
+ let text = skip_whitespace ( text) ;
101
+
97
102
left_recursion:: enter ( scope, text, || {
98
103
let tracing_span = tracing:: span!(
99
104
tracing:: Level :: TRACE ,
@@ -154,12 +159,8 @@ where
154
159
155
160
let variant_precedence = Precedence ( variant_precedence) ;
156
161
157
- let mut active_variant = ActiveVariant {
158
- scope : self . scope ,
159
- text : self . start_text ,
160
- reductions : vec ! [ ] ,
161
- is_cast_variant : false ,
162
- } ;
162
+ let mut active_variant =
163
+ ActiveVariant :: new ( variant_precedence, self . scope , self . start_text ) ;
163
164
let result = op ( & mut active_variant) ;
164
165
165
166
// Drop the guard here so that the "success" or "error" results appear outside the variant span.
@@ -175,7 +176,7 @@ where
175
176
}
176
177
177
178
self . successes . push ( SuccessfulParse {
178
- text : active_variant. text ,
179
+ text : active_variant. current_text ,
179
180
reductions : active_variant. reductions ,
180
181
precedence : variant_precedence,
181
182
value,
@@ -271,19 +272,50 @@ impl<'s, 't, L> ActiveVariant<'s, 't, L>
271
272
where
272
273
L : Language ,
273
274
{
275
+ fn new ( precedence : Precedence , scope : & ' s Scope < L > , start_text : & ' t str ) -> Self {
276
+ let start_text = skip_whitespace ( start_text) ;
277
+ Self {
278
+ precedence,
279
+ scope,
280
+ start_text,
281
+ current_text : start_text,
282
+ reductions : vec ! [ ] ,
283
+ is_cast_variant : false ,
284
+ }
285
+ }
286
+ fn current_state ( & self ) -> CurrentState {
287
+ // Determine whether we are in Left or Right position -- Left means
288
+ // that we have not yet consumed any tokens. Right means that we have.
289
+ // See `LeftRight` type for more details.
290
+ //
291
+ // Subtle-ish: this comparison assumes there is no whitespace,
292
+ // but we establish that invariant in `Self::new`.
293
+ debug_assert_eq ! ( self . start_text, skip_whitespace( self . start_text) ) ;
294
+ let left_right = if self . start_text == self . current_text {
295
+ LeftRight :: Left
296
+ } else {
297
+ LeftRight :: Right
298
+ } ;
299
+
300
+ CurrentState {
301
+ left_right,
302
+ precedence : self . precedence ,
303
+ }
304
+ }
305
+
274
306
/// The current text remaining to be consumed.
275
307
pub fn text ( & self ) -> & ' t str {
276
- self . text
308
+ self . current_text
277
309
}
278
310
279
311
/// Skips whitespace in the input, producing no reduction.
280
312
pub fn skip_whitespace ( & mut self ) {
281
- self . text = skip_whitespace ( self . text ) ;
313
+ self . current_text = skip_whitespace ( self . current_text ) ;
282
314
}
283
315
284
316
/// Skips a comma in the input, producing no reduction.
285
317
pub fn skip_trailing_comma ( & mut self ) {
286
- self . text = skip_trailing_comma ( self . text ) ;
318
+ self . current_text = skip_trailing_comma ( self . current_text ) ;
287
319
}
288
320
289
321
/// Marks this variant as an cast variant,
@@ -366,7 +398,7 @@ where
366
398
/// Consume next identifier-like string, requiring that it be equal to `expected`.
367
399
#[ tracing:: instrument( level = "trace" , ret) ]
368
400
pub fn expect_keyword ( & mut self , expected : & str ) -> Result < ( ) , Set < ParseError < ' t > > > {
369
- let text0 = self . text ;
401
+ let text0 = self . current_text ;
370
402
match self . identifier_like_string ( ) {
371
403
Ok ( ident) if & * ident == expected => Ok ( ( ) ) ,
372
404
_ => Err ( ParseError :: at (
@@ -379,7 +411,7 @@ where
379
411
/// Accepts any of the given keywords.
380
412
#[ tracing:: instrument( level = "trace" , ret) ]
381
413
pub fn expect_keyword_in ( & mut self , expected : & [ & str ] ) -> Result < String , Set < ParseError < ' t > > > {
382
- let text0 = self . text ;
414
+ let text0 = self . current_text ;
383
415
match self . identifier_like_string ( ) {
384
416
Ok ( ident) if expected. iter ( ) . any ( |& kw| ident == kw) => Ok ( ident) ,
385
417
_ => Err ( ParseError :: at (
@@ -398,7 +430,9 @@ where
398
430
err : impl FnOnce ( T ) -> Set < ParseError < ' t > > ,
399
431
) -> Result < ( ) , Set < ParseError < ' t > > > {
400
432
let mut this = ActiveVariant {
401
- text : self . text ,
433
+ precedence : self . precedence ,
434
+ start_text : self . start_text ,
435
+ current_text : self . current_text ,
402
436
reductions : vec ! [ ] ,
403
437
scope : self . scope ,
404
438
is_cast_variant : false ,
@@ -420,7 +454,7 @@ where
420
454
|p| p. expect_keyword_in ( keywords) ,
421
455
|ident| {
422
456
ParseError :: at (
423
- self . text ,
457
+ self . current_text ,
424
458
format ! ( "expected identified, found keyword `{ident:?}`" ) ,
425
459
)
426
460
} ,
@@ -456,13 +490,15 @@ where
456
490
op : impl FnOnce ( & mut ActiveVariant < ' _ , ' t , L > ) -> R ,
457
491
) -> R {
458
492
let mut av = ActiveVariant {
493
+ precedence : self . precedence ,
459
494
scope : & scope,
460
- text : self . text ,
495
+ start_text : self . start_text ,
496
+ current_text : self . current_text ,
461
497
reductions : vec ! [ ] ,
462
498
is_cast_variant : false ,
463
499
} ;
464
500
let result = op ( & mut av) ;
465
- self . text = av. text ;
501
+ self . current_text = av. current_text ;
466
502
self . reductions . extend ( av. reductions ) ;
467
503
result
468
504
}
@@ -475,7 +511,7 @@ where
475
511
|p| p. variable ( ) ,
476
512
|var| {
477
513
ParseError :: at (
478
- self . text ,
514
+ self . current_text ,
479
515
format ! ( "found unexpected in-scope variable {:?}" , var) ,
480
516
)
481
517
} ,
@@ -510,7 +546,7 @@ where
510
546
{
511
547
self . skip_whitespace ( ) ;
512
548
let type_name = std:: any:: type_name :: < R > ( ) ;
513
- let text0 = self . text ;
549
+ let text0 = self . current_text ;
514
550
let id = self . identifier ( ) ?;
515
551
match self . scope . lookup ( & id) {
516
552
Some ( parameter) => match parameter. downcast ( ) {
@@ -535,7 +571,7 @@ where
535
571
T : FromStr + std:: fmt:: Debug ,
536
572
{
537
573
let description = std:: any:: type_name :: < T > ( ) ;
538
- let text0 = self . text ;
574
+ let text0 = self . current_text ;
539
575
let s = self . string ( char:: is_numeric, char:: is_numeric, description) ?;
540
576
match T :: from_str ( & s) {
541
577
Ok ( t) => Ok ( t) ,
@@ -562,7 +598,7 @@ where
562
598
) -> Result < T , Set < ParseError < ' t > > > {
563
599
self . skip_whitespace ( ) ;
564
600
let value;
565
- ( value, self . text ) = op ( self . text ) ?;
601
+ ( value, self . current_text ) = op ( self . current_text ) ?;
566
602
Ok ( value)
567
603
}
568
604
@@ -590,15 +626,15 @@ where
590
626
where
591
627
T : CoreParse < L > ,
592
628
{
593
- let text0 = self . text ;
629
+ let text0 = self . current_text ;
594
630
match self . nonterminal ( ) {
595
631
Ok ( v) => Ok ( Some ( v) ) ,
596
632
Err ( mut errs) => {
597
633
errs. retain ( |e| e. consumed_any_since ( text0) ) ;
598
634
if errs. is_empty ( ) {
599
635
// If no errors consumed anything, then self.text
600
636
// must not have advanced.
601
- assert_eq ! ( skip_whitespace( text0) , self . text ) ;
637
+ assert_eq ! ( skip_whitespace( text0) , self . current_text ) ;
602
638
Ok ( None )
603
639
} else {
604
640
Err ( errs)
@@ -682,10 +718,10 @@ where
682
718
reductions,
683
719
precedence : _,
684
720
value,
685
- } = op ( self . scope , self . text ) ?;
721
+ } = left_recursion :: recurse ( self . current_state ( ) , || op ( self . scope , self . current_text ) ) ?;
686
722
687
723
// Adjust our point in the input text
688
- self . text = text;
724
+ self . current_text = text;
689
725
690
726
// Some value was produced, so there must have been a reduction
691
727
assert ! ( !reductions. is_empty( ) ) ;
0 commit comments