blob: 7ad3b30bcfa52eb8c6462e44edd0979893baaf5c [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);
69 let result = Self::parse(buf.begin());
Michael Layzellad763b72017-06-01 00:25:31 -040070 let err = match result {
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
76 "failed to parse"
77 } else {
78 "unparsed tokens after"
79 }
80 }
Michael Layzellad763b72017-06-01 00:25:31 -040081 Err(ref err) => err.description(),
Alex Crichton954046c2017-05-30 21:49:42 -070082 };
83 match Self::description() {
Michael Layzellad763b72017-06-01 00:25:31 -040084 Some(s) => Err(ParseError(Some(format!("{} {}", err, s)))),
85 None => Err(ParseError(Some(err.to_string()))),
Alex Crichton954046c2017-05-30 21:49:42 -070086 }
87 }
88
89 fn parse_str_all(input: &str) -> Result<Self, ParseError> {
90 Self::parse_all(input.parse()?)
91 }
92
93 fn parse_all_unwrap(input: TokenStream) -> Self {
94 // TODO: eventually try to provide super nice error messages here as
95 // this is what most users will hit. Hopefully the compiler will give us
96 // an interface one day to give an extra-good error message here.
97 Self::parse_all(input).unwrap()
98 }
99}
100
101#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -0400102pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -0700103
104impl Error for ParseError {
105 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -0400106 match self.0 {
107 Some(ref desc) => desc,
108 None => "failed to parse",
109 }
Alex Crichton954046c2017-05-30 21:49:42 -0700110 }
111}
112
113impl fmt::Display for ParseError {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -0400115 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -0700116 }
117}
118
119impl From<LexError> for ParseError {
120 fn from(_: LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -0400121 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -0700122 }
123}
124
125impl Synom for TokenStream {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400126 fn parse(input: Cursor) -> PResult<Self> {
127 Ok((Cursor::empty(), input.token_stream()))
Alex Crichton954046c2017-05-30 21:49:42 -0700128 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700129}
130
Michael Layzell24645a32017-02-04 13:19:26 -0500131/// Define a function from a parser combination.
132///
David Tolnay1f16b602017-02-07 20:06:55 -0500133/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
134///
135/// ```rust
136/// # extern crate syn;
137/// # #[macro_use] extern crate synom;
138/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700139/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700140/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500141/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700142/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
143/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500144/// );
145/// # fn main() {}
146/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500147#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700148macro_rules! named {
149 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400150 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700151 $submac!(i, $($args)*)
152 }
153 };
154
155 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400156 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700157 $submac!(i, $($args)*)
158 }
159 };
160}
161
David Tolnay1f16b602017-02-07 20:06:55 -0500162/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500163///
164/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500165///
Michael Layzell760fd662017-05-31 22:46:05 -0400166/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500167/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500168#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700169macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700170 ($i:expr, $fun:expr $(, $args:expr)*) => {
171 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700172 };
173}
174
David Tolnay1f16b602017-02-07 20:06:55 -0500175/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500176///
David Tolnay1f16b602017-02-07 20:06:55 -0500177/// - **Syntax:** `map!(THING, FN)`
178/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500179///
180/// ```rust
181/// extern crate syn;
182/// #[macro_use] extern crate synom;
183///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700184/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500185///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700186/// fn get_cond(if_: ExprIf) -> Expr {
187/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500188/// }
189///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700190/// // Parses an `if` statement but returns the condition part only.
191/// named!(if_condition -> Expr,
192/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500193/// );
194///
195/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700196/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700197/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500198/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700199/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700200/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500201/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500202#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700203macro_rules! map {
204 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700205 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400206 ::std::result::Result::Err(err) =>
207 ::std::result::Result::Err(err),
208 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700209 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700210 }
211 };
David Tolnay1f16b602017-02-07 20:06:55 -0500212
213 ($i:expr, $f:expr, $g:expr) => {
214 map!($i, call!($f), $g)
215 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700216}
217
David Tolnaybc7d7d92017-06-03 20:54:05 -0700218// Somehow this helps with type inference in `map!`.
219//
220// Not public API.
221#[doc(hidden)]
222pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
223 f(t)
224}
225
David Tolnay1f16b602017-02-07 20:06:55 -0500226/// Parses successfully if the given parser fails to parse. Does not consume any
227/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500228///
229/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500230/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500231#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700232macro_rules! not {
233 ($i:expr, $submac:ident!( $($args:tt)* )) => {
234 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400235 ::std::result::Result::Ok(_) => $crate::parse_error(),
236 ::std::result::Result::Err(_) =>
237 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700238 }
239 };
240}
241
David Tolnay1f16b602017-02-07 20:06:55 -0500242/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500243///
David Tolnay1f16b602017-02-07 20:06:55 -0500244/// If you are familiar with nom, this is nom's `cond_with_error` parser.
245///
246/// - **Syntax:** `cond!(CONDITION, THING)`
247/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500248#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700249macro_rules! cond {
250 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
251 if $cond {
252 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400253 ::std::result::Result::Ok((i, o)) =>
254 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
255 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700256 }
257 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400258 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700259 }
David Tolnaycfe55022016-10-02 22:02:27 -0700260 };
261
262 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700263 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700264 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700265}
266
David Tolnay1f16b602017-02-07 20:06:55 -0500267/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500268///
David Tolnay1f16b602017-02-07 20:06:55 -0500269/// This is typically used inside of `option!` or `alt!`.
270///
271/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
272/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500273#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700274macro_rules! cond_reduce {
275 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
276 if $cond {
277 $submac!($i, $($args)*)
278 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400279 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700280 }
281 };
282
283 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700284 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700285 };
286}
287
David Tolnay1f16b602017-02-07 20:06:55 -0500288/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500289///
David Tolnay1f16b602017-02-07 20:06:55 -0500290/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500291/// - **Output:** `THING`
292///
293/// ```rust
294/// extern crate syn;
295/// #[macro_use] extern crate synom;
296///
297/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700298/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500299///
300/// // An expression terminated by ##.
301/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700302/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500303/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500304///
Alex Crichton954046c2017-05-30 21:49:42 -0700305/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500306/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500307#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700308macro_rules! terminated {
309 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
310 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400311 ::std::result::Result::Ok((i, (o, _))) =>
312 ::std::result::Result::Ok((i, o)),
313 ::std::result::Result::Err(err) =>
314 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700315 }
316 };
317
318 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700319 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700320 };
321
322 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700323 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700324 };
325
326 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700327 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700328 };
329}
330
David Tolnay1f16b602017-02-07 20:06:55 -0500331/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500332///
333/// - **Syntax:** `many0!(THING)`
334/// - **Output:** `Vec<THING>`
335///
David Tolnay1f16b602017-02-07 20:06:55 -0500336/// You may also be looking for:
337///
Alex Crichton954046c2017-05-30 21:49:42 -0700338/// - `call!(Delimited::parse_separated)` - zero or more values with separator
339/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
340/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500341///
Michael Layzell24645a32017-02-04 13:19:26 -0500342/// ```rust
343/// extern crate syn;
344/// #[macro_use] extern crate synom;
345///
346/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500347///
Alex Crichton954046c2017-05-30 21:49:42 -0700348/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500349///
Alex Crichton954046c2017-05-30 21:49:42 -0700350/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500351#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700352macro_rules! many0 {
353 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
354 let ret;
355 let mut res = ::std::vec::Vec::new();
356 let mut input = $i;
357
358 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400359 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400360 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700361 break;
362 }
363
364 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400365 ::std::result::Result::Err(_) => {
366 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700367 break;
368 }
Michael Layzell760fd662017-05-31 22:46:05 -0400369 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700370 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400371 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400372 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700373 break;
374 }
375
376 res.push(o);
377 input = i;
378 }
379 }
380 }
381
382 ret
383 }};
384
385 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500386 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700387 };
388}
389
David Tolnay1f16b602017-02-07 20:06:55 -0500390// Improve compile time by compiling this loop only once per type it is used
391// with.
392//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800393// Not public API.
394#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400395pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700396 let mut res = Vec::new();
397
398 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400399 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400400 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700401 }
402
403 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400404 Err(_) => {
405 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700406 }
Michael Layzell760fd662017-05-31 22:46:05 -0400407 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700408 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400409 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400410 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700411 }
412
413 res.push(o);
414 input = i;
415 }
416 }
417 }
418}
419
David Tolnay1f16b602017-02-07 20:06:55 -0500420/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500421///
422/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500423/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500424///
425/// ```rust
426/// extern crate syn;
427/// #[macro_use] extern crate synom;
428///
Alex Crichton954046c2017-05-30 21:49:42 -0700429/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500430///
David Tolnay1f16b602017-02-07 20:06:55 -0500431/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700432/// named!(ident_expr -> (Ident, Expr),
433/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500434/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500435///
Alex Crichton954046c2017-05-30 21:49:42 -0700436/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500437/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500438#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700439macro_rules! peek {
440 ($i:expr, $submac:ident!( $($args:tt)* )) => {
441 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400442 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
443 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700444 }
445 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700446
David Tolnay1f16b602017-02-07 20:06:55 -0500447 ($i:expr, $f:expr) => {
448 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700449 };
450}
451
David Tolnay1f16b602017-02-07 20:06:55 -0500452/// Pattern-match the result of a parser to select which other parser to run.
453///
454/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
455/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
456///
457/// ```rust
458/// extern crate syn;
459/// #[macro_use] extern crate synom;
460///
461/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700462/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500463///
464/// #[derive(Debug)]
465/// enum UnitType {
466/// Struct {
467/// name: Ident,
468/// },
469/// Enum {
470/// name: Ident,
471/// variant: Ident,
472/// },
473/// }
474///
475/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
476/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700477/// which: alt!(
478/// syn!(Struct) => { |_| 0 }
479/// |
480/// syn!(Enum) => { |_| 1 }
481/// ) >>
482/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500483/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700484/// 0 => map!(
485/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500486/// move |_| UnitType::Struct {
487/// name: id,
488/// }
489/// )
490/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700491/// 1 => map!(
492/// braces!(syn!(Ident)),
493/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500494/// name: id,
495/// variant: variant,
496/// }
497/// )
498/// ) >>
499/// (item)
500/// ));
501///
Alex Crichton954046c2017-05-30 21:49:42 -0700502/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500503/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500504#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700505macro_rules! switch {
506 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
507 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400508 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
509 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700510 $(
511 $p => $subrule!(i, $($args2)*),
512 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400513 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700514 }
515 }
516 };
517}
518
Alex Crichton954046c2017-05-30 21:49:42 -0700519
David Tolnay1f16b602017-02-07 20:06:55 -0500520/// Produce the given value without parsing anything. Useful as an argument to
521/// `switch!`.
522///
523/// - **Syntax:** `value!(VALUE)`
524/// - **Output:** `VALUE`
525///
526/// ```rust
527/// extern crate syn;
528/// #[macro_use] extern crate synom;
529///
530/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700531/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500532///
533/// #[derive(Debug)]
534/// enum UnitType {
535/// Struct {
536/// name: Ident,
537/// },
538/// Enum {
539/// name: Ident,
540/// variant: Ident,
541/// },
542/// }
543///
544/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
545/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700546/// which: alt!(
547/// syn!(Struct) => { |_| 0 }
548/// |
549/// syn!(Enum) => { |_| 1 }
550/// ) >>
551/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500552/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700553/// 0 => map!(
554/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500555/// move |_| UnitType::Struct {
556/// name: id,
557/// }
558/// )
559/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700560/// 1 => map!(
561/// braces!(syn!(Ident)),
562/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500563/// name: id,
564/// variant: variant,
565/// }
566/// )
567/// ) >>
568/// (item)
569/// ));
570///
Alex Crichton954046c2017-05-30 21:49:42 -0700571/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500572/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500573#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700574macro_rules! value {
575 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400576 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700577 };
578}
579
David Tolnay1f16b602017-02-07 20:06:55 -0500580/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500581///
David Tolnay1f16b602017-02-07 20:06:55 -0500582/// - **Syntax:** `tuple!(A, B, C, ...)`
583/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500584///
585/// ```rust
586/// extern crate syn;
587/// #[macro_use] extern crate synom;
588///
589/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500590///
Alex Crichton954046c2017-05-30 21:49:42 -0700591/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500592///
Alex Crichton954046c2017-05-30 21:49:42 -0700593/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500594/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500595#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700596macro_rules! tuple {
597 ($i:expr, $($rest:tt)*) => {
598 tuple_parser!($i, (), $($rest)*)
599 };
600}
601
David Tolnay1f16b602017-02-07 20:06:55 -0500602/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500603#[doc(hidden)]
604#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700605macro_rules! tuple_parser {
606 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700607 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700608 };
609
610 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
611 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400612 ::std::result::Result::Err(err) =>
613 ::std::result::Result::Err(err),
614 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700615 tuple_parser!(i, (o), $($rest)*),
616 }
617 };
618
619 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
620 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400621 ::std::result::Result::Err(err) =>
622 ::std::result::Result::Err(err),
623 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700624 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
625 }
626 };
627
628 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700629 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700630 };
631
632 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
633 $submac!($i, $($args)*)
634 };
635
636 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
637 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400638 ::std::result::Result::Err(err) =>
639 ::std::result::Result::Err(err),
640 ::std::result::Result::Ok((i, o)) =>
641 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700642 }
643 };
644
645 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400646 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700647 };
648}
649
David Tolnay1f16b602017-02-07 20:06:55 -0500650/// Run a series of parsers, returning the result of the first one which
651/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500652///
653/// Optionally allows for the result to be transformed.
654///
655/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500656/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500657///
658/// ```rust
659/// extern crate syn;
660/// #[macro_use] extern crate synom;
661///
662/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700663/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500664///
665/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500666/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700667/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500668/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700669/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500670/// )
671/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500672///
Alex Crichton954046c2017-05-30 21:49:42 -0700673/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500674/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500675#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700676macro_rules! alt {
677 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700678 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700679 };
680
681 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
682 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400683 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700684 _ => alt!($i, $($rest)*)
685 }
686 };
687
688 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
689 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400690 ::std::result::Result::Ok((i, o)) =>
691 ::std::result::Result::Ok((i, $gen(o))),
692 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700693 }
694 };
695
696 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700697 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700698 };
699
700 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700701 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700702 };
703
704 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
705 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400706 ::std::result::Result::Ok((i, o)) =>
707 ::std::result::Result::Ok((i, $gen(o))),
708 ::std::result::Result::Err(err) =>
709 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700710 }
711 };
712
713 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700714 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700715 };
716
717 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700718 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700719 };
720}
721
Michael Layzell24645a32017-02-04 13:19:26 -0500722/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500723/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500724///
David Tolnay1f16b602017-02-07 20:06:55 -0500725/// Produces the result of evaluating the final expression in parentheses with
726/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500727///
David Tolnay1f16b602017-02-07 20:06:55 -0500728/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500729/// - **Output:** `RESULT`
730///
731/// ```rust
732/// extern crate syn;
733/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700734/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500735///
736/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700737/// use synom::tokens::{Bang, Paren};
738/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500739///
David Tolnay1f16b602017-02-07 20:06:55 -0500740/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700741/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
742/// name: syn!(Ident) >>
743/// syn!(Bang) >>
744/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500745/// (name, body)
746/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500747///
Alex Crichton954046c2017-05-30 21:49:42 -0700748/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500749/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500750#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700751macro_rules! do_parse {
752 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400753 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700754 };
755
756 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700757 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700758 };
759
760 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
761 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400762 ::std::result::Result::Err(err) =>
763 ::std::result::Result::Err(err),
764 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700765 do_parse!(i, $($rest)*),
766 }
767 };
768
769 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700770 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700771 };
772
773 ($i:expr, $field:ident : $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, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700778 let $field = o;
779 do_parse!(i, $($rest)*)
780 },
781 }
782 };
783
David Tolnayfa0edf22016-09-23 22:58:24 -0700784 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700785 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700786 };
787
788 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
789 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400790 ::std::result::Result::Err(err) =>
791 ::std::result::Result::Err(err),
792 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700793 let mut $field = o;
794 do_parse!(i, $($rest)*)
795 },
796 }
797 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700798}
Michael Layzell416724e2017-05-24 21:12:34 -0400799
800#[macro_export]
801macro_rules! input_end {
802 ($i:expr,) => {
803 $crate::input_end($i)
804 };
805}
806
807// Not a public API
808#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400809pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400810 if input.eof() {
811 Ok((Cursor::empty(), ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400812 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400813 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400814 }
815}