blob: e257b5d540a94e6a4d9edbaf99290dab047c2697 [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 Layzell0a1a6632017-06-02 18:07:43 -040048pub use cursor::{SynomBuffer, Cursor};
David Tolnayb5a7b142016-09-13 22:46:39 -070049
Michael Layzell760fd662017-05-31 22:46:05 -040050/// The result of a parser
51pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
52
53/// An error with a default error message.
54///
55/// NOTE: We should provide better error messages in the future.
56pub fn parse_error<O>() -> PResult<'static, O> {
Michael Layzellad763b72017-06-01 00:25:31 -040057 Err(ParseError(None))
David Tolnayf2222f02017-01-27 17:09:20 -080058}
59
Alex Crichton7b9e02f2017-05-30 15:54:33 -070060pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040061 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070062
63 fn description() -> Option<&'static str> {
64 None
65 }
66
67 fn parse_all(input: TokenStream) -> Result<Self, ParseError> {
Michael Layzell0a1a6632017-06-02 18:07:43 -040068 let buf = SynomBuffer::new(input);
Michael Layzell729a4a02017-06-04 18:59:57 -040069 let descr = Self::description().unwrap_or("unnamed parser");
70 let err = match Self::parse(buf.begin()) {
Michael Layzell760fd662017-05-31 22:46:05 -040071 Ok((rest, t)) => {
Michael Layzell0a1a6632017-06-02 18:07:43 -040072 if rest.eof() {
Alex Crichton954046c2017-05-30 21:49:42 -070073 return Ok(t)
Michael Layzell0a1a6632017-06-02 18:07:43 -040074 } else if rest == buf.begin() {
Alex Crichton954046c2017-05-30 21:49:42 -070075 // parsed nothing
Michael Layzell729a4a02017-06-04 18:59:57 -040076 format!("parsed no input while parsing {}", descr)
Alex Crichton954046c2017-05-30 21:49:42 -070077 } else {
Michael Layzell729a4a02017-06-04 18:59:57 -040078 // Partially parsed the output. Print the input which remained.
79 format!("unparsed tokens after parsing {}:\n{}",
80 descr, rest.token_stream())
Alex Crichton954046c2017-05-30 21:49:42 -070081 }
82 }
Michael Layzell729a4a02017-06-04 18:59:57 -040083 Err(ref err) => format!("{} while parsing {}", err.description(), descr),
Alex Crichton954046c2017-05-30 21:49:42 -070084 };
Michael Layzell729a4a02017-06-04 18:59:57 -040085 Err(ParseError(Some(err)))
Alex Crichton954046c2017-05-30 21:49:42 -070086 }
87
88 fn parse_str_all(input: &str) -> Result<Self, ParseError> {
89 Self::parse_all(input.parse()?)
90 }
91
92 fn parse_all_unwrap(input: TokenStream) -> Self {
93 // TODO: eventually try to provide super nice error messages here as
94 // this is what most users will hit. Hopefully the compiler will give us
95 // an interface one day to give an extra-good error message here.
96 Self::parse_all(input).unwrap()
97 }
98}
99
100#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -0400101pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -0700102
103impl Error for ParseError {
104 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -0400105 match self.0 {
106 Some(ref desc) => desc,
107 None => "failed to parse",
108 }
Alex Crichton954046c2017-05-30 21:49:42 -0700109 }
110}
111
112impl fmt::Display for ParseError {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -0400114 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -0700115 }
116}
117
118impl From<LexError> for ParseError {
119 fn from(_: LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -0400120 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -0700121 }
122}
123
124impl Synom for TokenStream {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400125 fn parse(input: Cursor) -> PResult<Self> {
126 Ok((Cursor::empty(), input.token_stream()))
Alex Crichton954046c2017-05-30 21:49:42 -0700127 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700128}
129
Michael Layzell24645a32017-02-04 13:19:26 -0500130/// Define a function from a parser combination.
131///
David Tolnay1f16b602017-02-07 20:06:55 -0500132/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
133///
134/// ```rust
135/// # extern crate syn;
136/// # #[macro_use] extern crate synom;
137/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700138/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700139/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500140/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700141/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
142/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500143/// );
144/// # fn main() {}
145/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500146#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700147macro_rules! named {
148 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400149 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700150 $submac!(i, $($args)*)
151 }
152 };
153
154 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400155 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700156 $submac!(i, $($args)*)
157 }
158 };
Michael Layzellf8334e32017-06-04 19:01:08 -0400159
160 // These two variants are for defining named parsers which have custom
161 // arguments, and are called with `call!()`
162 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
163 fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
164 $submac!(i, $($args)*)
165 }
166 };
167
168 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
169 pub fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
170 $submac!(i, $($args)*)
171 }
172 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700173}
174
David Tolnay1f16b602017-02-07 20:06:55 -0500175/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500176///
177/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500178///
Michael Layzell760fd662017-05-31 22:46:05 -0400179/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500180/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500181#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700182macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700183 ($i:expr, $fun:expr $(, $args:expr)*) => {
184 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700185 };
186}
187
David Tolnay1f16b602017-02-07 20:06:55 -0500188/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500189///
David Tolnay1f16b602017-02-07 20:06:55 -0500190/// - **Syntax:** `map!(THING, FN)`
191/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500192///
193/// ```rust
194/// extern crate syn;
195/// #[macro_use] extern crate synom;
196///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700197/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500198///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700199/// fn get_cond(if_: ExprIf) -> Expr {
200/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500201/// }
202///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700203/// // Parses an `if` statement but returns the condition part only.
204/// named!(if_condition -> Expr,
205/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500206/// );
207///
208/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700209/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700210/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500211/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700212/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700213/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500214/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500215#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700216macro_rules! map {
217 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700218 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400219 ::std::result::Result::Err(err) =>
220 ::std::result::Result::Err(err),
221 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700222 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700223 }
224 };
David Tolnay1f16b602017-02-07 20:06:55 -0500225
226 ($i:expr, $f:expr, $g:expr) => {
227 map!($i, call!($f), $g)
228 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700229}
230
David Tolnaybc7d7d92017-06-03 20:54:05 -0700231// Somehow this helps with type inference in `map!`.
232//
233// Not public API.
234#[doc(hidden)]
235pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
236 f(t)
237}
238
David Tolnay1f16b602017-02-07 20:06:55 -0500239/// Parses successfully if the given parser fails to parse. Does not consume any
240/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500241///
242/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500243/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500244#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700245macro_rules! not {
246 ($i:expr, $submac:ident!( $($args:tt)* )) => {
247 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400248 ::std::result::Result::Ok(_) => $crate::parse_error(),
249 ::std::result::Result::Err(_) =>
250 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700251 }
252 };
253}
254
David Tolnay1f16b602017-02-07 20:06:55 -0500255/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500256///
David Tolnay1f16b602017-02-07 20:06:55 -0500257/// If you are familiar with nom, this is nom's `cond_with_error` parser.
258///
259/// - **Syntax:** `cond!(CONDITION, THING)`
260/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500261#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700262macro_rules! cond {
263 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
264 if $cond {
265 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400266 ::std::result::Result::Ok((i, o)) =>
267 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
268 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700269 }
270 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400271 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700272 }
David Tolnaycfe55022016-10-02 22:02:27 -0700273 };
274
275 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700276 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700277 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700278}
279
David Tolnay1f16b602017-02-07 20:06:55 -0500280/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500281///
David Tolnay1f16b602017-02-07 20:06:55 -0500282/// This is typically used inside of `option!` or `alt!`.
283///
284/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
285/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500286#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700287macro_rules! cond_reduce {
288 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
289 if $cond {
290 $submac!($i, $($args)*)
291 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400292 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700293 }
294 };
295
296 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700297 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700298 };
299}
300
David Tolnay1f16b602017-02-07 20:06:55 -0500301/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500302///
David Tolnay1f16b602017-02-07 20:06:55 -0500303/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500304/// - **Output:** `THING`
305///
306/// ```rust
307/// extern crate syn;
308/// #[macro_use] extern crate synom;
309///
310/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700311/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500312///
313/// // An expression terminated by ##.
314/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700315/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500316/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500317///
Alex Crichton954046c2017-05-30 21:49:42 -0700318/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500319/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500320#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700321macro_rules! terminated {
322 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
323 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400324 ::std::result::Result::Ok((i, (o, _))) =>
325 ::std::result::Result::Ok((i, o)),
326 ::std::result::Result::Err(err) =>
327 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700328 }
329 };
330
331 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700332 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700333 };
334
335 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700336 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700337 };
338
339 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700340 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700341 };
342}
343
David Tolnay1f16b602017-02-07 20:06:55 -0500344/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500345///
346/// - **Syntax:** `many0!(THING)`
347/// - **Output:** `Vec<THING>`
348///
David Tolnay1f16b602017-02-07 20:06:55 -0500349/// You may also be looking for:
350///
Alex Crichton954046c2017-05-30 21:49:42 -0700351/// - `call!(Delimited::parse_separated)` - zero or more values with separator
352/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
353/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500354///
Michael Layzell24645a32017-02-04 13:19:26 -0500355/// ```rust
356/// extern crate syn;
357/// #[macro_use] extern crate synom;
358///
359/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500360///
Alex Crichton954046c2017-05-30 21:49:42 -0700361/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500362///
Alex Crichton954046c2017-05-30 21:49:42 -0700363/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500364#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700365macro_rules! many0 {
366 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
367 let ret;
368 let mut res = ::std::vec::Vec::new();
369 let mut input = $i;
370
371 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400372 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400373 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700374 break;
375 }
376
377 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400378 ::std::result::Result::Err(_) => {
379 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700380 break;
381 }
Michael Layzell760fd662017-05-31 22:46:05 -0400382 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700383 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400384 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400385 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700386 break;
387 }
388
389 res.push(o);
390 input = i;
391 }
392 }
393 }
394
395 ret
396 }};
397
398 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500399 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700400 };
401}
402
David Tolnay1f16b602017-02-07 20:06:55 -0500403// Improve compile time by compiling this loop only once per type it is used
404// with.
405//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800406// Not public API.
407#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400408pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700409 let mut res = Vec::new();
410
411 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400412 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400413 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700414 }
415
416 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400417 Err(_) => {
418 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700419 }
Michael Layzell760fd662017-05-31 22:46:05 -0400420 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700421 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400422 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400423 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700424 }
425
426 res.push(o);
427 input = i;
428 }
429 }
430 }
431}
432
David Tolnay1f16b602017-02-07 20:06:55 -0500433/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500434///
435/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500436/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500437///
438/// ```rust
439/// extern crate syn;
440/// #[macro_use] extern crate synom;
441///
Alex Crichton954046c2017-05-30 21:49:42 -0700442/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500443///
David Tolnay1f16b602017-02-07 20:06:55 -0500444/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700445/// named!(ident_expr -> (Ident, Expr),
446/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500447/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500448///
Alex Crichton954046c2017-05-30 21:49:42 -0700449/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500450/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500451#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700452macro_rules! peek {
453 ($i:expr, $submac:ident!( $($args:tt)* )) => {
454 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400455 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
456 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700457 }
458 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700459
David Tolnay1f16b602017-02-07 20:06:55 -0500460 ($i:expr, $f:expr) => {
461 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700462 };
463}
464
David Tolnay1f16b602017-02-07 20:06:55 -0500465/// Pattern-match the result of a parser to select which other parser to run.
466///
467/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
468/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
469///
470/// ```rust
471/// extern crate syn;
472/// #[macro_use] extern crate synom;
473///
474/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700475/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500476///
477/// #[derive(Debug)]
478/// enum UnitType {
479/// Struct {
480/// name: Ident,
481/// },
482/// Enum {
483/// name: Ident,
484/// variant: Ident,
485/// },
486/// }
487///
488/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
489/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700490/// which: alt!(
491/// syn!(Struct) => { |_| 0 }
492/// |
493/// syn!(Enum) => { |_| 1 }
494/// ) >>
495/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500496/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700497/// 0 => map!(
498/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500499/// move |_| UnitType::Struct {
500/// name: id,
501/// }
502/// )
503/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700504/// 1 => map!(
505/// braces!(syn!(Ident)),
506/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500507/// name: id,
508/// variant: variant,
509/// }
510/// )
511/// ) >>
512/// (item)
513/// ));
514///
Alex Crichton954046c2017-05-30 21:49:42 -0700515/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500516/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500517#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700518macro_rules! switch {
519 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
520 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400521 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
522 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700523 $(
524 $p => $subrule!(i, $($args2)*),
525 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400526 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700527 }
528 }
529 };
530}
531
Alex Crichton954046c2017-05-30 21:49:42 -0700532
David Tolnay1f16b602017-02-07 20:06:55 -0500533/// Produce the given value without parsing anything. Useful as an argument to
534/// `switch!`.
535///
536/// - **Syntax:** `value!(VALUE)`
537/// - **Output:** `VALUE`
538///
539/// ```rust
540/// extern crate syn;
541/// #[macro_use] extern crate synom;
542///
543/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700544/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500545///
546/// #[derive(Debug)]
547/// enum UnitType {
548/// Struct {
549/// name: Ident,
550/// },
551/// Enum {
552/// name: Ident,
553/// variant: Ident,
554/// },
555/// }
556///
557/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
558/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700559/// which: alt!(
560/// syn!(Struct) => { |_| 0 }
561/// |
562/// syn!(Enum) => { |_| 1 }
563/// ) >>
564/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500565/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700566/// 0 => map!(
567/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500568/// move |_| UnitType::Struct {
569/// name: id,
570/// }
571/// )
572/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700573/// 1 => map!(
574/// braces!(syn!(Ident)),
575/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500576/// name: id,
577/// variant: variant,
578/// }
579/// )
580/// ) >>
581/// (item)
582/// ));
583///
Alex Crichton954046c2017-05-30 21:49:42 -0700584/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500585/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500586#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700587macro_rules! value {
588 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400589 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700590 };
591}
592
David Tolnay1f16b602017-02-07 20:06:55 -0500593/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500594///
David Tolnay1f16b602017-02-07 20:06:55 -0500595/// - **Syntax:** `tuple!(A, B, C, ...)`
596/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500597///
598/// ```rust
599/// extern crate syn;
600/// #[macro_use] extern crate synom;
601///
602/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500603///
Alex Crichton954046c2017-05-30 21:49:42 -0700604/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500605///
Alex Crichton954046c2017-05-30 21:49:42 -0700606/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500607/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500608#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700609macro_rules! tuple {
610 ($i:expr, $($rest:tt)*) => {
611 tuple_parser!($i, (), $($rest)*)
612 };
613}
614
David Tolnay1f16b602017-02-07 20:06:55 -0500615/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500616#[doc(hidden)]
617#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700618macro_rules! tuple_parser {
619 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700620 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700621 };
622
623 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
624 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400625 ::std::result::Result::Err(err) =>
626 ::std::result::Result::Err(err),
627 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700628 tuple_parser!(i, (o), $($rest)*),
629 }
630 };
631
632 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest: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)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700637 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
638 }
639 };
640
641 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700642 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700643 };
644
645 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
646 $submac!($i, $($args)*)
647 };
648
649 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
650 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400651 ::std::result::Result::Err(err) =>
652 ::std::result::Result::Err(err),
653 ::std::result::Result::Ok((i, o)) =>
654 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700655 }
656 };
657
658 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400659 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700660 };
661}
662
David Tolnay1f16b602017-02-07 20:06:55 -0500663/// Run a series of parsers, returning the result of the first one which
664/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500665///
666/// Optionally allows for the result to be transformed.
667///
668/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500669/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500670///
671/// ```rust
672/// extern crate syn;
673/// #[macro_use] extern crate synom;
674///
675/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700676/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500677///
678/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500679/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700680/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500681/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700682/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500683/// )
684/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500685///
Alex Crichton954046c2017-05-30 21:49:42 -0700686/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500687/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500688#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700689macro_rules! alt {
690 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700691 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700692 };
693
694 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
695 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400696 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700697 _ => alt!($i, $($rest)*)
698 }
699 };
700
701 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
702 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400703 ::std::result::Result::Ok((i, o)) =>
704 ::std::result::Result::Ok((i, $gen(o))),
705 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700706 }
707 };
708
709 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700710 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700711 };
712
713 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700714 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700715 };
716
717 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
718 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400719 ::std::result::Result::Ok((i, o)) =>
720 ::std::result::Result::Ok((i, $gen(o))),
721 ::std::result::Result::Err(err) =>
722 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700723 }
724 };
725
726 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700727 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700728 };
729
730 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700731 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700732 };
733}
734
Michael Layzell24645a32017-02-04 13:19:26 -0500735/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500736/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500737///
David Tolnay1f16b602017-02-07 20:06:55 -0500738/// Produces the result of evaluating the final expression in parentheses with
739/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500740///
David Tolnay1f16b602017-02-07 20:06:55 -0500741/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500742/// - **Output:** `RESULT`
743///
744/// ```rust
745/// extern crate syn;
746/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700747/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500748///
749/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700750/// use synom::tokens::{Bang, Paren};
751/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500752///
David Tolnay1f16b602017-02-07 20:06:55 -0500753/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700754/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
755/// name: syn!(Ident) >>
756/// syn!(Bang) >>
757/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500758/// (name, body)
759/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500760///
Alex Crichton954046c2017-05-30 21:49:42 -0700761/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500762/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500763#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700764macro_rules! do_parse {
765 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400766 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700767 };
768
769 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700770 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700771 };
772
773 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
774 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400775 ::std::result::Result::Err(err) =>
776 ::std::result::Result::Err(err),
777 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700778 do_parse!(i, $($rest)*),
779 }
780 };
781
782 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700783 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700784 };
785
786 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
787 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400788 ::std::result::Result::Err(err) =>
789 ::std::result::Result::Err(err),
790 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700791 let $field = o;
792 do_parse!(i, $($rest)*)
793 },
794 }
795 };
796
David Tolnayfa0edf22016-09-23 22:58:24 -0700797 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700798 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700799 };
800
801 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
802 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400803 ::std::result::Result::Err(err) =>
804 ::std::result::Result::Err(err),
805 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700806 let mut $field = o;
807 do_parse!(i, $($rest)*)
808 },
809 }
810 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700811}
Michael Layzell416724e2017-05-24 21:12:34 -0400812
813#[macro_export]
814macro_rules! input_end {
815 ($i:expr,) => {
816 $crate::input_end($i)
817 };
818}
819
820// Not a public API
821#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400822pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400823 if input.eof() {
824 Ok((Cursor::empty(), ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400825 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400826 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400827 }
828}