blob: f656e103c4fdb5b9e8df85afdf3d47f582db3c40 [file] [log] [blame]
David Tolnay30a36002017-02-08 14:24:12 -08001//! Adapted from [`nom`](https://github.com/Geal/nom) by removing the
Michael Layzell760fd662017-05-31 22:46:05 -04002//! `IPResult::Incomplete` variant which:
David Tolnay30a36002017-02-08 14:24:12 -08003//!
4//! - we don't need,
5//! - is an unintuitive footgun when working with non-streaming use cases, and
6//! - more than doubles compilation time.
7//!
8//! ## Whitespace handling strategy
9//!
10//! As (sy)nom is a parser combinator library, the parsers provided here and
11//! that you implement yourself are all made up of successively more primitive
12//! parsers, eventually culminating in a small number of fundamental parsers
13//! that are implemented in Rust. Among these are `punct!` and `keyword!`.
14//!
15//! All synom fundamental parsers (those not combined out of other parsers)
16//! should be written to skip over leading whitespace in their input. This way,
17//! as long as every parser eventually boils down to some combination of
18//! fundamental parsers, we get correct whitespace handling at all levels for
19//! free.
20//!
21//! For our use case, this strategy is a huge improvement in usability,
22//! correctness, and compile time over nom's `ws!` strategy.
David Tolnayb5a7b142016-09-13 22:46:39 -070023
Michael Layzell5bde96f2017-01-24 17:59:21 -050024extern crate unicode_xid;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070025extern crate proc_macro2;
Michael Layzell5bde96f2017-01-24 17:59:21 -050026
Alex Crichtonccbb45d2017-05-23 10:58:24 -070027#[cfg(feature = "printing")]
28extern crate quote;
29
David Tolnay30a36002017-02-08 14:24:12 -080030#[doc(hidden)]
Alex Crichton954046c2017-05-30 21:49:42 -070031pub use proc_macro2::{TokenTree, TokenStream};
32
33use std::convert::From;
34use std::error::Error;
35use std::fmt;
36
37use proc_macro2::LexError;
Michael Layzell5bde96f2017-01-24 17:59:21 -050038
Alex Crichtonccbb45d2017-05-23 10:58:24 -070039#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080040#[doc(hidden)]
41pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050042
Alex Crichtonccbb45d2017-05-23 10:58:24 -070043pub mod delimited;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070044pub mod tokens;
45pub mod span;
Michael Layzell2a60e252017-05-31 21:36:47 -040046pub mod cursor;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070047
Michael Layzell760fd662017-05-31 22:46:05 -040048/// A cursor into a Vec<TokenTree>.
49///
50/// NOTE: This type is currently unnecessary, but will make future refactorings
51/// which change this type easier.
52pub type Cursor<'a> = &'a [TokenTree];
David Tolnayb5a7b142016-09-13 22:46:39 -070053
Michael Layzell760fd662017-05-31 22:46:05 -040054/// The result of a parser
55pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
56
57/// An error with a default error message.
58///
59/// NOTE: We should provide better error messages in the future.
60pub fn parse_error<O>() -> PResult<'static, O> {
Michael Layzellad763b72017-06-01 00:25:31 -040061 Err(ParseError(None))
David Tolnayf2222f02017-01-27 17:09:20 -080062}
63
Alex Crichton7b9e02f2017-05-30 15:54:33 -070064pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040065 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070066
67 fn description() -> Option<&'static str> {
68 None
69 }
70
71 fn parse_all(input: TokenStream) -> Result<Self, ParseError> {
72 let tokens = input.into_iter().collect::<Vec<_>>();
Michael Layzellad763b72017-06-01 00:25:31 -040073 let result = Self::parse(&tokens);
74 let err = match result {
Michael Layzell760fd662017-05-31 22:46:05 -040075 Ok((rest, t)) => {
Alex Crichton954046c2017-05-30 21:49:42 -070076 if rest.is_empty() {
77 return Ok(t)
78 } else if rest.len() == tokens.len() {
79 // parsed nothing
80 "failed to parse"
81 } else {
82 "unparsed tokens after"
83 }
84 }
Michael Layzellad763b72017-06-01 00:25:31 -040085 Err(ref err) => err.description(),
Alex Crichton954046c2017-05-30 21:49:42 -070086 };
87 match Self::description() {
Michael Layzellad763b72017-06-01 00:25:31 -040088 Some(s) => Err(ParseError(Some(format!("{} {}", err, s)))),
89 None => Err(ParseError(Some(err.to_string()))),
Alex Crichton954046c2017-05-30 21:49:42 -070090 }
91 }
92
93 fn parse_str_all(input: &str) -> Result<Self, ParseError> {
94 Self::parse_all(input.parse()?)
95 }
96
97 fn parse_all_unwrap(input: TokenStream) -> Self {
98 // TODO: eventually try to provide super nice error messages here as
99 // this is what most users will hit. Hopefully the compiler will give us
100 // an interface one day to give an extra-good error message here.
101 Self::parse_all(input).unwrap()
102 }
103}
104
105#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -0400106pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -0700107
108impl Error for ParseError {
109 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -0400110 match self.0 {
111 Some(ref desc) => desc,
112 None => "failed to parse",
113 }
Alex Crichton954046c2017-05-30 21:49:42 -0700114 }
115}
116
117impl fmt::Display for ParseError {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -0400119 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -0700120 }
121}
122
123impl From<LexError> for ParseError {
124 fn from(_: LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -0400125 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -0700126 }
127}
128
129impl Synom for TokenStream {
Michael Layzell760fd662017-05-31 22:46:05 -0400130 fn parse(input: &[TokenTree]) -> PResult<Self> {
131 Ok((&[], input.iter().cloned().collect()))
Alex Crichton954046c2017-05-30 21:49:42 -0700132 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700133}
134
Michael Layzell24645a32017-02-04 13:19:26 -0500135/// Define a function from a parser combination.
136///
David Tolnay1f16b602017-02-07 20:06:55 -0500137/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
138///
139/// ```rust
140/// # extern crate syn;
141/// # #[macro_use] extern crate synom;
142/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700143/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700144/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500145/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700146/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
147/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500148/// );
149/// # fn main() {}
150/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500151#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700152macro_rules! named {
153 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400154 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700155 $submac!(i, $($args)*)
156 }
157 };
158
159 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400160 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700161 $submac!(i, $($args)*)
162 }
163 };
164}
165
David Tolnay1f16b602017-02-07 20:06:55 -0500166/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500167///
168/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500169///
Michael Layzell760fd662017-05-31 22:46:05 -0400170/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500171/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500172#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700173macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700174 ($i:expr, $fun:expr $(, $args:expr)*) => {
175 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700176 };
177}
178
David Tolnay1f16b602017-02-07 20:06:55 -0500179/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500180///
David Tolnay1f16b602017-02-07 20:06:55 -0500181/// - **Syntax:** `map!(THING, FN)`
182/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500183///
184/// ```rust
185/// extern crate syn;
186/// #[macro_use] extern crate synom;
187///
188/// use syn::{Item, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500189///
190/// fn get_item_ident(item: Item) -> Ident {
191/// item.ident
192/// }
193///
David Tolnay1f16b602017-02-07 20:06:55 -0500194/// // Parses an item and returns the name (identifier) of the item only.
195/// named!(item_ident -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700196/// map!(syn!(Item), get_item_ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500197/// );
198///
199/// // Or equivalently:
200/// named!(item_ident2 -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700201/// map!(syn!(Item), |i: Item| i.ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500202/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500203///
Alex Crichton954046c2017-05-30 21:49:42 -0700204/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500205/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500206#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700207macro_rules! map {
208 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700209 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400210 ::std::result::Result::Err(err) =>
211 ::std::result::Result::Err(err),
212 ::std::result::Result::Ok((i, o)) =>
213 ::std::result::Result::Ok((i, call!(o, $g))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700214 }
215 };
David Tolnay1f16b602017-02-07 20:06:55 -0500216
217 ($i:expr, $f:expr, $g:expr) => {
218 map!($i, call!($f), $g)
219 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700220}
221
David Tolnay1f16b602017-02-07 20:06:55 -0500222/// Parses successfully if the given parser fails to parse. Does not consume any
223/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500224///
225/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500226/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500227#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700228macro_rules! not {
229 ($i:expr, $submac:ident!( $($args:tt)* )) => {
230 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400231 ::std::result::Result::Ok(_) => $crate::parse_error(),
232 ::std::result::Result::Err(_) =>
233 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700234 }
235 };
236}
237
David Tolnay1f16b602017-02-07 20:06:55 -0500238/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500239///
David Tolnay1f16b602017-02-07 20:06:55 -0500240/// If you are familiar with nom, this is nom's `cond_with_error` parser.
241///
242/// - **Syntax:** `cond!(CONDITION, THING)`
243/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500244#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700245macro_rules! cond {
246 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
247 if $cond {
248 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400249 ::std::result::Result::Ok((i, o)) =>
250 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
251 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700252 }
253 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400254 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700255 }
David Tolnaycfe55022016-10-02 22:02:27 -0700256 };
257
258 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700259 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700260 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700261}
262
David Tolnay1f16b602017-02-07 20:06:55 -0500263/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500264///
David Tolnay1f16b602017-02-07 20:06:55 -0500265/// This is typically used inside of `option!` or `alt!`.
266///
267/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
268/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500269#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700270macro_rules! cond_reduce {
271 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
272 if $cond {
273 $submac!($i, $($args)*)
274 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400275 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700276 }
277 };
278
279 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700280 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700281 };
282}
283
David Tolnay1f16b602017-02-07 20:06:55 -0500284/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500285///
David Tolnay1f16b602017-02-07 20:06:55 -0500286/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500287/// - **Output:** `THING`
288///
289/// ```rust
290/// extern crate syn;
291/// #[macro_use] extern crate synom;
292///
293/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700294/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500295///
296/// // An expression terminated by ##.
297/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700298/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500299/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500300///
Alex Crichton954046c2017-05-30 21:49:42 -0700301/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500302/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500303#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700304macro_rules! terminated {
305 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
306 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400307 ::std::result::Result::Ok((i, (o, _))) =>
308 ::std::result::Result::Ok((i, o)),
309 ::std::result::Result::Err(err) =>
310 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700311 }
312 };
313
314 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700315 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700316 };
317
318 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700319 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700320 };
321
322 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700323 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700324 };
325}
326
David Tolnay1f16b602017-02-07 20:06:55 -0500327/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500328///
329/// - **Syntax:** `many0!(THING)`
330/// - **Output:** `Vec<THING>`
331///
David Tolnay1f16b602017-02-07 20:06:55 -0500332/// You may also be looking for:
333///
Alex Crichton954046c2017-05-30 21:49:42 -0700334/// - `call!(Delimited::parse_separated)` - zero or more values with separator
335/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
336/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500337///
Michael Layzell24645a32017-02-04 13:19:26 -0500338/// ```rust
339/// extern crate syn;
340/// #[macro_use] extern crate synom;
341///
342/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500343///
Alex Crichton954046c2017-05-30 21:49:42 -0700344/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500345///
Alex Crichton954046c2017-05-30 21:49:42 -0700346/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500347#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700348macro_rules! many0 {
349 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
350 let ret;
351 let mut res = ::std::vec::Vec::new();
352 let mut input = $i;
353
354 loop {
355 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400356 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700357 break;
358 }
359
360 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400361 ::std::result::Result::Err(_) => {
362 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700363 break;
364 }
Michael Layzell760fd662017-05-31 22:46:05 -0400365 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700366 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700367 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400368 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700369 break;
370 }
371
372 res.push(o);
373 input = i;
374 }
375 }
376 }
377
378 ret
379 }};
380
381 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500382 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700383 };
384}
385
David Tolnay1f16b602017-02-07 20:06:55 -0500386// Improve compile time by compiling this loop only once per type it is used
387// with.
388//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800389// Not public API.
390#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400391pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700392 let mut res = Vec::new();
393
394 loop {
395 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400396 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700397 }
398
399 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400400 Err(_) => {
401 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700402 }
Michael Layzell760fd662017-05-31 22:46:05 -0400403 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700404 // loop trip must always consume (otherwise infinite loops)
405 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400406 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700407 }
408
409 res.push(o);
410 input = i;
411 }
412 }
413 }
414}
415
David Tolnay1f16b602017-02-07 20:06:55 -0500416/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500417///
418/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500419/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500420///
421/// ```rust
422/// extern crate syn;
423/// #[macro_use] extern crate synom;
424///
Alex Crichton954046c2017-05-30 21:49:42 -0700425/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500426///
David Tolnay1f16b602017-02-07 20:06:55 -0500427/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700428/// named!(ident_expr -> (Ident, Expr),
429/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500430/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500431///
Alex Crichton954046c2017-05-30 21:49:42 -0700432/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500433/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500434#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700435macro_rules! peek {
436 ($i:expr, $submac:ident!( $($args:tt)* )) => {
437 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400438 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
439 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700440 }
441 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700442
David Tolnay1f16b602017-02-07 20:06:55 -0500443 ($i:expr, $f:expr) => {
444 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700445 };
446}
447
David Tolnay1f16b602017-02-07 20:06:55 -0500448/// Pattern-match the result of a parser to select which other parser to run.
449///
450/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
451/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
452///
453/// ```rust
454/// extern crate syn;
455/// #[macro_use] extern crate synom;
456///
457/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700458/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500459///
460/// #[derive(Debug)]
461/// enum UnitType {
462/// Struct {
463/// name: Ident,
464/// },
465/// Enum {
466/// name: Ident,
467/// variant: Ident,
468/// },
469/// }
470///
471/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
472/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700473/// which: alt!(
474/// syn!(Struct) => { |_| 0 }
475/// |
476/// syn!(Enum) => { |_| 1 }
477/// ) >>
478/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500479/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700480/// 0 => map!(
481/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500482/// move |_| UnitType::Struct {
483/// name: id,
484/// }
485/// )
486/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700487/// 1 => map!(
488/// braces!(syn!(Ident)),
489/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500490/// name: id,
491/// variant: variant,
492/// }
493/// )
494/// ) >>
495/// (item)
496/// ));
497///
Alex Crichton954046c2017-05-30 21:49:42 -0700498/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500499/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500500#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700501macro_rules! switch {
502 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
503 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400504 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
505 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700506 $(
507 $p => $subrule!(i, $($args2)*),
508 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400509 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700510 }
511 }
512 };
513}
514
Alex Crichton954046c2017-05-30 21:49:42 -0700515
David Tolnay1f16b602017-02-07 20:06:55 -0500516/// Produce the given value without parsing anything. Useful as an argument to
517/// `switch!`.
518///
519/// - **Syntax:** `value!(VALUE)`
520/// - **Output:** `VALUE`
521///
522/// ```rust
523/// extern crate syn;
524/// #[macro_use] extern crate synom;
525///
526/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700527/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500528///
529/// #[derive(Debug)]
530/// enum UnitType {
531/// Struct {
532/// name: Ident,
533/// },
534/// Enum {
535/// name: Ident,
536/// variant: Ident,
537/// },
538/// }
539///
540/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
541/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700542/// which: alt!(
543/// syn!(Struct) => { |_| 0 }
544/// |
545/// syn!(Enum) => { |_| 1 }
546/// ) >>
547/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500548/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700549/// 0 => map!(
550/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500551/// move |_| UnitType::Struct {
552/// name: id,
553/// }
554/// )
555/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700556/// 1 => map!(
557/// braces!(syn!(Ident)),
558/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500559/// name: id,
560/// variant: variant,
561/// }
562/// )
563/// ) >>
564/// (item)
565/// ));
566///
Alex Crichton954046c2017-05-30 21:49:42 -0700567/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500568/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500569#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700570macro_rules! value {
571 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400572 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700573 };
574}
575
David Tolnay1f16b602017-02-07 20:06:55 -0500576/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500577///
David Tolnay1f16b602017-02-07 20:06:55 -0500578/// - **Syntax:** `tuple!(A, B, C, ...)`
579/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500580///
581/// ```rust
582/// extern crate syn;
583/// #[macro_use] extern crate synom;
584///
585/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500586///
Alex Crichton954046c2017-05-30 21:49:42 -0700587/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500588///
Alex Crichton954046c2017-05-30 21:49:42 -0700589/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500590/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500591#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700592macro_rules! tuple {
593 ($i:expr, $($rest:tt)*) => {
594 tuple_parser!($i, (), $($rest)*)
595 };
596}
597
David Tolnay1f16b602017-02-07 20:06:55 -0500598/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500599#[doc(hidden)]
600#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700601macro_rules! tuple_parser {
602 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700603 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700604 };
605
606 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
607 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400608 ::std::result::Result::Err(err) =>
609 ::std::result::Result::Err(err),
610 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700611 tuple_parser!(i, (o), $($rest)*),
612 }
613 };
614
615 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
616 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400617 ::std::result::Result::Err(err) =>
618 ::std::result::Result::Err(err),
619 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700620 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
621 }
622 };
623
624 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700625 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700626 };
627
628 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
629 $submac!($i, $($args)*)
630 };
631
632 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
633 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400634 ::std::result::Result::Err(err) =>
635 ::std::result::Result::Err(err),
636 ::std::result::Result::Ok((i, o)) =>
637 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700638 }
639 };
640
641 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400642 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700643 };
644}
645
David Tolnay1f16b602017-02-07 20:06:55 -0500646/// Run a series of parsers, returning the result of the first one which
647/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500648///
649/// Optionally allows for the result to be transformed.
650///
651/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500652/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500653///
654/// ```rust
655/// extern crate syn;
656/// #[macro_use] extern crate synom;
657///
658/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700659/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500660///
661/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500662/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700663/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500664/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700665/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500666/// )
667/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500668///
Alex Crichton954046c2017-05-30 21:49:42 -0700669/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500670/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500671#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700672macro_rules! alt {
673 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700674 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700675 };
676
677 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
678 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400679 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700680 _ => alt!($i, $($rest)*)
681 }
682 };
683
684 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
685 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400686 ::std::result::Result::Ok((i, o)) =>
687 ::std::result::Result::Ok((i, $gen(o))),
688 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700689 }
690 };
691
692 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700693 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700694 };
695
696 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700697 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700698 };
699
700 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
701 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400702 ::std::result::Result::Ok((i, o)) =>
703 ::std::result::Result::Ok((i, $gen(o))),
704 ::std::result::Result::Err(err) =>
705 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700706 }
707 };
708
709 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700710 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700711 };
712
713 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700714 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700715 };
716}
717
Michael Layzell24645a32017-02-04 13:19:26 -0500718/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500719/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500720///
David Tolnay1f16b602017-02-07 20:06:55 -0500721/// Produces the result of evaluating the final expression in parentheses with
722/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500723///
David Tolnay1f16b602017-02-07 20:06:55 -0500724/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500725/// - **Output:** `RESULT`
726///
727/// ```rust
728/// extern crate syn;
729/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700730/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500731///
732/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700733/// use synom::tokens::{Bang, Paren};
734/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500735///
David Tolnay1f16b602017-02-07 20:06:55 -0500736/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700737/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
738/// name: syn!(Ident) >>
739/// syn!(Bang) >>
740/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500741/// (name, body)
742/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500743///
Alex Crichton954046c2017-05-30 21:49:42 -0700744/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500745/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500746#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700747macro_rules! do_parse {
748 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400749 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700750 };
751
752 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700753 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700754 };
755
756 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
757 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400758 ::std::result::Result::Err(err) =>
759 ::std::result::Result::Err(err),
760 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700761 do_parse!(i, $($rest)*),
762 }
763 };
764
765 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700766 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700767 };
768
769 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
770 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400771 ::std::result::Result::Err(err) =>
772 ::std::result::Result::Err(err),
773 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700774 let $field = o;
775 do_parse!(i, $($rest)*)
776 },
777 }
778 };
779
David Tolnayfa0edf22016-09-23 22:58:24 -0700780 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700781 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700782 };
783
784 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
785 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400786 ::std::result::Result::Err(err) =>
787 ::std::result::Result::Err(err),
788 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700789 let mut $field = o;
790 do_parse!(i, $($rest)*)
791 },
792 }
793 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700794}
Michael Layzell416724e2017-05-24 21:12:34 -0400795
796#[macro_export]
797macro_rules! input_end {
798 ($i:expr,) => {
799 $crate::input_end($i)
800 };
801}
802
803// Not a public API
804#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400805pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell416724e2017-05-24 21:12:34 -0400806 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400807 Ok((&[], ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400808 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400809 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400810 }
811}