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