blob: 2e540779018e90fea314efa22efeead82f0299e3 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnaye79ae182018-01-06 19:23:37 -08009//! Tokens representing Rust punctuation, keywords, and delimiters.
Alex Crichton954046c2017-05-30 21:49:42 -070010//!
David Tolnaye79ae182018-01-06 19:23:37 -080011//! The type names in this module can be difficult to keep straight, so we
12//! prefer to use the [`Token!`] macro instead. This is a type-macro that
13//! expands to the token type of the given token.
14//!
15//! [`Token!`]: ../macro.Token.html
16//!
17//! # Example
18//!
19//! The [`ItemStatic`] syntax tree node is defined like this.
20//!
21//! [`ItemStatic`]: ../struct.ItemStatic.html
22//!
23//! ```
David Tolnaye79ae182018-01-06 19:23:37 -080024//! # extern crate syn;
25//! #
David Tolnay9b00f652018-09-01 10:31:02 -070026//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility};
David Tolnaye79ae182018-01-06 19:23:37 -080027//! #
28//! pub struct ItemStatic {
29//! pub attrs: Vec<Attribute>,
30//! pub vis: Visibility,
31//! pub static_token: Token![static],
32//! pub mutability: Option<Token![mut]>,
33//! pub ident: Ident,
34//! pub colon_token: Token![:],
35//! pub ty: Box<Type>,
36//! pub eq_token: Token![=],
37//! pub expr: Box<Expr>,
38//! pub semi_token: Token![;],
39//! }
40//! #
41//! # fn main() {}
42//! ```
43//!
44//! # Parsing
45//!
David Tolnayd8cc0552018-08-31 08:39:17 -070046//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
47//! method. Delimiter tokens are parsed using the [`parenthesized!`],
48//! [`bracketed!`] and [`braced!`] macros.
David Tolnaye79ae182018-01-06 19:23:37 -080049//!
David Tolnayd8cc0552018-08-31 08:39:17 -070050//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
51//! [`parenthesized!`]: ../macro.parenthesized.html
52//! [`bracketed!`]: ../macro.bracketed.html
53//! [`braced!`]: ../macro.braced.html
David Tolnaye79ae182018-01-06 19:23:37 -080054//!
55//! ```
David Tolnay9b00f652018-09-01 10:31:02 -070056//! # extern crate syn;
57//! #
David Tolnayd8cc0552018-08-31 08:39:17 -070058//! use syn::Attribute;
59//! use syn::parse::{Parse, ParseStream, Result};
David Tolnaye79ae182018-01-06 19:23:37 -080060//! #
David Tolnay9b00f652018-09-01 10:31:02 -070061//! # enum ItemStatic {}
David Tolnaye79ae182018-01-06 19:23:37 -080062//!
63//! // Parse the ItemStatic struct shown above.
David Tolnayd8cc0552018-08-31 08:39:17 -070064//! impl Parse for ItemStatic {
65//! fn parse(input: ParseStream) -> Result<Self> {
David Tolnay9b00f652018-09-01 10:31:02 -070066//! # use syn::ItemStatic;
67//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
68//! Ok(ItemStatic {
69//! attrs: input.call(Attribute::parse_outer)?,
70//! vis: input.parse()?,
71//! static_token: input.parse()?,
72//! mutability: input.parse()?,
73//! ident: input.parse()?,
74//! colon_token: input.parse()?,
75//! ty: input.parse()?,
76//! eq_token: input.parse()?,
77//! expr: input.parse()?,
78//! semi_token: input.parse()?,
79//! })
80//! # }
81//! # unimplemented!()
82//! }
David Tolnaye79ae182018-01-06 19:23:37 -080083//! }
84//! #
85//! # fn main() {}
86//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070087
David Tolnay776f8e02018-08-24 22:32:10 -040088use std;
David Tolnayd9836922018-08-25 18:05:36 -040089#[cfg(feature = "parsing")]
90use std::cell::Cell;
David Tolnay776f8e02018-08-24 22:32:10 -040091#[cfg(feature = "extra-traits")]
92use std::cmp;
93#[cfg(feature = "extra-traits")]
94use std::fmt::{self, Debug};
95#[cfg(feature = "extra-traits")]
96use std::hash::{Hash, Hasher};
David Tolnayd9836922018-08-25 18:05:36 -040097#[cfg(feature = "parsing")]
98use std::rc::Rc;
David Tolnay776f8e02018-08-24 22:32:10 -040099
David Tolnay2d84a082018-08-25 16:31:38 -0400100#[cfg(feature = "parsing")]
101use proc_macro2::Delimiter;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700102#[cfg(feature = "printing")]
David Tolnay78612672018-08-31 08:47:41 -0700103use proc_macro2::TokenStream;
104use proc_macro2::{Ident, Span};
David Tolnay776f8e02018-08-24 22:32:10 -0400105#[cfg(feature = "printing")]
106use quote::{ToTokens, TokenStreamExt};
107
108#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400109use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700110#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400111#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400112use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700113#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400114#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400115use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400116#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400117use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400118#[cfg(feature = "parsing")]
David Tolnay10951d52018-08-31 10:27:39 -0700119use parse::{Lookahead1, Parse, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400120use span::IntoSpans;
121
122/// Marker trait for types that represent single tokens.
123///
124/// This trait is sealed and cannot be implemented for types outside of Syn.
125#[cfg(feature = "parsing")]
126pub trait Token: private::Sealed {
127 // Not public API.
128 #[doc(hidden)]
129 fn peek(lookahead: &Lookahead1) -> bool;
130
131 // Not public API.
132 #[doc(hidden)]
133 fn display() -> String;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700134}
135
136#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400137mod private {
138 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700139}
140
David Tolnay776f8e02018-08-24 22:32:10 -0400141macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400142 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400143 #[cfg(feature = "parsing")]
144 impl Token for $name {
145 fn peek(lookahead: &Lookahead1) -> bool {
David Tolnayd9836922018-08-25 18:05:36 -0400146 // TODO factor out in a way that can be compiled just once
147 let scope = Span::call_site();
148 let cursor = lookahead.cursor();
149 let unexpected = Rc::new(Cell::new(None));
David Tolnay10951d52018-08-31 10:27:39 -0700150 ::private::new_parse_buffer(scope, cursor, unexpected)
David Tolnayd9836922018-08-25 18:05:36 -0400151 .parse::<Self>()
152 .is_ok()
David Tolnay776f8e02018-08-24 22:32:10 -0400153 }
154
155 fn display() -> String {
David Tolnay4fb71232018-08-25 23:14:50 -0400156 $display.to_owned()
David Tolnay776f8e02018-08-24 22:32:10 -0400157 }
158 }
159
160 #[cfg(feature = "parsing")]
161 impl private::Sealed for $name {}
162 };
163}
164
David Tolnay4fb71232018-08-25 23:14:50 -0400165impl_token!(Ident "identifier");
David Tolnaya465b2d2018-08-27 08:21:09 -0700166#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400167impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700168#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400169impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700170#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400171impl_token!(LitStr "string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700172#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400173impl_token!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700174#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400175impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700176#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400177impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700178#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400179impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700180#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400181impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700182#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400183impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400184
David Tolnay776f8e02018-08-24 22:32:10 -0400185macro_rules! define_keywords {
186 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
187 $(
188 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
189 #[$doc]
190 ///
191 /// Don't try to remember the name of this type -- use the [`Token!`]
192 /// macro instead.
193 ///
194 /// [`Token!`]: index.html
195 pub struct $name {
196 pub span: Span,
197 }
198
199 #[doc(hidden)]
200 #[allow(non_snake_case)]
201 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
202 $name {
203 span: span.into_spans()[0],
204 }
205 }
206
David Tolnay4fb71232018-08-25 23:14:50 -0400207 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400208
209 impl std::default::Default for $name {
210 fn default() -> Self {
211 $name(Span::call_site())
212 }
213 }
214
215 #[cfg(feature = "extra-traits")]
216 impl Debug for $name {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 f.write_str(stringify!($name))
219 }
220 }
221
222 #[cfg(feature = "extra-traits")]
223 impl cmp::Eq for $name {}
224
225 #[cfg(feature = "extra-traits")]
226 impl PartialEq for $name {
227 fn eq(&self, _other: &$name) -> bool {
228 true
229 }
230 }
231
232 #[cfg(feature = "extra-traits")]
233 impl Hash for $name {
234 fn hash<H: Hasher>(&self, _state: &mut H) {}
235 }
236
237 #[cfg(feature = "printing")]
238 impl ToTokens for $name {
239 fn to_tokens(&self, tokens: &mut TokenStream) {
240 printing::keyword($token, &self.span, tokens);
241 }
242 }
243
244 #[cfg(feature = "parsing")]
245 impl Parse for $name {
246 fn parse(input: ParseStream) -> Result<Self> {
247 parsing::keyword(input, $token).map($name)
248 }
249 }
250 )*
251 };
252}
253
254macro_rules! define_punctuation_structs {
255 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
256 $(
257 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
258 #[$doc]
259 ///
260 /// Don't try to remember the name of this type -- use the [`Token!`]
261 /// macro instead.
262 ///
263 /// [`Token!`]: index.html
264 pub struct $name {
265 pub spans: [Span; $len],
266 }
267
268 #[doc(hidden)]
269 #[allow(non_snake_case)]
270 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
271 $name {
272 spans: spans.into_spans(),
273 }
274 }
275
David Tolnay4fb71232018-08-25 23:14:50 -0400276 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400277
278 impl std::default::Default for $name {
279 fn default() -> Self {
280 $name([Span::call_site(); $len])
281 }
282 }
283
284 #[cfg(feature = "extra-traits")]
285 impl Debug for $name {
286 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287 f.write_str(stringify!($name))
288 }
289 }
290
291 #[cfg(feature = "extra-traits")]
292 impl cmp::Eq for $name {}
293
294 #[cfg(feature = "extra-traits")]
295 impl PartialEq for $name {
296 fn eq(&self, _other: &$name) -> bool {
297 true
298 }
299 }
300
301 #[cfg(feature = "extra-traits")]
302 impl Hash for $name {
303 fn hash<H: Hasher>(&self, _state: &mut H) {}
304 }
305 )*
306 };
307}
308
309macro_rules! define_punctuation {
310 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
311 $(
312 define_punctuation_structs! {
313 $token pub struct $name/$len #[$doc]
314 }
315
316 #[cfg(feature = "printing")]
317 impl ToTokens for $name {
318 fn to_tokens(&self, tokens: &mut TokenStream) {
319 printing::punct($token, &self.spans, tokens);
320 }
321 }
322
323 #[cfg(feature = "parsing")]
324 impl Parse for $name {
325 fn parse(input: ParseStream) -> Result<Self> {
326 parsing::punct(input, $token).map($name::<[Span; $len]>)
327 }
328 }
329 )*
330 };
331}
332
333macro_rules! define_delimiters {
334 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
335 $(
336 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
337 #[$doc]
338 pub struct $name {
339 pub span: Span,
340 }
341
342 #[doc(hidden)]
343 #[allow(non_snake_case)]
344 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
345 $name {
346 span: span.into_spans()[0],
347 }
348 }
349
350 impl std::default::Default for $name {
351 fn default() -> Self {
352 $name(Span::call_site())
353 }
354 }
355
356 #[cfg(feature = "extra-traits")]
357 impl Debug for $name {
358 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359 f.write_str(stringify!($name))
360 }
361 }
362
363 #[cfg(feature = "extra-traits")]
364 impl cmp::Eq for $name {}
365
366 #[cfg(feature = "extra-traits")]
367 impl PartialEq for $name {
368 fn eq(&self, _other: &$name) -> bool {
369 true
370 }
371 }
372
373 #[cfg(feature = "extra-traits")]
374 impl Hash for $name {
375 fn hash<H: Hasher>(&self, _state: &mut H) {}
376 }
377
378 impl $name {
379 #[cfg(feature = "printing")]
380 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
381 where
382 F: FnOnce(&mut TokenStream),
383 {
384 printing::delim($token, &self.span, tokens, f);
385 }
David Tolnay776f8e02018-08-24 22:32:10 -0400386 }
David Tolnay2d84a082018-08-25 16:31:38 -0400387
388 #[cfg(feature = "parsing")]
389 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400390 )*
391 };
392}
393
394define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400395 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700396}
397
David Tolnay776f8e02018-08-24 22:32:10 -0400398#[cfg(feature = "printing")]
399impl ToTokens for Underscore {
400 fn to_tokens(&self, tokens: &mut TokenStream) {
401 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700402 }
David Tolnay776f8e02018-08-24 22:32:10 -0400403}
404
405#[cfg(feature = "parsing")]
406impl Parse for Underscore {
407 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700408 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400409 if let Some((ident, rest)) = cursor.ident() {
410 if ident == "_" {
411 return Ok((Underscore(ident.span()), rest));
412 }
413 }
414 if let Some((punct, rest)) = cursor.punct() {
415 if punct.as_char() == '_' {
416 return Ok((Underscore(punct.span()), rest));
417 }
418 }
419 Err(cursor.error("expected `_`"))
420 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700421 }
David Tolnay776f8e02018-08-24 22:32:10 -0400422}
423
David Tolnay2d84a082018-08-25 16:31:38 -0400424#[cfg(feature = "parsing")]
425impl Token for Paren {
426 fn peek(lookahead: &Lookahead1) -> bool {
427 lookahead::is_delimiter(lookahead, Delimiter::Parenthesis)
428 }
429
430 fn display() -> String {
431 "parentheses".to_owned()
432 }
433}
434
435#[cfg(feature = "parsing")]
436impl Token for Brace {
437 fn peek(lookahead: &Lookahead1) -> bool {
438 lookahead::is_delimiter(lookahead, Delimiter::Brace)
439 }
440
441 fn display() -> String {
442 "curly braces".to_owned()
443 }
444}
445
446#[cfg(feature = "parsing")]
447impl Token for Bracket {
448 fn peek(lookahead: &Lookahead1) -> bool {
449 lookahead::is_delimiter(lookahead, Delimiter::Bracket)
450 }
451
452 fn display() -> String {
453 "square brackets".to_owned()
454 }
455}
456
David Tolnaya7d69fc2018-08-26 13:30:24 -0400457#[cfg(feature = "parsing")]
458impl Token for Group {
459 fn peek(lookahead: &Lookahead1) -> bool {
460 lookahead::is_delimiter(lookahead, Delimiter::None)
461 }
462
463 fn display() -> String {
464 "invisible group".to_owned()
465 }
466}
467
David Tolnay776f8e02018-08-24 22:32:10 -0400468define_keywords! {
469 "as" pub struct As /// `as`
470 "async" pub struct Async /// `async`
471 "auto" pub struct Auto /// `auto`
472 "box" pub struct Box /// `box`
473 "break" pub struct Break /// `break`
474 "Self" pub struct CapSelf /// `Self`
475 "const" pub struct Const /// `const`
476 "continue" pub struct Continue /// `continue`
477 "crate" pub struct Crate /// `crate`
478 "default" pub struct Default /// `default`
479 "dyn" pub struct Dyn /// `dyn`
480 "else" pub struct Else /// `else`
481 "enum" pub struct Enum /// `enum`
482 "existential" pub struct Existential /// `existential`
483 "extern" pub struct Extern /// `extern`
484 "fn" pub struct Fn /// `fn`
485 "for" pub struct For /// `for`
486 "if" pub struct If /// `if`
487 "impl" pub struct Impl /// `impl`
488 "in" pub struct In /// `in`
489 "let" pub struct Let /// `let`
490 "loop" pub struct Loop /// `loop`
491 "macro" pub struct Macro /// `macro`
492 "match" pub struct Match /// `match`
493 "mod" pub struct Mod /// `mod`
494 "move" pub struct Move /// `move`
495 "mut" pub struct Mut /// `mut`
496 "pub" pub struct Pub /// `pub`
497 "ref" pub struct Ref /// `ref`
498 "return" pub struct Return /// `return`
499 "self" pub struct Self_ /// `self`
500 "static" pub struct Static /// `static`
501 "struct" pub struct Struct /// `struct`
502 "super" pub struct Super /// `super`
503 "trait" pub struct Trait /// `trait`
504 "try" pub struct Try /// `try`
505 "type" pub struct Type /// `type`
506 "union" pub struct Union /// `union`
507 "unsafe" pub struct Unsafe /// `unsafe`
508 "use" pub struct Use /// `use`
509 "where" pub struct Where /// `where`
510 "while" pub struct While /// `while`
511 "yield" pub struct Yield /// `yield`
512}
513
514define_punctuation! {
515 "+" pub struct Add/1 /// `+`
516 "+=" pub struct AddEq/2 /// `+=`
517 "&" pub struct And/1 /// `&`
518 "&&" pub struct AndAnd/2 /// `&&`
519 "&=" pub struct AndEq/2 /// `&=`
520 "@" pub struct At/1 /// `@`
521 "!" pub struct Bang/1 /// `!`
522 "^" pub struct Caret/1 /// `^`
523 "^=" pub struct CaretEq/2 /// `^=`
524 ":" pub struct Colon/1 /// `:`
525 "::" pub struct Colon2/2 /// `::`
526 "," pub struct Comma/1 /// `,`
527 "/" pub struct Div/1 /// `/`
528 "/=" pub struct DivEq/2 /// `/=`
529 "$" pub struct Dollar/1 /// `$`
530 "." pub struct Dot/1 /// `.`
531 ".." pub struct Dot2/2 /// `..`
532 "..." pub struct Dot3/3 /// `...`
533 "..=" pub struct DotDotEq/3 /// `..=`
534 "=" pub struct Eq/1 /// `=`
535 "==" pub struct EqEq/2 /// `==`
536 ">=" pub struct Ge/2 /// `>=`
537 ">" pub struct Gt/1 /// `>`
538 "<=" pub struct Le/2 /// `<=`
539 "<" pub struct Lt/1 /// `<`
540 "*=" pub struct MulEq/2 /// `*=`
541 "!=" pub struct Ne/2 /// `!=`
542 "|" pub struct Or/1 /// `|`
543 "|=" pub struct OrEq/2 /// `|=`
544 "||" pub struct OrOr/2 /// `||`
545 "#" pub struct Pound/1 /// `#`
546 "?" pub struct Question/1 /// `?`
547 "->" pub struct RArrow/2 /// `->`
548 "<-" pub struct LArrow/2 /// `<-`
549 "%" pub struct Rem/1 /// `%`
550 "%=" pub struct RemEq/2 /// `%=`
551 "=>" pub struct FatArrow/2 /// `=>`
552 ";" pub struct Semi/1 /// `;`
553 "<<" pub struct Shl/2 /// `<<`
554 "<<=" pub struct ShlEq/3 /// `<<=`
555 ">>" pub struct Shr/2 /// `>>`
556 ">>=" pub struct ShrEq/3 /// `>>=`
557 "*" pub struct Star/1 /// `*`
558 "-" pub struct Sub/1 /// `-`
559 "-=" pub struct SubEq/2 /// `-=`
560}
561
562define_delimiters! {
563 "{" pub struct Brace /// `{...}`
564 "[" pub struct Bracket /// `[...]`
565 "(" pub struct Paren /// `(...)`
566 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700567}
568
David Tolnayf005f962018-01-06 21:19:41 -0800569/// A type-macro that expands to the name of the Rust type representation of a
570/// given token.
571///
572/// See the [token module] documentation for details and examples.
573///
574/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800575// Unfortunate duplication due to a rustdoc bug.
576// https://github.com/rust-lang/rust/issues/45939
577#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700578#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800579macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400580 (as) => { $crate::token::As };
581 (async) => { $crate::token::Async };
582 (auto) => { $crate::token::Auto };
583 (box) => { $crate::token::Box };
584 (break) => { $crate::token::Break };
585 (Self) => { $crate::token::CapSelf };
586 (const) => { $crate::token::Const };
587 (continue) => { $crate::token::Continue };
588 (crate) => { $crate::token::Crate };
589 (default) => { $crate::token::Default };
590 (dyn) => { $crate::token::Dyn };
591 (else) => { $crate::token::Else };
592 (enum) => { $crate::token::Enum };
593 (existential) => { $crate::token::Existential };
594 (extern) => { $crate::token::Extern };
595 (fn) => { $crate::token::Fn };
596 (for) => { $crate::token::For };
597 (if) => { $crate::token::If };
598 (impl) => { $crate::token::Impl };
599 (in) => { $crate::token::In };
600 (let) => { $crate::token::Let };
601 (loop) => { $crate::token::Loop };
602 (macro) => { $crate::token::Macro };
603 (match) => { $crate::token::Match };
604 (mod) => { $crate::token::Mod };
605 (move) => { $crate::token::Move };
606 (mut) => { $crate::token::Mut };
607 (pub) => { $crate::token::Pub };
608 (ref) => { $crate::token::Ref };
609 (return) => { $crate::token::Return };
610 (self) => { $crate::token::Self_ };
611 (static) => { $crate::token::Static };
612 (struct) => { $crate::token::Struct };
613 (super) => { $crate::token::Super };
614 (trait) => { $crate::token::Trait };
615 (try) => { $crate::token::Try };
616 (type) => { $crate::token::Type };
617 (union) => { $crate::token::Union };
618 (unsafe) => { $crate::token::Unsafe };
619 (use) => { $crate::token::Use };
620 (where) => { $crate::token::Where };
621 (while) => { $crate::token::While };
622 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400623 (+) => { $crate::token::Add };
624 (+=) => { $crate::token::AddEq };
625 (&) => { $crate::token::And };
626 (&&) => { $crate::token::AndAnd };
627 (&=) => { $crate::token::AndEq };
628 (@) => { $crate::token::At };
629 (!) => { $crate::token::Bang };
630 (^) => { $crate::token::Caret };
631 (^=) => { $crate::token::CaretEq };
632 (:) => { $crate::token::Colon };
633 (::) => { $crate::token::Colon2 };
634 (,) => { $crate::token::Comma };
635 (/) => { $crate::token::Div };
636 (/=) => { $crate::token::DivEq };
637 (.) => { $crate::token::Dot };
638 (..) => { $crate::token::Dot2 };
639 (...) => { $crate::token::Dot3 };
640 (..=) => { $crate::token::DotDotEq };
641 (=) => { $crate::token::Eq };
642 (==) => { $crate::token::EqEq };
643 (>=) => { $crate::token::Ge };
644 (>) => { $crate::token::Gt };
645 (<=) => { $crate::token::Le };
646 (<) => { $crate::token::Lt };
647 (*=) => { $crate::token::MulEq };
648 (!=) => { $crate::token::Ne };
649 (|) => { $crate::token::Or };
650 (|=) => { $crate::token::OrEq };
651 (||) => { $crate::token::OrOr };
652 (#) => { $crate::token::Pound };
653 (?) => { $crate::token::Question };
654 (->) => { $crate::token::RArrow };
655 (<-) => { $crate::token::LArrow };
656 (%) => { $crate::token::Rem };
657 (%=) => { $crate::token::RemEq };
658 (=>) => { $crate::token::FatArrow };
659 (;) => { $crate::token::Semi };
660 (<<) => { $crate::token::Shl };
661 (<<=) => { $crate::token::ShlEq };
662 (>>) => { $crate::token::Shr };
663 (>>=) => { $crate::token::ShrEq };
664 (*) => { $crate::token::Star };
665 (-) => { $crate::token::Sub };
666 (-=) => { $crate::token::SubEq };
667 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800668}
669
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700670macro_rules! ident_from_token {
671 ($token:ident) => {
672 impl From<Token![$token]> for Ident {
673 fn from(token: Token![$token]) -> Ident {
David Tolnay7ac699c2018-08-24 14:00:58 -0400674 Ident::new(stringify!($token), token.span)
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700675 }
676 }
677 };
678}
679
680ident_from_token!(self);
681ident_from_token!(Self);
682ident_from_token!(super);
683ident_from_token!(crate);
David Tolnay0a4d4e92018-07-21 15:31:45 -0700684ident_from_token!(extern);
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700685
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700686#[cfg(feature = "parsing")]
687mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700688 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700689
David Tolnayad4b2472018-08-25 08:25:24 -0400690 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400691 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400692 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700693
David Tolnay776f8e02018-08-24 22:32:10 -0400694 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700695 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400696 if let Some((ident, rest)) = cursor.ident() {
697 if ident == token {
698 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700699 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700700 }
David Tolnay776f8e02018-08-24 22:32:10 -0400701 Err(cursor.error(format!("expected `{}`", token)))
702 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700703 }
704
David Tolnay776f8e02018-08-24 22:32:10 -0400705 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700706 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400707 let mut cursor = *cursor;
708 let mut spans = [cursor.span(); 3];
709 assert!(token.len() <= spans.len());
710
711 for (i, ch) in token.chars().enumerate() {
712 match cursor.punct() {
713 Some((punct, rest)) => {
714 spans[i] = punct.span();
715 if punct.as_char() != ch {
716 break;
717 } else if i == token.len() - 1 {
718 return Ok((S::from_spans(&spans), rest));
719 } else if punct.spacing() != Spacing::Joint {
720 break;
721 }
722 cursor = rest;
723 }
724 None => break,
725 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400726 }
David Tolnay776f8e02018-08-24 22:32:10 -0400727
728 Err(Error::new(spans[0], format!("expected `{}`", token)))
729 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700730 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700731}
732
733#[cfg(feature = "printing")]
734mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700735 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700736 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700737
Alex Crichtona74a1c82018-05-16 10:20:44 -0700738 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700739 assert_eq!(s.len(), spans.len());
740
741 let mut chars = s.chars();
742 let mut spans = spans.iter();
743 let ch = chars.next_back().unwrap();
744 let span = spans.next_back().unwrap();
745 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700746 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700747 op.set_span(*span);
748 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700749 }
750
Alex Crichtona74a1c82018-05-16 10:20:44 -0700751 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700752 op.set_span(*span);
753 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700754 }
755
Alex Crichtona74a1c82018-05-16 10:20:44 -0700756 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
757 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700758 }
759
Alex Crichtona74a1c82018-05-16 10:20:44 -0700760 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500761 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700762 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700763 {
David Tolnay00ab6982017-12-31 18:15:06 -0500764 let delim = match s {
765 "(" => Delimiter::Parenthesis,
766 "[" => Delimiter::Bracket,
767 "{" => Delimiter::Brace,
768 " " => Delimiter::None,
769 _ => panic!("unknown delimiter: {}", s),
770 };
hcplaa511792018-05-29 07:13:01 +0300771 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500772 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700773 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700774 g.set_span(*span);
775 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700776 }
777}