@@ -122,7 +122,7 @@ impl<'tt> TokenTreeOrTokenTreeSlice<'tt> {
122122
123123/// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
124124///
125- /// This is used by `inner_parse_loop ` to keep track of delimited submatchers that we have
125+ /// This is used by `parse_tt_inner ` to keep track of delimited submatchers that we have
126126/// descended into.
127127#[ derive( Clone ) ]
128128struct MatcherTtFrame < ' tt > {
@@ -439,9 +439,8 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
439439 }
440440 Occupied ( ..) => return Err ( ( sp, format ! ( "duplicated bind name: {}" , bind_name) ) ) ,
441441 } ,
442- // FIXME(c410-f3r) MetaVar and MetaVarExpr should be handled instead of being ignored
443- // https://github.com/rust-lang/rust/issues/9390
444- TokenTree :: MetaVar ( ..) | TokenTree :: MetaVarExpr ( ..) | TokenTree :: Token ( ..) => { }
442+ TokenTree :: Token ( ..) => ( ) ,
443+ TokenTree :: MetaVar ( ..) | TokenTree :: MetaVarExpr ( ..) => unreachable ! ( ) ,
445444 }
446445
447446 Ok ( ( ) )
@@ -481,21 +480,24 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
481480/// successful execution of this function.
482481/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
483482/// the function `parse`.
484- /// - `eof_items`: the set of items that would be valid if this was the EOF.
485483/// - `bb_items`: the set of items that are waiting for the black-box parser.
486484/// - `token`: the current token of the parser.
487485///
488486/// # Returns
489487///
490- /// A `ParseResult`. Note that matches are kept track of through the items generated.
491- fn inner_parse_loop < ' root , ' tt > (
488+ /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept track of
489+ /// through the items generated.
490+ fn parse_tt_inner < ' root , ' tt > (
492491 sess : & ParseSess ,
492+ ms : & [ TokenTree ] ,
493493 cur_items : & mut SmallVec < [ MatcherPosHandle < ' root , ' tt > ; 1 ] > ,
494- next_items : & mut Vec < MatcherPosHandle < ' root , ' tt > > ,
494+ next_items : & mut SmallVec < [ MatcherPosHandle < ' root , ' tt > ; 1 ] > ,
495495 bb_items : & mut SmallVec < [ MatcherPosHandle < ' root , ' tt > ; 1 ] > ,
496- eof_items : & mut EofItems < ' root , ' tt > ,
497496 token : & Token ,
498- ) -> Result < ( ) , ( rustc_span:: Span , String ) > {
497+ ) -> Option < NamedParseResult > {
498+ // Matcher positions that would be valid if the macro invocation was over now
499+ let mut eof_items = EofItems :: None ;
500+
499501 // Pop items from `cur_items` until it is empty.
500502 while let Some ( mut item) = cur_items. pop ( ) {
501503 // When unzipped trees end, remove them. This corresponds to backtracking out of a
@@ -522,6 +524,8 @@ fn inner_parse_loop<'root, 'tt>(
522524 // then we could be at the end of a sequence or at the beginning of the next
523525 // repetition.
524526 if let Some ( repetition) = & item. repetition {
527+ debug_assert ! ( matches!( item. top_elts, Tt ( TokenTree :: Sequence ( ..) ) ) ) ;
528+
525529 // At this point, regardless of whether there is a separator, we should add all
526530 // matches from the complete repetition of the sequence to the shared, top-level
527531 // `matches` list (actually, `up.matches`, which could itself not be the top-level,
@@ -565,7 +569,7 @@ fn inner_parse_loop<'root, 'tt>(
565569 } else {
566570 // If we are not in a repetition, then being at the end of a matcher means that we
567571 // have reached the potential end of the input.
568- * eof_items = match eof_items {
572+ eof_items = match eof_items {
569573 EofItems :: None => EofItems :: One ( item) ,
570574 EofItems :: One ( _) | EofItems :: Multiple => EofItems :: Multiple ,
571575 }
@@ -613,7 +617,7 @@ fn inner_parse_loop<'root, 'tt>(
613617 // We need to match a metavar (but the identifier is invalid)... this is an error
614618 TokenTree :: MetaVarDecl ( span, _, None ) => {
615619 if sess. missing_fragment_specifiers . borrow_mut ( ) . remove ( & span) . is_some ( ) {
616- return Err ( ( span, "missing fragment specifier" . to_string ( ) ) ) ;
620+ return Some ( Error ( span, "missing fragment specifier" . to_string ( ) ) ) ;
617621 }
618622 }
619623
@@ -655,13 +659,36 @@ fn inner_parse_loop<'root, 'tt>(
655659 // rules. NOTE that this is not necessarily an error unless _all_ items in
656660 // `cur_items` end up doing this. There may still be some other matchers that do
657661 // end up working out.
658- TokenTree :: Token ( ..) | TokenTree :: MetaVar ( ..) | TokenTree :: MetaVarExpr ( ..) => { }
662+ TokenTree :: Token ( ..) => { }
663+
664+ TokenTree :: MetaVar ( ..) | TokenTree :: MetaVarExpr ( ..) => unreachable ! ( ) ,
659665 }
660666 }
661667 }
662668
663- // Yay a successful parse (so far)!
664- Ok ( ( ) )
669+ // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
670+ // either the parse is ambiguous (which should never happen) or there is a syntax error.
671+ if * token == token:: Eof {
672+ Some ( match eof_items {
673+ EofItems :: One ( mut eof_item) => {
674+ let matches =
675+ eof_item. matches . iter_mut ( ) . map ( |dv| Lrc :: make_mut ( dv) . pop ( ) . unwrap ( ) ) ;
676+ nameize ( sess, ms, matches)
677+ }
678+ EofItems :: Multiple => {
679+ Error ( token. span , "ambiguity: multiple successful parses" . to_string ( ) )
680+ }
681+ EofItems :: None => Failure (
682+ Token :: new (
683+ token:: Eof ,
684+ if token. span . is_dummy ( ) { token. span } else { token. span . shrink_to_hi ( ) } ,
685+ ) ,
686+ "missing tokens in macro arguments" ,
687+ ) ,
688+ } )
689+ } else {
690+ None
691+ }
665692}
666693
667694/// Use the given sequence of token trees (`ms`) as a matcher. Match the token
@@ -672,7 +699,7 @@ pub(super) fn parse_tt(
672699 macro_name : Ident ,
673700) -> NamedParseResult {
674701 // A queue of possible matcher positions. We initialize it with the matcher position in which
675- // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop ` then
702+ // the "dot" is before the first token of the first token tree in `ms`. `parse_tt_inner ` then
676703 // processes all of these possible matcher positions and produces possible next positions into
677704 // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
678705 // and we start over again.
@@ -681,135 +708,118 @@ pub(super) fn parse_tt(
681708 // there are frequently *no* others! -- are allocated on the heap.
682709 let mut initial = MatcherPos :: new ( ms) ;
683710 let mut cur_items = smallvec ! [ MatcherPosHandle :: Ref ( & mut initial) ] ;
684- let mut next_items = Vec :: new ( ) ;
685711
686712 loop {
687- assert ! ( next_items. is_empty ( ) ) ;
713+ let mut next_items = SmallVec :: new ( ) ;
688714
689715 // Matcher positions black-box parsed by parser.rs (`parser`)
690716 let mut bb_items = SmallVec :: new ( ) ;
691717
692- // Matcher positions that would be valid if the macro invocation was over now
693- let mut eof_items = EofItems :: None ;
694-
695718 // Process `cur_items` until either we have finished the input or we need to get some
696719 // parsing from the black-box parser done. The result is that `next_items` will contain a
697720 // bunch of possible next matcher positions in `next_items`.
698- match inner_parse_loop (
721+ if let Some ( result ) = parse_tt_inner (
699722 parser. sess ,
723+ ms,
700724 & mut cur_items,
701725 & mut next_items,
702726 & mut bb_items,
703- & mut eof_items,
704727 & parser. token ,
705728 ) {
706- Ok ( ( ) ) => { }
707- Err ( ( sp, msg) ) => return Error ( sp, msg) ,
729+ return result;
708730 }
709731
710- // inner parse loop handled all cur_items, so it's empty
732+ // `parse_tt_inner` handled all cur_items, so it's empty.
711733 assert ! ( cur_items. is_empty( ) ) ;
712734
713- // We need to do some post processing after the `inner_parse_loop `.
735+ // We need to do some post processing after the `parse_tt_inner `.
714736 //
715737 // Error messages here could be improved with links to original rules.
716738
717- // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
718- // either the parse is ambiguous (which should never happen) or there is a syntax error.
719- if parser. token == token:: Eof {
720- return match eof_items {
721- EofItems :: One ( mut eof_item) => {
722- let matches =
723- eof_item. matches . iter_mut ( ) . map ( |dv| Lrc :: make_mut ( dv) . pop ( ) . unwrap ( ) ) ;
724- nameize ( parser. sess , ms, matches)
725- }
726- EofItems :: Multiple => {
727- Error ( parser. token . span , "ambiguity: multiple successful parses" . to_string ( ) )
728- }
729- EofItems :: None => Failure (
730- Token :: new (
731- token:: Eof ,
732- if parser. token . span . is_dummy ( ) {
733- parser. token . span
734- } else {
735- parser. token . span . shrink_to_hi ( )
736- } ,
737- ) ,
738- "missing tokens in macro arguments" ,
739- ) ,
740- } ;
741- }
742- // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
743- // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
744- // unnecessary implicit clone later in `Rc::make_mut`.
745- drop ( eof_items) ;
746-
747- // If there are no possible next positions AND we aren't waiting for the black-box parser,
748- // then there is a syntax error.
749- if bb_items. is_empty ( ) && next_items. is_empty ( ) {
750- return Failure ( parser. token . clone ( ) , "no rules expected this token in macro call" ) ;
751- }
739+ match ( next_items. len ( ) , bb_items. len ( ) ) {
740+ ( 0 , 0 ) => {
741+ // There are no possible next positions AND we aren't waiting for the black-box
742+ // parser: syntax error.
743+ return Failure ( parser. token . clone ( ) , "no rules expected this token in macro call" ) ;
744+ }
752745
753- if ( !bb_items. is_empty ( ) && !next_items. is_empty ( ) ) || bb_items. len ( ) > 1 {
754- // We need to call out to parse some rust nonterminal (black-box) parser. But something
755- // is wrong, because there is not EXACTLY ONE of these.
756- let nts = bb_items
757- . iter ( )
758- . map ( |item| match item. top_elts . get_tt ( item. idx ) {
759- TokenTree :: MetaVarDecl ( _, bind, Some ( kind) ) => format ! ( "{} ('{}')" , kind, bind) ,
760- _ => panic ! ( ) ,
761- } )
762- . collect :: < Vec < String > > ( )
763- . join ( " or " ) ;
764-
765- return Error (
766- parser. token . span ,
767- format ! (
768- "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}" ,
769- match next_items. len( ) {
770- 0 => format!( "built-in NTs {}." , nts) ,
771- 1 => format!( "built-in NTs {} or 1 other option." , nts) ,
772- n => format!( "built-in NTs {} or {} other options." , nts, n) ,
773- }
774- ) ,
775- ) ;
776- }
746+ ( _, 0 ) => {
747+ // Dump all possible `next_items` into `cur_items` for the next iteration. Then
748+ // process the next token.
749+ cur_items. extend ( next_items. drain ( ..) ) ;
750+ parser. to_mut ( ) . bump ( ) ;
751+ }
777752
778- if !next_items. is_empty ( ) {
779- // Dump all possible `next_items` into `cur_items` for the next iteration. Then process
780- // the next token.
781- cur_items. extend ( next_items. drain ( ..) ) ;
782- parser. to_mut ( ) . bump ( ) ;
783- } else {
784- // Finally, we have the case where we need to call the black-box parser to get some
785- // nonterminal.
786- assert_eq ! ( bb_items. len( ) , 1 ) ;
787-
788- let mut item = bb_items. pop ( ) . unwrap ( ) ;
789- if let TokenTree :: MetaVarDecl ( span, _, Some ( kind) ) = item. top_elts . get_tt ( item. idx ) {
790- let match_cur = item. match_cur ;
791- // We use the span of the metavariable declaration to determine any
792- // edition-specific matching behavior for non-terminals.
793- let nt = match parser. to_mut ( ) . parse_nonterminal ( kind) {
794- Err ( mut err) => {
795- err. span_label (
796- span,
797- format ! ( "while parsing argument for this `{}` macro fragment" , kind) ,
798- )
799- . emit ( ) ;
800- return ErrorReported ;
801- }
802- Ok ( nt) => nt,
803- } ;
804- item. push_match ( match_cur, MatchedNonterminal ( Lrc :: new ( nt) ) ) ;
805- item. idx += 1 ;
806- item. match_cur += 1 ;
807- } else {
808- unreachable ! ( )
753+ ( 0 , 1 ) => {
754+ // We need to call the black-box parser to get some nonterminal.
755+ let mut item = bb_items. pop ( ) . unwrap ( ) ;
756+ if let TokenTree :: MetaVarDecl ( span, _, Some ( kind) ) = item. top_elts . get_tt ( item. idx )
757+ {
758+ let match_cur = item. match_cur ;
759+ // We use the span of the metavariable declaration to determine any
760+ // edition-specific matching behavior for non-terminals.
761+ let nt = match parser. to_mut ( ) . parse_nonterminal ( kind) {
762+ Err ( mut err) => {
763+ err. span_label (
764+ span,
765+ format ! ( "while parsing argument for this `{kind}` macro fragment" ) ,
766+ )
767+ . emit ( ) ;
768+ return ErrorReported ;
769+ }
770+ Ok ( nt) => nt,
771+ } ;
772+ item. push_match ( match_cur, MatchedNonterminal ( Lrc :: new ( nt) ) ) ;
773+ item. idx += 1 ;
774+ item. match_cur += 1 ;
775+ } else {
776+ unreachable ! ( )
777+ }
778+ cur_items. push ( item) ;
779+ }
780+
781+ ( _, _) => {
782+ // We need to call the black-box parser to get some nonterminal, but something is
783+ // wrong.
784+ return bb_items_ambiguity_error (
785+ macro_name,
786+ next_items,
787+ bb_items,
788+ parser. token . span ,
789+ ) ;
809790 }
810- cur_items. push ( item) ;
811791 }
812792
813793 assert ! ( !cur_items. is_empty( ) ) ;
814794 }
815795}
796+
797+ fn bb_items_ambiguity_error < ' root , ' tt > (
798+ macro_name : Ident ,
799+ next_items : SmallVec < [ MatcherPosHandle < ' root , ' tt > ; 1 ] > ,
800+ bb_items : SmallVec < [ MatcherPosHandle < ' root , ' tt > ; 1 ] > ,
801+ token_span : rustc_span:: Span ,
802+ ) -> NamedParseResult {
803+ let nts = bb_items
804+ . iter ( )
805+ . map ( |item| match item. top_elts . get_tt ( item. idx ) {
806+ TokenTree :: MetaVarDecl ( _, bind, Some ( kind) ) => {
807+ format ! ( "{} ('{}')" , kind, bind)
808+ }
809+ _ => panic ! ( ) ,
810+ } )
811+ . collect :: < Vec < String > > ( )
812+ . join ( " or " ) ;
813+
814+ Error (
815+ token_span,
816+ format ! (
817+ "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}" ,
818+ match next_items. len( ) {
819+ 0 => format!( "built-in NTs {}." , nts) ,
820+ 1 => format!( "built-in NTs {} or 1 other option." , nts) ,
821+ n => format!( "built-in NTs {} or {} other options." , nts, n) ,
822+ }
823+ ) ,
824+ )
825+ }
0 commit comments