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