blob: 1453ae97581b574953c370008ddc099d74c9324a [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnaye79ae182018-01-06 19:23:37 -08009//! Tokens representing Rust punctuation, keywords, and delimiters.
Alex Crichton954046c2017-05-30 21:49:42 -070010//!
David Tolnaye79ae182018-01-06 19:23:37 -080011//! The type names in this module can be difficult to keep straight, so we
12//! prefer to use the [`Token!`] macro instead. This is a type-macro that
13//! expands to the token type of the given token.
14//!
15//! [`Token!`]: ../macro.Token.html
16//!
17//! # Example
18//!
19//! The [`ItemStatic`] syntax tree node is defined like this.
20//!
21//! [`ItemStatic`]: ../struct.ItemStatic.html
22//!
23//! ```
David Tolnaya1c98072018-09-06 08:58:10 -070024//! # #[macro_use]
David Tolnaye79ae182018-01-06 19:23:37 -080025//! # extern crate syn;
26//! #
David Tolnaya1c98072018-09-06 08:58:10 -070027//! # use syn::{Attribute, Expr, Ident, Type, Visibility};
David Tolnaye79ae182018-01-06 19:23:37 -080028//! #
29//! pub struct ItemStatic {
30//! pub attrs: Vec<Attribute>,
31//! pub vis: Visibility,
32//! pub static_token: Token![static],
33//! pub mutability: Option<Token![mut]>,
34//! pub ident: Ident,
35//! pub colon_token: Token![:],
36//! pub ty: Box<Type>,
37//! pub eq_token: Token![=],
38//! pub expr: Box<Expr>,
39//! pub semi_token: Token![;],
40//! }
41//! #
42//! # fn main() {}
43//! ```
44//!
45//! # Parsing
46//!
David Tolnayd8cc0552018-08-31 08:39:17 -070047//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
48//! method. Delimiter tokens are parsed using the [`parenthesized!`],
49//! [`bracketed!`] and [`braced!`] macros.
David Tolnaye79ae182018-01-06 19:23:37 -080050//!
David Tolnayd8cc0552018-08-31 08:39:17 -070051//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
52//! [`parenthesized!`]: ../macro.parenthesized.html
53//! [`bracketed!`]: ../macro.bracketed.html
54//! [`braced!`]: ../macro.braced.html
David Tolnaye79ae182018-01-06 19:23:37 -080055//!
56//! ```
David Tolnay9b00f652018-09-01 10:31:02 -070057//! # extern crate syn;
58//! #
David Tolnay67fea042018-11-24 14:50:20 -080059//! use syn::{Attribute, Result};
60//! use syn::parse::{Parse, ParseStream};
David Tolnaye79ae182018-01-06 19:23:37 -080061//! #
David Tolnay9b00f652018-09-01 10:31:02 -070062//! # enum ItemStatic {}
David Tolnaye79ae182018-01-06 19:23:37 -080063//!
64//! // Parse the ItemStatic struct shown above.
David Tolnayd8cc0552018-08-31 08:39:17 -070065//! impl Parse for ItemStatic {
66//! fn parse(input: ParseStream) -> Result<Self> {
David Tolnay9b00f652018-09-01 10:31:02 -070067//! # use syn::ItemStatic;
68//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
69//! Ok(ItemStatic {
70//! attrs: input.call(Attribute::parse_outer)?,
71//! vis: input.parse()?,
72//! static_token: input.parse()?,
73//! mutability: input.parse()?,
74//! ident: input.parse()?,
75//! colon_token: input.parse()?,
76//! ty: input.parse()?,
77//! eq_token: input.parse()?,
78//! expr: input.parse()?,
79//! semi_token: input.parse()?,
80//! })
81//! # }
82//! # unimplemented!()
83//! }
David Tolnaye79ae182018-01-06 19:23:37 -080084//! }
85//! #
86//! # fn main() {}
87//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070088
David Tolnay776f8e02018-08-24 22:32:10 -040089use std;
90#[cfg(feature = "extra-traits")]
91use std::cmp;
92#[cfg(feature = "extra-traits")]
93use std::fmt::{self, Debug};
94#[cfg(feature = "extra-traits")]
95use std::hash::{Hash, Hasher};
96
David Tolnay2d84a082018-08-25 16:31:38 -040097#[cfg(feature = "parsing")]
98use proc_macro2::Delimiter;
David Tolnayaf1df8c2018-09-22 13:22:24 -070099#[cfg(any(feature = "parsing", feature = "printing"))]
100use proc_macro2::Ident;
101use proc_macro2::Span;
David Tolnay776f8e02018-08-24 22:32:10 -0400102#[cfg(feature = "printing")]
David Tolnayabbf8192018-09-22 13:24:46 -0700103use proc_macro2::TokenStream;
104#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400105use quote::{ToTokens, TokenStreamExt};
106
107#[cfg(feature = "parsing")]
David Tolnay00f81fd2018-09-01 10:50:12 -0700108use buffer::Cursor;
109#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400110use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700111#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400112#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400113use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700114#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400115#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400116use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400117#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400118use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400119#[cfg(feature = "parsing")]
David Tolnay7fb11e72018-09-06 01:02:27 -0700120use parse::{Parse, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400121use span::IntoSpans;
122
123/// Marker trait for types that represent single tokens.
124///
125/// This trait is sealed and cannot be implemented for types outside of Syn.
126#[cfg(feature = "parsing")]
127pub trait Token: private::Sealed {
128 // Not public API.
129 #[doc(hidden)]
David Tolnay00f81fd2018-09-01 10:50:12 -0700130 fn peek(cursor: Cursor) -> bool;
David Tolnay776f8e02018-08-24 22:32:10 -0400131
132 // Not public API.
133 #[doc(hidden)]
David Tolnay2d032802018-09-01 10:51:59 -0700134 fn display() -> &'static str;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700135}
136
137#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400138mod private {
139 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700140}
141
David Tolnay65557f02018-09-01 11:08:27 -0700142#[cfg(feature = "parsing")]
David Tolnay719ad5a2018-09-02 18:01:15 -0700143impl private::Sealed for Ident {}
144
David Tolnayff18ed92018-10-26 02:25:05 -0700145#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay719ad5a2018-09-02 18:01:15 -0700146#[cfg(feature = "parsing")]
David Tolnay65557f02018-09-01 11:08:27 -0700147fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
David Tolnayff18ed92018-10-26 02:25:05 -0700148 use std::cell::Cell;
149 use std::rc::Rc;
150
David Tolnay65557f02018-09-01 11:08:27 -0700151 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 Tolnayaf1df8c2018-09-22 13:22:24 -0700157#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay776f8e02018-08-24 22:32:10 -0400158macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400159 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400160 #[cfg(feature = "parsing")]
161 impl Token for $name {
David Tolnay00f81fd2018-09-01 10:50:12 -0700162 fn peek(cursor: Cursor) -> bool {
David Tolnay65557f02018-09-01 11:08:27 -0700163 fn peek(input: ParseStream) -> bool {
164 <$name as Parse>::parse(input).is_ok()
165 }
166 peek_impl(cursor, peek)
David Tolnay776f8e02018-08-24 22:32:10 -0400167 }
168
David Tolnay2d032802018-09-01 10:51:59 -0700169 fn display() -> &'static str {
170 $display
David Tolnay776f8e02018-08-24 22:32:10 -0400171 }
172 }
173
174 #[cfg(feature = "parsing")]
175 impl private::Sealed for $name {}
176 };
177}
178
David Tolnaya465b2d2018-08-27 08:21:09 -0700179#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400180impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700181#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400182impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700183#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400184impl_token!(LitStr "string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700185#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400186impl_token!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700187#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400188impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700189#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400190impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700191#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400192impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700193#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400194impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700195#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400196impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400197
David Tolnay7fb11e72018-09-06 01:02:27 -0700198// Not public API.
199#[cfg(feature = "parsing")]
200#[doc(hidden)]
201pub trait CustomKeyword {
202 fn ident() -> &'static str;
203 fn display() -> &'static str;
204}
205
206#[cfg(feature = "parsing")]
207impl<K: CustomKeyword> private::Sealed for K {}
208
209#[cfg(feature = "parsing")]
210impl<K: CustomKeyword> Token for K {
211 fn peek(cursor: Cursor) -> bool {
212 parsing::peek_keyword(cursor, K::ident())
213 }
214
215 fn display() -> &'static str {
216 K::display()
217 }
218}
219
David Tolnay776f8e02018-08-24 22:32:10 -0400220macro_rules! define_keywords {
221 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
222 $(
223 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
224 #[$doc]
225 ///
226 /// Don't try to remember the name of this type -- use the [`Token!`]
227 /// macro instead.
228 ///
229 /// [`Token!`]: index.html
230 pub struct $name {
231 pub span: Span,
232 }
233
234 #[doc(hidden)]
235 #[allow(non_snake_case)]
236 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
237 $name {
238 span: span.into_spans()[0],
239 }
240 }
241
David Tolnay776f8e02018-08-24 22:32:10 -0400242 impl std::default::Default for $name {
243 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700244 $name {
245 span: Span::call_site(),
246 }
David Tolnay776f8e02018-08-24 22:32:10 -0400247 }
248 }
249
250 #[cfg(feature = "extra-traits")]
251 impl Debug for $name {
252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 f.write_str(stringify!($name))
254 }
255 }
256
257 #[cfg(feature = "extra-traits")]
258 impl cmp::Eq for $name {}
259
260 #[cfg(feature = "extra-traits")]
261 impl PartialEq for $name {
262 fn eq(&self, _other: &$name) -> bool {
263 true
264 }
265 }
266
267 #[cfg(feature = "extra-traits")]
268 impl Hash for $name {
269 fn hash<H: Hasher>(&self, _state: &mut H) {}
270 }
271
272 #[cfg(feature = "printing")]
273 impl ToTokens for $name {
274 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800275 printing::keyword($token, self.span, tokens);
David Tolnay776f8e02018-08-24 22:32:10 -0400276 }
277 }
278
279 #[cfg(feature = "parsing")]
280 impl Parse for $name {
281 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700282 Ok($name {
283 span: parsing::keyword(input, $token)?,
284 })
David Tolnay776f8e02018-08-24 22:32:10 -0400285 }
286 }
David Tolnay68274de2018-09-02 17:15:01 -0700287
288 #[cfg(feature = "parsing")]
289 impl Token for $name {
290 fn peek(cursor: Cursor) -> bool {
291 parsing::peek_keyword(cursor, $token)
292 }
293
294 fn display() -> &'static str {
295 concat!("`", $token, "`")
296 }
297 }
298
299 #[cfg(feature = "parsing")]
300 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400301 )*
302 };
303}
304
305macro_rules! define_punctuation_structs {
306 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
307 $(
308 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
309 #[$doc]
310 ///
311 /// Don't try to remember the name of this type -- use the [`Token!`]
312 /// macro instead.
313 ///
314 /// [`Token!`]: index.html
315 pub struct $name {
316 pub spans: [Span; $len],
317 }
318
319 #[doc(hidden)]
320 #[allow(non_snake_case)]
321 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
322 $name {
323 spans: spans.into_spans(),
324 }
325 }
326
David Tolnay776f8e02018-08-24 22:32:10 -0400327 impl std::default::Default for $name {
328 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700329 $name {
330 spans: [Span::call_site(); $len],
331 }
David Tolnay776f8e02018-08-24 22:32:10 -0400332 }
333 }
334
335 #[cfg(feature = "extra-traits")]
336 impl Debug for $name {
337 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338 f.write_str(stringify!($name))
339 }
340 }
341
342 #[cfg(feature = "extra-traits")]
343 impl cmp::Eq for $name {}
344
345 #[cfg(feature = "extra-traits")]
346 impl PartialEq for $name {
347 fn eq(&self, _other: &$name) -> bool {
348 true
349 }
350 }
351
352 #[cfg(feature = "extra-traits")]
353 impl Hash for $name {
354 fn hash<H: Hasher>(&self, _state: &mut H) {}
355 }
356 )*
357 };
358}
359
360macro_rules! define_punctuation {
361 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
362 $(
363 define_punctuation_structs! {
364 $token pub struct $name/$len #[$doc]
365 }
366
367 #[cfg(feature = "printing")]
368 impl ToTokens for $name {
369 fn to_tokens(&self, tokens: &mut TokenStream) {
370 printing::punct($token, &self.spans, tokens);
371 }
372 }
373
374 #[cfg(feature = "parsing")]
375 impl Parse for $name {
376 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay4398c922018-09-01 11:23:10 -0700377 Ok($name {
378 spans: parsing::punct(input, $token)?,
379 })
David Tolnay776f8e02018-08-24 22:32:10 -0400380 }
381 }
David Tolnay68274de2018-09-02 17:15:01 -0700382
383 #[cfg(feature = "parsing")]
384 impl Token for $name {
385 fn peek(cursor: Cursor) -> bool {
386 parsing::peek_punct(cursor, $token)
387 }
388
389 fn display() -> &'static str {
390 concat!("`", $token, "`")
391 }
392 }
393
394 #[cfg(feature = "parsing")]
395 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400396 )*
397 };
398}
399
400macro_rules! define_delimiters {
401 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
402 $(
403 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
404 #[$doc]
405 pub struct $name {
406 pub span: Span,
407 }
408
409 #[doc(hidden)]
410 #[allow(non_snake_case)]
411 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
412 $name {
413 span: span.into_spans()[0],
414 }
415 }
416
417 impl std::default::Default for $name {
418 fn default() -> Self {
David Tolnay4398c922018-09-01 11:23:10 -0700419 $name {
420 span: Span::call_site(),
421 }
David Tolnay776f8e02018-08-24 22:32:10 -0400422 }
423 }
424
425 #[cfg(feature = "extra-traits")]
426 impl Debug for $name {
427 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
428 f.write_str(stringify!($name))
429 }
430 }
431
432 #[cfg(feature = "extra-traits")]
433 impl cmp::Eq for $name {}
434
435 #[cfg(feature = "extra-traits")]
436 impl PartialEq for $name {
437 fn eq(&self, _other: &$name) -> bool {
438 true
439 }
440 }
441
442 #[cfg(feature = "extra-traits")]
443 impl Hash for $name {
444 fn hash<H: Hasher>(&self, _state: &mut H) {}
445 }
446
447 impl $name {
448 #[cfg(feature = "printing")]
449 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
450 where
451 F: FnOnce(&mut TokenStream),
452 {
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800453 printing::delim($token, self.span, tokens, f);
David Tolnay776f8e02018-08-24 22:32:10 -0400454 }
David Tolnay776f8e02018-08-24 22:32:10 -0400455 }
David Tolnay2d84a082018-08-25 16:31:38 -0400456
457 #[cfg(feature = "parsing")]
458 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400459 )*
460 };
461}
462
463define_punctuation_structs! {
David Tolnay776f8e02018-08-24 22:32:10 -0400464 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700465}
466
David Tolnay776f8e02018-08-24 22:32:10 -0400467#[cfg(feature = "printing")]
468impl ToTokens for Underscore {
469 fn to_tokens(&self, tokens: &mut TokenStream) {
470 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700471 }
David Tolnay776f8e02018-08-24 22:32:10 -0400472}
473
474#[cfg(feature = "parsing")]
475impl Parse for Underscore {
476 fn parse(input: ParseStream) -> Result<Self> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700477 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400478 if let Some((ident, rest)) = cursor.ident() {
479 if ident == "_" {
480 return Ok((Underscore(ident.span()), rest));
481 }
482 }
483 if let Some((punct, rest)) = cursor.punct() {
484 if punct.as_char() == '_' {
485 return Ok((Underscore(punct.span()), rest));
486 }
487 }
488 Err(cursor.error("expected `_`"))
489 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700490 }
David Tolnay776f8e02018-08-24 22:32:10 -0400491}
492
David Tolnay2d84a082018-08-25 16:31:38 -0400493#[cfg(feature = "parsing")]
David Tolnay68274de2018-09-02 17:15:01 -0700494impl Token for Underscore {
495 fn peek(cursor: Cursor) -> bool {
496 if let Some((ident, _rest)) = cursor.ident() {
497 return ident == "_";
498 }
499 if let Some((punct, _rest)) = cursor.punct() {
David Tolnay3db288c2018-09-09 22:16:51 -0700500 return punct.as_char() == '_';
David Tolnay68274de2018-09-02 17:15:01 -0700501 }
502 false
503 }
504
505 fn display() -> &'static str {
506 "`_`"
507 }
508}
509
510#[cfg(feature = "parsing")]
511impl private::Sealed for Underscore {}
512
513#[cfg(feature = "parsing")]
David Tolnay2d84a082018-08-25 16:31:38 -0400514impl Token for Paren {
David Tolnay00f81fd2018-09-01 10:50:12 -0700515 fn peek(cursor: Cursor) -> bool {
516 lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
David Tolnay2d84a082018-08-25 16:31:38 -0400517 }
518
David Tolnay2d032802018-09-01 10:51:59 -0700519 fn display() -> &'static str {
520 "parentheses"
David Tolnay2d84a082018-08-25 16:31:38 -0400521 }
522}
523
524#[cfg(feature = "parsing")]
525impl Token for Brace {
David Tolnay00f81fd2018-09-01 10:50:12 -0700526 fn peek(cursor: Cursor) -> bool {
527 lookahead::is_delimiter(cursor, Delimiter::Brace)
David Tolnay2d84a082018-08-25 16:31:38 -0400528 }
529
David Tolnay2d032802018-09-01 10:51:59 -0700530 fn display() -> &'static str {
531 "curly braces"
David Tolnay2d84a082018-08-25 16:31:38 -0400532 }
533}
534
535#[cfg(feature = "parsing")]
536impl Token for Bracket {
David Tolnay00f81fd2018-09-01 10:50:12 -0700537 fn peek(cursor: Cursor) -> bool {
538 lookahead::is_delimiter(cursor, Delimiter::Bracket)
David Tolnay2d84a082018-08-25 16:31:38 -0400539 }
540
David Tolnay2d032802018-09-01 10:51:59 -0700541 fn display() -> &'static str {
542 "square brackets"
David Tolnay2d84a082018-08-25 16:31:38 -0400543 }
544}
545
David Tolnaya7d69fc2018-08-26 13:30:24 -0400546#[cfg(feature = "parsing")]
547impl Token for Group {
David Tolnay00f81fd2018-09-01 10:50:12 -0700548 fn peek(cursor: Cursor) -> bool {
549 lookahead::is_delimiter(cursor, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -0400550 }
551
David Tolnay2d032802018-09-01 10:51:59 -0700552 fn display() -> &'static str {
553 "invisible group"
David Tolnaya7d69fc2018-08-26 13:30:24 -0400554 }
555}
556
David Tolnay776f8e02018-08-24 22:32:10 -0400557define_keywords! {
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700558 "abstract" pub struct Abstract /// `abstract`
David Tolnay776f8e02018-08-24 22:32:10 -0400559 "as" pub struct As /// `as`
560 "async" pub struct Async /// `async`
561 "auto" pub struct Auto /// `auto`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700562 "become" pub struct Become /// `become`
David Tolnay776f8e02018-08-24 22:32:10 -0400563 "box" pub struct Box /// `box`
564 "break" pub struct Break /// `break`
David Tolnay776f8e02018-08-24 22:32:10 -0400565 "const" pub struct Const /// `const`
566 "continue" pub struct Continue /// `continue`
567 "crate" pub struct Crate /// `crate`
568 "default" pub struct Default /// `default`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700569 "do" pub struct Do /// `do`
David Tolnay776f8e02018-08-24 22:32:10 -0400570 "dyn" pub struct Dyn /// `dyn`
571 "else" pub struct Else /// `else`
572 "enum" pub struct Enum /// `enum`
573 "existential" pub struct Existential /// `existential`
574 "extern" pub struct Extern /// `extern`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700575 "final" pub struct Final /// `final`
David Tolnay776f8e02018-08-24 22:32:10 -0400576 "fn" pub struct Fn /// `fn`
577 "for" pub struct For /// `for`
578 "if" pub struct If /// `if`
579 "impl" pub struct Impl /// `impl`
580 "in" pub struct In /// `in`
581 "let" pub struct Let /// `let`
582 "loop" pub struct Loop /// `loop`
583 "macro" pub struct Macro /// `macro`
584 "match" pub struct Match /// `match`
585 "mod" pub struct Mod /// `mod`
586 "move" pub struct Move /// `move`
587 "mut" pub struct Mut /// `mut`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700588 "override" pub struct Override /// `override`
589 "priv" pub struct Priv /// `priv`
David Tolnay776f8e02018-08-24 22:32:10 -0400590 "pub" pub struct Pub /// `pub`
591 "ref" pub struct Ref /// `ref`
592 "return" pub struct Return /// `return`
David Tolnayc0e742d2018-10-30 02:17:17 -0700593 "Self" pub struct SelfType /// `Self`
csmoef04dcc02018-10-30 16:45:13 +0800594 "self" pub struct SelfValue /// `self`
David Tolnay776f8e02018-08-24 22:32:10 -0400595 "static" pub struct Static /// `static`
596 "struct" pub struct Struct /// `struct`
597 "super" pub struct Super /// `super`
598 "trait" pub struct Trait /// `trait`
599 "try" pub struct Try /// `try`
600 "type" pub struct Type /// `type`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700601 "typeof" pub struct Typeof /// `typeof`
David Tolnay776f8e02018-08-24 22:32:10 -0400602 "union" pub struct Union /// `union`
603 "unsafe" pub struct Unsafe /// `unsafe`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700604 "unsized" pub struct Unsized /// `unsized`
David Tolnay776f8e02018-08-24 22:32:10 -0400605 "use" pub struct Use /// `use`
David Tolnayb1cbf7e2018-09-09 00:00:17 -0700606 "virtual" pub struct Virtual /// `virtual`
David Tolnay776f8e02018-08-24 22:32:10 -0400607 "where" pub struct Where /// `where`
608 "while" pub struct While /// `while`
609 "yield" pub struct Yield /// `yield`
610}
611
612define_punctuation! {
613 "+" pub struct Add/1 /// `+`
614 "+=" pub struct AddEq/2 /// `+=`
615 "&" pub struct And/1 /// `&`
616 "&&" pub struct AndAnd/2 /// `&&`
617 "&=" pub struct AndEq/2 /// `&=`
618 "@" pub struct At/1 /// `@`
619 "!" pub struct Bang/1 /// `!`
620 "^" pub struct Caret/1 /// `^`
621 "^=" pub struct CaretEq/2 /// `^=`
622 ":" pub struct Colon/1 /// `:`
623 "::" pub struct Colon2/2 /// `::`
624 "," pub struct Comma/1 /// `,`
625 "/" pub struct Div/1 /// `/`
626 "/=" pub struct DivEq/2 /// `/=`
627 "$" pub struct Dollar/1 /// `$`
628 "." pub struct Dot/1 /// `.`
629 ".." pub struct Dot2/2 /// `..`
630 "..." pub struct Dot3/3 /// `...`
631 "..=" pub struct DotDotEq/3 /// `..=`
632 "=" pub struct Eq/1 /// `=`
633 "==" pub struct EqEq/2 /// `==`
634 ">=" pub struct Ge/2 /// `>=`
635 ">" pub struct Gt/1 /// `>`
636 "<=" pub struct Le/2 /// `<=`
637 "<" pub struct Lt/1 /// `<`
638 "*=" pub struct MulEq/2 /// `*=`
639 "!=" pub struct Ne/2 /// `!=`
640 "|" pub struct Or/1 /// `|`
641 "|=" pub struct OrEq/2 /// `|=`
642 "||" pub struct OrOr/2 /// `||`
643 "#" pub struct Pound/1 /// `#`
644 "?" pub struct Question/1 /// `?`
645 "->" pub struct RArrow/2 /// `->`
646 "<-" pub struct LArrow/2 /// `<-`
647 "%" pub struct Rem/1 /// `%`
648 "%=" pub struct RemEq/2 /// `%=`
649 "=>" pub struct FatArrow/2 /// `=>`
650 ";" pub struct Semi/1 /// `;`
651 "<<" pub struct Shl/2 /// `<<`
652 "<<=" pub struct ShlEq/3 /// `<<=`
653 ">>" pub struct Shr/2 /// `>>`
654 ">>=" pub struct ShrEq/3 /// `>>=`
655 "*" pub struct Star/1 /// `*`
656 "-" pub struct Sub/1 /// `-`
657 "-=" pub struct SubEq/2 /// `-=`
David Tolnayf26be7d2018-09-23 01:32:08 -0700658 "~" pub struct Tilde/1 /// `~`
David Tolnay776f8e02018-08-24 22:32:10 -0400659}
660
661define_delimiters! {
662 "{" pub struct Brace /// `{...}`
663 "[" pub struct Bracket /// `[...]`
664 "(" pub struct Paren /// `(...)`
665 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700666}
667
David Tolnayf005f962018-01-06 21:19:41 -0800668/// A type-macro that expands to the name of the Rust type representation of a
669/// given token.
670///
671/// See the [token module] documentation for details and examples.
672///
673/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800674// Unfortunate duplication due to a rustdoc bug.
675// https://github.com/rust-lang/rust/issues/45939
676#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700677#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800678macro_rules! Token {
David Tolnayc327cd22018-09-09 00:37:28 -0700679 (abstract) => { $crate::token::Abstract };
David Tolnay776f8e02018-08-24 22:32:10 -0400680 (as) => { $crate::token::As };
681 (async) => { $crate::token::Async };
682 (auto) => { $crate::token::Auto };
David Tolnayc327cd22018-09-09 00:37:28 -0700683 (become) => { $crate::token::Become };
David Tolnay776f8e02018-08-24 22:32:10 -0400684 (box) => { $crate::token::Box };
685 (break) => { $crate::token::Break };
David Tolnay776f8e02018-08-24 22:32:10 -0400686 (const) => { $crate::token::Const };
687 (continue) => { $crate::token::Continue };
688 (crate) => { $crate::token::Crate };
689 (default) => { $crate::token::Default };
David Tolnayc327cd22018-09-09 00:37:28 -0700690 (do) => { $crate::token::Do };
David Tolnay776f8e02018-08-24 22:32:10 -0400691 (dyn) => { $crate::token::Dyn };
692 (else) => { $crate::token::Else };
693 (enum) => { $crate::token::Enum };
694 (existential) => { $crate::token::Existential };
695 (extern) => { $crate::token::Extern };
David Tolnayc327cd22018-09-09 00:37:28 -0700696 (final) => { $crate::token::Final };
David Tolnay776f8e02018-08-24 22:32:10 -0400697 (fn) => { $crate::token::Fn };
698 (for) => { $crate::token::For };
699 (if) => { $crate::token::If };
700 (impl) => { $crate::token::Impl };
701 (in) => { $crate::token::In };
702 (let) => { $crate::token::Let };
703 (loop) => { $crate::token::Loop };
704 (macro) => { $crate::token::Macro };
705 (match) => { $crate::token::Match };
706 (mod) => { $crate::token::Mod };
707 (move) => { $crate::token::Move };
708 (mut) => { $crate::token::Mut };
David Tolnayc327cd22018-09-09 00:37:28 -0700709 (override) => { $crate::token::Override };
710 (priv) => { $crate::token::Priv };
David Tolnay776f8e02018-08-24 22:32:10 -0400711 (pub) => { $crate::token::Pub };
712 (ref) => { $crate::token::Ref };
713 (return) => { $crate::token::Return };
David Tolnayc0e742d2018-10-30 02:17:17 -0700714 (Self) => { $crate::token::SelfType };
csmoef04dcc02018-10-30 16:45:13 +0800715 (self) => { $crate::token::SelfValue };
David Tolnay776f8e02018-08-24 22:32:10 -0400716 (static) => { $crate::token::Static };
717 (struct) => { $crate::token::Struct };
718 (super) => { $crate::token::Super };
719 (trait) => { $crate::token::Trait };
720 (try) => { $crate::token::Try };
721 (type) => { $crate::token::Type };
David Tolnayc327cd22018-09-09 00:37:28 -0700722 (typeof) => { $crate::token::Typeof };
David Tolnay776f8e02018-08-24 22:32:10 -0400723 (union) => { $crate::token::Union };
724 (unsafe) => { $crate::token::Unsafe };
David Tolnayc327cd22018-09-09 00:37:28 -0700725 (unsized) => { $crate::token::Unsized };
David Tolnay776f8e02018-08-24 22:32:10 -0400726 (use) => { $crate::token::Use };
David Tolnayc327cd22018-09-09 00:37:28 -0700727 (virtual) => { $crate::token::Virtual };
David Tolnay776f8e02018-08-24 22:32:10 -0400728 (where) => { $crate::token::Where };
729 (while) => { $crate::token::While };
730 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400731 (+) => { $crate::token::Add };
732 (+=) => { $crate::token::AddEq };
733 (&) => { $crate::token::And };
734 (&&) => { $crate::token::AndAnd };
735 (&=) => { $crate::token::AndEq };
736 (@) => { $crate::token::At };
737 (!) => { $crate::token::Bang };
738 (^) => { $crate::token::Caret };
739 (^=) => { $crate::token::CaretEq };
740 (:) => { $crate::token::Colon };
741 (::) => { $crate::token::Colon2 };
742 (,) => { $crate::token::Comma };
743 (/) => { $crate::token::Div };
744 (/=) => { $crate::token::DivEq };
745 (.) => { $crate::token::Dot };
746 (..) => { $crate::token::Dot2 };
747 (...) => { $crate::token::Dot3 };
748 (..=) => { $crate::token::DotDotEq };
749 (=) => { $crate::token::Eq };
750 (==) => { $crate::token::EqEq };
751 (>=) => { $crate::token::Ge };
752 (>) => { $crate::token::Gt };
753 (<=) => { $crate::token::Le };
754 (<) => { $crate::token::Lt };
755 (*=) => { $crate::token::MulEq };
756 (!=) => { $crate::token::Ne };
757 (|) => { $crate::token::Or };
758 (|=) => { $crate::token::OrEq };
759 (||) => { $crate::token::OrOr };
760 (#) => { $crate::token::Pound };
761 (?) => { $crate::token::Question };
762 (->) => { $crate::token::RArrow };
763 (<-) => { $crate::token::LArrow };
764 (%) => { $crate::token::Rem };
765 (%=) => { $crate::token::RemEq };
766 (=>) => { $crate::token::FatArrow };
767 (;) => { $crate::token::Semi };
768 (<<) => { $crate::token::Shl };
769 (<<=) => { $crate::token::ShlEq };
770 (>>) => { $crate::token::Shr };
771 (>>=) => { $crate::token::ShrEq };
772 (*) => { $crate::token::Star };
773 (-) => { $crate::token::Sub };
774 (-=) => { $crate::token::SubEq };
David Tolnayf26be7d2018-09-23 01:32:08 -0700775 (~) => { $crate::token::Tilde };
David Tolnaybb82ef02018-08-24 20:15:45 -0400776 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800777}
778
David Tolnayee612812018-10-30 02:16:03 -0700779// Old names. TODO: remove these re-exports in a breaking change.
780// https://github.com/dtolnay/syn/issues/486
781#[doc(hidden)]
782pub use self::SelfType as CapSelf;
783#[doc(hidden)]
784pub use self::SelfValue as Self_;
785
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700786#[cfg(feature = "parsing")]
787mod parsing {
David Tolnaya8205d92018-08-30 18:44:59 -0700788 use proc_macro2::{Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700789
David Tolnay68274de2018-09-02 17:15:01 -0700790 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400791 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400792 use parse::ParseStream;
David Tolnay776f8e02018-08-24 22:32:10 -0400793 use span::FromSpans;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700794
David Tolnay776f8e02018-08-24 22:32:10 -0400795 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700796 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400797 if let Some((ident, rest)) = cursor.ident() {
798 if ident == token {
799 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700800 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700801 }
David Tolnay776f8e02018-08-24 22:32:10 -0400802 Err(cursor.error(format!("expected `{}`", token)))
803 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700804 }
805
David Tolnay68274de2018-09-02 17:15:01 -0700806 pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
807 if let Some((ident, _rest)) = cursor.ident() {
808 ident == token
809 } else {
810 false
811 }
812 }
813
David Tolnay776f8e02018-08-24 22:32:10 -0400814 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
David Tolnay4398c922018-09-01 11:23:10 -0700815 let mut spans = [input.cursor().span(); 3];
816 punct_helper(input, token, &mut spans)?;
817 Ok(S::from_spans(&spans))
818 }
819
820 fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
David Tolnayb50c65a2018-08-30 21:14:57 -0700821 input.step(|cursor| {
David Tolnay776f8e02018-08-24 22:32:10 -0400822 let mut cursor = *cursor;
David Tolnay776f8e02018-08-24 22:32:10 -0400823 assert!(token.len() <= spans.len());
824
825 for (i, ch) in token.chars().enumerate() {
826 match cursor.punct() {
827 Some((punct, rest)) => {
828 spans[i] = punct.span();
829 if punct.as_char() != ch {
830 break;
831 } else if i == token.len() - 1 {
David Tolnay4398c922018-09-01 11:23:10 -0700832 return Ok(((), rest));
David Tolnay776f8e02018-08-24 22:32:10 -0400833 } else if punct.spacing() != Spacing::Joint {
834 break;
835 }
836 cursor = rest;
837 }
838 None => break,
839 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400840 }
David Tolnay776f8e02018-08-24 22:32:10 -0400841
842 Err(Error::new(spans[0], format!("expected `{}`", token)))
843 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700844 }
David Tolnay68274de2018-09-02 17:15:01 -0700845
846 pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
847 for (i, ch) in token.chars().enumerate() {
848 match cursor.punct() {
849 Some((punct, rest)) => {
850 if punct.as_char() != ch {
851 break;
852 } else if i == token.len() - 1 {
853 return true;
854 } else if punct.spacing() != Spacing::Joint {
855 break;
856 }
857 cursor = rest;
858 }
859 None => break,
860 }
861 }
862 false
863 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700864}
865
866#[cfg(feature = "printing")]
867mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700868 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700869 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700870
Alex Crichtona74a1c82018-05-16 10:20:44 -0700871 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700872 assert_eq!(s.len(), spans.len());
873
874 let mut chars = s.chars();
875 let mut spans = spans.iter();
876 let ch = chars.next_back().unwrap();
877 let span = spans.next_back().unwrap();
878 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700879 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700880 op.set_span(*span);
881 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700882 }
883
Alex Crichtona74a1c82018-05-16 10:20:44 -0700884 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700885 op.set_span(*span);
886 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700887 }
888
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800889 pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
890 tokens.append(Ident::new(s, span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700891 }
892
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800893 pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500894 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700895 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700896 {
David Tolnay00ab6982017-12-31 18:15:06 -0500897 let delim = match s {
898 "(" => Delimiter::Parenthesis,
899 "[" => Delimiter::Bracket,
900 "{" => Delimiter::Brace,
901 " " => Delimiter::None,
902 _ => panic!("unknown delimiter: {}", s),
903 };
hcplaa511792018-05-29 07:13:01 +0300904 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500905 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700906 let mut g = Group::new(delim, inner);
David Tolnay7f7eb0e2018-11-21 01:03:47 -0800907 g.set_span(span);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700908 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700909 }
910}