blob: 637d9015a06b1dd077b43884e20645d69759d998 [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")]
Louis Kureuil Personc0beaf32018-09-05 00:12:43 +0200121use parse::{Keyword, 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")]
David Tolnay719ad5a2018-09-02 18:01:15 -0700144impl private::Sealed for Ident {}
145
146#[cfg(feature = "parsing")]
Louis Kureuil Personc0beaf32018-09-05 00:12:43 +0200147impl<K: Keyword> private::Sealed for K {}
148
149#[cfg(feature = "parsing")]
David Tolnay65557f02018-09-01 11:08:27 -0700150fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
151 let scope = Span::call_site();
152 let unexpected = Rc::new(Cell::new(None));
153 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
154 peek(&buffer)
155}
156
David Tolnay776f8e02018-08-24 22:32:10 -0400157macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400158 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400159 #[cfg(feature = "parsing")]
160 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700161 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700162 fn peek(input: ParseStream) -> bool {
163 <$name as Parse>::parse(input).is_ok()
164 }
165 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400166 }
167
David Tolnay2d032802018-09-01 10:51:59 -0700168 fn display() -> &'static str {
169 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400170 }
171 }
172
173 #[cfg(feature = "parsing")]
174 impl private::Sealed for $name {}
175 };
176}
177
David Tolnaya465b2d2018-08-27 08:21:09 -0700178#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400179impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700180#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400181impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700182#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400183impl_token!(LitStr "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!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700186#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400187impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700188#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400189impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700190#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400191impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700192#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400193impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700194#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400195impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400196
David Tolnay776f8e02018-08-24 22:32:10 -0400197macro_rules! define_keywords {
198 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
199 $(
200 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
201 #[$doc]
202 ///
203 /// Don't try to remember the name of this type -- use the [`Token!`]
204 /// macro instead.
205 ///
206 /// [`Token!`]: index.html
207 pub struct $name {
208 pub span: Span,
209 }
210
211 #[doc(hidden)]
212 #[allow(non_snake_case)]
213 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
214 $name {
215 span: span.into_spans()[0],
216 }
217 }
218
David Tolnay776f8e02018-08-24 22:32:10 -0400219 impl std::default::Default for $name {
220 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700221 $name {
222 span: Span::call_site(),
223 }
David Tolnay776f8e02018-08-24 22:32:10 -0400224 }
225 }
226
227 #[cfg(feature = "extra-traits")]
228 impl Debug for $name {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 f.write_str(stringify!($name))
231 }
232 }
233
234 #[cfg(feature = "extra-traits")]
235 impl cmp::Eq for $name {}
236
237 #[cfg(feature = "extra-traits")]
238 impl PartialEq for $name {
239 fn eq(&self, _other: &$name) -> bool {
240 true
241 }
242 }
243
244 #[cfg(feature = "extra-traits")]
245 impl Hash for $name {
246 fn hash<H: Hasher>(&self, _state: &mut H) {}
247 }
248
249 #[cfg(feature = "printing")]
250 impl ToTokens for $name {
251 fn to_tokens(&self, tokens: &mut TokenStream) {
252 printing::keyword($token, &self.span, tokens);
253 }
254 }
255
256 #[cfg(feature = "parsing")]
257 impl Parse for $name {
258 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700259 Ok($name {
260 span: parsing::keyword(input, $token)?,
261 })
David Tolnay776f8e02018-08-24 22:32:10 -0400262 }
263 }
David Tolnay68274de2018-09-02 17:15:01 -0700264
265 #[cfg(feature = "parsing")]
266 impl Token for $name {
267 fn peek(cursor: Cursor) -> bool {
268 parsing::peek_keyword(cursor, $token)
269 }
270
271 fn display() -> &'static str {
272 concat!("`", $token, "`")
273 }
274 }
275
276 #[cfg(feature = "parsing")]
277 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400278 )*
279 };
280}
281
282macro_rules! define_punctuation_structs {
283 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
284 $(
285 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
286 #[$doc]
287 ///
288 /// Don't try to remember the name of this type -- use the [`Token!`]
289 /// macro instead.
290 ///
291 /// [`Token!`]: index.html
292 pub struct $name {
293 pub spans: [Span; $len],
294 }
295
296 #[doc(hidden)]
297 #[allow(non_snake_case)]
298 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
299 $name {
300 spans: spans.into_spans(),
301 }
302 }
303
David Tolnay776f8e02018-08-24 22:32:10 -0400304 impl std::default::Default for $name {
305 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700306 $name {
307 spans: [Span::call_site(); $len],
308 }
David Tolnay776f8e02018-08-24 22:32:10 -0400309 }
310 }
311
312 #[cfg(feature = "extra-traits")]
313 impl Debug for $name {
314 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
315 f.write_str(stringify!($name))
316 }
317 }
318
319 #[cfg(feature = "extra-traits")]
320 impl cmp::Eq for $name {}
321
322 #[cfg(feature = "extra-traits")]
323 impl PartialEq for $name {
324 fn eq(&self, _other: &$name) -> bool {
325 true
326 }
327 }
328
329 #[cfg(feature = "extra-traits")]
330 impl Hash for $name {
331 fn hash<H: Hasher>(&self, _state: &mut H) {}
332 }
333 )*
334 };
335}
336
337macro_rules! define_punctuation {
338 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
339 $(
340 define_punctuation_structs! {
341 $token pub struct $name/$len #[$doc]
342 }
343
344 #[cfg(feature = "printing")]
345 impl ToTokens for $name {
346 fn to_tokens(&self, tokens: &mut TokenStream) {
347 printing::punct($token, &self.spans, tokens);
348 }
349 }
350
351 #[cfg(feature = "parsing")]
352 impl Parse for $name {
353 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700354 Ok($name {
355 spans: parsing::punct(input, $token)?,
356 })
David Tolnay776f8e02018-08-24 22:32:10 -0400357 }
358 }
David Tolnay68274de2018-09-02 17:15:01 -0700359
360 #[cfg(feature = "parsing")]
361 impl Token for $name {
362 fn peek(cursor: Cursor) -> bool {
363 parsing::peek_punct(cursor, $token)
364 }
365
366 fn display() -> &'static str {
367 concat!("`", $token, "`")
368 }
369 }
370
371 #[cfg(feature = "parsing")]
372 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400373 )*
374 };
375}
376
377macro_rules! define_delimiters {
378 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
379 $(
380 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
381 #[$doc]
382 pub struct $name {
383 pub span: Span,
384 }
385
386 #[doc(hidden)]
387 #[allow(non_snake_case)]
388 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
389 $name {
390 span: span.into_spans()[0],
391 }
392 }
393
394 impl std::default::Default for $name {
395 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700396 $name {
397 span: Span::call_site(),
398 }
David Tolnay776f8e02018-08-24 22:32:10 -0400399 }
400 }
401
402 #[cfg(feature = "extra-traits")]
403 impl Debug for $name {
404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405 f.write_str(stringify!($name))
406 }
407 }
408
409 #[cfg(feature = "extra-traits")]
410 impl cmp::Eq for $name {}
411
412 #[cfg(feature = "extra-traits")]
413 impl PartialEq for $name {
414 fn eq(&self, _other: &$name) -> bool {
415 true
416 }
417 }
418
419 #[cfg(feature = "extra-traits")]
420 impl Hash for $name {
421 fn hash<H: Hasher>(&self, _state: &mut H) {}
422 }
423
424 impl $name {
425 #[cfg(feature = "printing")]
426 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
427 where
428 F: FnOnce(&mut TokenStream),
429 {
430 printing::delim($token, &self.span, tokens, f);
431 }
David Tolnay776f8e02018-08-24 22:32:10 -0400432 }
David Tolnay2d84a082018-08-25 16:31:38 -0400433
434 #[cfg(feature = "parsing")]
435 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400436 )*
437 };
438}
439
440define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400441 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700442}
443
David Tolnay776f8e02018-08-24 22:32:10 -0400444#[cfg(feature = "printing")]
445impl ToTokens for Underscore {
446 fn to_tokens(&self, tokens: &mut TokenStream) {
447 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700448 }
David Tolnay776f8e02018-08-24 22:32:10 -0400449}
450
451#[cfg(feature = "parsing")]
452impl Parse for Underscore {
453 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700454 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400455 if let Some((ident, rest)) = cursor.ident() {
456 if ident == "_" {
457 return Ok((Underscore(ident.span()), rest));
458 }
459 }
460 if let Some((punct, rest)) = cursor.punct() {
461 if punct.as_char() == '_' {
462 return Ok((Underscore(punct.span()), rest));
463 }
464 }
465 Err(cursor.error("expected `_`"))
466 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700467 }
David Tolnay776f8e02018-08-24 22:32:10 -0400468}
469
David Tolnay2d84a082018-08-25 16:31:38 -0400470#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700471impl Token for Underscore {
472 fn peek(cursor: Cursor) -> bool {
473 if let Some((ident, _rest)) = cursor.ident() {
474 return ident == "_";
475 }
476 if let Some((punct, _rest)) = cursor.punct() {
477 return punct.as_char() == '_'
478 }
479 false
480 }
481
482 fn display() -> &'static str {
483 "`_`"
484 }
485}
486
487#[cfg(feature = "parsing")]
488impl private::Sealed for Underscore {}
489
490#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400491impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700492 fn peek(cursor: Cursor) -> bool {
493 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400494 }
495
David Tolnay2d032802018-09-01 10:51:59 -0700496 fn display() -> &'static str {
497 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400498 }
499}
500
501#[cfg(feature = "parsing")]
502impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700503 fn peek(cursor: Cursor) -> bool {
504 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400505 }
506
David Tolnay2d032802018-09-01 10:51:59 -0700507 fn display() -> &'static str {
508 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400509 }
510}
511
512#[cfg(feature = "parsing")]
513impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700514 fn peek(cursor: Cursor) -> bool {
515 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400516 }
517
David Tolnay2d032802018-09-01 10:51:59 -0700518 fn display() -> &'static str {
519 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400520 }
521}
522
David Tolnaya7d69fc2018-08-26 13:30:24 -0400523#[cfg(feature = "parsing")]
524impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700525 fn peek(cursor: Cursor) -> bool {
526 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400527 }
528
David Tolnay2d032802018-09-01 10:51:59 -0700529 fn display() -> &'static str {
530 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400531 }
532}
533
David Tolnay776f8e02018-08-24 22:32:10 -0400534define_keywords! {
535 "as" pub struct As /// `as`
536 "async" pub struct Async /// `async`
537 "auto" pub struct Auto /// `auto`
538 "box" pub struct Box /// `box`
539 "break" pub struct Break /// `break`
540 "Self" pub struct CapSelf /// `Self`
541 "const" pub struct Const /// `const`
542 "continue" pub struct Continue /// `continue`
543 "crate" pub struct Crate /// `crate`
544 "default" pub struct Default /// `default`
545 "dyn" pub struct Dyn /// `dyn`
546 "else" pub struct Else /// `else`
547 "enum" pub struct Enum /// `enum`
548 "existential" pub struct Existential /// `existential`
549 "extern" pub struct Extern /// `extern`
550 "fn" pub struct Fn /// `fn`
551 "for" pub struct For /// `for`
552 "if" pub struct If /// `if`
553 "impl" pub struct Impl /// `impl`
554 "in" pub struct In /// `in`
555 "let" pub struct Let /// `let`
556 "loop" pub struct Loop /// `loop`
557 "macro" pub struct Macro /// `macro`
558 "match" pub struct Match /// `match`
559 "mod" pub struct Mod /// `mod`
560 "move" pub struct Move /// `move`
561 "mut" pub struct Mut /// `mut`
562 "pub" pub struct Pub /// `pub`
563 "ref" pub struct Ref /// `ref`
564 "return" pub struct Return /// `return`
565 "self" pub struct Self_ /// `self`
566 "static" pub struct Static /// `static`
567 "struct" pub struct Struct /// `struct`
568 "super" pub struct Super /// `super`
569 "trait" pub struct Trait /// `trait`
570 "try" pub struct Try /// `try`
571 "type" pub struct Type /// `type`
572 "union" pub struct Union /// `union`
573 "unsafe" pub struct Unsafe /// `unsafe`
574 "use" pub struct Use /// `use`
575 "where" pub struct Where /// `where`
576 "while" pub struct While /// `while`
577 "yield" pub struct Yield /// `yield`
578}
579
580define_punctuation! {
581 "+" pub struct Add/1 /// `+`
582 "+=" pub struct AddEq/2 /// `+=`
583 "&" pub struct And/1 /// `&`
584 "&&" pub struct AndAnd/2 /// `&&`
585 "&=" pub struct AndEq/2 /// `&=`
586 "@" pub struct At/1 /// `@`
587 "!" pub struct Bang/1 /// `!`
588 "^" pub struct Caret/1 /// `^`
589 "^=" pub struct CaretEq/2 /// `^=`
590 ":" pub struct Colon/1 /// `:`
591 "::" pub struct Colon2/2 /// `::`
592 "," pub struct Comma/1 /// `,`
593 "/" pub struct Div/1 /// `/`
594 "/=" pub struct DivEq/2 /// `/=`
595 "$" pub struct Dollar/1 /// `$`
596 "." pub struct Dot/1 /// `.`
597 ".." pub struct Dot2/2 /// `..`
598 "..." pub struct Dot3/3 /// `...`
599 "..=" pub struct DotDotEq/3 /// `..=`
600 "=" pub struct Eq/1 /// `=`
601 "==" pub struct EqEq/2 /// `==`
602 ">=" pub struct Ge/2 /// `>=`
603 ">" pub struct Gt/1 /// `>`
604 "<=" pub struct Le/2 /// `<=`
605 "<" pub struct Lt/1 /// `<`
606 "*=" pub struct MulEq/2 /// `*=`
607 "!=" pub struct Ne/2 /// `!=`
608 "|" pub struct Or/1 /// `|`
609 "|=" pub struct OrEq/2 /// `|=`
610 "||" pub struct OrOr/2 /// `||`
611 "#" pub struct Pound/1 /// `#`
612 "?" pub struct Question/1 /// `?`
613 "->" pub struct RArrow/2 /// `->`
614 "<-" pub struct LArrow/2 /// `<-`
615 "%" pub struct Rem/1 /// `%`
616 "%=" pub struct RemEq/2 /// `%=`
617 "=>" pub struct FatArrow/2 /// `=>`
618 ";" pub struct Semi/1 /// `;`
619 "<<" pub struct Shl/2 /// `<<`
620 "<<=" pub struct ShlEq/3 /// `<<=`
621 ">>" pub struct Shr/2 /// `>>`
622 ">>=" pub struct ShrEq/3 /// `>>=`
623 "*" pub struct Star/1 /// `*`
624 "-" pub struct Sub/1 /// `-`
625 "-=" pub struct SubEq/2 /// `-=`
626}
627
628define_delimiters! {
629 "{" pub struct Brace /// `{...}`
630 "[" pub struct Bracket /// `[...]`
631 "(" pub struct Paren /// `(...)`
632 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700633}
634
David Tolnayf005f962018-01-06 21:19:41 -0800635/// A type-macro that expands to the name of the Rust type representation of a
636/// given token.
637///
638/// See the [token module] documentation for details and examples.
639///
640/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800641// Unfortunate duplication due to a rustdoc bug.
642// https://github.com/rust-lang/rust/issues/45939
643#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700644#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800645macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400646 (as) => { $crate::token::As };
647 (async) => { $crate::token::Async };
648 (auto) => { $crate::token::Auto };
649 (box) => { $crate::token::Box };
650 (break) => { $crate::token::Break };
651 (Self) => { $crate::token::CapSelf };
652 (const) => { $crate::token::Const };
653 (continue) => { $crate::token::Continue };
654 (crate) => { $crate::token::Crate };
655 (default) => { $crate::token::Default };
656 (dyn) => { $crate::token::Dyn };
657 (else) => { $crate::token::Else };
658 (enum) => { $crate::token::Enum };
659 (existential) => { $crate::token::Existential };
660 (extern) => { $crate::token::Extern };
661 (fn) => { $crate::token::Fn };
662 (for) => { $crate::token::For };
663 (if) => { $crate::token::If };
664 (impl) => { $crate::token::Impl };
665 (in) => { $crate::token::In };
666 (let) => { $crate::token::Let };
667 (loop) => { $crate::token::Loop };
668 (macro) => { $crate::token::Macro };
669 (match) => { $crate::token::Match };
670 (mod) => { $crate::token::Mod };
671 (move) => { $crate::token::Move };
672 (mut) => { $crate::token::Mut };
673 (pub) => { $crate::token::Pub };
674 (ref) => { $crate::token::Ref };
675 (return) => { $crate::token::Return };
676 (self) => { $crate::token::Self_ };
677 (static) => { $crate::token::Static };
678 (struct) => { $crate::token::Struct };
679 (super) => { $crate::token::Super };
680 (trait) => { $crate::token::Trait };
681 (try) => { $crate::token::Try };
682 (type) => { $crate::token::Type };
683 (union) => { $crate::token::Union };
684 (unsafe) => { $crate::token::Unsafe };
685 (use) => { $crate::token::Use };
686 (where) => { $crate::token::Where };
687 (while) => { $crate::token::While };
688 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400689 (+) => { $crate::token::Add };
690 (+=) => { $crate::token::AddEq };
691 (&) => { $crate::token::And };
692 (&&) => { $crate::token::AndAnd };
693 (&=) => { $crate::token::AndEq };
694 (@) => { $crate::token::At };
695 (!) => { $crate::token::Bang };
696 (^) => { $crate::token::Caret };
697 (^=) => { $crate::token::CaretEq };
698 (:) => { $crate::token::Colon };
699 (::) => { $crate::token::Colon2 };
700 (,) => { $crate::token::Comma };
701 (/) => { $crate::token::Div };
702 (/=) => { $crate::token::DivEq };
703 (.) => { $crate::token::Dot };
704 (..) => { $crate::token::Dot2 };
705 (...) => { $crate::token::Dot3 };
706 (..=) => { $crate::token::DotDotEq };
707 (=) => { $crate::token::Eq };
708 (==) => { $crate::token::EqEq };
709 (>=) => { $crate::token::Ge };
710 (>) => { $crate::token::Gt };
711 (<=) => { $crate::token::Le };
712 (<) => { $crate::token::Lt };
713 (*=) => { $crate::token::MulEq };
714 (!=) => { $crate::token::Ne };
715 (|) => { $crate::token::Or };
716 (|=) => { $crate::token::OrEq };
717 (||) => { $crate::token::OrOr };
718 (#) => { $crate::token::Pound };
719 (?) => { $crate::token::Question };
720 (->) => { $crate::token::RArrow };
721 (<-) => { $crate::token::LArrow };
722 (%) => { $crate::token::Rem };
723 (%=) => { $crate::token::RemEq };
724 (=>) => { $crate::token::FatArrow };
725 (;) => { $crate::token::Semi };
726 (<<) => { $crate::token::Shl };
727 (<<=) => { $crate::token::ShlEq };
728 (>>) => { $crate::token::Shr };
729 (>>=) => { $crate::token::ShrEq };
730 (*) => { $crate::token::Star };
731 (-) => { $crate::token::Sub };
732 (-=) => { $crate::token::SubEq };
733 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800734}
735
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700736#[cfg(feature = "parsing")]
737mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700738 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700739
David Tolnay68274de2018-09-02 17:15:01 -0700740 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400741 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400742 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400743 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700744
David Tolnay776f8e02018-08-24 22:32:10 -0400745 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700746 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400747 if let Some((ident, rest)) = cursor.ident() {
748 if ident == token {
749 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700750 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700751 }
David Tolnay776f8e02018-08-24 22:32:10 -0400752 Err(cursor.error(format!("expected `{}`", token)))
753 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700754 }
755
David Tolnay68274de2018-09-02 17:15:01 -0700756 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
757 if let Some((ident, _rest)) = cursor.ident() {
758 ident == token
759 } else {
760 false
761 }
762 }
763
David Tolnay776f8e02018-08-24 22:32:10 -0400764 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700765 let mut spans = [input.cursor().span(); 3];
766 punct_helper(input, token, &mut spans)?;
767 Ok(S::from_spans(&spans))
768 }
769
770 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700771 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400772 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400773 assert!(token.len() <= spans.len());
774
775 for (i, ch) in token.chars().enumerate() {
776 match cursor.punct() {
777 Some((punct, rest)) => {
778 spans[i] = punct.span();
779 if punct.as_char() != ch {
780 break;
781 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700782 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400783 } else if punct.spacing() != Spacing::Joint {
784 break;
785 }
786 cursor = rest;
787 }
788 None => break,
789 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400790 }
David Tolnay776f8e02018-08-24 22:32:10 -0400791
792 Err(Error::new(spans[0], format!("expected `{}`", token)))
793 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700794 }
David Tolnay68274de2018-09-02 17:15:01 -0700795
796 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
797 for (i, ch) in token.chars().enumerate() {
798 match cursor.punct() {
799 Some((punct, rest)) => {
800 if punct.as_char() != ch {
801 break;
802 } else if i == token.len() - 1 {
803 return true;
804 } else if punct.spacing() != Spacing::Joint {
805 break;
806 }
807 cursor = rest;
808 }
809 None => break,
810 }
811 }
812 false
813 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700814}
815
816#[cfg(feature = "printing")]
817mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700818 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700819 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700820
Alex Crichtona74a1c82018-05-16 10:20:44 -0700821 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700822 assert_eq!(s.len(), spans.len());
823
824 let mut chars = s.chars();
825 let mut spans = spans.iter();
826 let ch = chars.next_back().unwrap();
827 let span = spans.next_back().unwrap();
828 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700829 let mut op = Punct::new(ch, Spacing::Joint);
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 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700835 op.set_span(*span);
836 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700837 }
838
Alex Crichtona74a1c82018-05-16 10:20:44 -0700839 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
840 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700841 }
842
Alex Crichtona74a1c82018-05-16 10:20:44 -0700843 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500844 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700845 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700846 {
David Tolnay00ab6982017-12-31 18:15:06 -0500847 let delim = match s {
848 "(" => Delimiter::Parenthesis,
849 "[" => Delimiter::Bracket,
850 "{" => Delimiter::Brace,
851 " " => Delimiter::None,
852 _ => panic!("unknown delimiter: {}", s),
853 };
hcplaa511792018-05-29 07:13:01 +0300854 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500855 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700856 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700857 g.set_span(*span);
858 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700859 }
860}