@@ -116,7 +116,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
116
116
117
117
118
118
fn make_stmts ( self : Box < ParserAnyMacro < ' a > > )
119
- -> Option < SmallVector < ast:: Stmt > > {
119
+ -> Option < SmallVector < ast:: Stmt > > {
120
120
let mut ret = SmallVector :: zero ( ) ;
121
121
loop {
122
122
let mut parser = self . parser . borrow_mut ( ) ;
@@ -250,7 +250,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
250
250
/// Converts a `macro_rules!` invocation into a syntax extension.
251
251
pub fn compile < ' cx > ( cx : & ' cx mut ExtCtxt ,
252
252
def : & ast:: MacroDef ,
253
- imported : bool ) -> SyntaxExtension {
253
+ check_macro : bool ) -> SyntaxExtension {
254
254
255
255
let lhs_nm = gensym_ident ( "lhs" ) ;
256
256
let rhs_nm = gensym_ident ( "rhs" ) ;
@@ -306,7 +306,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
306
306
MatchedSeq ( ref s, _) => {
307
307
s. iter ( ) . map ( |m| match * * m {
308
308
MatchedNonterminal ( NtTT ( ref tt) ) => {
309
- if !imported {
309
+ if check_macro {
310
310
valid &= check_lhs_nt_follows ( cx, tt) ;
311
311
}
312
312
( * * tt) . clone ( )
@@ -317,17 +317,20 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
317
317
_ => cx. span_bug ( def. span , "wrong-structured lhs" )
318
318
} ;
319
319
320
- if !imported {
320
+ if check_macro {
321
321
' a: for ( i, lhs) in lhses. iter ( ) . enumerate ( ) {
322
322
for lhs_ in lhses[ i + 1 ..] . iter ( ) {
323
- if !check_lhs_firsts ( cx, lhs, lhs_) {
324
- cx. struct_span_warn ( def. span , "macro is not future-proof" )
325
- . span_help ( lhs. get_span ( ) , "parsing of this arm is ambiguous..." )
326
- . span_help ( lhs_. get_span ( ) , "with the parsing of this arm." )
327
- . help ( "the behaviour of this macro might change in the future" )
328
- . emit ( ) ;
329
- //valid = false;
330
- break ' a;
323
+ match check_lhs_firsts ( cx, lhs, lhs_) {
324
+ AnalysisResult :: Error => {
325
+ cx. struct_span_err ( def. span , "macro is not future-proof" )
326
+ . span_help ( lhs. get_span ( ) , "parsing of this arm is ambiguous..." )
327
+ . span_help ( lhs_. get_span ( ) , "with the parsing of this arm." )
328
+ . help ( "the behaviour of this macro might change in the future" )
329
+ . emit ( ) ;
330
+ //valid = false;
331
+ break ' a;
332
+ }
333
+ _ => ( )
331
334
}
332
335
}
333
336
}
@@ -358,7 +361,8 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
358
361
NormalTT ( exp, Some ( def. span ) , def. allow_internal_unstable )
359
362
}
360
363
361
- fn check_lhs_firsts ( cx : & ExtCtxt , lhs : & TokenTree , lhs_ : & TokenTree ) -> bool {
364
+ fn check_lhs_firsts ( cx : & ExtCtxt , lhs : & TokenTree , lhs_ : & TokenTree )
365
+ -> AnalysisResult {
362
366
match ( lhs, lhs_) {
363
367
( & TokenTree :: Delimited ( _, ref tta) ,
364
368
& TokenTree :: Delimited ( _, ref ttb) ) =>
@@ -578,7 +582,20 @@ fn first_sets_disjoints(ma: &TokenTree, mb: &TokenTree,
578
582
}
579
583
}
580
584
581
- fn check_matcher_firsts ( cx : & ExtCtxt , ma : & [ TokenTree ] , mb : & [ TokenTree ] ) -> bool {
585
+ // the result of the FIRST set analysis.
586
+ // * Ok -> an obvious disambiguation has been found
587
+ // * Unsure -> no problem between those matchers but analysis should continue
588
+ // * Error -> maybe a problem. should be accepted only if an obvious
589
+ // disambiguation is found later
590
+ enum AnalysisResult {
591
+ Ok ,
592
+ Unsure ,
593
+ Error
594
+ }
595
+
596
+ fn check_matcher_firsts ( cx : & ExtCtxt , ma : & [ TokenTree ] , mb : & [ TokenTree ] )
597
+ -> AnalysisResult {
598
+ use self :: AnalysisResult :: * ;
582
599
let mut need_disambiguation = false ;
583
600
584
601
// first compute the FIRST sets. FIRST sets for tokens, delimited TTs and NT
@@ -601,7 +618,7 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
601
618
602
619
if first_sets_disjoints ( & ta, & tb, & firsts_a, & firsts_b) {
603
620
// accept the macro
604
- return true
621
+ return Ok
605
622
}
606
623
607
624
// i.e. A or B is either a repeated sequence or a NT matcher that is
@@ -611,22 +628,26 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
611
628
( & TokenTree :: Token ( _, MatchNt ( _, nta) ) ,
612
629
& TokenTree :: Token ( _, MatchNt ( _, ntb) ) ) =>
613
630
if !( nt_is_single_tt ( nta) && nt_is_single_tt ( ntb) ) {
614
- return false
631
+ return Error
615
632
} ,
616
633
617
634
( & TokenTree :: Token ( _, MatchNt ( _, nt) ) , _) if !nt_is_single_tt ( nt) =>
618
- return false ,
635
+ return Error ,
619
636
620
637
// super specific corner case: if one arm is always one token,
621
638
// followed by the end of the macro invocation, then we can accept
622
639
// it.
623
640
624
641
( & TokenTree :: Sequence ( _, _) , _) |
625
642
( _, & TokenTree :: Sequence ( _, _) ) =>
626
- return only_simple_tokens ( & ma[ idx_a..] ) && !need_disambiguation,
643
+ return if only_simple_tokens ( & ma[ idx_a..] ) && !need_disambiguation {
644
+ Unsure
645
+ } else { Error } ,
627
646
628
647
( _ , & TokenTree :: Token ( _, MatchNt ( _, nt) ) ) if !nt_is_single_tt ( nt) =>
629
- return only_simple_tokens ( & ma[ idx_a..] ) && !need_disambiguation,
648
+ return if only_simple_tokens ( & ma[ idx_a..] ) && !need_disambiguation {
649
+ Unsure
650
+ } else { Error } ,
630
651
631
652
_ => ( )
632
653
}
@@ -690,12 +711,17 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
690
711
continue
691
712
}
692
713
693
- ( & TokenTree :: Delimited ( ..) , & TokenTree :: Delimited ( ..) ) => {
714
+ ( & TokenTree :: Delimited ( _, ref d1) ,
715
+ & TokenTree :: Delimited ( _, ref d2) ) => {
694
716
// they have the same delim. as above.
695
- // FIXME: we could search for disambiguation *inside* the
696
- // delimited TTs
697
- need_disambiguation = true ;
698
- continue
717
+ match check_matcher_firsts ( cx, & d1. tts , & d2. tts ) {
718
+ Ok => return Ok ,
719
+ Unsure => continue ,
720
+ Error => {
721
+ need_disambiguation = true ;
722
+ continue
723
+ }
724
+ }
699
725
}
700
726
701
727
// cannot happen. either they're the same token or their FIRST sets
@@ -713,12 +739,12 @@ fn check_matcher_firsts(cx: &ExtCtxt, ma: &[TokenTree], mb: &[TokenTree]) -> boo
713
739
// reject conservatively.
714
740
// FIXME: if we are not at the end of the other arm, and that the other
715
741
// arm cannot derive empty, I think we could accept...?
716
- false
742
+ Error
717
743
} else {
718
744
// either A is strictly included in B and the other inputs that match B
719
745
// will never match A, or B is included in or equal to A, which means
720
746
// it's unreachable. this is not our problem. accept.
721
- true
747
+ Unsure
722
748
}
723
749
}
724
750
0 commit comments