blob: 009de4334a925678dcedc983f19c7980780264b2 [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;
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
Alex Crichtonccbb45d2017-05-23 10:58:24 -070037#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080038#[doc(hidden)]
39pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050040
Alex Crichtonccbb45d2017-05-23 10:58:24 -070041pub mod delimited;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070042pub mod tokens;
43pub mod span;
Michael Layzell2a60e252017-05-31 21:36:47 -040044pub mod cursor;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070045
Michael Layzell0a1a6632017-06-02 18:07:43 -040046pub use cursor::{SynomBuffer, Cursor};
David Tolnayb5a7b142016-09-13 22:46:39 -070047
Michael Layzell760fd662017-05-31 22:46:05 -040048/// The result of a parser
49pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
50
51/// An error with a default error message.
52///
53/// NOTE: We should provide better error messages in the future.
54pub fn parse_error<O>() -> PResult<'static, O> {
Michael Layzellad763b72017-06-01 00:25:31 -040055 Err(ParseError(None))
David Tolnayf2222f02017-01-27 17:09:20 -080056}
57
Alex Crichton7b9e02f2017-05-30 15:54:33 -070058pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040059 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070060
61 fn description() -> Option<&'static str> {
62 None
63 }
Alex Crichton954046c2017-05-30 21:49:42 -070064}
65
66#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -040067pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -070068
69impl Error for ParseError {
70 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -040071 match self.0 {
72 Some(ref desc) => desc,
73 None => "failed to parse",
74 }
Alex Crichton954046c2017-05-30 21:49:42 -070075 }
76}
77
78impl fmt::Display for ParseError {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -040080 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -070081 }
82}
83
David Tolnayc7a5d3d2017-06-04 12:11:05 -070084impl From<proc_macro2::LexError> for ParseError {
85 fn from(_: proc_macro2::LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -040086 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -070087 }
88}
89
David Tolnayc7a5d3d2017-06-04 12:11:05 -070090impl From<proc_macro::LexError> for ParseError {
91 fn from(_: proc_macro::LexError) -> ParseError {
92 ParseError(Some("error while lexing input string".to_owned()))
93 }
94}
95
96impl ParseError {
97 // For syn use only. Not public API.
98 #[doc(hidden)]
99 pub fn new<T: Into<String>>(msg: T) -> Self {
100 ParseError(Some(msg.into()))
101 }
102}
103
Alex Crichton954046c2017-05-30 21:49:42 -0700104impl Synom for TokenStream {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400105 fn parse(input: Cursor) -> PResult<Self> {
106 Ok((Cursor::empty(), input.token_stream()))
Alex Crichton954046c2017-05-30 21:49:42 -0700107 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700108}
109
Michael Layzell24645a32017-02-04 13:19:26 -0500110/// Define a function from a parser combination.
111///
David Tolnay1f16b602017-02-07 20:06:55 -0500112/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
113///
114/// ```rust
115/// # extern crate syn;
116/// # #[macro_use] extern crate synom;
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800117/// # use syn::Type;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700118/// # use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -0500119/// // One or more Rust types separated by commas.
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800120/// named!(pub comma_separated_types -> Delimited<Type, Token![,]>,
Alex Crichton954046c2017-05-30 21:49:42 -0700121/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500122/// );
123/// # fn main() {}
124/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500125#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700126macro_rules! named {
127 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400128 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700129 $submac!(i, $($args)*)
130 }
131 };
132
133 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400134 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700135 $submac!(i, $($args)*)
136 }
137 };
Michael Layzellf8334e32017-06-04 19:01:08 -0400138
139 // These two variants are for defining named parsers which have custom
140 // arguments, and are called with `call!()`
141 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
142 fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
143 $submac!(i, $($args)*)
144 }
145 };
146
147 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
148 pub fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
149 $submac!(i, $($args)*)
150 }
151 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700152}
153
Nika Layzellae81b372017-12-05 14:12:33 -0500154#[cfg(feature = "verbose-trace")]
155#[macro_export]
156macro_rules! call {
157 ($i:expr, $fun:expr $(, $args:expr)*) => {
158 {
159 let i = $i;
160 eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
161 let r = $fun(i $(, $args)*);
162 match r {
163 Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
164 Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
165 }
166 r
167 }
168 };
169}
170
David Tolnay1f16b602017-02-07 20:06:55 -0500171/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500172///
173/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500174///
Michael Layzell760fd662017-05-31 22:46:05 -0400175/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500176/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Nika Layzellae81b372017-12-05 14:12:33 -0500177#[cfg(not(feature = "verbose-trace"))]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500178#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700179macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700180 ($i:expr, $fun:expr $(, $args:expr)*) => {
181 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700182 };
183}
184
David Tolnay1f16b602017-02-07 20:06:55 -0500185/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500186///
David Tolnay1f16b602017-02-07 20:06:55 -0500187/// - **Syntax:** `map!(THING, FN)`
188/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500189///
190/// ```rust
191/// extern crate syn;
192/// #[macro_use] extern crate synom;
193///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700194/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500195///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700196/// fn get_cond(if_: ExprIf) -> Expr {
197/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500198/// }
199///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700200/// // Parses an `if` statement but returns the condition part only.
201/// named!(if_condition -> Expr,
202/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500203/// );
204///
205/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700206/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700207/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700209/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700210/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500211/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500212#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700213macro_rules! map {
214 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700215 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400216 ::std::result::Result::Err(err) =>
217 ::std::result::Result::Err(err),
218 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700219 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700220 }
221 };
David Tolnay1f16b602017-02-07 20:06:55 -0500222
223 ($i:expr, $f:expr, $g:expr) => {
224 map!($i, call!($f), $g)
225 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700226}
227
David Tolnaybc7d7d92017-06-03 20:54:05 -0700228// Somehow this helps with type inference in `map!`.
229//
230// Not public API.
231#[doc(hidden)]
232pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
233 f(t)
234}
235
David Tolnay1f16b602017-02-07 20:06:55 -0500236/// Parses successfully if the given parser fails to parse. Does not consume any
237/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500238///
239/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500240/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500241#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700242macro_rules! not {
243 ($i:expr, $submac:ident!( $($args:tt)* )) => {
244 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400245 ::std::result::Result::Ok(_) => $crate::parse_error(),
246 ::std::result::Result::Err(_) =>
247 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700248 }
249 };
250}
251
David Tolnay1f16b602017-02-07 20:06:55 -0500252/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500253///
David Tolnay1f16b602017-02-07 20:06:55 -0500254/// If you are familiar with nom, this is nom's `cond_with_error` parser.
255///
256/// - **Syntax:** `cond!(CONDITION, THING)`
257/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500258#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700259macro_rules! cond {
260 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
261 if $cond {
262 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400263 ::std::result::Result::Ok((i, o)) =>
264 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
265 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700266 }
267 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400268 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700269 }
David Tolnaycfe55022016-10-02 22:02:27 -0700270 };
271
272 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700273 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700274 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700275}
276
David Tolnay1f16b602017-02-07 20:06:55 -0500277/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500278///
David Tolnay1f16b602017-02-07 20:06:55 -0500279/// This is typically used inside of `option!` or `alt!`.
280///
281/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
282/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500283#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700284macro_rules! cond_reduce {
285 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
286 if $cond {
287 $submac!($i, $($args)*)
288 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400289 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700290 }
291 };
292
293 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700294 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700295 };
296}
297
David Tolnay1f16b602017-02-07 20:06:55 -0500298/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500299///
David Tolnay1f16b602017-02-07 20:06:55 -0500300/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500301/// - **Output:** `THING`
302///
303/// ```rust
304/// extern crate syn;
305/// #[macro_use] extern crate synom;
306///
307/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500308///
309/// // An expression terminated by ##.
310/// named!(expr_pound_pound -> Expr,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800311/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
David Tolnay1f16b602017-02-07 20:06:55 -0500312/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500313///
Alex Crichton954046c2017-05-30 21:49:42 -0700314/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500315/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500316#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700317macro_rules! terminated {
318 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
319 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400320 ::std::result::Result::Ok((i, (o, _))) =>
321 ::std::result::Result::Ok((i, o)),
322 ::std::result::Result::Err(err) =>
323 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700324 }
325 };
326
327 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700328 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700329 };
330
331 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700332 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700333 };
334
335 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700336 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700337 };
338}
339
David Tolnay1f16b602017-02-07 20:06:55 -0500340/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500341///
342/// - **Syntax:** `many0!(THING)`
343/// - **Output:** `Vec<THING>`
344///
David Tolnay1f16b602017-02-07 20:06:55 -0500345/// You may also be looking for:
346///
Alex Crichton954046c2017-05-30 21:49:42 -0700347/// - `call!(Delimited::parse_separated)` - zero or more values with separator
348/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
349/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500350///
Michael Layzell24645a32017-02-04 13:19:26 -0500351/// ```rust
352/// extern crate syn;
353/// #[macro_use] extern crate synom;
354///
355/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500356///
Alex Crichton954046c2017-05-30 21:49:42 -0700357/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500358///
Alex Crichton954046c2017-05-30 21:49:42 -0700359/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500360#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700361macro_rules! many0 {
362 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
363 let ret;
364 let mut res = ::std::vec::Vec::new();
365 let mut input = $i;
366
367 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400368 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400369 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700370 break;
371 }
372
373 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400374 ::std::result::Result::Err(_) => {
375 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700376 break;
377 }
Michael Layzell760fd662017-05-31 22:46:05 -0400378 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700379 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400380 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400381 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700382 break;
383 }
384
385 res.push(o);
386 input = i;
387 }
388 }
389 }
390
391 ret
392 }};
393
394 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500395 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700396 };
397}
398
David Tolnay1f16b602017-02-07 20:06:55 -0500399// Improve compile time by compiling this loop only once per type it is used
400// with.
401//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800402// Not public API.
403#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400404pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700405 let mut res = Vec::new();
406
407 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400408 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400409 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700410 }
411
412 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400413 Err(_) => {
414 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700415 }
Michael Layzell760fd662017-05-31 22:46:05 -0400416 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700417 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400418 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400419 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700420 }
421
422 res.push(o);
423 input = i;
424 }
425 }
426 }
427}
428
David Tolnay1f16b602017-02-07 20:06:55 -0500429/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500430///
431/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500432/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500433///
434/// ```rust
435/// extern crate syn;
436/// #[macro_use] extern crate synom;
437///
Alex Crichton954046c2017-05-30 21:49:42 -0700438/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500439///
David Tolnay1f16b602017-02-07 20:06:55 -0500440/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700441/// named!(ident_expr -> (Ident, Expr),
442/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500443/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500444///
Alex Crichton954046c2017-05-30 21:49:42 -0700445/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500446/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500447#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700448macro_rules! peek {
449 ($i:expr, $submac:ident!( $($args:tt)* )) => {
450 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400451 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
452 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700453 }
454 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700455
David Tolnay1f16b602017-02-07 20:06:55 -0500456 ($i:expr, $f:expr) => {
457 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700458 };
459}
460
David Tolnay1f16b602017-02-07 20:06:55 -0500461/// Pattern-match the result of a parser to select which other parser to run.
462///
463/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
464/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
465///
466/// ```rust
467/// extern crate syn;
468/// #[macro_use] extern crate synom;
469///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800470/// use syn::{Ident, Type};
David Tolnay1f16b602017-02-07 20:06:55 -0500471///
472/// #[derive(Debug)]
473/// enum UnitType {
474/// Struct {
475/// name: Ident,
476/// },
477/// Enum {
478/// name: Ident,
479/// variant: Ident,
480/// },
481/// }
482///
483/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
484/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700485/// which: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800486/// keyword!(struct) => { |_| 0 }
Alex Crichton954046c2017-05-30 21:49:42 -0700487/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800488/// keyword!(enum) => { |_| 1 }
Alex Crichton954046c2017-05-30 21:49:42 -0700489/// ) >>
490/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500491/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700492/// 0 => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800493/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500494/// move |_| UnitType::Struct {
495/// name: id,
496/// }
497/// )
498/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700499/// 1 => map!(
500/// braces!(syn!(Ident)),
501/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500502/// name: id,
503/// variant: variant,
504/// }
505/// )
David Tolnay92a56512017-11-10 00:02:14 -0800506/// |
507/// _ => reject!()
David Tolnay1f16b602017-02-07 20:06:55 -0500508/// ) >>
509/// (item)
510/// ));
511///
Alex Crichton954046c2017-05-30 21:49:42 -0700512/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500513/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500514#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700515macro_rules! switch {
516 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
517 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400518 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
519 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700520 $(
521 $p => $subrule!(i, $($args2)*),
522 )*
David Tolnayb5a7b142016-09-13 22:46:39 -0700523 }
524 }
525 };
526}
527
Alex Crichton954046c2017-05-30 21:49:42 -0700528
David Tolnay1f16b602017-02-07 20:06:55 -0500529/// Produce the given value without parsing anything. Useful as an argument to
530/// `switch!`.
531///
532/// - **Syntax:** `value!(VALUE)`
533/// - **Output:** `VALUE`
534///
535/// ```rust
536/// extern crate syn;
537/// #[macro_use] extern crate synom;
538///
David Tolnay92a56512017-11-10 00:02:14 -0800539/// use syn::Ident;
David Tolnay1f16b602017-02-07 20:06:55 -0500540///
541/// #[derive(Debug)]
542/// enum UnitType {
543/// Struct {
544/// name: Ident,
545/// },
546/// Enum {
547/// name: Ident,
548/// variant: Ident,
549/// },
550/// }
551///
552/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
553/// named!(unit_type -> UnitType, do_parse!(
David Tolnay92a56512017-11-10 00:02:14 -0800554/// is_struct: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800555/// keyword!(struct) => { |_| true }
Alex Crichton954046c2017-05-30 21:49:42 -0700556/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800557/// keyword!(enum) => { |_| false }
Alex Crichton954046c2017-05-30 21:49:42 -0700558/// ) >>
559/// id: syn!(Ident) >>
David Tolnay92a56512017-11-10 00:02:14 -0800560/// item: switch!(value!(is_struct),
561/// true => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800562/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500563/// move |_| UnitType::Struct {
564/// name: id,
565/// }
566/// )
567/// |
David Tolnay92a56512017-11-10 00:02:14 -0800568/// false => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700569/// braces!(syn!(Ident)),
570/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500571/// name: id,
572/// variant: variant,
573/// }
574/// )
575/// ) >>
576/// (item)
577/// ));
578///
Alex Crichton954046c2017-05-30 21:49:42 -0700579/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500580/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500581#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700582macro_rules! value {
583 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400584 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700585 };
586}
587
David Tolnay92a56512017-11-10 00:02:14 -0800588/// Unconditionally fail to parse anything. This may be useful in ignoring some
589/// arms of a `switch!` parser.
590///
591/// - **Syntax:** `reject!()`
592/// - **Output:** never succeeds
593///
594/// ```rust
595/// extern crate syn;
596/// #[macro_use] extern crate synom;
597///
598/// use syn::Item;
599///
600/// // Parse any item, except for a module.
601/// named!(almost_any_item -> Item,
602/// switch!(syn!(Item),
603/// Item::Mod(_) => reject!()
604/// |
605/// ok => value!(ok)
606/// )
607/// );
608///
609/// # fn main() {}
610/// ```
611#[macro_export]
612macro_rules! reject {
613 ($i:expr,) => {
614 $crate::parse_error()
615 }
616}
617
David Tolnay1f16b602017-02-07 20:06:55 -0500618/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500619///
David Tolnay1f16b602017-02-07 20:06:55 -0500620/// - **Syntax:** `tuple!(A, B, C, ...)`
621/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500622///
623/// ```rust
624/// extern crate syn;
625/// #[macro_use] extern crate synom;
626///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800627/// use syn::Type;
Michael Layzell24645a32017-02-04 13:19:26 -0500628///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800629/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
Michael Layzell24645a32017-02-04 13:19:26 -0500630///
Alex Crichton954046c2017-05-30 21:49:42 -0700631/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500632/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500633#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700634macro_rules! tuple {
635 ($i:expr, $($rest:tt)*) => {
636 tuple_parser!($i, (), $($rest)*)
637 };
638}
639
David Tolnay1f16b602017-02-07 20:06:55 -0500640/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500641#[doc(hidden)]
642#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700643macro_rules! tuple_parser {
644 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700645 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700646 };
647
648 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
649 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400650 ::std::result::Result::Err(err) =>
651 ::std::result::Result::Err(err),
652 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700653 tuple_parser!(i, (o), $($rest)*),
654 }
655 };
656
657 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
658 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400659 ::std::result::Result::Err(err) =>
660 ::std::result::Result::Err(err),
661 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700662 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
663 }
664 };
665
666 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700667 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700668 };
669
670 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
671 $submac!($i, $($args)*)
672 };
673
674 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
675 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400676 ::std::result::Result::Err(err) =>
677 ::std::result::Result::Err(err),
678 ::std::result::Result::Ok((i, o)) =>
679 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700680 }
681 };
682
683 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400684 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700685 };
686}
687
David Tolnay1f16b602017-02-07 20:06:55 -0500688/// Run a series of parsers, returning the result of the first one which
689/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500690///
691/// Optionally allows for the result to be transformed.
692///
693/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500694/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500695///
696/// ```rust
697/// extern crate syn;
698/// #[macro_use] extern crate synom;
699///
700/// use syn::Ident;
Michael Layzell24645a32017-02-04 13:19:26 -0500701///
702/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500703/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700704/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500705/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800706/// punct!(!) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500707/// )
708/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500709///
Alex Crichton954046c2017-05-30 21:49:42 -0700710/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500711/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500712#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700713macro_rules! alt {
714 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700715 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700716 };
717
718 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
719 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400720 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700721 _ => alt!($i, $($rest)*)
722 }
723 };
724
725 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
726 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400727 ::std::result::Result::Ok((i, o)) =>
728 ::std::result::Result::Ok((i, $gen(o))),
729 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700730 }
731 };
732
733 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700734 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700735 };
736
737 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700738 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700739 };
740
741 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
742 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400743 ::std::result::Result::Ok((i, o)) =>
744 ::std::result::Result::Ok((i, $gen(o))),
745 ::std::result::Result::Err(err) =>
746 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700747 }
748 };
749
750 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700751 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700752 };
753
754 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700755 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700756 };
757}
758
Michael Layzell24645a32017-02-04 13:19:26 -0500759/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500760/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500761///
David Tolnay1f16b602017-02-07 20:06:55 -0500762/// Produces the result of evaluating the final expression in parentheses with
763/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500764///
David Tolnay1f16b602017-02-07 20:06:55 -0500765/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500766/// - **Output:** `RESULT`
767///
768/// ```rust
769/// extern crate syn;
770/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700771/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500772///
773/// use syn::{Ident, TokenTree};
David Tolnayf8db7ba2017-11-11 22:52:16 -0800774/// use synom::tokens::Paren;
Alex Crichton954046c2017-05-30 21:49:42 -0700775/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500776///
David Tolnay1f16b602017-02-07 20:06:55 -0500777/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700778/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
779/// name: syn!(Ident) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800780/// punct!(!) >>
Alex Crichton954046c2017-05-30 21:49:42 -0700781/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500782/// (name, body)
783/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500784///
Alex Crichton954046c2017-05-30 21:49:42 -0700785/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500786/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500787#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700788macro_rules! do_parse {
789 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400790 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700791 };
792
793 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700794 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700795 };
796
797 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
798 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400799 ::std::result::Result::Err(err) =>
800 ::std::result::Result::Err(err),
801 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700802 do_parse!(i, $($rest)*),
803 }
804 };
805
806 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700807 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700808 };
809
810 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
811 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400812 ::std::result::Result::Err(err) =>
813 ::std::result::Result::Err(err),
814 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700815 let $field = o;
816 do_parse!(i, $($rest)*)
817 },
818 }
819 };
820
David Tolnayfa0edf22016-09-23 22:58:24 -0700821 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700822 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700823 };
824
825 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
826 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400827 ::std::result::Result::Err(err) =>
828 ::std::result::Result::Err(err),
829 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700830 let mut $field = o;
831 do_parse!(i, $($rest)*)
832 },
833 }
834 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700835}
Michael Layzell416724e2017-05-24 21:12:34 -0400836
837#[macro_export]
838macro_rules! input_end {
839 ($i:expr,) => {
840 $crate::input_end($i)
841 };
842}
843
844// Not a public API
845#[doc(hidden)]
David Tolnay1fc4e492017-11-11 22:17:22 -0800846pub fn input_end(input: Cursor) -> PResult<'static, ()> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400847 if input.eof() {
David Tolnay1fc4e492017-11-11 22:17:22 -0800848 Ok((Cursor::empty(), ()))
Michael Layzell416724e2017-05-24 21:12:34 -0400849 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400850 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400851 }
852}