blob: b1c83d2e76ed87d52bb89b19bccc01d17955dbe8 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnaye79ae182018-01-06 19:23:37 -08009//! Tokens representing Rust punctuation, keywords, and delimiters.
Alex Crichton954046c2017-05-30 21:49:42 -070010//!
David Tolnaye79ae182018-01-06 19:23:37 -080011//! The type names in this module can be difficult to keep straight, so we
12//! prefer to use the [`Token!`] macro instead. This is a type-macro that
13//! expands to the token type of the given token.
14//!
15//! [`Token!`]: ../macro.Token.html
16//!
17//! # Example
18//!
19//! The [`ItemStatic`] syntax tree node is defined like this.
20//!
21//! [`ItemStatic`]: ../struct.ItemStatic.html
22//!
23//! ```
David Tolnaya1c98072018-09-06 08:58:10 -070024//! # #[macro_use]
David Tolnaye79ae182018-01-06 19:23:37 -080025//! # extern crate syn;
26//! #
David Tolnaya1c98072018-09-06 08:58:10 -070027//! # use syn::{Attribute, Expr, Ident, Type, Visibility};
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 Tolnay9b00f652018-09-01 10:31:02 -070057//! # 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//! #
David Tolnay9b00f652018-09-01 10:31:02 -070062//! # enum 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> {
David Tolnay9b00f652018-09-01 10:31:02 -070067//! # use syn::ItemStatic;
68//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
69//! Ok(ItemStatic {
70//! attrs: input.call(Attribute::parse_outer)?,
71//! vis: input.parse()?,
72//! static_token: input.parse()?,
73//! mutability: input.parse()?,
74//! ident: input.parse()?,
75//! colon_token: input.parse()?,
76//! ty: input.parse()?,
77//! eq_token: input.parse()?,
78//! expr: input.parse()?,
79//! semi_token: input.parse()?,
80//! })
81//! # }
82//! # unimplemented!()
83//! }
David Tolnaye79ae182018-01-06 19:23:37 -080084//! }
85//! #
86//! # fn main() {}
87//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070088
David Tolnay776f8e02018-08-24 22:32:10 -040089use std;
David Tolnayd9836922018-08-25 18:05:36 -040090#[cfg(feature = "parsing")]
91use std::cell::Cell;
David Tolnay776f8e02018-08-24 22:32:10 -040092#[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 Tolnayd9836922018-08-25 18:05:36 -040098#[cfg(feature = "parsing")]
99use std::rc::Rc;
David Tolnay776f8e02018-08-24 22:32:10 -0400100
David Tolnay2d84a082018-08-25 16:31:38 -0400101#[cfg(feature = "parsing")]
102use proc_macro2::Delimiter;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700103#[cfg(feature = "printing")]
David Tolnay78612672018-08-31 08:47:41 -0700104use proc_macro2::TokenStream;
105use proc_macro2::{Ident, Span};
David Tolnay776f8e02018-08-24 22:32:10 -0400106#[cfg(feature = "printing")]
107use quote::{ToTokens, TokenStreamExt};
108
109#[cfg(feature = "parsing")]
David Tolnay00f81fd2018-09-01 10:50:12 -0700110use buffer::Cursor;
111#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400112use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700113#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400114#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400115use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700116#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400117#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400118use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400119#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400120use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400121#[cfg(feature = "parsing")]
David Tolnay7fb11e72018-09-06 01:02:27 -0700122use parse::{Parse, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400123use span::IntoSpans;
124
125/// Marker trait for types that represent single tokens.
126///
127/// This trait is sealed and cannot be implemented for types outside of Syn.
128#[cfg(feature = "parsing")]
129pub trait Token: private::Sealed {
130 // Not public API.
131 #[doc(hidden)]
David Tolnay00f81fd2018-09-01 10:50:12 -0700132 fn peek(cursor: Cursor) -> bool;
David Tolnay776f8e02018-08-24 22:32:10 -0400133
134 // Not public API.
135 #[doc(hidden)]
David Tolnay2d032802018-09-01 10:51:59 -0700136 fn display() -> &'static str;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700137}
138
139#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400140mod private {
141 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700142}
143
David Tolnay65557f02018-09-01 11:08:27 -0700144#[cfg(feature = "parsing")]
David Tolnay719ad5a2018-09-02 18:01:15 -0700145impl private::Sealed for Ident {}
146
147#[cfg(feature = "parsing")]
David Tolnay65557f02018-09-01 11:08:27 -0700148fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
149 let scope = Span::call_site();
150 let unexpected = Rc::new(Cell::new(None));
151 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
152 peek(&buffer)
153}
154
David Tolnay776f8e02018-08-24 22:32:10 -0400155macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400156 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400157 #[cfg(feature = "parsing")]
158 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700159 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700160 fn peek(input: ParseStream) -> bool {
161 <$name as Parse>::parse(input).is_ok()
162 }
163 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400164 }
165
David Tolnay2d032802018-09-01 10:51:59 -0700166 fn display() -> &'static str {
167 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400168 }
169 }
170
171 #[cfg(feature = "parsing")]
172 impl private::Sealed for $name {}
173 };
174}
175
David Tolnaya465b2d2018-08-27 08:21:09 -0700176#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400177impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700178#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400179impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700180#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400181impl_token!(LitStr "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!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700184#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400185impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700186#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400187impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700188#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400189impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700190#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400191impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700192#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400193impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400194
David Tolnay7fb11e72018-09-06 01:02:27 -0700195// Not public API.
196#[cfg(feature = "parsing")]
197#[doc(hidden)]
198pub trait CustomKeyword {
199 fn ident() -> &'static str;
200 fn display() -> &'static str;
201}
202
203#[cfg(feature = "parsing")]
204impl<K: CustomKeyword> private::Sealed for K {}
205
206#[cfg(feature = "parsing")]
207impl<K: CustomKeyword> Token for K {
208 fn peek(cursor: Cursor) -> bool {
209 parsing::peek_keyword(cursor, K::ident())
210 }
211
212 fn display() -> &'static str {
213 K::display()
214 }
215}
216
David Tolnay776f8e02018-08-24 22:32:10 -0400217macro_rules! define_keywords {
218 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
219 $(
220 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
221 #[$doc]
222 ///
223 /// Don't try to remember the name of this type -- use the [`Token!`]
224 /// macro instead.
225 ///
226 /// [`Token!`]: index.html
227 pub struct $name {
228 pub span: Span,
229 }
230
231 #[doc(hidden)]
232 #[allow(non_snake_case)]
233 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
234 $name {
235 span: span.into_spans()[0],
236 }
237 }
238
David Tolnay776f8e02018-08-24 22:32:10 -0400239 impl std::default::Default for $name {
240 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700241 $name {
242 span: Span::call_site(),
243 }
David Tolnay776f8e02018-08-24 22:32:10 -0400244 }
245 }
246
247 #[cfg(feature = "extra-traits")]
248 impl Debug for $name {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 f.write_str(stringify!($name))
251 }
252 }
253
254 #[cfg(feature = "extra-traits")]
255 impl cmp::Eq for $name {}
256
257 #[cfg(feature = "extra-traits")]
258 impl PartialEq for $name {
259 fn eq(&self, _other: &$name) -> bool {
260 true
261 }
262 }
263
264 #[cfg(feature = "extra-traits")]
265 impl Hash for $name {
266 fn hash<H: Hasher>(&self, _state: &mut H) {}
267 }
268
269 #[cfg(feature = "printing")]
270 impl ToTokens for $name {
271 fn to_tokens(&self, tokens: &mut TokenStream) {
272 printing::keyword($token, &self.span, tokens);
273 }
274 }
275
276 #[cfg(feature = "parsing")]
277 impl Parse for $name {
278 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700279 Ok($name {
280 span: parsing::keyword(input, $token)?,
281 })
David Tolnay776f8e02018-08-24 22:32:10 -0400282 }
283 }
David Tolnay68274de2018-09-02 17:15:01 -0700284
285 #[cfg(feature = "parsing")]
286 impl Token for $name {
287 fn peek(cursor: Cursor) -> bool {
288 parsing::peek_keyword(cursor, $token)
289 }
290
291 fn display() -> &'static str {
292 concat!("`", $token, "`")
293 }
294 }
295
296 #[cfg(feature = "parsing")]
297 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400298 )*
299 };
300}
301
302macro_rules! define_punctuation_structs {
303 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
304 $(
305 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
306 #[$doc]
307 ///
308 /// Don't try to remember the name of this type -- use the [`Token!`]
309 /// macro instead.
310 ///
311 /// [`Token!`]: index.html
312 pub struct $name {
313 pub spans: [Span; $len],
314 }
315
316 #[doc(hidden)]
317 #[allow(non_snake_case)]
318 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
319 $name {
320 spans: spans.into_spans(),
321 }
322 }
323
David Tolnay776f8e02018-08-24 22:32:10 -0400324 impl std::default::Default for $name {
325 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700326 $name {
327 spans: [Span::call_site(); $len],
328 }
David Tolnay776f8e02018-08-24 22:32:10 -0400329 }
330 }
331
332 #[cfg(feature = "extra-traits")]
333 impl Debug for $name {
334 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335 f.write_str(stringify!($name))
336 }
337 }
338
339 #[cfg(feature = "extra-traits")]
340 impl cmp::Eq for $name {}
341
342 #[cfg(feature = "extra-traits")]
343 impl PartialEq for $name {
344 fn eq(&self, _other: &$name) -> bool {
345 true
346 }
347 }
348
349 #[cfg(feature = "extra-traits")]
350 impl Hash for $name {
351 fn hash<H: Hasher>(&self, _state: &mut H) {}
352 }
353 )*
354 };
355}
356
357macro_rules! define_punctuation {
358 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
359 $(
360 define_punctuation_structs! {
361 $token pub struct $name/$len #[$doc]
362 }
363
364 #[cfg(feature = "printing")]
365 impl ToTokens for $name {
366 fn to_tokens(&self, tokens: &mut TokenStream) {
367 printing::punct($token, &self.spans, tokens);
368 }
369 }
370
371 #[cfg(feature = "parsing")]
372 impl Parse for $name {
373 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700374 Ok($name {
375 spans: parsing::punct(input, $token)?,
376 })
David Tolnay776f8e02018-08-24 22:32:10 -0400377 }
378 }
David Tolnay68274de2018-09-02 17:15:01 -0700379
380 #[cfg(feature = "parsing")]
381 impl Token for $name {
382 fn peek(cursor: Cursor) -> bool {
383 parsing::peek_punct(cursor, $token)
384 }
385
386 fn display() -> &'static str {
387 concat!("`", $token, "`")
388 }
389 }
390
391 #[cfg(feature = "parsing")]
392 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400393 )*
394 };
395}
396
397macro_rules! define_delimiters {
398 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
399 $(
400 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
401 #[$doc]
402 pub struct $name {
403 pub span: Span,
404 }
405
406 #[doc(hidden)]
407 #[allow(non_snake_case)]
408 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
409 $name {
410 span: span.into_spans()[0],
411 }
412 }
413
414 impl std::default::Default for $name {
415 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700416 $name {
417 span: Span::call_site(),
418 }
David Tolnay776f8e02018-08-24 22:32:10 -0400419 }
420 }
421
422 #[cfg(feature = "extra-traits")]
423 impl Debug for $name {
424 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425 f.write_str(stringify!($name))
426 }
427 }
428
429 #[cfg(feature = "extra-traits")]
430 impl cmp::Eq for $name {}
431
432 #[cfg(feature = "extra-traits")]
433 impl PartialEq for $name {
434 fn eq(&self, _other: &$name) -> bool {
435 true
436 }
437 }
438
439 #[cfg(feature = "extra-traits")]
440 impl Hash for $name {
441 fn hash<H: Hasher>(&self, _state: &mut H) {}
442 }
443
444 impl $name {
445 #[cfg(feature = "printing")]
446 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
447 where
448 F: FnOnce(&mut TokenStream),
449 {
450 printing::delim($token, &self.span, tokens, f);
451 }
David Tolnay776f8e02018-08-24 22:32:10 -0400452 }
David Tolnay2d84a082018-08-25 16:31:38 -0400453
454 #[cfg(feature = "parsing")]
455 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400456 )*
457 };
458}
459
460define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400461 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700462}
463
David Tolnay776f8e02018-08-24 22:32:10 -0400464#[cfg(feature = "printing")]
465impl ToTokens for Underscore {
466 fn to_tokens(&self, tokens: &mut TokenStream) {
467 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700468 }
David Tolnay776f8e02018-08-24 22:32:10 -0400469}
470
471#[cfg(feature = "parsing")]
472impl Parse for Underscore {
473 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700474 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400475 if let Some((ident, rest)) = cursor.ident() {
476 if ident == "_" {
477 return Ok((Underscore(ident.span()), rest));
478 }
479 }
480 if let Some((punct, rest)) = cursor.punct() {
481 if punct.as_char() == '_' {
482 return Ok((Underscore(punct.span()), rest));
483 }
484 }
485 Err(cursor.error("expected `_`"))
486 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700487 }
David Tolnay776f8e02018-08-24 22:32:10 -0400488}
489
David Tolnay2d84a082018-08-25 16:31:38 -0400490#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700491impl Token for Underscore {
492 fn peek(cursor: Cursor) -> bool {
493 if let Some((ident, _rest)) = cursor.ident() {
494 return ident == "_";
495 }
496 if let Some((punct, _rest)) = cursor.punct() {
497 return punct.as_char() == '_'
498 }
499 false
500 }
501
502 fn display() -> &'static str {
503 "`_`"
504 }
505}
506
507#[cfg(feature = "parsing")]
508impl private::Sealed for Underscore {}
509
510#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400511impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700512 fn peek(cursor: Cursor) -> bool {
513 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400514 }
515
David Tolnay2d032802018-09-01 10:51:59 -0700516 fn display() -> &'static str {
517 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400518 }
519}
520
521#[cfg(feature = "parsing")]
522impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700523 fn peek(cursor: Cursor) -> bool {
524 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400525 }
526
David Tolnay2d032802018-09-01 10:51:59 -0700527 fn display() -> &'static str {
528 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400529 }
530}
531
532#[cfg(feature = "parsing")]
533impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700534 fn peek(cursor: Cursor) -> bool {
535 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400536 }
537
David Tolnay2d032802018-09-01 10:51:59 -0700538 fn display() -> &'static str {
539 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400540 }
541}
542
David Tolnaya7d69fc2018-08-26 13:30:24 -0400543#[cfg(feature = "parsing")]
544impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700545 fn peek(cursor: Cursor) -> bool {
546 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400547 }
548
David Tolnay2d032802018-09-01 10:51:59 -0700549 fn display() -> &'static str {
550 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400551 }
552}
553
David Tolnay776f8e02018-08-24 22:32:10 -0400554define_keywords! {
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700555 "abstract" pub struct Abstract /// `abstract`
David Tolnay776f8e02018-08-24 22:32:10 -0400556 "as" pub struct As /// `as`
557 "async" pub struct Async /// `async`
558 "auto" pub struct Auto /// `auto`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700559 "become" pub struct Become /// `become`
David Tolnay776f8e02018-08-24 22:32:10 -0400560 "box" pub struct Box /// `box`
561 "break" pub struct Break /// `break`
562 "Self" pub struct CapSelf /// `Self`
563 "const" pub struct Const /// `const`
564 "continue" pub struct Continue /// `continue`
565 "crate" pub struct Crate /// `crate`
566 "default" pub struct Default /// `default`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700567 "do" pub struct Do /// `do`
David Tolnay776f8e02018-08-24 22:32:10 -0400568 "dyn" pub struct Dyn /// `dyn`
569 "else" pub struct Else /// `else`
570 "enum" pub struct Enum /// `enum`
571 "existential" pub struct Existential /// `existential`
572 "extern" pub struct Extern /// `extern`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700573 "final" pub struct Final /// `final`
David Tolnay776f8e02018-08-24 22:32:10 -0400574 "fn" pub struct Fn /// `fn`
575 "for" pub struct For /// `for`
576 "if" pub struct If /// `if`
577 "impl" pub struct Impl /// `impl`
578 "in" pub struct In /// `in`
579 "let" pub struct Let /// `let`
580 "loop" pub struct Loop /// `loop`
581 "macro" pub struct Macro /// `macro`
582 "match" pub struct Match /// `match`
583 "mod" pub struct Mod /// `mod`
584 "move" pub struct Move /// `move`
585 "mut" pub struct Mut /// `mut`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700586 "override" pub struct Override /// `override`
587 "priv" pub struct Priv /// `priv`
David Tolnay776f8e02018-08-24 22:32:10 -0400588 "pub" pub struct Pub /// `pub`
589 "ref" pub struct Ref /// `ref`
590 "return" pub struct Return /// `return`
591 "self" pub struct Self_ /// `self`
592 "static" pub struct Static /// `static`
593 "struct" pub struct Struct /// `struct`
594 "super" pub struct Super /// `super`
595 "trait" pub struct Trait /// `trait`
596 "try" pub struct Try /// `try`
597 "type" pub struct Type /// `type`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700598 "typeof" pub struct Typeof /// `typeof`
David Tolnay776f8e02018-08-24 22:32:10 -0400599 "union" pub struct Union /// `union`
600 "unsafe" pub struct Unsafe /// `unsafe`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700601 "unsized" pub struct Unsized /// `unsized`
David Tolnay776f8e02018-08-24 22:32:10 -0400602 "use" pub struct Use /// `use`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700603 "virtual" pub struct Virtual /// `virtual`
David Tolnay776f8e02018-08-24 22:32:10 -0400604 "where" pub struct Where /// `where`
605 "while" pub struct While /// `while`
606 "yield" pub struct Yield /// `yield`
607}
608
609define_punctuation! {
610 "+" pub struct Add/1 /// `+`
611 "+=" pub struct AddEq/2 /// `+=`
612 "&" pub struct And/1 /// `&`
613 "&&" pub struct AndAnd/2 /// `&&`
614 "&=" pub struct AndEq/2 /// `&=`
615 "@" pub struct At/1 /// `@`
616 "!" pub struct Bang/1 /// `!`
617 "^" pub struct Caret/1 /// `^`
618 "^=" pub struct CaretEq/2 /// `^=`
619 ":" pub struct Colon/1 /// `:`
620 "::" pub struct Colon2/2 /// `::`
621 "," pub struct Comma/1 /// `,`
622 "/" pub struct Div/1 /// `/`
623 "/=" pub struct DivEq/2 /// `/=`
624 "$" pub struct Dollar/1 /// `$`
625 "." pub struct Dot/1 /// `.`
626 ".." pub struct Dot2/2 /// `..`
627 "..." pub struct Dot3/3 /// `...`
628 "..=" pub struct DotDotEq/3 /// `..=`
629 "=" pub struct Eq/1 /// `=`
630 "==" pub struct EqEq/2 /// `==`
631 ">=" pub struct Ge/2 /// `>=`
632 ">" pub struct Gt/1 /// `>`
633 "<=" pub struct Le/2 /// `<=`
634 "<" pub struct Lt/1 /// `<`
635 "*=" pub struct MulEq/2 /// `*=`
636 "!=" pub struct Ne/2 /// `!=`
637 "|" pub struct Or/1 /// `|`
638 "|=" pub struct OrEq/2 /// `|=`
639 "||" pub struct OrOr/2 /// `||`
640 "#" pub struct Pound/1 /// `#`
641 "?" pub struct Question/1 /// `?`
642 "->" pub struct RArrow/2 /// `->`
643 "<-" pub struct LArrow/2 /// `<-`
644 "%" pub struct Rem/1 /// `%`
645 "%=" pub struct RemEq/2 /// `%=`
646 "=>" pub struct FatArrow/2 /// `=>`
647 ";" pub struct Semi/1 /// `;`
648 "<<" pub struct Shl/2 /// `<<`
649 "<<=" pub struct ShlEq/3 /// `<<=`
650 ">>" pub struct Shr/2 /// `>>`
651 ">>=" pub struct ShrEq/3 /// `>>=`
652 "*" pub struct Star/1 /// `*`
653 "-" pub struct Sub/1 /// `-`
654 "-=" pub struct SubEq/2 /// `-=`
655}
656
657define_delimiters! {
658 "{" pub struct Brace /// `{...}`
659 "[" pub struct Bracket /// `[...]`
660 "(" pub struct Paren /// `(...)`
661 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700662}
663
David Tolnayf005f962018-01-06 21:19:41 -0800664/// A type-macro that expands to the name of the Rust type representation of a
665/// given token.
666///
667/// See the [token module] documentation for details and examples.
668///
669/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800670// Unfortunate duplication due to a rustdoc bug.
671// https://github.com/rust-lang/rust/issues/45939
672#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700673#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800674macro_rules! Token {
David Tolnayc327cd22018-09-09 00:37:28 -0700675 (abstract) => { $crate::token::Abstract };
David Tolnay776f8e02018-08-24 22:32:10 -0400676 (as) => { $crate::token::As };
677 (async) => { $crate::token::Async };
678 (auto) => { $crate::token::Auto };
David Tolnayc327cd22018-09-09 00:37:28 -0700679 (become) => { $crate::token::Become };
David Tolnay776f8e02018-08-24 22:32:10 -0400680 (box) => { $crate::token::Box };
681 (break) => { $crate::token::Break };
682 (Self) => { $crate::token::CapSelf };
683 (const) => { $crate::token::Const };
684 (continue) => { $crate::token::Continue };
685 (crate) => { $crate::token::Crate };
686 (default) => { $crate::token::Default };
David Tolnayc327cd22018-09-09 00:37:28 -0700687 (do) => { $crate::token::Do };
David Tolnay776f8e02018-08-24 22:32:10 -0400688 (dyn) => { $crate::token::Dyn };
689 (else) => { $crate::token::Else };
690 (enum) => { $crate::token::Enum };
691 (existential) => { $crate::token::Existential };
692 (extern) => { $crate::token::Extern };
David Tolnayc327cd22018-09-09 00:37:28 -0700693 (final) => { $crate::token::Final };
David Tolnay776f8e02018-08-24 22:32:10 -0400694 (fn) => { $crate::token::Fn };
695 (for) => { $crate::token::For };
696 (if) => { $crate::token::If };
697 (impl) => { $crate::token::Impl };
698 (in) => { $crate::token::In };
699 (let) => { $crate::token::Let };
700 (loop) => { $crate::token::Loop };
701 (macro) => { $crate::token::Macro };
702 (match) => { $crate::token::Match };
703 (mod) => { $crate::token::Mod };
704 (move) => { $crate::token::Move };
705 (mut) => { $crate::token::Mut };
David Tolnayc327cd22018-09-09 00:37:28 -0700706 (override) => { $crate::token::Override };
707 (priv) => { $crate::token::Priv };
David Tolnay776f8e02018-08-24 22:32:10 -0400708 (pub) => { $crate::token::Pub };
709 (ref) => { $crate::token::Ref };
710 (return) => { $crate::token::Return };
711 (self) => { $crate::token::Self_ };
712 (static) => { $crate::token::Static };
713 (struct) => { $crate::token::Struct };
714 (super) => { $crate::token::Super };
715 (trait) => { $crate::token::Trait };
716 (try) => { $crate::token::Try };
717 (type) => { $crate::token::Type };
David Tolnayc327cd22018-09-09 00:37:28 -0700718 (typeof) => { $crate::token::Typeof };
David Tolnay776f8e02018-08-24 22:32:10 -0400719 (union) => { $crate::token::Union };
720 (unsafe) => { $crate::token::Unsafe };
David Tolnayc327cd22018-09-09 00:37:28 -0700721 (unsized) => { $crate::token::Unsized };
David Tolnay776f8e02018-08-24 22:32:10 -0400722 (use) => { $crate::token::Use };
David Tolnayc327cd22018-09-09 00:37:28 -0700723 (virtual) => { $crate::token::Virtual };
David Tolnay776f8e02018-08-24 22:32:10 -0400724 (where) => { $crate::token::Where };
725 (while) => { $crate::token::While };
726 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400727 (+) => { $crate::token::Add };
728 (+=) => { $crate::token::AddEq };
729 (&) => { $crate::token::And };
730 (&&) => { $crate::token::AndAnd };
731 (&=) => { $crate::token::AndEq };
732 (@) => { $crate::token::At };
733 (!) => { $crate::token::Bang };
734 (^) => { $crate::token::Caret };
735 (^=) => { $crate::token::CaretEq };
736 (:) => { $crate::token::Colon };
737 (::) => { $crate::token::Colon2 };
738 (,) => { $crate::token::Comma };
739 (/) => { $crate::token::Div };
740 (/=) => { $crate::token::DivEq };
741 (.) => { $crate::token::Dot };
742 (..) => { $crate::token::Dot2 };
743 (...) => { $crate::token::Dot3 };
744 (..=) => { $crate::token::DotDotEq };
745 (=) => { $crate::token::Eq };
746 (==) => { $crate::token::EqEq };
747 (>=) => { $crate::token::Ge };
748 (>) => { $crate::token::Gt };
749 (<=) => { $crate::token::Le };
750 (<) => { $crate::token::Lt };
751 (*=) => { $crate::token::MulEq };
752 (!=) => { $crate::token::Ne };
753 (|) => { $crate::token::Or };
754 (|=) => { $crate::token::OrEq };
755 (||) => { $crate::token::OrOr };
756 (#) => { $crate::token::Pound };
757 (?) => { $crate::token::Question };
758 (->) => { $crate::token::RArrow };
759 (<-) => { $crate::token::LArrow };
760 (%) => { $crate::token::Rem };
761 (%=) => { $crate::token::RemEq };
762 (=>) => { $crate::token::FatArrow };
763 (;) => { $crate::token::Semi };
764 (<<) => { $crate::token::Shl };
765 (<<=) => { $crate::token::ShlEq };
766 (>>) => { $crate::token::Shr };
767 (>>=) => { $crate::token::ShrEq };
768 (*) => { $crate::token::Star };
769 (-) => { $crate::token::Sub };
770 (-=) => { $crate::token::SubEq };
771 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800772}
773
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700774#[cfg(feature = "parsing")]
775mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700776 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700777
David Tolnay68274de2018-09-02 17:15:01 -0700778 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400779 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400780 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400781 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700782
David Tolnay776f8e02018-08-24 22:32:10 -0400783 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700784 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400785 if let Some((ident, rest)) = cursor.ident() {
786 if ident == token {
787 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700788 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700789 }
David Tolnay776f8e02018-08-24 22:32:10 -0400790 Err(cursor.error(format!("expected `{}`", token)))
791 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700792 }
793
David Tolnay68274de2018-09-02 17:15:01 -0700794 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
795 if let Some((ident, _rest)) = cursor.ident() {
796 ident == token
797 } else {
798 false
799 }
800 }
801
David Tolnay776f8e02018-08-24 22:32:10 -0400802 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700803 let mut spans = [input.cursor().span(); 3];
804 punct_helper(input, token, &mut spans)?;
805 Ok(S::from_spans(&spans))
806 }
807
808 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700809 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400810 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400811 assert!(token.len() <= spans.len());
812
813 for (i, ch) in token.chars().enumerate() {
814 match cursor.punct() {
815 Some((punct, rest)) => {
816 spans[i] = punct.span();
817 if punct.as_char() != ch {
818 break;
819 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700820 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400821 } else if punct.spacing() != Spacing::Joint {
822 break;
823 }
824 cursor = rest;
825 }
826 None => break,
827 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400828 }
David Tolnay776f8e02018-08-24 22:32:10 -0400829
830 Err(Error::new(spans[0], format!("expected `{}`", token)))
831 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700832 }
David Tolnay68274de2018-09-02 17:15:01 -0700833
834 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
835 for (i, ch) in token.chars().enumerate() {
836 match cursor.punct() {
837 Some((punct, rest)) => {
838 if punct.as_char() != ch {
839 break;
840 } else if i == token.len() - 1 {
841 return true;
842 } else if punct.spacing() != Spacing::Joint {
843 break;
844 }
845 cursor = rest;
846 }
847 None => break,
848 }
849 }
850 false
851 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700852}
853
854#[cfg(feature = "printing")]
855mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700856 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700857 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700858
Alex Crichtona74a1c82018-05-16 10:20:44 -0700859 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700860 assert_eq!(s.len(), spans.len());
861
862 let mut chars = s.chars();
863 let mut spans = spans.iter();
864 let ch = chars.next_back().unwrap();
865 let span = spans.next_back().unwrap();
866 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700867 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700868 op.set_span(*span);
869 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700870 }
871
Alex Crichtona74a1c82018-05-16 10:20:44 -0700872 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700873 op.set_span(*span);
874 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700875 }
876
Alex Crichtona74a1c82018-05-16 10:20:44 -0700877 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
878 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700879 }
880
Alex Crichtona74a1c82018-05-16 10:20:44 -0700881 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500882 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700883 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700884 {
David Tolnay00ab6982017-12-31 18:15:06 -0500885 let delim = match s {
886 "(" => Delimiter::Parenthesis,
887 "[" => Delimiter::Bracket,
888 "{" => Delimiter::Brace,
889 " " => Delimiter::None,
890 _ => panic!("unknown delimiter: {}", s),
891 };
hcplaa511792018-05-29 07:13:01 +0300892 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500893 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700894 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700895 g.set_span(*span);
896 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700897 }
898}