blob: 4db039ab87bbba523c768bebbc6665679355cc44 [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//! ```
24//! # #[macro_use]
25//! # extern crate syn;
26//! #
David Tolnaye303b7c2018-05-20 16:46:35 -070027//! # use syn::{Attribute, Visibility, Ident, Type, Expr};
David Tolnaye79ae182018-01-06 19:23:37 -080028//! #
29//! pub struct ItemStatic {
30//! pub attrs: Vec<Attribute>,
31//! pub vis: Visibility,
32//! pub static_token: Token![static],
33//! pub mutability: Option<Token![mut]>,
34//! pub ident: Ident,
35//! pub colon_token: Token![:],
36//! pub ty: Box<Type>,
37//! pub eq_token: Token![=],
38//! pub expr: Box<Expr>,
39//! pub semi_token: Token![;],
40//! }
41//! #
42//! # fn main() {}
43//! ```
44//!
45//! # Parsing
46//!
David Tolnayd8cc0552018-08-31 08:39:17 -070047//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
48//! method. Delimiter tokens are parsed using the [`parenthesized!`],
49//! [`bracketed!`] and [`braced!`] macros.
David Tolnaye79ae182018-01-06 19:23:37 -080050//!
David Tolnayd8cc0552018-08-31 08:39:17 -070051//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
52//! [`parenthesized!`]: ../macro.parenthesized.html
53//! [`bracketed!`]: ../macro.bracketed.html
54//! [`braced!`]: ../macro.braced.html
David Tolnaye79ae182018-01-06 19:23:37 -080055//!
56//! ```
David Tolnaye79ae182018-01-06 19:23:37 -080057//! extern crate syn;
58//!
David Tolnayd8cc0552018-08-31 08:39:17 -070059//! use syn::Attribute;
60//! use syn::parse::{Parse, ParseStream, Result};
David Tolnaye79ae182018-01-06 19:23:37 -080061//! #
62//! # struct ItemStatic;
David Tolnaye79ae182018-01-06 19:23:37 -080063//!
64//! // Parse the ItemStatic struct shown above.
David Tolnayd8cc0552018-08-31 08:39:17 -070065//! impl Parse for ItemStatic {
66//! fn parse(input: ParseStream) -> Result<Self> {
67//! # Ok(ItemStatic)
68//! # }
David Tolnaye79ae182018-01-06 19:23:37 -080069//! # }
70//! #
71//! # mod example {
David Tolnayd8cc0552018-08-31 08:39:17 -070072//! # use super::*;
73//! # use syn::ItemStatic;
David Tolnaye79ae182018-01-06 19:23:37 -080074//! #
David Tolnayd8cc0552018-08-31 08:39:17 -070075//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
76//! Ok(ItemStatic {
77//! attrs: input.call(Attribute::parse_outer)?,
78//! vis: input.parse()?,
79//! static_token: input.parse()?,
80//! mutability: input.parse()?,
81//! ident: input.parse()?,
82//! colon_token: input.parse()?,
83//! ty: input.parse()?,
84//! eq_token: input.parse()?,
85//! expr: input.parse()?,
86//! semi_token: input.parse()?,
87//! })
88//! }
David Tolnaye79ae182018-01-06 19:23:37 -080089//! }
90//! #
91//! # fn main() {}
92//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070093
David Tolnay776f8e02018-08-24 22:32:10 -040094use std;
David Tolnayd9836922018-08-25 18:05:36 -040095#[cfg(feature = "parsing")]
96use std::cell::Cell;
David Tolnay776f8e02018-08-24 22:32:10 -040097#[cfg(feature = "extra-traits")]
98use std::cmp;
99#[cfg(feature = "extra-traits")]
100use std::fmt::{self, Debug};
101#[cfg(feature = "extra-traits")]
102use std::hash::{Hash, Hasher};
David Tolnayd9836922018-08-25 18:05:36 -0400103#[cfg(feature = "parsing")]
104use std::rc::Rc;
David Tolnay776f8e02018-08-24 22:32:10 -0400105
David Tolnay2d84a082018-08-25 16:31:38 -0400106#[cfg(feature = "parsing")]
107use proc_macro2::Delimiter;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700108#[cfg(feature = "printing")]
David Tolnay78612672018-08-31 08:47:41 -0700109use proc_macro2::TokenStream;
110use proc_macro2::{Ident, Span};
David Tolnay776f8e02018-08-24 22:32:10 -0400111#[cfg(feature = "printing")]
112use quote::{ToTokens, TokenStreamExt};
113
114#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400115use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700116#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400117#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400118use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700119#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400120#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400121use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400122#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400123use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400124#[cfg(feature = "parsing")]
David Tolnayd9836922018-08-25 18:05:36 -0400125use parse::{Lookahead1, Parse, ParseBuffer, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400126use span::IntoSpans;
127
128/// Marker trait for types that represent single tokens.
129///
130/// This trait is sealed and cannot be implemented for types outside of Syn.
131#[cfg(feature = "parsing")]
132pub trait Token: private::Sealed {
133 // Not public API.
134 #[doc(hidden)]
135 fn peek(lookahead: &Lookahead1) -> bool;
136
137 // Not public API.
138 #[doc(hidden)]
139 fn display() -> String;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700140}
141
142#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400143mod private {
144 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700145}
146
David Tolnay776f8e02018-08-24 22:32:10 -0400147macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400148 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400149 #[cfg(feature = "parsing")]
150 impl Token for $name {
151 fn peek(lookahead: &Lookahead1) -> bool {
David Tolnayd9836922018-08-25 18:05:36 -0400152 // TODO factor out in a way that can be compiled just once
153 let scope = Span::call_site();
154 let cursor = lookahead.cursor();
155 let unexpected = Rc::new(Cell::new(None));
156 ParseBuffer::new(scope, cursor, unexpected)
157 .parse::<Self>()
158 .is_ok()
David Tolnay776f8e02018-08-24 22:32:10 -0400159 }
160
161 fn display() -> String {
David Tolnay4fb71232018-08-25 23:14:50 -0400162 $display.to_owned()
David Tolnay776f8e02018-08-24 22:32:10 -0400163 }
164 }
165
166 #[cfg(feature = "parsing")]
167 impl private::Sealed for $name {}
168 };
169}
170
David Tolnay4fb71232018-08-25 23:14:50 -0400171impl_token!(Ident "identifier");
David Tolnaya465b2d2018-08-27 08:21:09 -0700172#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400173impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700174#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400175impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700176#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400177impl_token!(LitStr "string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700178#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400179impl_token!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700180#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400181impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700182#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400183impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700184#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400185impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700186#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400187impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700188#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400189impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400190
David Tolnay776f8e02018-08-24 22:32:10 -0400191macro_rules! define_keywords {
192 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
193 $(
194 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
195 #[$doc]
196 ///
197 /// Don't try to remember the name of this type -- use the [`Token!`]
198 /// macro instead.
199 ///
200 /// [`Token!`]: index.html
201 pub struct $name {
202 pub span: Span,
203 }
204
205 #[doc(hidden)]
206 #[allow(non_snake_case)]
207 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
208 $name {
209 span: span.into_spans()[0],
210 }
211 }
212
David Tolnay4fb71232018-08-25 23:14:50 -0400213 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400214
215 impl std::default::Default for $name {
216 fn default() -> Self {
217 $name(Span::call_site())
218 }
219 }
220
221 #[cfg(feature = "extra-traits")]
222 impl Debug for $name {
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 f.write_str(stringify!($name))
225 }
226 }
227
228 #[cfg(feature = "extra-traits")]
229 impl cmp::Eq for $name {}
230
231 #[cfg(feature = "extra-traits")]
232 impl PartialEq for $name {
233 fn eq(&self, _other: &$name) -> bool {
234 true
235 }
236 }
237
238 #[cfg(feature = "extra-traits")]
239 impl Hash for $name {
240 fn hash<H: Hasher>(&self, _state: &mut H) {}
241 }
242
243 #[cfg(feature = "printing")]
244 impl ToTokens for $name {
245 fn to_tokens(&self, tokens: &mut TokenStream) {
246 printing::keyword($token, &self.span, tokens);
247 }
248 }
249
250 #[cfg(feature = "parsing")]
251 impl Parse for $name {
252 fn parse(input: ParseStream) -> Result<Self> {
253 parsing::keyword(input, $token).map($name)
254 }
255 }
256 )*
257 };
258}
259
260macro_rules! define_punctuation_structs {
261 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
262 $(
263 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
264 #[$doc]
265 ///
266 /// Don't try to remember the name of this type -- use the [`Token!`]
267 /// macro instead.
268 ///
269 /// [`Token!`]: index.html
270 pub struct $name {
271 pub spans: [Span; $len],
272 }
273
274 #[doc(hidden)]
275 #[allow(non_snake_case)]
276 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
277 $name {
278 spans: spans.into_spans(),
279 }
280 }
281
David Tolnay4fb71232018-08-25 23:14:50 -0400282 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400283
284 impl std::default::Default for $name {
285 fn default() -> Self {
286 $name([Span::call_site(); $len])
287 }
288 }
289
290 #[cfg(feature = "extra-traits")]
291 impl Debug for $name {
292 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293 f.write_str(stringify!($name))
294 }
295 }
296
297 #[cfg(feature = "extra-traits")]
298 impl cmp::Eq for $name {}
299
300 #[cfg(feature = "extra-traits")]
301 impl PartialEq for $name {
302 fn eq(&self, _other: &$name) -> bool {
303 true
304 }
305 }
306
307 #[cfg(feature = "extra-traits")]
308 impl Hash for $name {
309 fn hash<H: Hasher>(&self, _state: &mut H) {}
310 }
311 )*
312 };
313}
314
315macro_rules! define_punctuation {
316 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
317 $(
318 define_punctuation_structs! {
319 $token pub struct $name/$len #[$doc]
320 }
321
322 #[cfg(feature = "printing")]
323 impl ToTokens for $name {
324 fn to_tokens(&self, tokens: &mut TokenStream) {
325 printing::punct($token, &self.spans, tokens);
326 }
327 }
328
329 #[cfg(feature = "parsing")]
330 impl Parse for $name {
331 fn parse(input: ParseStream) -> Result<Self> {
332 parsing::punct(input, $token).map($name::<[Span; $len]>)
333 }
334 }
335 )*
336 };
337}
338
339macro_rules! define_delimiters {
340 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
341 $(
342 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
343 #[$doc]
344 pub struct $name {
345 pub span: Span,
346 }
347
348 #[doc(hidden)]
349 #[allow(non_snake_case)]
350 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
351 $name {
352 span: span.into_spans()[0],
353 }
354 }
355
356 impl std::default::Default for $name {
357 fn default() -> Self {
358 $name(Span::call_site())
359 }
360 }
361
362 #[cfg(feature = "extra-traits")]
363 impl Debug for $name {
364 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
365 f.write_str(stringify!($name))
366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 impl cmp::Eq for $name {}
371
372 #[cfg(feature = "extra-traits")]
373 impl PartialEq for $name {
374 fn eq(&self, _other: &$name) -> bool {
375 true
376 }
377 }
378
379 #[cfg(feature = "extra-traits")]
380 impl Hash for $name {
381 fn hash<H: Hasher>(&self, _state: &mut H) {}
382 }
383
384 impl $name {
385 #[cfg(feature = "printing")]
386 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
387 where
388 F: FnOnce(&mut TokenStream),
389 {
390 printing::delim($token, &self.span, tokens, f);
391 }
David Tolnay776f8e02018-08-24 22:32:10 -0400392 }
David Tolnay2d84a082018-08-25 16:31:38 -0400393
394 #[cfg(feature = "parsing")]
395 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400396 )*
397 };
398}
399
400define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400401 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700402}
403
David Tolnay776f8e02018-08-24 22:32:10 -0400404#[cfg(feature = "printing")]
405impl ToTokens for Underscore {
406 fn to_tokens(&self, tokens: &mut TokenStream) {
407 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700408 }
David Tolnay776f8e02018-08-24 22:32:10 -0400409}
410
411#[cfg(feature = "parsing")]
412impl Parse for Underscore {
413 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700414 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400415 if let Some((ident, rest)) = cursor.ident() {
416 if ident == "_" {
417 return Ok((Underscore(ident.span()), rest));
418 }
419 }
420 if let Some((punct, rest)) = cursor.punct() {
421 if punct.as_char() == '_' {
422 return Ok((Underscore(punct.span()), rest));
423 }
424 }
425 Err(cursor.error("expected `_`"))
426 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700427 }
David Tolnay776f8e02018-08-24 22:32:10 -0400428}
429
David Tolnay2d84a082018-08-25 16:31:38 -0400430#[cfg(feature = "parsing")]
431impl Token for Paren {
432 fn peek(lookahead: &Lookahead1) -> bool {
433 lookahead::is_delimiter(lookahead, Delimiter::Parenthesis)
434 }
435
436 fn display() -> String {
437 "parentheses".to_owned()
438 }
439}
440
441#[cfg(feature = "parsing")]
442impl Token for Brace {
443 fn peek(lookahead: &Lookahead1) -> bool {
444 lookahead::is_delimiter(lookahead, Delimiter::Brace)
445 }
446
447 fn display() -> String {
448 "curly braces".to_owned()
449 }
450}
451
452#[cfg(feature = "parsing")]
453impl Token for Bracket {
454 fn peek(lookahead: &Lookahead1) -> bool {
455 lookahead::is_delimiter(lookahead, Delimiter::Bracket)
456 }
457
458 fn display() -> String {
459 "square brackets".to_owned()
460 }
461}
462
David Tolnaya7d69fc2018-08-26 13:30:24 -0400463#[cfg(feature = "parsing")]
464impl Token for Group {
465 fn peek(lookahead: &Lookahead1) -> bool {
466 lookahead::is_delimiter(lookahead, Delimiter::None)
467 }
468
469 fn display() -> String {
470 "invisible group".to_owned()
471 }
472}
473
David Tolnay776f8e02018-08-24 22:32:10 -0400474define_keywords! {
475 "as" pub struct As /// `as`
476 "async" pub struct Async /// `async`
477 "auto" pub struct Auto /// `auto`
478 "box" pub struct Box /// `box`
479 "break" pub struct Break /// `break`
480 "Self" pub struct CapSelf /// `Self`
481 "const" pub struct Const /// `const`
482 "continue" pub struct Continue /// `continue`
483 "crate" pub struct Crate /// `crate`
484 "default" pub struct Default /// `default`
485 "dyn" pub struct Dyn /// `dyn`
486 "else" pub struct Else /// `else`
487 "enum" pub struct Enum /// `enum`
488 "existential" pub struct Existential /// `existential`
489 "extern" pub struct Extern /// `extern`
490 "fn" pub struct Fn /// `fn`
491 "for" pub struct For /// `for`
492 "if" pub struct If /// `if`
493 "impl" pub struct Impl /// `impl`
494 "in" pub struct In /// `in`
495 "let" pub struct Let /// `let`
496 "loop" pub struct Loop /// `loop`
497 "macro" pub struct Macro /// `macro`
498 "match" pub struct Match /// `match`
499 "mod" pub struct Mod /// `mod`
500 "move" pub struct Move /// `move`
501 "mut" pub struct Mut /// `mut`
502 "pub" pub struct Pub /// `pub`
503 "ref" pub struct Ref /// `ref`
504 "return" pub struct Return /// `return`
505 "self" pub struct Self_ /// `self`
506 "static" pub struct Static /// `static`
507 "struct" pub struct Struct /// `struct`
508 "super" pub struct Super /// `super`
509 "trait" pub struct Trait /// `trait`
510 "try" pub struct Try /// `try`
511 "type" pub struct Type /// `type`
512 "union" pub struct Union /// `union`
513 "unsafe" pub struct Unsafe /// `unsafe`
514 "use" pub struct Use /// `use`
515 "where" pub struct Where /// `where`
516 "while" pub struct While /// `while`
517 "yield" pub struct Yield /// `yield`
518}
519
520define_punctuation! {
521 "+" pub struct Add/1 /// `+`
522 "+=" pub struct AddEq/2 /// `+=`
523 "&" pub struct And/1 /// `&`
524 "&&" pub struct AndAnd/2 /// `&&`
525 "&=" pub struct AndEq/2 /// `&=`
526 "@" pub struct At/1 /// `@`
527 "!" pub struct Bang/1 /// `!`
528 "^" pub struct Caret/1 /// `^`
529 "^=" pub struct CaretEq/2 /// `^=`
530 ":" pub struct Colon/1 /// `:`
531 "::" pub struct Colon2/2 /// `::`
532 "," pub struct Comma/1 /// `,`
533 "/" pub struct Div/1 /// `/`
534 "/=" pub struct DivEq/2 /// `/=`
535 "$" pub struct Dollar/1 /// `$`
536 "." pub struct Dot/1 /// `.`
537 ".." pub struct Dot2/2 /// `..`
538 "..." pub struct Dot3/3 /// `...`
539 "..=" pub struct DotDotEq/3 /// `..=`
540 "=" pub struct Eq/1 /// `=`
541 "==" pub struct EqEq/2 /// `==`
542 ">=" pub struct Ge/2 /// `>=`
543 ">" pub struct Gt/1 /// `>`
544 "<=" pub struct Le/2 /// `<=`
545 "<" pub struct Lt/1 /// `<`
546 "*=" pub struct MulEq/2 /// `*=`
547 "!=" pub struct Ne/2 /// `!=`
548 "|" pub struct Or/1 /// `|`
549 "|=" pub struct OrEq/2 /// `|=`
550 "||" pub struct OrOr/2 /// `||`
551 "#" pub struct Pound/1 /// `#`
552 "?" pub struct Question/1 /// `?`
553 "->" pub struct RArrow/2 /// `->`
554 "<-" pub struct LArrow/2 /// `<-`
555 "%" pub struct Rem/1 /// `%`
556 "%=" pub struct RemEq/2 /// `%=`
557 "=>" pub struct FatArrow/2 /// `=>`
558 ";" pub struct Semi/1 /// `;`
559 "<<" pub struct Shl/2 /// `<<`
560 "<<=" pub struct ShlEq/3 /// `<<=`
561 ">>" pub struct Shr/2 /// `>>`
562 ">>=" pub struct ShrEq/3 /// `>>=`
563 "*" pub struct Star/1 /// `*`
564 "-" pub struct Sub/1 /// `-`
565 "-=" pub struct SubEq/2 /// `-=`
566}
567
568define_delimiters! {
569 "{" pub struct Brace /// `{...}`
570 "[" pub struct Bracket /// `[...]`
571 "(" pub struct Paren /// `(...)`
572 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700573}
574
David Tolnayf005f962018-01-06 21:19:41 -0800575/// A type-macro that expands to the name of the Rust type representation of a
576/// given token.
577///
578/// See the [token module] documentation for details and examples.
579///
580/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800581// Unfortunate duplication due to a rustdoc bug.
582// https://github.com/rust-lang/rust/issues/45939
583#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700584#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800585macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400586 (as) => { $crate::token::As };
587 (async) => { $crate::token::Async };
588 (auto) => { $crate::token::Auto };
589 (box) => { $crate::token::Box };
590 (break) => { $crate::token::Break };
591 (Self) => { $crate::token::CapSelf };
592 (const) => { $crate::token::Const };
593 (continue) => { $crate::token::Continue };
594 (crate) => { $crate::token::Crate };
595 (default) => { $crate::token::Default };
596 (dyn) => { $crate::token::Dyn };
597 (else) => { $crate::token::Else };
598 (enum) => { $crate::token::Enum };
599 (existential) => { $crate::token::Existential };
600 (extern) => { $crate::token::Extern };
601 (fn) => { $crate::token::Fn };
602 (for) => { $crate::token::For };
603 (if) => { $crate::token::If };
604 (impl) => { $crate::token::Impl };
605 (in) => { $crate::token::In };
606 (let) => { $crate::token::Let };
607 (loop) => { $crate::token::Loop };
608 (macro) => { $crate::token::Macro };
609 (match) => { $crate::token::Match };
610 (mod) => { $crate::token::Mod };
611 (move) => { $crate::token::Move };
612 (mut) => { $crate::token::Mut };
613 (pub) => { $crate::token::Pub };
614 (ref) => { $crate::token::Ref };
615 (return) => { $crate::token::Return };
616 (self) => { $crate::token::Self_ };
617 (static) => { $crate::token::Static };
618 (struct) => { $crate::token::Struct };
619 (super) => { $crate::token::Super };
620 (trait) => { $crate::token::Trait };
621 (try) => { $crate::token::Try };
622 (type) => { $crate::token::Type };
623 (union) => { $crate::token::Union };
624 (unsafe) => { $crate::token::Unsafe };
625 (use) => { $crate::token::Use };
626 (where) => { $crate::token::Where };
627 (while) => { $crate::token::While };
628 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400629 (+) => { $crate::token::Add };
630 (+=) => { $crate::token::AddEq };
631 (&) => { $crate::token::And };
632 (&&) => { $crate::token::AndAnd };
633 (&=) => { $crate::token::AndEq };
634 (@) => { $crate::token::At };
635 (!) => { $crate::token::Bang };
636 (^) => { $crate::token::Caret };
637 (^=) => { $crate::token::CaretEq };
638 (:) => { $crate::token::Colon };
639 (::) => { $crate::token::Colon2 };
640 (,) => { $crate::token::Comma };
641 (/) => { $crate::token::Div };
642 (/=) => { $crate::token::DivEq };
643 (.) => { $crate::token::Dot };
644 (..) => { $crate::token::Dot2 };
645 (...) => { $crate::token::Dot3 };
646 (..=) => { $crate::token::DotDotEq };
647 (=) => { $crate::token::Eq };
648 (==) => { $crate::token::EqEq };
649 (>=) => { $crate::token::Ge };
650 (>) => { $crate::token::Gt };
651 (<=) => { $crate::token::Le };
652 (<) => { $crate::token::Lt };
653 (*=) => { $crate::token::MulEq };
654 (!=) => { $crate::token::Ne };
655 (|) => { $crate::token::Or };
656 (|=) => { $crate::token::OrEq };
657 (||) => { $crate::token::OrOr };
658 (#) => { $crate::token::Pound };
659 (?) => { $crate::token::Question };
660 (->) => { $crate::token::RArrow };
661 (<-) => { $crate::token::LArrow };
662 (%) => { $crate::token::Rem };
663 (%=) => { $crate::token::RemEq };
664 (=>) => { $crate::token::FatArrow };
665 (;) => { $crate::token::Semi };
666 (<<) => { $crate::token::Shl };
667 (<<=) => { $crate::token::ShlEq };
668 (>>) => { $crate::token::Shr };
669 (>>=) => { $crate::token::ShrEq };
670 (*) => { $crate::token::Star };
671 (-) => { $crate::token::Sub };
672 (-=) => { $crate::token::SubEq };
673 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800674}
675
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700676macro_rules! ident_from_token {
677 ($token:ident) => {
678 impl From<Token![$token]> for Ident {
679 fn from(token: Token![$token]) -> Ident {
David Tolnay7ac699c2018-08-24 14:00:58 -0400680 Ident::new(stringify!($token), token.span)
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700681 }
682 }
683 };
684}
685
686ident_from_token!(self);
687ident_from_token!(Self);
688ident_from_token!(super);
689ident_from_token!(crate);
David Tolnay0a4d4e92018-07-21 15:31:45 -0700690ident_from_token!(extern);
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700691
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700692#[cfg(feature = "parsing")]
693mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700694 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700695
David Tolnayad4b2472018-08-25 08:25:24 -0400696 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400697 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400698 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700699
David Tolnay776f8e02018-08-24 22:32:10 -0400700 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700701 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400702 if let Some((ident, rest)) = cursor.ident() {
703 if ident == token {
704 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700705 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700706 }
David Tolnay776f8e02018-08-24 22:32:10 -0400707 Err(cursor.error(format!("expected `{}`", token)))
708 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700709 }
710
David Tolnay776f8e02018-08-24 22:32:10 -0400711 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700712 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400713 let mut cursor = *cursor;
714 let mut spans = [cursor.span(); 3];
715 assert!(token.len() <= spans.len());
716
717 for (i, ch) in token.chars().enumerate() {
718 match cursor.punct() {
719 Some((punct, rest)) => {
720 spans[i] = punct.span();
721 if punct.as_char() != ch {
722 break;
723 } else if i == token.len() - 1 {
724 return Ok((S::from_spans(&spans), rest));
725 } else if punct.spacing() != Spacing::Joint {
726 break;
727 }
728 cursor = rest;
729 }
730 None => break,
731 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400732 }
David Tolnay776f8e02018-08-24 22:32:10 -0400733
734 Err(Error::new(spans[0], format!("expected `{}`", token)))
735 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700736 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700737}
738
739#[cfg(feature = "printing")]
740mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700741 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700742 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700743
Alex Crichtona74a1c82018-05-16 10:20:44 -0700744 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700745 assert_eq!(s.len(), spans.len());
746
747 let mut chars = s.chars();
748 let mut spans = spans.iter();
749 let ch = chars.next_back().unwrap();
750 let span = spans.next_back().unwrap();
751 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700752 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700753 op.set_span(*span);
754 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700755 }
756
Alex Crichtona74a1c82018-05-16 10:20:44 -0700757 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700758 op.set_span(*span);
759 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700760 }
761
Alex Crichtona74a1c82018-05-16 10:20:44 -0700762 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
763 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700764 }
765
Alex Crichtona74a1c82018-05-16 10:20:44 -0700766 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500767 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700768 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700769 {
David Tolnay00ab6982017-12-31 18:15:06 -0500770 let delim = match s {
771 "(" => Delimiter::Parenthesis,
772 "[" => Delimiter::Bracket,
773 "{" => Delimiter::Brace,
774 " " => Delimiter::None,
775 _ => panic!("unknown delimiter: {}", s),
776 };
hcplaa511792018-05-29 07:13:01 +0300777 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500778 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700779 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700780 g.set_span(*span);
781 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700782 }
783}