@@ -789,6 +789,9 @@ impl<'a> Iterator for TokenIter<'a> {
789789 }
790790}
791791
792+ /// Used to know if a keyword followed by a `!` should never be treated as a macro.
793+ const NON_MACRO_KEYWORDS : & [ & str ] = & [ "if" , "while" , "match" , "break" , "return" , "impl" ] ;
794+
792795/// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than
793796/// just the next item by using `peek_next`. The `peek` method always returns the next item after
794797/// the current one whereas `peek_next` will return the next item after the last one peeked.
@@ -1010,6 +1013,19 @@ impl<'src> Classifier<'src> {
10101013 }
10111014 }
10121015
1016+ fn new_macro_span (
1017+ & mut self ,
1018+ text : & ' src str ,
1019+ sink : & mut dyn FnMut ( Span , Highlight < ' src > ) ,
1020+ before : u32 ,
1021+ file_span : Span ,
1022+ ) {
1023+ self . in_macro = true ;
1024+ let span = new_span ( before, text, file_span) ;
1025+ sink ( DUMMY_SP , Highlight :: EnterSpan { class : Class :: Macro ( span) } ) ;
1026+ sink ( span, Highlight :: Token { text, class : None } ) ;
1027+ }
1028+
10131029 /// Single step of highlighting. This will classify `token`, but maybe also a couple of
10141030 /// following ones as well.
10151031 ///
@@ -1216,16 +1232,46 @@ impl<'src> Classifier<'src> {
12161232 LiteralKind :: Float { .. } | LiteralKind :: Int { .. } => Class :: Number ,
12171233 } ,
12181234 TokenKind :: GuardedStrPrefix => return no_highlight ( sink) ,
1219- TokenKind :: Ident | TokenKind :: RawIdent
1220- if let Some ( ( TokenKind :: Bang , _) ) = self . peek_non_trivia ( ) =>
1221- {
1222- self . in_macro = true ;
1223- let span = new_span ( before, text, file_span) ;
1224- sink ( DUMMY_SP , Highlight :: EnterSpan { class : Class :: Macro ( span) } ) ;
1225- sink ( span, Highlight :: Token { text, class : None } ) ;
1235+ TokenKind :: RawIdent if let Some ( ( TokenKind :: Bang , _) ) = self . peek_non_trivia ( ) => {
1236+ self . new_macro_span ( text, sink, before, file_span) ;
12261237 return ;
12271238 }
1228- TokenKind :: Ident => self . classify_ident ( before, text) ,
1239+ // Macro non-terminals (meta vars) take precedence.
1240+ TokenKind :: Ident if self . in_macro_nonterminal => {
1241+ self . in_macro_nonterminal = false ;
1242+ Class :: MacroNonTerminal
1243+ }
1244+ TokenKind :: Ident => {
1245+ let file_span = self . file_span ;
1246+ let span = || new_span ( before, text, file_span) ;
1247+
1248+ match text {
1249+ "ref" | "mut" => Class :: RefKeyWord ,
1250+ "false" | "true" => Class :: Bool ,
1251+ "self" | "Self" => Class :: Self_ ( span ( ) ) ,
1252+ "Option" | "Result" => Class :: PreludeTy ( span ( ) ) ,
1253+ "Some" | "None" | "Ok" | "Err" => Class :: PreludeVal ( span ( ) ) ,
1254+ _ if self . is_weak_keyword ( text) || is_keyword ( Symbol :: intern ( text) ) => {
1255+ // So if it's not a keyword which can be followed by a value (like `if` or
1256+ // `return`) and the next non-whitespace token is a `!`, then we consider
1257+ // it's a macro.
1258+ if !NON_MACRO_KEYWORDS . contains ( & text)
1259+ && matches ! ( self . peek_non_trivia( ) , Some ( ( TokenKind :: Bang , _) ) )
1260+ {
1261+ self . new_macro_span ( text, sink, before, file_span) ;
1262+ return ;
1263+ }
1264+ Class :: KeyWord
1265+ }
1266+ // If it's not a keyword and the next non whitespace token is a `!`, then
1267+ // we consider it's a macro.
1268+ _ if matches ! ( self . peek_non_trivia( ) , Some ( ( TokenKind :: Bang , _) ) ) => {
1269+ self . new_macro_span ( text, sink, before, file_span) ;
1270+ return ;
1271+ }
1272+ _ => Class :: Ident ( span ( ) ) ,
1273+ }
1274+ }
12291275 TokenKind :: RawIdent | TokenKind :: UnknownPrefix | TokenKind :: InvalidIdent => {
12301276 Class :: Ident ( new_span ( before, text, file_span) )
12311277 }
@@ -1246,27 +1292,6 @@ impl<'src> Classifier<'src> {
12461292 }
12471293 }
12481294
1249- fn classify_ident ( & mut self , before : u32 , text : & ' src str ) -> Class {
1250- // Macro non-terminals (meta vars) take precedence.
1251- if self . in_macro_nonterminal {
1252- self . in_macro_nonterminal = false ;
1253- return Class :: MacroNonTerminal ;
1254- }
1255-
1256- let file_span = self . file_span ;
1257- let span = || new_span ( before, text, file_span) ;
1258-
1259- match text {
1260- "ref" | "mut" => Class :: RefKeyWord ,
1261- "false" | "true" => Class :: Bool ,
1262- "self" | "Self" => Class :: Self_ ( span ( ) ) ,
1263- "Option" | "Result" => Class :: PreludeTy ( span ( ) ) ,
1264- "Some" | "None" | "Ok" | "Err" => Class :: PreludeVal ( span ( ) ) ,
1265- _ if self . is_weak_keyword ( text) || is_keyword ( Symbol :: intern ( text) ) => Class :: KeyWord ,
1266- _ => Class :: Ident ( span ( ) ) ,
1267- }
1268- }
1269-
12701295 fn is_weak_keyword ( & mut self , text : & str ) -> bool {
12711296 // NOTE: `yeet` (`do yeet $expr`), `catch` (`do catch $block`), `default` (specialization),
12721297 // `contract_{ensures,requires}`, `builtin` (builtin_syntax) & `reuse` (fn_delegation) are
0 commit comments