8
8
use crate :: html:: escape:: Escape ;
9
9
use crate :: html:: render:: Context ;
10
10
11
+ use std:: collections:: VecDeque ;
11
12
use std:: fmt:: { Display , Write } ;
12
- use std:: iter:: Peekable ;
13
13
14
14
use rustc_lexer:: { LiteralKind , TokenKind } ;
15
15
use rustc_span:: edition:: Edition ;
@@ -199,10 +199,57 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
199
199
} )
200
200
}
201
201
202
+ /// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than
203
+ /// just the next item by using `peek_next`. The `peek` method always returns the next item after
204
+ /// the current one whereas `peek_next` will return the next item after the last one peeked.
205
+ ///
206
+ /// You can use both `peek` and `peek_next` at the same time without problem.
207
+ struct PeekIter < ' a > {
208
+ stored : VecDeque < ( TokenKind , & ' a str ) > ,
209
+ /// This position is reinitialized when using `next`. It is used in `peek_next`.
210
+ peek_pos : usize ,
211
+ iter : TokenIter < ' a > ,
212
+ }
213
+
214
+ impl PeekIter < ' a > {
215
+ fn new ( iter : TokenIter < ' a > ) -> Self {
216
+ Self { stored : VecDeque :: new ( ) , peek_pos : 0 , iter }
217
+ }
218
+ /// Returns the next item after the current one. It doesn't interfer with `peek_next` output.
219
+ fn peek ( & mut self ) -> Option < & ( TokenKind , & ' a str ) > {
220
+ if self . stored . is_empty ( ) {
221
+ if let Some ( next) = self . iter . next ( ) {
222
+ self . stored . push_back ( next) ;
223
+ }
224
+ }
225
+ self . stored . front ( )
226
+ }
227
+ /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output.
228
+ fn peek_next ( & mut self ) -> Option < & ( TokenKind , & ' a str ) > {
229
+ self . peek_pos += 1 ;
230
+ if self . peek_pos - 1 < self . stored . len ( ) {
231
+ self . stored . get ( self . peek_pos - 1 )
232
+ } else if let Some ( next) = self . iter . next ( ) {
233
+ self . stored . push_back ( next) ;
234
+ self . stored . back ( )
235
+ } else {
236
+ None
237
+ }
238
+ }
239
+ }
240
+
241
+ impl Iterator for PeekIter < ' a > {
242
+ type Item = ( TokenKind , & ' a str ) ;
243
+ fn next ( & mut self ) -> Option < Self :: Item > {
244
+ self . peek_pos = 0 ;
245
+ if let Some ( first) = self . stored . pop_front ( ) { Some ( first) } else { self . iter . next ( ) }
246
+ }
247
+ }
248
+
202
249
/// Processes program tokens, classifying strings of text by highlighting
203
250
/// category (`Class`).
204
251
struct Classifier < ' a > {
205
- tokens : Peekable < TokenIter < ' a > > ,
252
+ tokens : PeekIter < ' a > ,
206
253
in_attribute : bool ,
207
254
in_macro : bool ,
208
255
in_macro_nonterminal : bool ,
@@ -216,7 +263,7 @@ impl<'a> Classifier<'a> {
216
263
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
217
264
/// file span which will be used later on by the `span_correspondance_map`.
218
265
fn new ( src : & str , edition : Edition , file_span : Span ) -> Classifier < ' _ > {
219
- let tokens = TokenIter { src } . peekable ( ) ;
266
+ let tokens = PeekIter :: new ( TokenIter { src } ) ;
220
267
Classifier {
221
268
tokens,
222
269
in_attribute : false ,
@@ -367,7 +414,7 @@ impl<'a> Classifier<'a> {
367
414
// Assume that '&' or '*' is the reference or dereference operator
368
415
// or a reference or pointer type. Unless, of course, it looks like
369
416
// a logical and or a multiplication operator: `&&` or `* `.
370
- TokenKind :: Star => match lookahead {
417
+ TokenKind :: Star => match self . peek ( ) {
371
418
Some ( TokenKind :: Whitespace ) => Class :: Op ,
372
419
_ => Class :: RefKeyWord ,
373
420
} ,
@@ -478,6 +525,9 @@ impl<'a> Classifier<'a> {
478
525
None => match text {
479
526
"Option" | "Result" => Class :: PreludeTy ,
480
527
"Some" | "None" | "Ok" | "Err" => Class :: PreludeVal ,
528
+ // "union" is a weak keyword and is only considered as a keyword when declaring
529
+ // a union type.
530
+ "union" if self . check_if_is_union_keyword ( ) => Class :: KeyWord ,
481
531
_ if self . in_macro_nonterminal => {
482
532
self . in_macro_nonterminal = false ;
483
533
Class :: MacroNonTerminal
@@ -498,7 +548,17 @@ impl<'a> Classifier<'a> {
498
548
}
499
549
500
550
fn peek ( & mut self ) -> Option < TokenKind > {
501
- self . tokens . peek ( ) . map ( |( toke_kind, _text) | * toke_kind)
551
+ self . tokens . peek ( ) . map ( |( token_kind, _text) | * token_kind)
552
+ }
553
+
554
+ fn check_if_is_union_keyword ( & mut self ) -> bool {
555
+ while let Some ( kind) = self . tokens . peek_next ( ) . map ( |( token_kind, _text) | token_kind) {
556
+ if * kind == TokenKind :: Whitespace {
557
+ continue ;
558
+ }
559
+ return * kind == TokenKind :: Ident ;
560
+ }
561
+ false
502
562
}
503
563
}
504
564
0 commit comments