]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | pub use BinOpToken::*; |
2 | pub use Nonterminal::*; | |
3 | pub use DelimToken::*; | |
dc9dc135 XL |
4 | pub use LitKind::*; |
5 | pub use TokenKind::*; | |
9fa01778 | 6 | |
e74abb32 | 7 | use crate::ast; |
9fa01778 | 8 | use crate::ptr::P; |
dc9dc135 | 9 | use crate::symbol::kw; |
e74abb32 | 10 | use crate::tokenstream::TokenTree; |
9fa01778 | 11 | |
dc9dc135 | 12 | use syntax_pos::symbol::Symbol; |
e74abb32 | 13 | use syntax_pos::{self, Span, DUMMY_SP}; |
223e47cc | 14 | |
9fa01778 | 15 | use std::fmt; |
83c7162d | 16 | use std::mem; |
9fa01778 | 17 | #[cfg(target_arch = "x86_64")] |
48663c56 | 18 | use rustc_data_structures::static_assert_size; |
9fa01778 | 19 | use rustc_data_structures::sync::Lrc; |
1a4d82fc | 20 | |
8faf50e0 | 21 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] |
1a4d82fc JJ |
22 | pub enum BinOpToken { |
23 | Plus, | |
24 | Minus, | |
25 | Star, | |
26 | Slash, | |
27 | Percent, | |
28 | Caret, | |
29 | And, | |
30 | Or, | |
31 | Shl, | |
32 | Shr, | |
33 | } | |
34 | ||
9fa01778 | 35 | /// A delimiter token. |
e74abb32 | 36 | #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] |
1a4d82fc | 37 | pub enum DelimToken { |
9fa01778 | 38 | /// A round parenthesis (i.e., `(` or `)`). |
1a4d82fc | 39 | Paren, |
9fa01778 | 40 | /// A square bracket (i.e., `[` or `]`). |
1a4d82fc | 41 | Bracket, |
9fa01778 | 42 | /// A curly brace (i.e., `{` or `}`). |
1a4d82fc | 43 | Brace, |
9fa01778 | 44 | /// An empty delimiter. |
5bcae85e | 45 | NoDelim, |
1a4d82fc JJ |
46 | } |
47 | ||
32a655c1 | 48 | impl DelimToken { |
8bb4bdeb XL |
49 | pub fn len(self) -> usize { |
50 | if self == NoDelim { 0 } else { 1 } | |
32a655c1 | 51 | } |
7cac9316 XL |
52 | |
53 | pub fn is_empty(self) -> bool { | |
54 | self == NoDelim | |
55 | } | |
32a655c1 SL |
56 | } |
57 | ||
dc9dc135 XL |
58 | #[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] |
59 | pub enum LitKind { | |
60 | Bool, // AST only, must never appear in a `Token` | |
61 | Byte, | |
62 | Char, | |
63 | Integer, | |
64 | Float, | |
65 | Str, | |
66 | StrRaw(u16), // raw string delimited by `n` hash symbols | |
67 | ByteStr, | |
68 | ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols | |
69 | Err, | |
1a4d82fc JJ |
70 | } |
71 | ||
dc9dc135 XL |
72 | /// A literal token. |
73 | #[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] | |
74 | pub struct Lit { | |
75 | pub kind: LitKind, | |
76 | pub symbol: Symbol, | |
77 | pub suffix: Option<Symbol>, | |
78 | } | |
48663c56 | 79 | |
416331ca XL |
80 | impl fmt::Display for Lit { |
81 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
82 | let Lit { kind, symbol, suffix } = *self; | |
83 | match kind { | |
84 | Byte => write!(f, "b'{}'", symbol)?, | |
85 | Char => write!(f, "'{}'", symbol)?, | |
86 | Str => write!(f, "\"{}\"", symbol)?, | |
87 | StrRaw(n) => write!(f, "r{delim}\"{string}\"{delim}", | |
88 | delim="#".repeat(n as usize), | |
89 | string=symbol)?, | |
90 | ByteStr => write!(f, "b\"{}\"", symbol)?, | |
91 | ByteStrRaw(n) => write!(f, "br{delim}\"{string}\"{delim}", | |
92 | delim="#".repeat(n as usize), | |
93 | string=symbol)?, | |
94 | Integer | | |
95 | Float | | |
96 | Bool | | |
97 | Err => write!(f, "{}", symbol)?, | |
98 | } | |
99 | ||
100 | if let Some(suffix) = suffix { | |
101 | write!(f, "{}", suffix)?; | |
102 | } | |
103 | ||
104 | Ok(()) | |
105 | } | |
106 | } | |
107 | ||
dc9dc135 XL |
108 | impl LitKind { |
109 | /// An English article for the literal token kind. | |
110 | crate fn article(self) -> &'static str { | |
111 | match self { | |
112 | Integer | Err => "an", | |
113 | _ => "a", | |
1a4d82fc JJ |
114 | } |
115 | } | |
83c7162d | 116 | |
dc9dc135 XL |
117 | crate fn descr(self) -> &'static str { |
118 | match self { | |
119 | Bool => panic!("literal token contains `Lit::Bool`"), | |
120 | Byte => "byte", | |
121 | Char => "char", | |
122 | Integer => "integer", | |
123 | Float => "float", | |
124 | Str | StrRaw(..) => "string", | |
125 | ByteStr | ByteStrRaw(..) => "byte string", | |
126 | Err => "error", | |
127 | } | |
128 | } | |
129 | ||
130 | crate fn may_have_suffix(self) -> bool { | |
131 | match self { | |
132 | Integer | Float | Err => true, | |
48663c56 XL |
133 | _ => false, |
134 | } | |
135 | } | |
dc9dc135 | 136 | } |
48663c56 | 137 | |
dc9dc135 XL |
138 | impl Lit { |
139 | pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit { | |
140 | Lit { kind, symbol, suffix } | |
83c7162d | 141 | } |
1a4d82fc JJ |
142 | } |
143 | ||
dc9dc135 XL |
144 | pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool { |
145 | let ident_token = Token::new(Ident(name, is_raw), span); | |
e74abb32 XL |
146 | token_can_begin_expr(&ident_token) |
147 | } | |
32a655c1 | 148 | |
e74abb32 | 149 | pub(crate) fn token_can_begin_expr(ident_token: &Token) -> bool { |
041b39d2 | 150 | !ident_token.is_reserved_ident() || |
32a655c1 | 151 | ident_token.is_path_segment_keyword() || |
e74abb32 XL |
152 | match ident_token.kind { |
153 | TokenKind::Ident(ident, _) => [ | |
154 | kw::Async, | |
155 | kw::Do, | |
156 | kw::Box, | |
157 | kw::Break, | |
158 | kw::Continue, | |
159 | kw::False, | |
160 | kw::For, | |
161 | kw::If, | |
162 | kw::Let, | |
163 | kw::Loop, | |
164 | kw::Match, | |
165 | kw::Move, | |
166 | kw::Return, | |
167 | kw::True, | |
168 | kw::Unsafe, | |
169 | kw::While, | |
170 | kw::Yield, | |
171 | kw::Static, | |
172 | ].contains(&ident), | |
173 | _=> false, | |
174 | } | |
32a655c1 SL |
175 | } |
176 | ||
dc9dc135 XL |
177 | fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool { |
178 | let ident_token = Token::new(Ident(name, is_raw), span); | |
cc61c64b | 179 | |
041b39d2 | 180 | !ident_token.is_reserved_ident() || |
cc61c64b XL |
181 | ident_token.is_path_segment_keyword() || |
182 | [ | |
dc9dc135 XL |
183 | kw::Underscore, |
184 | kw::For, | |
185 | kw::Impl, | |
186 | kw::Fn, | |
187 | kw::Unsafe, | |
188 | kw::Extern, | |
189 | kw::Typeof, | |
190 | kw::Dyn, | |
191 | ].contains(&name) | |
cc61c64b XL |
192 | } |
193 | ||
dc9dc135 XL |
194 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] |
195 | pub enum TokenKind { | |
223e47cc | 196 | /* Expression-operator symbols. */ |
1a4d82fc JJ |
197 | Eq, |
198 | Lt, | |
199 | Le, | |
200 | EqEq, | |
201 | Ne, | |
202 | Ge, | |
203 | Gt, | |
204 | AndAnd, | |
205 | OrOr, | |
206 | Not, | |
207 | Tilde, | |
208 | BinOp(BinOpToken), | |
209 | BinOpEq(BinOpToken), | |
223e47cc LB |
210 | |
211 | /* Structural symbols */ | |
1a4d82fc JJ |
212 | At, |
213 | Dot, | |
214 | DotDot, | |
215 | DotDotDot, | |
ea8adc8c | 216 | DotDotEq, |
1a4d82fc JJ |
217 | Comma, |
218 | Semi, | |
219 | Colon, | |
220 | ModSep, | |
221 | RArrow, | |
222 | LArrow, | |
223 | FatArrow, | |
224 | Pound, | |
225 | Dollar, | |
226 | Question, | |
94b46f34 XL |
227 | /// Used by proc macros for representing lifetimes, not generated by lexer right now. |
228 | SingleQuote, | |
9fa01778 | 229 | /// An opening delimiter (e.g., `{`). |
1a4d82fc | 230 | OpenDelim(DelimToken), |
9fa01778 | 231 | /// A closing delimiter (e.g., `}`). |
1a4d82fc | 232 | CloseDelim(DelimToken), |
223e47cc LB |
233 | |
234 | /* Literals */ | |
dc9dc135 | 235 | Literal(Lit), |
223e47cc LB |
236 | |
237 | /* Name components */ | |
dc9dc135 XL |
238 | Ident(ast::Name, /* is_raw */ bool), |
239 | Lifetime(ast::Name), | |
223e47cc | 240 | |
9fa01778 XL |
241 | Interpolated(Lrc<Nonterminal>), |
242 | ||
1a4d82fc | 243 | // Can be expanded into several tokens. |
9fa01778 | 244 | /// A doc comment. |
1a4d82fc | 245 | DocComment(ast::Name), |
1a4d82fc JJ |
246 | |
247 | // Junk. These carry no data because we don't really care about the data | |
248 | // they *would* carry, and don't really want to allocate a new ident for | |
249 | // them. Instead, users could extract that from the associated span. | |
250 | ||
9fa01778 | 251 | /// Whitespace. |
1a4d82fc | 252 | Whitespace, |
9fa01778 | 253 | /// A comment. |
1a4d82fc JJ |
254 | Comment, |
255 | Shebang(ast::Name), | |
416331ca XL |
256 | /// A completely invalid token which should be skipped. |
257 | Unknown(ast::Name), | |
1a4d82fc JJ |
258 | |
259 | Eof, | |
260 | } | |
261 | ||
dc9dc135 | 262 | // `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger. |
0731742a | 263 | #[cfg(target_arch = "x86_64")] |
dc9dc135 XL |
264 | static_assert_size!(TokenKind, 16); |
265 | ||
266 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] | |
267 | pub struct Token { | |
268 | pub kind: TokenKind, | |
269 | pub span: Span, | |
270 | } | |
271 | ||
272 | impl TokenKind { | |
273 | pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind { | |
274 | Literal(Lit::new(kind, symbol, suffix)) | |
275 | } | |
276 | ||
277 | /// Returns tokens that are likely to be typed accidentally instead of the current token. | |
278 | /// Enables better error recovery when the wrong token is found. | |
279 | crate fn similar_tokens(&self) -> Option<Vec<TokenKind>> { | |
280 | match *self { | |
281 | Comma => Some(vec![Dot, Lt, Semi]), | |
282 | Semi => Some(vec![Colon, Comma]), | |
283 | _ => None | |
284 | } | |
285 | } | |
286 | } | |
0731742a | 287 | |
1a4d82fc | 288 | impl Token { |
e74abb32 | 289 | pub fn new(kind: TokenKind, span: Span) -> Self { |
dc9dc135 XL |
290 | Token { kind, span } |
291 | } | |
292 | ||
293 | /// Some token that will be thrown away later. | |
294 | crate fn dummy() -> Self { | |
295 | Token::new(TokenKind::Whitespace, DUMMY_SP) | |
296 | } | |
297 | ||
0531ce1d | 298 | /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary. |
e74abb32 | 299 | pub fn from_ast_ident(ident: ast::Ident) -> Self { |
dc9dc135 XL |
300 | Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) |
301 | } | |
302 | ||
303 | /// Return this token by value and leave a dummy token in its place. | |
e74abb32 | 304 | pub fn take(&mut self) -> Self { |
dc9dc135 XL |
305 | mem::replace(self, Token::dummy()) |
306 | } | |
307 | ||
308 | crate fn is_op(&self) -> bool { | |
309 | match self.kind { | |
310 | OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | | |
311 | Ident(..) | Lifetime(..) | Interpolated(..) | | |
312 | Whitespace | Comment | Shebang(..) | Eof => false, | |
313 | _ => true, | |
314 | } | |
041b39d2 XL |
315 | } |
316 | ||
94b46f34 | 317 | crate fn is_like_plus(&self) -> bool { |
dc9dc135 | 318 | match self.kind { |
94b46f34 | 319 | BinOp(Plus) | BinOpEq(Plus) => true, |
bd371182 AL |
320 | _ => false, |
321 | } | |
322 | } | |
323 | ||
1a4d82fc | 324 | /// Returns `true` if the token can appear at the start of an expression. |
e74abb32 | 325 | pub fn can_begin_expr(&self) -> bool { |
dc9dc135 XL |
326 | match self.kind { |
327 | Ident(name, is_raw) => | |
328 | ident_can_begin_expr(name, self.span, is_raw), // value name or keyword | |
ea8adc8c XL |
329 | OpenDelim(..) | // tuple, array or block |
330 | Literal(..) | // literal | |
331 | Not | // operator not | |
332 | BinOp(Minus) | // unary minus | |
333 | BinOp(Star) | // dereference | |
334 | BinOp(Or) | OrOr | // closure | |
335 | BinOp(And) | // reference | |
336 | AndAnd | // double reference | |
abe05a73 | 337 | // DotDotDot is no longer supported, but we need some way to display the error |
ea8adc8c | 338 | DotDot | DotDotDot | DotDotEq | // range notation |
ea8adc8c XL |
339 | Lt | BinOp(Shl) | // associated path |
340 | ModSep | // global path | |
83c7162d | 341 | Lifetime(..) | // labeled loop |
ea8adc8c | 342 | Pound => true, // expression attributes |
9fa01778 | 343 | Interpolated(ref nt) => match **nt { |
94b46f34 XL |
344 | NtLiteral(..) | |
345 | NtIdent(..) | | |
346 | NtExpr(..) | | |
347 | NtBlock(..) | | |
348 | NtPath(..) | | |
349 | NtLifetime(..) => true, | |
c30ab7b3 SL |
350 | _ => false, |
351 | }, | |
352 | _ => false, | |
1a4d82fc JJ |
353 | } |
354 | } | |
223e47cc | 355 | |
32a655c1 | 356 | /// Returns `true` if the token can appear at the start of a type. |
e74abb32 | 357 | pub fn can_begin_type(&self) -> bool { |
dc9dc135 XL |
358 | match self.kind { |
359 | Ident(name, is_raw) => | |
360 | ident_can_begin_type(name, self.span, is_raw), // type name or keyword | |
7cac9316 XL |
361 | OpenDelim(Paren) | // tuple |
362 | OpenDelim(Bracket) | // array | |
7cac9316 XL |
363 | Not | // never |
364 | BinOp(Star) | // raw pointer | |
365 | BinOp(And) | // reference | |
366 | AndAnd | // double reference | |
367 | Question | // maybe bound in trait object | |
368 | Lifetime(..) | // lifetime bound in trait object | |
369 | Lt | BinOp(Shl) | // associated path | |
32a655c1 | 370 | ModSep => true, // global path |
9fa01778 | 371 | Interpolated(ref nt) => match **nt { |
ff7c6d11 | 372 | NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true, |
32a655c1 SL |
373 | _ => false, |
374 | }, | |
375 | _ => false, | |
376 | } | |
377 | } | |
378 | ||
9fa01778 | 379 | /// Returns `true` if the token can appear at the start of a const param. |
dc9dc135 XL |
380 | crate fn can_begin_const_arg(&self) -> bool { |
381 | match self.kind { | |
9fa01778 XL |
382 | OpenDelim(Brace) => true, |
383 | Interpolated(ref nt) => match **nt { | |
384 | NtExpr(..) => true, | |
385 | NtBlock(..) => true, | |
386 | NtLiteral(..) => true, | |
387 | _ => false, | |
388 | } | |
389 | _ => self.can_begin_literal_or_bool(), | |
390 | } | |
391 | } | |
392 | ||
abe05a73 | 393 | /// Returns `true` if the token can appear at the start of a generic bound. |
94b46f34 | 394 | crate fn can_begin_bound(&self) -> bool { |
dc9dc135 | 395 | self.is_path_start() || self.is_lifetime() || self.is_keyword(kw::For) || |
abe05a73 XL |
396 | self == &Question || self == &OpenDelim(Paren) |
397 | } | |
398 | ||
1a4d82fc | 399 | /// Returns `true` if the token is any literal |
e74abb32 | 400 | pub fn is_lit(&self) -> bool { |
dc9dc135 | 401 | match self.kind { |
9e0c209e SL |
402 | Literal(..) => true, |
403 | _ => false, | |
1a4d82fc JJ |
404 | } |
405 | } | |
223e47cc | 406 | |
dc9dc135 XL |
407 | crate fn expect_lit(&self) -> Lit { |
408 | match self.kind { | |
409 | Literal(lit) => lit, | |
e1599b0c | 410 | _ => panic!("`expect_lit` called on non-literal"), |
dc9dc135 XL |
411 | } |
412 | } | |
413 | ||
9fa01778 | 414 | /// Returns `true` if the token is any literal, a minus (which can prefix a literal, |
94b46f34 | 415 | /// for example a '-42', or one of the boolean idents). |
e74abb32 | 416 | pub fn can_begin_literal_or_bool(&self) -> bool { |
dc9dc135 | 417 | match self.kind { |
e1599b0c XL |
418 | Literal(..) | BinOp(Minus) => true, |
419 | Ident(name, false) if name.is_bool_lit() => true, | |
9fa01778 | 420 | Interpolated(ref nt) => match **nt { |
b7449926 XL |
421 | NtLiteral(..) => true, |
422 | _ => false, | |
423 | }, | |
94b46f34 XL |
424 | _ => false, |
425 | } | |
426 | } | |
427 | ||
83c7162d XL |
428 | /// Returns an identifier if this token is an identifier. |
429 | pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { | |
dc9dc135 XL |
430 | match self.kind { |
431 | Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)), | |
9fa01778 | 432 | Interpolated(ref nt) => match **nt { |
83c7162d XL |
433 | NtIdent(ident, is_raw) => Some((ident, is_raw)), |
434 | _ => None, | |
435 | }, | |
436 | _ => None, | |
437 | } | |
438 | } | |
dc9dc135 | 439 | |
83c7162d XL |
440 | /// Returns a lifetime identifier if this token is a lifetime. |
441 | pub fn lifetime(&self) -> Option<ast::Ident> { | |
dc9dc135 XL |
442 | match self.kind { |
443 | Lifetime(name) => Some(ast::Ident::new(name, self.span)), | |
9fa01778 | 444 | Interpolated(ref nt) => match **nt { |
83c7162d | 445 | NtLifetime(ident) => Some(ident), |
cc61c64b XL |
446 | _ => None, |
447 | }, | |
448 | _ => None, | |
223e47cc | 449 | } |
1a4d82fc | 450 | } |
dc9dc135 | 451 | |
cc61c64b XL |
452 | /// Returns `true` if the token is an identifier. |
453 | pub fn is_ident(&self) -> bool { | |
454 | self.ident().is_some() | |
455 | } | |
e1599b0c | 456 | |
83c7162d | 457 | /// Returns `true` if the token is a lifetime. |
94b46f34 | 458 | crate fn is_lifetime(&self) -> bool { |
83c7162d XL |
459 | self.lifetime().is_some() |
460 | } | |
461 | ||
462 | /// Returns `true` if the token is a identifier whose name is the given | |
463 | /// string slice. | |
dc9dc135 XL |
464 | crate fn is_ident_named(&self, name: Symbol) -> bool { |
465 | self.ident().map_or(false, |(ident, _)| ident.name == name) | |
83c7162d | 466 | } |
cc61c64b | 467 | |
1a4d82fc | 468 | /// Returns `true` if the token is an interpolated path. |
94b46f34 | 469 | fn is_path(&self) -> bool { |
dc9dc135 | 470 | if let Interpolated(ref nt) = self.kind { |
9fa01778 | 471 | if let NtPath(..) = **nt { |
c30ab7b3 SL |
472 | return true; |
473 | } | |
1a4d82fc | 474 | } |
c30ab7b3 | 475 | false |
1a4d82fc JJ |
476 | } |
477 | ||
416331ca XL |
478 | /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? |
479 | /// That is, is this a pre-parsed expression dropped into the token stream | |
480 | /// (which happens while parsing the result of macro expansion)? | |
481 | crate fn is_whole_expr(&self) -> bool { | |
482 | if let Interpolated(ref nt) = self.kind { | |
483 | if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt { | |
484 | return true; | |
485 | } | |
486 | } | |
487 | ||
488 | false | |
489 | } | |
490 | ||
1a4d82fc | 491 | /// Returns `true` if the token is either the `mut` or `const` keyword. |
94b46f34 | 492 | crate fn is_mutability(&self) -> bool { |
dc9dc135 XL |
493 | self.is_keyword(kw::Mut) || |
494 | self.is_keyword(kw::Const) | |
1a4d82fc JJ |
495 | } |
496 | ||
94b46f34 | 497 | crate fn is_qpath_start(&self) -> bool { |
c30ab7b3 SL |
498 | self == &Lt || self == &BinOp(Shl) |
499 | } | |
500 | ||
94b46f34 | 501 | crate fn is_path_start(&self) -> bool { |
c30ab7b3 | 502 | self == &ModSep || self.is_qpath_start() || self.is_path() || |
041b39d2 | 503 | self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() |
a7813a04 XL |
504 | } |
505 | ||
1a4d82fc | 506 | /// Returns `true` if the token is a given keyword, `kw`. |
dc9dc135 | 507 | pub fn is_keyword(&self, kw: Symbol) -> bool { |
e1599b0c | 508 | self.is_non_raw_ident_where(|id| id.name == kw) |
1a4d82fc JJ |
509 | } |
510 | ||
dc9dc135 | 511 | crate fn is_path_segment_keyword(&self) -> bool { |
e1599b0c | 512 | self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword) |
1a4d82fc JJ |
513 | } |
514 | ||
041b39d2 XL |
515 | // Returns true for reserved identifiers used internally for elided lifetimes, |
516 | // unnamed method parameters, crate root module, error recovery etc. | |
dc9dc135 | 517 | crate fn is_special_ident(&self) -> bool { |
e1599b0c | 518 | self.is_non_raw_ident_where(ast::Ident::is_special) |
1a4d82fc JJ |
519 | } |
520 | ||
041b39d2 | 521 | /// Returns `true` if the token is a keyword used in the language. |
94b46f34 | 522 | crate fn is_used_keyword(&self) -> bool { |
e1599b0c | 523 | self.is_non_raw_ident_where(ast::Ident::is_used_keyword) |
1a4d82fc JJ |
524 | } |
525 | ||
a7813a04 | 526 | /// Returns `true` if the token is a keyword reserved for possible future use. |
94b46f34 | 527 | crate fn is_unused_keyword(&self) -> bool { |
e1599b0c | 528 | self.is_non_raw_ident_where(ast::Ident::is_unused_keyword) |
1a4d82fc | 529 | } |
041b39d2 | 530 | |
83c7162d XL |
531 | /// Returns `true` if the token is either a special identifier or a keyword. |
532 | pub fn is_reserved_ident(&self) -> bool { | |
e1599b0c XL |
533 | self.is_non_raw_ident_where(ast::Ident::is_reserved) |
534 | } | |
535 | ||
536 | /// Returns `true` if the token is the identifier `true` or `false`. | |
537 | crate fn is_bool_lit(&self) -> bool { | |
538 | self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) | |
539 | } | |
540 | ||
541 | /// Returns `true` if the token is a non-raw identifier for which `pred` holds. | |
542 | fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { | |
83c7162d | 543 | match self.ident() { |
e1599b0c | 544 | Some((id, false)) => pred(id), |
83c7162d XL |
545 | _ => false, |
546 | } | |
547 | } | |
548 | ||
e1599b0c | 549 | crate fn glue(&self, joint: &Token) -> Option<Token> { |
dc9dc135 XL |
550 | let kind = match self.kind { |
551 | Eq => match joint.kind { | |
041b39d2 XL |
552 | Eq => EqEq, |
553 | Gt => FatArrow, | |
554 | _ => return None, | |
555 | }, | |
dc9dc135 | 556 | Lt => match joint.kind { |
041b39d2 XL |
557 | Eq => Le, |
558 | Lt => BinOp(Shl), | |
559 | Le => BinOpEq(Shl), | |
560 | BinOp(Minus) => LArrow, | |
561 | _ => return None, | |
562 | }, | |
dc9dc135 | 563 | Gt => match joint.kind { |
041b39d2 XL |
564 | Eq => Ge, |
565 | Gt => BinOp(Shr), | |
566 | Ge => BinOpEq(Shr), | |
567 | _ => return None, | |
568 | }, | |
dc9dc135 | 569 | Not => match joint.kind { |
041b39d2 XL |
570 | Eq => Ne, |
571 | _ => return None, | |
572 | }, | |
dc9dc135 | 573 | BinOp(op) => match joint.kind { |
041b39d2 XL |
574 | Eq => BinOpEq(op), |
575 | BinOp(And) if op == And => AndAnd, | |
576 | BinOp(Or) if op == Or => OrOr, | |
577 | Gt if op == Minus => RArrow, | |
578 | _ => return None, | |
579 | }, | |
dc9dc135 | 580 | Dot => match joint.kind { |
041b39d2 XL |
581 | Dot => DotDot, |
582 | DotDot => DotDotDot, | |
583 | _ => return None, | |
584 | }, | |
dc9dc135 | 585 | DotDot => match joint.kind { |
041b39d2 | 586 | Dot => DotDotDot, |
ea8adc8c | 587 | Eq => DotDotEq, |
041b39d2 XL |
588 | _ => return None, |
589 | }, | |
dc9dc135 | 590 | Colon => match joint.kind { |
041b39d2 XL |
591 | Colon => ModSep, |
592 | _ => return None, | |
593 | }, | |
dc9dc135 XL |
594 | SingleQuote => match joint.kind { |
595 | Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))), | |
94b46f34 XL |
596 | _ => return None, |
597 | }, | |
041b39d2 | 598 | |
a1dfa0c6 | 599 | Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | |
ea8adc8c | 600 | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | |
9fa01778 | 601 | Question | OpenDelim(..) | CloseDelim(..) | |
041b39d2 | 602 | Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | |
416331ca | 603 | Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => return None, |
dc9dc135 | 604 | }; |
041b39d2 | 605 | |
dc9dc135 | 606 | Some(Token::new(kind, self.span.to(joint.span))) |
abe05a73 XL |
607 | } |
608 | ||
9fa01778 | 609 | // See comments in `Nonterminal::to_tokenstream` for why we care about |
83c7162d | 610 | // *probably* equal here rather than actual equality |
94b46f34 | 611 | crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { |
dc9dc135 | 612 | if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) { |
83c7162d XL |
613 | return false |
614 | } | |
dc9dc135 | 615 | match (&self.kind, &other.kind) { |
83c7162d XL |
616 | (&Eq, &Eq) | |
617 | (&Lt, &Lt) | | |
618 | (&Le, &Le) | | |
619 | (&EqEq, &EqEq) | | |
620 | (&Ne, &Ne) | | |
621 | (&Ge, &Ge) | | |
622 | (&Gt, &Gt) | | |
623 | (&AndAnd, &AndAnd) | | |
624 | (&OrOr, &OrOr) | | |
625 | (&Not, &Not) | | |
626 | (&Tilde, &Tilde) | | |
627 | (&At, &At) | | |
628 | (&Dot, &Dot) | | |
629 | (&DotDot, &DotDot) | | |
630 | (&DotDotDot, &DotDotDot) | | |
631 | (&DotDotEq, &DotDotEq) | | |
83c7162d XL |
632 | (&Comma, &Comma) | |
633 | (&Semi, &Semi) | | |
634 | (&Colon, &Colon) | | |
635 | (&ModSep, &ModSep) | | |
636 | (&RArrow, &RArrow) | | |
637 | (&LArrow, &LArrow) | | |
638 | (&FatArrow, &FatArrow) | | |
639 | (&Pound, &Pound) | | |
640 | (&Dollar, &Dollar) | | |
641 | (&Question, &Question) | | |
642 | (&Whitespace, &Whitespace) | | |
643 | (&Comment, &Comment) | | |
644 | (&Eof, &Eof) => true, | |
645 | ||
646 | (&BinOp(a), &BinOp(b)) | | |
647 | (&BinOpEq(a), &BinOpEq(b)) => a == b, | |
648 | ||
649 | (&OpenDelim(a), &OpenDelim(b)) | | |
650 | (&CloseDelim(a), &CloseDelim(b)) => a == b, | |
651 | ||
652 | (&DocComment(a), &DocComment(b)) | | |
653 | (&Shebang(a), &Shebang(b)) => a == b, | |
654 | ||
dc9dc135 | 655 | (&Literal(a), &Literal(b)) => a == b, |
83c7162d | 656 | |
dc9dc135 XL |
657 | (&Lifetime(a), &Lifetime(b)) => a == b, |
658 | (&Ident(a, b), &Ident(c, d)) => b == d && (a == c || | |
659 | a == kw::DollarCrate || | |
660 | c == kw::DollarCrate), | |
83c7162d XL |
661 | |
662 | (&Interpolated(_), &Interpolated(_)) => false, | |
663 | ||
664 | _ => panic!("forgot to add a token?"), | |
665 | } | |
ea8adc8c | 666 | } |
223e47cc LB |
667 | } |
668 | ||
dc9dc135 XL |
669 | impl PartialEq<TokenKind> for Token { |
670 | fn eq(&self, rhs: &TokenKind) -> bool { | |
671 | self.kind == *rhs | |
672 | } | |
673 | } | |
674 | ||
8faf50e0 | 675 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
1a4d82fc JJ |
676 | /// For interpolation during macro expansion. |
677 | pub enum Nonterminal { | |
678 | NtItem(P<ast::Item>), | |
679 | NtBlock(P<ast::Block>), | |
c30ab7b3 | 680 | NtStmt(ast::Stmt), |
1a4d82fc JJ |
681 | NtPat(P<ast::Pat>), |
682 | NtExpr(P<ast::Expr>), | |
683 | NtTy(P<ast::Ty>), | |
83c7162d XL |
684 | NtIdent(ast::Ident, /* is_raw */ bool), |
685 | NtLifetime(ast::Ident), | |
94b46f34 | 686 | NtLiteral(P<ast::Expr>), |
1a4d82fc | 687 | /// Stuff inside brackets for attributes |
e74abb32 | 688 | NtMeta(ast::AttrItem), |
c30ab7b3 | 689 | NtPath(ast::Path), |
cc61c64b XL |
690 | NtVis(ast::Visibility), |
691 | NtTT(TokenTree), | |
48663c56 XL |
692 | // Used only for passing items to proc macro attributes (they are not |
693 | // strictly necessary for that, `Annotatable` can be converted into | |
694 | // tokens directly, but doing that naively regresses pretty-printing). | |
c30ab7b3 | 695 | NtTraitItem(ast::TraitItem), |
48663c56 | 696 | NtImplItem(ast::ImplItem), |
83c7162d | 697 | NtForeignItem(ast::ForeignItem), |
83c7162d XL |
698 | } |
699 | ||
700 | impl PartialEq for Nonterminal { | |
701 | fn eq(&self, rhs: &Self) -> bool { | |
702 | match (self, rhs) { | |
703 | (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => | |
704 | ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs, | |
705 | (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs, | |
706 | (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs, | |
707 | // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them | |
708 | // correctly based on data from AST. This will prevent them from matching each other | |
709 | // in macros. The comparison will become possible only when each nonterminal has an | |
710 | // attached token stream from which it was parsed. | |
711 | _ => false, | |
712 | } | |
713 | } | |
1a4d82fc JJ |
714 | } |
715 | ||
85aaf69f | 716 | impl fmt::Debug for Nonterminal { |
9fa01778 | 717 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1a4d82fc JJ |
718 | match *self { |
719 | NtItem(..) => f.pad("NtItem(..)"), | |
720 | NtBlock(..) => f.pad("NtBlock(..)"), | |
721 | NtStmt(..) => f.pad("NtStmt(..)"), | |
722 | NtPat(..) => f.pad("NtPat(..)"), | |
723 | NtExpr(..) => f.pad("NtExpr(..)"), | |
724 | NtTy(..) => f.pad("NtTy(..)"), | |
725 | NtIdent(..) => f.pad("NtIdent(..)"), | |
94b46f34 | 726 | NtLiteral(..) => f.pad("NtLiteral(..)"), |
1a4d82fc JJ |
727 | NtMeta(..) => f.pad("NtMeta(..)"), |
728 | NtPath(..) => f.pad("NtPath(..)"), | |
729 | NtTT(..) => f.pad("NtTT(..)"), | |
d9579d0f AL |
730 | NtImplItem(..) => f.pad("NtImplItem(..)"), |
731 | NtTraitItem(..) => f.pad("NtTraitItem(..)"), | |
83c7162d | 732 | NtForeignItem(..) => f.pad("NtForeignItem(..)"), |
cc61c64b | 733 | NtVis(..) => f.pad("NtVis(..)"), |
ff7c6d11 | 734 | NtLifetime(..) => f.pad("NtLifetime(..)"), |
1a4d82fc | 735 | } |
970d7e83 LB |
736 | } |
737 | } |