@@ -9,7 +9,9 @@ use crate::{
9
9
Set , Upcast ,
10
10
} ;
11
11
12
- use super :: { CoreParse , ParseError , ParseResult , Scope , SuccessfulParse , TokenResult } ;
12
+ use super :: {
13
+ CoreParse , ParseError , ParseResult , ReductionKind , Scope , SuccessfulParse , TokenResult ,
14
+ } ;
13
15
14
16
mod left_recursion;
15
17
@@ -151,9 +153,8 @@ where
151
153
scope : & ' s Scope < L > ,
152
154
start_text : & ' t str ,
153
155
current_text : & ' t str ,
154
- reductions : Vec < & ' static str > ,
155
- is_cast_variant : bool ,
156
- is_in_scope_var : bool ,
156
+ reductions : Vec < ( & ' static str , ReductionKind ) > ,
157
+ variant_kind : ReductionKind ,
157
158
158
159
/// A variant is 'committed' when we have seen enough success
159
160
is_committed : bool ,
@@ -218,6 +219,20 @@ where
218
219
} )
219
220
}
220
221
222
+ pub fn identifier (
223
+ scope : & ' s Scope < L > ,
224
+ text : & ' t str ,
225
+ nonterminal_name : & ' static str ,
226
+ ) -> ParseResult < ' t , T >
227
+ where
228
+ String : Into < T > ,
229
+ {
230
+ Self :: single_variant ( scope, text, nonterminal_name, |p| {
231
+ p. mark_as_identifier ( ) ;
232
+ Ok ( p. identifier ( ) ?. into ( ) )
233
+ } )
234
+ }
235
+
221
236
/// Shorthand for `parse_variant` where the parsing operation is to
222
237
/// parse the type `V` and then upcast it to the desired result type.
223
238
/// Also marks the variant as a cast variant.
@@ -289,15 +304,14 @@ where
289
304
Ok ( value) => {
290
305
// Subtle: for cast variants, don't record the variant name in the reduction list,
291
306
// as it doesn't carry semantic weight. See `mark_as_cast_variant` for more details.
292
- if ! active_variant. is_cast_variant {
293
- active_variant . reductions . push ( variant_name ) ;
294
- }
307
+ active_variant
308
+ . reductions
309
+ . push ( ( variant_name , active_variant . variant_kind ) ) ;
295
310
296
311
self . successes . push ( SuccessfulParse {
297
312
text : active_variant. current_text ,
298
313
reductions : active_variant. reductions ,
299
314
precedence : variant_precedence,
300
- is_in_scope_var : active_variant. is_in_scope_var ,
301
315
value : value. upcast ( ) ,
302
316
} ) ;
303
317
tracing:: trace!( "success: {:?}" , self . successes. last( ) . unwrap( ) ) ;
@@ -380,14 +394,42 @@ where
380
394
}
381
395
382
396
fn is_preferable ( s_i : & SuccessfulParse < T > , s_j : & SuccessfulParse < T > ) -> bool {
383
- fn has_prefix < T : Eq > ( l1 : & [ T ] , l2 : & [ T ] ) -> bool {
384
- l1. len ( ) > l2. len ( ) && ( 0 ..l2. len ( ) ) . all ( |i| l1[ i] == l2[ i] )
397
+ let mut reductions_i = s_i. reductions . iter ( ) . peekable ( ) ;
398
+ let mut reductions_j = s_j. reductions . iter ( ) . peekable ( ) ;
399
+
400
+ loop {
401
+ match ( reductions_i. peek ( ) , reductions_j. peek ( ) ) {
402
+ // Drop casts from left or right if we see them, as they
403
+ // are not significant. (See `ReductionKind::Cast`)
404
+ ( Some ( ( _, ReductionKind :: Cast ) ) , _) => {
405
+ reductions_i. next ( ) ;
406
+ }
407
+ ( _, Some ( ( _, ReductionKind :: Cast ) ) ) => {
408
+ reductions_j. next ( ) ;
409
+ }
410
+ ( Some ( ( _, ReductionKind :: Variable ) ) , Some ( ( _, ReductionKind :: Identifier ) ) ) => {
411
+ // at some point, s_i parsed an in-scope variable and s_j parsed an identifier;
412
+ // we tilt in favor of in-scope variables in this kind of case
413
+ return true ;
414
+ }
415
+ ( Some ( _) , None ) => {
416
+ // s_j is a prefix of s_i -- prefer s_i
417
+ return true ;
418
+ }
419
+ ( None , Some ( _) ) | ( None , None ) => {
420
+ // s_i is a prefix of s_j or they are equal -- do NOT prefer s_i
421
+ return false ;
422
+ }
423
+ ( Some ( reduction_i) , Some ( reduction_j) ) => {
424
+ if reduction_i == reduction_j {
425
+ reductions_i. next ( ) ;
426
+ reductions_j. next ( ) ;
427
+ } else {
428
+ return false ;
429
+ }
430
+ }
431
+ }
385
432
}
386
-
387
- has_prefix ( & s_i. reductions , & s_j. reductions )
388
- || ( s_i. is_in_scope_var
389
- && !s_j. is_in_scope_var
390
- && skip_whitespace ( s_i. text ) == skip_whitespace ( s_j. text ) )
391
433
}
392
434
}
393
435
@@ -403,8 +445,7 @@ where
403
445
start_text,
404
446
current_text : start_text,
405
447
reductions : vec ! [ ] ,
406
- is_cast_variant : false ,
407
- is_in_scope_var : false ,
448
+ variant_kind : ReductionKind :: default ( ) ,
408
449
is_committed : true ,
409
450
}
410
451
}
@@ -470,45 +511,22 @@ where
470
511
self . current_text = skip_trailing_comma ( self . current_text ) ;
471
512
}
472
513
473
- /// Marks this variant as an cast variant,
474
- /// which means there is no semantic difference
475
- /// between the thing you parsed and the reduced form.
476
- /// We do this automatically for enum variants marked
477
- /// as `#[cast]` or calls to `parse_variant_cast`.
478
- ///
479
- /// Cast variants interact differently with ambiguity detection.
480
- /// Consider this grammar:
481
- ///
482
- /// ```text
483
- /// X = Y | Z // X has two variants
484
- /// Y = A // Y has 1 variant
485
- /// Z = A B // Z has 1 variant
486
- /// A = "a" // A has 1 variant
487
- /// B = "b" // B has 1 variant
488
- /// ```
489
- ///
490
- /// If you mark the two `X` variants (`X = Y` and `X = Z`)
491
- /// as cast variants, then the input `"a b"` is considered
492
- /// unambiguous and is parsed as `X = (Z = (A = "a') (B = "b))`
493
- /// with no remainder.
494
- ///
495
- /// If you don't mark those variants as cast variants,
496
- /// then we consider this *ambiguous*, because
497
- /// it could be that you want `X = (Y = (A = "a"))` with
498
- /// a remainder of `"b"`. This is appropriate
499
- /// if choosing Y vs Z has different semantic meaning.
514
+ /// Marks this variant as an cast variant.
515
+ /// See [`ReductionKind::Cast`].
500
516
pub fn mark_as_cast_variant ( & mut self ) {
501
- self . is_cast_variant = true ;
517
+ self . variant_kind = ReductionKind :: Cast ;
502
518
}
503
519
504
520
/// Indicates that this variant is parsing *only* an in-scope variable.
505
- /// We have special treatment for disambiguation such that if a variant marked
506
- /// as parsing an "in-scope variable" and some other variant both consume the
507
- /// same part of the input string, we prefer the variable. This method is automatically
508
- /// invoked on `#[variable]` variants by the generated parser code and you generally
509
- /// wouldn't want to call it yourself.
521
+ /// See [`ReducgionKind::Variable`].
510
522
pub fn mark_as_in_scope_var ( & mut self ) {
511
- self . is_in_scope_var = true ;
523
+ self . variant_kind = ReductionKind :: Variable ;
524
+ }
525
+
526
+ /// Indicates that this variant is parsing *only* an identifier.
527
+ /// See [`ReducgionKind::Identifier`].
528
+ pub fn mark_as_identifier ( & mut self ) {
529
+ self . variant_kind = ReductionKind :: Identifier ;
512
530
}
513
531
514
532
/// Expect *exactly* the given text (after skipping whitespace)
@@ -598,8 +616,7 @@ where
598
616
current_text : self . current_text ,
599
617
reductions : vec ! [ ] ,
600
618
scope : self . scope ,
601
- is_cast_variant : false ,
602
- is_in_scope_var : false ,
619
+ variant_kind : ReductionKind :: default ( ) ,
603
620
is_committed : true ,
604
621
} ;
605
622
@@ -659,8 +676,7 @@ where
659
676
start_text : self . start_text ,
660
677
current_text : self . current_text ,
661
678
reductions : vec ! [ ] ,
662
- is_cast_variant : false ,
663
- is_in_scope_var : false ,
679
+ variant_kind : ReductionKind :: default ( ) ,
664
680
is_committed : true ,
665
681
} ;
666
682
let result = op ( & mut av) ;
@@ -890,7 +906,6 @@ where
890
906
text,
891
907
reductions,
892
908
precedence : _,
893
- is_in_scope_var : _,
894
909
value,
895
910
} = left_recursion:: recurse ( self . current_state ( ) , || op ( self . scope , self . current_text ) ) ?;
896
911
0 commit comments