blob: 8ca6dc702b6826f1222f544e6d7b3e05a0f0235e [file] [log] [blame]
David Tolnayc5ab8c62017-12-26 16:43:39 -05001use cursor::Cursor;
David Tolnay51382052017-12-27 13:46:21 -05002use error::{parse_error, PResult};
Alex Crichton7b9e02f2017-05-30 15:54:33 -07003
Michael Layzell24645a32017-02-04 13:19:26 -05004/// Define a function from a parser combination.
5///
David Tolnay1f16b602017-02-07 20:06:55 -05006/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
7///
8/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -05009/// # #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -050010/// # extern crate syn;
David Tolnayc5ab8c62017-12-26 16:43:39 -050011/// #
David Tolnayfd6bf5c2017-11-12 09:41:14 -080012/// # use syn::Type;
David Tolnayc5ab8c62017-12-26 16:43:39 -050013/// # use syn::delimited::Delimited;
14/// #
David Tolnay1f16b602017-02-07 20:06:55 -050015/// // One or more Rust types separated by commas.
David Tolnayfd6bf5c2017-11-12 09:41:14 -080016/// named!(pub comma_separated_types -> Delimited<Type, Token![,]>,
Alex Crichton954046c2017-05-30 21:49:42 -070017/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -050018/// );
19/// # fn main() {}
20/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050021#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070022macro_rules! named {
23 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -050024 fn $name(i: $crate::synom::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070025 $submac!(i, $($args)*)
26 }
27 };
28
29 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -050030 pub fn $name(i: $crate::synom::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070031 $submac!(i, $($args)*)
32 }
33 };
Michael Layzellf8334e32017-06-04 19:01:08 -040034
35 // These two variants are for defining named parsers which have custom
36 // arguments, and are called with `call!()`
37 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -050038 fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::PResult<$o> {
Michael Layzellf8334e32017-06-04 19:01:08 -040039 $submac!(i, $($args)*)
40 }
41 };
42
43 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -050044 pub fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::PResult<$o> {
Michael Layzellf8334e32017-06-04 19:01:08 -040045 $submac!(i, $($args)*)
46 }
47 };
David Tolnayb5a7b142016-09-13 22:46:39 -070048}
49
David Tolnayc5ab8c62017-12-26 16:43:39 -050050#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
Nika Layzellae81b372017-12-05 14:12:33 -050051#[macro_export]
52macro_rules! call {
53 ($i:expr, $fun:expr $(, $args:expr)*) => {
54 {
55 let i = $i;
56 eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
57 let r = $fun(i $(, $args)*);
58 match r {
59 Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
60 Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
61 }
62 r
63 }
64 };
65}
66
David Tolnay1f16b602017-02-07 20:06:55 -050067/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -050068///
69/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -050070///
Michael Layzell760fd662017-05-31 22:46:05 -040071/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -050072/// - **Output:** `T`, the result of invoking the function `FUNCTION`
David Tolnayc5ab8c62017-12-26 16:43:39 -050073#[cfg(any(not(feature = "verbose-trace"), feature = "all-features"))]
Michael Layzell5bde96f2017-01-24 17:59:21 -050074#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070075macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -070076 ($i:expr, $fun:expr $(, $args:expr)*) => {
77 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -070078 };
79}
80
David Tolnay1f16b602017-02-07 20:06:55 -050081/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -050082///
David Tolnay1f16b602017-02-07 20:06:55 -050083/// - **Syntax:** `map!(THING, FN)`
84/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -050085///
86/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -050087/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -050088/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -050089///
David Tolnayb21bb0c2017-06-03 20:39:19 -070090/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -050091///
David Tolnayb21bb0c2017-06-03 20:39:19 -070092/// fn get_cond(if_: ExprIf) -> Expr {
93/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -050094/// }
95///
David Tolnayb21bb0c2017-06-03 20:39:19 -070096/// // Parses an `if` statement but returns the condition part only.
97/// named!(if_condition -> Expr,
98/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -050099/// );
100///
101/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700102/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700103/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500104/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700105/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700106/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500107/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500108#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700109macro_rules! map {
110 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700111 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400112 ::std::result::Result::Err(err) =>
113 ::std::result::Result::Err(err),
114 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500115 ::std::result::Result::Ok((i, $crate::parsers::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700116 }
117 };
David Tolnay1f16b602017-02-07 20:06:55 -0500118
119 ($i:expr, $f:expr, $g:expr) => {
120 map!($i, call!($f), $g)
121 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700122}
123
David Tolnay995bff22017-12-17 23:44:43 -0800124// Somehow this helps with type inference in `map!` and `alt!`.
David Tolnaybc7d7d92017-06-03 20:54:05 -0700125//
126// Not public API.
127#[doc(hidden)]
128pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
129 f(t)
130}
131
David Tolnay1f16b602017-02-07 20:06:55 -0500132/// Parses successfully if the given parser fails to parse. Does not consume any
133/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500134///
135/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500136/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500137#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700138macro_rules! not {
139 ($i:expr, $submac:ident!( $($args:tt)* )) => {
140 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400141 ::std::result::Result::Ok(_) => $crate::parse_error(),
142 ::std::result::Result::Err(_) =>
143 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700144 }
145 };
146}
147
David Tolnay1f16b602017-02-07 20:06:55 -0500148/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500149///
David Tolnay1f16b602017-02-07 20:06:55 -0500150/// If you are familiar with nom, this is nom's `cond_with_error` parser.
151///
152/// - **Syntax:** `cond!(CONDITION, THING)`
153/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500154#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700155macro_rules! cond {
156 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
157 if $cond {
158 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400159 ::std::result::Result::Ok((i, o)) =>
160 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
161 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700162 }
163 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400164 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700165 }
David Tolnaycfe55022016-10-02 22:02:27 -0700166 };
167
168 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700169 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700170 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700171}
172
David Tolnay1f16b602017-02-07 20:06:55 -0500173/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500174///
David Tolnay1f16b602017-02-07 20:06:55 -0500175/// This is typically used inside of `option!` or `alt!`.
176///
177/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
178/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500179#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700180macro_rules! cond_reduce {
181 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
182 if $cond {
183 $submac!($i, $($args)*)
184 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400185 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700186 }
187 };
188
189 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700190 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700191 };
192}
193
David Tolnay1f16b602017-02-07 20:06:55 -0500194/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500195///
David Tolnay1f16b602017-02-07 20:06:55 -0500196/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500197/// - **Output:** `THING`
198///
199/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500200/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500201/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500202///
203/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500204///
205/// // An expression terminated by ##.
206/// named!(expr_pound_pound -> Expr,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800207/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500209///
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! terminated {
214 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
215 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400216 ::std::result::Result::Ok((i, (o, _))) =>
217 ::std::result::Result::Ok((i, o)),
218 ::std::result::Result::Err(err) =>
219 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700220 }
221 };
222
223 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700224 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700225 };
226
227 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700228 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700229 };
230
231 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700232 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700233 };
234}
235
David Tolnay1f16b602017-02-07 20:06:55 -0500236/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500237///
238/// - **Syntax:** `many0!(THING)`
239/// - **Output:** `Vec<THING>`
240///
David Tolnay1f16b602017-02-07 20:06:55 -0500241/// You may also be looking for:
242///
Alex Crichton954046c2017-05-30 21:49:42 -0700243/// - `call!(Delimited::parse_separated)` - zero or more values with separator
244/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
245/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500246///
Michael Layzell24645a32017-02-04 13:19:26 -0500247/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500248/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500249/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500250///
251/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500252///
Alex Crichton954046c2017-05-30 21:49:42 -0700253/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500254///
Alex Crichton954046c2017-05-30 21:49:42 -0700255/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500256#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700257macro_rules! many0 {
258 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
259 let ret;
260 let mut res = ::std::vec::Vec::new();
261 let mut input = $i;
262
263 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400264 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400265 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700266 break;
267 }
268
269 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400270 ::std::result::Result::Err(_) => {
271 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700272 break;
273 }
Michael Layzell760fd662017-05-31 22:46:05 -0400274 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700275 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400276 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400277 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700278 break;
279 }
280
281 res.push(o);
282 input = i;
283 }
284 }
285 }
286
287 ret
288 }};
289
290 ($i:expr, $f:expr) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -0500291 $crate::parsers::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700292 };
293}
294
David Tolnay1f16b602017-02-07 20:06:55 -0500295// Improve compile time by compiling this loop only once per type it is used
296// with.
297//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800298// Not public API.
299#[doc(hidden)]
David Tolnay1c03d8c2017-12-26 23:17:06 -0500300pub fn many0<T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700301 let mut res = Vec::new();
302
303 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400304 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400305 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700306 }
307
308 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400309 Err(_) => {
310 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700311 }
Michael Layzell760fd662017-05-31 22:46:05 -0400312 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700313 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400314 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400315 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700316 }
317
318 res.push(o);
319 input = i;
320 }
321 }
322 }
323}
324
David Tolnay1f16b602017-02-07 20:06:55 -0500325/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500326///
327/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500328/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500329///
330/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500331/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500332/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500333///
Alex Crichton954046c2017-05-30 21:49:42 -0700334/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500335///
David Tolnay1f16b602017-02-07 20:06:55 -0500336/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700337/// named!(ident_expr -> (Ident, Expr),
338/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500339/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500340///
Alex Crichton954046c2017-05-30 21:49:42 -0700341/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500342/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500343#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700344macro_rules! peek {
345 ($i:expr, $submac:ident!( $($args:tt)* )) => {
346 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400347 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
348 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700349 }
350 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700351
David Tolnay1f16b602017-02-07 20:06:55 -0500352 ($i:expr, $f:expr) => {
353 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700354 };
355}
356
David Tolnay1f16b602017-02-07 20:06:55 -0500357/// Pattern-match the result of a parser to select which other parser to run.
358///
359/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
360/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
361///
362/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500363/// #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -0500364/// extern crate syn;
David Tolnay1f16b602017-02-07 20:06:55 -0500365///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800366/// use syn::{Ident, Type};
David Tolnay1f16b602017-02-07 20:06:55 -0500367///
368/// #[derive(Debug)]
369/// enum UnitType {
370/// Struct {
371/// name: Ident,
372/// },
373/// Enum {
374/// name: Ident,
375/// variant: Ident,
376/// },
377/// }
378///
379/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
380/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700381/// which: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800382/// keyword!(struct) => { |_| 0 }
Alex Crichton954046c2017-05-30 21:49:42 -0700383/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800384/// keyword!(enum) => { |_| 1 }
Alex Crichton954046c2017-05-30 21:49:42 -0700385/// ) >>
386/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500387/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700388/// 0 => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800389/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500390/// move |_| UnitType::Struct {
391/// name: id,
392/// }
393/// )
394/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700395/// 1 => map!(
396/// braces!(syn!(Ident)),
397/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500398/// name: id,
399/// variant: variant,
400/// }
401/// )
David Tolnay92a56512017-11-10 00:02:14 -0800402/// |
403/// _ => reject!()
David Tolnay1f16b602017-02-07 20:06:55 -0500404/// ) >>
405/// (item)
406/// ));
407///
Alex Crichton954046c2017-05-30 21:49:42 -0700408/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500409/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500410#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700411macro_rules! switch {
412 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
413 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400414 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
415 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700416 $(
417 $p => $subrule!(i, $($args2)*),
418 )*
David Tolnayb5a7b142016-09-13 22:46:39 -0700419 }
420 }
421 };
422}
423
David Tolnay1f16b602017-02-07 20:06:55 -0500424/// Produce the given value without parsing anything. Useful as an argument to
425/// `switch!`.
426///
427/// - **Syntax:** `value!(VALUE)`
428/// - **Output:** `VALUE`
429///
430/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500431/// #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -0500432/// extern crate syn;
David Tolnay1f16b602017-02-07 20:06:55 -0500433///
David Tolnay92a56512017-11-10 00:02:14 -0800434/// use syn::Ident;
David Tolnay1f16b602017-02-07 20:06:55 -0500435///
436/// #[derive(Debug)]
437/// enum UnitType {
438/// Struct {
439/// name: Ident,
440/// },
441/// Enum {
442/// name: Ident,
443/// variant: Ident,
444/// },
445/// }
446///
447/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
448/// named!(unit_type -> UnitType, do_parse!(
David Tolnay92a56512017-11-10 00:02:14 -0800449/// is_struct: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800450/// keyword!(struct) => { |_| true }
Alex Crichton954046c2017-05-30 21:49:42 -0700451/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800452/// keyword!(enum) => { |_| false }
Alex Crichton954046c2017-05-30 21:49:42 -0700453/// ) >>
454/// id: syn!(Ident) >>
David Tolnay92a56512017-11-10 00:02:14 -0800455/// item: switch!(value!(is_struct),
456/// true => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800457/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500458/// move |_| UnitType::Struct {
459/// name: id,
460/// }
461/// )
462/// |
David Tolnay92a56512017-11-10 00:02:14 -0800463/// false => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700464/// braces!(syn!(Ident)),
465/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500466/// name: id,
467/// variant: variant,
468/// }
469/// )
470/// ) >>
471/// (item)
472/// ));
473///
Alex Crichton954046c2017-05-30 21:49:42 -0700474/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500475/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500476#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700477macro_rules! value {
478 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400479 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700480 };
481}
482
David Tolnay92a56512017-11-10 00:02:14 -0800483/// Unconditionally fail to parse anything. This may be useful in ignoring some
484/// arms of a `switch!` parser.
485///
486/// - **Syntax:** `reject!()`
487/// - **Output:** never succeeds
488///
489/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500490/// #[macro_use]
David Tolnay92a56512017-11-10 00:02:14 -0800491/// extern crate syn;
David Tolnay92a56512017-11-10 00:02:14 -0800492///
493/// use syn::Item;
494///
495/// // Parse any item, except for a module.
496/// named!(almost_any_item -> Item,
497/// switch!(syn!(Item),
498/// Item::Mod(_) => reject!()
499/// |
500/// ok => value!(ok)
501/// )
502/// );
503///
504/// # fn main() {}
505/// ```
506#[macro_export]
507macro_rules! reject {
David Tolnay2bd17422017-12-25 18:44:20 -0500508 ($i:expr,) => {{
509 let _ = $i;
David Tolnay92a56512017-11-10 00:02:14 -0800510 $crate::parse_error()
David Tolnay2bd17422017-12-25 18:44:20 -0500511 }}
David Tolnay92a56512017-11-10 00:02:14 -0800512}
513
David Tolnay1f16b602017-02-07 20:06:55 -0500514/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500515///
David Tolnay1f16b602017-02-07 20:06:55 -0500516/// - **Syntax:** `tuple!(A, B, C, ...)`
517/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500518///
519/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500520/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500521/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500522///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800523/// use syn::Type;
Michael Layzell24645a32017-02-04 13:19:26 -0500524///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800525/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
Michael Layzell24645a32017-02-04 13:19:26 -0500526///
Alex Crichton954046c2017-05-30 21:49:42 -0700527/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500528/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500529#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700530macro_rules! tuple {
531 ($i:expr, $($rest:tt)*) => {
532 tuple_parser!($i, (), $($rest)*)
533 };
534}
535
David Tolnay1f16b602017-02-07 20:06:55 -0500536/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500537#[doc(hidden)]
538#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700539macro_rules! tuple_parser {
540 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700541 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700542 };
543
544 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
545 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400546 ::std::result::Result::Err(err) =>
547 ::std::result::Result::Err(err),
548 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700549 tuple_parser!(i, (o), $($rest)*),
550 }
551 };
552
553 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
554 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400555 ::std::result::Result::Err(err) =>
556 ::std::result::Result::Err(err),
557 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700558 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
559 }
560 };
561
562 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700563 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700564 };
565
566 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
567 $submac!($i, $($args)*)
568 };
569
570 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
571 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400572 ::std::result::Result::Err(err) =>
573 ::std::result::Result::Err(err),
574 ::std::result::Result::Ok((i, o)) =>
575 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700576 }
577 };
578
579 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400580 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700581 };
582}
583
David Tolnay1f16b602017-02-07 20:06:55 -0500584/// Run a series of parsers, returning the result of the first one which
585/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500586///
587/// Optionally allows for the result to be transformed.
588///
589/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500590/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500591///
592/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500593/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500594/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500595///
596/// use syn::Ident;
Michael Layzell24645a32017-02-04 13:19:26 -0500597///
598/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500599/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700600/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500601/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800602/// punct!(!) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500603/// )
604/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500605///
Alex Crichton954046c2017-05-30 21:49:42 -0700606/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500607/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500608#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700609macro_rules! alt {
610 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700611 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700612 };
613
614 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
615 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400616 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700617 _ => alt!($i, $($rest)*)
618 }
619 };
620
621 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
622 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400623 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500624 ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
Michael Layzell760fd662017-05-31 22:46:05 -0400625 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700626 }
627 };
628
629 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700630 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700631 };
632
633 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700634 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700635 };
636
637 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
638 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400639 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500640 ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
Michael Layzell760fd662017-05-31 22:46:05 -0400641 ::std::result::Result::Err(err) =>
642 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700643 }
644 };
645
646 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700647 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700648 };
649
650 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700651 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700652 };
653}
654
Michael Layzell24645a32017-02-04 13:19:26 -0500655/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500656/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500657///
David Tolnay1f16b602017-02-07 20:06:55 -0500658/// Produces the result of evaluating the final expression in parentheses with
659/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500660///
David Tolnay1f16b602017-02-07 20:06:55 -0500661/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500662/// - **Output:** `RESULT`
663///
664/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500665/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500666/// extern crate syn;
Alex Crichton954046c2017-05-30 21:49:42 -0700667/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500668///
David Tolnay9c76bcb2017-12-26 23:14:59 -0500669/// use syn::Ident;
David Tolnay32954ef2017-12-26 22:43:16 -0500670/// use syn::token::Paren;
Alex Crichton954046c2017-05-30 21:49:42 -0700671/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500672///
David Tolnay1f16b602017-02-07 20:06:55 -0500673/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700674/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
675/// name: syn!(Ident) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800676/// punct!(!) >>
Alex Crichton954046c2017-05-30 21:49:42 -0700677/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500678/// (name, body)
679/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500680///
Alex Crichton954046c2017-05-30 21:49:42 -0700681/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500682/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500683#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700684macro_rules! do_parse {
685 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400686 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700687 };
688
689 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700690 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700691 };
692
693 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
694 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400695 ::std::result::Result::Err(err) =>
696 ::std::result::Result::Err(err),
697 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700698 do_parse!(i, $($rest)*),
699 }
700 };
701
702 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700703 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700704 };
705
706 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
707 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400708 ::std::result::Result::Err(err) =>
709 ::std::result::Result::Err(err),
710 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700711 let $field = o;
712 do_parse!(i, $($rest)*)
713 },
714 }
715 };
716
David Tolnayfa0edf22016-09-23 22:58:24 -0700717 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700718 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700719 };
720
721 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
722 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400723 ::std::result::Result::Err(err) =>
724 ::std::result::Result::Err(err),
725 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700726 let mut $field = o;
727 do_parse!(i, $($rest)*)
728 },
729 }
730 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700731}
Michael Layzell416724e2017-05-24 21:12:34 -0400732
733#[macro_export]
734macro_rules! input_end {
735 ($i:expr,) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -0500736 $crate::parsers::input_end($i)
Michael Layzell416724e2017-05-24 21:12:34 -0400737 };
738}
739
740// Not a public API
741#[doc(hidden)]
David Tolnay1fc4e492017-11-11 22:17:22 -0800742pub fn input_end(input: Cursor) -> PResult<'static, ()> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400743 if input.eof() {
David Tolnay1fc4e492017-11-11 22:17:22 -0800744 Ok((Cursor::empty(), ()))
Michael Layzell416724e2017-05-24 21:12:34 -0400745 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400746 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400747 }
748}