blob: 29d777e5ce1619230870ca20ad333b984ce656e0 [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//! ```
24//! # #[macro_use]
25//! # extern crate syn;
26//! #
David Tolnaye303b7c2018-05-20 16:46:35 -070027//! # use syn::{Attribute, Visibility, Ident, Type, Expr};
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//!
47//! These tokens can be parsed using the [`Synom`] trait and the parser
48//! combinator macros [`punct!`], [`keyword!`], [`parens!`], [`braces!`], and
49//! [`brackets!`].
50//!
51//! [`Synom`]: ../synom/trait.Synom.html
52//! [`punct!`]: ../macro.punct.html
53//! [`keyword!`]: ../macro.keyword.html
54//! [`parens!`]: ../macro.parens.html
55//! [`braces!`]: ../macro.braces.html
56//! [`brackets!`]: ../macro.brackets.html
57//!
58//! ```
59//! #[macro_use]
60//! extern crate syn;
61//!
62//! use syn::synom::Synom;
David Tolnaye303b7c2018-05-20 16:46:35 -070063//! use syn::{Attribute, Visibility, Ident, Type, Expr};
David Tolnaye79ae182018-01-06 19:23:37 -080064//! #
65//! # struct ItemStatic;
66//! # use syn::ItemStatic as SynItemStatic;
67//!
68//! // Parse the ItemStatic struct shown above.
69//! impl Synom for ItemStatic {
70//! named!(parse -> Self, do_parse!(
71//! # (ItemStatic)
72//! # ));
73//! # }
74//! #
75//! # mod example {
76//! # use super::*;
77//! # use super::SynItemStatic as ItemStatic;
78//! #
79//! # named!(parse -> ItemStatic, do_parse!(
David Tolnayf8106f82018-08-25 21:17:45 -040080//! attrs: many0!(Attribute::old_parse_outer) >>
David Tolnaye79ae182018-01-06 19:23:37 -080081//! vis: syn!(Visibility) >>
82//! static_token: keyword!(static) >>
83//! mutability: option!(keyword!(mut)) >>
84//! ident: syn!(Ident) >>
85//! colon_token: punct!(:) >>
86//! ty: syn!(Type) >>
87//! eq_token: punct!(=) >>
88//! expr: syn!(Expr) >>
89//! semi_token: punct!(;) >>
90//! (ItemStatic {
91//! attrs, vis, static_token, mutability, ident, colon_token,
92//! ty: Box::new(ty), eq_token, expr: Box::new(expr), semi_token,
93//! })
94//! ));
95//! }
96//! #
97//! # fn main() {}
98//! ```
Alex Crichton954046c2017-05-30 21:49:42 -070099
David Tolnay776f8e02018-08-24 22:32:10 -0400100use std;
David Tolnayd9836922018-08-25 18:05:36 -0400101#[cfg(feature = "parsing")]
102use std::cell::Cell;
David Tolnay776f8e02018-08-24 22:32:10 -0400103#[cfg(feature = "extra-traits")]
104use std::cmp;
105#[cfg(feature = "extra-traits")]
106use std::fmt::{self, Debug};
107#[cfg(feature = "extra-traits")]
108use std::hash::{Hash, Hasher};
David Tolnayd9836922018-08-25 18:05:36 -0400109#[cfg(feature = "parsing")]
110use std::rc::Rc;
David Tolnay776f8e02018-08-24 22:32:10 -0400111
David Tolnay2d84a082018-08-25 16:31:38 -0400112#[cfg(feature = "parsing")]
113use proc_macro2::Delimiter;
David Tolnay8c39ac52018-08-25 08:46:21 -0400114#[cfg(any(feature = "printing", feature = "parsing"))]
115use proc_macro2::Spacing;
David Tolnay65fb5662018-05-20 20:02:28 -0700116use proc_macro2::{Ident, Span};
Sergio Benitezd14d5362018-04-28 15:38:25 -0700117#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400118use proc_macro2::{Punct, TokenStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400119#[cfg(feature = "printing")]
120use quote::{ToTokens, TokenStreamExt};
121
122#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400123use error::Result;
David Tolnaya465b2d2018-08-27 08:21:09 -0700124#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400125#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400126use lifetime::Lifetime;
David Tolnaya465b2d2018-08-27 08:21:09 -0700127#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400128#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400129use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
David Tolnay4fb71232018-08-25 23:14:50 -0400130#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400131use lookahead;
David Tolnay776f8e02018-08-24 22:32:10 -0400132#[cfg(feature = "parsing")]
David Tolnayd9836922018-08-25 18:05:36 -0400133use parse::{Lookahead1, Parse, ParseBuffer, ParseStream};
David Tolnay776f8e02018-08-24 22:32:10 -0400134use span::IntoSpans;
135
136/// Marker trait for types that represent single tokens.
137///
138/// This trait is sealed and cannot be implemented for types outside of Syn.
139#[cfg(feature = "parsing")]
140pub trait Token: private::Sealed {
141 // Not public API.
142 #[doc(hidden)]
143 fn peek(lookahead: &Lookahead1) -> bool;
144
145 // Not public API.
146 #[doc(hidden)]
147 fn display() -> String;
Sergio Benitezd14d5362018-04-28 15:38:25 -0700148}
149
150#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400151mod private {
152 pub trait Sealed {}
Sergio Benitezd14d5362018-04-28 15:38:25 -0700153}
154
David Tolnay776f8e02018-08-24 22:32:10 -0400155macro_rules! impl_token {
David Tolnay4fb71232018-08-25 23:14:50 -0400156 ($name:ident $display:expr) => {
David Tolnay776f8e02018-08-24 22:32:10 -0400157 #[cfg(feature = "parsing")]
158 impl Token for $name {
159 fn peek(lookahead: &Lookahead1) -> bool {
David Tolnayd9836922018-08-25 18:05:36 -0400160 // TODO factor out in a way that can be compiled just once
161 let scope = Span::call_site();
162 let cursor = lookahead.cursor();
163 let unexpected = Rc::new(Cell::new(None));
164 ParseBuffer::new(scope, cursor, unexpected)
165 .parse::<Self>()
166 .is_ok()
David Tolnay776f8e02018-08-24 22:32:10 -0400167 }
168
169 fn display() -> String {
David Tolnay4fb71232018-08-25 23:14:50 -0400170 $display.to_owned()
David Tolnay776f8e02018-08-24 22:32:10 -0400171 }
172 }
173
174 #[cfg(feature = "parsing")]
175 impl private::Sealed for $name {}
176 };
177}
178
David Tolnay4fb71232018-08-25 23:14:50 -0400179impl_token!(Ident "identifier");
David Tolnaya465b2d2018-08-27 08:21:09 -0700180#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400181impl_token!(Lifetime "lifetime");
David Tolnaya465b2d2018-08-27 08:21:09 -0700182#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay4fb71232018-08-25 23:14:50 -0400183impl_token!(Lit "literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700184#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400185impl_token!(LitStr "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!(LitByteStr "byte string literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700188#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400189impl_token!(LitByte "byte literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700190#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400191impl_token!(LitChar "character literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700192#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400193impl_token!(LitInt "integer literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700194#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400195impl_token!(LitFloat "floating point literal");
David Tolnaya465b2d2018-08-27 08:21:09 -0700196#[cfg(any(feature = "full", feature = "derive"))]
David Tolnaya7d69fc2018-08-26 13:30:24 -0400197impl_token!(LitBool "boolean literal");
David Tolnay4fb71232018-08-25 23:14:50 -0400198
David Tolnay776f8e02018-08-24 22:32:10 -0400199macro_rules! define_keywords {
200 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
201 $(
202 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
203 #[$doc]
204 ///
205 /// Don't try to remember the name of this type -- use the [`Token!`]
206 /// macro instead.
207 ///
208 /// [`Token!`]: index.html
209 pub struct $name {
210 pub span: Span,
211 }
212
213 #[doc(hidden)]
214 #[allow(non_snake_case)]
215 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
216 $name {
217 span: span.into_spans()[0],
218 }
219 }
220
David Tolnay4fb71232018-08-25 23:14:50 -0400221 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400222
223 impl std::default::Default for $name {
224 fn default() -> Self {
225 $name(Span::call_site())
226 }
227 }
228
229 #[cfg(feature = "extra-traits")]
230 impl Debug for $name {
231 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232 f.write_str(stringify!($name))
233 }
234 }
235
236 #[cfg(feature = "extra-traits")]
237 impl cmp::Eq for $name {}
238
239 #[cfg(feature = "extra-traits")]
240 impl PartialEq for $name {
241 fn eq(&self, _other: &$name) -> bool {
242 true
243 }
244 }
245
246 #[cfg(feature = "extra-traits")]
247 impl Hash for $name {
248 fn hash<H: Hasher>(&self, _state: &mut H) {}
249 }
250
251 #[cfg(feature = "printing")]
252 impl ToTokens for $name {
253 fn to_tokens(&self, tokens: &mut TokenStream) {
254 printing::keyword($token, &self.span, tokens);
255 }
256 }
257
258 #[cfg(feature = "parsing")]
259 impl Parse for $name {
260 fn parse(input: ParseStream) -> Result<Self> {
261 parsing::keyword(input, $token).map($name)
262 }
263 }
264 )*
265 };
266}
267
268macro_rules! define_punctuation_structs {
269 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
270 $(
271 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
272 #[$doc]
273 ///
274 /// Don't try to remember the name of this type -- use the [`Token!`]
275 /// macro instead.
276 ///
277 /// [`Token!`]: index.html
278 pub struct $name {
279 pub spans: [Span; $len],
280 }
281
282 #[doc(hidden)]
283 #[allow(non_snake_case)]
284 pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
285 $name {
286 spans: spans.into_spans(),
287 }
288 }
289
David Tolnay4fb71232018-08-25 23:14:50 -0400290 impl_token!($name concat!("`", $token, "`"));
David Tolnay776f8e02018-08-24 22:32:10 -0400291
292 impl std::default::Default for $name {
293 fn default() -> Self {
294 $name([Span::call_site(); $len])
295 }
296 }
297
298 #[cfg(feature = "extra-traits")]
299 impl Debug for $name {
300 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
301 f.write_str(stringify!($name))
302 }
303 }
304
305 #[cfg(feature = "extra-traits")]
306 impl cmp::Eq for $name {}
307
308 #[cfg(feature = "extra-traits")]
309 impl PartialEq for $name {
310 fn eq(&self, _other: &$name) -> bool {
311 true
312 }
313 }
314
315 #[cfg(feature = "extra-traits")]
316 impl Hash for $name {
317 fn hash<H: Hasher>(&self, _state: &mut H) {}
318 }
319 )*
320 };
321}
322
323macro_rules! define_punctuation {
324 ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
325 $(
326 define_punctuation_structs! {
327 $token pub struct $name/$len #[$doc]
328 }
329
330 #[cfg(feature = "printing")]
331 impl ToTokens for $name {
332 fn to_tokens(&self, tokens: &mut TokenStream) {
333 printing::punct($token, &self.spans, tokens);
334 }
335 }
336
337 #[cfg(feature = "parsing")]
338 impl Parse for $name {
339 fn parse(input: ParseStream) -> Result<Self> {
340 parsing::punct(input, $token).map($name::<[Span; $len]>)
341 }
342 }
343 )*
344 };
345}
346
347macro_rules! define_delimiters {
348 ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
349 $(
350 #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
351 #[$doc]
352 pub struct $name {
353 pub span: Span,
354 }
355
356 #[doc(hidden)]
357 #[allow(non_snake_case)]
358 pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
359 $name {
360 span: span.into_spans()[0],
361 }
362 }
363
364 impl std::default::Default for $name {
365 fn default() -> Self {
366 $name(Span::call_site())
367 }
368 }
369
370 #[cfg(feature = "extra-traits")]
371 impl Debug for $name {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 f.write_str(stringify!($name))
374 }
375 }
376
377 #[cfg(feature = "extra-traits")]
378 impl cmp::Eq for $name {}
379
380 #[cfg(feature = "extra-traits")]
381 impl PartialEq for $name {
382 fn eq(&self, _other: &$name) -> bool {
383 true
384 }
385 }
386
387 #[cfg(feature = "extra-traits")]
388 impl Hash for $name {
389 fn hash<H: Hasher>(&self, _state: &mut H) {}
390 }
391
392 impl $name {
393 #[cfg(feature = "printing")]
394 pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
395 where
396 F: FnOnce(&mut TokenStream),
397 {
398 printing::delim($token, &self.span, tokens, f);
399 }
400
401 #[cfg(feature = "parsing")]
402 pub fn parse<F, R>(
403 tokens: $crate::buffer::Cursor,
404 f: F,
405 ) -> $crate::synom::PResult<($name, R)>
406 where
407 F: FnOnce($crate::buffer::Cursor) -> $crate::synom::PResult<R>,
408 {
409 parsing::delim($token, tokens, $name, f)
410 }
411 }
David Tolnay2d84a082018-08-25 16:31:38 -0400412
413 #[cfg(feature = "parsing")]
414 impl private::Sealed for $name {}
David Tolnay776f8e02018-08-24 22:32:10 -0400415 )*
416 };
417}
418
419define_punctuation_structs! {
420 "'" pub struct Apostrophe/1 /// `'`
421 "_" pub struct Underscore/1 /// `_`
Alex Crichton131308c2018-05-18 14:00:24 -0700422}
423
David Tolnayb2fc7ef2018-05-20 19:54:14 -0700424// Implement Clone anyway because it is required for cloning Lifetime.
425#[cfg(not(feature = "clone-impls"))]
426impl Clone for Apostrophe {
427 fn clone(&self) -> Self {
David Tolnay7ac699c2018-08-24 14:00:58 -0400428 Apostrophe(self.spans)
David Tolnayb2fc7ef2018-05-20 19:54:14 -0700429 }
430}
431
Alex Crichton131308c2018-05-18 14:00:24 -0700432#[cfg(feature = "printing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400433impl ToTokens for Apostrophe {
434 fn to_tokens(&self, tokens: &mut TokenStream) {
435 let mut token = Punct::new('\'', Spacing::Joint);
David Tolnay7ac699c2018-08-24 14:00:58 -0400436 token.set_span(self.spans[0]);
Alex Crichton131308c2018-05-18 14:00:24 -0700437 tokens.append(token);
438 }
439}
440
441#[cfg(feature = "parsing")]
David Tolnay776f8e02018-08-24 22:32:10 -0400442impl Parse for Apostrophe {
443 fn parse(input: ParseStream) -> Result<Self> {
444 input.step_cursor(|cursor| {
445 if let Some((punct, rest)) = cursor.punct() {
446 if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint {
447 return Ok((Apostrophe(punct.span()), rest));
Alex Crichton131308c2018-05-18 14:00:24 -0700448 }
449 }
David Tolnay776f8e02018-08-24 22:32:10 -0400450 Err(cursor.error("expected `'`"))
451 })
Alex Crichton131308c2018-05-18 14:00:24 -0700452 }
453}
454
David Tolnay776f8e02018-08-24 22:32:10 -0400455#[cfg(feature = "printing")]
456impl ToTokens for Underscore {
457 fn to_tokens(&self, tokens: &mut TokenStream) {
458 tokens.append(Ident::new("_", self.spans[0]));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700459 }
David Tolnay776f8e02018-08-24 22:32:10 -0400460}
461
462#[cfg(feature = "parsing")]
463impl Parse for Underscore {
464 fn parse(input: ParseStream) -> Result<Self> {
465 input.step_cursor(|cursor| {
466 if let Some((ident, rest)) = cursor.ident() {
467 if ident == "_" {
468 return Ok((Underscore(ident.span()), rest));
469 }
470 }
471 if let Some((punct, rest)) = cursor.punct() {
472 if punct.as_char() == '_' {
473 return Ok((Underscore(punct.span()), rest));
474 }
475 }
476 Err(cursor.error("expected `_`"))
477 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700478 }
David Tolnay776f8e02018-08-24 22:32:10 -0400479}
480
David Tolnay2d84a082018-08-25 16:31:38 -0400481#[cfg(feature = "parsing")]
482impl Token for Paren {
483 fn peek(lookahead: &Lookahead1) -> bool {
484 lookahead::is_delimiter(lookahead, Delimiter::Parenthesis)
485 }
486
487 fn display() -> String {
488 "parentheses".to_owned()
489 }
490}
491
492#[cfg(feature = "parsing")]
493impl Token for Brace {
494 fn peek(lookahead: &Lookahead1) -> bool {
495 lookahead::is_delimiter(lookahead, Delimiter::Brace)
496 }
497
498 fn display() -> String {
499 "curly braces".to_owned()
500 }
501}
502
503#[cfg(feature = "parsing")]
504impl Token for Bracket {
505 fn peek(lookahead: &Lookahead1) -> bool {
506 lookahead::is_delimiter(lookahead, Delimiter::Bracket)
507 }
508
509 fn display() -> String {
510 "square brackets".to_owned()
511 }
512}
513
David Tolnaya7d69fc2018-08-26 13:30:24 -0400514#[cfg(feature = "parsing")]
515impl Token for Group {
516 fn peek(lookahead: &Lookahead1) -> bool {
517 lookahead::is_delimiter(lookahead, Delimiter::None)
518 }
519
520 fn display() -> String {
521 "invisible group".to_owned()
522 }
523}
524
David Tolnay776f8e02018-08-24 22:32:10 -0400525define_keywords! {
526 "as" pub struct As /// `as`
527 "async" pub struct Async /// `async`
528 "auto" pub struct Auto /// `auto`
529 "box" pub struct Box /// `box`
530 "break" pub struct Break /// `break`
531 "Self" pub struct CapSelf /// `Self`
532 "const" pub struct Const /// `const`
533 "continue" pub struct Continue /// `continue`
534 "crate" pub struct Crate /// `crate`
535 "default" pub struct Default /// `default`
536 "dyn" pub struct Dyn /// `dyn`
537 "else" pub struct Else /// `else`
538 "enum" pub struct Enum /// `enum`
539 "existential" pub struct Existential /// `existential`
540 "extern" pub struct Extern /// `extern`
541 "fn" pub struct Fn /// `fn`
542 "for" pub struct For /// `for`
543 "if" pub struct If /// `if`
544 "impl" pub struct Impl /// `impl`
545 "in" pub struct In /// `in`
546 "let" pub struct Let /// `let`
547 "loop" pub struct Loop /// `loop`
548 "macro" pub struct Macro /// `macro`
549 "match" pub struct Match /// `match`
550 "mod" pub struct Mod /// `mod`
551 "move" pub struct Move /// `move`
552 "mut" pub struct Mut /// `mut`
553 "pub" pub struct Pub /// `pub`
554 "ref" pub struct Ref /// `ref`
555 "return" pub struct Return /// `return`
556 "self" pub struct Self_ /// `self`
557 "static" pub struct Static /// `static`
558 "struct" pub struct Struct /// `struct`
559 "super" pub struct Super /// `super`
560 "trait" pub struct Trait /// `trait`
561 "try" pub struct Try /// `try`
562 "type" pub struct Type /// `type`
563 "union" pub struct Union /// `union`
564 "unsafe" pub struct Unsafe /// `unsafe`
565 "use" pub struct Use /// `use`
566 "where" pub struct Where /// `where`
567 "while" pub struct While /// `while`
568 "yield" pub struct Yield /// `yield`
569}
570
571define_punctuation! {
572 "+" pub struct Add/1 /// `+`
573 "+=" pub struct AddEq/2 /// `+=`
574 "&" pub struct And/1 /// `&`
575 "&&" pub struct AndAnd/2 /// `&&`
576 "&=" pub struct AndEq/2 /// `&=`
577 "@" pub struct At/1 /// `@`
578 "!" pub struct Bang/1 /// `!`
579 "^" pub struct Caret/1 /// `^`
580 "^=" pub struct CaretEq/2 /// `^=`
581 ":" pub struct Colon/1 /// `:`
582 "::" pub struct Colon2/2 /// `::`
583 "," pub struct Comma/1 /// `,`
584 "/" pub struct Div/1 /// `/`
585 "/=" pub struct DivEq/2 /// `/=`
586 "$" pub struct Dollar/1 /// `$`
587 "." pub struct Dot/1 /// `.`
588 ".." pub struct Dot2/2 /// `..`
589 "..." pub struct Dot3/3 /// `...`
590 "..=" pub struct DotDotEq/3 /// `..=`
591 "=" pub struct Eq/1 /// `=`
592 "==" pub struct EqEq/2 /// `==`
593 ">=" pub struct Ge/2 /// `>=`
594 ">" pub struct Gt/1 /// `>`
595 "<=" pub struct Le/2 /// `<=`
596 "<" pub struct Lt/1 /// `<`
597 "*=" pub struct MulEq/2 /// `*=`
598 "!=" pub struct Ne/2 /// `!=`
599 "|" pub struct Or/1 /// `|`
600 "|=" pub struct OrEq/2 /// `|=`
601 "||" pub struct OrOr/2 /// `||`
602 "#" pub struct Pound/1 /// `#`
603 "?" pub struct Question/1 /// `?`
604 "->" pub struct RArrow/2 /// `->`
605 "<-" pub struct LArrow/2 /// `<-`
606 "%" pub struct Rem/1 /// `%`
607 "%=" pub struct RemEq/2 /// `%=`
608 "=>" pub struct FatArrow/2 /// `=>`
609 ";" pub struct Semi/1 /// `;`
610 "<<" pub struct Shl/2 /// `<<`
611 "<<=" pub struct ShlEq/3 /// `<<=`
612 ">>" pub struct Shr/2 /// `>>`
613 ">>=" pub struct ShrEq/3 /// `>>=`
614 "*" pub struct Star/1 /// `*`
615 "-" pub struct Sub/1 /// `-`
616 "-=" pub struct SubEq/2 /// `-=`
617}
618
619define_delimiters! {
620 "{" pub struct Brace /// `{...}`
621 "[" pub struct Bracket /// `[...]`
622 "(" pub struct Paren /// `(...)`
623 " " pub struct Group /// None-delimited group
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700624}
625
David Tolnayf005f962018-01-06 21:19:41 -0800626/// A type-macro that expands to the name of the Rust type representation of a
627/// given token.
628///
629/// See the [token module] documentation for details and examples.
630///
631/// [token module]: token/index.html
David Tolnayf8db7ba2017-11-11 22:52:16 -0800632// Unfortunate duplication due to a rustdoc bug.
633// https://github.com/rust-lang/rust/issues/45939
634#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700635#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800636macro_rules! Token {
David Tolnay776f8e02018-08-24 22:32:10 -0400637 (as) => { $crate::token::As };
638 (async) => { $crate::token::Async };
639 (auto) => { $crate::token::Auto };
640 (box) => { $crate::token::Box };
641 (break) => { $crate::token::Break };
642 (Self) => { $crate::token::CapSelf };
643 (const) => { $crate::token::Const };
644 (continue) => { $crate::token::Continue };
645 (crate) => { $crate::token::Crate };
646 (default) => { $crate::token::Default };
647 (dyn) => { $crate::token::Dyn };
648 (else) => { $crate::token::Else };
649 (enum) => { $crate::token::Enum };
650 (existential) => { $crate::token::Existential };
651 (extern) => { $crate::token::Extern };
652 (fn) => { $crate::token::Fn };
653 (for) => { $crate::token::For };
654 (if) => { $crate::token::If };
655 (impl) => { $crate::token::Impl };
656 (in) => { $crate::token::In };
657 (let) => { $crate::token::Let };
658 (loop) => { $crate::token::Loop };
659 (macro) => { $crate::token::Macro };
660 (match) => { $crate::token::Match };
661 (mod) => { $crate::token::Mod };
662 (move) => { $crate::token::Move };
663 (mut) => { $crate::token::Mut };
664 (pub) => { $crate::token::Pub };
665 (ref) => { $crate::token::Ref };
666 (return) => { $crate::token::Return };
667 (self) => { $crate::token::Self_ };
668 (static) => { $crate::token::Static };
669 (struct) => { $crate::token::Struct };
670 (super) => { $crate::token::Super };
671 (trait) => { $crate::token::Trait };
672 (try) => { $crate::token::Try };
673 (type) => { $crate::token::Type };
674 (union) => { $crate::token::Union };
675 (unsafe) => { $crate::token::Unsafe };
676 (use) => { $crate::token::Use };
677 (where) => { $crate::token::Where };
678 (while) => { $crate::token::While };
679 (yield) => { $crate::token::Yield };
David Tolnaybb82ef02018-08-24 20:15:45 -0400680 (+) => { $crate::token::Add };
681 (+=) => { $crate::token::AddEq };
682 (&) => { $crate::token::And };
683 (&&) => { $crate::token::AndAnd };
684 (&=) => { $crate::token::AndEq };
685 (@) => { $crate::token::At };
686 (!) => { $crate::token::Bang };
687 (^) => { $crate::token::Caret };
688 (^=) => { $crate::token::CaretEq };
689 (:) => { $crate::token::Colon };
690 (::) => { $crate::token::Colon2 };
691 (,) => { $crate::token::Comma };
692 (/) => { $crate::token::Div };
693 (/=) => { $crate::token::DivEq };
694 (.) => { $crate::token::Dot };
695 (..) => { $crate::token::Dot2 };
696 (...) => { $crate::token::Dot3 };
697 (..=) => { $crate::token::DotDotEq };
698 (=) => { $crate::token::Eq };
699 (==) => { $crate::token::EqEq };
700 (>=) => { $crate::token::Ge };
701 (>) => { $crate::token::Gt };
702 (<=) => { $crate::token::Le };
703 (<) => { $crate::token::Lt };
704 (*=) => { $crate::token::MulEq };
705 (!=) => { $crate::token::Ne };
706 (|) => { $crate::token::Or };
707 (|=) => { $crate::token::OrEq };
708 (||) => { $crate::token::OrOr };
709 (#) => { $crate::token::Pound };
710 (?) => { $crate::token::Question };
711 (->) => { $crate::token::RArrow };
712 (<-) => { $crate::token::LArrow };
713 (%) => { $crate::token::Rem };
714 (%=) => { $crate::token::RemEq };
715 (=>) => { $crate::token::FatArrow };
716 (;) => { $crate::token::Semi };
717 (<<) => { $crate::token::Shl };
718 (<<=) => { $crate::token::ShlEq };
719 (>>) => { $crate::token::Shr };
720 (>>=) => { $crate::token::ShrEq };
721 (*) => { $crate::token::Star };
722 (-) => { $crate::token::Sub };
723 (-=) => { $crate::token::SubEq };
724 (_) => { $crate::token::Underscore };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800725}
726
David Tolnayf005f962018-01-06 21:19:41 -0800727/// Parse a single Rust punctuation token.
728///
729/// See the [token module] documentation for details and examples.
730///
731/// [token module]: token/index.html
David Tolnay461d98e2018-01-07 11:07:19 -0800732///
733/// *This macro is available if Syn is built with the `"parsing"` feature.*
David Tolnay0fbe3282017-12-26 21:46:16 -0500734#[cfg(feature = "parsing")]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800735#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700736#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800737macro_rules! punct {
David Tolnay32954ef2017-12-26 22:43:16 -0500738 ($i:expr, +) => { call!($i, <$crate::token::Add as $crate::synom::Synom>::parse) };
739 ($i:expr, +=) => { call!($i, <$crate::token::AddEq as $crate::synom::Synom>::parse) };
740 ($i:expr, &) => { call!($i, <$crate::token::And as $crate::synom::Synom>::parse) };
741 ($i:expr, &&) => { call!($i, <$crate::token::AndAnd as $crate::synom::Synom>::parse) };
742 ($i:expr, &=) => { call!($i, <$crate::token::AndEq as $crate::synom::Synom>::parse) };
743 ($i:expr, @) => { call!($i, <$crate::token::At as $crate::synom::Synom>::parse) };
744 ($i:expr, !) => { call!($i, <$crate::token::Bang as $crate::synom::Synom>::parse) };
745 ($i:expr, ^) => { call!($i, <$crate::token::Caret as $crate::synom::Synom>::parse) };
746 ($i:expr, ^=) => { call!($i, <$crate::token::CaretEq as $crate::synom::Synom>::parse) };
747 ($i:expr, :) => { call!($i, <$crate::token::Colon as $crate::synom::Synom>::parse) };
748 ($i:expr, ::) => { call!($i, <$crate::token::Colon2 as $crate::synom::Synom>::parse) };
749 ($i:expr, ,) => { call!($i, <$crate::token::Comma as $crate::synom::Synom>::parse) };
750 ($i:expr, /) => { call!($i, <$crate::token::Div as $crate::synom::Synom>::parse) };
751 ($i:expr, /=) => { call!($i, <$crate::token::DivEq as $crate::synom::Synom>::parse) };
752 ($i:expr, .) => { call!($i, <$crate::token::Dot as $crate::synom::Synom>::parse) };
753 ($i:expr, ..) => { call!($i, <$crate::token::Dot2 as $crate::synom::Synom>::parse) };
754 ($i:expr, ...) => { call!($i, <$crate::token::Dot3 as $crate::synom::Synom>::parse) };
755 ($i:expr, ..=) => { call!($i, <$crate::token::DotDotEq as $crate::synom::Synom>::parse) };
756 ($i:expr, =) => { call!($i, <$crate::token::Eq as $crate::synom::Synom>::parse) };
757 ($i:expr, ==) => { call!($i, <$crate::token::EqEq as $crate::synom::Synom>::parse) };
758 ($i:expr, >=) => { call!($i, <$crate::token::Ge as $crate::synom::Synom>::parse) };
759 ($i:expr, >) => { call!($i, <$crate::token::Gt as $crate::synom::Synom>::parse) };
760 ($i:expr, <=) => { call!($i, <$crate::token::Le as $crate::synom::Synom>::parse) };
761 ($i:expr, <) => { call!($i, <$crate::token::Lt as $crate::synom::Synom>::parse) };
762 ($i:expr, *=) => { call!($i, <$crate::token::MulEq as $crate::synom::Synom>::parse) };
763 ($i:expr, !=) => { call!($i, <$crate::token::Ne as $crate::synom::Synom>::parse) };
764 ($i:expr, |) => { call!($i, <$crate::token::Or as $crate::synom::Synom>::parse) };
765 ($i:expr, |=) => { call!($i, <$crate::token::OrEq as $crate::synom::Synom>::parse) };
766 ($i:expr, ||) => { call!($i, <$crate::token::OrOr as $crate::synom::Synom>::parse) };
767 ($i:expr, #) => { call!($i, <$crate::token::Pound as $crate::synom::Synom>::parse) };
768 ($i:expr, ?) => { call!($i, <$crate::token::Question as $crate::synom::Synom>::parse) };
769 ($i:expr, ->) => { call!($i, <$crate::token::RArrow as $crate::synom::Synom>::parse) };
770 ($i:expr, <-) => { call!($i, <$crate::token::LArrow as $crate::synom::Synom>::parse) };
771 ($i:expr, %) => { call!($i, <$crate::token::Rem as $crate::synom::Synom>::parse) };
772 ($i:expr, %=) => { call!($i, <$crate::token::RemEq as $crate::synom::Synom>::parse) };
David Tolnay17624152018-03-31 18:11:40 +0200773 ($i:expr, =>) => { call!($i, <$crate::token::FatArrow as $crate::synom::Synom>::parse) };
David Tolnay32954ef2017-12-26 22:43:16 -0500774 ($i:expr, ;) => { call!($i, <$crate::token::Semi as $crate::synom::Synom>::parse) };
775 ($i:expr, <<) => { call!($i, <$crate::token::Shl as $crate::synom::Synom>::parse) };
776 ($i:expr, <<=) => { call!($i, <$crate::token::ShlEq as $crate::synom::Synom>::parse) };
777 ($i:expr, >>) => { call!($i, <$crate::token::Shr as $crate::synom::Synom>::parse) };
778 ($i:expr, >>=) => { call!($i, <$crate::token::ShrEq as $crate::synom::Synom>::parse) };
779 ($i:expr, *) => { call!($i, <$crate::token::Star as $crate::synom::Synom>::parse) };
780 ($i:expr, -) => { call!($i, <$crate::token::Sub as $crate::synom::Synom>::parse) };
781 ($i:expr, -=) => { call!($i, <$crate::token::SubEq as $crate::synom::Synom>::parse) };
782 ($i:expr, _) => { call!($i, <$crate::token::Underscore as $crate::synom::Synom>::parse) };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800783}
784
David Tolnayf005f962018-01-06 21:19:41 -0800785/// Parse a single Rust keyword token.
786///
787/// See the [token module] documentation for details and examples.
788///
789/// [token module]: token/index.html
David Tolnay461d98e2018-01-07 11:07:19 -0800790///
791/// *This macro is available if Syn is built with the `"parsing"` feature.*
David Tolnay0fbe3282017-12-26 21:46:16 -0500792#[cfg(feature = "parsing")]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800793#[macro_export]
David Tolnaya5ed2fe2018-04-29 12:23:34 -0700794#[cfg_attr(rustfmt, rustfmt_skip)]
David Tolnayf8db7ba2017-11-11 22:52:16 -0800795macro_rules! keyword {
David Tolnaybb82ef02018-08-24 20:15:45 -0400796 ($i:expr, as) => { call!($i, <$crate::token::As as $crate::synom::Synom>::parse) };
797 ($i:expr, async) => { call!($i, <$crate::token::Async as $crate::synom::Synom>::parse) };
798 ($i:expr, auto) => { call!($i, <$crate::token::Auto as $crate::synom::Synom>::parse) };
799 ($i:expr, box) => { call!($i, <$crate::token::Box as $crate::synom::Synom>::parse) };
800 ($i:expr, break) => { call!($i, <$crate::token::Break as $crate::synom::Synom>::parse) };
801 ($i:expr, Self) => { call!($i, <$crate::token::CapSelf as $crate::synom::Synom>::parse) };
802 ($i:expr, const) => { call!($i, <$crate::token::Const as $crate::synom::Synom>::parse) };
803 ($i:expr, continue) => { call!($i, <$crate::token::Continue as $crate::synom::Synom>::parse) };
804 ($i:expr, crate) => { call!($i, <$crate::token::Crate as $crate::synom::Synom>::parse) };
805 ($i:expr, default) => { call!($i, <$crate::token::Default as $crate::synom::Synom>::parse) };
806 ($i:expr, dyn) => { call!($i, <$crate::token::Dyn as $crate::synom::Synom>::parse) };
807 ($i:expr, else) => { call!($i, <$crate::token::Else as $crate::synom::Synom>::parse) };
808 ($i:expr, enum) => { call!($i, <$crate::token::Enum as $crate::synom::Synom>::parse) };
809 ($i:expr, extern) => { call!($i, <$crate::token::Extern as $crate::synom::Synom>::parse) };
810 ($i:expr, existential) => { call!($i, <$crate::token::Existential as $crate::synom::Synom>::parse) };
811 ($i:expr, fn) => { call!($i, <$crate::token::Fn as $crate::synom::Synom>::parse) };
812 ($i:expr, for) => { call!($i, <$crate::token::For as $crate::synom::Synom>::parse) };
813 ($i:expr, if) => { call!($i, <$crate::token::If as $crate::synom::Synom>::parse) };
814 ($i:expr, impl) => { call!($i, <$crate::token::Impl as $crate::synom::Synom>::parse) };
815 ($i:expr, in) => { call!($i, <$crate::token::In as $crate::synom::Synom>::parse) };
816 ($i:expr, let) => { call!($i, <$crate::token::Let as $crate::synom::Synom>::parse) };
817 ($i:expr, loop) => { call!($i, <$crate::token::Loop as $crate::synom::Synom>::parse) };
818 ($i:expr, macro) => { call!($i, <$crate::token::Macro as $crate::synom::Synom>::parse) };
819 ($i:expr, match) => { call!($i, <$crate::token::Match as $crate::synom::Synom>::parse) };
820 ($i:expr, mod) => { call!($i, <$crate::token::Mod as $crate::synom::Synom>::parse) };
821 ($i:expr, move) => { call!($i, <$crate::token::Move as $crate::synom::Synom>::parse) };
822 ($i:expr, mut) => { call!($i, <$crate::token::Mut as $crate::synom::Synom>::parse) };
823 ($i:expr, pub) => { call!($i, <$crate::token::Pub as $crate::synom::Synom>::parse) };
824 ($i:expr, ref) => { call!($i, <$crate::token::Ref as $crate::synom::Synom>::parse) };
825 ($i:expr, return) => { call!($i, <$crate::token::Return as $crate::synom::Synom>::parse) };
826 ($i:expr, self) => { call!($i, <$crate::token::Self_ as $crate::synom::Synom>::parse) };
827 ($i:expr, static) => { call!($i, <$crate::token::Static as $crate::synom::Synom>::parse) };
828 ($i:expr, struct) => { call!($i, <$crate::token::Struct as $crate::synom::Synom>::parse) };
829 ($i:expr, super) => { call!($i, <$crate::token::Super as $crate::synom::Synom>::parse) };
830 ($i:expr, trait) => { call!($i, <$crate::token::Trait as $crate::synom::Synom>::parse) };
831 ($i:expr, try) => { call!($i, <$crate::token::Try as $crate::synom::Synom>::parse) };
832 ($i:expr, type) => { call!($i, <$crate::token::Type as $crate::synom::Synom>::parse) };
833 ($i:expr, union) => { call!($i, <$crate::token::Union as $crate::synom::Synom>::parse) };
834 ($i:expr, unsafe) => { call!($i, <$crate::token::Unsafe as $crate::synom::Synom>::parse) };
835 ($i:expr, use) => { call!($i, <$crate::token::Use as $crate::synom::Synom>::parse) };
836 ($i:expr, where) => { call!($i, <$crate::token::Where as $crate::synom::Synom>::parse) };
837 ($i:expr, while) => { call!($i, <$crate::token::While as $crate::synom::Synom>::parse) };
838 ($i:expr, yield) => { call!($i, <$crate::token::Yield as $crate::synom::Synom>::parse) };
David Tolnayf8db7ba2017-11-11 22:52:16 -0800839}
840
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700841macro_rules! ident_from_token {
842 ($token:ident) => {
843 impl From<Token![$token]> for Ident {
844 fn from(token: Token![$token]) -> Ident {
David Tolnay7ac699c2018-08-24 14:00:58 -0400845 Ident::new(stringify!($token), token.span)
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700846 }
847 }
848 };
849}
850
851ident_from_token!(self);
852ident_from_token!(Self);
853ident_from_token!(super);
854ident_from_token!(crate);
David Tolnay0a4d4e92018-07-21 15:31:45 -0700855ident_from_token!(extern);
David Tolnaybd0bc3e2018-05-20 17:15:35 -0700856
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700857#[cfg(feature = "parsing")]
858mod parsing {
David Tolnay51382052017-12-27 13:46:21 -0500859 use proc_macro2::{Delimiter, Spacing, Span};
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700860
David Tolnaydfc886b2018-01-06 08:03:09 -0800861 use buffer::Cursor;
David Tolnayad4b2472018-08-25 08:25:24 -0400862 use error::{Error, Result};
David Tolnayb6254182018-08-25 08:44:54 -0400863 use parse::ParseStream;
David Tolnay203557a2017-12-27 23:59:33 -0500864 use parse_error;
David Tolnay776f8e02018-08-24 22:32:10 -0400865 use span::FromSpans;
David Tolnay203557a2017-12-27 23:59:33 -0500866 use synom::PResult;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700867
David Tolnay776f8e02018-08-24 22:32:10 -0400868 pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
869 input.step_cursor(|cursor| {
870 if let Some((ident, rest)) = cursor.ident() {
871 if ident == token {
872 return Ok((ident.span(), rest));
Alex Crichton954046c2017-05-30 21:49:42 -0700873 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700874 }
David Tolnay776f8e02018-08-24 22:32:10 -0400875 Err(cursor.error(format!("expected `{}`", token)))
876 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700877 }
878
David Tolnay776f8e02018-08-24 22:32:10 -0400879 pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
880 input.step_cursor(|cursor| {
881 let mut cursor = *cursor;
882 let mut spans = [cursor.span(); 3];
883 assert!(token.len() <= spans.len());
884
885 for (i, ch) in token.chars().enumerate() {
886 match cursor.punct() {
887 Some((punct, rest)) => {
888 spans[i] = punct.span();
889 if punct.as_char() != ch {
890 break;
891 } else if i == token.len() - 1 {
892 return Ok((S::from_spans(&spans), rest));
893 } else if punct.spacing() != Spacing::Joint {
894 break;
895 }
896 cursor = rest;
897 }
898 None => break,
899 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400900 }
David Tolnay776f8e02018-08-24 22:32:10 -0400901
902 Err(Error::new(spans[0], format!("expected `{}`", token)))
903 })
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700904 }
905
David Tolnay51382052017-12-27 13:46:21 -0500906 pub fn delim<'a, F, R, T>(
907 delim: &str,
908 tokens: Cursor<'a>,
David Tolnay2b069542018-05-09 12:59:36 -0700909 new: fn(Span) -> T,
David Tolnay51382052017-12-27 13:46:21 -0500910 f: F,
David Tolnay8875fca2017-12-31 13:52:37 -0500911 ) -> PResult<'a, (T, R)>
David Tolnay51382052017-12-27 13:46:21 -0500912 where
913 F: FnOnce(Cursor) -> PResult<R>,
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700914 {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400915 // NOTE: We should support none-delimited sequences here.
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700916 let delim = match delim {
917 "(" => Delimiter::Parenthesis,
918 "{" => Delimiter::Brace,
919 "[" => Delimiter::Bracket,
Michael Layzell93c36282017-06-04 20:43:14 -0400920 " " => Delimiter::None,
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700921 _ => panic!("unknown delimiter: {}", delim),
922 };
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700923
David Tolnay65729482017-12-31 16:14:50 -0500924 if let Some((inside, span, rest)) = tokens.group(delim) {
925 match f(inside) {
David Tolnayf4aa6b42017-12-31 16:40:33 -0500926 Ok((ret, remaining)) => {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400927 if remaining.eof() {
David Tolnay2b069542018-05-09 12:59:36 -0700928 return Ok(((new(span), ret), rest));
Michael Layzell0a1a6632017-06-02 18:07:43 -0400929 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700930 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400931 Err(err) => return Err(err),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700932 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700933 }
Michael Layzell0a1a6632017-06-02 18:07:43 -0400934 parse_error()
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700935 }
936}
937
938#[cfg(feature = "printing")]
939mod printing {
David Tolnay65fb5662018-05-20 20:02:28 -0700940 use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
Alex Crichtona74a1c82018-05-16 10:20:44 -0700941 use quote::TokenStreamExt;
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700942
Alex Crichtona74a1c82018-05-16 10:20:44 -0700943 pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700944 assert_eq!(s.len(), spans.len());
945
946 let mut chars = s.chars();
947 let mut spans = spans.iter();
948 let ch = chars.next_back().unwrap();
949 let span = spans.next_back().unwrap();
950 for (ch, span) in chars.zip(spans) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700951 let mut op = Punct::new(ch, Spacing::Joint);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700952 op.set_span(*span);
953 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700954 }
955
Alex Crichtona74a1c82018-05-16 10:20:44 -0700956 let mut op = Punct::new(ch, Spacing::Alone);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700957 op.set_span(*span);
958 tokens.append(op);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700959 }
960
Alex Crichtona74a1c82018-05-16 10:20:44 -0700961 pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
962 tokens.append(Ident::new(s, *span));
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700963 }
964
Alex Crichtona74a1c82018-05-16 10:20:44 -0700965 pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
David Tolnay51382052017-12-27 13:46:21 -0500966 where
Alex Crichtona74a1c82018-05-16 10:20:44 -0700967 F: FnOnce(&mut TokenStream),
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700968 {
David Tolnay00ab6982017-12-31 18:15:06 -0500969 let delim = match s {
970 "(" => Delimiter::Parenthesis,
971 "[" => Delimiter::Bracket,
972 "{" => Delimiter::Brace,
973 " " => Delimiter::None,
974 _ => panic!("unknown delimiter: {}", s),
975 };
hcplaa511792018-05-29 07:13:01 +0300976 let mut inner = TokenStream::new();
David Tolnay00ab6982017-12-31 18:15:06 -0500977 f(&mut inner);
David Tolnay106db5e2018-05-20 19:56:38 -0700978 let mut g = Group::new(delim, inner);
Alex Crichton9a4dca22018-03-28 06:32:19 -0700979 g.set_span(*span);
980 tokens.append(g);
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700981 }
982}