blob: a53688834a88057fd27f15f03cc051343da62abb [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;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070025extern crate proc_macro2;
Michael Layzell5bde96f2017-01-24 17:59:21 -050026
Alex Crichtonccbb45d2017-05-23 10:58:24 -070027#[cfg(feature = "printing")]
28extern crate quote;
29
David Tolnay30a36002017-02-08 14:24:12 -080030#[doc(hidden)]
Alex Crichton7b9e02f2017-05-30 15:54:33 -070031pub use proc_macro2::TokenTree;
Michael Layzell5bde96f2017-01-24 17:59:21 -050032
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;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070038pub mod tokens;
39pub mod span;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070040
Michael Layzell24645a32017-02-04 13:19:26 -050041/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070042#[derive(Debug, PartialEq, Eq, Clone)]
43pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080044 /// Parsing succeeded. The first field contains the rest of the unparsed
45 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070046 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080047 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070048 Error,
49}
50
Michael Layzell416724e2017-05-24 21:12:34 -040051impl<'a, O> IResult<&'a [TokenTree], O> {
Michael Layzell24645a32017-02-04 13:19:26 -050052 /// Unwraps the result, asserting the the parse is complete. Panics with a
53 /// message based on the given string if the parse failed or is incomplete.
David Tolnay1f16b602017-02-07 20:06:55 -050054 ///
55 /// ```rust
56 /// extern crate syn;
57 /// #[macro_use] extern crate synom;
58 ///
59 /// use syn::Ty;
60 /// use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070061 /// use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -050062 ///
63 /// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -070064 /// named!(comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -050065 /// separated_nonempty_list!(punct!(","), ty)
66 /// );
67 ///
68 /// fn main() {
69 /// let input = "&str, Map<K, V>, String";
70 ///
71 /// let parsed = comma_separated_types(input).expect("comma-separated types");
72 ///
73 /// assert_eq!(parsed.len(), 3);
74 /// println!("{:?}", parsed);
75 /// }
76 /// ```
David Tolnayf2222f02017-01-27 17:09:20 -080077 pub fn expect(self, name: &str) -> O {
78 match self {
Michael Layzell416724e2017-05-24 21:12:34 -040079 IResult::Done(rest, o) => {
David Tolnayf2222f02017-01-27 17:09:20 -080080 if rest.is_empty() {
81 o
82 } else {
Michael Layzell416724e2017-05-24 21:12:34 -040083 panic!("unparsed tokens after {}: {:?}", name, /* rest */ ())
David Tolnayf2222f02017-01-27 17:09:20 -080084 }
85 }
86 IResult::Error => panic!("failed to parse {}", name),
87 }
88 }
89}
90
Alex Crichton7b9e02f2017-05-30 15:54:33 -070091pub trait Synom: Sized {
92 fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self>;
93}
94
Michael Layzell24645a32017-02-04 13:19:26 -050095/// Define a function from a parser combination.
96///
David Tolnay1f16b602017-02-07 20:06:55 -050097/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
98///
99/// ```rust
100/// # extern crate syn;
101/// # #[macro_use] extern crate synom;
102/// # use syn::Ty;
103/// # use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700104/// # use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -0500105/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700106/// named!(pub comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500107/// separated_nonempty_list!(punct!(","), ty)
108/// );
109/// # fn main() {}
110/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500111#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700112macro_rules! named {
113 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400114 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 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400120 pub fn $name(i: &[$crate::TokenTree]) -> $crate::IResult<&[$crate::TokenTree], $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700121 $submac!(i, $($args)*)
122 }
123 };
124}
125
David Tolnay1f16b602017-02-07 20:06:55 -0500126/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500127///
128/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500129///
130/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
131/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -0500132///
133/// ```rust
134/// #[macro_use] extern crate synom;
135///
136/// use synom::IResult;
137///
David Tolnay1f16b602017-02-07 20:06:55 -0500138/// // Parses any string up to but not including the given character, returning
139/// // the content up to the given character. The given character is required to
140/// // be present in the input string.
141/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
142/// if let Some(pos) = input.find(ch) {
143/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500144/// } else {
145/// IResult::Error
146/// }
147/// }
148///
David Tolnay1f16b602017-02-07 20:06:55 -0500149/// // Parses any string surrounded by tilde characters '~'. Returns the content
150/// // between the tilde characters.
151/// named!(surrounded_by_tilde -> &str, delimited!(
152/// punct!("~"),
153/// call!(skip_until, '~'),
154/// punct!("~")
155/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500156///
157/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500158/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500159///
David Tolnay1f16b602017-02-07 20:06:55 -0500160/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500161///
David Tolnay1f16b602017-02-07 20:06:55 -0500162/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500163/// }
164/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500165#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700166macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700167 ($i:expr, $fun:expr $(, $args:expr)*) => {
168 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700169 };
170}
171
David Tolnay1f16b602017-02-07 20:06:55 -0500172/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500173///
David Tolnay1f16b602017-02-07 20:06:55 -0500174/// - **Syntax:** `map!(THING, FN)`
175/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500176///
177/// ```rust
178/// extern crate syn;
179/// #[macro_use] extern crate synom;
180///
181/// use syn::{Item, Ident};
182/// use syn::parse::item;
183///
184/// fn get_item_ident(item: Item) -> Ident {
185/// item.ident
186/// }
187///
David Tolnay1f16b602017-02-07 20:06:55 -0500188/// // Parses an item and returns the name (identifier) of the item only.
189/// named!(item_ident -> Ident,
190/// map!(item, get_item_ident)
191/// );
192///
193/// // Or equivalently:
194/// named!(item_ident2 -> Ident,
195/// map!(item, |i: Item| i.ident)
196/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500197///
198/// fn main() {
199/// let input = "fn foo() {}";
200///
David Tolnay1f16b602017-02-07 20:06:55 -0500201/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500202///
David Tolnay1f16b602017-02-07 20:06:55 -0500203/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500204/// }
205/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500206#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700207macro_rules! map {
208 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700209 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500210 $crate::IResult::Error => $crate::IResult::Error,
211 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500212 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700213 }
214 }
215 };
David Tolnay1f16b602017-02-07 20:06:55 -0500216
217 ($i:expr, $f:expr, $g:expr) => {
218 map!($i, call!($f), $g)
219 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700220}
221
David Tolnay1f16b602017-02-07 20:06:55 -0500222/// Parses successfully if the given parser fails to parse. Does not consume any
223/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500224///
225/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500226/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500227///
228/// ```rust
229/// extern crate syn;
230/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500231/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500232///
David Tolnay1f16b602017-02-07 20:06:55 -0500233/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
234/// // Note that a line starting with `#![` is an inner attribute, not a
235/// // shebang.
236/// named!(shebang -> &str, preceded!(
237/// tuple!(tag!("#!"), not!(tag!("["))),
238/// take_until!("\n")
239/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500240///
241/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500242/// let bin_bash = "#!/bin/bash\n";
243/// let parsed = shebang(bin_bash).expect("shebang");
244/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500245///
David Tolnay1f16b602017-02-07 20:06:55 -0500246/// let inner_attr = "#![feature(specialization)]\n";
247/// let err = shebang(inner_attr);
248/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500249/// }
250/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500251#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700252macro_rules! not {
253 ($i:expr, $submac:ident!( $($args:tt)* )) => {
254 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500255 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500256 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700257 }
258 };
259}
260
David Tolnay1f16b602017-02-07 20:06:55 -0500261/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500262///
David Tolnay1f16b602017-02-07 20:06:55 -0500263/// If you are familiar with nom, this is nom's `cond_with_error` parser.
264///
265/// - **Syntax:** `cond!(CONDITION, THING)`
266/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500267///
268/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500269/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500270/// #[macro_use] extern crate synom;
271///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700272/// named!(boolean -> bool, alt!(
273/// keyword!("true") => { |_| true }
274/// |
275/// keyword!("false") => { |_| false }
276/// ));
David Tolnay1f16b602017-02-07 20:06:55 -0500277///
278/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
279/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
280/// // separate vectors for the booleans before and after the dotdot. The second
281/// // vector is None if there was no dotdot.
282/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
283/// punct!("(") >>
284/// before: separated_list!(punct!(","), boolean) >>
285/// after: option!(do_parse!(
286/// // Only allow comma if there are elements before dotdot, i.e. cannot
287/// // be `(, .., true)`.
288/// cond!(!before.is_empty(), punct!(",")) >>
289/// punct!("..") >>
290/// after: many0!(preceded!(punct!(","), boolean)) >>
291/// // Only allow trailing comma if there are elements after dotdot,
292/// // i.e. cannot be `(true, .., )`.
293/// cond!(!after.is_empty(), option!(punct!(","))) >>
294/// (after)
295/// )) >>
296/// // Allow trailing comma if there is no dotdot but there are elements.
297/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
298/// punct!(")") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700299/// (before.into_vec(), after)
David Tolnay1f16b602017-02-07 20:06:55 -0500300/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500301///
302/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500303/// let input = "(true, false, false)";
304/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
305/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500306///
David Tolnay1f16b602017-02-07 20:06:55 -0500307/// let input = "(true, true, .., true)";
308/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
309/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
310///
311/// let input = "(.., true)";
312/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
313/// assert_eq!(parsed, (vec![], Some(vec![true])));
314///
315/// let input = "(true, true, ..)";
316/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
317/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
318///
319/// let input = "(..)";
320/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
321/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500322/// }
323/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500324#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700325macro_rules! cond {
326 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
327 if $cond {
328 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500329 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
330 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700331 }
332 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500333 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700334 }
David Tolnaycfe55022016-10-02 22:02:27 -0700335 };
336
337 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700338 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700339 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700340}
341
David Tolnay1f16b602017-02-07 20:06:55 -0500342/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500343///
David Tolnay1f16b602017-02-07 20:06:55 -0500344/// This is typically used inside of `option!` or `alt!`.
345///
346/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
347/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500348///
349/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500350/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500351/// #[macro_use] extern crate synom;
352///
David Tolnay1f16b602017-02-07 20:06:55 -0500353/// #[derive(Debug, PartialEq)]
354/// struct VariadicBools {
355/// data: Vec<bool>,
356/// variadic: bool,
357/// }
358///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700359/// named!(boolean -> bool, alt!(
360/// keyword!("true") => { |_| true }
361/// |
362/// keyword!("false") => { |_| false }
363/// ));
364///
David Tolnay1f16b602017-02-07 20:06:55 -0500365/// // Parse one or more comma-separated booleans, possibly ending in "..." to
366/// // indicate there may be more.
367/// named!(variadic_bools -> VariadicBools, do_parse!(
368/// data: separated_nonempty_list!(punct!(","), boolean) >>
369/// trailing_comma: option!(punct!(",")) >>
370/// // Only allow "..." if there is a comma after the last boolean. Using
371/// // `cond_reduce!` is more convenient here than using `cond!`. The
372/// // alternatives are:
373/// //
374/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
375/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
376/// // which both mean not variadic.
377/// // - `cond_reduce!(c, option!(p))`
378/// // Incorrect; would fail to parse if there is no trailing comma.
379/// // - `option!(cond_reduce!(c, p))`
380/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
381/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
382/// (VariadicBools {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700383/// data: data.into_vec(),
David Tolnay1f16b602017-02-07 20:06:55 -0500384/// variadic: variadic.is_some(),
385/// })
386/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500387///
388/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500389/// let input = "true, true";
390/// let parsed = variadic_bools(input).expect("variadic bools");
391/// assert_eq!(parsed, VariadicBools {
392/// data: vec![true, true],
393/// variadic: false,
394/// });
395///
396/// let input = "true, ...";
397/// let parsed = variadic_bools(input).expect("variadic bools");
398/// assert_eq!(parsed, VariadicBools {
399/// data: vec![true],
400/// variadic: true,
401/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500402/// }
403/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500404#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700405macro_rules! cond_reduce {
406 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
407 if $cond {
408 $submac!($i, $($args)*)
409 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500410 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700411 }
412 };
413
414 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700415 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700416 };
417}
418
David Tolnay1f16b602017-02-07 20:06:55 -0500419/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500420///
David Tolnay1f16b602017-02-07 20:06:55 -0500421/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500422/// - **Output:** `THING`
423///
424/// ```rust
425/// extern crate syn;
426/// #[macro_use] extern crate synom;
427///
428/// use syn::Expr;
429/// use syn::parse::expr;
430///
431/// // An expression preceded by ##.
432/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500433/// preceded!(punct!("##"), expr)
434/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500435///
436/// fn main() {
437/// let input = "## 1 + 1";
438///
439/// let parsed = pound_pound_expr(input).expect("pound pound expr");
440///
441/// println!("{:?}", parsed);
442/// }
443/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500444#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700445macro_rules! preceded {
446 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
447 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500448 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
449 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700450 }
451 };
452
453 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700454 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700455 };
456
457 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700458 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700459 };
460
461 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700462 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700463 };
464}
465
David Tolnay1f16b602017-02-07 20:06:55 -0500466/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500467///
David Tolnay1f16b602017-02-07 20:06:55 -0500468/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500469/// - **Output:** `THING`
470///
471/// ```rust
472/// extern crate syn;
473/// #[macro_use] extern crate synom;
474///
475/// use syn::Expr;
476/// use syn::parse::expr;
477///
478/// // An expression terminated by ##.
479/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500480/// terminated!(expr, punct!("##"))
481/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500482///
483/// fn main() {
484/// let input = "1 + 1 ##";
485///
486/// let parsed = expr_pound_pound(input).expect("expr pound pound");
487///
488/// println!("{:?}", parsed);
489/// }
490/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500491#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700492macro_rules! terminated {
493 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
494 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500495 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
496 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700497 }
498 };
499
500 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700501 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700502 };
503
504 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700505 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700506 };
507
508 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700509 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700510 };
511}
512
David Tolnay1f16b602017-02-07 20:06:55 -0500513/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500514///
515/// - **Syntax:** `many0!(THING)`
516/// - **Output:** `Vec<THING>`
517///
David Tolnay1f16b602017-02-07 20:06:55 -0500518/// You may also be looking for:
519///
520/// - `separated_list!` - zero or more values with separator
521/// - `separated_nonempty_list!` - one or more values
522/// - `terminated_list!` - zero or more, allows trailing separator
523///
Michael Layzell24645a32017-02-04 13:19:26 -0500524/// ```rust
525/// extern crate syn;
526/// #[macro_use] extern crate synom;
527///
528/// use syn::Item;
529/// use syn::parse::item;
530///
531/// named!(items -> Vec<Item>, many0!(item));
532///
533/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500534/// let input = "
535/// fn a() {}
536/// fn b() {}
537/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500538///
539/// let parsed = items(input).expect("items");
540///
David Tolnay1f16b602017-02-07 20:06:55 -0500541/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500542/// println!("{:?}", parsed);
543/// }
544/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500545#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700546macro_rules! many0 {
547 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
548 let ret;
549 let mut res = ::std::vec::Vec::new();
550 let mut input = $i;
551
552 loop {
553 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500554 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700555 break;
556 }
557
558 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500559 $crate::IResult::Error => {
560 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700561 break;
562 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500563 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700564 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700565 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500566 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700567 break;
568 }
569
570 res.push(o);
571 input = i;
572 }
573 }
574 }
575
576 ret
577 }};
578
579 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500580 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700581 };
582}
583
David Tolnay1f16b602017-02-07 20:06:55 -0500584// Improve compile time by compiling this loop only once per type it is used
585// with.
586//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800587// Not public API.
588#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400589pub fn many0<'a, T>(mut input: &'a [TokenTree],
590 f: fn(&'a [TokenTree]) -> IResult<&'a [TokenTree], T>)
591 -> IResult<&'a [TokenTree], Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700592 let mut res = Vec::new();
593
594 loop {
595 if input.is_empty() {
596 return IResult::Done(input, res);
597 }
598
599 match f(input) {
600 IResult::Error => {
601 return IResult::Done(input, res);
602 }
603 IResult::Done(i, o) => {
604 // loop trip must always consume (otherwise infinite loops)
605 if i.len() == input.len() {
606 return IResult::Error;
607 }
608
609 res.push(o);
610 input = i;
611 }
612 }
613 }
614}
615
David Tolnay1f16b602017-02-07 20:06:55 -0500616/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500617///
618/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500619/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500620///
621/// ```rust
622/// extern crate syn;
623/// #[macro_use] extern crate synom;
624///
David Tolnay1f16b602017-02-07 20:06:55 -0500625/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500626/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500627/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500628///
David Tolnay1f16b602017-02-07 20:06:55 -0500629/// // Parse an expression that begins with an identifier.
630/// named!(ident_expr -> Expr,
631/// preceded!(peek!(ident), expr)
632/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500633///
634/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500635/// // begins with an identifier
636/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500637/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500638/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500639///
640/// // does not begin with an identifier
641/// let input = "1 + banana";
642/// let err = ident_expr(input);
643/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500644/// }
645/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500646#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700647macro_rules! peek {
648 ($i:expr, $submac:ident!( $($args:tt)* )) => {
649 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500650 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
651 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700652 }
653 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700654
David Tolnay1f16b602017-02-07 20:06:55 -0500655 ($i:expr, $f:expr) => {
656 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700657 };
658}
659
David Tolnay1f16b602017-02-07 20:06:55 -0500660/// Parse the part of the input up to but not including the given string. Fail
661/// to parse if the given string is not present in the input.
662///
663/// - **Syntax:** `take_until!("...")`
664/// - **Output:** `&str`
665///
666/// ```rust
667/// extern crate syn;
668/// #[macro_use] extern crate synom;
669/// use synom::IResult;
670///
671/// // Parse a single line doc comment: /// ...
672/// named!(single_line_doc -> &str,
673/// preceded!(punct!("///"), take_until!("\n"))
674/// );
675///
676/// fn main() {
677/// let comment = "/// comment\n";
678/// let parsed = single_line_doc(comment).expect("single line doc comment");
679/// assert_eq!(parsed, " comment");
680/// }
681/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500682#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700683macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500684 ($i:expr, $substr:expr) => {{
685 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500686 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700687 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500688 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700689 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500690 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700691 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500692 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700693 window.push(c);
694 if window.len() > substr_vec.len() {
695 window.remove(0);
696 }
697 if window == substr_vec {
698 parsed = true;
699 window.pop();
700 let window_len: usize = window.iter()
701 .map(|x| x.len_utf8())
702 .fold(0, |x, y| x + y);
703 offset = o - window_len;
704 break;
705 }
706 }
707 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500708 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700709 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500710 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700711 }
712 }
713 }};
714}
715
David Tolnay1f16b602017-02-07 20:06:55 -0500716/// Parse the given string from exactly the current position in the input. You
717/// almost always want `punct!` or `keyword!` instead of this.
718///
719/// The `tag!` parser is equivalent to `punct!` but does not ignore leading
720/// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See
721/// an explanation of synom's whitespace handling strategy in the top-level
722/// crate documentation.
723///
724/// - **Syntax:** `tag!("...")`
725/// - **Output:** `"..."`
726///
727/// ```rust
728/// extern crate syn;
729/// #[macro_use] extern crate synom;
730///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700731/// use syn::Lit;
David Tolnay1f16b602017-02-07 20:06:55 -0500732/// use syn::parse::string;
733/// use synom::IResult;
734///
735/// // Parse a proposed syntax for an owned string literal: "abc"s
736/// named!(owned_string -> String,
737/// map!(
738/// terminated!(string, tag!("s")),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700739/// |lit: Lit| lit.to_string()
David Tolnay1f16b602017-02-07 20:06:55 -0500740/// )
741/// );
742///
743/// fn main() {
744/// let input = r#" "abc"s "#;
745/// let parsed = owned_string(input).expect("owned string literal");
746/// println!("{:?}", parsed);
747///
748/// let input = r#" "abc" s "#;
749/// let err = owned_string(input);
750/// assert_eq!(err, IResult::Error);
751/// }
752/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500753#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700754macro_rules! tag {
David Tolnay1f16b602017-02-07 20:06:55 -0500755 ($i:expr, $tag:expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700756 if $i.starts_with($tag) {
David Tolnay1f16b602017-02-07 20:06:55 -0500757 $crate::IResult::Done(&$i[$tag.len()..], &$i[..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700758 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500759 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700760 }
761 };
762}
763
David Tolnay1f16b602017-02-07 20:06:55 -0500764/// Pattern-match the result of a parser to select which other parser to run.
765///
766/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
767/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
768///
769/// ```rust
770/// extern crate syn;
771/// #[macro_use] extern crate synom;
772///
773/// use syn::{Ident, Ty};
774/// use syn::parse::{ident, ty};
775///
776/// #[derive(Debug)]
777/// enum UnitType {
778/// Struct {
779/// name: Ident,
780/// },
781/// Enum {
782/// name: Ident,
783/// variant: Ident,
784/// },
785/// }
786///
787/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
788/// named!(unit_type -> UnitType, do_parse!(
789/// which: alt!(keyword!("struct") | keyword!("enum")) >>
790/// id: ident >>
791/// item: switch!(value!(which),
792/// "struct" => map!(
793/// punct!(";"),
794/// move |_| UnitType::Struct {
795/// name: id,
796/// }
797/// )
798/// |
799/// "enum" => map!(
800/// delimited!(punct!("{"), ident, punct!("}")),
801/// move |variant| UnitType::Enum {
802/// name: id,
803/// variant: variant,
804/// }
805/// )
806/// ) >>
807/// (item)
808/// ));
809///
810/// fn main() {
811/// let input = "struct S;";
812/// let parsed = unit_type(input).expect("unit struct or enum");
813/// println!("{:?}", parsed);
814///
815/// let input = "enum E { V }";
816/// let parsed = unit_type(input).expect("unit struct or enum");
817/// println!("{:?}", parsed);
818/// }
819/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500820#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700821macro_rules! switch {
822 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
823 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500824 $crate::IResult::Error => $crate::IResult::Error,
825 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700826 $(
827 $p => $subrule!(i, $($args2)*),
828 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500829 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700830 }
831 }
832 };
833}
834
David Tolnay1f16b602017-02-07 20:06:55 -0500835/// Produce the given value without parsing anything. Useful as an argument to
836/// `switch!`.
837///
838/// - **Syntax:** `value!(VALUE)`
839/// - **Output:** `VALUE`
840///
841/// ```rust
842/// extern crate syn;
843/// #[macro_use] extern crate synom;
844///
845/// use syn::{Ident, Ty};
846/// use syn::parse::{ident, ty};
847///
848/// #[derive(Debug)]
849/// enum UnitType {
850/// Struct {
851/// name: Ident,
852/// },
853/// Enum {
854/// name: Ident,
855/// variant: Ident,
856/// },
857/// }
858///
859/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
860/// named!(unit_type -> UnitType, do_parse!(
861/// which: alt!(keyword!("struct") | keyword!("enum")) >>
862/// id: ident >>
863/// item: switch!(value!(which),
864/// "struct" => map!(
865/// punct!(";"),
866/// move |_| UnitType::Struct {
867/// name: id,
868/// }
869/// )
870/// |
871/// "enum" => map!(
872/// delimited!(punct!("{"), ident, punct!("}")),
873/// move |variant| UnitType::Enum {
874/// name: id,
875/// variant: variant,
876/// }
877/// )
878/// ) >>
879/// (item)
880/// ));
881///
882/// fn main() {
883/// let input = "struct S;";
884/// let parsed = unit_type(input).expect("unit struct or enum");
885/// println!("{:?}", parsed);
886///
887/// let input = "enum E { V }";
888/// let parsed = unit_type(input).expect("unit struct or enum");
889/// println!("{:?}", parsed);
890/// }
891/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500892#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700893macro_rules! value {
894 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500895 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700896 };
897}
898
David Tolnayf2222f02017-01-27 17:09:20 -0800899/// Value surrounded by a pair of delimiters.
900///
901/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
902/// - **Output:** `THING`
903///
904/// ```rust
905/// extern crate syn;
906/// #[macro_use] extern crate synom;
907///
908/// use syn::Expr;
909/// use syn::parse::expr;
910///
911/// // An expression surrounded by [[ ... ]].
912/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500913/// delimited!(punct!("[["), expr, punct!("]]"))
914/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800915///
916/// fn main() {
917/// let input = "[[ 1 + 1 ]]";
918///
919/// let parsed = double_bracket_expr(input).expect("double bracket expr");
920///
921/// println!("{:?}", parsed);
922/// }
923/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500924#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700925macro_rules! delimited {
926 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
927 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500928 $crate::IResult::Error => $crate::IResult::Error,
929 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700930 }
931 };
932
933 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700934 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700935 };
936}
937
David Tolnay1f16b602017-02-07 20:06:55 -0500938/// One or more values separated by some separator. Does not allow a trailing
939/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800940///
941/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
942/// - **Output:** `Vec<THING>`
943///
David Tolnay1f16b602017-02-07 20:06:55 -0500944/// You may also be looking for:
945///
946/// - `separated_list!` - one or more values
947/// - `terminated_list!` - zero or more, allows trailing separator
948/// - `many0!` - zero or more, no separator
949///
David Tolnayf2222f02017-01-27 17:09:20 -0800950/// ```rust
951/// extern crate syn;
952/// #[macro_use] extern crate synom;
953///
954/// use syn::Ty;
955/// use syn::parse::ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700956/// use synom::delimited::Delimited;
David Tolnayf2222f02017-01-27 17:09:20 -0800957///
958/// // One or more Rust types separated by commas.
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700959/// named!(comma_separated_types -> Delimited<Ty, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500960/// separated_nonempty_list!(punct!(","), ty)
961/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800962///
963/// fn main() {
964/// let input = "&str, Map<K, V>, String";
965///
966/// let parsed = comma_separated_types(input).expect("comma-separated types");
967///
968/// assert_eq!(parsed.len(), 3);
969/// println!("{:?}", parsed);
970/// }
971/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500972#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700973macro_rules! separated_nonempty_list {
974 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700975 let mut res = $crate::delimited::Delimited::new();
David Tolnayb5a7b142016-09-13 22:46:39 -0700976 let mut input = $i;
977
978 // get the first element
979 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500980 $crate::IResult::Error => $crate::IResult::Error,
981 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700982 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500983 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700984 } else {
David Tolnayb5a7b142016-09-13 22:46:39 -0700985 input = i;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700986 res.push_first(o);
David Tolnayb5a7b142016-09-13 22:46:39 -0700987
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700988 while let $crate::IResult::Done(i2, s) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700989 if i2.len() == input.len() {
990 break;
991 }
992
Michael Layzell5bde96f2017-01-24 17:59:21 -0500993 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700994 res.push_next(o3, s);
David Tolnayb5a7b142016-09-13 22:46:39 -0700995 if i3.len() == i2.len() {
996 break;
997 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700998 input = i3;
999 } else {
1000 break;
1001 }
1002 }
Michael Layzell5bde96f2017-01-24 17:59:21 -05001003 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -07001004 }
1005 }
1006 }
1007 }};
1008
1009 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001010 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001011 };
1012
1013 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001014 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001015 };
1016
1017 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001018 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -07001019 };
1020}
1021
David Tolnay1f16b602017-02-07 20:06:55 -05001022/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -05001023///
David Tolnay1f16b602017-02-07 20:06:55 -05001024/// - **Syntax:** `tuple!(A, B, C, ...)`
1025/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -05001026///
1027/// ```rust
1028/// extern crate syn;
1029/// #[macro_use] extern crate synom;
1030///
1031/// use syn::Ty;
1032/// use syn::parse::ty;
1033///
1034/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
1035///
1036/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001037/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -05001038///
David Tolnay1f16b602017-02-07 20:06:55 -05001039/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -05001040///
1041/// println!("{:?}", parsed);
1042/// }
1043/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001044#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001045macro_rules! tuple {
1046 ($i:expr, $($rest:tt)*) => {
1047 tuple_parser!($i, (), $($rest)*)
1048 };
1049}
1050
David Tolnay1f16b602017-02-07 20:06:55 -05001051/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001052#[doc(hidden)]
1053#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001054macro_rules! tuple_parser {
1055 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001056 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001057 };
1058
1059 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1060 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001061 $crate::IResult::Error => $crate::IResult::Error,
1062 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001063 tuple_parser!(i, (o), $($rest)*),
1064 }
1065 };
1066
1067 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1068 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001069 $crate::IResult::Error => $crate::IResult::Error,
1070 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001071 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1072 }
1073 };
1074
1075 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001076 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001077 };
1078
1079 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1080 $submac!($i, $($args)*)
1081 };
1082
1083 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1084 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001085 $crate::IResult::Error => $crate::IResult::Error,
1086 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001087 }
1088 };
1089
1090 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001091 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001092 };
1093}
1094
David Tolnay1f16b602017-02-07 20:06:55 -05001095/// Run a series of parsers, returning the result of the first one which
1096/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001097///
1098/// Optionally allows for the result to be transformed.
1099///
1100/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001101/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001102///
1103/// ```rust
1104/// extern crate syn;
1105/// #[macro_use] extern crate synom;
1106///
1107/// use syn::Ident;
1108/// use syn::parse::ident;
1109///
1110/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001111/// alt!(
1112/// ident
1113/// |
1114/// punct!("!") => { |_| "BANG".into() }
1115/// )
1116/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001117///
1118/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001119/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001120/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1121/// assert_eq!(parsed, "foo");
1122///
1123/// let input = "!";
1124/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1125/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001126/// }
1127/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001128#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001129macro_rules! alt {
1130 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001131 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001132 };
1133
1134 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1135 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001136 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001137 _ => alt!($i, $($rest)*)
1138 }
1139 };
1140
1141 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1142 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001143 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1144 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001145 }
1146 };
1147
1148 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001149 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001150 };
1151
1152 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001153 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001154 };
1155
1156 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1157 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001158 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1159 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001160 }
1161 };
1162
1163 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001164 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001165 };
1166
1167 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001168 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001169 };
1170}
1171
Michael Layzell24645a32017-02-04 13:19:26 -05001172/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001173/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001174///
David Tolnay1f16b602017-02-07 20:06:55 -05001175/// Produces the result of evaluating the final expression in parentheses with
1176/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001177///
David Tolnay1f16b602017-02-07 20:06:55 -05001178/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001179/// - **Output:** `RESULT`
1180///
1181/// ```rust
1182/// extern crate syn;
1183/// #[macro_use] extern crate synom;
1184///
1185/// use syn::{Ident, TokenTree};
1186/// use syn::parse::{ident, tt};
1187///
David Tolnay1f16b602017-02-07 20:06:55 -05001188/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001189/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1190/// name: ident >>
1191/// punct!("!") >>
1192/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001193/// (name, body)
1194/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001195///
1196/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001197/// let input = "stringify!($args)";
1198/// let (name, body) = simple_mac(input).expect("macro invocation");
1199/// println!("{:?}", name);
1200/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001201/// }
1202/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001203#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001204macro_rules! do_parse {
1205 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001206 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001207 };
1208
1209 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001210 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001211 };
1212
1213 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1214 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001215 $crate::IResult::Error => $crate::IResult::Error,
1216 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001217 do_parse!(i, $($rest)*),
1218 }
1219 };
1220
1221 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001222 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001223 };
1224
1225 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1226 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001227 $crate::IResult::Error => $crate::IResult::Error,
1228 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001229 let $field = o;
1230 do_parse!(i, $($rest)*)
1231 },
1232 }
1233 };
1234
David Tolnayfa0edf22016-09-23 22:58:24 -07001235 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001236 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001237 };
1238
1239 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1240 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001241 $crate::IResult::Error => $crate::IResult::Error,
1242 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001243 let mut $field = o;
1244 do_parse!(i, $($rest)*)
1245 },
1246 }
1247 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001248}
Michael Layzell416724e2017-05-24 21:12:34 -04001249
1250#[macro_export]
1251macro_rules! input_end {
1252 ($i:expr,) => {
1253 $crate::input_end($i)
1254 };
1255}
1256
1257// Not a public API
1258#[doc(hidden)]
1259pub fn input_end(input: &[TokenTree]) -> IResult<&'static [TokenTree], &'static str> {
1260 if input.is_empty() {
1261 IResult::Done(&[], "")
1262 } else {
1263 IResult::Error
1264 }
1265}