blob: 04d69670fe59c80621bc4065a0b68d55c917d5d2 [file] [log] [blame]
David Tolnaye79ae182018-01-06 19:23:37 -08001//! Tokens representing Rust punctuation, keywords, and delimiters.
Alex Crichton954046c2017-05-30 21:49:42 -07002//!
David Tolnaye79ae182018-01-06 19:23:37 -08003//! The type names in this module can be difficult to keep straight, so we
4//! prefer to use the [`Token!`] macro instead. This is a type-macro that
5//! expands to the token type of the given token.
6//!
7//! [`Token!`]: ../macro.Token.html
8//!
9//! # Example
10//!
11//! The [`ItemStatic`] syntax tree node is defined like this.
12//!
13//! [`ItemStatic`]: ../struct.ItemStatic.html
14//!
David Tolnay95989db2019-01-01 15:05:57 -050015//! ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -050016//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility};
David Tolnaye79ae182018-01-06 19:23:37 -080017//! #
18//! pub struct ItemStatic {
19//! pub attrs: Vec<Attribute>,
20//! pub vis: Visibility,
21//! pub static_token: Token![static],
22//! pub mutability: Option<Token![mut]>,
23//! pub ident: Ident,
24//! pub colon_token: Token![:],
25//! pub ty: Box<Type>,
26//! pub eq_token: Token![=],
27//! pub expr: Box<Expr>,
28//! pub semi_token: Token![;],
29//! }
David Tolnaye79ae182018-01-06 19:23:37 -080030//! ```
31//!
32//! # Parsing
33//!
David Tolnayd8cc0552018-08-31 08:39:17 -070034//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
35//! method. Delimiter tokens are parsed using the [`parenthesized!`],
36//! [`bracketed!`] and [`braced!`] macros.
David Tolnaye79ae182018-01-06 19:23:37 -080037//!
David Tolnayd8cc0552018-08-31 08:39:17 -070038//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
39//! [`parenthesized!`]: ../macro.parenthesized.html
40//! [`bracketed!`]: ../macro.bracketed.html
41//! [`braced!`]: ../macro.braced.html
David Tolnaye79ae182018-01-06 19:23:37 -080042//!
David Tolnay95989db2019-01-01 15:05:57 -050043//! ```edition2018
David Tolnay67fea042018-11-24 14:50:20 -080044//! use syn::{Attribute, Result};
45//! use syn::parse::{Parse, ParseStream};
David Tolnaye79ae182018-01-06 19:23:37 -080046//! #
David Tolnay9b00f652018-09-01 10:31:02 -070047//! # enum ItemStatic {}
David Tolnaye79ae182018-01-06 19:23:37 -080048//!
49//! // Parse the ItemStatic struct shown above.
David Tolnayd8cc0552018-08-31 08:39:17 -070050//! impl Parse for ItemStatic {
51//! fn parse(input: ParseStream) -> Result<Self> {
David Tolnay9b00f652018-09-01 10:31:02 -070052//! # use syn::ItemStatic;
53//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
54//! Ok(ItemStatic {
55//! attrs: input.call(Attribute::parse_outer)?,
56//! vis: input.parse()?,
57//! static_token: input.parse()?,
58//! mutability: input.parse()?,
59//! ident: input.parse()?,
60//! colon_token: input.parse()?,
61//! ty: input.parse()?,
62//! eq_token: input.parse()?,
63//! expr: input.parse()?,
64//! semi_token: input.parse()?,
65//! })
66//! # }
67//! # unimplemented!()
68//! }
David Tolnaye79ae182018-01-06 19:23:37 -080069//! }
David Tolnaye79ae182018-01-06 19:23:37 -080070//! ```
David Tolnay44d0d492019-02-02 08:33:54 -080071//!
72//! # Other operations
73//!
74//! Every keyword and punctuation token supports the following operations.
75//!
76//! - [Peeking] — `input.peek(Token![...])`
77//!
78//! - [Parsing] — `input.parse::<Token![...]>()?`
79//!
80//! - [Printing] — `quote!( ... #the_token ... )`
81//!
82//! - Construction from a [`Span`] — `let the_token = Token![...](sp)`
83//!
84//! - Field access to its span — `let sp = the_token.span`
85//!
86//! [Peeking]: ../parse/struct.ParseBuffer.html#method.peek
87//! [Parsing]: ../parse/struct.ParseBuffer.html#method.parse
88//! [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
David Tolnay85449262019-02-07 17:36:19 +010089//! [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html
Alex Crichton954046c2017-05-30 21:49:42 -070090
David Tolnay776f8e02018-08-24 22:32:10 -040091use std;
92#[cfg(feature = "extra-traits")]
93use std::cmp;
94#[cfg(feature = "extra-traits")]
95use std::fmt::{self, Debug};
96#[cfg(feature = "extra-traits")]
97use std::hash::{Hash, Hasher};
David Tolnay19ce0e72019-03-09 19:31:01 -080098use std::ops::{Deref, DerefMut};
David Tolnay776f8e02018-08-24 22:32:10 -040099
David Tolnay2d84a082018-08-25 16:31:38 -0400100#[cfg(feature = "parsing")]
101use proc_macro2::Delimiter;
David Tolnayaf1df8c2018-09-22 13:22:24 -0700102#[cfg(any(feature = "parsing", feature = "printing"))]
103use proc_macro2::Ident;
104use proc_macro2::Span;
David Tolnay776f8e02018-08-24 22:32:10 -0400105#[cfg(feature = "printing")]
David Tolnayabbf8192018-09-22 13:24:46 -0700106use proc_macro2::TokenStream;
107#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400108use quote::{ToTokens, TokenStreamExt};
109
David Tolnay19ce0e72019-03-09 19:31:01 -0800110use self::private::WithSpan;
David Tolnay776f8e02018-08-24 22:32:10 -0400111#[cfg(feature = "parsing")]
David Tolnay00f81fd2018-09-01 10:50:12 -0700112use buffer::Cursor;
113#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400114use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700115#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400116#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400117use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700118#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400119#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400120use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400121#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400122use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400123#[cfg(feature = "parsing")]
David Tolnay7fb11e72018-09-06 01:02:27 -0700124use parse::{Parse, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400125use span::IntoSpans;
126
127/// Marker trait for types that represent single tokens.
128///
129/// This trait is sealed and cannot be implemented for types outside of Syn.
130#[cfg(feature = "parsing")]
131pub trait Token: private::Sealed {
132 // Not public API.
133 #[doc(hidden)]
David Tolnay00f81fd2018-09-01 10:50:12 -0700134 fn peek(cursor: Cursor) -> bool;
David Tolnay776f8e02018-08-24 22:32:10 -0400135
136 // Not public API.
137 #[doc(hidden)]
David Tolnay2d032802018-09-01 10:51:59 -0700138 fn display() -> &'static str;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700139}
140
David Tolnay776f8e02018-08-24 22:32:10 -0400141mod private {
David Tolnay19ce0e72019-03-09 19:31:01 -0800142 use proc_macro2::Span;
143
144 #[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400145 pub trait Sealed {}
David Tolnay19ce0e72019-03-09 19:31:01 -0800146
147 /// Support writing `token.span` rather than `token.spans[0]` on tokens that
148 /// hold a single span.
149 #[repr(C)]
150 pub struct WithSpan {
151 pub span: Span,
152 }
Sergio Benitezd14d5362018-04-28 15:38:25 -0700153}
154
David Tolnay65557f02018-09-01 11:08:27 -0700155#[cfg(feature = "parsing")]
David Tolnay719ad5a2018-09-02 18:01:15 -0700156impl private::Sealed for Ident {}
157
David Tolnayff18ed92018-10-26 02:25:05 -0700158#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay719ad5a2018-09-02 18:01:15 -0700159#[cfg(feature = "parsing")]
David Tolnay65557f02018-09-01 11:08:27 -0700160fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
David Tolnayff18ed92018-10-26 02:25:05 -0700161 use std::cell::Cell;
162 use std::rc::Rc;
163
David Tolnay65557f02018-09-01 11:08:27 -0700164 let scope = Span::call_site();
165 let unexpected = Rc::new(Cell::new(None));
166 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
167 peek(&buffer)
168}
169
David Tolnayaf1df8c2018-09-22 13:22:24 -0700170#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay776f8e02018-08-24 22:32:10 -0400171macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400172 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400173 #[cfg(feature = "parsing")]
174 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700175 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700176 fn peek(input: ParseStream) -> bool {
177 <$name as Parse>::parse(input).is_ok()
178 }
179 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400180 }
181
David Tolnay2d032802018-09-01 10:51:59 -0700182 fn display() -> &'static str {
183 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400184 }
185 }
186
187 #[cfg(feature = "parsing")]
188 impl private::Sealed for $name {}
189 };
190}
191
David Tolnaya465b2d2018-08-27 08:21:09 -0700192#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400193impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700194#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400195impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700196#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400197impl_token!(LitStr "string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700198#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400199impl_token!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700200#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400201impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700202#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400203impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700204#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400205impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700206#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400207impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700208#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400209impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400210
David Tolnay7fb11e72018-09-06 01:02:27 -0700211// Not public API.
212#[cfg(feature = "parsing")]
213#[doc(hidden)]
214pub trait CustomKeyword {
215 fn ident() -> &'static str;
216 fn display() -> &'static str;
217}
218
219#[cfg(feature = "parsing")]
220impl<K: CustomKeyword> private::Sealed for K {}
221
222#[cfg(feature = "parsing")]
223impl<K: CustomKeyword> Token for K {
224 fn peek(cursor: Cursor) -> bool {
225 parsing::peek_keyword(cursor, K::ident())
226 }
227
228 fn display() -> &'static str {
229 K::display()
230 }
231}
232
David Tolnay776f8e02018-08-24 22:32:10 -0400233macro_rules! define_keywords {
234 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
235 $(
236 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
237 #[$doc]
238 ///
239 /// Don't try to remember the name of this type -- use the [`Token!`]
240 /// macro instead.
241 ///
242 /// [`Token!`]: index.html
243 pub struct $name {
244 pub span: Span,
245 }
246
247 #[doc(hidden)]
248 #[allow(non_snake_case)]
249 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
250 $name {
251 span: span.into_spans()[0],
252 }
253 }
254
David Tolnay776f8e02018-08-24 22:32:10 -0400255 impl std::default::Default for $name {
256 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700257 $name {
258 span: Span::call_site(),
259 }
David Tolnay776f8e02018-08-24 22:32:10 -0400260 }
261 }
262
263 #[cfg(feature = "extra-traits")]
264 impl Debug for $name {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 f.write_str(stringify!($name))
267 }
268 }
269
270 #[cfg(feature = "extra-traits")]
271 impl cmp::Eq for $name {}
272
273 #[cfg(feature = "extra-traits")]
274 impl PartialEq for $name {
275 fn eq(&self, _other: &$name) -> bool {
276 true
277 }
278 }
279
280 #[cfg(feature = "extra-traits")]
281 impl Hash for $name {
282 fn hash<H: Hasher>(&self, _state: &mut H) {}
283 }
284
285 #[cfg(feature = "printing")]
286 impl ToTokens for $name {
287 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800288 printing::keyword($token, self.span, tokens);
David Tolnay776f8e02018-08-24 22:32:10 -0400289 }
290 }
291
292 #[cfg(feature = "parsing")]
293 impl Parse for $name {
294 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700295 Ok($name {
296 span: parsing::keyword(input, $token)?,
297 })
David Tolnay776f8e02018-08-24 22:32:10 -0400298 }
299 }
David Tolnay68274de2018-09-02 17:15:01 -0700300
301 #[cfg(feature = "parsing")]
302 impl Token for $name {
303 fn peek(cursor: Cursor) -> bool {
304 parsing::peek_keyword(cursor, $token)
305 }
306
307 fn display() -> &'static str {
308 concat!("`", $token, "`")
309 }
310 }
311
312 #[cfg(feature = "parsing")]
313 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400314 )*
315 };
316}
317
David Tolnay19ce0e72019-03-09 19:31:01 -0800318macro_rules! impl_deref_if_len_is_1 {
319 ($name:ident/1) => {
320 impl Deref for $name {
321 type Target = WithSpan;
322
323 fn deref(&self) -> &Self::Target {
324 unsafe { &*(self as *const Self as *const WithSpan) }
325 }
326 }
327
328 impl DerefMut for $name {
329 fn deref_mut(&mut self) -> &mut Self::Target {
330 unsafe { &mut *(self as *mut Self as *mut WithSpan) }
331 }
332 }
333 };
334
335 ($name:ident/$len:tt) => {};
336}
337
David Tolnay776f8e02018-08-24 22:32:10 -0400338macro_rules! define_punctuation_structs {
339 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
340 $(
341 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
David Tolnay19ce0e72019-03-09 19:31:01 -0800342 #[repr(C)]
David Tolnay776f8e02018-08-24 22:32:10 -0400343 #[$doc]
344 ///
345 /// Don't try to remember the name of this type -- use the [`Token!`]
346 /// macro instead.
347 ///
348 /// [`Token!`]: index.html
349 pub struct $name {
350 pub spans: [Span; $len],
351 }
352
353 #[doc(hidden)]
354 #[allow(non_snake_case)]
355 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
356 $name {
357 spans: spans.into_spans(),
358 }
359 }
360
David Tolnay776f8e02018-08-24 22:32:10 -0400361 impl std::default::Default for $name {
362 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700363 $name {
364 spans: [Span::call_site(); $len],
365 }
David Tolnay776f8e02018-08-24 22:32:10 -0400366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 impl Debug for $name {
371 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372 f.write_str(stringify!($name))
373 }
374 }
375
376 #[cfg(feature = "extra-traits")]
377 impl cmp::Eq for $name {}
378
379 #[cfg(feature = "extra-traits")]
380 impl PartialEq for $name {
381 fn eq(&self, _other: &$name) -> bool {
382 true
383 }
384 }
385
386 #[cfg(feature = "extra-traits")]
387 impl Hash for $name {
388 fn hash<H: Hasher>(&self, _state: &mut H) {}
389 }
David Tolnay19ce0e72019-03-09 19:31:01 -0800390
391 impl_deref_if_len_is_1!($name/$len);
David Tolnay776f8e02018-08-24 22:32:10 -0400392 )*
393 };
394}
395
396macro_rules! define_punctuation {
397 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
398 $(
399 define_punctuation_structs! {
400 $token pub struct $name/$len #[$doc]
401 }
402
403 #[cfg(feature = "printing")]
404 impl ToTokens for $name {
405 fn to_tokens(&self, tokens: &mut TokenStream) {
406 printing::punct($token, &self.spans, tokens);
407 }
408 }
409
410 #[cfg(feature = "parsing")]
411 impl Parse for $name {
412 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700413 Ok($name {
414 spans: parsing::punct(input, $token)?,
415 })
David Tolnay776f8e02018-08-24 22:32:10 -0400416 }
417 }
David Tolnay68274de2018-09-02 17:15:01 -0700418
419 #[cfg(feature = "parsing")]
420 impl Token for $name {
421 fn peek(cursor: Cursor) -> bool {
422 parsing::peek_punct(cursor, $token)
423 }
424
425 fn display() -> &'static str {
426 concat!("`", $token, "`")
427 }
428 }
429
430 #[cfg(feature = "parsing")]
431 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400432 )*
433 };
434}
435
436macro_rules! define_delimiters {
437 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
438 $(
439 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
440 #[$doc]
441 pub struct $name {
442 pub span: Span,
443 }
444
445 #[doc(hidden)]
446 #[allow(non_snake_case)]
447 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
448 $name {
449 span: span.into_spans()[0],
450 }
451 }
452
453 impl std::default::Default for $name {
454 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700455 $name {
456 span: Span::call_site(),
457 }
David Tolnay776f8e02018-08-24 22:32:10 -0400458 }
459 }
460
461 #[cfg(feature = "extra-traits")]
462 impl Debug for $name {
463 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464 f.write_str(stringify!($name))
465 }
466 }
467
468 #[cfg(feature = "extra-traits")]
469 impl cmp::Eq for $name {}
470
471 #[cfg(feature = "extra-traits")]
472 impl PartialEq for $name {
473 fn eq(&self, _other: &$name) -> bool {
474 true
475 }
476 }
477
478 #[cfg(feature = "extra-traits")]
479 impl Hash for $name {
480 fn hash<H: Hasher>(&self, _state: &mut H) {}
481 }
482
483 impl $name {
484 #[cfg(feature = "printing")]
485 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
486 where
487 F: FnOnce(&mut TokenStream),
488 {
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800489 printing::delim($token, self.span, tokens, f);
David Tolnay776f8e02018-08-24 22:32:10 -0400490 }
David Tolnay776f8e02018-08-24 22:32:10 -0400491 }
David Tolnay2d84a082018-08-25 16:31:38 -0400492
493 #[cfg(feature = "parsing")]
494 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400495 )*
496 };
497}
498
499define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400500 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700501}
502
David Tolnay776f8e02018-08-24 22:32:10 -0400503#[cfg(feature = "printing")]
504impl ToTokens for Underscore {
505 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnaycefc7882019-03-09 19:47:16 -0800506 tokens.append(Ident::new("_", self.span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700507 }
David Tolnay776f8e02018-08-24 22:32:10 -0400508}
509
510#[cfg(feature = "parsing")]
511impl Parse for Underscore {
512 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700513 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400514 if let Some((ident, rest)) = cursor.ident() {
515 if ident == "_" {
516 return Ok((Underscore(ident.span()), rest));
517 }
518 }
519 if let Some((punct, rest)) = cursor.punct() {
520 if punct.as_char() == '_' {
521 return Ok((Underscore(punct.span()), rest));
522 }
523 }
524 Err(cursor.error("expected `_`"))
525 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700526 }
David Tolnay776f8e02018-08-24 22:32:10 -0400527}
528
David Tolnay2d84a082018-08-25 16:31:38 -0400529#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700530impl Token for Underscore {
531 fn peek(cursor: Cursor) -> bool {
532 if let Some((ident, _rest)) = cursor.ident() {
533 return ident == "_";
534 }
535 if let Some((punct, _rest)) = cursor.punct() {
David Tolnay3db288c2018-09-09 22:16:51 -0700536 return punct.as_char() == '_';
David Tolnay68274de2018-09-02 17:15:01 -0700537 }
538 false
539 }
540
541 fn display() -> &'static str {
542 "`_`"
543 }
544}
545
546#[cfg(feature = "parsing")]
547impl private::Sealed for Underscore {}
548
549#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400550impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700551 fn peek(cursor: Cursor) -> bool {
552 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400553 }
554
David Tolnay2d032802018-09-01 10:51:59 -0700555 fn display() -> &'static str {
556 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400557 }
558}
559
560#[cfg(feature = "parsing")]
561impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700562 fn peek(cursor: Cursor) -> bool {
563 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400564 }
565
David Tolnay2d032802018-09-01 10:51:59 -0700566 fn display() -> &'static str {
567 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400568 }
569}
570
571#[cfg(feature = "parsing")]
572impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700573 fn peek(cursor: Cursor) -> bool {
574 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400575 }
576
David Tolnay2d032802018-09-01 10:51:59 -0700577 fn display() -> &'static str {
578 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400579 }
580}
581
David Tolnaya7d69fc2018-08-26 13:30:24 -0400582#[cfg(feature = "parsing")]
583impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700584 fn peek(cursor: Cursor) -> bool {
585 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400586 }
587
David Tolnay2d032802018-09-01 10:51:59 -0700588 fn display() -> &'static str {
589 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400590 }
591}
592
David Tolnay776f8e02018-08-24 22:32:10 -0400593define_keywords! {
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700594 "abstract" pub struct Abstract /// `abstract`
David Tolnay776f8e02018-08-24 22:32:10 -0400595 "as" pub struct As /// `as`
596 "async" pub struct Async /// `async`
597 "auto" pub struct Auto /// `auto`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700598 "become" pub struct Become /// `become`
David Tolnay776f8e02018-08-24 22:32:10 -0400599 "box" pub struct Box /// `box`
600 "break" pub struct Break /// `break`
David Tolnay776f8e02018-08-24 22:32:10 -0400601 "const" pub struct Const /// `const`
602 "continue" pub struct Continue /// `continue`
603 "crate" pub struct Crate /// `crate`
604 "default" pub struct Default /// `default`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700605 "do" pub struct Do /// `do`
David Tolnay776f8e02018-08-24 22:32:10 -0400606 "dyn" pub struct Dyn /// `dyn`
607 "else" pub struct Else /// `else`
608 "enum" pub struct Enum /// `enum`
609 "existential" pub struct Existential /// `existential`
610 "extern" pub struct Extern /// `extern`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700611 "final" pub struct Final /// `final`
David Tolnay776f8e02018-08-24 22:32:10 -0400612 "fn" pub struct Fn /// `fn`
613 "for" pub struct For /// `for`
614 "if" pub struct If /// `if`
615 "impl" pub struct Impl /// `impl`
616 "in" pub struct In /// `in`
617 "let" pub struct Let /// `let`
618 "loop" pub struct Loop /// `loop`
619 "macro" pub struct Macro /// `macro`
620 "match" pub struct Match /// `match`
621 "mod" pub struct Mod /// `mod`
622 "move" pub struct Move /// `move`
623 "mut" pub struct Mut /// `mut`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700624 "override" pub struct Override /// `override`
625 "priv" pub struct Priv /// `priv`
David Tolnay776f8e02018-08-24 22:32:10 -0400626 "pub" pub struct Pub /// `pub`
627 "ref" pub struct Ref /// `ref`
628 "return" pub struct Return /// `return`
David Tolnayc0e742d2018-10-30 02:17:17 -0700629 "Self" pub struct SelfType /// `Self`
csmoef04dcc02018-10-30 16:45:13 +0800630 "self" pub struct SelfValue /// `self`
David Tolnay776f8e02018-08-24 22:32:10 -0400631 "static" pub struct Static /// `static`
632 "struct" pub struct Struct /// `struct`
633 "super" pub struct Super /// `super`
634 "trait" pub struct Trait /// `trait`
635 "try" pub struct Try /// `try`
636 "type" pub struct Type /// `type`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700637 "typeof" pub struct Typeof /// `typeof`
David Tolnay776f8e02018-08-24 22:32:10 -0400638 "union" pub struct Union /// `union`
639 "unsafe" pub struct Unsafe /// `unsafe`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700640 "unsized" pub struct Unsized /// `unsized`
David Tolnay776f8e02018-08-24 22:32:10 -0400641 "use" pub struct Use /// `use`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700642 "virtual" pub struct Virtual /// `virtual`
David Tolnay776f8e02018-08-24 22:32:10 -0400643 "where" pub struct Where /// `where`
644 "while" pub struct While /// `while`
645 "yield" pub struct Yield /// `yield`
646}
647
648define_punctuation! {
649 "+" pub struct Add/1 /// `+`
650 "+=" pub struct AddEq/2 /// `+=`
651 "&" pub struct And/1 /// `&`
652 "&&" pub struct AndAnd/2 /// `&&`
653 "&=" pub struct AndEq/2 /// `&=`
654 "@" pub struct At/1 /// `@`
655 "!" pub struct Bang/1 /// `!`
656 "^" pub struct Caret/1 /// `^`
657 "^=" pub struct CaretEq/2 /// `^=`
658 ":" pub struct Colon/1 /// `:`
659 "::" pub struct Colon2/2 /// `::`
660 "," pub struct Comma/1 /// `,`
661 "/" pub struct Div/1 /// `/`
662 "/=" pub struct DivEq/2 /// `/=`
663 "$" pub struct Dollar/1 /// `$`
664 "." pub struct Dot/1 /// `.`
665 ".." pub struct Dot2/2 /// `..`
666 "..." pub struct Dot3/3 /// `...`
667 "..=" pub struct DotDotEq/3 /// `..=`
668 "=" pub struct Eq/1 /// `=`
669 "==" pub struct EqEq/2 /// `==`
670 ">=" pub struct Ge/2 /// `>=`
671 ">" pub struct Gt/1 /// `>`
672 "<=" pub struct Le/2 /// `<=`
673 "<" pub struct Lt/1 /// `<`
674 "*=" pub struct MulEq/2 /// `*=`
675 "!=" pub struct Ne/2 /// `!=`
676 "|" pub struct Or/1 /// `|`
677 "|=" pub struct OrEq/2 /// `|=`
678 "||" pub struct OrOr/2 /// `||`
679 "#" pub struct Pound/1 /// `#`
680 "?" pub struct Question/1 /// `?`
681 "->" pub struct RArrow/2 /// `->`
682 "<-" pub struct LArrow/2 /// `<-`
683 "%" pub struct Rem/1 /// `%`
684 "%=" pub struct RemEq/2 /// `%=`
685 "=>" pub struct FatArrow/2 /// `=>`
686 ";" pub struct Semi/1 /// `;`
687 "<<" pub struct Shl/2 /// `<<`
688 "<<=" pub struct ShlEq/3 /// `<<=`
689 ">>" pub struct Shr/2 /// `>>`
690 ">>=" pub struct ShrEq/3 /// `>>=`
691 "*" pub struct Star/1 /// `*`
692 "-" pub struct Sub/1 /// `-`
693 "-=" pub struct SubEq/2 /// `-=`
David Tolnayf26be7d2018-09-23 01:32:08 -0700694 "~" pub struct Tilde/1 /// `~`
David Tolnay776f8e02018-08-24 22:32:10 -0400695}
696
697define_delimiters! {
698 "{" pub struct Brace /// `{...}`
699 "[" pub struct Bracket /// `[...]`
700 "(" pub struct Paren /// `(...)`
701 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700702}
703
David Tolnayf005f962018-01-06 21:19:41 -0800704/// A type-macro that expands to the name of the Rust type representation of a
705/// given token.
706///
707/// See the [token module] documentation for details and examples.
708///
709/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800710// Unfortunate duplication due to a rustdoc bug.
711// https://github.com/rust-lang/rust/issues/45939
712#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700713#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800714macro_rules! Token {
David Tolnayc327cd22018-09-09 00:37:28 -0700715 (abstract) => { $crate::token::Abstract };
David Tolnay776f8e02018-08-24 22:32:10 -0400716 (as) => { $crate::token::As };
717 (async) => { $crate::token::Async };
718 (auto) => { $crate::token::Auto };
David Tolnayc327cd22018-09-09 00:37:28 -0700719 (become) => { $crate::token::Become };
David Tolnay776f8e02018-08-24 22:32:10 -0400720 (box) => { $crate::token::Box };
721 (break) => { $crate::token::Break };
David Tolnay776f8e02018-08-24 22:32:10 -0400722 (const) => { $crate::token::Const };
723 (continue) => { $crate::token::Continue };
724 (crate) => { $crate::token::Crate };
725 (default) => { $crate::token::Default };
David Tolnayc327cd22018-09-09 00:37:28 -0700726 (do) => { $crate::token::Do };
David Tolnay776f8e02018-08-24 22:32:10 -0400727 (dyn) => { $crate::token::Dyn };
728 (else) => { $crate::token::Else };
729 (enum) => { $crate::token::Enum };
730 (existential) => { $crate::token::Existential };
731 (extern) => { $crate::token::Extern };
David Tolnayc327cd22018-09-09 00:37:28 -0700732 (final) => { $crate::token::Final };
David Tolnay776f8e02018-08-24 22:32:10 -0400733 (fn) => { $crate::token::Fn };
734 (for) => { $crate::token::For };
735 (if) => { $crate::token::If };
736 (impl) => { $crate::token::Impl };
737 (in) => { $crate::token::In };
738 (let) => { $crate::token::Let };
739 (loop) => { $crate::token::Loop };
740 (macro) => { $crate::token::Macro };
741 (match) => { $crate::token::Match };
742 (mod) => { $crate::token::Mod };
743 (move) => { $crate::token::Move };
744 (mut) => { $crate::token::Mut };
David Tolnayc327cd22018-09-09 00:37:28 -0700745 (override) => { $crate::token::Override };
746 (priv) => { $crate::token::Priv };
David Tolnay776f8e02018-08-24 22:32:10 -0400747 (pub) => { $crate::token::Pub };
748 (ref) => { $crate::token::Ref };
749 (return) => { $crate::token::Return };
David Tolnayc0e742d2018-10-30 02:17:17 -0700750 (Self) => { $crate::token::SelfType };
csmoef04dcc02018-10-30 16:45:13 +0800751 (self) => { $crate::token::SelfValue };
David Tolnay776f8e02018-08-24 22:32:10 -0400752 (static) => { $crate::token::Static };
753 (struct) => { $crate::token::Struct };
754 (super) => { $crate::token::Super };
755 (trait) => { $crate::token::Trait };
756 (try) => { $crate::token::Try };
757 (type) => { $crate::token::Type };
David Tolnayc327cd22018-09-09 00:37:28 -0700758 (typeof) => { $crate::token::Typeof };
David Tolnay776f8e02018-08-24 22:32:10 -0400759 (union) => { $crate::token::Union };
760 (unsafe) => { $crate::token::Unsafe };
David Tolnayc327cd22018-09-09 00:37:28 -0700761 (unsized) => { $crate::token::Unsized };
David Tolnay776f8e02018-08-24 22:32:10 -0400762 (use) => { $crate::token::Use };
David Tolnayc327cd22018-09-09 00:37:28 -0700763 (virtual) => { $crate::token::Virtual };
David Tolnay776f8e02018-08-24 22:32:10 -0400764 (where) => { $crate::token::Where };
765 (while) => { $crate::token::While };
766 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400767 (+) => { $crate::token::Add };
768 (+=) => { $crate::token::AddEq };
769 (&) => { $crate::token::And };
770 (&&) => { $crate::token::AndAnd };
771 (&=) => { $crate::token::AndEq };
772 (@) => { $crate::token::At };
773 (!) => { $crate::token::Bang };
774 (^) => { $crate::token::Caret };
775 (^=) => { $crate::token::CaretEq };
776 (:) => { $crate::token::Colon };
777 (::) => { $crate::token::Colon2 };
778 (,) => { $crate::token::Comma };
779 (/) => { $crate::token::Div };
780 (/=) => { $crate::token::DivEq };
781 (.) => { $crate::token::Dot };
782 (..) => { $crate::token::Dot2 };
783 (...) => { $crate::token::Dot3 };
784 (..=) => { $crate::token::DotDotEq };
785 (=) => { $crate::token::Eq };
786 (==) => { $crate::token::EqEq };
787 (>=) => { $crate::token::Ge };
788 (>) => { $crate::token::Gt };
789 (<=) => { $crate::token::Le };
790 (<) => { $crate::token::Lt };
791 (*=) => { $crate::token::MulEq };
792 (!=) => { $crate::token::Ne };
793 (|) => { $crate::token::Or };
794 (|=) => { $crate::token::OrEq };
795 (||) => { $crate::token::OrOr };
796 (#) => { $crate::token::Pound };
797 (?) => { $crate::token::Question };
798 (->) => { $crate::token::RArrow };
799 (<-) => { $crate::token::LArrow };
800 (%) => { $crate::token::Rem };
801 (%=) => { $crate::token::RemEq };
802 (=>) => { $crate::token::FatArrow };
803 (;) => { $crate::token::Semi };
804 (<<) => { $crate::token::Shl };
805 (<<=) => { $crate::token::ShlEq };
806 (>>) => { $crate::token::Shr };
807 (>>=) => { $crate::token::ShrEq };
808 (*) => { $crate::token::Star };
809 (-) => { $crate::token::Sub };
810 (-=) => { $crate::token::SubEq };
David Tolnayf26be7d2018-09-23 01:32:08 -0700811 (~) => { $crate::token::Tilde };
David Tolnaybb82ef02018-08-24 20:15:45 -0400812 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800813}
814
David Tolnayee612812018-10-30 02:16:03 -0700815// Old names. TODO: remove these re-exports in a breaking change.
816// https://github.com/dtolnay/syn/issues/486
817#[doc(hidden)]
818pub use self::SelfType as CapSelf;
819#[doc(hidden)]
820pub use self::SelfValue as Self_;
821
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700822#[cfg(feature = "parsing")]
823mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700824 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700825
David Tolnay68274de2018-09-02 17:15:01 -0700826 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400827 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400828 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400829 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700830
David Tolnay776f8e02018-08-24 22:32:10 -0400831 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700832 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400833 if let Some((ident, rest)) = cursor.ident() {
834 if ident == token {
835 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700836 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700837 }
David Tolnay776f8e02018-08-24 22:32:10 -0400838 Err(cursor.error(format!("expected `{}`", token)))
839 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700840 }
841
David Tolnay68274de2018-09-02 17:15:01 -0700842 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
843 if let Some((ident, _rest)) = cursor.ident() {
844 ident == token
845 } else {
846 false
847 }
848 }
849
David Tolnay776f8e02018-08-24 22:32:10 -0400850 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700851 let mut spans = [input.cursor().span(); 3];
852 punct_helper(input, token, &mut spans)?;
853 Ok(S::from_spans(&spans))
854 }
855
856 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700857 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400858 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400859 assert!(token.len() <= spans.len());
860
861 for (i, ch) in token.chars().enumerate() {
862 match cursor.punct() {
863 Some((punct, rest)) => {
864 spans[i] = punct.span();
865 if punct.as_char() != ch {
866 break;
867 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700868 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400869 } else if punct.spacing() != Spacing::Joint {
870 break;
871 }
872 cursor = rest;
873 }
874 None => break,
875 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400876 }
David Tolnay776f8e02018-08-24 22:32:10 -0400877
878 Err(Error::new(spans[0], format!("expected `{}`", token)))
879 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700880 }
David Tolnay68274de2018-09-02 17:15:01 -0700881
882 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
883 for (i, ch) in token.chars().enumerate() {
884 match cursor.punct() {
885 Some((punct, rest)) => {
886 if punct.as_char() != ch {
887 break;
888 } else if i == token.len() - 1 {
889 return true;
890 } else if punct.spacing() != Spacing::Joint {
891 break;
892 }
893 cursor = rest;
894 }
895 None => break,
896 }
897 }
898 false
899 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700900}
901
902#[cfg(feature = "printing")]
903mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700904 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700905 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700906
Alex Crichtona74a1c82018-05-16 10:20:44 -0700907 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700908 assert_eq!(s.len(), spans.len());
909
910 let mut chars = s.chars();
911 let mut spans = spans.iter();
912 let ch = chars.next_back().unwrap();
913 let span = spans.next_back().unwrap();
914 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700915 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700916 op.set_span(*span);
917 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700918 }
919
Alex Crichtona74a1c82018-05-16 10:20:44 -0700920 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700921 op.set_span(*span);
922 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700923 }
924
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800925 pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
926 tokens.append(Ident::new(s, span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700927 }
928
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800929 pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500930 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700931 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700932 {
David Tolnay00ab6982017-12-31 18:15:06 -0500933 let delim = match s {
934 "(" => Delimiter::Parenthesis,
935 "[" => Delimiter::Bracket,
936 "{" => Delimiter::Brace,
937 " " => Delimiter::None,
938 _ => panic!("unknown delimiter: {}", s),
939 };
hcplaa511792018-05-29 07:13:01 +0300940 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500941 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700942 let mut g = Group::new(delim, inner);
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800943 g.set_span(span);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700944 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700945 }
946}