blob: 685fc475e5e54d465f9ef1582854a91dd41bd267 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnaye79ae182018-01-06 19:23:37 -08009//! Tokens representing Rust punctuation, keywords, and delimiters.
Alex Crichton954046c2017-05-30 21:49:42 -070010//!
David Tolnaye79ae182018-01-06 19:23:37 -080011//! The type names in this module can be difficult to keep straight, so we
12//! prefer to use the [`Token!`] macro instead. This is a type-macro that
13//! expands to the token type of the given token.
14//!
15//! [`Token!`]: ../macro.Token.html
16//!
17//! # Example
18//!
19//! The [`ItemStatic`] syntax tree node is defined like this.
20//!
21//! [`ItemStatic`]: ../struct.ItemStatic.html
22//!
23//! ```
David Tolnaye79ae182018-01-06 19:23:37 -080024//! # extern crate syn;
25//! #
David Tolnay9b00f652018-09-01 10:31:02 -070026//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility};
David Tolnaye79ae182018-01-06 19:23:37 -080027//! #
28//! pub struct ItemStatic {
29//! pub attrs: Vec<Attribute>,
30//! pub vis: Visibility,
31//! pub static_token: Token![static],
32//! pub mutability: Option<Token![mut]>,
33//! pub ident: Ident,
34//! pub colon_token: Token![:],
35//! pub ty: Box<Type>,
36//! pub eq_token: Token![=],
37//! pub expr: Box<Expr>,
38//! pub semi_token: Token![;],
39//! }
40//! #
41//! # fn main() {}
42//! ```
43//!
44//! # Parsing
45//!
David Tolnayd8cc0552018-08-31 08:39:17 -070046//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
47//! method. Delimiter tokens are parsed using the [`parenthesized!`],
48//! [`bracketed!`] and [`braced!`] macros.
David Tolnaye79ae182018-01-06 19:23:37 -080049//!
David Tolnayd8cc0552018-08-31 08:39:17 -070050//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
51//! [`parenthesized!`]: ../macro.parenthesized.html
52//! [`bracketed!`]: ../macro.bracketed.html
53//! [`braced!`]: ../macro.braced.html
David Tolnaye79ae182018-01-06 19:23:37 -080054//!
55//! ```
David Tolnay9b00f652018-09-01 10:31:02 -070056//! # extern crate syn;
57//! #
David Tolnayd8cc0552018-08-31 08:39:17 -070058//! use syn::Attribute;
59//! use syn::parse::{Parse, ParseStream, Result};
David Tolnaye79ae182018-01-06 19:23:37 -080060//! #
David Tolnay9b00f652018-09-01 10:31:02 -070061//! # enum ItemStatic {}
David Tolnaye79ae182018-01-06 19:23:37 -080062//!
63//! // Parse the ItemStatic struct shown above.
David Tolnayd8cc0552018-08-31 08:39:17 -070064//! impl Parse for ItemStatic {
65//! fn parse(input: ParseStream) -> Result<Self> {
David Tolnay9b00f652018-09-01 10:31:02 -070066//! # use syn::ItemStatic;
67//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
68//! Ok(ItemStatic {
69//! attrs: input.call(Attribute::parse_outer)?,
70//! vis: input.parse()?,
71//! static_token: input.parse()?,
72//! mutability: input.parse()?,
73//! ident: input.parse()?,
74//! colon_token: input.parse()?,
75//! ty: input.parse()?,
76//! eq_token: input.parse()?,
77//! expr: input.parse()?,
78//! semi_token: input.parse()?,
79//! })
80//! # }
81//! # unimplemented!()
82//! }
David Tolnaye79ae182018-01-06 19:23:37 -080083//! }
84//! #
85//! # fn main() {}
86//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070087
David Tolnay776f8e02018-08-24 22:32:10 -040088use std;
David Tolnayd9836922018-08-25 18:05:36 -040089#[cfg(feature = "parsing")]
90use std::cell::Cell;
David Tolnay776f8e02018-08-24 22:32:10 -040091#[cfg(feature = "extra-traits")]
92use std::cmp;
93#[cfg(feature = "extra-traits")]
94use std::fmt::{self, Debug};
95#[cfg(feature = "extra-traits")]
96use std::hash::{Hash, Hasher};
David Tolnayd9836922018-08-25 18:05:36 -040097#[cfg(feature = "parsing")]
98use std::rc::Rc;
David Tolnay776f8e02018-08-24 22:32:10 -040099
David Tolnay2d84a082018-08-25 16:31:38 -0400100#[cfg(feature = "parsing")]
101use proc_macro2::Delimiter;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700102#[cfg(feature = "printing")]
David Tolnay78612672018-08-31 08:47:41 -0700103use proc_macro2::TokenStream;
104use proc_macro2::{Ident, Span};
David Tolnay776f8e02018-08-24 22:32:10 -0400105#[cfg(feature = "printing")]
106use quote::{ToTokens, TokenStreamExt};
107
108#[cfg(feature = "parsing")]
David Tolnay00f81fd2018-09-01 10:50:12 -0700109use buffer::Cursor;
110#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400111use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700112#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400113#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400114use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700115#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400116#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400117use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400118#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400119use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400120#[cfg(feature = "parsing")]
David Tolnay00f81fd2018-09-01 10:50:12 -0700121use parse::{Parse, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400122use span::IntoSpans;
123
124/// Marker trait for types that represent single tokens.
125///
126/// This trait is sealed and cannot be implemented for types outside of Syn.
127#[cfg(feature = "parsing")]
128pub trait Token: private::Sealed {
129 // Not public API.
130 #[doc(hidden)]
David Tolnay00f81fd2018-09-01 10:50:12 -0700131 fn peek(cursor: Cursor) -> bool;
David Tolnay776f8e02018-08-24 22:32:10 -0400132
133 // Not public API.
134 #[doc(hidden)]
David Tolnay2d032802018-09-01 10:51:59 -0700135 fn display() -> &'static str;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700136}
137
138#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400139mod private {
140 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700141}
142
David Tolnay65557f02018-09-01 11:08:27 -0700143#[cfg(feature = "parsing")]
144fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
145 let scope = Span::call_site();
146 let unexpected = Rc::new(Cell::new(None));
147 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
148 peek(&buffer)
149}
150
David Tolnay776f8e02018-08-24 22:32:10 -0400151macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400152 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400153 #[cfg(feature = "parsing")]
154 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700155 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700156 fn peek(input: ParseStream) -> bool {
157 <$name as Parse>::parse(input).is_ok()
158 }
159 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400160 }
161
David Tolnay2d032802018-09-01 10:51:59 -0700162 fn display() -> &'static str {
163 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400164 }
165 }
166
167 #[cfg(feature = "parsing")]
168 impl private::Sealed for $name {}
169 };
170}
171
David Tolnay4fb71232018-08-25 23:14:50 -0400172impl_token!(Ident "identifier");
David Tolnaya465b2d2018-08-27 08:21:09 -0700173#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400174impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700175#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400176impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700177#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400178impl_token!(LitStr "string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700179#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400180impl_token!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700181#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400182impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700183#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400184impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700185#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400186impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700187#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400188impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700189#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400190impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400191
David Tolnay776f8e02018-08-24 22:32:10 -0400192macro_rules! define_keywords {
193 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
194 $(
195 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
196 #[$doc]
197 ///
198 /// Don't try to remember the name of this type -- use the [`Token!`]
199 /// macro instead.
200 ///
201 /// [`Token!`]: index.html
202 pub struct $name {
203 pub span: Span,
204 }
205
206 #[doc(hidden)]
207 #[allow(non_snake_case)]
208 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
209 $name {
210 span: span.into_spans()[0],
211 }
212 }
213
David Tolnay776f8e02018-08-24 22:32:10 -0400214 impl std::default::Default for $name {
215 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700216 $name {
217 span: Span::call_site(),
218 }
David Tolnay776f8e02018-08-24 22:32:10 -0400219 }
220 }
221
222 #[cfg(feature = "extra-traits")]
223 impl Debug for $name {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 f.write_str(stringify!($name))
226 }
227 }
228
229 #[cfg(feature = "extra-traits")]
230 impl cmp::Eq for $name {}
231
232 #[cfg(feature = "extra-traits")]
233 impl PartialEq for $name {
234 fn eq(&self, _other: &$name) -> bool {
235 true
236 }
237 }
238
239 #[cfg(feature = "extra-traits")]
240 impl Hash for $name {
241 fn hash<H: Hasher>(&self, _state: &mut H) {}
242 }
243
244 #[cfg(feature = "printing")]
245 impl ToTokens for $name {
246 fn to_tokens(&self, tokens: &mut TokenStream) {
247 printing::keyword($token, &self.span, tokens);
248 }
249 }
250
251 #[cfg(feature = "parsing")]
252 impl Parse for $name {
253 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700254 Ok($name {
255 span: parsing::keyword(input, $token)?,
256 })
David Tolnay776f8e02018-08-24 22:32:10 -0400257 }
258 }
David Tolnay68274de2018-09-02 17:15:01 -0700259
260 #[cfg(feature = "parsing")]
261 impl Token for $name {
262 fn peek(cursor: Cursor) -> bool {
263 parsing::peek_keyword(cursor, $token)
264 }
265
266 fn display() -> &'static str {
267 concat!("`", $token, "`")
268 }
269 }
270
271 #[cfg(feature = "parsing")]
272 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400273 )*
274 };
275}
276
277macro_rules! define_punctuation_structs {
278 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
279 $(
280 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
281 #[$doc]
282 ///
283 /// Don't try to remember the name of this type -- use the [`Token!`]
284 /// macro instead.
285 ///
286 /// [`Token!`]: index.html
287 pub struct $name {
288 pub spans: [Span; $len],
289 }
290
291 #[doc(hidden)]
292 #[allow(non_snake_case)]
293 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
294 $name {
295 spans: spans.into_spans(),
296 }
297 }
298
David Tolnay776f8e02018-08-24 22:32:10 -0400299 impl std::default::Default for $name {
300 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700301 $name {
302 spans: [Span::call_site(); $len],
303 }
David Tolnay776f8e02018-08-24 22:32:10 -0400304 }
305 }
306
307 #[cfg(feature = "extra-traits")]
308 impl Debug for $name {
309 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310 f.write_str(stringify!($name))
311 }
312 }
313
314 #[cfg(feature = "extra-traits")]
315 impl cmp::Eq for $name {}
316
317 #[cfg(feature = "extra-traits")]
318 impl PartialEq for $name {
319 fn eq(&self, _other: &$name) -> bool {
320 true
321 }
322 }
323
324 #[cfg(feature = "extra-traits")]
325 impl Hash for $name {
326 fn hash<H: Hasher>(&self, _state: &mut H) {}
327 }
328 )*
329 };
330}
331
332macro_rules! define_punctuation {
333 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
334 $(
335 define_punctuation_structs! {
336 $token pub struct $name/$len #[$doc]
337 }
338
339 #[cfg(feature = "printing")]
340 impl ToTokens for $name {
341 fn to_tokens(&self, tokens: &mut TokenStream) {
342 printing::punct($token, &self.spans, tokens);
343 }
344 }
345
346 #[cfg(feature = "parsing")]
347 impl Parse for $name {
348 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700349 Ok($name {
350 spans: parsing::punct(input, $token)?,
351 })
David Tolnay776f8e02018-08-24 22:32:10 -0400352 }
353 }
David Tolnay68274de2018-09-02 17:15:01 -0700354
355 #[cfg(feature = "parsing")]
356 impl Token for $name {
357 fn peek(cursor: Cursor) -> bool {
358 parsing::peek_punct(cursor, $token)
359 }
360
361 fn display() -> &'static str {
362 concat!("`", $token, "`")
363 }
364 }
365
366 #[cfg(feature = "parsing")]
367 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400368 )*
369 };
370}
371
372macro_rules! define_delimiters {
373 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
374 $(
375 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
376 #[$doc]
377 pub struct $name {
378 pub span: Span,
379 }
380
381 #[doc(hidden)]
382 #[allow(non_snake_case)]
383 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
384 $name {
385 span: span.into_spans()[0],
386 }
387 }
388
389 impl std::default::Default for $name {
390 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700391 $name {
392 span: Span::call_site(),
393 }
David Tolnay776f8e02018-08-24 22:32:10 -0400394 }
395 }
396
397 #[cfg(feature = "extra-traits")]
398 impl Debug for $name {
399 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400 f.write_str(stringify!($name))
401 }
402 }
403
404 #[cfg(feature = "extra-traits")]
405 impl cmp::Eq for $name {}
406
407 #[cfg(feature = "extra-traits")]
408 impl PartialEq for $name {
409 fn eq(&self, _other: &$name) -> bool {
410 true
411 }
412 }
413
414 #[cfg(feature = "extra-traits")]
415 impl Hash for $name {
416 fn hash<H: Hasher>(&self, _state: &mut H) {}
417 }
418
419 impl $name {
420 #[cfg(feature = "printing")]
421 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
422 where
423 F: FnOnce(&mut TokenStream),
424 {
425 printing::delim($token, &self.span, tokens, f);
426 }
David Tolnay776f8e02018-08-24 22:32:10 -0400427 }
David Tolnay2d84a082018-08-25 16:31:38 -0400428
429 #[cfg(feature = "parsing")]
430 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400431 )*
432 };
433}
434
435define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400436 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700437}
438
David Tolnay776f8e02018-08-24 22:32:10 -0400439#[cfg(feature = "printing")]
440impl ToTokens for Underscore {
441 fn to_tokens(&self, tokens: &mut TokenStream) {
442 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700443 }
David Tolnay776f8e02018-08-24 22:32:10 -0400444}
445
446#[cfg(feature = "parsing")]
447impl Parse for Underscore {
448 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700449 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400450 if let Some((ident, rest)) = cursor.ident() {
451 if ident == "_" {
452 return Ok((Underscore(ident.span()), rest));
453 }
454 }
455 if let Some((punct, rest)) = cursor.punct() {
456 if punct.as_char() == '_' {
457 return Ok((Underscore(punct.span()), rest));
458 }
459 }
460 Err(cursor.error("expected `_`"))
461 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700462 }
David Tolnay776f8e02018-08-24 22:32:10 -0400463}
464
David Tolnay2d84a082018-08-25 16:31:38 -0400465#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700466impl Token for Underscore {
467 fn peek(cursor: Cursor) -> bool {
468 if let Some((ident, _rest)) = cursor.ident() {
469 return ident == "_";
470 }
471 if let Some((punct, _rest)) = cursor.punct() {
472 return punct.as_char() == '_'
473 }
474 false
475 }
476
477 fn display() -> &'static str {
478 "`_`"
479 }
480}
481
482#[cfg(feature = "parsing")]
483impl private::Sealed for Underscore {}
484
485#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400486impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700487 fn peek(cursor: Cursor) -> bool {
488 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400489 }
490
David Tolnay2d032802018-09-01 10:51:59 -0700491 fn display() -> &'static str {
492 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400493 }
494}
495
496#[cfg(feature = "parsing")]
497impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700498 fn peek(cursor: Cursor) -> bool {
499 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400500 }
501
David Tolnay2d032802018-09-01 10:51:59 -0700502 fn display() -> &'static str {
503 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400504 }
505}
506
507#[cfg(feature = "parsing")]
508impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700509 fn peek(cursor: Cursor) -> bool {
510 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400511 }
512
David Tolnay2d032802018-09-01 10:51:59 -0700513 fn display() -> &'static str {
514 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400515 }
516}
517
David Tolnaya7d69fc2018-08-26 13:30:24 -0400518#[cfg(feature = "parsing")]
519impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700520 fn peek(cursor: Cursor) -> bool {
521 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400522 }
523
David Tolnay2d032802018-09-01 10:51:59 -0700524 fn display() -> &'static str {
525 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400526 }
527}
528
David Tolnay776f8e02018-08-24 22:32:10 -0400529define_keywords! {
530 "as" pub struct As /// `as`
531 "async" pub struct Async /// `async`
532 "auto" pub struct Auto /// `auto`
533 "box" pub struct Box /// `box`
534 "break" pub struct Break /// `break`
535 "Self" pub struct CapSelf /// `Self`
536 "const" pub struct Const /// `const`
537 "continue" pub struct Continue /// `continue`
538 "crate" pub struct Crate /// `crate`
539 "default" pub struct Default /// `default`
540 "dyn" pub struct Dyn /// `dyn`
541 "else" pub struct Else /// `else`
542 "enum" pub struct Enum /// `enum`
543 "existential" pub struct Existential /// `existential`
544 "extern" pub struct Extern /// `extern`
545 "fn" pub struct Fn /// `fn`
546 "for" pub struct For /// `for`
547 "if" pub struct If /// `if`
548 "impl" pub struct Impl /// `impl`
549 "in" pub struct In /// `in`
550 "let" pub struct Let /// `let`
551 "loop" pub struct Loop /// `loop`
552 "macro" pub struct Macro /// `macro`
553 "match" pub struct Match /// `match`
554 "mod" pub struct Mod /// `mod`
555 "move" pub struct Move /// `move`
556 "mut" pub struct Mut /// `mut`
557 "pub" pub struct Pub /// `pub`
558 "ref" pub struct Ref /// `ref`
559 "return" pub struct Return /// `return`
560 "self" pub struct Self_ /// `self`
561 "static" pub struct Static /// `static`
562 "struct" pub struct Struct /// `struct`
563 "super" pub struct Super /// `super`
564 "trait" pub struct Trait /// `trait`
565 "try" pub struct Try /// `try`
566 "type" pub struct Type /// `type`
567 "union" pub struct Union /// `union`
568 "unsafe" pub struct Unsafe /// `unsafe`
569 "use" pub struct Use /// `use`
570 "where" pub struct Where /// `where`
571 "while" pub struct While /// `while`
572 "yield" pub struct Yield /// `yield`
573}
574
575define_punctuation! {
576 "+" pub struct Add/1 /// `+`
577 "+=" pub struct AddEq/2 /// `+=`
578 "&" pub struct And/1 /// `&`
579 "&&" pub struct AndAnd/2 /// `&&`
580 "&=" pub struct AndEq/2 /// `&=`
581 "@" pub struct At/1 /// `@`
582 "!" pub struct Bang/1 /// `!`
583 "^" pub struct Caret/1 /// `^`
584 "^=" pub struct CaretEq/2 /// `^=`
585 ":" pub struct Colon/1 /// `:`
586 "::" pub struct Colon2/2 /// `::`
587 "," pub struct Comma/1 /// `,`
588 "/" pub struct Div/1 /// `/`
589 "/=" pub struct DivEq/2 /// `/=`
590 "$" pub struct Dollar/1 /// `$`
591 "." pub struct Dot/1 /// `.`
592 ".." pub struct Dot2/2 /// `..`
593 "..." pub struct Dot3/3 /// `...`
594 "..=" pub struct DotDotEq/3 /// `..=`
595 "=" pub struct Eq/1 /// `=`
596 "==" pub struct EqEq/2 /// `==`
597 ">=" pub struct Ge/2 /// `>=`
598 ">" pub struct Gt/1 /// `>`
599 "<=" pub struct Le/2 /// `<=`
600 "<" pub struct Lt/1 /// `<`
601 "*=" pub struct MulEq/2 /// `*=`
602 "!=" pub struct Ne/2 /// `!=`
603 "|" pub struct Or/1 /// `|`
604 "|=" pub struct OrEq/2 /// `|=`
605 "||" pub struct OrOr/2 /// `||`
606 "#" pub struct Pound/1 /// `#`
607 "?" pub struct Question/1 /// `?`
608 "->" pub struct RArrow/2 /// `->`
609 "<-" pub struct LArrow/2 /// `<-`
610 "%" pub struct Rem/1 /// `%`
611 "%=" pub struct RemEq/2 /// `%=`
612 "=>" pub struct FatArrow/2 /// `=>`
613 ";" pub struct Semi/1 /// `;`
614 "<<" pub struct Shl/2 /// `<<`
615 "<<=" pub struct ShlEq/3 /// `<<=`
616 ">>" pub struct Shr/2 /// `>>`
617 ">>=" pub struct ShrEq/3 /// `>>=`
618 "*" pub struct Star/1 /// `*`
619 "-" pub struct Sub/1 /// `-`
620 "-=" pub struct SubEq/2 /// `-=`
621}
622
623define_delimiters! {
624 "{" pub struct Brace /// `{...}`
625 "[" pub struct Bracket /// `[...]`
626 "(" pub struct Paren /// `(...)`
627 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700628}
629
David Tolnayf005f962018-01-06 21:19:41 -0800630/// A type-macro that expands to the name of the Rust type representation of a
631/// given token.
632///
633/// See the [token module] documentation for details and examples.
634///
635/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800636// Unfortunate duplication due to a rustdoc bug.
637// https://github.com/rust-lang/rust/issues/45939
638#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700639#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800640macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400641 (as) => { $crate::token::As };
642 (async) => { $crate::token::Async };
643 (auto) => { $crate::token::Auto };
644 (box) => { $crate::token::Box };
645 (break) => { $crate::token::Break };
646 (Self) => { $crate::token::CapSelf };
647 (const) => { $crate::token::Const };
648 (continue) => { $crate::token::Continue };
649 (crate) => { $crate::token::Crate };
650 (default) => { $crate::token::Default };
651 (dyn) => { $crate::token::Dyn };
652 (else) => { $crate::token::Else };
653 (enum) => { $crate::token::Enum };
654 (existential) => { $crate::token::Existential };
655 (extern) => { $crate::token::Extern };
656 (fn) => { $crate::token::Fn };
657 (for) => { $crate::token::For };
658 (if) => { $crate::token::If };
659 (impl) => { $crate::token::Impl };
660 (in) => { $crate::token::In };
661 (let) => { $crate::token::Let };
662 (loop) => { $crate::token::Loop };
663 (macro) => { $crate::token::Macro };
664 (match) => { $crate::token::Match };
665 (mod) => { $crate::token::Mod };
666 (move) => { $crate::token::Move };
667 (mut) => { $crate::token::Mut };
668 (pub) => { $crate::token::Pub };
669 (ref) => { $crate::token::Ref };
670 (return) => { $crate::token::Return };
671 (self) => { $crate::token::Self_ };
672 (static) => { $crate::token::Static };
673 (struct) => { $crate::token::Struct };
674 (super) => { $crate::token::Super };
675 (trait) => { $crate::token::Trait };
676 (try) => { $crate::token::Try };
677 (type) => { $crate::token::Type };
678 (union) => { $crate::token::Union };
679 (unsafe) => { $crate::token::Unsafe };
680 (use) => { $crate::token::Use };
681 (where) => { $crate::token::Where };
682 (while) => { $crate::token::While };
683 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400684 (+) => { $crate::token::Add };
685 (+=) => { $crate::token::AddEq };
686 (&) => { $crate::token::And };
687 (&&) => { $crate::token::AndAnd };
688 (&=) => { $crate::token::AndEq };
689 (@) => { $crate::token::At };
690 (!) => { $crate::token::Bang };
691 (^) => { $crate::token::Caret };
692 (^=) => { $crate::token::CaretEq };
693 (:) => { $crate::token::Colon };
694 (::) => { $crate::token::Colon2 };
695 (,) => { $crate::token::Comma };
696 (/) => { $crate::token::Div };
697 (/=) => { $crate::token::DivEq };
698 (.) => { $crate::token::Dot };
699 (..) => { $crate::token::Dot2 };
700 (...) => { $crate::token::Dot3 };
701 (..=) => { $crate::token::DotDotEq };
702 (=) => { $crate::token::Eq };
703 (==) => { $crate::token::EqEq };
704 (>=) => { $crate::token::Ge };
705 (>) => { $crate::token::Gt };
706 (<=) => { $crate::token::Le };
707 (<) => { $crate::token::Lt };
708 (*=) => { $crate::token::MulEq };
709 (!=) => { $crate::token::Ne };
710 (|) => { $crate::token::Or };
711 (|=) => { $crate::token::OrEq };
712 (||) => { $crate::token::OrOr };
713 (#) => { $crate::token::Pound };
714 (?) => { $crate::token::Question };
715 (->) => { $crate::token::RArrow };
716 (<-) => { $crate::token::LArrow };
717 (%) => { $crate::token::Rem };
718 (%=) => { $crate::token::RemEq };
719 (=>) => { $crate::token::FatArrow };
720 (;) => { $crate::token::Semi };
721 (<<) => { $crate::token::Shl };
722 (<<=) => { $crate::token::ShlEq };
723 (>>) => { $crate::token::Shr };
724 (>>=) => { $crate::token::ShrEq };
725 (*) => { $crate::token::Star };
726 (-) => { $crate::token::Sub };
727 (-=) => { $crate::token::SubEq };
728 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800729}
730
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700731#[cfg(feature = "parsing")]
732mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700733 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700734
David Tolnay68274de2018-09-02 17:15:01 -0700735 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400736 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400737 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400738 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700739
David Tolnay776f8e02018-08-24 22:32:10 -0400740 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700741 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400742 if let Some((ident, rest)) = cursor.ident() {
743 if ident == token {
744 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700745 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700746 }
David Tolnay776f8e02018-08-24 22:32:10 -0400747 Err(cursor.error(format!("expected `{}`", token)))
748 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700749 }
750
David Tolnay68274de2018-09-02 17:15:01 -0700751 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
752 if let Some((ident, _rest)) = cursor.ident() {
753 ident == token
754 } else {
755 false
756 }
757 }
758
David Tolnay776f8e02018-08-24 22:32:10 -0400759 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700760 let mut spans = [input.cursor().span(); 3];
761 punct_helper(input, token, &mut spans)?;
762 Ok(S::from_spans(&spans))
763 }
764
765 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700766 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400767 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400768 assert!(token.len() <= spans.len());
769
770 for (i, ch) in token.chars().enumerate() {
771 match cursor.punct() {
772 Some((punct, rest)) => {
773 spans[i] = punct.span();
774 if punct.as_char() != ch {
775 break;
776 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700777 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400778 } else if punct.spacing() != Spacing::Joint {
779 break;
780 }
781 cursor = rest;
782 }
783 None => break,
784 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400785 }
David Tolnay776f8e02018-08-24 22:32:10 -0400786
787 Err(Error::new(spans[0], format!("expected `{}`", token)))
788 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700789 }
David Tolnay68274de2018-09-02 17:15:01 -0700790
791 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
792 for (i, ch) in token.chars().enumerate() {
793 match cursor.punct() {
794 Some((punct, rest)) => {
795 if punct.as_char() != ch {
796 break;
797 } else if i == token.len() - 1 {
798 return true;
799 } else if punct.spacing() != Spacing::Joint {
800 break;
801 }
802 cursor = rest;
803 }
804 None => break,
805 }
806 }
807 false
808 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700809}
810
811#[cfg(feature = "printing")]
812mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700813 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700814 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700815
Alex Crichtona74a1c82018-05-16 10:20:44 -0700816 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700817 assert_eq!(s.len(), spans.len());
818
819 let mut chars = s.chars();
820 let mut spans = spans.iter();
821 let ch = chars.next_back().unwrap();
822 let span = spans.next_back().unwrap();
823 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700824 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700825 op.set_span(*span);
826 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700827 }
828
Alex Crichtona74a1c82018-05-16 10:20:44 -0700829 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700830 op.set_span(*span);
831 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700832 }
833
Alex Crichtona74a1c82018-05-16 10:20:44 -0700834 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
835 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700836 }
837
Alex Crichtona74a1c82018-05-16 10:20:44 -0700838 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500839 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700840 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700841 {
David Tolnay00ab6982017-12-31 18:15:06 -0500842 let delim = match s {
843 "(" => Delimiter::Parenthesis,
844 "[" => Delimiter::Bracket,
845 "{" => Delimiter::Brace,
846 " " => Delimiter::None,
847 _ => panic!("unknown delimiter: {}", s),
848 };
hcplaa511792018-05-29 07:13:01 +0300849 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500850 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700851 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700852 g.set_span(*span);
853 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700854 }
855}