blob: 0d33839ccd23bfcaf2308ab454c84835e32591b9 [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;
David Tolnay8c39ac52018-08-25 08:46:21 -0400108#[cfg(any(feature = "printing", feature = "parsing"))]
109use proc_macro2::Spacing;
David Tolnay65fb5662018-05-20 20:02:28 -0700110use proc_macro2::{Ident, Span};
Sergio Benitezd14d5362018-04-28 15:38:25 -0700111#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400112use proc_macro2::{Punct, TokenStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400113#[cfg(feature = "printing")]
114use quote::{ToTokens, TokenStreamExt};
115
116#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400117use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700118#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400119#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400120use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700121#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400122#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400123use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400124#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400125use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400126#[cfg(feature = "parsing")]
David Tolnayd9836922018-08-25 18:05:36 -0400127use parse::{Lookahead1, Parse, ParseBuffer, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400128use span::IntoSpans;
129
130/// Marker trait for types that represent single tokens.
131///
132/// This trait is sealed and cannot be implemented for types outside of Syn.
133#[cfg(feature = "parsing")]
134pub trait Token: private::Sealed {
135 // Not public API.
136 #[doc(hidden)]
137 fn peek(lookahead: &Lookahead1) -> bool;
138
139 // Not public API.
140 #[doc(hidden)]
141 fn display() -> String;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700142}
143
144#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400145mod private {
146 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700147}
148
David Tolnay776f8e02018-08-24 22:32:10 -0400149macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400150 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400151 #[cfg(feature = "parsing")]
152 impl Token for $name {
153 fn peek(lookahead: &Lookahead1) -> bool {
David Tolnayd9836922018-08-25 18:05:36 -0400154 // TODO factor out in a way that can be compiled just once
155 let scope = Span::call_site();
156 let cursor = lookahead.cursor();
157 let unexpected = Rc::new(Cell::new(None));
158 ParseBuffer::new(scope, cursor, unexpected)
159 .parse::<Self>()
160 .is_ok()
David Tolnay776f8e02018-08-24 22:32:10 -0400161 }
162
163 fn display() -> String {
David Tolnay4fb71232018-08-25 23:14:50 -0400164 $display.to_owned()
David Tolnay776f8e02018-08-24 22:32:10 -0400165 }
166 }
167
168 #[cfg(feature = "parsing")]
169 impl private::Sealed for $name {}
170 };
171}
172
David Tolnay4fb71232018-08-25 23:14:50 -0400173impl_token!(Ident "identifier");
David Tolnaya465b2d2018-08-27 08:21:09 -0700174#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400175impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700176#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400177impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700178#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400179impl_token!(LitStr "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!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700182#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400183impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700184#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400185impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700186#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400187impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700188#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400189impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700190#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400191impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400192
David Tolnay776f8e02018-08-24 22:32:10 -0400193macro_rules! define_keywords {
194 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
195 $(
196 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
197 #[$doc]
198 ///
199 /// Don't try to remember the name of this type -- use the [`Token!`]
200 /// macro instead.
201 ///
202 /// [`Token!`]: index.html
203 pub struct $name {
204 pub span: Span,
205 }
206
207 #[doc(hidden)]
208 #[allow(non_snake_case)]
209 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
210 $name {
211 span: span.into_spans()[0],
212 }
213 }
214
David Tolnay4fb71232018-08-25 23:14:50 -0400215 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400216
217 impl std::default::Default for $name {
218 fn default() -> Self {
219 $name(Span::call_site())
220 }
221 }
222
223 #[cfg(feature = "extra-traits")]
224 impl Debug for $name {
225 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 f.write_str(stringify!($name))
227 }
228 }
229
230 #[cfg(feature = "extra-traits")]
231 impl cmp::Eq for $name {}
232
233 #[cfg(feature = "extra-traits")]
234 impl PartialEq for $name {
235 fn eq(&self, _other: &$name) -> bool {
236 true
237 }
238 }
239
240 #[cfg(feature = "extra-traits")]
241 impl Hash for $name {
242 fn hash<H: Hasher>(&self, _state: &mut H) {}
243 }
244
245 #[cfg(feature = "printing")]
246 impl ToTokens for $name {
247 fn to_tokens(&self, tokens: &mut TokenStream) {
248 printing::keyword($token, &self.span, tokens);
249 }
250 }
251
252 #[cfg(feature = "parsing")]
253 impl Parse for $name {
254 fn parse(input: ParseStream) -> Result<Self> {
255 parsing::keyword(input, $token).map($name)
256 }
257 }
258 )*
259 };
260}
261
262macro_rules! define_punctuation_structs {
263 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
264 $(
265 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
266 #[$doc]
267 ///
268 /// Don't try to remember the name of this type -- use the [`Token!`]
269 /// macro instead.
270 ///
271 /// [`Token!`]: index.html
272 pub struct $name {
273 pub spans: [Span; $len],
274 }
275
276 #[doc(hidden)]
277 #[allow(non_snake_case)]
278 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
279 $name {
280 spans: spans.into_spans(),
281 }
282 }
283
David Tolnay4fb71232018-08-25 23:14:50 -0400284 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400285
286 impl std::default::Default for $name {
287 fn default() -> Self {
288 $name([Span::call_site(); $len])
289 }
290 }
291
292 #[cfg(feature = "extra-traits")]
293 impl Debug for $name {
294 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295 f.write_str(stringify!($name))
296 }
297 }
298
299 #[cfg(feature = "extra-traits")]
300 impl cmp::Eq for $name {}
301
302 #[cfg(feature = "extra-traits")]
303 impl PartialEq for $name {
304 fn eq(&self, _other: &$name) -> bool {
305 true
306 }
307 }
308
309 #[cfg(feature = "extra-traits")]
310 impl Hash for $name {
311 fn hash<H: Hasher>(&self, _state: &mut H) {}
312 }
313 )*
314 };
315}
316
317macro_rules! define_punctuation {
318 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
319 $(
320 define_punctuation_structs! {
321 $token pub struct $name/$len #[$doc]
322 }
323
324 #[cfg(feature = "printing")]
325 impl ToTokens for $name {
326 fn to_tokens(&self, tokens: &mut TokenStream) {
327 printing::punct($token, &self.spans, tokens);
328 }
329 }
330
331 #[cfg(feature = "parsing")]
332 impl Parse for $name {
333 fn parse(input: ParseStream) -> Result<Self> {
334 parsing::punct(input, $token).map($name::<[Span; $len]>)
335 }
336 }
337 )*
338 };
339}
340
341macro_rules! define_delimiters {
342 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
343 $(
344 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
345 #[$doc]
346 pub struct $name {
347 pub span: Span,
348 }
349
350 #[doc(hidden)]
351 #[allow(non_snake_case)]
352 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
353 $name {
354 span: span.into_spans()[0],
355 }
356 }
357
358 impl std::default::Default for $name {
359 fn default() -> Self {
360 $name(Span::call_site())
361 }
362 }
363
364 #[cfg(feature = "extra-traits")]
365 impl Debug for $name {
366 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367 f.write_str(stringify!($name))
368 }
369 }
370
371 #[cfg(feature = "extra-traits")]
372 impl cmp::Eq for $name {}
373
374 #[cfg(feature = "extra-traits")]
375 impl PartialEq for $name {
376 fn eq(&self, _other: &$name) -> bool {
377 true
378 }
379 }
380
381 #[cfg(feature = "extra-traits")]
382 impl Hash for $name {
383 fn hash<H: Hasher>(&self, _state: &mut H) {}
384 }
385
386 impl $name {
387 #[cfg(feature = "printing")]
388 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
389 where
390 F: FnOnce(&mut TokenStream),
391 {
392 printing::delim($token, &self.span, tokens, f);
393 }
David Tolnay776f8e02018-08-24 22:32:10 -0400394 }
David Tolnay2d84a082018-08-25 16:31:38 -0400395
396 #[cfg(feature = "parsing")]
397 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400398 )*
399 };
400}
401
402define_punctuation_structs! {
403 "'" pub struct Apostrophe/1 /// `'`
404 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700405}
406
David Tolnayb2fc7ef2018-05-20 19:54:14 -0700407// Implement Clone anyway because it is required for cloning Lifetime.
408#[cfg(not(feature = "clone-impls"))]
409impl Clone for Apostrophe {
410 fn clone(&self) -> Self {
David Tolnay7ac699c2018-08-24 14:00:58 -0400411 Apostrophe(self.spans)
David Tolnayb2fc7ef2018-05-20 19:54:14 -0700412 }
413}
414
Alex Crichton131308c2018-05-18 14:00:24 -0700415#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400416impl ToTokens for Apostrophe {
417 fn to_tokens(&self, tokens: &mut TokenStream) {
418 let mut token = Punct::new('\'', Spacing::Joint);
David Tolnay7ac699c2018-08-24 14:00:58 -0400419 token.set_span(self.spans[0]);
Alex Crichton131308c2018-05-18 14:00:24 -0700420 tokens.append(token);
421 }
422}
423
424#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400425impl Parse for Apostrophe {
426 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700427 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400428 if let Some((punct, rest)) = cursor.punct() {
429 if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint {
430 return Ok((Apostrophe(punct.span()), rest));
Alex Crichton131308c2018-05-18 14:00:24 -0700431 }
432 }
David Tolnay776f8e02018-08-24 22:32:10 -0400433 Err(cursor.error("expected `'`"))
434 })
Alex Crichton131308c2018-05-18 14:00:24 -0700435 }
436}
437
David Tolnay776f8e02018-08-24 22:32:10 -0400438#[cfg(feature = "printing")]
439impl ToTokens for Underscore {
440 fn to_tokens(&self, tokens: &mut TokenStream) {
441 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700442 }
David Tolnay776f8e02018-08-24 22:32:10 -0400443}
444
445#[cfg(feature = "parsing")]
446impl Parse for Underscore {
447 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700448 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400449 if let Some((ident, rest)) = cursor.ident() {
450 if ident == "_" {
451 return Ok((Underscore(ident.span()), rest));
452 }
453 }
454 if let Some((punct, rest)) = cursor.punct() {
455 if punct.as_char() == '_' {
456 return Ok((Underscore(punct.span()), rest));
457 }
458 }
459 Err(cursor.error("expected `_`"))
460 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700461 }
David Tolnay776f8e02018-08-24 22:32:10 -0400462}
463
David Tolnay2d84a082018-08-25 16:31:38 -0400464#[cfg(feature = "parsing")]
465impl Token for Paren {
466 fn peek(lookahead: &Lookahead1) -> bool {
467 lookahead::is_delimiter(lookahead, Delimiter::Parenthesis)
468 }
469
470 fn display() -> String {
471 "parentheses".to_owned()
472 }
473}
474
475#[cfg(feature = "parsing")]
476impl Token for Brace {
477 fn peek(lookahead: &Lookahead1) -> bool {
478 lookahead::is_delimiter(lookahead, Delimiter::Brace)
479 }
480
481 fn display() -> String {
482 "curly braces".to_owned()
483 }
484}
485
486#[cfg(feature = "parsing")]
487impl Token for Bracket {
488 fn peek(lookahead: &Lookahead1) -> bool {
489 lookahead::is_delimiter(lookahead, Delimiter::Bracket)
490 }
491
492 fn display() -> String {
493 "square brackets".to_owned()
494 }
495}
496
David Tolnaya7d69fc2018-08-26 13:30:24 -0400497#[cfg(feature = "parsing")]
498impl Token for Group {
499 fn peek(lookahead: &Lookahead1) -> bool {
500 lookahead::is_delimiter(lookahead, Delimiter::None)
501 }
502
503 fn display() -> String {
504 "invisible group".to_owned()
505 }
506}
507
David Tolnay776f8e02018-08-24 22:32:10 -0400508define_keywords! {
509 "as" pub struct As /// `as`
510 "async" pub struct Async /// `async`
511 "auto" pub struct Auto /// `auto`
512 "box" pub struct Box /// `box`
513 "break" pub struct Break /// `break`
514 "Self" pub struct CapSelf /// `Self`
515 "const" pub struct Const /// `const`
516 "continue" pub struct Continue /// `continue`
517 "crate" pub struct Crate /// `crate`
518 "default" pub struct Default /// `default`
519 "dyn" pub struct Dyn /// `dyn`
520 "else" pub struct Else /// `else`
521 "enum" pub struct Enum /// `enum`
522 "existential" pub struct Existential /// `existential`
523 "extern" pub struct Extern /// `extern`
524 "fn" pub struct Fn /// `fn`
525 "for" pub struct For /// `for`
526 "if" pub struct If /// `if`
527 "impl" pub struct Impl /// `impl`
528 "in" pub struct In /// `in`
529 "let" pub struct Let /// `let`
530 "loop" pub struct Loop /// `loop`
531 "macro" pub struct Macro /// `macro`
532 "match" pub struct Match /// `match`
533 "mod" pub struct Mod /// `mod`
534 "move" pub struct Move /// `move`
535 "mut" pub struct Mut /// `mut`
536 "pub" pub struct Pub /// `pub`
537 "ref" pub struct Ref /// `ref`
538 "return" pub struct Return /// `return`
539 "self" pub struct Self_ /// `self`
540 "static" pub struct Static /// `static`
541 "struct" pub struct Struct /// `struct`
542 "super" pub struct Super /// `super`
543 "trait" pub struct Trait /// `trait`
544 "try" pub struct Try /// `try`
545 "type" pub struct Type /// `type`
546 "union" pub struct Union /// `union`
547 "unsafe" pub struct Unsafe /// `unsafe`
548 "use" pub struct Use /// `use`
549 "where" pub struct Where /// `where`
550 "while" pub struct While /// `while`
551 "yield" pub struct Yield /// `yield`
552}
553
554define_punctuation! {
555 "+" pub struct Add/1 /// `+`
556 "+=" pub struct AddEq/2 /// `+=`
557 "&" pub struct And/1 /// `&`
558 "&&" pub struct AndAnd/2 /// `&&`
559 "&=" pub struct AndEq/2 /// `&=`
560 "@" pub struct At/1 /// `@`
561 "!" pub struct Bang/1 /// `!`
562 "^" pub struct Caret/1 /// `^`
563 "^=" pub struct CaretEq/2 /// `^=`
564 ":" pub struct Colon/1 /// `:`
565 "::" pub struct Colon2/2 /// `::`
566 "," pub struct Comma/1 /// `,`
567 "/" pub struct Div/1 /// `/`
568 "/=" pub struct DivEq/2 /// `/=`
569 "$" pub struct Dollar/1 /// `$`
570 "." pub struct Dot/1 /// `.`
571 ".." pub struct Dot2/2 /// `..`
572 "..." pub struct Dot3/3 /// `...`
573 "..=" pub struct DotDotEq/3 /// `..=`
574 "=" pub struct Eq/1 /// `=`
575 "==" pub struct EqEq/2 /// `==`
576 ">=" pub struct Ge/2 /// `>=`
577 ">" pub struct Gt/1 /// `>`
578 "<=" pub struct Le/2 /// `<=`
579 "<" pub struct Lt/1 /// `<`
580 "*=" pub struct MulEq/2 /// `*=`
581 "!=" pub struct Ne/2 /// `!=`
582 "|" pub struct Or/1 /// `|`
583 "|=" pub struct OrEq/2 /// `|=`
584 "||" pub struct OrOr/2 /// `||`
585 "#" pub struct Pound/1 /// `#`
586 "?" pub struct Question/1 /// `?`
587 "->" pub struct RArrow/2 /// `->`
588 "<-" pub struct LArrow/2 /// `<-`
589 "%" pub struct Rem/1 /// `%`
590 "%=" pub struct RemEq/2 /// `%=`
591 "=>" pub struct FatArrow/2 /// `=>`
592 ";" pub struct Semi/1 /// `;`
593 "<<" pub struct Shl/2 /// `<<`
594 "<<=" pub struct ShlEq/3 /// `<<=`
595 ">>" pub struct Shr/2 /// `>>`
596 ">>=" pub struct ShrEq/3 /// `>>=`
597 "*" pub struct Star/1 /// `*`
598 "-" pub struct Sub/1 /// `-`
599 "-=" pub struct SubEq/2 /// `-=`
600}
601
602define_delimiters! {
603 "{" pub struct Brace /// `{...}`
604 "[" pub struct Bracket /// `[...]`
605 "(" pub struct Paren /// `(...)`
606 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700607}
608
David Tolnayf005f962018-01-06 21:19:41 -0800609/// A type-macro that expands to the name of the Rust type representation of a
610/// given token.
611///
612/// See the [token module] documentation for details and examples.
613///
614/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800615// Unfortunate duplication due to a rustdoc bug.
616// https://github.com/rust-lang/rust/issues/45939
617#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700618#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800619macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400620 (as) => { $crate::token::As };
621 (async) => { $crate::token::Async };
622 (auto) => { $crate::token::Auto };
623 (box) => { $crate::token::Box };
624 (break) => { $crate::token::Break };
625 (Self) => { $crate::token::CapSelf };
626 (const) => { $crate::token::Const };
627 (continue) => { $crate::token::Continue };
628 (crate) => { $crate::token::Crate };
629 (default) => { $crate::token::Default };
630 (dyn) => { $crate::token::Dyn };
631 (else) => { $crate::token::Else };
632 (enum) => { $crate::token::Enum };
633 (existential) => { $crate::token::Existential };
634 (extern) => { $crate::token::Extern };
635 (fn) => { $crate::token::Fn };
636 (for) => { $crate::token::For };
637 (if) => { $crate::token::If };
638 (impl) => { $crate::token::Impl };
639 (in) => { $crate::token::In };
640 (let) => { $crate::token::Let };
641 (loop) => { $crate::token::Loop };
642 (macro) => { $crate::token::Macro };
643 (match) => { $crate::token::Match };
644 (mod) => { $crate::token::Mod };
645 (move) => { $crate::token::Move };
646 (mut) => { $crate::token::Mut };
647 (pub) => { $crate::token::Pub };
648 (ref) => { $crate::token::Ref };
649 (return) => { $crate::token::Return };
650 (self) => { $crate::token::Self_ };
651 (static) => { $crate::token::Static };
652 (struct) => { $crate::token::Struct };
653 (super) => { $crate::token::Super };
654 (trait) => { $crate::token::Trait };
655 (try) => { $crate::token::Try };
656 (type) => { $crate::token::Type };
657 (union) => { $crate::token::Union };
658 (unsafe) => { $crate::token::Unsafe };
659 (use) => { $crate::token::Use };
660 (where) => { $crate::token::Where };
661 (while) => { $crate::token::While };
662 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400663 (+) => { $crate::token::Add };
664 (+=) => { $crate::token::AddEq };
665 (&) => { $crate::token::And };
666 (&&) => { $crate::token::AndAnd };
667 (&=) => { $crate::token::AndEq };
668 (@) => { $crate::token::At };
669 (!) => { $crate::token::Bang };
670 (^) => { $crate::token::Caret };
671 (^=) => { $crate::token::CaretEq };
672 (:) => { $crate::token::Colon };
673 (::) => { $crate::token::Colon2 };
674 (,) => { $crate::token::Comma };
675 (/) => { $crate::token::Div };
676 (/=) => { $crate::token::DivEq };
677 (.) => { $crate::token::Dot };
678 (..) => { $crate::token::Dot2 };
679 (...) => { $crate::token::Dot3 };
680 (..=) => { $crate::token::DotDotEq };
681 (=) => { $crate::token::Eq };
682 (==) => { $crate::token::EqEq };
683 (>=) => { $crate::token::Ge };
684 (>) => { $crate::token::Gt };
685 (<=) => { $crate::token::Le };
686 (<) => { $crate::token::Lt };
687 (*=) => { $crate::token::MulEq };
688 (!=) => { $crate::token::Ne };
689 (|) => { $crate::token::Or };
690 (|=) => { $crate::token::OrEq };
691 (||) => { $crate::token::OrOr };
692 (#) => { $crate::token::Pound };
693 (?) => { $crate::token::Question };
694 (->) => { $crate::token::RArrow };
695 (<-) => { $crate::token::LArrow };
696 (%) => { $crate::token::Rem };
697 (%=) => { $crate::token::RemEq };
698 (=>) => { $crate::token::FatArrow };
699 (;) => { $crate::token::Semi };
700 (<<) => { $crate::token::Shl };
701 (<<=) => { $crate::token::ShlEq };
702 (>>) => { $crate::token::Shr };
703 (>>=) => { $crate::token::ShrEq };
704 (*) => { $crate::token::Star };
705 (-) => { $crate::token::Sub };
706 (-=) => { $crate::token::SubEq };
707 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800708}
709
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700710macro_rules! ident_from_token {
711 ($token:ident) => {
712 impl From<Token![$token]> for Ident {
713 fn from(token: Token![$token]) -> Ident {
David Tolnay7ac699c2018-08-24 14:00:58 -0400714 Ident::new(stringify!($token), token.span)
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700715 }
716 }
717 };
718}
719
720ident_from_token!(self);
721ident_from_token!(Self);
722ident_from_token!(super);
723ident_from_token!(crate);
David Tolnay0a4d4e92018-07-21 15:31:45 -0700724ident_from_token!(extern);
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700725
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700726#[cfg(feature = "parsing")]
727mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700728 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700729
David Tolnayad4b2472018-08-25 08:25:24 -0400730 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400731 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400732 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700733
David Tolnay776f8e02018-08-24 22:32:10 -0400734 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700735 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400736 if let Some((ident, rest)) = cursor.ident() {
737 if ident == token {
738 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700739 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700740 }
David Tolnay776f8e02018-08-24 22:32:10 -0400741 Err(cursor.error(format!("expected `{}`", token)))
742 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700743 }
744
David Tolnay776f8e02018-08-24 22:32:10 -0400745 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700746 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400747 let mut cursor = *cursor;
748 let mut spans = [cursor.span(); 3];
749 assert!(token.len() <= spans.len());
750
751 for (i, ch) in token.chars().enumerate() {
752 match cursor.punct() {
753 Some((punct, rest)) => {
754 spans[i] = punct.span();
755 if punct.as_char() != ch {
756 break;
757 } else if i == token.len() - 1 {
758 return Ok((S::from_spans(&spans), rest));
759 } else if punct.spacing() != Spacing::Joint {
760 break;
761 }
762 cursor = rest;
763 }
764 None => break,
765 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400766 }
David Tolnay776f8e02018-08-24 22:32:10 -0400767
768 Err(Error::new(spans[0], format!("expected `{}`", token)))
769 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700770 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700771}
772
773#[cfg(feature = "printing")]
774mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700775 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700776 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700777
Alex Crichtona74a1c82018-05-16 10:20:44 -0700778 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700779 assert_eq!(s.len(), spans.len());
780
781 let mut chars = s.chars();
782 let mut spans = spans.iter();
783 let ch = chars.next_back().unwrap();
784 let span = spans.next_back().unwrap();
785 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700786 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700787 op.set_span(*span);
788 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700789 }
790
Alex Crichtona74a1c82018-05-16 10:20:44 -0700791 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700792 op.set_span(*span);
793 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700794 }
795
Alex Crichtona74a1c82018-05-16 10:20:44 -0700796 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
797 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700798 }
799
Alex Crichtona74a1c82018-05-16 10:20:44 -0700800 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500801 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700802 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700803 {
David Tolnay00ab6982017-12-31 18:15:06 -0500804 let delim = match s {
805 "(" => Delimiter::Parenthesis,
806 "[" => Delimiter::Bracket,
807 "{" => Delimiter::Brace,
808 " " => Delimiter::None,
809 _ => panic!("unknown delimiter: {}", s),
810 };
hcplaa511792018-05-29 07:13:01 +0300811 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500812 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700813 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700814 g.set_span(*span);
815 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700816 }
817}