]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_ast/src/token.rs
New upstream version 1.67.1+dfsg1
[rustc.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 // 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.
66 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
67 pub enum LitKind {
68 Bool, // AST only, must never appear in a `Token`
69 Byte,
70 Char,
71 Integer, // e.g. `1`, `1u8`, `1f32`
72 Float, // e.g. `1.`, `1.0`, `1e3f32`
73 Str,
74 StrRaw(u8), // raw string delimited by `n` hash symbols
75 ByteStr,
76 ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
77 Err,
78 }
79
80 /// A literal token.
81 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
82 pub struct Lit {
83 pub kind: LitKind,
84 pub symbol: Symbol,
85 pub suffix: Option<Symbol>,
86 }
87
88 impl 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 {
117 Some(token_lit.clone())
118 }
119 _ => None,
120 }
121 }
122 }
123
124 impl fmt::Display for Lit {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 let Lit { kind, symbol, suffix } = *self;
127 match kind {
128 Byte => write!(f, "b'{}'", symbol)?,
129 Char => write!(f, "'{}'", symbol)?,
130 Str => write!(f, "\"{}\"", symbol)?,
131 StrRaw(n) => write!(
132 f,
133 "r{delim}\"{string}\"{delim}",
134 delim = "#".repeat(n as usize),
135 string = symbol
136 )?,
137 ByteStr => write!(f, "b\"{}\"", symbol)?,
138 ByteStrRaw(n) => write!(
139 f,
140 "br{delim}\"{string}\"{delim}",
141 delim = "#".repeat(n as usize),
142 string = symbol
143 )?,
144 Integer | Float | Bool | Err => write!(f, "{}", symbol)?,
145 }
146
147 if let Some(suffix) = suffix {
148 write!(f, "{}", suffix)?;
149 }
150
151 Ok(())
152 }
153 }
154
155 impl LitKind {
156 /// An English article for the literal token kind.
157 pub fn article(self) -> &'static str {
158 match self {
159 Integer | Err => "an",
160 _ => "a",
161 }
162 }
163
164 pub fn descr(self) -> &'static str {
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
177 pub(crate) fn may_have_suffix(self) -> bool {
178 matches!(self, Integer | Float | Err)
179 }
180 }
181
182 pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
183 let ident_token = Token::new(Ident(name, is_raw), span);
184
185 !ident_token.is_reserved_ident()
186 || ident_token.is_path_segment_keyword()
187 || [
188 kw::Async,
189 kw::Do,
190 kw::Box,
191 kw::Break,
192 kw::Const,
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,
203 kw::Try,
204 kw::Unsafe,
205 kw::While,
206 kw::Yield,
207 kw::Static,
208 ]
209 .contains(&name)
210 }
211
212 fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
213 let ident_token = Token::new(Ident(name, is_raw), span);
214
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)
219 }
220
221 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
222 pub enum TokenKind {
223 /* Expression-operator symbols. */
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),
237
238 /* Structural symbols */
239 At,
240 Dot,
241 DotDot,
242 DotDotDot,
243 DotDotEq,
244 Comma,
245 Semi,
246 Colon,
247 ModSep,
248 RArrow,
249 LArrow,
250 FatArrow,
251 Pound,
252 Dollar,
253 Question,
254 /// Used by proc macros for representing lifetimes, not generated by lexer right now.
255 SingleQuote,
256 /// An opening delimiter (e.g., `{`).
257 OpenDelim(Delimiter),
258 /// A closing delimiter (e.g., `}`).
259 CloseDelim(Delimiter),
260
261 /* Literals */
262 Literal(Lit),
263
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.
268 Ident(Symbol, /* is_raw */ bool),
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.
273 Lifetime(Symbol),
274
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!
284 Interpolated(Lrc<Nonterminal>),
285
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),
290
291 Eof,
292 }
293
294 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
295 pub struct Token {
296 pub kind: TokenKind,
297 pub span: Span,
298 }
299
300 impl TokenKind {
301 pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
302 Literal(Lit::new(kind, symbol, suffix))
303 }
304
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`.
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
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.
340 pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
341 match *self {
342 Comma => Some(vec![Dot, Lt, Semi]),
343 Semi => Some(vec![Colon, Comma]),
344 FatArrow => Some(vec![Eq, RArrow]),
345 _ => None,
346 }
347 }
348
349 pub fn should_end_const_arg(&self) -> bool {
350 matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
351 }
352 }
353
354 impl Token {
355 pub fn new(kind: TokenKind, span: Span) -> Self {
356 Token { kind, span }
357 }
358
359 /// Some token that will be thrown away later.
360 pub fn dummy() -> Self {
361 Token::new(TokenKind::Question, DUMMY_SP)
362 }
363
364 /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
365 pub fn from_ast_ident(ident: Ident) -> Self {
366 Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
367 }
368
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
382 pub fn is_op(&self) -> bool {
383 match self.kind {
384 Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
385 | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
386 | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
387
388 OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
389 | Lifetime(..) | Interpolated(..) | Eof => false,
390 }
391 }
392
393 pub fn is_like_plus(&self) -> bool {
394 matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
395 }
396
397 /// Returns `true` if the token can appear at the start of an expression.
398 pub fn can_begin_expr(&self) -> bool {
399 match self.uninterpolate().kind {
400 Ident(name, is_raw) =>
401 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
402 OpenDelim(..) | // tuple, array or block
403 Literal(..) | // literal
404 Not | // operator not
405 BinOp(Minus) | // unary minus
406 BinOp(Star) | // dereference
407 BinOp(Or) | OrOr | // closure
408 BinOp(And) | // reference
409 AndAnd | // double reference
410 // DotDotDot is no longer supported, but we need some way to display the error
411 DotDot | DotDotDot | DotDotEq | // range notation
412 Lt | BinOp(Shl) | // associated path
413 ModSep | // global path
414 Lifetime(..) | // labeled loop
415 Pound => true, // expression attributes
416 Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
417 NtExpr(..) |
418 NtBlock(..) |
419 NtPath(..)),
420 _ => false,
421 }
422 }
423
424 /// Returns `true` if the token can appear at the start of an pattern.
425 ///
426 /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
427 pub fn can_begin_pattern(&self) -> bool {
428 match self.uninterpolate().kind {
429 Ident(name, is_raw) =>
430 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
431 | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array
432 | Literal(..) // literal
433 | BinOp(Minus) // unary minus
434 | BinOp(And) // reference
435 | AndAnd // double reference
436 // DotDotDot is no longer supported
437 | DotDot | DotDotDot | DotDotEq // ranges
438 | Lt | BinOp(Shl) // associated path
439 | ModSep => true, // global path
440 Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
441 NtPat(..) |
442 NtBlock(..) |
443 NtPath(..)),
444 _ => false,
445 }
446 }
447
448 /// Returns `true` if the token can appear at the start of a type.
449 pub fn can_begin_type(&self) -> bool {
450 match self.uninterpolate().kind {
451 Ident(name, is_raw) =>
452 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
453 OpenDelim(Delimiter::Parenthesis) | // tuple
454 OpenDelim(Delimiter::Bracket) | // array
455 Not | // never
456 BinOp(Star) | // raw pointer
457 BinOp(And) | // reference
458 AndAnd | // double reference
459 Question | // maybe bound in trait object
460 Lifetime(..) | // lifetime bound in trait object
461 Lt | BinOp(Shl) | // associated path
462 ModSep => true, // global path
463 Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
464 _ => false,
465 }
466 }
467
468 /// Returns `true` if the token can appear at the start of a const param.
469 pub fn can_begin_const_arg(&self) -> bool {
470 match self.kind {
471 OpenDelim(Delimiter::Brace) => true,
472 Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
473 _ => self.can_begin_literal_maybe_minus(),
474 }
475 }
476
477 /// Returns `true` if the token can appear at the start of a generic bound.
478 pub fn can_begin_bound(&self) -> bool {
479 self.is_path_start()
480 || self.is_lifetime()
481 || self.is_keyword(kw::For)
482 || self == &Question
483 || self == &OpenDelim(Delimiter::Parenthesis)
484 }
485
486 /// Returns `true` if the token can appear at the start of an item.
487 pub fn can_begin_item(&self) -> bool {
488 match self.kind {
489 Ident(name, _) => [
490 kw::Fn,
491 kw::Use,
492 kw::Struct,
493 kw::Enum,
494 kw::Pub,
495 kw::Trait,
496 kw::Extern,
497 kw::Impl,
498 kw::Unsafe,
499 kw::Const,
500 kw::Static,
501 kw::Union,
502 kw::Macro,
503 kw::Mod,
504 kw::Type,
505 ]
506 .contains(&name),
507 _ => false,
508 }
509 }
510
511 /// Returns `true` if the token is any literal.
512 pub fn is_lit(&self) -> bool {
513 matches!(self.kind, Literal(..))
514 }
515
516 /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
517 /// for example a '-42', or one of the boolean idents).
518 ///
519 /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
520 ///
521 /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
522 pub fn can_begin_literal_maybe_minus(&self) -> bool {
523 match self.uninterpolate().kind {
524 Literal(..) | BinOp(Minus) => true,
525 Ident(name, false) if name.is_bool_lit() => true,
526 Interpolated(ref nt) => match &**nt {
527 NtLiteral(_) => true,
528 NtExpr(e) => match &e.kind {
529 ast::ExprKind::Lit(_) => true,
530 ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
531 matches!(&e.kind, ast::ExprKind::Lit(_))
532 }
533 _ => false,
534 },
535 _ => false,
536 },
537 _ => false,
538 }
539 }
540
541 /// A convenience function for matching on identifiers during parsing.
542 /// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
543 /// into the regular identifier or lifetime token it refers to,
544 /// otherwise returns the original token.
545 pub fn uninterpolate(&self) -> Cow<'_, Token> {
546 match &self.kind {
547 Interpolated(nt) => match **nt {
548 NtIdent(ident, is_raw) => {
549 Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
550 }
551 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
552 _ => Cow::Borrowed(self),
553 },
554 _ => Cow::Borrowed(self),
555 }
556 }
557
558 /// Returns an identifier if this token is an identifier.
559 #[inline]
560 pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
561 // We avoid using `Token::uninterpolate` here because it's slow.
562 match &self.kind {
563 &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
564 Interpolated(nt) => match **nt {
565 NtIdent(ident, is_raw) => Some((ident, is_raw)),
566 _ => None,
567 },
568 _ => None,
569 }
570 }
571
572 /// Returns a lifetime identifier if this token is a lifetime.
573 #[inline]
574 pub fn lifetime(&self) -> Option<Ident> {
575 // We avoid using `Token::uninterpolate` here because it's slow.
576 match &self.kind {
577 &Lifetime(name) => Some(Ident::new(name, self.span)),
578 Interpolated(nt) => match **nt {
579 NtLifetime(ident) => Some(ident),
580 _ => None,
581 },
582 _ => None,
583 }
584 }
585
586 /// Returns `true` if the token is an identifier.
587 pub fn is_ident(&self) -> bool {
588 self.ident().is_some()
589 }
590
591 /// Returns `true` if the token is a lifetime.
592 pub fn is_lifetime(&self) -> bool {
593 self.lifetime().is_some()
594 }
595
596 /// Returns `true` if the token is an identifier whose name is the given
597 /// string slice.
598 pub fn is_ident_named(&self, name: Symbol) -> bool {
599 self.ident().map_or(false, |(ident, _)| ident.name == name)
600 }
601
602 /// Returns `true` if the token is an interpolated path.
603 fn is_path(&self) -> bool {
604 if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt {
605 return true;
606 }
607
608 false
609 }
610
611 /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
612 /// That is, is this a pre-parsed expression dropped into the token stream
613 /// (which happens while parsing the result of macro expansion)?
614 pub fn is_whole_expr(&self) -> bool {
615 if let Interpolated(nt) = &self.kind
616 && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
617 {
618 return true;
619 }
620
621 false
622 }
623
624 /// Is the token an interpolated block (`$b:block`)?
625 pub fn is_whole_block(&self) -> bool {
626 if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt {
627 return true;
628 }
629
630 false
631 }
632
633 /// Returns `true` if the token is either the `mut` or `const` keyword.
634 pub fn is_mutability(&self) -> bool {
635 self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
636 }
637
638 pub fn is_qpath_start(&self) -> bool {
639 self == &Lt || self == &BinOp(Shl)
640 }
641
642 pub fn is_path_start(&self) -> bool {
643 self == &ModSep
644 || self.is_qpath_start()
645 || self.is_path()
646 || self.is_path_segment_keyword()
647 || self.is_ident() && !self.is_reserved_ident()
648 }
649
650 /// Returns `true` if the token is a given keyword, `kw`.
651 pub fn is_keyword(&self, kw: Symbol) -> bool {
652 self.is_non_raw_ident_where(|id| id.name == kw)
653 }
654
655 /// 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.
656 pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
657 self.is_keyword(kw)
658 || (case == Case::Insensitive
659 && self.is_non_raw_ident_where(|id| {
660 id.name.as_str().to_lowercase() == kw.as_str().to_lowercase()
661 }))
662 }
663
664 pub fn is_path_segment_keyword(&self) -> bool {
665 self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
666 }
667
668 /// Returns true for reserved identifiers used internally for elided lifetimes,
669 /// unnamed method parameters, crate root module, error recovery etc.
670 pub fn is_special_ident(&self) -> bool {
671 self.is_non_raw_ident_where(Ident::is_special)
672 }
673
674 /// Returns `true` if the token is a keyword used in the language.
675 pub fn is_used_keyword(&self) -> bool {
676 self.is_non_raw_ident_where(Ident::is_used_keyword)
677 }
678
679 /// Returns `true` if the token is a keyword reserved for possible future use.
680 pub fn is_unused_keyword(&self) -> bool {
681 self.is_non_raw_ident_where(Ident::is_unused_keyword)
682 }
683
684 /// Returns `true` if the token is either a special identifier or a keyword.
685 pub fn is_reserved_ident(&self) -> bool {
686 self.is_non_raw_ident_where(Ident::is_reserved)
687 }
688
689 /// Returns `true` if the token is the identifier `true` or `false`.
690 pub fn is_bool_lit(&self) -> bool {
691 self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
692 }
693
694 pub fn is_numeric_lit(&self) -> bool {
695 matches!(
696 self.kind,
697 Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
698 )
699 }
700
701 /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
702 pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
703 match self.ident() {
704 Some((id, false)) => pred(id),
705 _ => false,
706 }
707 }
708
709 pub fn glue(&self, joint: &Token) -> Option<Token> {
710 let kind = match self.kind {
711 Eq => match joint.kind {
712 Eq => EqEq,
713 Gt => FatArrow,
714 _ => return None,
715 },
716 Lt => match joint.kind {
717 Eq => Le,
718 Lt => BinOp(Shl),
719 Le => BinOpEq(Shl),
720 BinOp(Minus) => LArrow,
721 _ => return None,
722 },
723 Gt => match joint.kind {
724 Eq => Ge,
725 Gt => BinOp(Shr),
726 Ge => BinOpEq(Shr),
727 _ => return None,
728 },
729 Not => match joint.kind {
730 Eq => Ne,
731 _ => return None,
732 },
733 BinOp(op) => match joint.kind {
734 Eq => BinOpEq(op),
735 BinOp(And) if op == And => AndAnd,
736 BinOp(Or) if op == Or => OrOr,
737 Gt if op == Minus => RArrow,
738 _ => return None,
739 },
740 Dot => match joint.kind {
741 Dot => DotDot,
742 DotDot => DotDotDot,
743 _ => return None,
744 },
745 DotDot => match joint.kind {
746 Dot => DotDotDot,
747 Eq => DotDotEq,
748 _ => return None,
749 },
750 Colon => match joint.kind {
751 Colon => ModSep,
752 _ => return None,
753 },
754 SingleQuote => match joint.kind {
755 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
756 _ => return None,
757 },
758
759 Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
760 | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
761 | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
762 | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
763 };
764
765 Some(Token::new(kind, self.span.to(joint.span)))
766 }
767 }
768
769 impl PartialEq<TokenKind> for Token {
770 #[inline]
771 fn eq(&self, rhs: &TokenKind) -> bool {
772 self.kind == *rhs
773 }
774 }
775
776 #[derive(Clone, Encodable, Decodable)]
777 /// For interpolation during macro expansion.
778 pub enum Nonterminal {
779 NtItem(P<ast::Item>),
780 NtBlock(P<ast::Block>),
781 NtStmt(P<ast::Stmt>),
782 NtPat(P<ast::Pat>),
783 NtExpr(P<ast::Expr>),
784 NtTy(P<ast::Ty>),
785 NtIdent(Ident, /* is_raw */ bool),
786 NtLifetime(Ident),
787 NtLiteral(P<ast::Expr>),
788 /// Stuff inside brackets for attributes
789 NtMeta(P<ast::AttrItem>),
790 NtPath(P<ast::Path>),
791 NtVis(P<ast::Visibility>),
792 }
793
794 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
795 pub enum NonterminalKind {
796 Item,
797 Block,
798 Stmt,
799 PatParam {
800 /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
801 /// edition of the span. This is used for diagnostics.
802 inferred: bool,
803 },
804 PatWithOr,
805 Expr,
806 Ty,
807 Ident,
808 Lifetime,
809 Literal,
810 Meta,
811 Path,
812 Vis,
813 TT,
814 }
815
816 impl NonterminalKind {
817 /// The `edition` closure is used to get the edition for the given symbol. Doing
818 /// `span.edition()` is expensive, so we do it lazily.
819 pub fn from_symbol(
820 symbol: Symbol,
821 edition: impl FnOnce() -> Edition,
822 ) -> Option<NonterminalKind> {
823 Some(match symbol {
824 sym::item => NonterminalKind::Item,
825 sym::block => NonterminalKind::Block,
826 sym::stmt => NonterminalKind::Stmt,
827 sym::pat => match edition() {
828 Edition::Edition2015 | Edition::Edition2018 => {
829 NonterminalKind::PatParam { inferred: true }
830 }
831 Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
832 },
833 sym::pat_param => NonterminalKind::PatParam { inferred: false },
834 sym::expr => NonterminalKind::Expr,
835 sym::ty => NonterminalKind::Ty,
836 sym::ident => NonterminalKind::Ident,
837 sym::lifetime => NonterminalKind::Lifetime,
838 sym::literal => NonterminalKind::Literal,
839 sym::meta => NonterminalKind::Meta,
840 sym::path => NonterminalKind::Path,
841 sym::vis => NonterminalKind::Vis,
842 sym::tt => NonterminalKind::TT,
843 _ => return None,
844 })
845 }
846 fn symbol(self) -> Symbol {
847 match self {
848 NonterminalKind::Item => sym::item,
849 NonterminalKind::Block => sym::block,
850 NonterminalKind::Stmt => sym::stmt,
851 NonterminalKind::PatParam { inferred: false } => sym::pat_param,
852 NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
853 NonterminalKind::Expr => sym::expr,
854 NonterminalKind::Ty => sym::ty,
855 NonterminalKind::Ident => sym::ident,
856 NonterminalKind::Lifetime => sym::lifetime,
857 NonterminalKind::Literal => sym::literal,
858 NonterminalKind::Meta => sym::meta,
859 NonterminalKind::Path => sym::path,
860 NonterminalKind::Vis => sym::vis,
861 NonterminalKind::TT => sym::tt,
862 }
863 }
864 }
865
866 impl fmt::Display for NonterminalKind {
867 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
868 write!(f, "{}", self.symbol())
869 }
870 }
871
872 impl Nonterminal {
873 pub fn span(&self) -> Span {
874 match self {
875 NtItem(item) => item.span,
876 NtBlock(block) => block.span,
877 NtStmt(stmt) => stmt.span,
878 NtPat(pat) => pat.span,
879 NtExpr(expr) | NtLiteral(expr) => expr.span,
880 NtTy(ty) => ty.span,
881 NtIdent(ident, _) | NtLifetime(ident) => ident.span,
882 NtMeta(attr_item) => attr_item.span(),
883 NtPath(path) => path.span,
884 NtVis(vis) => vis.span,
885 }
886 }
887 }
888
889 impl PartialEq for Nonterminal {
890 fn eq(&self, rhs: &Self) -> bool {
891 match (self, rhs) {
892 (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
893 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
894 }
895 (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
896 // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
897 // correctly based on data from AST. This will prevent them from matching each other
898 // in macros. The comparison will become possible only when each nonterminal has an
899 // attached token stream from which it was parsed.
900 _ => false,
901 }
902 }
903 }
904
905 impl fmt::Debug for Nonterminal {
906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907 match *self {
908 NtItem(..) => f.pad("NtItem(..)"),
909 NtBlock(..) => f.pad("NtBlock(..)"),
910 NtStmt(..) => f.pad("NtStmt(..)"),
911 NtPat(..) => f.pad("NtPat(..)"),
912 NtExpr(..) => f.pad("NtExpr(..)"),
913 NtTy(..) => f.pad("NtTy(..)"),
914 NtIdent(..) => f.pad("NtIdent(..)"),
915 NtLiteral(..) => f.pad("NtLiteral(..)"),
916 NtMeta(..) => f.pad("NtMeta(..)"),
917 NtPath(..) => f.pad("NtPath(..)"),
918 NtVis(..) => f.pad("NtVis(..)"),
919 NtLifetime(..) => f.pad("NtLifetime(..)"),
920 }
921 }
922 }
923
924 impl<CTX> HashStable<CTX> for Nonterminal
925 where
926 CTX: crate::HashStableContext,
927 {
928 fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
929 panic!("interpolated tokens should not be present in the HIR")
930 }
931 }
932
933 // Some types are used a lot. Make sure they don't unintentionally get bigger.
934 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
935 mod size_asserts {
936 use super::*;
937 use rustc_data_structures::static_assert_size;
938 // tidy-alphabetical-start
939 static_assert_size!(Lit, 12);
940 static_assert_size!(LitKind, 2);
941 static_assert_size!(Nonterminal, 16);
942 static_assert_size!(Token, 24);
943 static_assert_size!(TokenKind, 16);
944 // tidy-alphabetical-end
945 }