blob: 4a44067dce12742f5de5b830a2e0dcf7914d77c6 [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")]
David Tolnay719ad5a2018-09-02 18:01:15 -0700144impl private::Sealed for Ident {}
145
146#[cfg(feature = "parsing")]
David Tolnay65557f02018-09-01 11:08:27 -0700147fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
148 let scope = Span::call_site();
149 let unexpected = Rc::new(Cell::new(None));
150 let buffer = ::private::new_parse_buffer(scope, cursor, unexpected);
151 peek(&buffer)
152}
153
David Tolnay776f8e02018-08-24 22:32:10 -0400154macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400155 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400156 #[cfg(feature = "parsing")]
157 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700158 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700159 fn peek(input: ParseStream) -> bool {
160 <$name as Parse>::parse(input).is_ok()
161 }
162 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400163 }
164
David Tolnay2d032802018-09-01 10:51:59 -0700165 fn display() -> &'static str {
166 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400167 }
168 }
169
170 #[cfg(feature = "parsing")]
171 impl private::Sealed for $name {}
172 };
173}
174
David Tolnaya465b2d2018-08-27 08:21:09 -0700175#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400176impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700177#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400178impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700179#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400180impl_token!(LitStr "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!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700183#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400184impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700185#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400186impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700187#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400188impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700189#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400190impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700191#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400192impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400193
David Tolnay776f8e02018-08-24 22:32:10 -0400194macro_rules! define_keywords {
195 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
196 $(
197 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
198 #[$doc]
199 ///
200 /// Don't try to remember the name of this type -- use the [`Token!`]
201 /// macro instead.
202 ///
203 /// [`Token!`]: index.html
204 pub struct $name {
205 pub span: Span,
206 }
207
208 #[doc(hidden)]
209 #[allow(non_snake_case)]
210 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
211 $name {
212 span: span.into_spans()[0],
213 }
214 }
215
David Tolnay776f8e02018-08-24 22:32:10 -0400216 impl std::default::Default for $name {
217 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700218 $name {
219 span: Span::call_site(),
220 }
David Tolnay776f8e02018-08-24 22:32:10 -0400221 }
222 }
223
224 #[cfg(feature = "extra-traits")]
225 impl Debug for $name {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 f.write_str(stringify!($name))
228 }
229 }
230
231 #[cfg(feature = "extra-traits")]
232 impl cmp::Eq for $name {}
233
234 #[cfg(feature = "extra-traits")]
235 impl PartialEq for $name {
236 fn eq(&self, _other: &$name) -> bool {
237 true
238 }
239 }
240
241 #[cfg(feature = "extra-traits")]
242 impl Hash for $name {
243 fn hash<H: Hasher>(&self, _state: &mut H) {}
244 }
245
246 #[cfg(feature = "printing")]
247 impl ToTokens for $name {
248 fn to_tokens(&self, tokens: &mut TokenStream) {
249 printing::keyword($token, &self.span, tokens);
250 }
251 }
252
253 #[cfg(feature = "parsing")]
254 impl Parse for $name {
255 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700256 Ok($name {
257 span: parsing::keyword(input, $token)?,
258 })
David Tolnay776f8e02018-08-24 22:32:10 -0400259 }
260 }
David Tolnay68274de2018-09-02 17:15:01 -0700261
262 #[cfg(feature = "parsing")]
263 impl Token for $name {
264 fn peek(cursor: Cursor) -> bool {
265 parsing::peek_keyword(cursor, $token)
266 }
267
268 fn display() -> &'static str {
269 concat!("`", $token, "`")
270 }
271 }
272
273 #[cfg(feature = "parsing")]
274 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400275 )*
276 };
277}
278
279macro_rules! define_punctuation_structs {
280 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
281 $(
282 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
283 #[$doc]
284 ///
285 /// Don't try to remember the name of this type -- use the [`Token!`]
286 /// macro instead.
287 ///
288 /// [`Token!`]: index.html
289 pub struct $name {
290 pub spans: [Span; $len],
291 }
292
293 #[doc(hidden)]
294 #[allow(non_snake_case)]
295 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
296 $name {
297 spans: spans.into_spans(),
298 }
299 }
300
David Tolnay776f8e02018-08-24 22:32:10 -0400301 impl std::default::Default for $name {
302 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700303 $name {
304 spans: [Span::call_site(); $len],
305 }
David Tolnay776f8e02018-08-24 22:32:10 -0400306 }
307 }
308
309 #[cfg(feature = "extra-traits")]
310 impl Debug for $name {
311 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312 f.write_str(stringify!($name))
313 }
314 }
315
316 #[cfg(feature = "extra-traits")]
317 impl cmp::Eq for $name {}
318
319 #[cfg(feature = "extra-traits")]
320 impl PartialEq for $name {
321 fn eq(&self, _other: &$name) -> bool {
322 true
323 }
324 }
325
326 #[cfg(feature = "extra-traits")]
327 impl Hash for $name {
328 fn hash<H: Hasher>(&self, _state: &mut H) {}
329 }
330 )*
331 };
332}
333
334macro_rules! define_punctuation {
335 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
336 $(
337 define_punctuation_structs! {
338 $token pub struct $name/$len #[$doc]
339 }
340
341 #[cfg(feature = "printing")]
342 impl ToTokens for $name {
343 fn to_tokens(&self, tokens: &mut TokenStream) {
344 printing::punct($token, &self.spans, tokens);
345 }
346 }
347
348 #[cfg(feature = "parsing")]
349 impl Parse for $name {
350 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700351 Ok($name {
352 spans: parsing::punct(input, $token)?,
353 })
David Tolnay776f8e02018-08-24 22:32:10 -0400354 }
355 }
David Tolnay68274de2018-09-02 17:15:01 -0700356
357 #[cfg(feature = "parsing")]
358 impl Token for $name {
359 fn peek(cursor: Cursor) -> bool {
360 parsing::peek_punct(cursor, $token)
361 }
362
363 fn display() -> &'static str {
364 concat!("`", $token, "`")
365 }
366 }
367
368 #[cfg(feature = "parsing")]
369 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400370 )*
371 };
372}
373
374macro_rules! define_delimiters {
375 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
376 $(
377 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
378 #[$doc]
379 pub struct $name {
380 pub span: Span,
381 }
382
383 #[doc(hidden)]
384 #[allow(non_snake_case)]
385 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
386 $name {
387 span: span.into_spans()[0],
388 }
389 }
390
391 impl std::default::Default for $name {
392 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700393 $name {
394 span: Span::call_site(),
395 }
David Tolnay776f8e02018-08-24 22:32:10 -0400396 }
397 }
398
399 #[cfg(feature = "extra-traits")]
400 impl Debug for $name {
401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402 f.write_str(stringify!($name))
403 }
404 }
405
406 #[cfg(feature = "extra-traits")]
407 impl cmp::Eq for $name {}
408
409 #[cfg(feature = "extra-traits")]
410 impl PartialEq for $name {
411 fn eq(&self, _other: &$name) -> bool {
412 true
413 }
414 }
415
416 #[cfg(feature = "extra-traits")]
417 impl Hash for $name {
418 fn hash<H: Hasher>(&self, _state: &mut H) {}
419 }
420
421 impl $name {
422 #[cfg(feature = "printing")]
423 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
424 where
425 F: FnOnce(&mut TokenStream),
426 {
427 printing::delim($token, &self.span, tokens, f);
428 }
David Tolnay776f8e02018-08-24 22:32:10 -0400429 }
David Tolnay2d84a082018-08-25 16:31:38 -0400430
431 #[cfg(feature = "parsing")]
432 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400433 )*
434 };
435}
436
437define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400438 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700439}
440
David Tolnay776f8e02018-08-24 22:32:10 -0400441#[cfg(feature = "printing")]
442impl ToTokens for Underscore {
443 fn to_tokens(&self, tokens: &mut TokenStream) {
444 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700445 }
David Tolnay776f8e02018-08-24 22:32:10 -0400446}
447
448#[cfg(feature = "parsing")]
449impl Parse for Underscore {
450 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700451 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400452 if let Some((ident, rest)) = cursor.ident() {
453 if ident == "_" {
454 return Ok((Underscore(ident.span()), rest));
455 }
456 }
457 if let Some((punct, rest)) = cursor.punct() {
458 if punct.as_char() == '_' {
459 return Ok((Underscore(punct.span()), rest));
460 }
461 }
462 Err(cursor.error("expected `_`"))
463 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700464 }
David Tolnay776f8e02018-08-24 22:32:10 -0400465}
466
David Tolnay2d84a082018-08-25 16:31:38 -0400467#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700468impl Token for Underscore {
469 fn peek(cursor: Cursor) -> bool {
470 if let Some((ident, _rest)) = cursor.ident() {
471 return ident == "_";
472 }
473 if let Some((punct, _rest)) = cursor.punct() {
474 return punct.as_char() == '_'
475 }
476 false
477 }
478
479 fn display() -> &'static str {
480 "`_`"
481 }
482}
483
484#[cfg(feature = "parsing")]
485impl private::Sealed for Underscore {}
486
487#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400488impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700489 fn peek(cursor: Cursor) -> bool {
490 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400491 }
492
David Tolnay2d032802018-09-01 10:51:59 -0700493 fn display() -> &'static str {
494 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400495 }
496}
497
498#[cfg(feature = "parsing")]
499impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700500 fn peek(cursor: Cursor) -> bool {
501 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400502 }
503
David Tolnay2d032802018-09-01 10:51:59 -0700504 fn display() -> &'static str {
505 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400506 }
507}
508
509#[cfg(feature = "parsing")]
510impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700511 fn peek(cursor: Cursor) -> bool {
512 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400513 }
514
David Tolnay2d032802018-09-01 10:51:59 -0700515 fn display() -> &'static str {
516 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400517 }
518}
519
David Tolnaya7d69fc2018-08-26 13:30:24 -0400520#[cfg(feature = "parsing")]
521impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700522 fn peek(cursor: Cursor) -> bool {
523 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400524 }
525
David Tolnay2d032802018-09-01 10:51:59 -0700526 fn display() -> &'static str {
527 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400528 }
529}
530
David Tolnay776f8e02018-08-24 22:32:10 -0400531define_keywords! {
532 "as" pub struct As /// `as`
533 "async" pub struct Async /// `async`
534 "auto" pub struct Auto /// `auto`
535 "box" pub struct Box /// `box`
536 "break" pub struct Break /// `break`
537 "Self" pub struct CapSelf /// `Self`
538 "const" pub struct Const /// `const`
539 "continue" pub struct Continue /// `continue`
540 "crate" pub struct Crate /// `crate`
541 "default" pub struct Default /// `default`
542 "dyn" pub struct Dyn /// `dyn`
543 "else" pub struct Else /// `else`
544 "enum" pub struct Enum /// `enum`
545 "existential" pub struct Existential /// `existential`
546 "extern" pub struct Extern /// `extern`
547 "fn" pub struct Fn /// `fn`
548 "for" pub struct For /// `for`
549 "if" pub struct If /// `if`
550 "impl" pub struct Impl /// `impl`
551 "in" pub struct In /// `in`
552 "let" pub struct Let /// `let`
553 "loop" pub struct Loop /// `loop`
554 "macro" pub struct Macro /// `macro`
555 "match" pub struct Match /// `match`
556 "mod" pub struct Mod /// `mod`
557 "move" pub struct Move /// `move`
558 "mut" pub struct Mut /// `mut`
559 "pub" pub struct Pub /// `pub`
560 "ref" pub struct Ref /// `ref`
561 "return" pub struct Return /// `return`
562 "self" pub struct Self_ /// `self`
563 "static" pub struct Static /// `static`
564 "struct" pub struct Struct /// `struct`
565 "super" pub struct Super /// `super`
566 "trait" pub struct Trait /// `trait`
567 "try" pub struct Try /// `try`
568 "type" pub struct Type /// `type`
569 "union" pub struct Union /// `union`
570 "unsafe" pub struct Unsafe /// `unsafe`
571 "use" pub struct Use /// `use`
572 "where" pub struct Where /// `where`
573 "while" pub struct While /// `while`
574 "yield" pub struct Yield /// `yield`
575}
576
577define_punctuation! {
578 "+" pub struct Add/1 /// `+`
579 "+=" pub struct AddEq/2 /// `+=`
580 "&" pub struct And/1 /// `&`
581 "&&" pub struct AndAnd/2 /// `&&`
582 "&=" pub struct AndEq/2 /// `&=`
583 "@" pub struct At/1 /// `@`
584 "!" pub struct Bang/1 /// `!`
585 "^" pub struct Caret/1 /// `^`
586 "^=" pub struct CaretEq/2 /// `^=`
587 ":" pub struct Colon/1 /// `:`
588 "::" pub struct Colon2/2 /// `::`
589 "," pub struct Comma/1 /// `,`
590 "/" pub struct Div/1 /// `/`
591 "/=" pub struct DivEq/2 /// `/=`
592 "$" pub struct Dollar/1 /// `$`
593 "." pub struct Dot/1 /// `.`
594 ".." pub struct Dot2/2 /// `..`
595 "..." pub struct Dot3/3 /// `...`
596 "..=" pub struct DotDotEq/3 /// `..=`
597 "=" pub struct Eq/1 /// `=`
598 "==" pub struct EqEq/2 /// `==`
599 ">=" pub struct Ge/2 /// `>=`
600 ">" pub struct Gt/1 /// `>`
601 "<=" pub struct Le/2 /// `<=`
602 "<" pub struct Lt/1 /// `<`
603 "*=" pub struct MulEq/2 /// `*=`
604 "!=" pub struct Ne/2 /// `!=`
605 "|" pub struct Or/1 /// `|`
606 "|=" pub struct OrEq/2 /// `|=`
607 "||" pub struct OrOr/2 /// `||`
608 "#" pub struct Pound/1 /// `#`
609 "?" pub struct Question/1 /// `?`
610 "->" pub struct RArrow/2 /// `->`
611 "<-" pub struct LArrow/2 /// `<-`
612 "%" pub struct Rem/1 /// `%`
613 "%=" pub struct RemEq/2 /// `%=`
614 "=>" pub struct FatArrow/2 /// `=>`
615 ";" pub struct Semi/1 /// `;`
616 "<<" pub struct Shl/2 /// `<<`
617 "<<=" pub struct ShlEq/3 /// `<<=`
618 ">>" pub struct Shr/2 /// `>>`
619 ">>=" pub struct ShrEq/3 /// `>>=`
620 "*" pub struct Star/1 /// `*`
621 "-" pub struct Sub/1 /// `-`
622 "-=" pub struct SubEq/2 /// `-=`
623}
624
625define_delimiters! {
626 "{" pub struct Brace /// `{...}`
627 "[" pub struct Bracket /// `[...]`
628 "(" pub struct Paren /// `(...)`
629 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700630}
631
David Tolnayf005f962018-01-06 21:19:41 -0800632/// A type-macro that expands to the name of the Rust type representation of a
633/// given token.
634///
635/// See the [token module] documentation for details and examples.
636///
637/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800638// Unfortunate duplication due to a rustdoc bug.
639// https://github.com/rust-lang/rust/issues/45939
640#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700641#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800642macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400643 (as) => { $crate::token::As };
644 (async) => { $crate::token::Async };
645 (auto) => { $crate::token::Auto };
646 (box) => { $crate::token::Box };
647 (break) => { $crate::token::Break };
648 (Self) => { $crate::token::CapSelf };
649 (const) => { $crate::token::Const };
650 (continue) => { $crate::token::Continue };
651 (crate) => { $crate::token::Crate };
652 (default) => { $crate::token::Default };
653 (dyn) => { $crate::token::Dyn };
654 (else) => { $crate::token::Else };
655 (enum) => { $crate::token::Enum };
656 (existential) => { $crate::token::Existential };
657 (extern) => { $crate::token::Extern };
658 (fn) => { $crate::token::Fn };
659 (for) => { $crate::token::For };
660 (if) => { $crate::token::If };
661 (impl) => { $crate::token::Impl };
662 (in) => { $crate::token::In };
663 (let) => { $crate::token::Let };
664 (loop) => { $crate::token::Loop };
665 (macro) => { $crate::token::Macro };
666 (match) => { $crate::token::Match };
667 (mod) => { $crate::token::Mod };
668 (move) => { $crate::token::Move };
669 (mut) => { $crate::token::Mut };
670 (pub) => { $crate::token::Pub };
671 (ref) => { $crate::token::Ref };
672 (return) => { $crate::token::Return };
673 (self) => { $crate::token::Self_ };
674 (static) => { $crate::token::Static };
675 (struct) => { $crate::token::Struct };
676 (super) => { $crate::token::Super };
677 (trait) => { $crate::token::Trait };
678 (try) => { $crate::token::Try };
679 (type) => { $crate::token::Type };
680 (union) => { $crate::token::Union };
681 (unsafe) => { $crate::token::Unsafe };
682 (use) => { $crate::token::Use };
683 (where) => { $crate::token::Where };
684 (while) => { $crate::token::While };
685 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400686 (+) => { $crate::token::Add };
687 (+=) => { $crate::token::AddEq };
688 (&) => { $crate::token::And };
689 (&&) => { $crate::token::AndAnd };
690 (&=) => { $crate::token::AndEq };
691 (@) => { $crate::token::At };
692 (!) => { $crate::token::Bang };
693 (^) => { $crate::token::Caret };
694 (^=) => { $crate::token::CaretEq };
695 (:) => { $crate::token::Colon };
696 (::) => { $crate::token::Colon2 };
697 (,) => { $crate::token::Comma };
698 (/) => { $crate::token::Div };
699 (/=) => { $crate::token::DivEq };
700 (.) => { $crate::token::Dot };
701 (..) => { $crate::token::Dot2 };
702 (...) => { $crate::token::Dot3 };
703 (..=) => { $crate::token::DotDotEq };
704 (=) => { $crate::token::Eq };
705 (==) => { $crate::token::EqEq };
706 (>=) => { $crate::token::Ge };
707 (>) => { $crate::token::Gt };
708 (<=) => { $crate::token::Le };
709 (<) => { $crate::token::Lt };
710 (*=) => { $crate::token::MulEq };
711 (!=) => { $crate::token::Ne };
712 (|) => { $crate::token::Or };
713 (|=) => { $crate::token::OrEq };
714 (||) => { $crate::token::OrOr };
715 (#) => { $crate::token::Pound };
716 (?) => { $crate::token::Question };
717 (->) => { $crate::token::RArrow };
718 (<-) => { $crate::token::LArrow };
719 (%) => { $crate::token::Rem };
720 (%=) => { $crate::token::RemEq };
721 (=>) => { $crate::token::FatArrow };
722 (;) => { $crate::token::Semi };
723 (<<) => { $crate::token::Shl };
724 (<<=) => { $crate::token::ShlEq };
725 (>>) => { $crate::token::Shr };
726 (>>=) => { $crate::token::ShrEq };
727 (*) => { $crate::token::Star };
728 (-) => { $crate::token::Sub };
729 (-=) => { $crate::token::SubEq };
730 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800731}
732
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700733#[cfg(feature = "parsing")]
734mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700735 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700736
David Tolnay68274de2018-09-02 17:15:01 -0700737 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400738 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400739 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400740 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700741
David Tolnay776f8e02018-08-24 22:32:10 -0400742 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700743 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400744 if let Some((ident, rest)) = cursor.ident() {
745 if ident == token {
746 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700747 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700748 }
David Tolnay776f8e02018-08-24 22:32:10 -0400749 Err(cursor.error(format!("expected `{}`", token)))
750 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700751 }
752
David Tolnay68274de2018-09-02 17:15:01 -0700753 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
754 if let Some((ident, _rest)) = cursor.ident() {
755 ident == token
756 } else {
757 false
758 }
759 }
760
David Tolnay776f8e02018-08-24 22:32:10 -0400761 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700762 let mut spans = [input.cursor().span(); 3];
763 punct_helper(input, token, &mut spans)?;
764 Ok(S::from_spans(&spans))
765 }
766
767 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700768 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400769 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400770 assert!(token.len() <= spans.len());
771
772 for (i, ch) in token.chars().enumerate() {
773 match cursor.punct() {
774 Some((punct, rest)) => {
775 spans[i] = punct.span();
776 if punct.as_char() != ch {
777 break;
778 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700779 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400780 } else if punct.spacing() != Spacing::Joint {
781 break;
782 }
783 cursor = rest;
784 }
785 None => break,
786 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400787 }
David Tolnay776f8e02018-08-24 22:32:10 -0400788
789 Err(Error::new(spans[0], format!("expected `{}`", token)))
790 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700791 }
David Tolnay68274de2018-09-02 17:15:01 -0700792
793 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
794 for (i, ch) in token.chars().enumerate() {
795 match cursor.punct() {
796 Some((punct, rest)) => {
797 if punct.as_char() != ch {
798 break;
799 } else if i == token.len() - 1 {
800 return true;
801 } else if punct.spacing() != Spacing::Joint {
802 break;
803 }
804 cursor = rest;
805 }
806 None => break,
807 }
808 }
809 false
810 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700811}
812
813#[cfg(feature = "printing")]
814mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700815 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700816 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700817
Alex Crichtona74a1c82018-05-16 10:20:44 -0700818 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700819 assert_eq!(s.len(), spans.len());
820
821 let mut chars = s.chars();
822 let mut spans = spans.iter();
823 let ch = chars.next_back().unwrap();
824 let span = spans.next_back().unwrap();
825 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700826 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700827 op.set_span(*span);
828 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700829 }
830
Alex Crichtona74a1c82018-05-16 10:20:44 -0700831 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700832 op.set_span(*span);
833 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700834 }
835
Alex Crichtona74a1c82018-05-16 10:20:44 -0700836 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
837 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700838 }
839
Alex Crichtona74a1c82018-05-16 10:20:44 -0700840 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500841 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700842 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700843 {
David Tolnay00ab6982017-12-31 18:15:06 -0500844 let delim = match s {
845 "(" => Delimiter::Parenthesis,
846 "[" => Delimiter::Bracket,
847 "{" => Delimiter::Brace,
848 " " => Delimiter::None,
849 _ => panic!("unknown delimiter: {}", s),
850 };
hcplaa511792018-05-29 07:13:01 +0300851 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500852 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700853 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700854 g.set_span(*span);
855 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700856 }
857}