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