blob: 396260ed869d73484b29db10d0d75ac8cc253507 [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
David Tolnayc7a5d3d2017-06-04 12:11:05 -070024extern crate proc_macro;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070025extern crate proc_macro2;
David Tolnayc7a5d3d2017-06-04 12:11:05 -070026extern crate unicode_xid;
Michael Layzell5bde96f2017-01-24 17:59:21 -050027
Alex Crichtonccbb45d2017-05-23 10:58:24 -070028#[cfg(feature = "printing")]
29extern crate quote;
30
David Tolnay30a36002017-02-08 14:24:12 -080031#[doc(hidden)]
Alex Crichton954046c2017-05-30 21:49:42 -070032pub use proc_macro2::{TokenTree, TokenStream};
33
34use std::convert::From;
35use std::error::Error;
36use std::fmt;
37
Alex Crichtonccbb45d2017-05-23 10:58:24 -070038#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080039#[doc(hidden)]
40pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050041
Alex Crichtonccbb45d2017-05-23 10:58:24 -070042pub mod delimited;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070043pub mod tokens;
44pub mod span;
Michael Layzell2a60e252017-05-31 21:36:47 -040045pub mod cursor;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070046
Michael Layzell0a1a6632017-06-02 18:07:43 -040047pub use cursor::{SynomBuffer, Cursor};
David Tolnayb5a7b142016-09-13 22:46:39 -070048
Michael Layzell760fd662017-05-31 22:46:05 -040049/// The result of a parser
50pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
51
52/// An error with a default error message.
53///
54/// NOTE: We should provide better error messages in the future.
55pub fn parse_error<O>() -> PResult<'static, O> {
Michael Layzellad763b72017-06-01 00:25:31 -040056 Err(ParseError(None))
David Tolnayf2222f02017-01-27 17:09:20 -080057}
58
Alex Crichton7b9e02f2017-05-30 15:54:33 -070059pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040060 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070061
62 fn description() -> Option<&'static str> {
63 None
64 }
Alex Crichton954046c2017-05-30 21:49:42 -070065}
66
67#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -040068pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -070069
70impl Error for ParseError {
71 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -040072 match self.0 {
73 Some(ref desc) => desc,
74 None => "failed to parse",
75 }
Alex Crichton954046c2017-05-30 21:49:42 -070076 }
77}
78
79impl fmt::Display for ParseError {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -040081 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -070082 }
83}
84
David Tolnayc7a5d3d2017-06-04 12:11:05 -070085impl From<proc_macro2::LexError> for ParseError {
86 fn from(_: proc_macro2::LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -040087 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -070088 }
89}
90
David Tolnayc7a5d3d2017-06-04 12:11:05 -070091impl From<proc_macro::LexError> for ParseError {
92 fn from(_: proc_macro::LexError) -> ParseError {
93 ParseError(Some("error while lexing input string".to_owned()))
94 }
95}
96
97impl ParseError {
98 // For syn use only. Not public API.
99 #[doc(hidden)]
100 pub fn new<T: Into<String>>(msg: T) -> Self {
101 ParseError(Some(msg.into()))
102 }
103}
104
Alex Crichton954046c2017-05-30 21:49:42 -0700105impl Synom for TokenStream {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400106 fn parse(input: Cursor) -> PResult<Self> {
107 Ok((Cursor::empty(), input.token_stream()))
Alex Crichton954046c2017-05-30 21:49:42 -0700108 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700109}
110
Michael Layzell24645a32017-02-04 13:19:26 -0500111/// Define a function from a parser combination.
112///
David Tolnay1f16b602017-02-07 20:06:55 -0500113/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
114///
115/// ```rust
116/// # extern crate syn;
117/// # #[macro_use] extern crate synom;
118/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700119/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700120/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500121/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700122/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
123/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500124/// );
125/// # fn main() {}
126/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500127#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700128macro_rules! named {
129 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400130 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700131 $submac!(i, $($args)*)
132 }
133 };
134
135 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400136 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700137 $submac!(i, $($args)*)
138 }
139 };
Michael Layzellf8334e32017-06-04 19:01:08 -0400140
141 // These two variants are for defining named parsers which have custom
142 // arguments, and are called with `call!()`
143 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
144 fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
145 $submac!(i, $($args)*)
146 }
147 };
148
149 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
150 pub fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
151 $submac!(i, $($args)*)
152 }
153 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700154}
155
David Tolnay1f16b602017-02-07 20:06:55 -0500156/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500157///
158/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500159///
Michael Layzell760fd662017-05-31 22:46:05 -0400160/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500161/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500162#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700163macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700164 ($i:expr, $fun:expr $(, $args:expr)*) => {
165 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700166 };
167}
168
David Tolnay1f16b602017-02-07 20:06:55 -0500169/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500170///
David Tolnay1f16b602017-02-07 20:06:55 -0500171/// - **Syntax:** `map!(THING, FN)`
172/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500173///
174/// ```rust
175/// extern crate syn;
176/// #[macro_use] extern crate synom;
177///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700178/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500179///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700180/// fn get_cond(if_: ExprIf) -> Expr {
181/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500182/// }
183///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700184/// // Parses an `if` statement but returns the condition part only.
185/// named!(if_condition -> Expr,
186/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500187/// );
188///
189/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700190/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700191/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500192/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700193/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700194/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500195/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500196#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700197macro_rules! map {
198 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700199 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400200 ::std::result::Result::Err(err) =>
201 ::std::result::Result::Err(err),
202 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700203 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700204 }
205 };
David Tolnay1f16b602017-02-07 20:06:55 -0500206
207 ($i:expr, $f:expr, $g:expr) => {
208 map!($i, call!($f), $g)
209 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700210}
211
David Tolnaybc7d7d92017-06-03 20:54:05 -0700212// Somehow this helps with type inference in `map!`.
213//
214// Not public API.
215#[doc(hidden)]
216pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
217 f(t)
218}
219
David Tolnay1f16b602017-02-07 20:06:55 -0500220/// Parses successfully if the given parser fails to parse. Does not consume any
221/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500222///
223/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500224/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500225#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700226macro_rules! not {
227 ($i:expr, $submac:ident!( $($args:tt)* )) => {
228 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400229 ::std::result::Result::Ok(_) => $crate::parse_error(),
230 ::std::result::Result::Err(_) =>
231 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700232 }
233 };
234}
235
David Tolnay1f16b602017-02-07 20:06:55 -0500236/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500237///
David Tolnay1f16b602017-02-07 20:06:55 -0500238/// If you are familiar with nom, this is nom's `cond_with_error` parser.
239///
240/// - **Syntax:** `cond!(CONDITION, THING)`
241/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500242#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700243macro_rules! cond {
244 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
245 if $cond {
246 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400247 ::std::result::Result::Ok((i, o)) =>
248 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
249 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700250 }
251 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400252 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700253 }
David Tolnaycfe55022016-10-02 22:02:27 -0700254 };
255
256 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700257 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700258 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700259}
260
David Tolnay1f16b602017-02-07 20:06:55 -0500261/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500262///
David Tolnay1f16b602017-02-07 20:06:55 -0500263/// This is typically used inside of `option!` or `alt!`.
264///
265/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
266/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500267#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700268macro_rules! cond_reduce {
269 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
270 if $cond {
271 $submac!($i, $($args)*)
272 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400273 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700274 }
275 };
276
277 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700278 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700279 };
280}
281
David Tolnay1f16b602017-02-07 20:06:55 -0500282/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500283///
David Tolnay1f16b602017-02-07 20:06:55 -0500284/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500285/// - **Output:** `THING`
286///
287/// ```rust
288/// extern crate syn;
289/// #[macro_use] extern crate synom;
290///
291/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700292/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500293///
294/// // An expression terminated by ##.
295/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700296/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500297/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500298///
Alex Crichton954046c2017-05-30 21:49:42 -0700299/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500300/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500301#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700302macro_rules! terminated {
303 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
304 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400305 ::std::result::Result::Ok((i, (o, _))) =>
306 ::std::result::Result::Ok((i, o)),
307 ::std::result::Result::Err(err) =>
308 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700309 }
310 };
311
312 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700313 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700314 };
315
316 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700317 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700318 };
319
320 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700321 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700322 };
323}
324
David Tolnay1f16b602017-02-07 20:06:55 -0500325/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500326///
327/// - **Syntax:** `many0!(THING)`
328/// - **Output:** `Vec<THING>`
329///
David Tolnay1f16b602017-02-07 20:06:55 -0500330/// You may also be looking for:
331///
Alex Crichton954046c2017-05-30 21:49:42 -0700332/// - `call!(Delimited::parse_separated)` - zero or more values with separator
333/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
334/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500335///
Michael Layzell24645a32017-02-04 13:19:26 -0500336/// ```rust
337/// extern crate syn;
338/// #[macro_use] extern crate synom;
339///
340/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500341///
Alex Crichton954046c2017-05-30 21:49:42 -0700342/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500343///
Alex Crichton954046c2017-05-30 21:49:42 -0700344/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500345#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700346macro_rules! many0 {
347 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
348 let ret;
349 let mut res = ::std::vec::Vec::new();
350 let mut input = $i;
351
352 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400353 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400354 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700355 break;
356 }
357
358 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400359 ::std::result::Result::Err(_) => {
360 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700361 break;
362 }
Michael Layzell760fd662017-05-31 22:46:05 -0400363 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700364 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400365 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400366 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700367 break;
368 }
369
370 res.push(o);
371 input = i;
372 }
373 }
374 }
375
376 ret
377 }};
378
379 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500380 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700381 };
382}
383
David Tolnay1f16b602017-02-07 20:06:55 -0500384// Improve compile time by compiling this loop only once per type it is used
385// with.
386//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800387// Not public API.
388#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400389pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700390 let mut res = Vec::new();
391
392 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400393 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400394 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700395 }
396
397 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400398 Err(_) => {
399 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700400 }
Michael Layzell760fd662017-05-31 22:46:05 -0400401 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700402 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400403 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400404 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700405 }
406
407 res.push(o);
408 input = i;
409 }
410 }
411 }
412}
413
David Tolnay1f16b602017-02-07 20:06:55 -0500414/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500415///
416/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500417/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500418///
419/// ```rust
420/// extern crate syn;
421/// #[macro_use] extern crate synom;
422///
Alex Crichton954046c2017-05-30 21:49:42 -0700423/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500424///
David Tolnay1f16b602017-02-07 20:06:55 -0500425/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700426/// named!(ident_expr -> (Ident, Expr),
427/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500428/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500429///
Alex Crichton954046c2017-05-30 21:49:42 -0700430/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500431/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500432#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700433macro_rules! peek {
434 ($i:expr, $submac:ident!( $($args:tt)* )) => {
435 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400436 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
437 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700438 }
439 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700440
David Tolnay1f16b602017-02-07 20:06:55 -0500441 ($i:expr, $f:expr) => {
442 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700443 };
444}
445
David Tolnay1f16b602017-02-07 20:06:55 -0500446/// Pattern-match the result of a parser to select which other parser to run.
447///
448/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
449/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
450///
451/// ```rust
452/// extern crate syn;
453/// #[macro_use] extern crate synom;
454///
455/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700456/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500457///
458/// #[derive(Debug)]
459/// enum UnitType {
460/// Struct {
461/// name: Ident,
462/// },
463/// Enum {
464/// name: Ident,
465/// variant: Ident,
466/// },
467/// }
468///
469/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
470/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700471/// which: alt!(
472/// syn!(Struct) => { |_| 0 }
473/// |
474/// syn!(Enum) => { |_| 1 }
475/// ) >>
476/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500477/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700478/// 0 => map!(
479/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500480/// move |_| UnitType::Struct {
481/// name: id,
482/// }
483/// )
484/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700485/// 1 => map!(
486/// braces!(syn!(Ident)),
487/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500488/// name: id,
489/// variant: variant,
490/// }
491/// )
492/// ) >>
493/// (item)
494/// ));
495///
Alex Crichton954046c2017-05-30 21:49:42 -0700496/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500497/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500498#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700499macro_rules! switch {
500 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
501 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400502 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
503 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700504 $(
505 $p => $subrule!(i, $($args2)*),
506 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400507 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700508 }
509 }
510 };
511}
512
Alex Crichton954046c2017-05-30 21:49:42 -0700513
David Tolnay1f16b602017-02-07 20:06:55 -0500514/// Produce the given value without parsing anything. Useful as an argument to
515/// `switch!`.
516///
517/// - **Syntax:** `value!(VALUE)`
518/// - **Output:** `VALUE`
519///
520/// ```rust
521/// extern crate syn;
522/// #[macro_use] extern crate synom;
523///
524/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700525/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500526///
527/// #[derive(Debug)]
528/// enum UnitType {
529/// Struct {
530/// name: Ident,
531/// },
532/// Enum {
533/// name: Ident,
534/// variant: Ident,
535/// },
536/// }
537///
538/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
539/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700540/// which: alt!(
541/// syn!(Struct) => { |_| 0 }
542/// |
543/// syn!(Enum) => { |_| 1 }
544/// ) >>
545/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500546/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700547/// 0 => map!(
548/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500549/// move |_| UnitType::Struct {
550/// name: id,
551/// }
552/// )
553/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700554/// 1 => map!(
555/// braces!(syn!(Ident)),
556/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500557/// name: id,
558/// variant: variant,
559/// }
560/// )
561/// ) >>
562/// (item)
563/// ));
564///
Alex Crichton954046c2017-05-30 21:49:42 -0700565/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500566/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500567#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700568macro_rules! value {
569 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400570 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700571 };
572}
573
David Tolnay1f16b602017-02-07 20:06:55 -0500574/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500575///
David Tolnay1f16b602017-02-07 20:06:55 -0500576/// - **Syntax:** `tuple!(A, B, C, ...)`
577/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500578///
579/// ```rust
580/// extern crate syn;
581/// #[macro_use] extern crate synom;
582///
583/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500584///
Alex Crichton954046c2017-05-30 21:49:42 -0700585/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500586///
Alex Crichton954046c2017-05-30 21:49:42 -0700587/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500588/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500589#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700590macro_rules! tuple {
591 ($i:expr, $($rest:tt)*) => {
592 tuple_parser!($i, (), $($rest)*)
593 };
594}
595
David Tolnay1f16b602017-02-07 20:06:55 -0500596/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500597#[doc(hidden)]
598#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700599macro_rules! tuple_parser {
600 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700601 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700602 };
603
604 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
605 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400606 ::std::result::Result::Err(err) =>
607 ::std::result::Result::Err(err),
608 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700609 tuple_parser!(i, (o), $($rest)*),
610 }
611 };
612
613 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
614 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400615 ::std::result::Result::Err(err) =>
616 ::std::result::Result::Err(err),
617 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700618 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
619 }
620 };
621
622 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700623 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700624 };
625
626 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
627 $submac!($i, $($args)*)
628 };
629
630 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
631 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400632 ::std::result::Result::Err(err) =>
633 ::std::result::Result::Err(err),
634 ::std::result::Result::Ok((i, o)) =>
635 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700636 }
637 };
638
639 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400640 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700641 };
642}
643
David Tolnay1f16b602017-02-07 20:06:55 -0500644/// Run a series of parsers, returning the result of the first one which
645/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500646///
647/// Optionally allows for the result to be transformed.
648///
649/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500650/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500651///
652/// ```rust
653/// extern crate syn;
654/// #[macro_use] extern crate synom;
655///
656/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700657/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500658///
659/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500660/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700661/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500662/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700663/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500664/// )
665/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500666///
Alex Crichton954046c2017-05-30 21:49:42 -0700667/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500668/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500669#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700670macro_rules! alt {
671 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700672 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700673 };
674
675 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
676 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400677 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700678 _ => alt!($i, $($rest)*)
679 }
680 };
681
682 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
683 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400684 ::std::result::Result::Ok((i, o)) =>
685 ::std::result::Result::Ok((i, $gen(o))),
686 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700687 }
688 };
689
690 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700691 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700692 };
693
694 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700695 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700696 };
697
698 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
699 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400700 ::std::result::Result::Ok((i, o)) =>
701 ::std::result::Result::Ok((i, $gen(o))),
702 ::std::result::Result::Err(err) =>
703 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700704 }
705 };
706
707 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700708 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700709 };
710
711 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700712 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700713 };
714}
715
Michael Layzell24645a32017-02-04 13:19:26 -0500716/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500717/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500718///
David Tolnay1f16b602017-02-07 20:06:55 -0500719/// Produces the result of evaluating the final expression in parentheses with
720/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500721///
David Tolnay1f16b602017-02-07 20:06:55 -0500722/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500723/// - **Output:** `RESULT`
724///
725/// ```rust
726/// extern crate syn;
727/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700728/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500729///
730/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700731/// use synom::tokens::{Bang, Paren};
732/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500733///
David Tolnay1f16b602017-02-07 20:06:55 -0500734/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700735/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
736/// name: syn!(Ident) >>
737/// syn!(Bang) >>
738/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500739/// (name, body)
740/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500741///
Alex Crichton954046c2017-05-30 21:49:42 -0700742/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500743/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500744#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700745macro_rules! do_parse {
746 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400747 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700748 };
749
750 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700751 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700752 };
753
754 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
755 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400756 ::std::result::Result::Err(err) =>
757 ::std::result::Result::Err(err),
758 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700759 do_parse!(i, $($rest)*),
760 }
761 };
762
763 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700764 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700765 };
766
767 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
768 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400769 ::std::result::Result::Err(err) =>
770 ::std::result::Result::Err(err),
771 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700772 let $field = o;
773 do_parse!(i, $($rest)*)
774 },
775 }
776 };
777
David Tolnayfa0edf22016-09-23 22:58:24 -0700778 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700779 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700780 };
781
782 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
783 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400784 ::std::result::Result::Err(err) =>
785 ::std::result::Result::Err(err),
786 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700787 let mut $field = o;
788 do_parse!(i, $($rest)*)
789 },
790 }
791 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700792}
Michael Layzell416724e2017-05-24 21:12:34 -0400793
794#[macro_export]
795macro_rules! input_end {
796 ($i:expr,) => {
797 $crate::input_end($i)
798 };
799}
800
801// Not a public API
802#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400803pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400804 if input.eof() {
805 Ok((Cursor::empty(), ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400806 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400807 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400808 }
809}