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