blob: 97c7833029ab7f62c32b8319fe3f3f897788e8c5 [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
David Tolnay30a36002017-02-08 14:24:12 -080026#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -050027pub mod space;
28
David Tolnay5fe14fc2017-01-27 16:22:08 -080029#[doc(hidden)]
30pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050031
Michael Layzell24645a32017-02-04 13:19:26 -050032/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070033#[derive(Debug, PartialEq, Eq, Clone)]
34pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080035 /// Parsing succeeded. The first field contains the rest of the unparsed
36 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070037 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080038 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070039 Error,
40}
41
David Tolnayf2222f02017-01-27 17:09:20 -080042impl<'a, O> IResult<&'a str, O> {
Michael Layzell24645a32017-02-04 13:19:26 -050043 /// Unwraps the result, asserting the the parse is complete. Panics with a
44 /// message based on the given string if the parse failed or is incomplete.
David Tolnay1f16b602017-02-07 20:06:55 -050045 ///
46 /// ```rust
47 /// extern crate syn;
48 /// #[macro_use] extern crate synom;
49 ///
50 /// use syn::Ty;
51 /// use syn::parse::ty;
52 ///
53 /// // One or more Rust types separated by commas.
54 /// named!(comma_separated_types -> Vec<Ty>,
55 /// separated_nonempty_list!(punct!(","), ty)
56 /// );
57 ///
58 /// fn main() {
59 /// let input = "&str, Map<K, V>, String";
60 ///
61 /// let parsed = comma_separated_types(input).expect("comma-separated types");
62 ///
63 /// assert_eq!(parsed.len(), 3);
64 /// println!("{:?}", parsed);
65 /// }
66 /// ```
David Tolnayf2222f02017-01-27 17:09:20 -080067 pub fn expect(self, name: &str) -> O {
68 match self {
69 IResult::Done(mut rest, o) => {
70 rest = space::skip_whitespace(rest);
71 if rest.is_empty() {
72 o
73 } else {
74 panic!("unparsed tokens after {}: {:?}", name, rest)
75 }
76 }
77 IResult::Error => panic!("failed to parse {}", name),
78 }
79 }
80}
81
Michael Layzell24645a32017-02-04 13:19:26 -050082/// Define a function from a parser combination.
83///
David Tolnay1f16b602017-02-07 20:06:55 -050084/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
85///
86/// ```rust
87/// # extern crate syn;
88/// # #[macro_use] extern crate synom;
89/// # use syn::Ty;
90/// # use syn::parse::ty;
91/// // One or more Rust types separated by commas.
92/// named!(pub comma_separated_types -> Vec<Ty>,
93/// separated_nonempty_list!(punct!(","), ty)
94/// );
95/// # fn main() {}
96/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050097#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070098macro_rules! named {
99 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500100 fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700101 $submac!(i, $($args)*)
102 }
103 };
104
105 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500106 pub fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700107 $submac!(i, $($args)*)
108 }
109 };
110}
111
David Tolnay1f16b602017-02-07 20:06:55 -0500112/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500113///
114/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500115///
116/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
117/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -0500118///
119/// ```rust
120/// #[macro_use] extern crate synom;
121///
122/// use synom::IResult;
123///
David Tolnay1f16b602017-02-07 20:06:55 -0500124/// // Parses any string up to but not including the given character, returning
125/// // the content up to the given character. The given character is required to
126/// // be present in the input string.
127/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
128/// if let Some(pos) = input.find(ch) {
129/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500130/// } else {
131/// IResult::Error
132/// }
133/// }
134///
David Tolnay1f16b602017-02-07 20:06:55 -0500135/// // Parses any string surrounded by tilde characters '~'. Returns the content
136/// // between the tilde characters.
137/// named!(surrounded_by_tilde -> &str, delimited!(
138/// punct!("~"),
139/// call!(skip_until, '~'),
140/// punct!("~")
141/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500142///
143/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500144/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500145///
David Tolnay1f16b602017-02-07 20:06:55 -0500146/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500147///
David Tolnay1f16b602017-02-07 20:06:55 -0500148/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500149/// }
150/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500151#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700152macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700153 ($i:expr, $fun:expr $(, $args:expr)*) => {
154 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700155 };
156}
157
David Tolnay1f16b602017-02-07 20:06:55 -0500158/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500159///
David Tolnay1f16b602017-02-07 20:06:55 -0500160/// - **Syntax:** `map!(THING, FN)`
161/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500162///
163/// ```rust
164/// extern crate syn;
165/// #[macro_use] extern crate synom;
166///
167/// use syn::{Item, Ident};
168/// use syn::parse::item;
169///
170/// fn get_item_ident(item: Item) -> Ident {
171/// item.ident
172/// }
173///
David Tolnay1f16b602017-02-07 20:06:55 -0500174/// // Parses an item and returns the name (identifier) of the item only.
175/// named!(item_ident -> Ident,
176/// map!(item, get_item_ident)
177/// );
178///
179/// // Or equivalently:
180/// named!(item_ident2 -> Ident,
181/// map!(item, |i: Item| i.ident)
182/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500183///
184/// fn main() {
185/// let input = "fn foo() {}";
186///
David Tolnay1f16b602017-02-07 20:06:55 -0500187/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500188///
David Tolnay1f16b602017-02-07 20:06:55 -0500189/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500190/// }
191/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500192#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700193macro_rules! map {
194 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700195 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500196 $crate::IResult::Error => $crate::IResult::Error,
197 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500198 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700199 }
200 }
201 };
David Tolnay1f16b602017-02-07 20:06:55 -0500202
203 ($i:expr, $f:expr, $g:expr) => {
204 map!($i, call!($f), $g)
205 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700206}
207
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// Parses successfully if the given parser fails to parse. Does not consume any
209/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500210///
211/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500212/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500213///
214/// ```rust
215/// extern crate syn;
216/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500217/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500218///
David Tolnay1f16b602017-02-07 20:06:55 -0500219/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
220/// // Note that a line starting with `#![` is an inner attribute, not a
221/// // shebang.
222/// named!(shebang -> &str, preceded!(
223/// tuple!(tag!("#!"), not!(tag!("["))),
224/// take_until!("\n")
225/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500226///
227/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500228/// let bin_bash = "#!/bin/bash\n";
229/// let parsed = shebang(bin_bash).expect("shebang");
230/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500231///
David Tolnay1f16b602017-02-07 20:06:55 -0500232/// let inner_attr = "#![feature(specialization)]\n";
233/// let err = shebang(inner_attr);
234/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500235/// }
236/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500237#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700238macro_rules! not {
239 ($i:expr, $submac:ident!( $($args:tt)* )) => {
240 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500241 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500242 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700243 }
244 };
245}
246
David Tolnay1f16b602017-02-07 20:06:55 -0500247/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500248///
David Tolnay1f16b602017-02-07 20:06:55 -0500249/// If you are familiar with nom, this is nom's `cond_with_error` parser.
250///
251/// - **Syntax:** `cond!(CONDITION, THING)`
252/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500253///
254/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500255/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500256/// #[macro_use] extern crate synom;
257///
David Tolnay1f16b602017-02-07 20:06:55 -0500258/// use syn::parse::boolean;
259///
260/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
261/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
262/// // separate vectors for the booleans before and after the dotdot. The second
263/// // vector is None if there was no dotdot.
264/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
265/// punct!("(") >>
266/// before: separated_list!(punct!(","), boolean) >>
267/// after: option!(do_parse!(
268/// // Only allow comma if there are elements before dotdot, i.e. cannot
269/// // be `(, .., true)`.
270/// cond!(!before.is_empty(), punct!(",")) >>
271/// punct!("..") >>
272/// after: many0!(preceded!(punct!(","), boolean)) >>
273/// // Only allow trailing comma if there are elements after dotdot,
274/// // i.e. cannot be `(true, .., )`.
275/// cond!(!after.is_empty(), option!(punct!(","))) >>
276/// (after)
277/// )) >>
278/// // Allow trailing comma if there is no dotdot but there are elements.
279/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
280/// punct!(")") >>
281/// (before, after)
282/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500283///
284/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500285/// let input = "(true, false, false)";
286/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
287/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500288///
David Tolnay1f16b602017-02-07 20:06:55 -0500289/// let input = "(true, true, .., true)";
290/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
291/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
292///
293/// let input = "(.., true)";
294/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
295/// assert_eq!(parsed, (vec![], Some(vec![true])));
296///
297/// let input = "(true, true, ..)";
298/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
299/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
300///
301/// let input = "(..)";
302/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
303/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500304/// }
305/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500306#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700307macro_rules! cond {
308 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
309 if $cond {
310 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500311 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
312 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700313 }
314 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500315 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700316 }
David Tolnaycfe55022016-10-02 22:02:27 -0700317 };
318
319 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700320 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700321 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700322}
323
David Tolnay1f16b602017-02-07 20:06:55 -0500324/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500325///
David Tolnay1f16b602017-02-07 20:06:55 -0500326/// This is typically used inside of `option!` or `alt!`.
327///
328/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
329/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500330///
331/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500332/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500333/// #[macro_use] extern crate synom;
334///
David Tolnay1f16b602017-02-07 20:06:55 -0500335/// use syn::parse::boolean;
336///
337/// #[derive(Debug, PartialEq)]
338/// struct VariadicBools {
339/// data: Vec<bool>,
340/// variadic: bool,
341/// }
342///
343/// // Parse one or more comma-separated booleans, possibly ending in "..." to
344/// // indicate there may be more.
345/// named!(variadic_bools -> VariadicBools, do_parse!(
346/// data: separated_nonempty_list!(punct!(","), boolean) >>
347/// trailing_comma: option!(punct!(",")) >>
348/// // Only allow "..." if there is a comma after the last boolean. Using
349/// // `cond_reduce!` is more convenient here than using `cond!`. The
350/// // alternatives are:
351/// //
352/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
353/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
354/// // which both mean not variadic.
355/// // - `cond_reduce!(c, option!(p))`
356/// // Incorrect; would fail to parse if there is no trailing comma.
357/// // - `option!(cond_reduce!(c, p))`
358/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
359/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
360/// (VariadicBools {
361/// data: data,
362/// variadic: variadic.is_some(),
363/// })
364/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500365///
366/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500367/// let input = "true, true";
368/// let parsed = variadic_bools(input).expect("variadic bools");
369/// assert_eq!(parsed, VariadicBools {
370/// data: vec![true, true],
371/// variadic: false,
372/// });
373///
374/// let input = "true, ...";
375/// let parsed = variadic_bools(input).expect("variadic bools");
376/// assert_eq!(parsed, VariadicBools {
377/// data: vec![true],
378/// variadic: true,
379/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500380/// }
381/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500382#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700383macro_rules! cond_reduce {
384 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
385 if $cond {
386 $submac!($i, $($args)*)
387 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500388 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700389 }
390 };
391
392 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700393 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700394 };
395}
396
David Tolnay1f16b602017-02-07 20:06:55 -0500397/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500398///
David Tolnay1f16b602017-02-07 20:06:55 -0500399/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500400/// - **Output:** `THING`
401///
402/// ```rust
403/// extern crate syn;
404/// #[macro_use] extern crate synom;
405///
406/// use syn::Expr;
407/// use syn::parse::expr;
408///
409/// // An expression preceded by ##.
410/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500411/// preceded!(punct!("##"), expr)
412/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500413///
414/// fn main() {
415/// let input = "## 1 + 1";
416///
417/// let parsed = pound_pound_expr(input).expect("pound pound expr");
418///
419/// println!("{:?}", parsed);
420/// }
421/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500422#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700423macro_rules! preceded {
424 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
425 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500426 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
427 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700428 }
429 };
430
431 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700432 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700433 };
434
435 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700436 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700437 };
438
439 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700440 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700441 };
442}
443
David Tolnay1f16b602017-02-07 20:06:55 -0500444/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500445///
David Tolnay1f16b602017-02-07 20:06:55 -0500446/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500447/// - **Output:** `THING`
448///
449/// ```rust
450/// extern crate syn;
451/// #[macro_use] extern crate synom;
452///
453/// use syn::Expr;
454/// use syn::parse::expr;
455///
456/// // An expression terminated by ##.
457/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500458/// terminated!(expr, punct!("##"))
459/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500460///
461/// fn main() {
462/// let input = "1 + 1 ##";
463///
464/// let parsed = expr_pound_pound(input).expect("expr pound pound");
465///
466/// println!("{:?}", parsed);
467/// }
468/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500469#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700470macro_rules! terminated {
471 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
472 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500473 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
474 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700475 }
476 };
477
478 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700479 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700480 };
481
482 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700483 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700484 };
485
486 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700487 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700488 };
489}
490
David Tolnay1f16b602017-02-07 20:06:55 -0500491/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500492///
493/// - **Syntax:** `many0!(THING)`
494/// - **Output:** `Vec<THING>`
495///
David Tolnay1f16b602017-02-07 20:06:55 -0500496/// You may also be looking for:
497///
498/// - `separated_list!` - zero or more values with separator
499/// - `separated_nonempty_list!` - one or more values
500/// - `terminated_list!` - zero or more, allows trailing separator
501///
Michael Layzell24645a32017-02-04 13:19:26 -0500502/// ```rust
503/// extern crate syn;
504/// #[macro_use] extern crate synom;
505///
506/// use syn::Item;
507/// use syn::parse::item;
508///
509/// named!(items -> Vec<Item>, many0!(item));
510///
511/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500512/// let input = "
513/// fn a() {}
514/// fn b() {}
515/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500516///
517/// let parsed = items(input).expect("items");
518///
David Tolnay1f16b602017-02-07 20:06:55 -0500519/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500520/// println!("{:?}", parsed);
521/// }
522/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500523#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700524macro_rules! many0 {
525 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
526 let ret;
527 let mut res = ::std::vec::Vec::new();
528 let mut input = $i;
529
530 loop {
531 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500532 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700533 break;
534 }
535
536 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500537 $crate::IResult::Error => {
538 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700539 break;
540 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500541 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700542 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700543 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500544 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700545 break;
546 }
547
548 res.push(o);
549 input = i;
550 }
551 }
552 }
553
554 ret
555 }};
556
557 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500558 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700559 };
560}
561
David Tolnay1f16b602017-02-07 20:06:55 -0500562// Improve compile time by compiling this loop only once per type it is used
563// with.
564//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800565// Not public API.
566#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700567pub fn many0<'a, T>(mut input: &'a str,
568 f: fn(&'a str) -> IResult<&'a str, T>)
569 -> IResult<&'a str, Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700570 let mut res = Vec::new();
571
572 loop {
573 if input.is_empty() {
574 return IResult::Done(input, res);
575 }
576
577 match f(input) {
578 IResult::Error => {
579 return IResult::Done(input, res);
580 }
581 IResult::Done(i, o) => {
582 // loop trip must always consume (otherwise infinite loops)
583 if i.len() == input.len() {
584 return IResult::Error;
585 }
586
587 res.push(o);
588 input = i;
589 }
590 }
591 }
592}
593
David Tolnay1f16b602017-02-07 20:06:55 -0500594/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500595///
596/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500597/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500598///
599/// ```rust
600/// extern crate syn;
601/// #[macro_use] extern crate synom;
602///
David Tolnay1f16b602017-02-07 20:06:55 -0500603/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500604/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500605/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500606///
David Tolnay1f16b602017-02-07 20:06:55 -0500607/// // Parse an expression that begins with an identifier.
608/// named!(ident_expr -> Expr,
609/// preceded!(peek!(ident), expr)
610/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500611///
612/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500613/// // begins with an identifier
614/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500615/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500616/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500617///
618/// // does not begin with an identifier
619/// let input = "1 + banana";
620/// let err = ident_expr(input);
621/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500622/// }
623/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500624#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700625macro_rules! peek {
626 ($i:expr, $submac:ident!( $($args:tt)* )) => {
627 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500628 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
629 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700630 }
631 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700632
David Tolnay1f16b602017-02-07 20:06:55 -0500633 ($i:expr, $f:expr) => {
634 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700635 };
636}
637
David Tolnay1f16b602017-02-07 20:06:55 -0500638/// Parse the part of the input up to but not including the given string. Fail
639/// to parse if the given string is not present in the input.
640///
641/// - **Syntax:** `take_until!("...")`
642/// - **Output:** `&str`
643///
644/// ```rust
645/// extern crate syn;
646/// #[macro_use] extern crate synom;
647/// use synom::IResult;
648///
649/// // Parse a single line doc comment: /// ...
650/// named!(single_line_doc -> &str,
651/// preceded!(punct!("///"), take_until!("\n"))
652/// );
653///
654/// fn main() {
655/// let comment = "/// comment\n";
656/// let parsed = single_line_doc(comment).expect("single line doc comment");
657/// assert_eq!(parsed, " comment");
658/// }
659/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500660#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700661macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500662 ($i:expr, $substr:expr) => {{
663 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500664 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700665 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500666 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700667 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500668 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700669 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500670 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700671 window.push(c);
672 if window.len() > substr_vec.len() {
673 window.remove(0);
674 }
675 if window == substr_vec {
676 parsed = true;
677 window.pop();
678 let window_len: usize = window.iter()
679 .map(|x| x.len_utf8())
680 .fold(0, |x, y| x + y);
681 offset = o - window_len;
682 break;
683 }
684 }
685 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500686 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700687 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500688 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700689 }
690 }
691 }};
692}
693
David Tolnay1f16b602017-02-07 20:06:55 -0500694/// Parse the given string from exactly the current position in the input. You
695/// almost always want `punct!` or `keyword!` instead of this.
696///
697/// The `tag!` parser is equivalent to `punct!` but does not ignore leading
698/// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See
699/// an explanation of synom's whitespace handling strategy in the top-level
700/// crate documentation.
701///
702/// - **Syntax:** `tag!("...")`
703/// - **Output:** `"..."`
704///
705/// ```rust
706/// extern crate syn;
707/// #[macro_use] extern crate synom;
708///
709/// use syn::StrLit;
710/// use syn::parse::string;
711/// use synom::IResult;
712///
713/// // Parse a proposed syntax for an owned string literal: "abc"s
714/// named!(owned_string -> String,
715/// map!(
716/// terminated!(string, tag!("s")),
717/// |lit: StrLit| lit.value
718/// )
719/// );
720///
721/// fn main() {
722/// let input = r#" "abc"s "#;
723/// let parsed = owned_string(input).expect("owned string literal");
724/// println!("{:?}", parsed);
725///
726/// let input = r#" "abc" s "#;
727/// let err = owned_string(input);
728/// assert_eq!(err, IResult::Error);
729/// }
730/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500731#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700732macro_rules! tag {
David Tolnay1f16b602017-02-07 20:06:55 -0500733 ($i:expr, $tag:expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700734 if $i.starts_with($tag) {
David Tolnay1f16b602017-02-07 20:06:55 -0500735 $crate::IResult::Done(&$i[$tag.len()..], &$i[..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700736 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500737 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700738 }
739 };
740}
741
David Tolnay1f16b602017-02-07 20:06:55 -0500742/// Pattern-match the result of a parser to select which other parser to run.
743///
744/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
745/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
746///
747/// ```rust
748/// extern crate syn;
749/// #[macro_use] extern crate synom;
750///
751/// use syn::{Ident, Ty};
752/// use syn::parse::{ident, ty};
753///
754/// #[derive(Debug)]
755/// enum UnitType {
756/// Struct {
757/// name: Ident,
758/// },
759/// Enum {
760/// name: Ident,
761/// variant: Ident,
762/// },
763/// }
764///
765/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
766/// named!(unit_type -> UnitType, do_parse!(
767/// which: alt!(keyword!("struct") | keyword!("enum")) >>
768/// id: ident >>
769/// item: switch!(value!(which),
770/// "struct" => map!(
771/// punct!(";"),
772/// move |_| UnitType::Struct {
773/// name: id,
774/// }
775/// )
776/// |
777/// "enum" => map!(
778/// delimited!(punct!("{"), ident, punct!("}")),
779/// move |variant| UnitType::Enum {
780/// name: id,
781/// variant: variant,
782/// }
783/// )
784/// ) >>
785/// (item)
786/// ));
787///
788/// fn main() {
789/// let input = "struct S;";
790/// let parsed = unit_type(input).expect("unit struct or enum");
791/// println!("{:?}", parsed);
792///
793/// let input = "enum E { V }";
794/// let parsed = unit_type(input).expect("unit struct or enum");
795/// println!("{:?}", parsed);
796/// }
797/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500798#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700799macro_rules! switch {
800 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
801 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500802 $crate::IResult::Error => $crate::IResult::Error,
803 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700804 $(
805 $p => $subrule!(i, $($args2)*),
806 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500807 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700808 }
809 }
810 };
811}
812
David Tolnay1f16b602017-02-07 20:06:55 -0500813/// Produce the given value without parsing anything. Useful as an argument to
814/// `switch!`.
815///
816/// - **Syntax:** `value!(VALUE)`
817/// - **Output:** `VALUE`
818///
819/// ```rust
820/// extern crate syn;
821/// #[macro_use] extern crate synom;
822///
823/// use syn::{Ident, Ty};
824/// use syn::parse::{ident, ty};
825///
826/// #[derive(Debug)]
827/// enum UnitType {
828/// Struct {
829/// name: Ident,
830/// },
831/// Enum {
832/// name: Ident,
833/// variant: Ident,
834/// },
835/// }
836///
837/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
838/// named!(unit_type -> UnitType, do_parse!(
839/// which: alt!(keyword!("struct") | keyword!("enum")) >>
840/// id: ident >>
841/// item: switch!(value!(which),
842/// "struct" => map!(
843/// punct!(";"),
844/// move |_| UnitType::Struct {
845/// name: id,
846/// }
847/// )
848/// |
849/// "enum" => map!(
850/// delimited!(punct!("{"), ident, punct!("}")),
851/// move |variant| UnitType::Enum {
852/// name: id,
853/// variant: variant,
854/// }
855/// )
856/// ) >>
857/// (item)
858/// ));
859///
860/// fn main() {
861/// let input = "struct S;";
862/// let parsed = unit_type(input).expect("unit struct or enum");
863/// println!("{:?}", parsed);
864///
865/// let input = "enum E { V }";
866/// let parsed = unit_type(input).expect("unit struct or enum");
867/// println!("{:?}", parsed);
868/// }
869/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500870#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700871macro_rules! value {
872 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500873 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700874 };
875}
876
David Tolnayf2222f02017-01-27 17:09:20 -0800877/// Value surrounded by a pair of delimiters.
878///
879/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
880/// - **Output:** `THING`
881///
882/// ```rust
883/// extern crate syn;
884/// #[macro_use] extern crate synom;
885///
886/// use syn::Expr;
887/// use syn::parse::expr;
888///
889/// // An expression surrounded by [[ ... ]].
890/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500891/// delimited!(punct!("[["), expr, punct!("]]"))
892/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800893///
894/// fn main() {
895/// let input = "[[ 1 + 1 ]]";
896///
897/// let parsed = double_bracket_expr(input).expect("double bracket expr");
898///
899/// println!("{:?}", parsed);
900/// }
901/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500902#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700903macro_rules! delimited {
904 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
905 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500906 $crate::IResult::Error => $crate::IResult::Error,
907 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700908 }
909 };
910
911 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700912 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700913 };
914}
915
David Tolnay1f16b602017-02-07 20:06:55 -0500916/// One or more values separated by some separator. Does not allow a trailing
917/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800918///
919/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
920/// - **Output:** `Vec<THING>`
921///
David Tolnay1f16b602017-02-07 20:06:55 -0500922/// You may also be looking for:
923///
924/// - `separated_list!` - one or more values
925/// - `terminated_list!` - zero or more, allows trailing separator
926/// - `many0!` - zero or more, no separator
927///
David Tolnayf2222f02017-01-27 17:09:20 -0800928/// ```rust
929/// extern crate syn;
930/// #[macro_use] extern crate synom;
931///
932/// use syn::Ty;
933/// use syn::parse::ty;
934///
935/// // One or more Rust types separated by commas.
936/// named!(comma_separated_types -> Vec<Ty>,
David Tolnay1f16b602017-02-07 20:06:55 -0500937/// separated_nonempty_list!(punct!(","), ty)
938/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800939///
940/// fn main() {
941/// let input = "&str, Map<K, V>, String";
942///
943/// let parsed = comma_separated_types(input).expect("comma-separated types");
944///
945/// assert_eq!(parsed.len(), 3);
946/// println!("{:?}", parsed);
947/// }
948/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500949#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700950macro_rules! separated_nonempty_list {
951 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
952 let mut res = ::std::vec::Vec::new();
953 let mut input = $i;
954
955 // get the first element
956 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500957 $crate::IResult::Error => $crate::IResult::Error,
958 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700959 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500960 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700961 } else {
962 res.push(o);
963 input = i;
964
Michael Layzell5bde96f2017-01-24 17:59:21 -0500965 while let $crate::IResult::Done(i2, _) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700966 if i2.len() == input.len() {
967 break;
968 }
969
Michael Layzell5bde96f2017-01-24 17:59:21 -0500970 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700971 if i3.len() == i2.len() {
972 break;
973 }
974 res.push(o3);
975 input = i3;
976 } else {
977 break;
978 }
979 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500980 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700981 }
982 }
983 }
984 }};
985
986 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700987 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700988 };
989
990 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700991 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700992 };
993
994 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700995 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700996 };
997}
998
David Tolnay1f16b602017-02-07 20:06:55 -0500999/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -05001000///
David Tolnay1f16b602017-02-07 20:06:55 -05001001/// - **Syntax:** `tuple!(A, B, C, ...)`
1002/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -05001003///
1004/// ```rust
1005/// extern crate syn;
1006/// #[macro_use] extern crate synom;
1007///
1008/// use syn::Ty;
1009/// use syn::parse::ty;
1010///
1011/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
1012///
1013/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001014/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -05001015///
David Tolnay1f16b602017-02-07 20:06:55 -05001016/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -05001017///
1018/// println!("{:?}", parsed);
1019/// }
1020/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001021#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001022macro_rules! tuple {
1023 ($i:expr, $($rest:tt)*) => {
1024 tuple_parser!($i, (), $($rest)*)
1025 };
1026}
1027
David Tolnay1f16b602017-02-07 20:06:55 -05001028/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001029#[doc(hidden)]
1030#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001031macro_rules! tuple_parser {
1032 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001033 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001034 };
1035
1036 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1037 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001038 $crate::IResult::Error => $crate::IResult::Error,
1039 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001040 tuple_parser!(i, (o), $($rest)*),
1041 }
1042 };
1043
1044 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1045 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001046 $crate::IResult::Error => $crate::IResult::Error,
1047 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001048 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1049 }
1050 };
1051
1052 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001053 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001054 };
1055
1056 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1057 $submac!($i, $($args)*)
1058 };
1059
1060 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1061 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001062 $crate::IResult::Error => $crate::IResult::Error,
1063 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001064 }
1065 };
1066
1067 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001068 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001069 };
1070}
1071
David Tolnay1f16b602017-02-07 20:06:55 -05001072/// Run a series of parsers, returning the result of the first one which
1073/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001074///
1075/// Optionally allows for the result to be transformed.
1076///
1077/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001078/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001079///
1080/// ```rust
1081/// extern crate syn;
1082/// #[macro_use] extern crate synom;
1083///
1084/// use syn::Ident;
1085/// use syn::parse::ident;
1086///
1087/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001088/// alt!(
1089/// ident
1090/// |
1091/// punct!("!") => { |_| "BANG".into() }
1092/// )
1093/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001094///
1095/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001096/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001097/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1098/// assert_eq!(parsed, "foo");
1099///
1100/// let input = "!";
1101/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1102/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001103/// }
1104/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001105#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001106macro_rules! alt {
1107 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001108 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001109 };
1110
1111 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1112 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001113 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001114 _ => alt!($i, $($rest)*)
1115 }
1116 };
1117
1118 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1119 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001120 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1121 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001122 }
1123 };
1124
1125 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001126 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001127 };
1128
1129 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001130 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001131 };
1132
1133 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1134 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001135 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1136 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001137 }
1138 };
1139
1140 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001141 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001142 };
1143
1144 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001145 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001146 };
1147}
1148
Michael Layzell24645a32017-02-04 13:19:26 -05001149/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001150/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001151///
David Tolnay1f16b602017-02-07 20:06:55 -05001152/// Produces the result of evaluating the final expression in parentheses with
1153/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001154///
David Tolnay1f16b602017-02-07 20:06:55 -05001155/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001156/// - **Output:** `RESULT`
1157///
1158/// ```rust
1159/// extern crate syn;
1160/// #[macro_use] extern crate synom;
1161///
1162/// use syn::{Ident, TokenTree};
1163/// use syn::parse::{ident, tt};
1164///
David Tolnay1f16b602017-02-07 20:06:55 -05001165/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001166/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1167/// name: ident >>
1168/// punct!("!") >>
1169/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001170/// (name, body)
1171/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001172///
1173/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001174/// let input = "stringify!($args)";
1175/// let (name, body) = simple_mac(input).expect("macro invocation");
1176/// println!("{:?}", name);
1177/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001178/// }
1179/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001180#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001181macro_rules! do_parse {
1182 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001183 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001184 };
1185
1186 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001187 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001188 };
1189
1190 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1191 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001192 $crate::IResult::Error => $crate::IResult::Error,
1193 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001194 do_parse!(i, $($rest)*),
1195 }
1196 };
1197
1198 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001199 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001200 };
1201
1202 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1203 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001204 $crate::IResult::Error => $crate::IResult::Error,
1205 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001206 let $field = o;
1207 do_parse!(i, $($rest)*)
1208 },
1209 }
1210 };
1211
David Tolnayfa0edf22016-09-23 22:58:24 -07001212 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001213 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001214 };
1215
1216 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1217 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001218 $crate::IResult::Error => $crate::IResult::Error,
1219 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001220 let mut $field = o;
1221 do_parse!(i, $($rest)*)
1222 },
1223 }
1224 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001225}