• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 pub use BinOpToken::*;
2 pub use LitKind::*;
3 pub use Nonterminal::*;
4 pub use TokenKind::*;
5 
6 use crate::ast;
7 use crate::ptr::P;
8 use crate::util::case::Case;
9 
10 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
11 use rustc_data_structures::sync::Lrc;
12 use rustc_macros::HashStable_Generic;
13 use rustc_span::symbol::{kw, sym};
14 #[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
15 use rustc_span::symbol::{Ident, Symbol};
16 use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
17 use std::borrow::Cow;
18 use std::fmt;
19 
20 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
21 pub enum CommentKind {
22     Line,
23     Block,
24 }
25 
26 #[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)]
27 #[derive(HashStable_Generic)]
28 pub enum BinOpToken {
29     Plus,
30     Minus,
31     Star,
32     Slash,
33     Percent,
34     Caret,
35     And,
36     Or,
37     Shl,
38     Shr,
39 }
40 
41 /// Describes how a sequence of token trees is delimited.
42 /// Cannot use `proc_macro::Delimiter` directly because this
43 /// structure should implement some additional traits.
44 /// The `None` variant is also renamed to `Invisible` to be
45 /// less confusing and better convey the semantics.
46 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
47 #[derive(Encodable, Decodable, Hash, HashStable_Generic)]
48 pub enum Delimiter {
49     /// `( ... )`
50     Parenthesis,
51     /// `{ ... }`
52     Brace,
53     /// `[ ... ]`
54     Bracket,
55     /// `Ø ... Ø`
56     /// An invisible delimiter, that may, for example, appear around tokens coming from a
57     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
58     /// `$var * 3` where `$var` is `1 + 2`.
59     /// Invisible delimiters might not survive roundtrip of a token stream through a string.
60     Invisible,
61 }
62 
63 // Note that the suffix is *not* considered when deciding the `LitKind` in this
64 // type. This means that float literals like `1f32` are classified by this type
65 // as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
66 // given the `Float` kind.
67 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
68 pub enum LitKind {
69     Bool, // AST only, must never appear in a `Token`
70     Byte,
71     Char,
72     Integer, // e.g. `1`, `1u8`, `1f32`
73     Float,   // e.g. `1.`, `1.0`, `1e3f32`
74     Str,
75     StrRaw(u8), // raw string delimited by `n` hash symbols
76     ByteStr,
77     ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
78     CStr,
79     CStrRaw(u8),
80     Err,
81 }
82 
83 /// A literal token.
84 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
85 pub struct Lit {
86     pub kind: LitKind,
87     pub symbol: Symbol,
88     pub suffix: Option<Symbol>,
89 }
90 
91 impl Lit {
new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit92     pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
93         Lit { kind, symbol, suffix }
94     }
95 
96     /// Returns `true` if this is semantically a float literal. This includes
97     /// ones like `1f32` that have an `Integer` kind but a float suffix.
is_semantic_float(&self) -> bool98     pub fn is_semantic_float(&self) -> bool {
99         match self.kind {
100             LitKind::Float => true,
101             LitKind::Integer => match self.suffix {
102                 Some(sym) => sym == sym::f32 || sym == sym::f64,
103                 None => false,
104             },
105             _ => false,
106         }
107     }
108 
109     /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
from_token(token: &Token) -> Option<Lit>110     pub fn from_token(token: &Token) -> Option<Lit> {
111         match token.uninterpolate().kind {
112             Ident(name, false) if name.is_bool_lit() => {
113                 Some(Lit::new(Bool, name, None))
114             }
115             Literal(token_lit) => Some(token_lit),
116             Interpolated(ref nt)
117                 if let NtExpr(expr) | NtLiteral(expr) = &**nt
118                 && let ast::ExprKind::Lit(token_lit) = expr.kind =>
119             {
120                 Some(token_lit)
121             }
122             _ => None,
123         }
124     }
125 }
126 
127 impl fmt::Display for Lit {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result128     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129         let Lit { kind, symbol, suffix } = *self;
130         match kind {
131             Byte => write!(f, "b'{symbol}'")?,
132             Char => write!(f, "'{symbol}'")?,
133             Str => write!(f, "\"{symbol}\"")?,
134             StrRaw(n) => write!(
135                 f,
136                 "r{delim}\"{string}\"{delim}",
137                 delim = "#".repeat(n as usize),
138                 string = symbol
139             )?,
140             ByteStr => write!(f, "b\"{symbol}\"")?,
141             ByteStrRaw(n) => write!(
142                 f,
143                 "br{delim}\"{string}\"{delim}",
144                 delim = "#".repeat(n as usize),
145                 string = symbol
146             )?,
147             CStr => write!(f, "c\"{symbol}\"")?,
148             CStrRaw(n) => {
149                 write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
150             }
151             Integer | Float | Bool | Err => write!(f, "{symbol}")?,
152         }
153 
154         if let Some(suffix) = suffix {
155             write!(f, "{suffix}")?;
156         }
157 
158         Ok(())
159     }
160 }
161 
162 impl LitKind {
163     /// An English article for the literal token kind.
article(self) -> &'static str164     pub fn article(self) -> &'static str {
165         match self {
166             Integer | Err => "an",
167             _ => "a",
168         }
169     }
170 
descr(self) -> &'static str171     pub fn descr(self) -> &'static str {
172         match self {
173             Bool => panic!("literal token contains `Lit::Bool`"),
174             Byte => "byte",
175             Char => "char",
176             Integer => "integer",
177             Float => "float",
178             Str | StrRaw(..) => "string",
179             ByteStr | ByteStrRaw(..) => "byte string",
180             CStr | CStrRaw(..) => "C string",
181             Err => "error",
182         }
183     }
184 
may_have_suffix(self) -> bool185     pub(crate) fn may_have_suffix(self) -> bool {
186         matches!(self, Integer | Float | Err)
187     }
188 }
189 
ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool190 pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
191     let ident_token = Token::new(Ident(name, is_raw), span);
192 
193     !ident_token.is_reserved_ident()
194         || ident_token.is_path_segment_keyword()
195         || [
196             kw::Async,
197             kw::Do,
198             kw::Box,
199             kw::Break,
200             kw::Const,
201             kw::Continue,
202             kw::False,
203             kw::For,
204             kw::If,
205             kw::Let,
206             kw::Loop,
207             kw::Match,
208             kw::Move,
209             kw::Return,
210             kw::True,
211             kw::Try,
212             kw::Unsafe,
213             kw::While,
214             kw::Yield,
215             kw::Static,
216         ]
217         .contains(&name)
218 }
219 
ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool220 fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
221     let ident_token = Token::new(Ident(name, is_raw), span);
222 
223     !ident_token.is_reserved_ident()
224         || ident_token.is_path_segment_keyword()
225         || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn]
226             .contains(&name)
227 }
228 
229 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
230 pub enum TokenKind {
231     /* Expression-operator symbols. */
232     Eq,
233     Lt,
234     Le,
235     EqEq,
236     Ne,
237     Ge,
238     Gt,
239     AndAnd,
240     OrOr,
241     Not,
242     Tilde,
243     BinOp(BinOpToken),
244     BinOpEq(BinOpToken),
245 
246     /* Structural symbols */
247     At,
248     Dot,
249     DotDot,
250     DotDotDot,
251     DotDotEq,
252     Comma,
253     Semi,
254     Colon,
255     ModSep,
256     RArrow,
257     LArrow,
258     FatArrow,
259     Pound,
260     Dollar,
261     Question,
262     /// Used by proc macros for representing lifetimes, not generated by lexer right now.
263     SingleQuote,
264     /// An opening delimiter (e.g., `{`).
265     OpenDelim(Delimiter),
266     /// A closing delimiter (e.g., `}`).
267     CloseDelim(Delimiter),
268 
269     /* Literals */
270     Literal(Lit),
271 
272     /// Identifier token.
273     /// Do not forget about `NtIdent` when you want to match on identifiers.
274     /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
275     /// treat regular and interpolated identifiers in the same way.
276     Ident(Symbol, /* is_raw */ bool),
277     /// Lifetime identifier token.
278     /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
279     /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
280     /// treat regular and interpolated lifetime identifiers in the same way.
281     Lifetime(Symbol),
282 
283     /// An embedded AST node, as produced by a macro. This only exists for
284     /// historical reasons. We'd like to get rid of it, for multiple reasons.
285     /// - It's conceptually very strange. Saying a token can contain an AST
286     ///   node is like saying, in natural language, that a word can contain a
287     ///   sentence.
288     /// - It requires special handling in a bunch of places in the parser.
289     /// - It prevents `Token` from implementing `Copy`.
290     /// It adds complexity and likely slows things down. Please don't add new
291     /// occurrences of this token kind!
292     Interpolated(Lrc<Nonterminal>),
293 
294     /// A doc comment token.
295     /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
296     /// similarly to symbols in string literal tokens.
297     DocComment(CommentKind, ast::AttrStyle, Symbol),
298 
299     Eof,
300 }
301 
302 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
303 pub struct Token {
304     pub kind: TokenKind,
305     pub span: Span,
306 }
307 
308 impl TokenKind {
lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind309     pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
310         Literal(Lit::new(kind, symbol, suffix))
311     }
312 
313     /// An approximation to proc-macro-style single-character operators used by rustc parser.
314     /// If the operator token can be broken into two tokens, the first of which is single-character,
315     /// then this function performs that operation, otherwise it returns `None`.
break_two_token_op(&self) -> Option<(TokenKind, TokenKind)>316     pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
317         Some(match *self {
318             Le => (Lt, Eq),
319             EqEq => (Eq, Eq),
320             Ne => (Not, Eq),
321             Ge => (Gt, Eq),
322             AndAnd => (BinOp(And), BinOp(And)),
323             OrOr => (BinOp(Or), BinOp(Or)),
324             BinOp(Shl) => (Lt, Lt),
325             BinOp(Shr) => (Gt, Gt),
326             BinOpEq(Plus) => (BinOp(Plus), Eq),
327             BinOpEq(Minus) => (BinOp(Minus), Eq),
328             BinOpEq(Star) => (BinOp(Star), Eq),
329             BinOpEq(Slash) => (BinOp(Slash), Eq),
330             BinOpEq(Percent) => (BinOp(Percent), Eq),
331             BinOpEq(Caret) => (BinOp(Caret), Eq),
332             BinOpEq(And) => (BinOp(And), Eq),
333             BinOpEq(Or) => (BinOp(Or), Eq),
334             BinOpEq(Shl) => (Lt, Le),
335             BinOpEq(Shr) => (Gt, Ge),
336             DotDot => (Dot, Dot),
337             DotDotDot => (Dot, DotDot),
338             ModSep => (Colon, Colon),
339             RArrow => (BinOp(Minus), Gt),
340             LArrow => (Lt, BinOp(Minus)),
341             FatArrow => (Eq, Gt),
342             _ => return None,
343         })
344     }
345 
346     /// Returns tokens that are likely to be typed accidentally instead of the current token.
347     /// Enables better error recovery when the wrong token is found.
similar_tokens(&self) -> Option<Vec<TokenKind>>348     pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
349         match *self {
350             Comma => Some(vec![Dot, Lt, Semi]),
351             Semi => Some(vec![Colon, Comma]),
352             FatArrow => Some(vec![Eq, RArrow]),
353             _ => None,
354         }
355     }
356 
should_end_const_arg(&self) -> bool357     pub fn should_end_const_arg(&self) -> bool {
358         matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
359     }
360 }
361 
362 impl Token {
new(kind: TokenKind, span: Span) -> Self363     pub fn new(kind: TokenKind, span: Span) -> Self {
364         Token { kind, span }
365     }
366 
367     /// Some token that will be thrown away later.
dummy() -> Self368     pub fn dummy() -> Self {
369         Token::new(TokenKind::Question, DUMMY_SP)
370     }
371 
372     /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
from_ast_ident(ident: Ident) -> Self373     pub fn from_ast_ident(ident: Ident) -> Self {
374         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
375     }
376 
377     /// For interpolated tokens, returns a span of the fragment to which the interpolated
378     /// token refers. For all other tokens this is just a regular span.
379     /// It is particularly important to use this for identifiers and lifetimes
380     /// for which spans affect name resolution and edition checks.
381     /// Note that keywords are also identifiers, so they should use this
382     /// if they keep spans or perform edition checks.
uninterpolated_span(&self) -> Span383     pub fn uninterpolated_span(&self) -> Span {
384         match &self.kind {
385             Interpolated(nt) => nt.span(),
386             _ => self.span,
387         }
388     }
389 
is_range_separator(&self) -> bool390     pub fn is_range_separator(&self) -> bool {
391         [DotDot, DotDotDot, DotDotEq].contains(&self.kind)
392     }
393 
is_op(&self) -> bool394     pub fn is_op(&self) -> bool {
395         match self.kind {
396             Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
397             | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
398             | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
399 
400             OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
401             | Lifetime(..) | Interpolated(..) | Eof => false,
402         }
403     }
404 
is_like_plus(&self) -> bool405     pub fn is_like_plus(&self) -> bool {
406         matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
407     }
408 
409     /// Returns `true` if the token can appear at the start of an expression.
can_begin_expr(&self) -> bool410     pub fn can_begin_expr(&self) -> bool {
411         match self.uninterpolate().kind {
412             Ident(name, is_raw)              =>
413                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
414             OpenDelim(..)                     | // tuple, array or block
415             Literal(..)                       | // literal
416             Not                               | // operator not
417             BinOp(Minus)                      | // unary minus
418             BinOp(Star)                       | // dereference
419             BinOp(Or) | OrOr                  | // closure
420             BinOp(And)                        | // reference
421             AndAnd                            | // double reference
422             // DotDotDot is no longer supported, but we need some way to display the error
423             DotDot | DotDotDot | DotDotEq     | // range notation
424             Lt | BinOp(Shl)                   | // associated path
425             ModSep                            | // global path
426             Lifetime(..)                      | // labeled loop
427             Pound                             => true, // expression attributes
428             Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
429                 NtExpr(..)    |
430                 NtBlock(..)   |
431                 NtPath(..)),
432             _ => false,
433         }
434     }
435 
436     /// Returns `true` if the token can appear at the start of an pattern.
437     ///
438     /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
can_begin_pattern(&self) -> bool439     pub fn can_begin_pattern(&self) -> bool {
440         match self.uninterpolate().kind {
441             Ident(name, is_raw)              =>
442                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
443             | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis)  // tuple or array
444             | Literal(..)                        // literal
445             | BinOp(Minus)                       // unary minus
446             | BinOp(And)                         // reference
447             | AndAnd                             // double reference
448             // DotDotDot is no longer supported
449             | DotDot | DotDotDot | DotDotEq      // ranges
450             | Lt | BinOp(Shl)                    // associated path
451             | ModSep                    => true, // global path
452             Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
453                 NtPat(..)     |
454                 NtBlock(..)   |
455                 NtPath(..)),
456             _ => false,
457         }
458     }
459 
460     /// Returns `true` if the token can appear at the start of a type.
can_begin_type(&self) -> bool461     pub fn can_begin_type(&self) -> bool {
462         match self.uninterpolate().kind {
463             Ident(name, is_raw)        =>
464                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
465             OpenDelim(Delimiter::Parenthesis) | // tuple
466             OpenDelim(Delimiter::Bracket)     | // array
467             Not                         | // never
468             BinOp(Star)                 | // raw pointer
469             BinOp(And)                  | // reference
470             AndAnd                      | // double reference
471             Question                    | // maybe bound in trait object
472             Lifetime(..)                | // lifetime bound in trait object
473             Lt | BinOp(Shl)             | // associated path
474             ModSep                      => true, // global path
475             Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
476             _ => false,
477         }
478     }
479 
480     /// Returns `true` if the token can appear at the start of a const param.
can_begin_const_arg(&self) -> bool481     pub fn can_begin_const_arg(&self) -> bool {
482         match self.kind {
483             OpenDelim(Delimiter::Brace) => true,
484             Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
485             _ => self.can_begin_literal_maybe_minus(),
486         }
487     }
488 
489     /// Returns `true` if the token can appear at the start of a generic bound.
can_begin_bound(&self) -> bool490     pub fn can_begin_bound(&self) -> bool {
491         self.is_path_start()
492             || self.is_lifetime()
493             || self.is_keyword(kw::For)
494             || self == &Question
495             || self == &OpenDelim(Delimiter::Parenthesis)
496     }
497 
498     /// Returns `true` if the token can appear at the start of an item.
can_begin_item(&self) -> bool499     pub fn can_begin_item(&self) -> bool {
500         match self.kind {
501             Ident(name, _) => [
502                 kw::Fn,
503                 kw::Use,
504                 kw::Struct,
505                 kw::Enum,
506                 kw::Pub,
507                 kw::Trait,
508                 kw::Extern,
509                 kw::Impl,
510                 kw::Unsafe,
511                 kw::Const,
512                 kw::Static,
513                 kw::Union,
514                 kw::Macro,
515                 kw::Mod,
516                 kw::Type,
517             ]
518             .contains(&name),
519             _ => false,
520         }
521     }
522 
523     /// Returns `true` if the token is any literal.
is_lit(&self) -> bool524     pub fn is_lit(&self) -> bool {
525         matches!(self.kind, Literal(..))
526     }
527 
528     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
529     /// for example a '-42', or one of the boolean idents).
530     ///
531     /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
532     ///
533     /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
can_begin_literal_maybe_minus(&self) -> bool534     pub fn can_begin_literal_maybe_minus(&self) -> bool {
535         match self.uninterpolate().kind {
536             Literal(..) | BinOp(Minus) => true,
537             Ident(name, false) if name.is_bool_lit() => true,
538             Interpolated(ref nt) => match &**nt {
539                 NtLiteral(_) => true,
540                 NtExpr(e) => match &e.kind {
541                     ast::ExprKind::Lit(_) => true,
542                     ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
543                         matches!(&e.kind, ast::ExprKind::Lit(_))
544                     }
545                     _ => false,
546                 },
547                 _ => false,
548             },
549             _ => false,
550         }
551     }
552 
553     /// A convenience function for matching on identifiers during parsing.
554     /// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
555     /// into the regular identifier or lifetime token it refers to,
556     /// otherwise returns the original token.
uninterpolate(&self) -> Cow<'_, Token>557     pub fn uninterpolate(&self) -> Cow<'_, Token> {
558         match &self.kind {
559             Interpolated(nt) => match **nt {
560                 NtIdent(ident, is_raw) => {
561                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
562                 }
563                 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
564                 _ => Cow::Borrowed(self),
565             },
566             _ => Cow::Borrowed(self),
567         }
568     }
569 
570     /// Returns an identifier if this token is an identifier.
571     #[inline]
ident(&self) -> Option<(Ident, bool)>572     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
573         // We avoid using `Token::uninterpolate` here because it's slow.
574         match &self.kind {
575             &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
576             Interpolated(nt) => match **nt {
577                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
578                 _ => None,
579             },
580             _ => None,
581         }
582     }
583 
584     /// Returns a lifetime identifier if this token is a lifetime.
585     #[inline]
lifetime(&self) -> Option<Ident>586     pub fn lifetime(&self) -> Option<Ident> {
587         // We avoid using `Token::uninterpolate` here because it's slow.
588         match &self.kind {
589             &Lifetime(name) => Some(Ident::new(name, self.span)),
590             Interpolated(nt) => match **nt {
591                 NtLifetime(ident) => Some(ident),
592                 _ => None,
593             },
594             _ => None,
595         }
596     }
597 
598     /// Returns `true` if the token is an identifier.
is_ident(&self) -> bool599     pub fn is_ident(&self) -> bool {
600         self.ident().is_some()
601     }
602 
603     /// Returns `true` if the token is a lifetime.
is_lifetime(&self) -> bool604     pub fn is_lifetime(&self) -> bool {
605         self.lifetime().is_some()
606     }
607 
608     /// Returns `true` if the token is an identifier whose name is the given
609     /// string slice.
is_ident_named(&self, name: Symbol) -> bool610     pub fn is_ident_named(&self, name: Symbol) -> bool {
611         self.ident().is_some_and(|(ident, _)| ident.name == name)
612     }
613 
614     /// Returns `true` if the token is an interpolated path.
is_path(&self) -> bool615     fn is_path(&self) -> bool {
616         if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt {
617             return true;
618         }
619 
620         false
621     }
622 
623     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
624     /// That is, is this a pre-parsed expression dropped into the token stream
625     /// (which happens while parsing the result of macro expansion)?
is_whole_expr(&self) -> bool626     pub fn is_whole_expr(&self) -> bool {
627         if let Interpolated(nt) = &self.kind
628             && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
629         {
630             return true;
631         }
632 
633         false
634     }
635 
636     /// Is the token an interpolated block (`$b:block`)?
is_whole_block(&self) -> bool637     pub fn is_whole_block(&self) -> bool {
638         if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt {
639             return true;
640         }
641 
642         false
643     }
644 
645     /// Returns `true` if the token is either the `mut` or `const` keyword.
is_mutability(&self) -> bool646     pub fn is_mutability(&self) -> bool {
647         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
648     }
649 
is_qpath_start(&self) -> bool650     pub fn is_qpath_start(&self) -> bool {
651         self == &Lt || self == &BinOp(Shl)
652     }
653 
is_path_start(&self) -> bool654     pub fn is_path_start(&self) -> bool {
655         self == &ModSep
656             || self.is_qpath_start()
657             || self.is_path()
658             || self.is_path_segment_keyword()
659             || self.is_ident() && !self.is_reserved_ident()
660     }
661 
662     /// Returns `true` if the token is a given keyword, `kw`.
is_keyword(&self, kw: Symbol) -> bool663     pub fn is_keyword(&self, kw: Symbol) -> bool {
664         self.is_non_raw_ident_where(|id| id.name == kw)
665     }
666 
667     /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
is_keyword_case(&self, kw: Symbol, case: Case) -> bool668     pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
669         self.is_keyword(kw)
670             || (case == Case::Insensitive
671                 && self.is_non_raw_ident_where(|id| {
672                     id.name.as_str().to_lowercase() == kw.as_str().to_lowercase()
673                 }))
674     }
675 
is_path_segment_keyword(&self) -> bool676     pub fn is_path_segment_keyword(&self) -> bool {
677         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
678     }
679 
680     /// Returns true for reserved identifiers used internally for elided lifetimes,
681     /// unnamed method parameters, crate root module, error recovery etc.
is_special_ident(&self) -> bool682     pub fn is_special_ident(&self) -> bool {
683         self.is_non_raw_ident_where(Ident::is_special)
684     }
685 
686     /// Returns `true` if the token is a keyword used in the language.
is_used_keyword(&self) -> bool687     pub fn is_used_keyword(&self) -> bool {
688         self.is_non_raw_ident_where(Ident::is_used_keyword)
689     }
690 
691     /// Returns `true` if the token is a keyword reserved for possible future use.
is_unused_keyword(&self) -> bool692     pub fn is_unused_keyword(&self) -> bool {
693         self.is_non_raw_ident_where(Ident::is_unused_keyword)
694     }
695 
696     /// Returns `true` if the token is either a special identifier or a keyword.
is_reserved_ident(&self) -> bool697     pub fn is_reserved_ident(&self) -> bool {
698         self.is_non_raw_ident_where(Ident::is_reserved)
699     }
700 
701     /// Returns `true` if the token is the identifier `true` or `false`.
is_bool_lit(&self) -> bool702     pub fn is_bool_lit(&self) -> bool {
703         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
704     }
705 
is_numeric_lit(&self) -> bool706     pub fn is_numeric_lit(&self) -> bool {
707         matches!(
708             self.kind,
709             Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
710         )
711     }
712 
713     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool714     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
715         match self.ident() {
716             Some((id, false)) => pred(id),
717             _ => false,
718         }
719     }
720 
glue(&self, joint: &Token) -> Option<Token>721     pub fn glue(&self, joint: &Token) -> Option<Token> {
722         let kind = match self.kind {
723             Eq => match joint.kind {
724                 Eq => EqEq,
725                 Gt => FatArrow,
726                 _ => return None,
727             },
728             Lt => match joint.kind {
729                 Eq => Le,
730                 Lt => BinOp(Shl),
731                 Le => BinOpEq(Shl),
732                 BinOp(Minus) => LArrow,
733                 _ => return None,
734             },
735             Gt => match joint.kind {
736                 Eq => Ge,
737                 Gt => BinOp(Shr),
738                 Ge => BinOpEq(Shr),
739                 _ => return None,
740             },
741             Not => match joint.kind {
742                 Eq => Ne,
743                 _ => return None,
744             },
745             BinOp(op) => match joint.kind {
746                 Eq => BinOpEq(op),
747                 BinOp(And) if op == And => AndAnd,
748                 BinOp(Or) if op == Or => OrOr,
749                 Gt if op == Minus => RArrow,
750                 _ => return None,
751             },
752             Dot => match joint.kind {
753                 Dot => DotDot,
754                 DotDot => DotDotDot,
755                 _ => return None,
756             },
757             DotDot => match joint.kind {
758                 Dot => DotDotDot,
759                 Eq => DotDotEq,
760                 _ => return None,
761             },
762             Colon => match joint.kind {
763                 Colon => ModSep,
764                 _ => return None,
765             },
766             SingleQuote => match joint.kind {
767                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))),
768                 _ => return None,
769             },
770 
771             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
772             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
773             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
774             | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
775         };
776 
777         Some(Token::new(kind, self.span.to(joint.span)))
778     }
779 }
780 
781 impl PartialEq<TokenKind> for Token {
782     #[inline]
eq(&self, rhs: &TokenKind) -> bool783     fn eq(&self, rhs: &TokenKind) -> bool {
784         self.kind == *rhs
785     }
786 }
787 
788 #[derive(Clone, Encodable, Decodable)]
789 /// For interpolation during macro expansion.
790 pub enum Nonterminal {
791     NtItem(P<ast::Item>),
792     NtBlock(P<ast::Block>),
793     NtStmt(P<ast::Stmt>),
794     NtPat(P<ast::Pat>),
795     NtExpr(P<ast::Expr>),
796     NtTy(P<ast::Ty>),
797     NtIdent(Ident, /* is_raw */ bool),
798     NtLifetime(Ident),
799     NtLiteral(P<ast::Expr>),
800     /// Stuff inside brackets for attributes
801     NtMeta(P<ast::AttrItem>),
802     NtPath(P<ast::Path>),
803     NtVis(P<ast::Visibility>),
804 }
805 
806 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
807 pub enum NonterminalKind {
808     Item,
809     Block,
810     Stmt,
811     PatParam {
812         /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
813         /// edition of the span. This is used for diagnostics.
814         inferred: bool,
815     },
816     PatWithOr,
817     Expr,
818     Ty,
819     Ident,
820     Lifetime,
821     Literal,
822     Meta,
823     Path,
824     Vis,
825     TT,
826 }
827 
828 impl NonterminalKind {
829     /// The `edition` closure is used to get the edition for the given symbol. Doing
830     /// `span.edition()` is expensive, so we do it lazily.
from_symbol( symbol: Symbol, edition: impl FnOnce() -> Edition, ) -> Option<NonterminalKind>831     pub fn from_symbol(
832         symbol: Symbol,
833         edition: impl FnOnce() -> Edition,
834     ) -> Option<NonterminalKind> {
835         Some(match symbol {
836             sym::item => NonterminalKind::Item,
837             sym::block => NonterminalKind::Block,
838             sym::stmt => NonterminalKind::Stmt,
839             sym::pat => match edition() {
840                 Edition::Edition2015 | Edition::Edition2018 => {
841                     NonterminalKind::PatParam { inferred: true }
842                 }
843                 Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
844             },
845             sym::pat_param => NonterminalKind::PatParam { inferred: false },
846             sym::expr => NonterminalKind::Expr,
847             sym::ty => NonterminalKind::Ty,
848             sym::ident => NonterminalKind::Ident,
849             sym::lifetime => NonterminalKind::Lifetime,
850             sym::literal => NonterminalKind::Literal,
851             sym::meta => NonterminalKind::Meta,
852             sym::path => NonterminalKind::Path,
853             sym::vis => NonterminalKind::Vis,
854             sym::tt => NonterminalKind::TT,
855             _ => return None,
856         })
857     }
symbol(self) -> Symbol858     fn symbol(self) -> Symbol {
859         match self {
860             NonterminalKind::Item => sym::item,
861             NonterminalKind::Block => sym::block,
862             NonterminalKind::Stmt => sym::stmt,
863             NonterminalKind::PatParam { inferred: false } => sym::pat_param,
864             NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
865             NonterminalKind::Expr => sym::expr,
866             NonterminalKind::Ty => sym::ty,
867             NonterminalKind::Ident => sym::ident,
868             NonterminalKind::Lifetime => sym::lifetime,
869             NonterminalKind::Literal => sym::literal,
870             NonterminalKind::Meta => sym::meta,
871             NonterminalKind::Path => sym::path,
872             NonterminalKind::Vis => sym::vis,
873             NonterminalKind::TT => sym::tt,
874         }
875     }
876 }
877 
878 impl fmt::Display for NonterminalKind {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result879     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880         write!(f, "{}", self.symbol())
881     }
882 }
883 
884 impl Nonterminal {
span(&self) -> Span885     pub fn span(&self) -> Span {
886         match self {
887             NtItem(item) => item.span,
888             NtBlock(block) => block.span,
889             NtStmt(stmt) => stmt.span,
890             NtPat(pat) => pat.span,
891             NtExpr(expr) | NtLiteral(expr) => expr.span,
892             NtTy(ty) => ty.span,
893             NtIdent(ident, _) | NtLifetime(ident) => ident.span,
894             NtMeta(attr_item) => attr_item.span(),
895             NtPath(path) => path.span,
896             NtVis(vis) => vis.span,
897         }
898     }
899 }
900 
901 impl PartialEq for Nonterminal {
eq(&self, rhs: &Self) -> bool902     fn eq(&self, rhs: &Self) -> bool {
903         match (self, rhs) {
904             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
905                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
906             }
907             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
908             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
909             // correctly based on data from AST. This will prevent them from matching each other
910             // in macros. The comparison will become possible only when each nonterminal has an
911             // attached token stream from which it was parsed.
912             _ => false,
913         }
914     }
915 }
916 
917 impl fmt::Debug for Nonterminal {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result918     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
919         match *self {
920             NtItem(..) => f.pad("NtItem(..)"),
921             NtBlock(..) => f.pad("NtBlock(..)"),
922             NtStmt(..) => f.pad("NtStmt(..)"),
923             NtPat(..) => f.pad("NtPat(..)"),
924             NtExpr(..) => f.pad("NtExpr(..)"),
925             NtTy(..) => f.pad("NtTy(..)"),
926             NtIdent(..) => f.pad("NtIdent(..)"),
927             NtLiteral(..) => f.pad("NtLiteral(..)"),
928             NtMeta(..) => f.pad("NtMeta(..)"),
929             NtPath(..) => f.pad("NtPath(..)"),
930             NtVis(..) => f.pad("NtVis(..)"),
931             NtLifetime(..) => f.pad("NtLifetime(..)"),
932         }
933     }
934 }
935 
936 impl<CTX> HashStable<CTX> for Nonterminal
937 where
938     CTX: crate::HashStableContext,
939 {
hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher)940     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
941         panic!("interpolated tokens should not be present in the HIR")
942     }
943 }
944 
945 // Some types are used a lot. Make sure they don't unintentionally get bigger.
946 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
947 mod size_asserts {
948     use super::*;
949     use rustc_data_structures::static_assert_size;
950     // tidy-alphabetical-start
951     static_assert_size!(Lit, 12);
952     static_assert_size!(LitKind, 2);
953     static_assert_size!(Nonterminal, 16);
954     static_assert_size!(Token, 24);
955     static_assert_size!(TokenKind, 16);
956     // tidy-alphabetical-end
957 }
958