blob: 0c90ecea6f4eda13a715e945b6b8f04d48263148 [file] [log] [blame]
David Tolnay30a36002017-02-08 14:24:12 -08001//! Adapted from [`nom`](https://github.com/Geal/nom) by removing the
2//! `IResult::Incomplete` variant which:
3//!
4//! - we don't need,
5//! - is an unintuitive footgun when working with non-streaming use cases, and
6//! - more than doubles compilation time.
7//!
8//! ## Whitespace handling strategy
9//!
10//! As (sy)nom is a parser combinator library, the parsers provided here and
11//! that you implement yourself are all made up of successively more primitive
12//! parsers, eventually culminating in a small number of fundamental parsers
13//! that are implemented in Rust. Among these are `punct!` and `keyword!`.
14//!
15//! All synom fundamental parsers (those not combined out of other parsers)
16//! should be written to skip over leading whitespace in their input. This way,
17//! as long as every parser eventually boils down to some combination of
18//! fundamental parsers, we get correct whitespace handling at all levels for
19//! free.
20//!
21//! For our use case, this strategy is a huge improvement in usability,
22//! correctness, and compile time over nom's `ws!` strategy.
David Tolnayb5a7b142016-09-13 22:46:39 -070023
Michael Layzell5bde96f2017-01-24 17:59:21 -050024extern crate unicode_xid;
25
Alex Crichtonccbb45d2017-05-23 10:58:24 -070026#[cfg(feature = "printing")]
27extern crate quote;
28
29#[cfg(feature = "parsing")]
David Tolnay30a36002017-02-08 14:24:12 -080030#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -050031pub mod space;
32
Alex Crichtonccbb45d2017-05-23 10:58:24 -070033#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080034#[doc(hidden)]
35pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050036
Alex Crichtonccbb45d2017-05-23 10:58:24 -070037pub mod delimited;
38
Michael Layzell24645a32017-02-04 13:19:26 -050039/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070040#[derive(Debug, PartialEq, Eq, Clone)]
41pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080042 /// Parsing succeeded. The first field contains the rest of the unparsed
43 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070044 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080045 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070046 Error,
47}
48
David Tolnayf2222f02017-01-27 17:09:20 -080049impl<'a, O> IResult<&'a str, O> {
Michael Layzell24645a32017-02-04 13:19:26 -050050 /// Unwraps the result, asserting the the parse is complete. Panics with a
51 /// message based on the given string if the parse failed or is incomplete.
David Tolnay1f16b602017-02-07 20:06:55 -050052 ///
53 /// ```rust
54 /// extern crate syn;
55 /// #[macro_use] extern crate synom;
56 ///
57 /// use syn::Ty;
58 /// use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070059 /// use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -050060 ///
61 /// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -070062 /// named!(comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -050063 /// separated_nonempty_list!(punct!(","), ty)
64 /// );
65 ///
66 /// fn main() {
67 /// let input = "&str, Map<K, V>, String";
68 ///
69 /// let parsed = comma_separated_types(input).expect("comma-separated types");
70 ///
71 /// assert_eq!(parsed.len(), 3);
72 /// println!("{:?}", parsed);
73 /// }
74 /// ```
David Tolnayf2222f02017-01-27 17:09:20 -080075 pub fn expect(self, name: &str) -> O {
76 match self {
77 IResult::Done(mut rest, o) => {
78 rest = space::skip_whitespace(rest);
79 if rest.is_empty() {
80 o
81 } else {
82 panic!("unparsed tokens after {}: {:?}", name, rest)
83 }
84 }
85 IResult::Error => panic!("failed to parse {}", name),
86 }
87 }
88}
89
Michael Layzell24645a32017-02-04 13:19:26 -050090/// Define a function from a parser combination.
91///
David Tolnay1f16b602017-02-07 20:06:55 -050092/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
93///
94/// ```rust
95/// # extern crate syn;
96/// # #[macro_use] extern crate synom;
97/// # use syn::Ty;
98/// # use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070099/// # use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -0500100/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700101/// named!(pub comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500102/// separated_nonempty_list!(punct!(","), ty)
103/// );
104/// # fn main() {}
105/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500106#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700107macro_rules! named {
108 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500109 fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700110 $submac!(i, $($args)*)
111 }
112 };
113
114 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500115 pub fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700116 $submac!(i, $($args)*)
117 }
118 };
119}
120
David Tolnay1f16b602017-02-07 20:06:55 -0500121/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500122///
123/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500124///
125/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
126/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -0500127///
128/// ```rust
129/// #[macro_use] extern crate synom;
130///
131/// use synom::IResult;
132///
David Tolnay1f16b602017-02-07 20:06:55 -0500133/// // Parses any string up to but not including the given character, returning
134/// // the content up to the given character. The given character is required to
135/// // be present in the input string.
136/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
137/// if let Some(pos) = input.find(ch) {
138/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500139/// } else {
140/// IResult::Error
141/// }
142/// }
143///
David Tolnay1f16b602017-02-07 20:06:55 -0500144/// // Parses any string surrounded by tilde characters '~'. Returns the content
145/// // between the tilde characters.
146/// named!(surrounded_by_tilde -> &str, delimited!(
147/// punct!("~"),
148/// call!(skip_until, '~'),
149/// punct!("~")
150/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500151///
152/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500153/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500154///
David Tolnay1f16b602017-02-07 20:06:55 -0500155/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500156///
David Tolnay1f16b602017-02-07 20:06:55 -0500157/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500158/// }
159/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500160#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700161macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700162 ($i:expr, $fun:expr $(, $args:expr)*) => {
163 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700164 };
165}
166
David Tolnay1f16b602017-02-07 20:06:55 -0500167/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500168///
David Tolnay1f16b602017-02-07 20:06:55 -0500169/// - **Syntax:** `map!(THING, FN)`
170/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500171///
172/// ```rust
173/// extern crate syn;
174/// #[macro_use] extern crate synom;
175///
176/// use syn::{Item, Ident};
177/// use syn::parse::item;
178///
179/// fn get_item_ident(item: Item) -> Ident {
180/// item.ident
181/// }
182///
David Tolnay1f16b602017-02-07 20:06:55 -0500183/// // Parses an item and returns the name (identifier) of the item only.
184/// named!(item_ident -> Ident,
185/// map!(item, get_item_ident)
186/// );
187///
188/// // Or equivalently:
189/// named!(item_ident2 -> Ident,
190/// map!(item, |i: Item| i.ident)
191/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500192///
193/// fn main() {
194/// let input = "fn foo() {}";
195///
David Tolnay1f16b602017-02-07 20:06:55 -0500196/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500197///
David Tolnay1f16b602017-02-07 20:06:55 -0500198/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500199/// }
200/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500201#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700202macro_rules! map {
203 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700204 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500205 $crate::IResult::Error => $crate::IResult::Error,
206 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500207 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700208 }
209 }
210 };
David Tolnay1f16b602017-02-07 20:06:55 -0500211
212 ($i:expr, $f:expr, $g:expr) => {
213 map!($i, call!($f), $g)
214 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700215}
216
David Tolnay1f16b602017-02-07 20:06:55 -0500217/// Parses successfully if the given parser fails to parse. Does not consume any
218/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500219///
220/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500221/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500222///
223/// ```rust
224/// extern crate syn;
225/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500226/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500227///
David Tolnay1f16b602017-02-07 20:06:55 -0500228/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
229/// // Note that a line starting with `#![` is an inner attribute, not a
230/// // shebang.
231/// named!(shebang -> &str, preceded!(
232/// tuple!(tag!("#!"), not!(tag!("["))),
233/// take_until!("\n")
234/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500235///
236/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500237/// let bin_bash = "#!/bin/bash\n";
238/// let parsed = shebang(bin_bash).expect("shebang");
239/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500240///
David Tolnay1f16b602017-02-07 20:06:55 -0500241/// let inner_attr = "#![feature(specialization)]\n";
242/// let err = shebang(inner_attr);
243/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500244/// }
245/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500246#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700247macro_rules! not {
248 ($i:expr, $submac:ident!( $($args:tt)* )) => {
249 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500250 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500251 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700252 }
253 };
254}
255
David Tolnay1f16b602017-02-07 20:06:55 -0500256/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500257///
David Tolnay1f16b602017-02-07 20:06:55 -0500258/// If you are familiar with nom, this is nom's `cond_with_error` parser.
259///
260/// - **Syntax:** `cond!(CONDITION, THING)`
261/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500262///
263/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500264/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500265/// #[macro_use] extern crate synom;
266///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700267/// named!(boolean -> bool, alt!(
268/// keyword!("true") => { |_| true }
269/// |
270/// keyword!("false") => { |_| false }
271/// ));
David Tolnay1f16b602017-02-07 20:06:55 -0500272///
273/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
274/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
275/// // separate vectors for the booleans before and after the dotdot. The second
276/// // vector is None if there was no dotdot.
277/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
278/// punct!("(") >>
279/// before: separated_list!(punct!(","), boolean) >>
280/// after: option!(do_parse!(
281/// // Only allow comma if there are elements before dotdot, i.e. cannot
282/// // be `(, .., true)`.
283/// cond!(!before.is_empty(), punct!(",")) >>
284/// punct!("..") >>
285/// after: many0!(preceded!(punct!(","), boolean)) >>
286/// // Only allow trailing comma if there are elements after dotdot,
287/// // i.e. cannot be `(true, .., )`.
288/// cond!(!after.is_empty(), option!(punct!(","))) >>
289/// (after)
290/// )) >>
291/// // Allow trailing comma if there is no dotdot but there are elements.
292/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
293/// punct!(")") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700294/// (before.into_vec(), after)
David Tolnay1f16b602017-02-07 20:06:55 -0500295/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500296///
297/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500298/// let input = "(true, false, false)";
299/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
300/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500301///
David Tolnay1f16b602017-02-07 20:06:55 -0500302/// let input = "(true, true, .., true)";
303/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
304/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
305///
306/// let input = "(.., true)";
307/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
308/// assert_eq!(parsed, (vec![], Some(vec![true])));
309///
310/// let input = "(true, true, ..)";
311/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
312/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
313///
314/// let input = "(..)";
315/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
316/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500317/// }
318/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500319#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700320macro_rules! cond {
321 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
322 if $cond {
323 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500324 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
325 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700326 }
327 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500328 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700329 }
David Tolnaycfe55022016-10-02 22:02:27 -0700330 };
331
332 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700333 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700334 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700335}
336
David Tolnay1f16b602017-02-07 20:06:55 -0500337/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500338///
David Tolnay1f16b602017-02-07 20:06:55 -0500339/// This is typically used inside of `option!` or `alt!`.
340///
341/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
342/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500343///
344/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500345/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500346/// #[macro_use] extern crate synom;
347///
David Tolnay1f16b602017-02-07 20:06:55 -0500348/// #[derive(Debug, PartialEq)]
349/// struct VariadicBools {
350/// data: Vec<bool>,
351/// variadic: bool,
352/// }
353///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700354/// named!(boolean -> bool, alt!(
355/// keyword!("true") => { |_| true }
356/// |
357/// keyword!("false") => { |_| false }
358/// ));
359///
David Tolnay1f16b602017-02-07 20:06:55 -0500360/// // Parse one or more comma-separated booleans, possibly ending in "..." to
361/// // indicate there may be more.
362/// named!(variadic_bools -> VariadicBools, do_parse!(
363/// data: separated_nonempty_list!(punct!(","), boolean) >>
364/// trailing_comma: option!(punct!(",")) >>
365/// // Only allow "..." if there is a comma after the last boolean. Using
366/// // `cond_reduce!` is more convenient here than using `cond!`. The
367/// // alternatives are:
368/// //
369/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
370/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
371/// // which both mean not variadic.
372/// // - `cond_reduce!(c, option!(p))`
373/// // Incorrect; would fail to parse if there is no trailing comma.
374/// // - `option!(cond_reduce!(c, p))`
375/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
376/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
377/// (VariadicBools {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700378/// data: data.into_vec(),
David Tolnay1f16b602017-02-07 20:06:55 -0500379/// variadic: variadic.is_some(),
380/// })
381/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500382///
383/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500384/// let input = "true, true";
385/// let parsed = variadic_bools(input).expect("variadic bools");
386/// assert_eq!(parsed, VariadicBools {
387/// data: vec![true, true],
388/// variadic: false,
389/// });
390///
391/// let input = "true, ...";
392/// let parsed = variadic_bools(input).expect("variadic bools");
393/// assert_eq!(parsed, VariadicBools {
394/// data: vec![true],
395/// variadic: true,
396/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500397/// }
398/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500399#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700400macro_rules! cond_reduce {
401 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
402 if $cond {
403 $submac!($i, $($args)*)
404 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500405 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700406 }
407 };
408
409 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700410 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700411 };
412}
413
David Tolnay1f16b602017-02-07 20:06:55 -0500414/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500415///
David Tolnay1f16b602017-02-07 20:06:55 -0500416/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500417/// - **Output:** `THING`
418///
419/// ```rust
420/// extern crate syn;
421/// #[macro_use] extern crate synom;
422///
423/// use syn::Expr;
424/// use syn::parse::expr;
425///
426/// // An expression preceded by ##.
427/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500428/// preceded!(punct!("##"), expr)
429/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500430///
431/// fn main() {
432/// let input = "## 1 + 1";
433///
434/// let parsed = pound_pound_expr(input).expect("pound pound expr");
435///
436/// println!("{:?}", parsed);
437/// }
438/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500439#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700440macro_rules! preceded {
441 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
442 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500443 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
444 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700445 }
446 };
447
448 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700449 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700450 };
451
452 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700453 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700454 };
455
456 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700457 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700458 };
459}
460
David Tolnay1f16b602017-02-07 20:06:55 -0500461/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500462///
David Tolnay1f16b602017-02-07 20:06:55 -0500463/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500464/// - **Output:** `THING`
465///
466/// ```rust
467/// extern crate syn;
468/// #[macro_use] extern crate synom;
469///
470/// use syn::Expr;
471/// use syn::parse::expr;
472///
473/// // An expression terminated by ##.
474/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500475/// terminated!(expr, punct!("##"))
476/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500477///
478/// fn main() {
479/// let input = "1 + 1 ##";
480///
481/// let parsed = expr_pound_pound(input).expect("expr pound pound");
482///
483/// println!("{:?}", parsed);
484/// }
485/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500486#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700487macro_rules! terminated {
488 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
489 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500490 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
491 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700492 }
493 };
494
495 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700496 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700497 };
498
499 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700500 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700501 };
502
503 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700504 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700505 };
506}
507
David Tolnay1f16b602017-02-07 20:06:55 -0500508/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500509///
510/// - **Syntax:** `many0!(THING)`
511/// - **Output:** `Vec<THING>`
512///
David Tolnay1f16b602017-02-07 20:06:55 -0500513/// You may also be looking for:
514///
515/// - `separated_list!` - zero or more values with separator
516/// - `separated_nonempty_list!` - one or more values
517/// - `terminated_list!` - zero or more, allows trailing separator
518///
Michael Layzell24645a32017-02-04 13:19:26 -0500519/// ```rust
520/// extern crate syn;
521/// #[macro_use] extern crate synom;
522///
523/// use syn::Item;
524/// use syn::parse::item;
525///
526/// named!(items -> Vec<Item>, many0!(item));
527///
528/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500529/// let input = "
530/// fn a() {}
531/// fn b() {}
532/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500533///
534/// let parsed = items(input).expect("items");
535///
David Tolnay1f16b602017-02-07 20:06:55 -0500536/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500537/// println!("{:?}", parsed);
538/// }
539/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500540#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700541macro_rules! many0 {
542 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
543 let ret;
544 let mut res = ::std::vec::Vec::new();
545 let mut input = $i;
546
547 loop {
548 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500549 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700550 break;
551 }
552
553 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500554 $crate::IResult::Error => {
555 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700556 break;
557 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500558 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700559 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700560 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500561 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700562 break;
563 }
564
565 res.push(o);
566 input = i;
567 }
568 }
569 }
570
571 ret
572 }};
573
574 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500575 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700576 };
577}
578
David Tolnay1f16b602017-02-07 20:06:55 -0500579// Improve compile time by compiling this loop only once per type it is used
580// with.
581//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800582// Not public API.
583#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700584pub fn many0<'a, T>(mut input: &'a str,
585 f: fn(&'a str) -> IResult<&'a str, T>)
586 -> IResult<&'a str, Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700587 let mut res = Vec::new();
588
589 loop {
590 if input.is_empty() {
591 return IResult::Done(input, res);
592 }
593
594 match f(input) {
595 IResult::Error => {
596 return IResult::Done(input, res);
597 }
598 IResult::Done(i, o) => {
599 // loop trip must always consume (otherwise infinite loops)
600 if i.len() == input.len() {
601 return IResult::Error;
602 }
603
604 res.push(o);
605 input = i;
606 }
607 }
608 }
609}
610
David Tolnay1f16b602017-02-07 20:06:55 -0500611/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500612///
613/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500614/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500615///
616/// ```rust
617/// extern crate syn;
618/// #[macro_use] extern crate synom;
619///
David Tolnay1f16b602017-02-07 20:06:55 -0500620/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500621/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500622/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500623///
David Tolnay1f16b602017-02-07 20:06:55 -0500624/// // Parse an expression that begins with an identifier.
625/// named!(ident_expr -> Expr,
626/// preceded!(peek!(ident), expr)
627/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500628///
629/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500630/// // begins with an identifier
631/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500632/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500633/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500634///
635/// // does not begin with an identifier
636/// let input = "1 + banana";
637/// let err = ident_expr(input);
638/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500639/// }
640/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500641#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700642macro_rules! peek {
643 ($i:expr, $submac:ident!( $($args:tt)* )) => {
644 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500645 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
646 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700647 }
648 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700649
David Tolnay1f16b602017-02-07 20:06:55 -0500650 ($i:expr, $f:expr) => {
651 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700652 };
653}
654
David Tolnay1f16b602017-02-07 20:06:55 -0500655/// Parse the part of the input up to but not including the given string. Fail
656/// to parse if the given string is not present in the input.
657///
658/// - **Syntax:** `take_until!("...")`
659/// - **Output:** `&str`
660///
661/// ```rust
662/// extern crate syn;
663/// #[macro_use] extern crate synom;
664/// use synom::IResult;
665///
666/// // Parse a single line doc comment: /// ...
667/// named!(single_line_doc -> &str,
668/// preceded!(punct!("///"), take_until!("\n"))
669/// );
670///
671/// fn main() {
672/// let comment = "/// comment\n";
673/// let parsed = single_line_doc(comment).expect("single line doc comment");
674/// assert_eq!(parsed, " comment");
675/// }
676/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500677#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700678macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500679 ($i:expr, $substr:expr) => {{
680 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500681 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700682 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500683 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700684 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500685 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700686 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500687 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700688 window.push(c);
689 if window.len() > substr_vec.len() {
690 window.remove(0);
691 }
692 if window == substr_vec {
693 parsed = true;
694 window.pop();
695 let window_len: usize = window.iter()
696 .map(|x| x.len_utf8())
697 .fold(0, |x, y| x + y);
698 offset = o - window_len;
699 break;
700 }
701 }
702 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500703 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700704 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500705 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700706 }
707 }
708 }};
709}
710
David Tolnay1f16b602017-02-07 20:06:55 -0500711/// Parse the given string from exactly the current position in the input. You
712/// almost always want `punct!` or `keyword!` instead of this.
713///
714/// The `tag!` parser is equivalent to `punct!` but does not ignore leading
715/// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See
716/// an explanation of synom's whitespace handling strategy in the top-level
717/// crate documentation.
718///
719/// - **Syntax:** `tag!("...")`
720/// - **Output:** `"..."`
721///
722/// ```rust
723/// extern crate syn;
724/// #[macro_use] extern crate synom;
725///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700726/// use syn::Lit;
David Tolnay1f16b602017-02-07 20:06:55 -0500727/// use syn::parse::string;
728/// use synom::IResult;
729///
730/// // Parse a proposed syntax for an owned string literal: "abc"s
731/// named!(owned_string -> String,
732/// map!(
733/// terminated!(string, tag!("s")),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700734/// |lit: Lit| lit.to_string()
David Tolnay1f16b602017-02-07 20:06:55 -0500735/// )
736/// );
737///
738/// fn main() {
739/// let input = r#" "abc"s "#;
740/// let parsed = owned_string(input).expect("owned string literal");
741/// println!("{:?}", parsed);
742///
743/// let input = r#" "abc" s "#;
744/// let err = owned_string(input);
745/// assert_eq!(err, IResult::Error);
746/// }
747/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500748#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700749macro_rules! tag {
David Tolnay1f16b602017-02-07 20:06:55 -0500750 ($i:expr, $tag:expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700751 if $i.starts_with($tag) {
David Tolnay1f16b602017-02-07 20:06:55 -0500752 $crate::IResult::Done(&$i[$tag.len()..], &$i[..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700753 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500754 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700755 }
756 };
757}
758
David Tolnay1f16b602017-02-07 20:06:55 -0500759/// Pattern-match the result of a parser to select which other parser to run.
760///
761/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
762/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
763///
764/// ```rust
765/// extern crate syn;
766/// #[macro_use] extern crate synom;
767///
768/// use syn::{Ident, Ty};
769/// use syn::parse::{ident, ty};
770///
771/// #[derive(Debug)]
772/// enum UnitType {
773/// Struct {
774/// name: Ident,
775/// },
776/// Enum {
777/// name: Ident,
778/// variant: Ident,
779/// },
780/// }
781///
782/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
783/// named!(unit_type -> UnitType, do_parse!(
784/// which: alt!(keyword!("struct") | keyword!("enum")) >>
785/// id: ident >>
786/// item: switch!(value!(which),
787/// "struct" => map!(
788/// punct!(";"),
789/// move |_| UnitType::Struct {
790/// name: id,
791/// }
792/// )
793/// |
794/// "enum" => map!(
795/// delimited!(punct!("{"), ident, punct!("}")),
796/// move |variant| UnitType::Enum {
797/// name: id,
798/// variant: variant,
799/// }
800/// )
801/// ) >>
802/// (item)
803/// ));
804///
805/// fn main() {
806/// let input = "struct S;";
807/// let parsed = unit_type(input).expect("unit struct or enum");
808/// println!("{:?}", parsed);
809///
810/// let input = "enum E { V }";
811/// let parsed = unit_type(input).expect("unit struct or enum");
812/// println!("{:?}", parsed);
813/// }
814/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500815#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700816macro_rules! switch {
817 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
818 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500819 $crate::IResult::Error => $crate::IResult::Error,
820 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700821 $(
822 $p => $subrule!(i, $($args2)*),
823 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500824 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700825 }
826 }
827 };
828}
829
David Tolnay1f16b602017-02-07 20:06:55 -0500830/// Produce the given value without parsing anything. Useful as an argument to
831/// `switch!`.
832///
833/// - **Syntax:** `value!(VALUE)`
834/// - **Output:** `VALUE`
835///
836/// ```rust
837/// extern crate syn;
838/// #[macro_use] extern crate synom;
839///
840/// use syn::{Ident, Ty};
841/// use syn::parse::{ident, ty};
842///
843/// #[derive(Debug)]
844/// enum UnitType {
845/// Struct {
846/// name: Ident,
847/// },
848/// Enum {
849/// name: Ident,
850/// variant: Ident,
851/// },
852/// }
853///
854/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
855/// named!(unit_type -> UnitType, do_parse!(
856/// which: alt!(keyword!("struct") | keyword!("enum")) >>
857/// id: ident >>
858/// item: switch!(value!(which),
859/// "struct" => map!(
860/// punct!(";"),
861/// move |_| UnitType::Struct {
862/// name: id,
863/// }
864/// )
865/// |
866/// "enum" => map!(
867/// delimited!(punct!("{"), ident, punct!("}")),
868/// move |variant| UnitType::Enum {
869/// name: id,
870/// variant: variant,
871/// }
872/// )
873/// ) >>
874/// (item)
875/// ));
876///
877/// fn main() {
878/// let input = "struct S;";
879/// let parsed = unit_type(input).expect("unit struct or enum");
880/// println!("{:?}", parsed);
881///
882/// let input = "enum E { V }";
883/// let parsed = unit_type(input).expect("unit struct or enum");
884/// println!("{:?}", parsed);
885/// }
886/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500887#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700888macro_rules! value {
889 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500890 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700891 };
892}
893
David Tolnayf2222f02017-01-27 17:09:20 -0800894/// Value surrounded by a pair of delimiters.
895///
896/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
897/// - **Output:** `THING`
898///
899/// ```rust
900/// extern crate syn;
901/// #[macro_use] extern crate synom;
902///
903/// use syn::Expr;
904/// use syn::parse::expr;
905///
906/// // An expression surrounded by [[ ... ]].
907/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500908/// delimited!(punct!("[["), expr, punct!("]]"))
909/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800910///
911/// fn main() {
912/// let input = "[[ 1 + 1 ]]";
913///
914/// let parsed = double_bracket_expr(input).expect("double bracket expr");
915///
916/// println!("{:?}", parsed);
917/// }
918/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500919#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700920macro_rules! delimited {
921 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
922 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500923 $crate::IResult::Error => $crate::IResult::Error,
924 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700925 }
926 };
927
928 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700929 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700930 };
931}
932
David Tolnay1f16b602017-02-07 20:06:55 -0500933/// One or more values separated by some separator. Does not allow a trailing
934/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800935///
936/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
937/// - **Output:** `Vec<THING>`
938///
David Tolnay1f16b602017-02-07 20:06:55 -0500939/// You may also be looking for:
940///
941/// - `separated_list!` - one or more values
942/// - `terminated_list!` - zero or more, allows trailing separator
943/// - `many0!` - zero or more, no separator
944///
David Tolnayf2222f02017-01-27 17:09:20 -0800945/// ```rust
946/// extern crate syn;
947/// #[macro_use] extern crate synom;
948///
949/// use syn::Ty;
950/// use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700951/// use synom::delimited::Delimited;
David Tolnayf2222f02017-01-27 17:09:20 -0800952///
953/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700954/// named!(comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500955/// separated_nonempty_list!(punct!(","), ty)
956/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800957///
958/// fn main() {
959/// let input = "&str, Map<K, V>, String";
960///
961/// let parsed = comma_separated_types(input).expect("comma-separated types");
962///
963/// assert_eq!(parsed.len(), 3);
964/// println!("{:?}", parsed);
965/// }
966/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500967#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700968macro_rules! separated_nonempty_list {
969 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700970 let mut res = $crate::delimited::Delimited::new();
David Tolnayb5a7b142016-09-13 22:46:39 -0700971 let mut input = $i;
972
973 // get the first element
974 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500975 $crate::IResult::Error => $crate::IResult::Error,
976 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700977 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500978 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700979 } else {
David Tolnayb5a7b142016-09-13 22:46:39 -0700980 input = i;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700981 res.push_first(o);
David Tolnayb5a7b142016-09-13 22:46:39 -0700982
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700983 while let $crate::IResult::Done(i2, s) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700984 if i2.len() == input.len() {
985 break;
986 }
987
Michael Layzell5bde96f2017-01-24 17:59:21 -0500988 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700989 res.push_next(o3, s);
David Tolnayb5a7b142016-09-13 22:46:39 -0700990 if i3.len() == i2.len() {
991 break;
992 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700993 input = i3;
994 } else {
995 break;
996 }
997 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500998 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700999 }
1000 }
1001 }
1002 }};
1003
1004 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001005 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001006 };
1007
1008 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001009 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001010 };
1011
1012 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001013 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001014 };
1015}
1016
David Tolnay1f16b602017-02-07 20:06:55 -05001017/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -05001018///
David Tolnay1f16b602017-02-07 20:06:55 -05001019/// - **Syntax:** `tuple!(A, B, C, ...)`
1020/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -05001021///
1022/// ```rust
1023/// extern crate syn;
1024/// #[macro_use] extern crate synom;
1025///
1026/// use syn::Ty;
1027/// use syn::parse::ty;
1028///
1029/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
1030///
1031/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001032/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -05001033///
David Tolnay1f16b602017-02-07 20:06:55 -05001034/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -05001035///
1036/// println!("{:?}", parsed);
1037/// }
1038/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001039#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001040macro_rules! tuple {
1041 ($i:expr, $($rest:tt)*) => {
1042 tuple_parser!($i, (), $($rest)*)
1043 };
1044}
1045
David Tolnay1f16b602017-02-07 20:06:55 -05001046/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001047#[doc(hidden)]
1048#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001049macro_rules! tuple_parser {
1050 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001051 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001052 };
1053
1054 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1055 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001056 $crate::IResult::Error => $crate::IResult::Error,
1057 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001058 tuple_parser!(i, (o), $($rest)*),
1059 }
1060 };
1061
1062 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1063 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001064 $crate::IResult::Error => $crate::IResult::Error,
1065 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001066 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1067 }
1068 };
1069
1070 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001071 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001072 };
1073
1074 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1075 $submac!($i, $($args)*)
1076 };
1077
1078 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1079 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001080 $crate::IResult::Error => $crate::IResult::Error,
1081 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001082 }
1083 };
1084
1085 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001086 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001087 };
1088}
1089
David Tolnay1f16b602017-02-07 20:06:55 -05001090/// Run a series of parsers, returning the result of the first one which
1091/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001092///
1093/// Optionally allows for the result to be transformed.
1094///
1095/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001096/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001097///
1098/// ```rust
1099/// extern crate syn;
1100/// #[macro_use] extern crate synom;
1101///
1102/// use syn::Ident;
1103/// use syn::parse::ident;
1104///
1105/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001106/// alt!(
1107/// ident
1108/// |
1109/// punct!("!") => { |_| "BANG".into() }
1110/// )
1111/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001112///
1113/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001114/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001115/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1116/// assert_eq!(parsed, "foo");
1117///
1118/// let input = "!";
1119/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1120/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001121/// }
1122/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001123#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001124macro_rules! alt {
1125 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001126 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001127 };
1128
1129 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1130 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001131 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001132 _ => alt!($i, $($rest)*)
1133 }
1134 };
1135
1136 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1137 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001138 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1139 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001140 }
1141 };
1142
1143 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001144 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001145 };
1146
1147 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001148 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001149 };
1150
1151 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1152 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001153 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1154 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001155 }
1156 };
1157
1158 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001159 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001160 };
1161
1162 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001163 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001164 };
1165}
1166
Michael Layzell24645a32017-02-04 13:19:26 -05001167/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001168/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001169///
David Tolnay1f16b602017-02-07 20:06:55 -05001170/// Produces the result of evaluating the final expression in parentheses with
1171/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001172///
David Tolnay1f16b602017-02-07 20:06:55 -05001173/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001174/// - **Output:** `RESULT`
1175///
1176/// ```rust
1177/// extern crate syn;
1178/// #[macro_use] extern crate synom;
1179///
1180/// use syn::{Ident, TokenTree};
1181/// use syn::parse::{ident, tt};
1182///
David Tolnay1f16b602017-02-07 20:06:55 -05001183/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001184/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1185/// name: ident >>
1186/// punct!("!") >>
1187/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001188/// (name, body)
1189/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001190///
1191/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001192/// let input = "stringify!($args)";
1193/// let (name, body) = simple_mac(input).expect("macro invocation");
1194/// println!("{:?}", name);
1195/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001196/// }
1197/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001198#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001199macro_rules! do_parse {
1200 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001201 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001202 };
1203
1204 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001205 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001206 };
1207
1208 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1209 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001210 $crate::IResult::Error => $crate::IResult::Error,
1211 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001212 do_parse!(i, $($rest)*),
1213 }
1214 };
1215
1216 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001217 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001218 };
1219
1220 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1221 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001222 $crate::IResult::Error => $crate::IResult::Error,
1223 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001224 let $field = o;
1225 do_parse!(i, $($rest)*)
1226 },
1227 }
1228 };
1229
David Tolnayfa0edf22016-09-23 22:58:24 -07001230 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001231 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001232 };
1233
1234 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1235 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001236 $crate::IResult::Error => $crate::IResult::Error,
1237 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001238 let mut $field = o;
1239 do_parse!(i, $($rest)*)
1240 },
1241 }
1242 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001243}