blob: 2817a51c260039d4d5000dba40d19ac328d005b3 [file] [log] [blame]
David Tolnayc5ab8c62017-12-26 16:43:39 -05001use cursor::Cursor;
David Tolnay203557a2017-12-27 23:59:33 -05002use parse_error;
3use synom::PResult;
Alex Crichton7b9e02f2017-05-30 15:54:33 -07004
Michael Layzell24645a32017-02-04 13:19:26 -05005/// Define a function from a parser combination.
6///
David Tolnay1f16b602017-02-07 20:06:55 -05007/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
8///
9/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -050010/// # #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -050011/// # extern crate syn;
David Tolnayc5ab8c62017-12-26 16:43:39 -050012/// #
David Tolnayfd6bf5c2017-11-12 09:41:14 -080013/// # use syn::Type;
David Tolnayc5ab8c62017-12-26 16:43:39 -050014/// # use syn::delimited::Delimited;
15/// #
David Tolnay1f16b602017-02-07 20:06:55 -050016/// // One or more Rust types separated by commas.
David Tolnayfd6bf5c2017-11-12 09:41:14 -080017/// named!(pub comma_separated_types -> Delimited<Type, Token![,]>,
Alex Crichton954046c2017-05-30 21:49:42 -070018/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -050019/// );
20/// # fn main() {}
21/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050022#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070023macro_rules! named {
24 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnay203557a2017-12-27 23:59:33 -050025 fn $name(i: $crate::synom::Cursor) -> $crate::synom::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070026 $submac!(i, $($args)*)
27 }
28 };
29
30 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnay203557a2017-12-27 23:59:33 -050031 pub fn $name(i: $crate::synom::Cursor) -> $crate::synom::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070032 $submac!(i, $($args)*)
33 }
34 };
Michael Layzellf8334e32017-06-04 19:01:08 -040035
36 // These two variants are for defining named parsers which have custom
37 // arguments, and are called with `call!()`
38 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnay203557a2017-12-27 23:59:33 -050039 fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::synom::PResult<$o> {
Michael Layzellf8334e32017-06-04 19:01:08 -040040 $submac!(i, $($args)*)
41 }
42 };
43
44 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
David Tolnay203557a2017-12-27 23:59:33 -050045 pub fn $name(i: $crate::synom::Cursor, $($params)*) -> $crate::synom::PResult<$o> {
Michael Layzellf8334e32017-06-04 19:01:08 -040046 $submac!(i, $($args)*)
47 }
48 };
David Tolnayb5a7b142016-09-13 22:46:39 -070049}
50
David Tolnayc5ab8c62017-12-26 16:43:39 -050051#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
Nika Layzellae81b372017-12-05 14:12:33 -050052#[macro_export]
53macro_rules! call {
54 ($i:expr, $fun:expr $(, $args:expr)*) => {
55 {
56 let i = $i;
57 eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
58 let r = $fun(i $(, $args)*);
59 match r {
60 Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
61 Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
62 }
63 r
64 }
65 };
66}
67
David Tolnay1f16b602017-02-07 20:06:55 -050068/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -050069///
70/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -050071///
Michael Layzell760fd662017-05-31 22:46:05 -040072/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -050073/// - **Output:** `T`, the result of invoking the function `FUNCTION`
David Tolnayc5ab8c62017-12-26 16:43:39 -050074#[cfg(any(not(feature = "verbose-trace"), feature = "all-features"))]
Michael Layzell5bde96f2017-01-24 17:59:21 -050075#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070076macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -070077 ($i:expr, $fun:expr $(, $args:expr)*) => {
78 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -070079 };
80}
81
David Tolnay1f16b602017-02-07 20:06:55 -050082/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -050083///
David Tolnay1f16b602017-02-07 20:06:55 -050084/// - **Syntax:** `map!(THING, FN)`
85/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -050086///
87/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -050088/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -050089/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -050090///
David Tolnayb21bb0c2017-06-03 20:39:19 -070091/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -050092///
David Tolnayb21bb0c2017-06-03 20:39:19 -070093/// fn get_cond(if_: ExprIf) -> Expr {
94/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -050095/// }
96///
David Tolnayb21bb0c2017-06-03 20:39:19 -070097/// // Parses an `if` statement but returns the condition part only.
98/// named!(if_condition -> Expr,
99/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500100/// );
101///
102/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700103/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700104/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500105/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700106/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700107/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500108/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500109#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700110macro_rules! map {
111 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700112 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400113 ::std::result::Result::Err(err) =>
114 ::std::result::Result::Err(err),
115 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500116 ::std::result::Result::Ok((i, $crate::parsers::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700117 }
118 };
David Tolnay1f16b602017-02-07 20:06:55 -0500119
120 ($i:expr, $f:expr, $g:expr) => {
121 map!($i, call!($f), $g)
122 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700123}
124
David Tolnay995bff22017-12-17 23:44:43 -0800125// Somehow this helps with type inference in `map!` and `alt!`.
David Tolnaybc7d7d92017-06-03 20:54:05 -0700126//
127// Not public API.
128#[doc(hidden)]
129pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
130 f(t)
131}
132
David Tolnay1f16b602017-02-07 20:06:55 -0500133/// Parses successfully if the given parser fails to parse. Does not consume any
134/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500135///
136/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500137/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500138#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700139macro_rules! not {
140 ($i:expr, $submac:ident!( $($args:tt)* )) => {
141 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400142 ::std::result::Result::Ok(_) => $crate::parse_error(),
143 ::std::result::Result::Err(_) =>
144 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700145 }
146 };
147}
148
David Tolnay1f16b602017-02-07 20:06:55 -0500149/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500150///
David Tolnay1f16b602017-02-07 20:06:55 -0500151/// If you are familiar with nom, this is nom's `cond_with_error` parser.
152///
153/// - **Syntax:** `cond!(CONDITION, THING)`
154/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500155#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700156macro_rules! cond {
157 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
158 if $cond {
159 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400160 ::std::result::Result::Ok((i, o)) =>
161 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
162 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700163 }
164 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400165 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700166 }
David Tolnaycfe55022016-10-02 22:02:27 -0700167 };
168
169 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700170 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700171 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700172}
173
David Tolnay1f16b602017-02-07 20:06:55 -0500174/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500175///
David Tolnay1f16b602017-02-07 20:06:55 -0500176/// This is typically used inside of `option!` or `alt!`.
177///
178/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
179/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500180#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700181macro_rules! cond_reduce {
182 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
183 if $cond {
184 $submac!($i, $($args)*)
185 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400186 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700187 }
188 };
189
190 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700191 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700192 };
193}
194
David Tolnay1f16b602017-02-07 20:06:55 -0500195/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500196///
David Tolnay1f16b602017-02-07 20:06:55 -0500197/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500198/// - **Output:** `THING`
199///
200/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500201/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500202/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500203///
204/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500205///
206/// // An expression terminated by ##.
207/// named!(expr_pound_pound -> Expr,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800208/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
David Tolnay1f16b602017-02-07 20:06:55 -0500209/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500210///
Alex Crichton954046c2017-05-30 21:49:42 -0700211/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500212/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500213#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700214macro_rules! terminated {
215 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
216 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400217 ::std::result::Result::Ok((i, (o, _))) =>
218 ::std::result::Result::Ok((i, o)),
219 ::std::result::Result::Err(err) =>
220 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700221 }
222 };
223
224 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700225 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700226 };
227
228 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700229 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700230 };
231
232 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700233 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700234 };
235}
236
David Tolnay1f16b602017-02-07 20:06:55 -0500237/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500238///
239/// - **Syntax:** `many0!(THING)`
240/// - **Output:** `Vec<THING>`
241///
David Tolnay1f16b602017-02-07 20:06:55 -0500242/// You may also be looking for:
243///
Alex Crichton954046c2017-05-30 21:49:42 -0700244/// - `call!(Delimited::parse_separated)` - zero or more values with separator
245/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
246/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500247///
Michael Layzell24645a32017-02-04 13:19:26 -0500248/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500249/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500250/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500251///
252/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500253///
Alex Crichton954046c2017-05-30 21:49:42 -0700254/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500255///
Alex Crichton954046c2017-05-30 21:49:42 -0700256/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500257#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700258macro_rules! many0 {
259 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
260 let ret;
261 let mut res = ::std::vec::Vec::new();
262 let mut input = $i;
263
264 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400265 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400266 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700267 break;
268 }
269
270 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400271 ::std::result::Result::Err(_) => {
272 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700273 break;
274 }
Michael Layzell760fd662017-05-31 22:46:05 -0400275 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700276 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400277 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400278 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700279 break;
280 }
281
282 res.push(o);
283 input = i;
284 }
285 }
286 }
287
288 ret
289 }};
290
291 ($i:expr, $f:expr) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -0500292 $crate::parsers::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700293 };
294}
295
David Tolnay1f16b602017-02-07 20:06:55 -0500296// Improve compile time by compiling this loop only once per type it is used
297// with.
298//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800299// Not public API.
300#[doc(hidden)]
David Tolnay1c03d8c2017-12-26 23:17:06 -0500301pub fn many0<T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700302 let mut res = Vec::new();
303
304 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400305 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400306 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700307 }
308
309 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400310 Err(_) => {
311 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700312 }
Michael Layzell760fd662017-05-31 22:46:05 -0400313 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700314 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400315 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400316 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700317 }
318
319 res.push(o);
320 input = i;
321 }
322 }
323 }
324}
325
David Tolnay1f16b602017-02-07 20:06:55 -0500326/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500327///
328/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500329/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500330///
331/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500332/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500333/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500334///
Alex Crichton954046c2017-05-30 21:49:42 -0700335/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500336///
David Tolnay1f16b602017-02-07 20:06:55 -0500337/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700338/// named!(ident_expr -> (Ident, Expr),
339/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500340/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500341///
Alex Crichton954046c2017-05-30 21:49:42 -0700342/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500343/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500344#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700345macro_rules! peek {
346 ($i:expr, $submac:ident!( $($args:tt)* )) => {
347 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400348 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
349 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700350 }
351 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700352
David Tolnay1f16b602017-02-07 20:06:55 -0500353 ($i:expr, $f:expr) => {
354 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700355 };
356}
357
David Tolnay1f16b602017-02-07 20:06:55 -0500358/// Pattern-match the result of a parser to select which other parser to run.
359///
360/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
361/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
362///
363/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500364/// #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -0500365/// extern crate syn;
David Tolnay1f16b602017-02-07 20:06:55 -0500366///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800367/// use syn::{Ident, Type};
David Tolnay1f16b602017-02-07 20:06:55 -0500368///
369/// #[derive(Debug)]
370/// enum UnitType {
371/// Struct {
372/// name: Ident,
373/// },
374/// Enum {
375/// name: Ident,
376/// variant: Ident,
377/// },
378/// }
379///
380/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
381/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700382/// which: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800383/// keyword!(struct) => { |_| 0 }
Alex Crichton954046c2017-05-30 21:49:42 -0700384/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800385/// keyword!(enum) => { |_| 1 }
Alex Crichton954046c2017-05-30 21:49:42 -0700386/// ) >>
387/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500388/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700389/// 0 => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800390/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500391/// move |_| UnitType::Struct {
392/// name: id,
393/// }
394/// )
395/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700396/// 1 => map!(
397/// braces!(syn!(Ident)),
398/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500399/// name: id,
400/// variant: variant,
401/// }
402/// )
David Tolnay92a56512017-11-10 00:02:14 -0800403/// |
404/// _ => reject!()
David Tolnay1f16b602017-02-07 20:06:55 -0500405/// ) >>
406/// (item)
407/// ));
408///
Alex Crichton954046c2017-05-30 21:49:42 -0700409/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500410/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500411#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700412macro_rules! switch {
413 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
414 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400415 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
416 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700417 $(
418 $p => $subrule!(i, $($args2)*),
419 )*
David Tolnayb5a7b142016-09-13 22:46:39 -0700420 }
421 }
422 };
423}
424
David Tolnay1f16b602017-02-07 20:06:55 -0500425/// Produce the given value without parsing anything. Useful as an argument to
426/// `switch!`.
427///
428/// - **Syntax:** `value!(VALUE)`
429/// - **Output:** `VALUE`
430///
431/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500432/// #[macro_use]
David Tolnay1f16b602017-02-07 20:06:55 -0500433/// extern crate syn;
David Tolnay1f16b602017-02-07 20:06:55 -0500434///
David Tolnay92a56512017-11-10 00:02:14 -0800435/// use syn::Ident;
David Tolnay1f16b602017-02-07 20:06:55 -0500436///
437/// #[derive(Debug)]
438/// enum UnitType {
439/// Struct {
440/// name: Ident,
441/// },
442/// Enum {
443/// name: Ident,
444/// variant: Ident,
445/// },
446/// }
447///
448/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
449/// named!(unit_type -> UnitType, do_parse!(
David Tolnay92a56512017-11-10 00:02:14 -0800450/// is_struct: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800451/// keyword!(struct) => { |_| true }
Alex Crichton954046c2017-05-30 21:49:42 -0700452/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800453/// keyword!(enum) => { |_| false }
Alex Crichton954046c2017-05-30 21:49:42 -0700454/// ) >>
455/// id: syn!(Ident) >>
David Tolnay92a56512017-11-10 00:02:14 -0800456/// item: switch!(value!(is_struct),
457/// true => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800458/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500459/// move |_| UnitType::Struct {
460/// name: id,
461/// }
462/// )
463/// |
David Tolnay92a56512017-11-10 00:02:14 -0800464/// false => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700465/// braces!(syn!(Ident)),
466/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500467/// name: id,
468/// variant: variant,
469/// }
470/// )
471/// ) >>
472/// (item)
473/// ));
474///
Alex Crichton954046c2017-05-30 21:49:42 -0700475/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500476/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500477#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700478macro_rules! value {
479 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400480 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700481 };
482}
483
David Tolnay92a56512017-11-10 00:02:14 -0800484/// Unconditionally fail to parse anything. This may be useful in ignoring some
485/// arms of a `switch!` parser.
486///
487/// - **Syntax:** `reject!()`
488/// - **Output:** never succeeds
489///
490/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500491/// #[macro_use]
David Tolnay92a56512017-11-10 00:02:14 -0800492/// extern crate syn;
David Tolnay92a56512017-11-10 00:02:14 -0800493///
494/// use syn::Item;
495///
496/// // Parse any item, except for a module.
497/// named!(almost_any_item -> Item,
498/// switch!(syn!(Item),
499/// Item::Mod(_) => reject!()
500/// |
501/// ok => value!(ok)
502/// )
503/// );
504///
505/// # fn main() {}
506/// ```
507#[macro_export]
508macro_rules! reject {
David Tolnay2bd17422017-12-25 18:44:20 -0500509 ($i:expr,) => {{
510 let _ = $i;
David Tolnay92a56512017-11-10 00:02:14 -0800511 $crate::parse_error()
David Tolnay2bd17422017-12-25 18:44:20 -0500512 }}
David Tolnay92a56512017-11-10 00:02:14 -0800513}
514
David Tolnay1f16b602017-02-07 20:06:55 -0500515/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500516///
David Tolnay1f16b602017-02-07 20:06:55 -0500517/// - **Syntax:** `tuple!(A, B, C, ...)`
518/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500519///
520/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500521/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500522/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500523///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800524/// use syn::Type;
Michael Layzell24645a32017-02-04 13:19:26 -0500525///
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800526/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
Michael Layzell24645a32017-02-04 13:19:26 -0500527///
Alex Crichton954046c2017-05-30 21:49:42 -0700528/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500529/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500530#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700531macro_rules! tuple {
532 ($i:expr, $($rest:tt)*) => {
533 tuple_parser!($i, (), $($rest)*)
534 };
535}
536
David Tolnay1f16b602017-02-07 20:06:55 -0500537/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500538#[doc(hidden)]
539#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700540macro_rules! tuple_parser {
541 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700542 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700543 };
544
545 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
546 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400547 ::std::result::Result::Err(err) =>
548 ::std::result::Result::Err(err),
549 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700550 tuple_parser!(i, (o), $($rest)*),
551 }
552 };
553
554 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
555 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400556 ::std::result::Result::Err(err) =>
557 ::std::result::Result::Err(err),
558 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700559 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
560 }
561 };
562
563 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700564 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700565 };
566
567 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
568 $submac!($i, $($args)*)
569 };
570
571 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
572 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400573 ::std::result::Result::Err(err) =>
574 ::std::result::Result::Err(err),
575 ::std::result::Result::Ok((i, o)) =>
576 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700577 }
578 };
579
580 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400581 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700582 };
583}
584
David Tolnay1f16b602017-02-07 20:06:55 -0500585/// Run a series of parsers, returning the result of the first one which
586/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500587///
588/// Optionally allows for the result to be transformed.
589///
590/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500591/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500592///
593/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500594/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500595/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500596///
597/// use syn::Ident;
Michael Layzell24645a32017-02-04 13:19:26 -0500598///
599/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500600/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700601/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500602/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800603/// punct!(!) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500604/// )
605/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500606///
Alex Crichton954046c2017-05-30 21:49:42 -0700607/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500608/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500609#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700610macro_rules! alt {
611 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700612 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700613 };
614
615 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
616 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400617 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700618 _ => alt!($i, $($rest)*)
619 }
620 };
621
622 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
623 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400624 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500625 ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
Michael Layzell760fd662017-05-31 22:46:05 -0400626 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700627 }
628 };
629
630 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700631 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700632 };
633
634 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700635 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700636 };
637
638 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
639 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400640 ::std::result::Result::Ok((i, o)) =>
David Tolnayc5ab8c62017-12-26 16:43:39 -0500641 ::std::result::Result::Ok((i, $crate::parsers::invoke($gen, o))),
Michael Layzell760fd662017-05-31 22:46:05 -0400642 ::std::result::Result::Err(err) =>
643 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700644 }
645 };
646
647 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700648 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700649 };
650
651 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700652 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700653 };
654}
655
Michael Layzell24645a32017-02-04 13:19:26 -0500656/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500657/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500658///
David Tolnay1f16b602017-02-07 20:06:55 -0500659/// Produces the result of evaluating the final expression in parentheses with
660/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500661///
David Tolnay1f16b602017-02-07 20:06:55 -0500662/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500663/// - **Output:** `RESULT`
664///
665/// ```rust
David Tolnayc5ab8c62017-12-26 16:43:39 -0500666/// #[macro_use]
Michael Layzell24645a32017-02-04 13:19:26 -0500667/// extern crate syn;
Alex Crichton954046c2017-05-30 21:49:42 -0700668/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500669///
David Tolnay9c76bcb2017-12-26 23:14:59 -0500670/// use syn::Ident;
David Tolnay32954ef2017-12-26 22:43:16 -0500671/// use syn::token::Paren;
Alex Crichton954046c2017-05-30 21:49:42 -0700672/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500673///
David Tolnay1f16b602017-02-07 20:06:55 -0500674/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700675/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
676/// name: syn!(Ident) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800677/// punct!(!) >>
Alex Crichton954046c2017-05-30 21:49:42 -0700678/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500679/// (name, body)
680/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500681///
Alex Crichton954046c2017-05-30 21:49:42 -0700682/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500683/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500684#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700685macro_rules! do_parse {
686 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400687 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700688 };
689
690 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700691 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700692 };
693
694 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
695 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400696 ::std::result::Result::Err(err) =>
697 ::std::result::Result::Err(err),
698 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700699 do_parse!(i, $($rest)*),
700 }
701 };
702
703 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700704 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700705 };
706
707 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
708 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400709 ::std::result::Result::Err(err) =>
710 ::std::result::Result::Err(err),
711 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700712 let $field = o;
713 do_parse!(i, $($rest)*)
714 },
715 }
716 };
717
David Tolnayfa0edf22016-09-23 22:58:24 -0700718 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700719 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700720 };
721
722 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
723 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400724 ::std::result::Result::Err(err) =>
725 ::std::result::Result::Err(err),
726 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700727 let mut $field = o;
728 do_parse!(i, $($rest)*)
729 },
730 }
731 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700732}
Michael Layzell416724e2017-05-24 21:12:34 -0400733
734#[macro_export]
735macro_rules! input_end {
736 ($i:expr,) => {
David Tolnayc5ab8c62017-12-26 16:43:39 -0500737 $crate::parsers::input_end($i)
Michael Layzell416724e2017-05-24 21:12:34 -0400738 };
739}
740
741// Not a public API
742#[doc(hidden)]
David Tolnay1fc4e492017-11-11 22:17:22 -0800743pub fn input_end(input: Cursor) -> PResult<'static, ()> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400744 if input.eof() {
David Tolnay1fc4e492017-11-11 22:17:22 -0800745 Ok((Cursor::empty(), ()))
Michael Layzell416724e2017-05-24 21:12:34 -0400746 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400747 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400748 }
749}