blob: 7bb7bec6e08b49669e2aafed89b5f950ae4a3aa1 [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
Michael Layzell416724e2017-05-24 21:12:34 -040049impl<'a, O> IResult<&'a [TokenTree], 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 {
Michael Layzell416724e2017-05-24 21:12:34 -040077 IResult::Done(rest, o) => {
David Tolnayf2222f02017-01-27 17:09:20 -080078 if rest.is_empty() {
79 o
80 } else {
Michael Layzell416724e2017-05-24 21:12:34 -040081 panic!("unparsed tokens after {}: {:?}", name, /* rest */ ())
David Tolnayf2222f02017-01-27 17:09:20 -080082 }
83 }
84 IResult::Error => panic!("failed to parse {}", name),
85 }
86 }
87}
88
Michael Layzell24645a32017-02-04 13:19:26 -050089/// Define a function from a parser combination.
90///
David Tolnay1f16b602017-02-07 20:06:55 -050091/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
92///
93/// ```rust
94/// # extern crate syn;
95/// # #[macro_use] extern crate synom;
96/// # use syn::Ty;
97/// # use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070098/// # use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -050099/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700100/// named!(pub comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500101/// separated_nonempty_list!(punct!(","), ty)
102/// );
103/// # fn main() {}
104/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500105#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700106macro_rules! named {
107 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400108 fn $name(i: &[$crate::TokenTree]) -> $crate::IResult<&[$crate::TokenTree], $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700109 $submac!(i, $($args)*)
110 }
111 };
112
113 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400114 pub fn $name(i: &[$crate::TokenTree]) -> $crate::IResult<&[$crate::TokenTree], $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700115 $submac!(i, $($args)*)
116 }
117 };
118}
119
David Tolnay1f16b602017-02-07 20:06:55 -0500120/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500121///
122/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500123///
124/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
125/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -0500126///
127/// ```rust
128/// #[macro_use] extern crate synom;
129///
130/// use synom::IResult;
131///
David Tolnay1f16b602017-02-07 20:06:55 -0500132/// // Parses any string up to but not including the given character, returning
133/// // the content up to the given character. The given character is required to
134/// // be present in the input string.
135/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
136/// if let Some(pos) = input.find(ch) {
137/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500138/// } else {
139/// IResult::Error
140/// }
141/// }
142///
David Tolnay1f16b602017-02-07 20:06:55 -0500143/// // Parses any string surrounded by tilde characters '~'. Returns the content
144/// // between the tilde characters.
145/// named!(surrounded_by_tilde -> &str, delimited!(
146/// punct!("~"),
147/// call!(skip_until, '~'),
148/// punct!("~")
149/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500150///
151/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500152/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500153///
David Tolnay1f16b602017-02-07 20:06:55 -0500154/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500155///
David Tolnay1f16b602017-02-07 20:06:55 -0500156/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500157/// }
158/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500159#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700160macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700161 ($i:expr, $fun:expr $(, $args:expr)*) => {
162 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700163 };
164}
165
David Tolnay1f16b602017-02-07 20:06:55 -0500166/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500167///
David Tolnay1f16b602017-02-07 20:06:55 -0500168/// - **Syntax:** `map!(THING, FN)`
169/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500170///
171/// ```rust
172/// extern crate syn;
173/// #[macro_use] extern crate synom;
174///
175/// use syn::{Item, Ident};
176/// use syn::parse::item;
177///
178/// fn get_item_ident(item: Item) -> Ident {
179/// item.ident
180/// }
181///
David Tolnay1f16b602017-02-07 20:06:55 -0500182/// // Parses an item and returns the name (identifier) of the item only.
183/// named!(item_ident -> Ident,
184/// map!(item, get_item_ident)
185/// );
186///
187/// // Or equivalently:
188/// named!(item_ident2 -> Ident,
189/// map!(item, |i: Item| i.ident)
190/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500191///
192/// fn main() {
193/// let input = "fn foo() {}";
194///
David Tolnay1f16b602017-02-07 20:06:55 -0500195/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500196///
David Tolnay1f16b602017-02-07 20:06:55 -0500197/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500198/// }
199/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500200#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700201macro_rules! map {
202 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700203 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500204 $crate::IResult::Error => $crate::IResult::Error,
205 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500206 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700207 }
208 }
209 };
David Tolnay1f16b602017-02-07 20:06:55 -0500210
211 ($i:expr, $f:expr, $g:expr) => {
212 map!($i, call!($f), $g)
213 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700214}
215
David Tolnay1f16b602017-02-07 20:06:55 -0500216/// Parses successfully if the given parser fails to parse. Does not consume any
217/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500218///
219/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500220/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500221///
222/// ```rust
223/// extern crate syn;
224/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500225/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500226///
David Tolnay1f16b602017-02-07 20:06:55 -0500227/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
228/// // Note that a line starting with `#![` is an inner attribute, not a
229/// // shebang.
230/// named!(shebang -> &str, preceded!(
231/// tuple!(tag!("#!"), not!(tag!("["))),
232/// take_until!("\n")
233/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500234///
235/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500236/// let bin_bash = "#!/bin/bash\n";
237/// let parsed = shebang(bin_bash).expect("shebang");
238/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500239///
David Tolnay1f16b602017-02-07 20:06:55 -0500240/// let inner_attr = "#![feature(specialization)]\n";
241/// let err = shebang(inner_attr);
242/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500243/// }
244/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500245#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700246macro_rules! not {
247 ($i:expr, $submac:ident!( $($args:tt)* )) => {
248 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500249 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500250 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700251 }
252 };
253}
254
David Tolnay1f16b602017-02-07 20:06:55 -0500255/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500256///
David Tolnay1f16b602017-02-07 20:06:55 -0500257/// If you are familiar with nom, this is nom's `cond_with_error` parser.
258///
259/// - **Syntax:** `cond!(CONDITION, THING)`
260/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500261///
262/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500263/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500264/// #[macro_use] extern crate synom;
265///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700266/// named!(boolean -> bool, alt!(
267/// keyword!("true") => { |_| true }
268/// |
269/// keyword!("false") => { |_| false }
270/// ));
David Tolnay1f16b602017-02-07 20:06:55 -0500271///
272/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
273/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
274/// // separate vectors for the booleans before and after the dotdot. The second
275/// // vector is None if there was no dotdot.
276/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
277/// punct!("(") >>
278/// before: separated_list!(punct!(","), boolean) >>
279/// after: option!(do_parse!(
280/// // Only allow comma if there are elements before dotdot, i.e. cannot
281/// // be `(, .., true)`.
282/// cond!(!before.is_empty(), punct!(",")) >>
283/// punct!("..") >>
284/// after: many0!(preceded!(punct!(","), boolean)) >>
285/// // Only allow trailing comma if there are elements after dotdot,
286/// // i.e. cannot be `(true, .., )`.
287/// cond!(!after.is_empty(), option!(punct!(","))) >>
288/// (after)
289/// )) >>
290/// // Allow trailing comma if there is no dotdot but there are elements.
291/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
292/// punct!(")") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700293/// (before.into_vec(), after)
David Tolnay1f16b602017-02-07 20:06:55 -0500294/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500295///
296/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500297/// let input = "(true, false, false)";
298/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
299/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500300///
David Tolnay1f16b602017-02-07 20:06:55 -0500301/// let input = "(true, true, .., true)";
302/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
303/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
304///
305/// let input = "(.., true)";
306/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
307/// assert_eq!(parsed, (vec![], Some(vec![true])));
308///
309/// let input = "(true, true, ..)";
310/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
311/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
312///
313/// let input = "(..)";
314/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
315/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500316/// }
317/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500318#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700319macro_rules! cond {
320 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
321 if $cond {
322 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500323 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
324 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700325 }
326 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500327 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700328 }
David Tolnaycfe55022016-10-02 22:02:27 -0700329 };
330
331 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700332 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700333 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700334}
335
David Tolnay1f16b602017-02-07 20:06:55 -0500336/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500337///
David Tolnay1f16b602017-02-07 20:06:55 -0500338/// This is typically used inside of `option!` or `alt!`.
339///
340/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
341/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500342///
343/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500344/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500345/// #[macro_use] extern crate synom;
346///
David Tolnay1f16b602017-02-07 20:06:55 -0500347/// #[derive(Debug, PartialEq)]
348/// struct VariadicBools {
349/// data: Vec<bool>,
350/// variadic: bool,
351/// }
352///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700353/// named!(boolean -> bool, alt!(
354/// keyword!("true") => { |_| true }
355/// |
356/// keyword!("false") => { |_| false }
357/// ));
358///
David Tolnay1f16b602017-02-07 20:06:55 -0500359/// // Parse one or more comma-separated booleans, possibly ending in "..." to
360/// // indicate there may be more.
361/// named!(variadic_bools -> VariadicBools, do_parse!(
362/// data: separated_nonempty_list!(punct!(","), boolean) >>
363/// trailing_comma: option!(punct!(",")) >>
364/// // Only allow "..." if there is a comma after the last boolean. Using
365/// // `cond_reduce!` is more convenient here than using `cond!`. The
366/// // alternatives are:
367/// //
368/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
369/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
370/// // which both mean not variadic.
371/// // - `cond_reduce!(c, option!(p))`
372/// // Incorrect; would fail to parse if there is no trailing comma.
373/// // - `option!(cond_reduce!(c, p))`
374/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
375/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
376/// (VariadicBools {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700377/// data: data.into_vec(),
David Tolnay1f16b602017-02-07 20:06:55 -0500378/// variadic: variadic.is_some(),
379/// })
380/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500381///
382/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500383/// let input = "true, true";
384/// let parsed = variadic_bools(input).expect("variadic bools");
385/// assert_eq!(parsed, VariadicBools {
386/// data: vec![true, true],
387/// variadic: false,
388/// });
389///
390/// let input = "true, ...";
391/// let parsed = variadic_bools(input).expect("variadic bools");
392/// assert_eq!(parsed, VariadicBools {
393/// data: vec![true],
394/// variadic: true,
395/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500396/// }
397/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500398#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700399macro_rules! cond_reduce {
400 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
401 if $cond {
402 $submac!($i, $($args)*)
403 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500404 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700405 }
406 };
407
408 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700409 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700410 };
411}
412
David Tolnay1f16b602017-02-07 20:06:55 -0500413/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500414///
David Tolnay1f16b602017-02-07 20:06:55 -0500415/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500416/// - **Output:** `THING`
417///
418/// ```rust
419/// extern crate syn;
420/// #[macro_use] extern crate synom;
421///
422/// use syn::Expr;
423/// use syn::parse::expr;
424///
425/// // An expression preceded by ##.
426/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500427/// preceded!(punct!("##"), expr)
428/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500429///
430/// fn main() {
431/// let input = "## 1 + 1";
432///
433/// let parsed = pound_pound_expr(input).expect("pound pound expr");
434///
435/// println!("{:?}", parsed);
436/// }
437/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500438#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700439macro_rules! preceded {
440 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
441 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500442 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
443 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700444 }
445 };
446
447 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700448 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700449 };
450
451 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700452 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700453 };
454
455 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700456 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700457 };
458}
459
David Tolnay1f16b602017-02-07 20:06:55 -0500460/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500461///
David Tolnay1f16b602017-02-07 20:06:55 -0500462/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500463/// - **Output:** `THING`
464///
465/// ```rust
466/// extern crate syn;
467/// #[macro_use] extern crate synom;
468///
469/// use syn::Expr;
470/// use syn::parse::expr;
471///
472/// // An expression terminated by ##.
473/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500474/// terminated!(expr, punct!("##"))
475/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500476///
477/// fn main() {
478/// let input = "1 + 1 ##";
479///
480/// let parsed = expr_pound_pound(input).expect("expr pound pound");
481///
482/// println!("{:?}", parsed);
483/// }
484/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500485#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700486macro_rules! terminated {
487 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
488 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500489 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
490 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700491 }
492 };
493
494 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700495 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700496 };
497
498 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700499 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700500 };
501
502 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700503 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700504 };
505}
506
David Tolnay1f16b602017-02-07 20:06:55 -0500507/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500508///
509/// - **Syntax:** `many0!(THING)`
510/// - **Output:** `Vec<THING>`
511///
David Tolnay1f16b602017-02-07 20:06:55 -0500512/// You may also be looking for:
513///
514/// - `separated_list!` - zero or more values with separator
515/// - `separated_nonempty_list!` - one or more values
516/// - `terminated_list!` - zero or more, allows trailing separator
517///
Michael Layzell24645a32017-02-04 13:19:26 -0500518/// ```rust
519/// extern crate syn;
520/// #[macro_use] extern crate synom;
521///
522/// use syn::Item;
523/// use syn::parse::item;
524///
525/// named!(items -> Vec<Item>, many0!(item));
526///
527/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500528/// let input = "
529/// fn a() {}
530/// fn b() {}
531/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500532///
533/// let parsed = items(input).expect("items");
534///
David Tolnay1f16b602017-02-07 20:06:55 -0500535/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500536/// println!("{:?}", parsed);
537/// }
538/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500539#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700540macro_rules! many0 {
541 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
542 let ret;
543 let mut res = ::std::vec::Vec::new();
544 let mut input = $i;
545
546 loop {
547 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500548 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700549 break;
550 }
551
552 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500553 $crate::IResult::Error => {
554 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700555 break;
556 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500557 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700558 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700559 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500560 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700561 break;
562 }
563
564 res.push(o);
565 input = i;
566 }
567 }
568 }
569
570 ret
571 }};
572
573 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500574 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700575 };
576}
577
David Tolnay1f16b602017-02-07 20:06:55 -0500578// Improve compile time by compiling this loop only once per type it is used
579// with.
580//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800581// Not public API.
582#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400583pub fn many0<'a, T>(mut input: &'a [TokenTree],
584 f: fn(&'a [TokenTree]) -> IResult<&'a [TokenTree], T>)
585 -> IResult<&'a [TokenTree], Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700586 let mut res = Vec::new();
587
588 loop {
589 if input.is_empty() {
590 return IResult::Done(input, res);
591 }
592
593 match f(input) {
594 IResult::Error => {
595 return IResult::Done(input, res);
596 }
597 IResult::Done(i, o) => {
598 // loop trip must always consume (otherwise infinite loops)
599 if i.len() == input.len() {
600 return IResult::Error;
601 }
602
603 res.push(o);
604 input = i;
605 }
606 }
607 }
608}
609
David Tolnay1f16b602017-02-07 20:06:55 -0500610/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500611///
612/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500613/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500614///
615/// ```rust
616/// extern crate syn;
617/// #[macro_use] extern crate synom;
618///
David Tolnay1f16b602017-02-07 20:06:55 -0500619/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500620/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500621/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500622///
David Tolnay1f16b602017-02-07 20:06:55 -0500623/// // Parse an expression that begins with an identifier.
624/// named!(ident_expr -> Expr,
625/// preceded!(peek!(ident), expr)
626/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500627///
628/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500629/// // begins with an identifier
630/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500631/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500632/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500633///
634/// // does not begin with an identifier
635/// let input = "1 + banana";
636/// let err = ident_expr(input);
637/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500638/// }
639/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500640#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700641macro_rules! peek {
642 ($i:expr, $submac:ident!( $($args:tt)* )) => {
643 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500644 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
645 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700646 }
647 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700648
David Tolnay1f16b602017-02-07 20:06:55 -0500649 ($i:expr, $f:expr) => {
650 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700651 };
652}
653
David Tolnay1f16b602017-02-07 20:06:55 -0500654/// Parse the part of the input up to but not including the given string. Fail
655/// to parse if the given string is not present in the input.
656///
657/// - **Syntax:** `take_until!("...")`
658/// - **Output:** `&str`
659///
660/// ```rust
661/// extern crate syn;
662/// #[macro_use] extern crate synom;
663/// use synom::IResult;
664///
665/// // Parse a single line doc comment: /// ...
666/// named!(single_line_doc -> &str,
667/// preceded!(punct!("///"), take_until!("\n"))
668/// );
669///
670/// fn main() {
671/// let comment = "/// comment\n";
672/// let parsed = single_line_doc(comment).expect("single line doc comment");
673/// assert_eq!(parsed, " comment");
674/// }
675/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500676#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700677macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500678 ($i:expr, $substr:expr) => {{
679 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500680 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700681 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500682 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700683 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500684 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700685 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500686 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700687 window.push(c);
688 if window.len() > substr_vec.len() {
689 window.remove(0);
690 }
691 if window == substr_vec {
692 parsed = true;
693 window.pop();
694 let window_len: usize = window.iter()
695 .map(|x| x.len_utf8())
696 .fold(0, |x, y| x + y);
697 offset = o - window_len;
698 break;
699 }
700 }
701 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500702 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700703 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500704 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700705 }
706 }
707 }};
708}
709
David Tolnay1f16b602017-02-07 20:06:55 -0500710/// Parse the given string from exactly the current position in the input. You
711/// almost always want `punct!` or `keyword!` instead of this.
712///
713/// The `tag!` parser is equivalent to `punct!` but does not ignore leading
714/// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See
715/// an explanation of synom's whitespace handling strategy in the top-level
716/// crate documentation.
717///
718/// - **Syntax:** `tag!("...")`
719/// - **Output:** `"..."`
720///
721/// ```rust
722/// extern crate syn;
723/// #[macro_use] extern crate synom;
724///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700725/// use syn::Lit;
David Tolnay1f16b602017-02-07 20:06:55 -0500726/// use syn::parse::string;
727/// use synom::IResult;
728///
729/// // Parse a proposed syntax for an owned string literal: "abc"s
730/// named!(owned_string -> String,
731/// map!(
732/// terminated!(string, tag!("s")),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700733/// |lit: Lit| lit.to_string()
David Tolnay1f16b602017-02-07 20:06:55 -0500734/// )
735/// );
736///
737/// fn main() {
738/// let input = r#" "abc"s "#;
739/// let parsed = owned_string(input).expect("owned string literal");
740/// println!("{:?}", parsed);
741///
742/// let input = r#" "abc" s "#;
743/// let err = owned_string(input);
744/// assert_eq!(err, IResult::Error);
745/// }
746/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500747#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700748macro_rules! tag {
David Tolnay1f16b602017-02-07 20:06:55 -0500749 ($i:expr, $tag:expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700750 if $i.starts_with($tag) {
David Tolnay1f16b602017-02-07 20:06:55 -0500751 $crate::IResult::Done(&$i[$tag.len()..], &$i[..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700752 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500753 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700754 }
755 };
756}
757
David Tolnay1f16b602017-02-07 20:06:55 -0500758/// Pattern-match the result of a parser to select which other parser to run.
759///
760/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
761/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
762///
763/// ```rust
764/// extern crate syn;
765/// #[macro_use] extern crate synom;
766///
767/// use syn::{Ident, Ty};
768/// use syn::parse::{ident, ty};
769///
770/// #[derive(Debug)]
771/// enum UnitType {
772/// Struct {
773/// name: Ident,
774/// },
775/// Enum {
776/// name: Ident,
777/// variant: Ident,
778/// },
779/// }
780///
781/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
782/// named!(unit_type -> UnitType, do_parse!(
783/// which: alt!(keyword!("struct") | keyword!("enum")) >>
784/// id: ident >>
785/// item: switch!(value!(which),
786/// "struct" => map!(
787/// punct!(";"),
788/// move |_| UnitType::Struct {
789/// name: id,
790/// }
791/// )
792/// |
793/// "enum" => map!(
794/// delimited!(punct!("{"), ident, punct!("}")),
795/// move |variant| UnitType::Enum {
796/// name: id,
797/// variant: variant,
798/// }
799/// )
800/// ) >>
801/// (item)
802/// ));
803///
804/// fn main() {
805/// let input = "struct S;";
806/// let parsed = unit_type(input).expect("unit struct or enum");
807/// println!("{:?}", parsed);
808///
809/// let input = "enum E { V }";
810/// let parsed = unit_type(input).expect("unit struct or enum");
811/// println!("{:?}", parsed);
812/// }
813/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500814#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700815macro_rules! switch {
816 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
817 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500818 $crate::IResult::Error => $crate::IResult::Error,
819 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700820 $(
821 $p => $subrule!(i, $($args2)*),
822 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500823 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700824 }
825 }
826 };
827}
828
David Tolnay1f16b602017-02-07 20:06:55 -0500829/// Produce the given value without parsing anything. Useful as an argument to
830/// `switch!`.
831///
832/// - **Syntax:** `value!(VALUE)`
833/// - **Output:** `VALUE`
834///
835/// ```rust
836/// extern crate syn;
837/// #[macro_use] extern crate synom;
838///
839/// use syn::{Ident, Ty};
840/// use syn::parse::{ident, ty};
841///
842/// #[derive(Debug)]
843/// enum UnitType {
844/// Struct {
845/// name: Ident,
846/// },
847/// Enum {
848/// name: Ident,
849/// variant: Ident,
850/// },
851/// }
852///
853/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
854/// named!(unit_type -> UnitType, do_parse!(
855/// which: alt!(keyword!("struct") | keyword!("enum")) >>
856/// id: ident >>
857/// item: switch!(value!(which),
858/// "struct" => map!(
859/// punct!(";"),
860/// move |_| UnitType::Struct {
861/// name: id,
862/// }
863/// )
864/// |
865/// "enum" => map!(
866/// delimited!(punct!("{"), ident, punct!("}")),
867/// move |variant| UnitType::Enum {
868/// name: id,
869/// variant: variant,
870/// }
871/// )
872/// ) >>
873/// (item)
874/// ));
875///
876/// fn main() {
877/// let input = "struct S;";
878/// let parsed = unit_type(input).expect("unit struct or enum");
879/// println!("{:?}", parsed);
880///
881/// let input = "enum E { V }";
882/// let parsed = unit_type(input).expect("unit struct or enum");
883/// println!("{:?}", parsed);
884/// }
885/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500886#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700887macro_rules! value {
888 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500889 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700890 };
891}
892
David Tolnayf2222f02017-01-27 17:09:20 -0800893/// Value surrounded by a pair of delimiters.
894///
895/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
896/// - **Output:** `THING`
897///
898/// ```rust
899/// extern crate syn;
900/// #[macro_use] extern crate synom;
901///
902/// use syn::Expr;
903/// use syn::parse::expr;
904///
905/// // An expression surrounded by [[ ... ]].
906/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500907/// delimited!(punct!("[["), expr, punct!("]]"))
908/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800909///
910/// fn main() {
911/// let input = "[[ 1 + 1 ]]";
912///
913/// let parsed = double_bracket_expr(input).expect("double bracket expr");
914///
915/// println!("{:?}", parsed);
916/// }
917/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500918#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700919macro_rules! delimited {
920 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
921 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500922 $crate::IResult::Error => $crate::IResult::Error,
923 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700924 }
925 };
926
927 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700928 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700929 };
930}
931
David Tolnay1f16b602017-02-07 20:06:55 -0500932/// One or more values separated by some separator. Does not allow a trailing
933/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800934///
935/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
936/// - **Output:** `Vec<THING>`
937///
David Tolnay1f16b602017-02-07 20:06:55 -0500938/// You may also be looking for:
939///
940/// - `separated_list!` - one or more values
941/// - `terminated_list!` - zero or more, allows trailing separator
942/// - `many0!` - zero or more, no separator
943///
David Tolnayf2222f02017-01-27 17:09:20 -0800944/// ```rust
945/// extern crate syn;
946/// #[macro_use] extern crate synom;
947///
948/// use syn::Ty;
949/// use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700950/// use synom::delimited::Delimited;
David Tolnayf2222f02017-01-27 17:09:20 -0800951///
952/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700953/// named!(comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500954/// separated_nonempty_list!(punct!(","), ty)
955/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800956///
957/// fn main() {
958/// let input = "&str, Map<K, V>, String";
959///
960/// let parsed = comma_separated_types(input).expect("comma-separated types");
961///
962/// assert_eq!(parsed.len(), 3);
963/// println!("{:?}", parsed);
964/// }
965/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500966#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700967macro_rules! separated_nonempty_list {
968 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700969 let mut res = $crate::delimited::Delimited::new();
David Tolnayb5a7b142016-09-13 22:46:39 -0700970 let mut input = $i;
971
972 // get the first element
973 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500974 $crate::IResult::Error => $crate::IResult::Error,
975 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700976 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500977 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700978 } else {
David Tolnayb5a7b142016-09-13 22:46:39 -0700979 input = i;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700980 res.push_first(o);
David Tolnayb5a7b142016-09-13 22:46:39 -0700981
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700982 while let $crate::IResult::Done(i2, s) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700983 if i2.len() == input.len() {
984 break;
985 }
986
Michael Layzell5bde96f2017-01-24 17:59:21 -0500987 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700988 res.push_next(o3, s);
David Tolnayb5a7b142016-09-13 22:46:39 -0700989 if i3.len() == i2.len() {
990 break;
991 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700992 input = i3;
993 } else {
994 break;
995 }
996 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500997 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700998 }
999 }
1000 }
1001 }};
1002
1003 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001004 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001005 };
1006
1007 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001008 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001009 };
1010
1011 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001012 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001013 };
1014}
1015
David Tolnay1f16b602017-02-07 20:06:55 -05001016/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -05001017///
David Tolnay1f16b602017-02-07 20:06:55 -05001018/// - **Syntax:** `tuple!(A, B, C, ...)`
1019/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -05001020///
1021/// ```rust
1022/// extern crate syn;
1023/// #[macro_use] extern crate synom;
1024///
1025/// use syn::Ty;
1026/// use syn::parse::ty;
1027///
1028/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
1029///
1030/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001031/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -05001032///
David Tolnay1f16b602017-02-07 20:06:55 -05001033/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -05001034///
1035/// println!("{:?}", parsed);
1036/// }
1037/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001038#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001039macro_rules! tuple {
1040 ($i:expr, $($rest:tt)*) => {
1041 tuple_parser!($i, (), $($rest)*)
1042 };
1043}
1044
David Tolnay1f16b602017-02-07 20:06:55 -05001045/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001046#[doc(hidden)]
1047#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001048macro_rules! tuple_parser {
1049 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001050 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001051 };
1052
1053 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1054 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001055 $crate::IResult::Error => $crate::IResult::Error,
1056 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001057 tuple_parser!(i, (o), $($rest)*),
1058 }
1059 };
1060
1061 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1062 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001063 $crate::IResult::Error => $crate::IResult::Error,
1064 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001065 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1066 }
1067 };
1068
1069 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001070 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001071 };
1072
1073 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1074 $submac!($i, $($args)*)
1075 };
1076
1077 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1078 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001079 $crate::IResult::Error => $crate::IResult::Error,
1080 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001081 }
1082 };
1083
1084 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001085 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001086 };
1087}
1088
David Tolnay1f16b602017-02-07 20:06:55 -05001089/// Run a series of parsers, returning the result of the first one which
1090/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001091///
1092/// Optionally allows for the result to be transformed.
1093///
1094/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001095/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001096///
1097/// ```rust
1098/// extern crate syn;
1099/// #[macro_use] extern crate synom;
1100///
1101/// use syn::Ident;
1102/// use syn::parse::ident;
1103///
1104/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001105/// alt!(
1106/// ident
1107/// |
1108/// punct!("!") => { |_| "BANG".into() }
1109/// )
1110/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001111///
1112/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001113/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001114/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1115/// assert_eq!(parsed, "foo");
1116///
1117/// let input = "!";
1118/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1119/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001120/// }
1121/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001122#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001123macro_rules! alt {
1124 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001125 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001126 };
1127
1128 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1129 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001130 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001131 _ => alt!($i, $($rest)*)
1132 }
1133 };
1134
1135 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1136 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001137 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1138 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001139 }
1140 };
1141
1142 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001143 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001144 };
1145
1146 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001147 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001148 };
1149
1150 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1151 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001152 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1153 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001154 }
1155 };
1156
1157 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001158 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001159 };
1160
1161 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001162 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001163 };
1164}
1165
Michael Layzell24645a32017-02-04 13:19:26 -05001166/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001167/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001168///
David Tolnay1f16b602017-02-07 20:06:55 -05001169/// Produces the result of evaluating the final expression in parentheses with
1170/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001171///
David Tolnay1f16b602017-02-07 20:06:55 -05001172/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001173/// - **Output:** `RESULT`
1174///
1175/// ```rust
1176/// extern crate syn;
1177/// #[macro_use] extern crate synom;
1178///
1179/// use syn::{Ident, TokenTree};
1180/// use syn::parse::{ident, tt};
1181///
David Tolnay1f16b602017-02-07 20:06:55 -05001182/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001183/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1184/// name: ident >>
1185/// punct!("!") >>
1186/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001187/// (name, body)
1188/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001189///
1190/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001191/// let input = "stringify!($args)";
1192/// let (name, body) = simple_mac(input).expect("macro invocation");
1193/// println!("{:?}", name);
1194/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001195/// }
1196/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001197#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001198macro_rules! do_parse {
1199 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001200 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001201 };
1202
1203 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001204 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001205 };
1206
1207 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1208 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001209 $crate::IResult::Error => $crate::IResult::Error,
1210 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001211 do_parse!(i, $($rest)*),
1212 }
1213 };
1214
1215 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001216 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001217 };
1218
1219 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1220 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001221 $crate::IResult::Error => $crate::IResult::Error,
1222 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001223 let $field = o;
1224 do_parse!(i, $($rest)*)
1225 },
1226 }
1227 };
1228
David Tolnayfa0edf22016-09-23 22:58:24 -07001229 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001230 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001231 };
1232
1233 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1234 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001235 $crate::IResult::Error => $crate::IResult::Error,
1236 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001237 let mut $field = o;
1238 do_parse!(i, $($rest)*)
1239 },
1240 }
1241 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001242}
Michael Layzell416724e2017-05-24 21:12:34 -04001243
1244#[macro_export]
1245macro_rules! input_end {
1246 ($i:expr,) => {
1247 $crate::input_end($i)
1248 };
1249}
1250
1251// Not a public API
1252#[doc(hidden)]
1253pub fn input_end(input: &[TokenTree]) -> IResult<&'static [TokenTree], &'static str> {
1254 if input.is_empty() {
1255 IResult::Done(&[], "")
1256 } else {
1257 IResult::Error
1258 }
1259}