blob: 69c4c63f655c6ea224d4e4ca27548f5b08349799 [file] [log] [blame]
David Tolnayb5a7b142016-09-13 22:46:39 -07001// Adapted from nom <https://github.com/Geal/nom> by removing the
2// IResult::Incomplete variant, which we don't use and which unfortunately more
3// than doubles the compilation time.
4
Michael Layzell5bde96f2017-01-24 17:59:21 -05005extern crate unicode_xid;
6
7pub mod space;
8
David Tolnay5fe14fc2017-01-27 16:22:08 -08009#[doc(hidden)]
10pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050011
Michael Layzell24645a32017-02-04 13:19:26 -050012/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070013#[derive(Debug, PartialEq, Eq, Clone)]
14pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080015 /// Parsing succeeded. The first field contains the rest of the unparsed
16 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070017 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080018 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070019 Error,
20}
21
David Tolnayf2222f02017-01-27 17:09:20 -080022impl<'a, O> IResult<&'a str, O> {
Michael Layzell24645a32017-02-04 13:19:26 -050023 /// Unwraps the result, asserting the the parse is complete. Panics with a
24 /// message based on the given string if the parse failed or is incomplete.
David Tolnay1f16b602017-02-07 20:06:55 -050025 ///
26 /// ```rust
27 /// extern crate syn;
28 /// #[macro_use] extern crate synom;
29 ///
30 /// use syn::Ty;
31 /// use syn::parse::ty;
32 ///
33 /// // One or more Rust types separated by commas.
34 /// named!(comma_separated_types -> Vec<Ty>,
35 /// separated_nonempty_list!(punct!(","), ty)
36 /// );
37 ///
38 /// fn main() {
39 /// let input = "&str, Map<K, V>, String";
40 ///
41 /// let parsed = comma_separated_types(input).expect("comma-separated types");
42 ///
43 /// assert_eq!(parsed.len(), 3);
44 /// println!("{:?}", parsed);
45 /// }
46 /// ```
David Tolnayf2222f02017-01-27 17:09:20 -080047 pub fn expect(self, name: &str) -> O {
48 match self {
49 IResult::Done(mut rest, o) => {
50 rest = space::skip_whitespace(rest);
51 if rest.is_empty() {
52 o
53 } else {
54 panic!("unparsed tokens after {}: {:?}", name, rest)
55 }
56 }
57 IResult::Error => panic!("failed to parse {}", name),
58 }
59 }
60}
61
Michael Layzell24645a32017-02-04 13:19:26 -050062/// Define a function from a parser combination.
63///
David Tolnay1f16b602017-02-07 20:06:55 -050064/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
65///
66/// ```rust
67/// # extern crate syn;
68/// # #[macro_use] extern crate synom;
69/// # use syn::Ty;
70/// # use syn::parse::ty;
71/// // One or more Rust types separated by commas.
72/// named!(pub comma_separated_types -> Vec<Ty>,
73/// separated_nonempty_list!(punct!(","), ty)
74/// );
75/// # fn main() {}
76/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050077#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070078macro_rules! named {
79 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -050080 fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070081 $submac!(i, $($args)*)
82 }
83 };
84
85 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -050086 pub fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070087 $submac!(i, $($args)*)
88 }
89 };
90}
91
David Tolnay1f16b602017-02-07 20:06:55 -050092/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -050093///
94/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -050095///
96/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
97/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -050098///
99/// ```rust
100/// #[macro_use] extern crate synom;
101///
102/// use synom::IResult;
103///
David Tolnay1f16b602017-02-07 20:06:55 -0500104/// // Parses any string up to but not including the given character, returning
105/// // the content up to the given character. The given character is required to
106/// // be present in the input string.
107/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
108/// if let Some(pos) = input.find(ch) {
109/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500110/// } else {
111/// IResult::Error
112/// }
113/// }
114///
David Tolnay1f16b602017-02-07 20:06:55 -0500115/// // Parses any string surrounded by tilde characters '~'. Returns the content
116/// // between the tilde characters.
117/// named!(surrounded_by_tilde -> &str, delimited!(
118/// punct!("~"),
119/// call!(skip_until, '~'),
120/// punct!("~")
121/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500122///
123/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500124/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500125///
David Tolnay1f16b602017-02-07 20:06:55 -0500126/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500127///
David Tolnay1f16b602017-02-07 20:06:55 -0500128/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500129/// }
130/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500131#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700132macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700133 ($i:expr, $fun:expr $(, $args:expr)*) => {
134 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700135 };
136}
137
David Tolnay1f16b602017-02-07 20:06:55 -0500138/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500139///
David Tolnay1f16b602017-02-07 20:06:55 -0500140/// - **Syntax:** `map!(THING, FN)`
141/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500142///
143/// ```rust
144/// extern crate syn;
145/// #[macro_use] extern crate synom;
146///
147/// use syn::{Item, Ident};
148/// use syn::parse::item;
149///
150/// fn get_item_ident(item: Item) -> Ident {
151/// item.ident
152/// }
153///
David Tolnay1f16b602017-02-07 20:06:55 -0500154/// // Parses an item and returns the name (identifier) of the item only.
155/// named!(item_ident -> Ident,
156/// map!(item, get_item_ident)
157/// );
158///
159/// // Or equivalently:
160/// named!(item_ident2 -> Ident,
161/// map!(item, |i: Item| i.ident)
162/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500163///
164/// fn main() {
165/// let input = "fn foo() {}";
166///
David Tolnay1f16b602017-02-07 20:06:55 -0500167/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500168///
David Tolnay1f16b602017-02-07 20:06:55 -0500169/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500170/// }
171/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500172#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700173macro_rules! map {
174 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700175 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500176 $crate::IResult::Error => $crate::IResult::Error,
177 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500178 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700179 }
180 }
181 };
David Tolnay1f16b602017-02-07 20:06:55 -0500182
183 ($i:expr, $f:expr, $g:expr) => {
184 map!($i, call!($f), $g)
185 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700186}
187
David Tolnay1f16b602017-02-07 20:06:55 -0500188/// Parses successfully if the given parser fails to parse. Does not consume any
189/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500190///
191/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500192/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500193///
194/// ```rust
195/// extern crate syn;
196/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500197/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500198///
David Tolnay1f16b602017-02-07 20:06:55 -0500199/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
200/// // Note that a line starting with `#![` is an inner attribute, not a
201/// // shebang.
202/// named!(shebang -> &str, preceded!(
203/// tuple!(tag!("#!"), not!(tag!("["))),
204/// take_until!("\n")
205/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500206///
207/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// let bin_bash = "#!/bin/bash\n";
209/// let parsed = shebang(bin_bash).expect("shebang");
210/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500211///
David Tolnay1f16b602017-02-07 20:06:55 -0500212/// let inner_attr = "#![feature(specialization)]\n";
213/// let err = shebang(inner_attr);
214/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500215/// }
216/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500217#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700218macro_rules! not {
219 ($i:expr, $submac:ident!( $($args:tt)* )) => {
220 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500221 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500222 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700223 }
224 };
225}
226
David Tolnay1f16b602017-02-07 20:06:55 -0500227/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500228///
David Tolnay1f16b602017-02-07 20:06:55 -0500229/// If you are familiar with nom, this is nom's `cond_with_error` parser.
230///
231/// - **Syntax:** `cond!(CONDITION, THING)`
232/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500233///
234/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500235/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500236/// #[macro_use] extern crate synom;
237///
David Tolnay1f16b602017-02-07 20:06:55 -0500238/// use syn::parse::boolean;
239///
240/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
241/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
242/// // separate vectors for the booleans before and after the dotdot. The second
243/// // vector is None if there was no dotdot.
244/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
245/// punct!("(") >>
246/// before: separated_list!(punct!(","), boolean) >>
247/// after: option!(do_parse!(
248/// // Only allow comma if there are elements before dotdot, i.e. cannot
249/// // be `(, .., true)`.
250/// cond!(!before.is_empty(), punct!(",")) >>
251/// punct!("..") >>
252/// after: many0!(preceded!(punct!(","), boolean)) >>
253/// // Only allow trailing comma if there are elements after dotdot,
254/// // i.e. cannot be `(true, .., )`.
255/// cond!(!after.is_empty(), option!(punct!(","))) >>
256/// (after)
257/// )) >>
258/// // Allow trailing comma if there is no dotdot but there are elements.
259/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
260/// punct!(")") >>
261/// (before, after)
262/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500263///
264/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500265/// let input = "(true, false, false)";
266/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
267/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500268///
David Tolnay1f16b602017-02-07 20:06:55 -0500269/// let input = "(true, true, .., true)";
270/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
271/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
272///
273/// let input = "(.., true)";
274/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
275/// assert_eq!(parsed, (vec![], Some(vec![true])));
276///
277/// let input = "(true, true, ..)";
278/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
279/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
280///
281/// let input = "(..)";
282/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
283/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500284/// }
285/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500286#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700287macro_rules! cond {
288 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
289 if $cond {
290 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500291 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
292 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700293 }
294 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500295 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700296 }
David Tolnaycfe55022016-10-02 22:02:27 -0700297 };
298
299 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700300 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700301 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700302}
303
David Tolnay1f16b602017-02-07 20:06:55 -0500304/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500305///
David Tolnay1f16b602017-02-07 20:06:55 -0500306/// This is typically used inside of `option!` or `alt!`.
307///
308/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
309/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500310///
311/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500312/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500313/// #[macro_use] extern crate synom;
314///
David Tolnay1f16b602017-02-07 20:06:55 -0500315/// use syn::parse::boolean;
316///
317/// #[derive(Debug, PartialEq)]
318/// struct VariadicBools {
319/// data: Vec<bool>,
320/// variadic: bool,
321/// }
322///
323/// // Parse one or more comma-separated booleans, possibly ending in "..." to
324/// // indicate there may be more.
325/// named!(variadic_bools -> VariadicBools, do_parse!(
326/// data: separated_nonempty_list!(punct!(","), boolean) >>
327/// trailing_comma: option!(punct!(",")) >>
328/// // Only allow "..." if there is a comma after the last boolean. Using
329/// // `cond_reduce!` is more convenient here than using `cond!`. The
330/// // alternatives are:
331/// //
332/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
333/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
334/// // which both mean not variadic.
335/// // - `cond_reduce!(c, option!(p))`
336/// // Incorrect; would fail to parse if there is no trailing comma.
337/// // - `option!(cond_reduce!(c, p))`
338/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
339/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
340/// (VariadicBools {
341/// data: data,
342/// variadic: variadic.is_some(),
343/// })
344/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500345///
346/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500347/// let input = "true, true";
348/// let parsed = variadic_bools(input).expect("variadic bools");
349/// assert_eq!(parsed, VariadicBools {
350/// data: vec![true, true],
351/// variadic: false,
352/// });
353///
354/// let input = "true, ...";
355/// let parsed = variadic_bools(input).expect("variadic bools");
356/// assert_eq!(parsed, VariadicBools {
357/// data: vec![true],
358/// variadic: true,
359/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500360/// }
361/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500362#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700363macro_rules! cond_reduce {
364 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
365 if $cond {
366 $submac!($i, $($args)*)
367 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500368 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700369 }
370 };
371
372 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700373 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700374 };
375}
376
David Tolnay1f16b602017-02-07 20:06:55 -0500377/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500378///
David Tolnay1f16b602017-02-07 20:06:55 -0500379/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500380/// - **Output:** `THING`
381///
382/// ```rust
383/// extern crate syn;
384/// #[macro_use] extern crate synom;
385///
386/// use syn::Expr;
387/// use syn::parse::expr;
388///
389/// // An expression preceded by ##.
390/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500391/// preceded!(punct!("##"), expr)
392/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500393///
394/// fn main() {
395/// let input = "## 1 + 1";
396///
397/// let parsed = pound_pound_expr(input).expect("pound pound expr");
398///
399/// println!("{:?}", parsed);
400/// }
401/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500402#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700403macro_rules! preceded {
404 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
405 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500406 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
407 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700408 }
409 };
410
411 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700412 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700413 };
414
415 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700416 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700417 };
418
419 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700420 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700421 };
422}
423
David Tolnay1f16b602017-02-07 20:06:55 -0500424/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500425///
David Tolnay1f16b602017-02-07 20:06:55 -0500426/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500427/// - **Output:** `THING`
428///
429/// ```rust
430/// extern crate syn;
431/// #[macro_use] extern crate synom;
432///
433/// use syn::Expr;
434/// use syn::parse::expr;
435///
436/// // An expression terminated by ##.
437/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500438/// terminated!(expr, punct!("##"))
439/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500440///
441/// fn main() {
442/// let input = "1 + 1 ##";
443///
444/// let parsed = expr_pound_pound(input).expect("expr pound pound");
445///
446/// println!("{:?}", parsed);
447/// }
448/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500449#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700450macro_rules! terminated {
451 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
452 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500453 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
454 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700455 }
456 };
457
458 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700459 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700460 };
461
462 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700463 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700464 };
465
466 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700467 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700468 };
469}
470
David Tolnay1f16b602017-02-07 20:06:55 -0500471/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500472///
473/// - **Syntax:** `many0!(THING)`
474/// - **Output:** `Vec<THING>`
475///
David Tolnay1f16b602017-02-07 20:06:55 -0500476/// You may also be looking for:
477///
478/// - `separated_list!` - zero or more values with separator
479/// - `separated_nonempty_list!` - one or more values
480/// - `terminated_list!` - zero or more, allows trailing separator
481///
Michael Layzell24645a32017-02-04 13:19:26 -0500482/// ```rust
483/// extern crate syn;
484/// #[macro_use] extern crate synom;
485///
486/// use syn::Item;
487/// use syn::parse::item;
488///
489/// named!(items -> Vec<Item>, many0!(item));
490///
491/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500492/// let input = "
493/// fn a() {}
494/// fn b() {}
495/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500496///
497/// let parsed = items(input).expect("items");
498///
David Tolnay1f16b602017-02-07 20:06:55 -0500499/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500500/// println!("{:?}", parsed);
501/// }
502/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500503#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700504macro_rules! many0 {
505 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
506 let ret;
507 let mut res = ::std::vec::Vec::new();
508 let mut input = $i;
509
510 loop {
511 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500512 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700513 break;
514 }
515
516 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500517 $crate::IResult::Error => {
518 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700519 break;
520 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500521 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700522 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700523 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500524 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700525 break;
526 }
527
528 res.push(o);
529 input = i;
530 }
531 }
532 }
533
534 ret
535 }};
536
537 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500538 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700539 };
540}
541
David Tolnay1f16b602017-02-07 20:06:55 -0500542// Improve compile time by compiling this loop only once per type it is used
543// with.
544//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800545// Not public API.
546#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700547pub fn many0<'a, T>(mut input: &'a str,
548 f: fn(&'a str) -> IResult<&'a str, T>)
549 -> IResult<&'a str, Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700550 let mut res = Vec::new();
551
552 loop {
553 if input.is_empty() {
554 return IResult::Done(input, res);
555 }
556
557 match f(input) {
558 IResult::Error => {
559 return IResult::Done(input, res);
560 }
561 IResult::Done(i, o) => {
562 // loop trip must always consume (otherwise infinite loops)
563 if i.len() == input.len() {
564 return IResult::Error;
565 }
566
567 res.push(o);
568 input = i;
569 }
570 }
571 }
572}
573
David Tolnay1f16b602017-02-07 20:06:55 -0500574/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500575///
576/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500577/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500578///
579/// ```rust
580/// extern crate syn;
581/// #[macro_use] extern crate synom;
582///
David Tolnay1f16b602017-02-07 20:06:55 -0500583/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500584/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500585/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500586///
David Tolnay1f16b602017-02-07 20:06:55 -0500587/// // Parse an expression that begins with an identifier.
588/// named!(ident_expr -> Expr,
589/// preceded!(peek!(ident), expr)
590/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500591///
592/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500593/// // begins with an identifier
594/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500595/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500596/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500597///
598/// // does not begin with an identifier
599/// let input = "1 + banana";
600/// let err = ident_expr(input);
601/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500602/// }
603/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500604#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700605macro_rules! peek {
606 ($i:expr, $submac:ident!( $($args:tt)* )) => {
607 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500608 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
609 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700610 }
611 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700612
David Tolnay1f16b602017-02-07 20:06:55 -0500613 ($i:expr, $f:expr) => {
614 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700615 };
616}
617
David Tolnay1f16b602017-02-07 20:06:55 -0500618/// Parse the part of the input up to but not including the given string. Fail
619/// to parse if the given string is not present in the input.
620///
621/// - **Syntax:** `take_until!("...")`
622/// - **Output:** `&str`
623///
624/// ```rust
625/// extern crate syn;
626/// #[macro_use] extern crate synom;
627/// use synom::IResult;
628///
629/// // Parse a single line doc comment: /// ...
630/// named!(single_line_doc -> &str,
631/// preceded!(punct!("///"), take_until!("\n"))
632/// );
633///
634/// fn main() {
635/// let comment = "/// comment\n";
636/// let parsed = single_line_doc(comment).expect("single line doc comment");
637/// assert_eq!(parsed, " comment");
638/// }
639/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500640#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700641macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500642 ($i:expr, $substr:expr) => {{
643 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500644 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700645 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500646 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700647 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500648 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700649 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500650 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700651 window.push(c);
652 if window.len() > substr_vec.len() {
653 window.remove(0);
654 }
655 if window == substr_vec {
656 parsed = true;
657 window.pop();
658 let window_len: usize = window.iter()
659 .map(|x| x.len_utf8())
660 .fold(0, |x, y| x + y);
661 offset = o - window_len;
662 break;
663 }
664 }
665 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500666 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700667 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500668 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700669 }
670 }
671 }};
672}
673
David Tolnay1f16b602017-02-07 20:06:55 -0500674/// Parse the given string from exactly the current position in the input. You
675/// almost always want `punct!` or `keyword!` instead of this.
676///
677/// The `tag!` parser is equivalent to `punct!` but does not ignore leading
678/// whitespace. Both `punct!` and `keyword!` skip over leading whitespace. See
679/// an explanation of synom's whitespace handling strategy in the top-level
680/// crate documentation.
681///
682/// - **Syntax:** `tag!("...")`
683/// - **Output:** `"..."`
684///
685/// ```rust
686/// extern crate syn;
687/// #[macro_use] extern crate synom;
688///
689/// use syn::StrLit;
690/// use syn::parse::string;
691/// use synom::IResult;
692///
693/// // Parse a proposed syntax for an owned string literal: "abc"s
694/// named!(owned_string -> String,
695/// map!(
696/// terminated!(string, tag!("s")),
697/// |lit: StrLit| lit.value
698/// )
699/// );
700///
701/// fn main() {
702/// let input = r#" "abc"s "#;
703/// let parsed = owned_string(input).expect("owned string literal");
704/// println!("{:?}", parsed);
705///
706/// let input = r#" "abc" s "#;
707/// let err = owned_string(input);
708/// assert_eq!(err, IResult::Error);
709/// }
710/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500711#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700712macro_rules! tag {
David Tolnay1f16b602017-02-07 20:06:55 -0500713 ($i:expr, $tag:expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700714 if $i.starts_with($tag) {
David Tolnay1f16b602017-02-07 20:06:55 -0500715 $crate::IResult::Done(&$i[$tag.len()..], &$i[..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700716 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500717 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700718 }
719 };
720}
721
David Tolnay1f16b602017-02-07 20:06:55 -0500722/// Pattern-match the result of a parser to select which other parser to run.
723///
724/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
725/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
726///
727/// ```rust
728/// extern crate syn;
729/// #[macro_use] extern crate synom;
730///
731/// use syn::{Ident, Ty};
732/// use syn::parse::{ident, ty};
733///
734/// #[derive(Debug)]
735/// enum UnitType {
736/// Struct {
737/// name: Ident,
738/// },
739/// Enum {
740/// name: Ident,
741/// variant: Ident,
742/// },
743/// }
744///
745/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
746/// named!(unit_type -> UnitType, do_parse!(
747/// which: alt!(keyword!("struct") | keyword!("enum")) >>
748/// id: ident >>
749/// item: switch!(value!(which),
750/// "struct" => map!(
751/// punct!(";"),
752/// move |_| UnitType::Struct {
753/// name: id,
754/// }
755/// )
756/// |
757/// "enum" => map!(
758/// delimited!(punct!("{"), ident, punct!("}")),
759/// move |variant| UnitType::Enum {
760/// name: id,
761/// variant: variant,
762/// }
763/// )
764/// ) >>
765/// (item)
766/// ));
767///
768/// fn main() {
769/// let input = "struct S;";
770/// let parsed = unit_type(input).expect("unit struct or enum");
771/// println!("{:?}", parsed);
772///
773/// let input = "enum E { V }";
774/// let parsed = unit_type(input).expect("unit struct or enum");
775/// println!("{:?}", parsed);
776/// }
777/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500778#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700779macro_rules! switch {
780 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
781 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500782 $crate::IResult::Error => $crate::IResult::Error,
783 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700784 $(
785 $p => $subrule!(i, $($args2)*),
786 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500787 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700788 }
789 }
790 };
791}
792
David Tolnay1f16b602017-02-07 20:06:55 -0500793/// Produce the given value without parsing anything. Useful as an argument to
794/// `switch!`.
795///
796/// - **Syntax:** `value!(VALUE)`
797/// - **Output:** `VALUE`
798///
799/// ```rust
800/// extern crate syn;
801/// #[macro_use] extern crate synom;
802///
803/// use syn::{Ident, Ty};
804/// use syn::parse::{ident, ty};
805///
806/// #[derive(Debug)]
807/// enum UnitType {
808/// Struct {
809/// name: Ident,
810/// },
811/// Enum {
812/// name: Ident,
813/// variant: Ident,
814/// },
815/// }
816///
817/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
818/// named!(unit_type -> UnitType, do_parse!(
819/// which: alt!(keyword!("struct") | keyword!("enum")) >>
820/// id: ident >>
821/// item: switch!(value!(which),
822/// "struct" => map!(
823/// punct!(";"),
824/// move |_| UnitType::Struct {
825/// name: id,
826/// }
827/// )
828/// |
829/// "enum" => map!(
830/// delimited!(punct!("{"), ident, punct!("}")),
831/// move |variant| UnitType::Enum {
832/// name: id,
833/// variant: variant,
834/// }
835/// )
836/// ) >>
837/// (item)
838/// ));
839///
840/// fn main() {
841/// let input = "struct S;";
842/// let parsed = unit_type(input).expect("unit struct or enum");
843/// println!("{:?}", parsed);
844///
845/// let input = "enum E { V }";
846/// let parsed = unit_type(input).expect("unit struct or enum");
847/// println!("{:?}", parsed);
848/// }
849/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500850#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700851macro_rules! value {
852 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500853 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700854 };
855}
856
David Tolnayf2222f02017-01-27 17:09:20 -0800857/// Value surrounded by a pair of delimiters.
858///
859/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
860/// - **Output:** `THING`
861///
862/// ```rust
863/// extern crate syn;
864/// #[macro_use] extern crate synom;
865///
866/// use syn::Expr;
867/// use syn::parse::expr;
868///
869/// // An expression surrounded by [[ ... ]].
870/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500871/// delimited!(punct!("[["), expr, punct!("]]"))
872/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800873///
874/// fn main() {
875/// let input = "[[ 1 + 1 ]]";
876///
877/// let parsed = double_bracket_expr(input).expect("double bracket expr");
878///
879/// println!("{:?}", parsed);
880/// }
881/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500882#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700883macro_rules! delimited {
884 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
885 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500886 $crate::IResult::Error => $crate::IResult::Error,
887 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700888 }
889 };
890
891 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700892 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700893 };
894}
895
David Tolnay1f16b602017-02-07 20:06:55 -0500896/// One or more values separated by some separator. Does not allow a trailing
897/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800898///
899/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
900/// - **Output:** `Vec<THING>`
901///
David Tolnay1f16b602017-02-07 20:06:55 -0500902/// You may also be looking for:
903///
904/// - `separated_list!` - one or more values
905/// - `terminated_list!` - zero or more, allows trailing separator
906/// - `many0!` - zero or more, no separator
907///
David Tolnayf2222f02017-01-27 17:09:20 -0800908/// ```rust
909/// extern crate syn;
910/// #[macro_use] extern crate synom;
911///
912/// use syn::Ty;
913/// use syn::parse::ty;
914///
915/// // One or more Rust types separated by commas.
916/// named!(comma_separated_types -> Vec<Ty>,
David Tolnay1f16b602017-02-07 20:06:55 -0500917/// separated_nonempty_list!(punct!(","), ty)
918/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800919///
920/// fn main() {
921/// let input = "&str, Map<K, V>, String";
922///
923/// let parsed = comma_separated_types(input).expect("comma-separated types");
924///
925/// assert_eq!(parsed.len(), 3);
926/// println!("{:?}", parsed);
927/// }
928/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500929#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700930macro_rules! separated_nonempty_list {
931 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
932 let mut res = ::std::vec::Vec::new();
933 let mut input = $i;
934
935 // get the first element
936 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500937 $crate::IResult::Error => $crate::IResult::Error,
938 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700939 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500940 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700941 } else {
942 res.push(o);
943 input = i;
944
Michael Layzell5bde96f2017-01-24 17:59:21 -0500945 while let $crate::IResult::Done(i2, _) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700946 if i2.len() == input.len() {
947 break;
948 }
949
Michael Layzell5bde96f2017-01-24 17:59:21 -0500950 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700951 if i3.len() == i2.len() {
952 break;
953 }
954 res.push(o3);
955 input = i3;
956 } else {
957 break;
958 }
959 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500960 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700961 }
962 }
963 }
964 }};
965
966 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700967 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700968 };
969
970 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700971 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700972 };
973
974 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700975 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700976 };
977}
978
David Tolnay1f16b602017-02-07 20:06:55 -0500979/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500980///
David Tolnay1f16b602017-02-07 20:06:55 -0500981/// - **Syntax:** `tuple!(A, B, C, ...)`
982/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500983///
984/// ```rust
985/// extern crate syn;
986/// #[macro_use] extern crate synom;
987///
988/// use syn::Ty;
989/// use syn::parse::ty;
990///
991/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
992///
993/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500994/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -0500995///
David Tolnay1f16b602017-02-07 20:06:55 -0500996/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -0500997///
998/// println!("{:?}", parsed);
999/// }
1000/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001001#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001002macro_rules! tuple {
1003 ($i:expr, $($rest:tt)*) => {
1004 tuple_parser!($i, (), $($rest)*)
1005 };
1006}
1007
David Tolnay1f16b602017-02-07 20:06:55 -05001008/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001009#[doc(hidden)]
1010#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001011macro_rules! tuple_parser {
1012 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001013 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001014 };
1015
1016 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1017 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001018 $crate::IResult::Error => $crate::IResult::Error,
1019 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001020 tuple_parser!(i, (o), $($rest)*),
1021 }
1022 };
1023
1024 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1025 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001026 $crate::IResult::Error => $crate::IResult::Error,
1027 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001028 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1029 }
1030 };
1031
1032 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001033 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001034 };
1035
1036 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1037 $submac!($i, $($args)*)
1038 };
1039
1040 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1041 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001042 $crate::IResult::Error => $crate::IResult::Error,
1043 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001044 }
1045 };
1046
1047 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001048 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001049 };
1050}
1051
David Tolnay1f16b602017-02-07 20:06:55 -05001052/// Run a series of parsers, returning the result of the first one which
1053/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001054///
1055/// Optionally allows for the result to be transformed.
1056///
1057/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001058/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001059///
1060/// ```rust
1061/// extern crate syn;
1062/// #[macro_use] extern crate synom;
1063///
1064/// use syn::Ident;
1065/// use syn::parse::ident;
1066///
1067/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001068/// alt!(
1069/// ident
1070/// |
1071/// punct!("!") => { |_| "BANG".into() }
1072/// )
1073/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001074///
1075/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001076/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001077/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1078/// assert_eq!(parsed, "foo");
1079///
1080/// let input = "!";
1081/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1082/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001083/// }
1084/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001085#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001086macro_rules! alt {
1087 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001088 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001089 };
1090
1091 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1092 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001093 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001094 _ => alt!($i, $($rest)*)
1095 }
1096 };
1097
1098 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1099 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001100 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1101 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001102 }
1103 };
1104
1105 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001106 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001107 };
1108
1109 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001110 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001111 };
1112
1113 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1114 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001115 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1116 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001117 }
1118 };
1119
1120 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001121 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001122 };
1123
1124 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001125 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001126 };
1127}
1128
Michael Layzell24645a32017-02-04 13:19:26 -05001129/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001130/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001131///
David Tolnay1f16b602017-02-07 20:06:55 -05001132/// Produces the result of evaluating the final expression in parentheses with
1133/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001134///
David Tolnay1f16b602017-02-07 20:06:55 -05001135/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001136/// - **Output:** `RESULT`
1137///
1138/// ```rust
1139/// extern crate syn;
1140/// #[macro_use] extern crate synom;
1141///
1142/// use syn::{Ident, TokenTree};
1143/// use syn::parse::{ident, tt};
1144///
David Tolnay1f16b602017-02-07 20:06:55 -05001145/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001146/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1147/// name: ident >>
1148/// punct!("!") >>
1149/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001150/// (name, body)
1151/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001152///
1153/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001154/// let input = "stringify!($args)";
1155/// let (name, body) = simple_mac(input).expect("macro invocation");
1156/// println!("{:?}", name);
1157/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001158/// }
1159/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001160#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001161macro_rules! do_parse {
1162 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001163 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001164 };
1165
1166 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001167 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001168 };
1169
1170 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1171 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001172 $crate::IResult::Error => $crate::IResult::Error,
1173 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001174 do_parse!(i, $($rest)*),
1175 }
1176 };
1177
1178 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001179 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001180 };
1181
1182 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1183 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001184 $crate::IResult::Error => $crate::IResult::Error,
1185 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001186 let $field = o;
1187 do_parse!(i, $($rest)*)
1188 },
1189 }
1190 };
1191
David Tolnayfa0edf22016-09-23 22:58:24 -07001192 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001193 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001194 };
1195
1196 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1197 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001198 $crate::IResult::Error => $crate::IResult::Error,
1199 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001200 let mut $field = o;
1201 do_parse!(i, $($rest)*)
1202 },
1203 }
1204 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001205}