1use std::borrow::Cow;
2use std::fmt;
3use std::sync::Arc;
4
5pub use LitKind::*;
6pub use Nonterminal::*;
7pub use NtExprKind::*;
8pub use NtPatKind::*;
9pub use TokenKind::*;
10use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
11use rustc_macros::{Decodable, Encodable, HashStable_Generic};
12use rustc_span::edition::Edition;
13use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
14#[allow(clippy::useless_attribute)] #[allow(hidden_glob_reexports)]
16use rustc_span::{Ident, Symbol};
17
18use crate::ast;
19use crate::ptr::P;
20use crate::util::case::Case;
21
22#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
23pub enum CommentKind {
24 Line,
25 Block,
26}
27
28#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
30pub enum InvisibleOrigin {
31 MetaVar(MetaVarKind),
33
34 ProcMacro,
37
38 FlattenToken,
41}
42
43impl PartialEq for InvisibleOrigin {
44 #[inline]
45 fn eq(&self, _other: &InvisibleOrigin) -> bool {
46 false
54 }
55}
56
57#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
59pub enum MetaVarKind {
60 Item,
61 Block,
62 Stmt,
63 Pat(NtPatKind),
64 Expr {
65 kind: NtExprKind,
66 can_begin_literal_maybe_minus: bool,
68 can_begin_string_literal: bool,
70 },
71 Ty {
72 is_path: bool,
73 },
74 Ident,
75 Lifetime,
76 Literal,
77 Meta {
78 has_meta_form: bool,
80 },
81 Path,
82 Vis,
83 TT,
84}
85
86impl fmt::Display for MetaVarKind {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 let sym = match self {
89 MetaVarKind::Item => sym::item,
90 MetaVarKind::Block => sym::block,
91 MetaVarKind::Stmt => sym::stmt,
92 MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
93 MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
94 MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
95 MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
96 MetaVarKind::Ty { .. } => sym::ty,
97 MetaVarKind::Ident => sym::ident,
98 MetaVarKind::Lifetime => sym::lifetime,
99 MetaVarKind::Literal => sym::literal,
100 MetaVarKind::Meta { .. } => sym::meta,
101 MetaVarKind::Path => sym::path,
102 MetaVarKind::Vis => sym::vis,
103 MetaVarKind::TT => sym::tt,
104 };
105 write!(f, "{sym}")
106 }
107}
108
109#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
113pub enum Delimiter {
114 Parenthesis,
116 Brace,
118 Bracket,
120 Invisible(InvisibleOrigin),
126}
127
128impl Delimiter {
129 #[inline]
133 pub fn skip(&self) -> bool {
134 match self {
135 Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
136 Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
137 Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
138 true
139 }
140 }
141 }
142
143 pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
145 match (self, other) {
146 (Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
147 (Delimiter::Brace, Delimiter::Brace) => true,
148 (Delimiter::Bracket, Delimiter::Bracket) => true,
149 (Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
150 _ => false,
151 }
152 }
153}
154
155#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
160pub enum LitKind {
161 Bool, Byte,
163 Char,
164 Integer, Float, Str,
167 StrRaw(u8), ByteStr,
169 ByteStrRaw(u8), CStr,
171 CStrRaw(u8),
172 Err(ErrorGuaranteed),
173}
174
175#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
177pub struct Lit {
178 pub kind: LitKind,
179 pub symbol: Symbol,
180 pub suffix: Option<Symbol>,
181}
182
183impl Lit {
184 pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
185 Lit { kind, symbol, suffix }
186 }
187
188 pub fn is_semantic_float(&self) -> bool {
191 match self.kind {
192 LitKind::Float => true,
193 LitKind::Integer => match self.suffix {
194 Some(sym) => sym == sym::f32 || sym == sym::f64,
195 None => false,
196 },
197 _ => false,
198 }
199 }
200
201 pub fn from_token(token: &Token) -> Option<Lit> {
203 match token.uninterpolate().kind {
204 Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
205 Literal(token_lit) => Some(token_lit),
206 Interpolated(ref nt)
207 if let NtExpr(expr) | NtLiteral(expr) = &**nt
208 && let ast::ExprKind::Lit(token_lit) = expr.kind =>
209 {
210 Some(token_lit)
211 }
212 _ => None,
213 }
214 }
215}
216
217impl fmt::Display for Lit {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 let Lit { kind, symbol, suffix } = *self;
220 match kind {
221 Byte => write!(f, "b'{symbol}'")?,
222 Char => write!(f, "'{symbol}'")?,
223 Str => write!(f, "\"{symbol}\"")?,
224 StrRaw(n) => write!(
225 f,
226 "r{delim}\"{string}\"{delim}",
227 delim = "#".repeat(n as usize),
228 string = symbol
229 )?,
230 ByteStr => write!(f, "b\"{symbol}\"")?,
231 ByteStrRaw(n) => write!(
232 f,
233 "br{delim}\"{string}\"{delim}",
234 delim = "#".repeat(n as usize),
235 string = symbol
236 )?,
237 CStr => write!(f, "c\"{symbol}\"")?,
238 CStrRaw(n) => {
239 write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
240 }
241 Integer | Float | Bool | Err(_) => write!(f, "{symbol}")?,
242 }
243
244 if let Some(suffix) = suffix {
245 write!(f, "{suffix}")?;
246 }
247
248 Ok(())
249 }
250}
251
252impl LitKind {
253 pub fn article(self) -> &'static str {
255 match self {
256 Integer | Err(_) => "an",
257 _ => "a",
258 }
259 }
260
261 pub fn descr(self) -> &'static str {
262 match self {
263 Bool => "boolean",
264 Byte => "byte",
265 Char => "char",
266 Integer => "integer",
267 Float => "float",
268 Str | StrRaw(..) => "string",
269 ByteStr | ByteStrRaw(..) => "byte string",
270 CStr | CStrRaw(..) => "C string",
271 Err(_) => "error",
272 }
273 }
274
275 pub(crate) fn may_have_suffix(self) -> bool {
276 matches!(self, Integer | Float | Err(_))
277 }
278}
279
280pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
281 let ident_token = Token::new(Ident(name, is_raw), span);
282
283 !ident_token.is_reserved_ident()
284 || ident_token.is_path_segment_keyword()
285 || [
286 kw::Async,
287 kw::Do,
288 kw::Box,
289 kw::Break,
290 kw::Const,
291 kw::Continue,
292 kw::False,
293 kw::For,
294 kw::Gen,
295 kw::If,
296 kw::Let,
297 kw::Loop,
298 kw::Match,
299 kw::Move,
300 kw::Return,
301 kw::True,
302 kw::Try,
303 kw::Unsafe,
304 kw::While,
305 kw::Yield,
306 kw::Safe,
307 kw::Static,
308 ]
309 .contains(&name)
310}
311
312fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
313 let ident_token = Token::new(Ident(name, is_raw), span);
314
315 !ident_token.is_reserved_ident()
316 || ident_token.is_path_segment_keyword()
317 || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn]
318 .contains(&name)
319}
320
321#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
322pub enum IdentIsRaw {
323 No,
324 Yes,
325}
326
327impl From<bool> for IdentIsRaw {
328 fn from(b: bool) -> Self {
329 if b { Self::Yes } else { Self::No }
330 }
331}
332
333impl From<IdentIsRaw> for bool {
334 fn from(is_raw: IdentIsRaw) -> bool {
335 matches!(is_raw, IdentIsRaw::Yes)
336 }
337}
338
339#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
342pub enum TokenKind {
343 Eq,
346 Lt,
348 Le,
350 EqEq,
352 Ne,
354 Ge,
356 Gt,
358 AndAnd,
360 OrOr,
362 Bang,
364 Tilde,
366 Plus,
368 Minus,
370 Star,
372 Slash,
374 Percent,
376 Caret,
378 And,
380 Or,
382 Shl,
384 Shr,
386 PlusEq,
388 MinusEq,
390 StarEq,
392 SlashEq,
394 PercentEq,
396 CaretEq,
398 AndEq,
400 OrEq,
402 ShlEq,
404 ShrEq,
406
407 At,
410 Dot,
412 DotDot,
414 DotDotDot,
416 DotDotEq,
418 Comma,
420 Semi,
422 Colon,
424 PathSep,
426 RArrow,
428 LArrow,
430 FatArrow,
432 Pound,
434 Dollar,
436 Question,
438 SingleQuote,
440 OpenDelim(Delimiter),
442 CloseDelim(Delimiter),
444
445 Literal(Lit),
447
448 Ident(Symbol, IdentIsRaw),
453 NtIdent(Ident, IdentIsRaw),
457
458 Lifetime(Symbol, IdentIsRaw),
463 NtLifetime(Ident, IdentIsRaw),
467
468 Interpolated(Arc<Nonterminal>),
482
483 DocComment(CommentKind, ast::AttrStyle, Symbol),
487
488 Eof,
490}
491
492impl Clone for TokenKind {
493 fn clone(&self) -> Self {
494 match self {
499 Interpolated(nt) => Interpolated(Arc::clone(nt)),
500 _ => unsafe { std::ptr::read(self) },
501 }
502 }
503}
504
505#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
506pub struct Token {
507 pub kind: TokenKind,
508 pub span: Span,
509}
510
511impl TokenKind {
512 pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
513 Literal(Lit::new(kind, symbol, suffix))
514 }
515
516 pub fn break_two_token_op(&self, n: u32) -> Option<(TokenKind, TokenKind)> {
521 assert!(n == 1 || n == 2);
522 Some(match (self, n) {
523 (Le, 1) => (Lt, Eq),
524 (EqEq, 1) => (Eq, Eq),
525 (Ne, 1) => (Bang, Eq),
526 (Ge, 1) => (Gt, Eq),
527 (AndAnd, 1) => (And, And),
528 (OrOr, 1) => (Or, Or),
529 (Shl, 1) => (Lt, Lt),
530 (Shr, 1) => (Gt, Gt),
531 (PlusEq, 1) => (Plus, Eq),
532 (MinusEq, 1) => (Minus, Eq),
533 (StarEq, 1) => (Star, Eq),
534 (SlashEq, 1) => (Slash, Eq),
535 (PercentEq, 1) => (Percent, Eq),
536 (CaretEq, 1) => (Caret, Eq),
537 (AndEq, 1) => (And, Eq),
538 (OrEq, 1) => (Or, Eq),
539 (ShlEq, 1) => (Lt, Le), (ShlEq, 2) => (Shl, Eq), (ShrEq, 1) => (Gt, Ge), (ShrEq, 2) => (Shr, Eq), (DotDot, 1) => (Dot, Dot),
544 (DotDotDot, 1) => (Dot, DotDot), (DotDotDot, 2) => (DotDot, Dot), (DotDotEq, 2) => (DotDot, Eq),
547 (PathSep, 1) => (Colon, Colon),
548 (RArrow, 1) => (Minus, Gt),
549 (LArrow, 1) => (Lt, Minus),
550 (FatArrow, 1) => (Eq, Gt),
551 _ => return None,
552 })
553 }
554
555 pub fn similar_tokens(&self) -> &[TokenKind] {
558 match self {
559 Comma => &[Dot, Lt, Semi],
560 Semi => &[Colon, Comma],
561 Colon => &[Semi],
562 FatArrow => &[Eq, RArrow, Ge, Gt],
563 _ => &[],
564 }
565 }
566
567 pub fn should_end_const_arg(&self) -> bool {
568 matches!(self, Gt | Ge | Shr | ShrEq)
569 }
570}
571
572impl Token {
573 pub fn new(kind: TokenKind, span: Span) -> Self {
574 Token { kind, span }
575 }
576
577 pub fn dummy() -> Self {
579 Token::new(TokenKind::Question, DUMMY_SP)
580 }
581
582 pub fn from_ast_ident(ident: Ident) -> Self {
584 Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span)
585 }
586
587 pub fn uninterpolated_span(&self) -> Span {
594 match self.kind {
595 NtIdent(ident, _) | NtLifetime(ident, _) => ident.span,
596 Interpolated(ref nt) => nt.use_span(),
597 _ => self.span,
598 }
599 }
600
601 pub fn is_range_separator(&self) -> bool {
602 [DotDot, DotDotDot, DotDotEq].contains(&self.kind)
603 }
604
605 pub fn is_punct(&self) -> bool {
606 match self.kind {
607 Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Bang | Tilde | Plus | Minus
608 | Star | Slash | Percent | Caret | And | Or | Shl | Shr | PlusEq | MinusEq | StarEq
609 | SlashEq | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | Dot | DotDot
610 | DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow
611 | FatArrow | Pound | Dollar | Question | SingleQuote => true,
612
613 OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
614 | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
615 }
616 }
617
618 pub fn is_like_plus(&self) -> bool {
619 matches!(self.kind, Plus | PlusEq)
620 }
621
622 pub fn can_begin_expr(&self) -> bool {
627 use Delimiter::*;
628 match self.uninterpolate().kind {
629 Ident(name, is_raw) =>
630 ident_can_begin_expr(name, self.span, is_raw), OpenDelim(Parenthesis | Brace | Bracket) | Literal(..) | Bang | Minus | Star | Or | OrOr | And | AndAnd | DotDot | DotDotDot | DotDotEq | Lt | Shl | PathSep | Lifetime(..) | Pound => true, Interpolated(ref nt) =>
646 matches!(&**nt,
647 NtBlock(..) |
648 NtExpr(..) |
649 NtLiteral(..)
650 ),
651 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
652 MetaVarKind::Block |
653 MetaVarKind::Expr { .. } |
654 MetaVarKind::Literal |
655 MetaVarKind::Path
656 ))) => true,
657 _ => false,
658 }
659 }
660
661 pub fn can_begin_pattern(&self, pat_kind: NtPatKind) -> bool {
665 match &self.uninterpolate().kind {
666 Ident(..) | NtIdent(..) |
668 OpenDelim(Delimiter::Parenthesis) | OpenDelim(Delimiter::Bracket) | And | Minus | AndAnd | Literal(_) | DotDot | DotDotDot | PathSep | Lt | Shl => true, Or => matches!(pat_kind, PatWithOr), Interpolated(nt) =>
681 matches!(&**nt,
682 | NtExpr(..)
683 | NtLiteral(..)
684 ),
685 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
686 MetaVarKind::Expr { .. } |
687 MetaVarKind::Literal |
688 MetaVarKind::Meta { .. } |
689 MetaVarKind::Pat(_) |
690 MetaVarKind::Path |
691 MetaVarKind::Ty { .. }
692 ))) => true,
693 _ => false,
694 }
695 }
696
697 pub fn can_begin_type(&self) -> bool {
699 match self.uninterpolate().kind {
700 Ident(name, is_raw) =>
701 ident_can_begin_type(name, self.span, is_raw), OpenDelim(Delimiter::Parenthesis) | OpenDelim(Delimiter::Bracket) | Bang | Star | And | AndAnd | Question | Lifetime(..) | Lt | Shl | PathSep => true, OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
713 MetaVarKind::Ty { .. } |
714 MetaVarKind::Path
715 ))) => true,
716 _ => false,
719 }
720 }
721
722 pub fn can_begin_const_arg(&self) -> bool {
724 match self.kind {
725 OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
726 Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
727 Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
728 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
729 MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
730 ))) => true,
731 _ => false,
732 }
733 }
734
735 pub fn can_begin_item(&self) -> bool {
737 match self.kind {
738 Ident(name, _) => [
739 kw::Fn,
740 kw::Use,
741 kw::Struct,
742 kw::Enum,
743 kw::Pub,
744 kw::Trait,
745 kw::Extern,
746 kw::Impl,
747 kw::Unsafe,
748 kw::Const,
749 kw::Safe,
750 kw::Static,
751 kw::Union,
752 kw::Macro,
753 kw::Mod,
754 kw::Type,
755 ]
756 .contains(&name),
757 _ => false,
758 }
759 }
760
761 pub fn is_lit(&self) -> bool {
763 matches!(self.kind, Literal(..))
764 }
765
766 pub fn can_begin_literal_maybe_minus(&self) -> bool {
773 match self.uninterpolate().kind {
774 Literal(..) | Minus => true,
775 Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
776 Interpolated(ref nt) => match &**nt {
777 NtLiteral(_) => true,
778 NtExpr(e) => match &e.kind {
779 ast::ExprKind::Lit(_) => true,
780 ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
781 matches!(&e.kind, ast::ExprKind::Lit(_))
782 }
783 _ => false,
784 },
785 _ => false,
786 },
787 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
788 MetaVarKind::Literal => true,
789 MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
790 can_begin_literal_maybe_minus
791 }
792 _ => false,
793 },
794 _ => false,
795 }
796 }
797
798 pub fn can_begin_string_literal(&self) -> bool {
799 match self.uninterpolate().kind {
800 Literal(..) => true,
801 Interpolated(ref nt) => match &**nt {
802 NtLiteral(_) => true,
803 NtExpr(e) => match &e.kind {
804 ast::ExprKind::Lit(_) => true,
805 _ => false,
806 },
807 _ => false,
808 },
809 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
810 MetaVarKind::Literal => true,
811 MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
812 _ => false,
813 },
814 _ => false,
815 }
816 }
817
818 pub fn uninterpolate(&self) -> Cow<'_, Token> {
823 match self.kind {
824 NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
825 NtLifetime(ident, is_raw) => {
826 Cow::Owned(Token::new(Lifetime(ident.name, is_raw), ident.span))
827 }
828 _ => Cow::Borrowed(self),
829 }
830 }
831
832 #[inline]
834 pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
835 match self.kind {
837 Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
838 NtIdent(ident, is_raw) => Some((ident, is_raw)),
839 _ => None,
840 }
841 }
842
843 #[inline]
845 pub fn lifetime(&self) -> Option<(Ident, IdentIsRaw)> {
846 match self.kind {
848 Lifetime(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
849 NtLifetime(ident, is_raw) => Some((ident, is_raw)),
850 _ => None,
851 }
852 }
853
854 pub fn is_ident(&self) -> bool {
856 self.ident().is_some()
857 }
858
859 pub fn is_lifetime(&self) -> bool {
861 self.lifetime().is_some()
862 }
863
864 pub fn is_ident_named(&self, name: Symbol) -> bool {
867 self.ident().is_some_and(|(ident, _)| ident.name == name)
868 }
869
870 pub fn is_whole_expr(&self) -> bool {
873 #[allow(irrefutable_let_patterns)] if let Interpolated(nt) = &self.kind
875 && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt
876 {
877 true
878 } else {
879 matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
880 }
881 }
882
883 pub fn is_whole_block(&self) -> bool {
885 if let Interpolated(nt) = &self.kind
886 && let NtBlock(..) = &**nt
887 {
888 return true;
889 }
890
891 false
892 }
893
894 pub fn is_mutability(&self) -> bool {
896 self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
897 }
898
899 pub fn is_qpath_start(&self) -> bool {
900 self == &Lt || self == &Shl
901 }
902
903 pub fn is_path_start(&self) -> bool {
904 self == &PathSep
905 || self.is_qpath_start()
906 || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
907 || self.is_path_segment_keyword()
908 || self.is_ident() && !self.is_reserved_ident()
909 }
910
911 pub fn is_keyword(&self, kw: Symbol) -> bool {
913 self.is_non_raw_ident_where(|id| id.name == kw)
914 }
915
916 pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
919 self.is_keyword(kw)
920 || (case == Case::Insensitive
921 && self.is_non_raw_ident_where(|id| {
922 id.name.as_str().eq_ignore_ascii_case(kw.as_str())
924 }))
925 }
926
927 pub fn is_path_segment_keyword(&self) -> bool {
928 self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
929 }
930
931 pub fn is_any_keyword(&self) -> bool {
933 self.is_non_raw_ident_where(Ident::is_any_keyword)
934 }
935
936 pub fn is_special_ident(&self) -> bool {
939 self.is_non_raw_ident_where(Ident::is_special)
940 }
941
942 pub fn is_used_keyword(&self) -> bool {
944 self.is_non_raw_ident_where(Ident::is_used_keyword)
945 }
946
947 pub fn is_unused_keyword(&self) -> bool {
949 self.is_non_raw_ident_where(Ident::is_unused_keyword)
950 }
951
952 pub fn is_reserved_ident(&self) -> bool {
954 self.is_non_raw_ident_where(Ident::is_reserved)
955 }
956
957 pub fn is_bool_lit(&self) -> bool {
959 self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
960 }
961
962 pub fn is_numeric_lit(&self) -> bool {
963 matches!(
964 self.kind,
965 Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
966 )
967 }
968
969 pub fn is_integer_lit(&self) -> bool {
971 matches!(self.kind, Literal(Lit { kind: LitKind::Integer, .. }))
972 }
973
974 pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
976 match self.ident() {
977 Some((id, IdentIsRaw::No)) => pred(id),
978 _ => false,
979 }
980 }
981
982 pub fn is_metavar_seq(&self) -> Option<MetaVarKind> {
985 match self.kind {
986 OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind),
987 _ => None,
988 }
989 }
990
991 pub fn glue(&self, joint: &Token) -> Option<Token> {
992 let kind = match (&self.kind, &joint.kind) {
993 (Eq, Eq) => EqEq,
994 (Eq, Gt) => FatArrow,
995 (Eq, _) => return None,
996
997 (Lt, Eq) => Le,
998 (Lt, Lt) => Shl,
999 (Lt, Le) => ShlEq,
1000 (Lt, Minus) => LArrow,
1001 (Lt, _) => return None,
1002
1003 (Gt, Eq) => Ge,
1004 (Gt, Gt) => Shr,
1005 (Gt, Ge) => ShrEq,
1006 (Gt, _) => return None,
1007
1008 (Bang, Eq) => Ne,
1009 (Bang, _) => return None,
1010
1011 (Plus, Eq) => PlusEq,
1012 (Plus, _) => return None,
1013
1014 (Minus, Eq) => MinusEq,
1015 (Minus, Gt) => RArrow,
1016 (Minus, _) => return None,
1017
1018 (Star, Eq) => StarEq,
1019 (Star, _) => return None,
1020
1021 (Slash, Eq) => SlashEq,
1022 (Slash, _) => return None,
1023
1024 (Percent, Eq) => PercentEq,
1025 (Percent, _) => return None,
1026
1027 (Caret, Eq) => CaretEq,
1028 (Caret, _) => return None,
1029
1030 (And, Eq) => AndEq,
1031 (And, And) => AndAnd,
1032 (And, _) => return None,
1033
1034 (Or, Eq) => OrEq,
1035 (Or, Or) => OrOr,
1036 (Or, _) => return None,
1037
1038 (Shl, Eq) => ShlEq,
1039 (Shl, _) => return None,
1040
1041 (Shr, Eq) => ShrEq,
1042 (Shr, _) => return None,
1043
1044 (Dot, Dot) => DotDot,
1045 (Dot, DotDot) => DotDotDot,
1046 (Dot, _) => return None,
1047
1048 (DotDot, Dot) => DotDotDot,
1049 (DotDot, Eq) => DotDotEq,
1050 (DotDot, _) => return None,
1051
1052 (Colon, Colon) => PathSep,
1053 (Colon, _) => return None,
1054
1055 (SingleQuote, Ident(name, is_raw)) => {
1056 Lifetime(Symbol::intern(&format!("'{name}")), *is_raw)
1057 }
1058 (SingleQuote, _) => return None,
1059
1060 (
1061 Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq
1062 | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
1063 | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
1064 | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
1065 | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof,
1066 _,
1067 ) => {
1068 return None;
1069 }
1070 };
1071
1072 Some(Token::new(kind, self.span.to(joint.span)))
1073 }
1074}
1075
1076impl PartialEq<TokenKind> for Token {
1077 #[inline]
1078 fn eq(&self, rhs: &TokenKind) -> bool {
1079 self.kind == *rhs
1080 }
1081}
1082
1083#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
1084pub enum NtPatKind {
1085 PatWithOr,
1087 PatParam { inferred: bool },
1091}
1092
1093#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
1094pub enum NtExprKind {
1095 Expr,
1098 Expr2021 { inferred: bool },
1102}
1103
1104#[derive(Clone, Encodable, Decodable)]
1105pub enum Nonterminal {
1107 NtBlock(P<ast::Block>),
1108 NtExpr(P<ast::Expr>),
1109 NtLiteral(P<ast::Expr>),
1110}
1111
1112#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
1113pub enum NonterminalKind {
1114 Item,
1115 Block,
1116 Stmt,
1117 Pat(NtPatKind),
1118 Expr(NtExprKind),
1119 Ty,
1120 Ident,
1121 Lifetime,
1122 Literal,
1123 Meta,
1124 Path,
1125 Vis,
1126 TT,
1127}
1128
1129impl NonterminalKind {
1130 pub fn from_symbol(
1133 symbol: Symbol,
1134 edition: impl FnOnce() -> Edition,
1135 ) -> Option<NonterminalKind> {
1136 Some(match symbol {
1137 sym::item => NonterminalKind::Item,
1138 sym::block => NonterminalKind::Block,
1139 sym::stmt => NonterminalKind::Stmt,
1140 sym::pat => {
1141 if edition().at_least_rust_2021() {
1142 NonterminalKind::Pat(PatWithOr)
1143 } else {
1144 NonterminalKind::Pat(PatParam { inferred: true })
1145 }
1146 }
1147 sym::pat_param => NonterminalKind::Pat(PatParam { inferred: false }),
1148 sym::expr => {
1149 if edition().at_least_rust_2024() {
1150 NonterminalKind::Expr(Expr)
1151 } else {
1152 NonterminalKind::Expr(Expr2021 { inferred: true })
1153 }
1154 }
1155 sym::expr_2021 => NonterminalKind::Expr(Expr2021 { inferred: false }),
1156 sym::ty => NonterminalKind::Ty,
1157 sym::ident => NonterminalKind::Ident,
1158 sym::lifetime => NonterminalKind::Lifetime,
1159 sym::literal => NonterminalKind::Literal,
1160 sym::meta => NonterminalKind::Meta,
1161 sym::path => NonterminalKind::Path,
1162 sym::vis => NonterminalKind::Vis,
1163 sym::tt => NonterminalKind::TT,
1164 _ => return None,
1165 })
1166 }
1167
1168 fn symbol(self) -> Symbol {
1169 match self {
1170 NonterminalKind::Item => sym::item,
1171 NonterminalKind::Block => sym::block,
1172 NonterminalKind::Stmt => sym::stmt,
1173 NonterminalKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
1174 NonterminalKind::Pat(PatParam { inferred: false }) => sym::pat_param,
1175 NonterminalKind::Expr(Expr2021 { inferred: true } | Expr) => sym::expr,
1176 NonterminalKind::Expr(Expr2021 { inferred: false }) => sym::expr_2021,
1177 NonterminalKind::Ty => sym::ty,
1178 NonterminalKind::Ident => sym::ident,
1179 NonterminalKind::Lifetime => sym::lifetime,
1180 NonterminalKind::Literal => sym::literal,
1181 NonterminalKind::Meta => sym::meta,
1182 NonterminalKind::Path => sym::path,
1183 NonterminalKind::Vis => sym::vis,
1184 NonterminalKind::TT => sym::tt,
1185 }
1186 }
1187}
1188
1189impl fmt::Display for NonterminalKind {
1190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1191 write!(f, "{}", self.symbol())
1192 }
1193}
1194
1195impl Nonterminal {
1196 pub fn use_span(&self) -> Span {
1197 match self {
1198 NtBlock(block) => block.span,
1199 NtExpr(expr) | NtLiteral(expr) => expr.span,
1200 }
1201 }
1202
1203 pub fn descr(&self) -> &'static str {
1204 match self {
1205 NtBlock(..) => "block",
1206 NtExpr(..) => "expression",
1207 NtLiteral(..) => "literal",
1208 }
1209 }
1210}
1211
1212impl PartialEq for Nonterminal {
1213 fn eq(&self, _rhs: &Self) -> bool {
1214 false
1219 }
1220}
1221
1222impl fmt::Debug for Nonterminal {
1223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1224 match *self {
1225 NtBlock(..) => f.pad("NtBlock(..)"),
1226 NtExpr(..) => f.pad("NtExpr(..)"),
1227 NtLiteral(..) => f.pad("NtLiteral(..)"),
1228 }
1229 }
1230}
1231
1232impl<CTX> HashStable<CTX> for Nonterminal
1233where
1234 CTX: crate::HashStableContext,
1235{
1236 fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
1237 panic!("interpolated tokens should not be present in the HIR")
1238 }
1239}
1240
1241#[cfg(target_pointer_width = "64")]
1243mod size_asserts {
1244 use rustc_data_structures::static_assert_size;
1245
1246 use super::*;
1247 static_assert_size!(Lit, 12);
1249 static_assert_size!(LitKind, 2);
1250 static_assert_size!(Nonterminal, 16);
1251 static_assert_size!(Token, 24);
1252 static_assert_size!(TokenKind, 16);
1253 }