@@ -68,7 +68,7 @@ use crate::{
6868 expander:: { Binding , Bindings , ExpandResult , Fragment } ,
6969 parser:: { MetaVarKind , Op , RepeatKind , Separator } ,
7070 tt_iter:: TtIter ,
71- ExpandError , MetaTemplate ,
71+ ExpandError , MetaTemplate , ValueResult ,
7272} ;
7373
7474impl Bindings {
@@ -500,18 +500,69 @@ fn match_loop_inner<'t>(
500500 }
501501 }
502502 }
503- OpDelimited :: Op ( Op :: Leaf ( leaf) ) => {
504- if let Err ( err) = match_leaf ( leaf, & mut src. clone ( ) ) {
505- res. add_err ( err) ;
503+ OpDelimited :: Op ( Op :: Literal ( lhs) ) => {
504+ if let Ok ( rhs) = src. clone ( ) . expect_leaf ( ) {
505+ if matches ! ( rhs, tt:: Leaf :: Literal ( it) if it. text == lhs. text) {
506+ item. dot . next ( ) ;
507+ } else {
508+ res. add_err ( ExpandError :: UnexpectedToken ) ;
509+ item. is_error = true ;
510+ }
511+ } else {
512+ res. add_err ( ExpandError :: binding_error ( format ! ( "expected literal: `{lhs}`" ) ) ) ;
506513 item. is_error = true ;
514+ }
515+ try_push ! ( next_items, item) ;
516+ }
517+ OpDelimited :: Op ( Op :: Ident ( lhs) ) => {
518+ if let Ok ( rhs) = src. clone ( ) . expect_leaf ( ) {
519+ if matches ! ( rhs, tt:: Leaf :: Ident ( it) if it. text == lhs. text) {
520+ item. dot . next ( ) ;
521+ } else {
522+ res. add_err ( ExpandError :: UnexpectedToken ) ;
523+ item. is_error = true ;
524+ }
507525 } else {
508- item. dot . next ( ) ;
526+ res. add_err ( ExpandError :: binding_error ( format ! ( "expected ident: `{lhs}`" ) ) ) ;
527+ item. is_error = true ;
509528 }
510529 try_push ! ( next_items, item) ;
511530 }
531+ OpDelimited :: Op ( Op :: Punct ( lhs) ) => {
532+ let mut fork = src. clone ( ) ;
533+ let error = if let Ok ( rhs) = fork. expect_glued_punct ( ) {
534+ let first_is_single_quote = rhs[ 0 ] . char == '\'' ;
535+ let lhs = lhs. iter ( ) . map ( |it| it. char ) ;
536+ let rhs = rhs. iter ( ) . map ( |it| it. char ) ;
537+ if lhs. clone ( ) . eq ( rhs) {
538+ // HACK: here we use `meta_result` to pass `TtIter` back to caller because
539+ // it might have been advanced multiple times. `ValueResult` is
540+ // insignificant.
541+ item. meta_result = Some ( ( fork, ValueResult :: ok ( None ) ) ) ;
542+ item. dot . next ( ) ;
543+ next_items. push ( item) ;
544+ continue ;
545+ }
546+
547+ if first_is_single_quote {
548+ // If the first punct token is a single quote, that's a part of a lifetime
549+ // ident, not a punct.
550+ ExpandError :: UnexpectedToken
551+ } else {
552+ let lhs: SmolStr = lhs. collect ( ) ;
553+ ExpandError :: binding_error ( format ! ( "expected punct: `{lhs}`" ) )
554+ }
555+ } else {
556+ ExpandError :: UnexpectedToken
557+ } ;
558+
559+ res. add_err ( error) ;
560+ item. is_error = true ;
561+ error_items. push ( item) ;
562+ }
512563 OpDelimited :: Op ( Op :: Ignore { .. } | Op :: Index { .. } ) => { }
513564 OpDelimited :: Open => {
514- if matches ! ( src. clone ( ) . next ( ) , Some ( tt:: TokenTree :: Subtree ( ..) ) ) {
565+ if matches ! ( src. peek_n ( 0 ) , Some ( tt:: TokenTree :: Subtree ( ..) ) ) {
515566 item. dot . next ( ) ;
516567 try_push ! ( next_items, item) ;
517568 }
@@ -616,21 +667,33 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
616667 }
617668 // Dump all possible `next_items` into `cur_items` for the next iteration.
618669 else if !next_items. is_empty ( ) {
619- // Now process the next token
620- cur_items. extend ( next_items. drain ( ..) ) ;
621-
622- match src. next ( ) {
623- Some ( tt:: TokenTree :: Subtree ( subtree) ) => {
624- stack. push ( src. clone ( ) ) ;
625- src = TtIter :: new ( subtree) ;
670+ if let Some ( ( iter, _) ) = next_items[ 0 ] . meta_result . take ( ) {
671+ // We've matched a possibly "glued" punct. The matched punct (hence
672+ // `meta_result` also) must be the same for all items.
673+ // FIXME: If there are multiple items, it's definitely redundant (and it's hacky!
674+ // `meta_result` isn't supposed to be used this way).
675+
676+ // We already bumped, so no need to call `.next()` like in the other branch.
677+ src = iter;
678+ for item in next_items. iter_mut ( ) {
679+ item. meta_result = None ;
626680 }
627- None => {
628- if let Some ( iter) = stack. pop ( ) {
629- src = iter;
681+ } else {
682+ match src. next ( ) {
683+ Some ( tt:: TokenTree :: Subtree ( subtree) ) => {
684+ stack. push ( src. clone ( ) ) ;
685+ src = TtIter :: new ( subtree) ;
686+ }
687+ None => {
688+ if let Some ( iter) = stack. pop ( ) {
689+ src = iter;
690+ }
630691 }
692+ _ => ( ) ,
631693 }
632- _ => ( ) ,
633694 }
695+ // Now process the next token
696+ cur_items. extend ( next_items. drain ( ..) ) ;
634697 }
635698 // Finally, we have the case where we need to call the black-box parser to get some
636699 // nonterminal.
@@ -663,27 +726,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
663726 }
664727}
665728
666- fn match_leaf ( lhs : & tt:: Leaf , src : & mut TtIter < ' _ > ) -> Result < ( ) , ExpandError > {
667- let rhs = src
668- . expect_leaf ( )
669- . map_err ( |( ) | ExpandError :: binding_error ( format ! ( "expected leaf: `{lhs}`" ) ) ) ?;
670- match ( lhs, rhs) {
671- (
672- tt:: Leaf :: Punct ( tt:: Punct { char : lhs, .. } ) ,
673- tt:: Leaf :: Punct ( tt:: Punct { char : rhs, .. } ) ,
674- ) if lhs == rhs => Ok ( ( ) ) ,
675- (
676- tt:: Leaf :: Ident ( tt:: Ident { text : lhs, .. } ) ,
677- tt:: Leaf :: Ident ( tt:: Ident { text : rhs, .. } ) ,
678- ) if lhs == rhs => Ok ( ( ) ) ,
679- (
680- tt:: Leaf :: Literal ( tt:: Literal { text : lhs, .. } ) ,
681- tt:: Leaf :: Literal ( tt:: Literal { text : rhs, .. } ) ,
682- ) if lhs == rhs => Ok ( ( ) ) ,
683- _ => Err ( ExpandError :: UnexpectedToken ) ,
684- }
685- }
686-
687729fn match_meta_var ( kind : MetaVarKind , input : & mut TtIter < ' _ > ) -> ExpandResult < Option < Fragment > > {
688730 let fragment = match kind {
689731 MetaVarKind :: Path => parser:: PrefixEntryPoint :: Path ,
@@ -756,10 +798,10 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate)
756798 for op in pattern. iter ( ) {
757799 match op {
758800 Op :: Var { name, .. } => collector_fun ( name. clone ( ) ) ,
759- Op :: Leaf ( _) => ( ) ,
760801 Op :: Subtree { tokens, .. } => collect_vars ( collector_fun, tokens) ,
761802 Op :: Repeat { tokens, .. } => collect_vars ( collector_fun, tokens) ,
762- Op :: Ignore { .. } | Op :: Index { .. } => { }
803+ Op :: Ignore { .. } | Op :: Index { .. } | Op :: Literal ( _) | Op :: Ident ( _) | Op :: Punct ( _) => {
804+ }
763805 }
764806 }
765807}
0 commit comments