blob: ae9aebd87671405da477453c96eda4227fd15418 [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 Layzell416724e2017-05-24 21:12:34 -040024extern crate proc_macro2;
Michael Layzell5bde96f2017-01-24 17:59:21 -050025
David Tolnay5fe14fc2017-01-27 16:22:08 -080026#[doc(hidden)]
27pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050028
Michael Layzell416724e2017-05-24 21:12:34 -040029// re-export TokenStream et. al. from proc_macro2, so that parsers which want to
30// use us don't have to manually import the type.
31pub use proc_macro2::{TokenStream, TokenTree, TokenKind, Delimiter, OpKind, LexError};
32
33use std::ops::Deref;
34
35/// A `TokenStream` does not provide a data format which is usable as a `synom`
36/// parser input. This type extracts `TokenTrees` from a `TokenStream` into a
37/// buffer, which can be iterated over as the `synom` input type.
38pub struct InputBuf {
39 data: Vec<TokenTree>,
40}
41
42impl InputBuf {
43 /// Transform the input `TokenStream` into a buffer which can be iterated
44 /// over as a `synom` parser input. Use the `Deref` implementation on this
45 /// type to extract the actual buffer type.
46 pub fn new(ts: TokenStream) -> Self {
47 fn flatten_stream(tt: TokenTree) -> Vec<TokenTree> {
48 match tt.kind {
49 TokenKind::Sequence(Delimiter::None, ts) => {
50 ts.into_iter().flat_map(flatten_stream).collect()
51 }
52 _ => vec![tt]
53 }
54 }
55
56 InputBuf {
57 data: ts.into_iter().flat_map(flatten_stream).collect()
58 }
59 }
60}
61
62impl Deref for InputBuf {
63 type Target = [TokenTree];
64 fn deref(&self) -> &[TokenTree] {
65 &self.data
66 }
67}
68
Michael Layzell24645a32017-02-04 13:19:26 -050069/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070070#[derive(Debug, PartialEq, Eq, Clone)]
71pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080072 /// Parsing succeeded. The first field contains the rest of the unparsed
73 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070074 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080075 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070076 Error,
77}
78
Michael Layzell416724e2017-05-24 21:12:34 -040079impl<'a, O> IResult<&'a [TokenTree], O> {
Michael Layzell24645a32017-02-04 13:19:26 -050080 /// Unwraps the result, asserting the the parse is complete. Panics with a
81 /// message based on the given string if the parse failed or is incomplete.
David Tolnay1f16b602017-02-07 20:06:55 -050082 ///
83 /// ```rust
84 /// extern crate syn;
85 /// #[macro_use] extern crate synom;
86 ///
87 /// use syn::Ty;
88 /// use syn::parse::ty;
89 ///
90 /// // One or more Rust types separated by commas.
91 /// named!(comma_separated_types -> Vec<Ty>,
92 /// separated_nonempty_list!(punct!(","), ty)
93 /// );
94 ///
95 /// fn main() {
96 /// let input = "&str, Map<K, V>, String";
97 ///
98 /// let parsed = comma_separated_types(input).expect("comma-separated types");
99 ///
100 /// assert_eq!(parsed.len(), 3);
101 /// println!("{:?}", parsed);
102 /// }
103 /// ```
David Tolnayf2222f02017-01-27 17:09:20 -0800104 pub fn expect(self, name: &str) -> O {
105 match self {
Michael Layzell416724e2017-05-24 21:12:34 -0400106 IResult::Done(rest, o) => {
David Tolnayf2222f02017-01-27 17:09:20 -0800107 if rest.is_empty() {
108 o
109 } else {
Michael Layzell416724e2017-05-24 21:12:34 -0400110 panic!("unparsed tokens after {}: {:?}", name, /* rest */ ())
David Tolnayf2222f02017-01-27 17:09:20 -0800111 }
112 }
113 IResult::Error => panic!("failed to parse {}", name),
114 }
115 }
116}
117
Michael Layzell24645a32017-02-04 13:19:26 -0500118/// Define a function from a parser combination.
119///
David Tolnay1f16b602017-02-07 20:06:55 -0500120/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
121///
122/// ```rust
123/// # extern crate syn;
124/// # #[macro_use] extern crate synom;
125/// # use syn::Ty;
126/// # use syn::parse::ty;
127/// // One or more Rust types separated by commas.
128/// named!(pub comma_separated_types -> Vec<Ty>,
129/// separated_nonempty_list!(punct!(","), ty)
130/// );
131/// # fn main() {}
132/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500133#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700134macro_rules! named {
135 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400136 fn $name(i: &[$crate::TokenTree]) -> $crate::IResult<&[$crate::TokenTree], $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700137 $submac!(i, $($args)*)
138 }
139 };
140
141 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell416724e2017-05-24 21:12:34 -0400142 pub fn $name(i: &[$crate::TokenTree]) -> $crate::IResult<&[$crate::TokenTree], $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700143 $submac!(i, $($args)*)
144 }
145 };
146}
147
David Tolnay1f16b602017-02-07 20:06:55 -0500148/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500149///
150/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500151///
152/// where the signature of the function is `fn(&str, ARGS...) -> IResult<&str, T>`
153/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell24645a32017-02-04 13:19:26 -0500154///
155/// ```rust
156/// #[macro_use] extern crate synom;
157///
158/// use synom::IResult;
159///
David Tolnay1f16b602017-02-07 20:06:55 -0500160/// // Parses any string up to but not including the given character, returning
161/// // the content up to the given character. The given character is required to
162/// // be present in the input string.
163/// fn skip_until(input: &str, ch: char) -> IResult<&str, &str> {
164/// if let Some(pos) = input.find(ch) {
165/// IResult::Done(&input[pos..], &input[..pos])
Michael Layzell24645a32017-02-04 13:19:26 -0500166/// } else {
167/// IResult::Error
168/// }
169/// }
170///
David Tolnay1f16b602017-02-07 20:06:55 -0500171/// // Parses any string surrounded by tilde characters '~'. Returns the content
172/// // between the tilde characters.
173/// named!(surrounded_by_tilde -> &str, delimited!(
174/// punct!("~"),
175/// call!(skip_until, '~'),
176/// punct!("~")
177/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500178///
179/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500180/// let input = "~ abc def ~";
Michael Layzell24645a32017-02-04 13:19:26 -0500181///
David Tolnay1f16b602017-02-07 20:06:55 -0500182/// let inner = surrounded_by_tilde(input).expect("surrounded by tilde");
Michael Layzell24645a32017-02-04 13:19:26 -0500183///
David Tolnay1f16b602017-02-07 20:06:55 -0500184/// println!("{:?}", inner);
Michael Layzell24645a32017-02-04 13:19:26 -0500185/// }
186/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500187#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700188macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700189 ($i:expr, $fun:expr $(, $args:expr)*) => {
190 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700191 };
192}
193
David Tolnay1f16b602017-02-07 20:06:55 -0500194/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500195///
David Tolnay1f16b602017-02-07 20:06:55 -0500196/// - **Syntax:** `map!(THING, FN)`
197/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500198///
199/// ```rust
200/// extern crate syn;
201/// #[macro_use] extern crate synom;
202///
203/// use syn::{Item, Ident};
204/// use syn::parse::item;
205///
206/// fn get_item_ident(item: Item) -> Ident {
207/// item.ident
208/// }
209///
David Tolnay1f16b602017-02-07 20:06:55 -0500210/// // Parses an item and returns the name (identifier) of the item only.
211/// named!(item_ident -> Ident,
212/// map!(item, get_item_ident)
213/// );
214///
215/// // Or equivalently:
216/// named!(item_ident2 -> Ident,
217/// map!(item, |i: Item| i.ident)
218/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500219///
220/// fn main() {
221/// let input = "fn foo() {}";
222///
David Tolnay1f16b602017-02-07 20:06:55 -0500223/// let parsed = item_ident(input).expect("item");
Michael Layzell24645a32017-02-04 13:19:26 -0500224///
David Tolnay1f16b602017-02-07 20:06:55 -0500225/// assert_eq!(parsed, "foo");
Michael Layzell24645a32017-02-04 13:19:26 -0500226/// }
227/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500228#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700229macro_rules! map {
230 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700231 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500232 $crate::IResult::Error => $crate::IResult::Error,
233 $crate::IResult::Done(i, o) => {
David Tolnay1f16b602017-02-07 20:06:55 -0500234 $crate::IResult::Done(i, call!(o, $g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700235 }
236 }
237 };
David Tolnay1f16b602017-02-07 20:06:55 -0500238
239 ($i:expr, $f:expr, $g:expr) => {
240 map!($i, call!($f), $g)
241 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700242}
243
David Tolnay1f16b602017-02-07 20:06:55 -0500244/// Parses successfully if the given parser fails to parse. Does not consume any
245/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500246///
247/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500248/// - **Output:** `()`
Michael Layzell24645a32017-02-04 13:19:26 -0500249///
250/// ```rust
251/// extern crate syn;
252/// #[macro_use] extern crate synom;
David Tolnay1f16b602017-02-07 20:06:55 -0500253/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500254///
David Tolnay1f16b602017-02-07 20:06:55 -0500255/// // Parses a shebang line like `#!/bin/bash` and returns the part after `#!`.
256/// // Note that a line starting with `#![` is an inner attribute, not a
257/// // shebang.
258/// named!(shebang -> &str, preceded!(
259/// tuple!(tag!("#!"), not!(tag!("["))),
260/// take_until!("\n")
261/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500262///
263/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500264/// let bin_bash = "#!/bin/bash\n";
265/// let parsed = shebang(bin_bash).expect("shebang");
266/// assert_eq!(parsed, "/bin/bash");
Michael Layzell24645a32017-02-04 13:19:26 -0500267///
David Tolnay1f16b602017-02-07 20:06:55 -0500268/// let inner_attr = "#![feature(specialization)]\n";
269/// let err = shebang(inner_attr);
270/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500271/// }
272/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500273#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700274macro_rules! not {
275 ($i:expr, $submac:ident!( $($args:tt)* )) => {
276 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500277 $crate::IResult::Done(_, _) => $crate::IResult::Error,
David Tolnay1f16b602017-02-07 20:06:55 -0500278 $crate::IResult::Error => $crate::IResult::Done($i, ()),
David Tolnayb5a7b142016-09-13 22:46:39 -0700279 }
280 };
281}
282
David Tolnay1f16b602017-02-07 20:06:55 -0500283/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500284///
David Tolnay1f16b602017-02-07 20:06:55 -0500285/// If you are familiar with nom, this is nom's `cond_with_error` parser.
286///
287/// - **Syntax:** `cond!(CONDITION, THING)`
288/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell24645a32017-02-04 13:19:26 -0500289///
290/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500291/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500292/// #[macro_use] extern crate synom;
293///
David Tolnay1f16b602017-02-07 20:06:55 -0500294/// use syn::parse::boolean;
295///
296/// // Parses a tuple of booleans like `(true, false, false)`, possibly with a
297/// // dotdot indicating omitted values like `(true, true, .., true)`. Returns
298/// // separate vectors for the booleans before and after the dotdot. The second
299/// // vector is None if there was no dotdot.
300/// named!(bools_with_dotdot -> (Vec<bool>, Option<Vec<bool>>), do_parse!(
301/// punct!("(") >>
302/// before: separated_list!(punct!(","), boolean) >>
303/// after: option!(do_parse!(
304/// // Only allow comma if there are elements before dotdot, i.e. cannot
305/// // be `(, .., true)`.
306/// cond!(!before.is_empty(), punct!(",")) >>
307/// punct!("..") >>
308/// after: many0!(preceded!(punct!(","), boolean)) >>
309/// // Only allow trailing comma if there are elements after dotdot,
310/// // i.e. cannot be `(true, .., )`.
311/// cond!(!after.is_empty(), option!(punct!(","))) >>
312/// (after)
313/// )) >>
314/// // Allow trailing comma if there is no dotdot but there are elements.
315/// cond!(!before.is_empty() && after.is_none(), option!(punct!(","))) >>
316/// punct!(")") >>
317/// (before, after)
318/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500319///
320/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500321/// let input = "(true, false, false)";
322/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
323/// assert_eq!(parsed, (vec![true, false, false], None));
Michael Layzell24645a32017-02-04 13:19:26 -0500324///
David Tolnay1f16b602017-02-07 20:06:55 -0500325/// let input = "(true, true, .., true)";
326/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
327/// assert_eq!(parsed, (vec![true, true], Some(vec![true])));
328///
329/// let input = "(.., true)";
330/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
331/// assert_eq!(parsed, (vec![], Some(vec![true])));
332///
333/// let input = "(true, true, ..)";
334/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
335/// assert_eq!(parsed, (vec![true, true], Some(vec![])));
336///
337/// let input = "(..)";
338/// let parsed = bools_with_dotdot(input).expect("bools with dotdot");
339/// assert_eq!(parsed, (vec![], Some(vec![])));
Michael Layzell24645a32017-02-04 13:19:26 -0500340/// }
341/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500342#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700343macro_rules! cond {
344 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
345 if $cond {
346 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500347 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
348 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700349 }
350 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500351 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700352 }
David Tolnaycfe55022016-10-02 22:02:27 -0700353 };
354
355 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700356 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700357 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700358}
359
David Tolnay1f16b602017-02-07 20:06:55 -0500360/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500361///
David Tolnay1f16b602017-02-07 20:06:55 -0500362/// This is typically used inside of `option!` or `alt!`.
363///
364/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
365/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500366///
367/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500368/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500369/// #[macro_use] extern crate synom;
370///
David Tolnay1f16b602017-02-07 20:06:55 -0500371/// use syn::parse::boolean;
372///
373/// #[derive(Debug, PartialEq)]
374/// struct VariadicBools {
375/// data: Vec<bool>,
376/// variadic: bool,
377/// }
378///
379/// // Parse one or more comma-separated booleans, possibly ending in "..." to
380/// // indicate there may be more.
381/// named!(variadic_bools -> VariadicBools, do_parse!(
382/// data: separated_nonempty_list!(punct!(","), boolean) >>
383/// trailing_comma: option!(punct!(",")) >>
384/// // Only allow "..." if there is a comma after the last boolean. Using
385/// // `cond_reduce!` is more convenient here than using `cond!`. The
386/// // alternatives are:
387/// //
388/// // - `cond!(c, option!(p))` or `option!(cond!(c, p))`
389/// // Gives `Some(Some("..."))` for variadic and `Some(None)` or `None`
390/// // which both mean not variadic.
391/// // - `cond_reduce!(c, option!(p))`
392/// // Incorrect; would fail to parse if there is no trailing comma.
393/// // - `option!(cond_reduce!(c, p))`
394/// // Gives `Some("...")` for variadic and `None` otherwise. Perfect!
395/// variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
396/// (VariadicBools {
397/// data: data,
398/// variadic: variadic.is_some(),
399/// })
400/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500401///
402/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500403/// let input = "true, true";
404/// let parsed = variadic_bools(input).expect("variadic bools");
405/// assert_eq!(parsed, VariadicBools {
406/// data: vec![true, true],
407/// variadic: false,
408/// });
409///
410/// let input = "true, ...";
411/// let parsed = variadic_bools(input).expect("variadic bools");
412/// assert_eq!(parsed, VariadicBools {
413/// data: vec![true],
414/// variadic: true,
415/// });
Michael Layzell24645a32017-02-04 13:19:26 -0500416/// }
417/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500418#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700419macro_rules! cond_reduce {
420 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
421 if $cond {
422 $submac!($i, $($args)*)
423 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500424 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700425 }
426 };
427
428 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700429 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700430 };
431}
432
David Tolnay1f16b602017-02-07 20:06:55 -0500433/// Parse two things, returning the value of the second.
Michael Layzell24645a32017-02-04 13:19:26 -0500434///
David Tolnay1f16b602017-02-07 20:06:55 -0500435/// - **Syntax:** `preceded!(BEFORE, THING)`
Michael Layzell24645a32017-02-04 13:19:26 -0500436/// - **Output:** `THING`
437///
438/// ```rust
439/// extern crate syn;
440/// #[macro_use] extern crate synom;
441///
442/// use syn::Expr;
443/// use syn::parse::expr;
444///
445/// // An expression preceded by ##.
446/// named!(pound_pound_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500447/// preceded!(punct!("##"), expr)
448/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500449///
450/// fn main() {
451/// let input = "## 1 + 1";
452///
453/// let parsed = pound_pound_expr(input).expect("pound pound expr");
454///
455/// println!("{:?}", parsed);
456/// }
457/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500458#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700459macro_rules! preceded {
460 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
461 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500462 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
463 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700464 }
465 };
466
467 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700468 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700469 };
470
471 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700472 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700473 };
474
475 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700476 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700477 };
478}
479
David Tolnay1f16b602017-02-07 20:06:55 -0500480/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500481///
David Tolnay1f16b602017-02-07 20:06:55 -0500482/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500483/// - **Output:** `THING`
484///
485/// ```rust
486/// extern crate syn;
487/// #[macro_use] extern crate synom;
488///
489/// use syn::Expr;
490/// use syn::parse::expr;
491///
492/// // An expression terminated by ##.
493/// named!(expr_pound_pound -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500494/// terminated!(expr, punct!("##"))
495/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500496///
497/// fn main() {
498/// let input = "1 + 1 ##";
499///
500/// let parsed = expr_pound_pound(input).expect("expr pound pound");
501///
502/// println!("{:?}", parsed);
503/// }
504/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500505#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700506macro_rules! terminated {
507 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
508 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500509 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
510 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700511 }
512 };
513
514 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700515 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700516 };
517
518 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700519 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700520 };
521
522 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700523 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700524 };
525}
526
David Tolnay1f16b602017-02-07 20:06:55 -0500527/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500528///
529/// - **Syntax:** `many0!(THING)`
530/// - **Output:** `Vec<THING>`
531///
David Tolnay1f16b602017-02-07 20:06:55 -0500532/// You may also be looking for:
533///
534/// - `separated_list!` - zero or more values with separator
535/// - `separated_nonempty_list!` - one or more values
536/// - `terminated_list!` - zero or more, allows trailing separator
537///
Michael Layzell24645a32017-02-04 13:19:26 -0500538/// ```rust
539/// extern crate syn;
540/// #[macro_use] extern crate synom;
541///
542/// use syn::Item;
543/// use syn::parse::item;
544///
545/// named!(items -> Vec<Item>, many0!(item));
546///
547/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500548/// let input = "
549/// fn a() {}
550/// fn b() {}
551/// ";
Michael Layzell24645a32017-02-04 13:19:26 -0500552///
553/// let parsed = items(input).expect("items");
554///
David Tolnay1f16b602017-02-07 20:06:55 -0500555/// assert_eq!(parsed.len(), 2);
Michael Layzell24645a32017-02-04 13:19:26 -0500556/// println!("{:?}", parsed);
557/// }
558/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500559#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700560macro_rules! many0 {
561 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
562 let ret;
563 let mut res = ::std::vec::Vec::new();
564 let mut input = $i;
565
566 loop {
567 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500568 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700569 break;
570 }
571
572 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500573 $crate::IResult::Error => {
574 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700575 break;
576 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500577 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700578 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700579 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500580 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700581 break;
582 }
583
584 res.push(o);
585 input = i;
586 }
587 }
588 }
589
590 ret
591 }};
592
593 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500594 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700595 };
596}
597
David Tolnay1f16b602017-02-07 20:06:55 -0500598// Improve compile time by compiling this loop only once per type it is used
599// with.
600//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800601// Not public API.
602#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400603pub fn many0<'a, T>(mut input: &'a [TokenTree],
604 f: fn(&'a [TokenTree]) -> IResult<&'a [TokenTree], T>)
605 -> IResult<&'a [TokenTree], Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700606 let mut res = Vec::new();
607
608 loop {
609 if input.is_empty() {
610 return IResult::Done(input, res);
611 }
612
613 match f(input) {
614 IResult::Error => {
615 return IResult::Done(input, res);
616 }
617 IResult::Done(i, o) => {
618 // loop trip must always consume (otherwise infinite loops)
619 if i.len() == input.len() {
620 return IResult::Error;
621 }
622
623 res.push(o);
624 input = i;
625 }
626 }
627 }
628}
629
David Tolnay1f16b602017-02-07 20:06:55 -0500630/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500631///
632/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500633/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500634///
635/// ```rust
636/// extern crate syn;
637/// #[macro_use] extern crate synom;
638///
David Tolnay1f16b602017-02-07 20:06:55 -0500639/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500640/// use syn::parse::{ident, expr};
David Tolnay1f16b602017-02-07 20:06:55 -0500641/// use synom::IResult;
Michael Layzell24645a32017-02-04 13:19:26 -0500642///
David Tolnay1f16b602017-02-07 20:06:55 -0500643/// // Parse an expression that begins with an identifier.
644/// named!(ident_expr -> Expr,
645/// preceded!(peek!(ident), expr)
646/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500647///
648/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500649/// // begins with an identifier
650/// let input = "banana + 1";
Michael Layzell24645a32017-02-04 13:19:26 -0500651/// let parsed = ident_expr(input).expect("ident");
Michael Layzell24645a32017-02-04 13:19:26 -0500652/// println!("{:?}", parsed);
David Tolnay1f16b602017-02-07 20:06:55 -0500653///
654/// // does not begin with an identifier
655/// let input = "1 + banana";
656/// let err = ident_expr(input);
657/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -0500658/// }
659/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500660#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700661macro_rules! peek {
662 ($i:expr, $submac:ident!( $($args:tt)* )) => {
663 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500664 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
665 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700666 }
667 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700668
David Tolnay1f16b602017-02-07 20:06:55 -0500669 ($i:expr, $f:expr) => {
670 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700671 };
672}
673
David Tolnay1f16b602017-02-07 20:06:55 -0500674/// Parse the part of the input up to but not including the given string. Fail
675/// to parse if the given string is not present in the input.
676///
677/// - **Syntax:** `take_until!("...")`
678/// - **Output:** `&str`
679///
680/// ```rust
681/// extern crate syn;
682/// #[macro_use] extern crate synom;
683/// use synom::IResult;
684///
685/// // Parse a single line doc comment: /// ...
686/// named!(single_line_doc -> &str,
687/// preceded!(punct!("///"), take_until!("\n"))
688/// );
689///
690/// fn main() {
691/// let comment = "/// comment\n";
692/// let parsed = single_line_doc(comment).expect("single line doc comment");
693/// assert_eq!(parsed, " comment");
694/// }
695/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500696#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700697macro_rules! take_until {
David Tolnay1f16b602017-02-07 20:06:55 -0500698 ($i:expr, $substr:expr) => {{
699 if $substr.len() > $i.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500700 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700701 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500702 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700703 let mut window: Vec<char> = vec![];
David Tolnay1f16b602017-02-07 20:06:55 -0500704 let mut offset = $i.len();
David Tolnayb5a7b142016-09-13 22:46:39 -0700705 let mut parsed = false;
David Tolnay1f16b602017-02-07 20:06:55 -0500706 for (o, c) in $i.char_indices() {
David Tolnayb5a7b142016-09-13 22:46:39 -0700707 window.push(c);
708 if window.len() > substr_vec.len() {
709 window.remove(0);
710 }
711 if window == substr_vec {
712 parsed = true;
713 window.pop();
714 let window_len: usize = window.iter()
715 .map(|x| x.len_utf8())
716 .fold(0, |x, y| x + y);
717 offset = o - window_len;
718 break;
719 }
720 }
721 if parsed {
David Tolnay1f16b602017-02-07 20:06:55 -0500722 $crate::IResult::Done(&$i[offset..], &$i[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700723 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500724 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700725 }
726 }
727 }};
728}
729
David Tolnay1f16b602017-02-07 20:06:55 -0500730/// Pattern-match the result of a parser to select which other parser to run.
731///
732/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
733/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
734///
735/// ```rust
736/// extern crate syn;
737/// #[macro_use] extern crate synom;
738///
739/// use syn::{Ident, Ty};
740/// use syn::parse::{ident, ty};
741///
742/// #[derive(Debug)]
743/// enum UnitType {
744/// Struct {
745/// name: Ident,
746/// },
747/// Enum {
748/// name: Ident,
749/// variant: Ident,
750/// },
751/// }
752///
753/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
754/// named!(unit_type -> UnitType, do_parse!(
755/// which: alt!(keyword!("struct") | keyword!("enum")) >>
756/// id: ident >>
757/// item: switch!(value!(which),
758/// "struct" => map!(
759/// punct!(";"),
760/// move |_| UnitType::Struct {
761/// name: id,
762/// }
763/// )
764/// |
765/// "enum" => map!(
766/// delimited!(punct!("{"), ident, punct!("}")),
767/// move |variant| UnitType::Enum {
768/// name: id,
769/// variant: variant,
770/// }
771/// )
772/// ) >>
773/// (item)
774/// ));
775///
776/// fn main() {
777/// let input = "struct S;";
778/// let parsed = unit_type(input).expect("unit struct or enum");
779/// println!("{:?}", parsed);
780///
781/// let input = "enum E { V }";
782/// let parsed = unit_type(input).expect("unit struct or enum");
783/// println!("{:?}", parsed);
784/// }
785/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500786#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700787macro_rules! switch {
788 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
789 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500790 $crate::IResult::Error => $crate::IResult::Error,
791 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700792 $(
793 $p => $subrule!(i, $($args2)*),
794 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500795 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700796 }
797 }
798 };
799}
800
David Tolnay1f16b602017-02-07 20:06:55 -0500801/// Produce the given value without parsing anything. Useful as an argument to
802/// `switch!`.
803///
804/// - **Syntax:** `value!(VALUE)`
805/// - **Output:** `VALUE`
806///
807/// ```rust
808/// extern crate syn;
809/// #[macro_use] extern crate synom;
810///
811/// use syn::{Ident, Ty};
812/// use syn::parse::{ident, ty};
813///
814/// #[derive(Debug)]
815/// enum UnitType {
816/// Struct {
817/// name: Ident,
818/// },
819/// Enum {
820/// name: Ident,
821/// variant: Ident,
822/// },
823/// }
824///
825/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
826/// named!(unit_type -> UnitType, do_parse!(
827/// which: alt!(keyword!("struct") | keyword!("enum")) >>
828/// id: ident >>
829/// item: switch!(value!(which),
830/// "struct" => map!(
831/// punct!(";"),
832/// move |_| UnitType::Struct {
833/// name: id,
834/// }
835/// )
836/// |
837/// "enum" => map!(
838/// delimited!(punct!("{"), ident, punct!("}")),
839/// move |variant| UnitType::Enum {
840/// name: id,
841/// variant: variant,
842/// }
843/// )
844/// ) >>
845/// (item)
846/// ));
847///
848/// fn main() {
849/// let input = "struct S;";
850/// let parsed = unit_type(input).expect("unit struct or enum");
851/// println!("{:?}", parsed);
852///
853/// let input = "enum E { V }";
854/// let parsed = unit_type(input).expect("unit struct or enum");
855/// println!("{:?}", parsed);
856/// }
857/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500858#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700859macro_rules! value {
860 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500861 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700862 };
863}
864
David Tolnayf2222f02017-01-27 17:09:20 -0800865/// Value surrounded by a pair of delimiters.
866///
867/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
868/// - **Output:** `THING`
869///
870/// ```rust
871/// extern crate syn;
872/// #[macro_use] extern crate synom;
873///
874/// use syn::Expr;
875/// use syn::parse::expr;
876///
877/// // An expression surrounded by [[ ... ]].
878/// named!(double_bracket_expr -> Expr,
David Tolnay1f16b602017-02-07 20:06:55 -0500879/// delimited!(punct!("[["), expr, punct!("]]"))
880/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800881///
882/// fn main() {
883/// let input = "[[ 1 + 1 ]]";
884///
885/// let parsed = double_bracket_expr(input).expect("double bracket expr");
886///
887/// println!("{:?}", parsed);
888/// }
889/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500890#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700891macro_rules! delimited {
892 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
893 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500894 $crate::IResult::Error => $crate::IResult::Error,
895 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700896 }
897 };
898
899 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700900 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700901 };
902}
903
David Tolnay1f16b602017-02-07 20:06:55 -0500904/// One or more values separated by some separator. Does not allow a trailing
905/// separator.
David Tolnayf2222f02017-01-27 17:09:20 -0800906///
907/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
908/// - **Output:** `Vec<THING>`
909///
David Tolnay1f16b602017-02-07 20:06:55 -0500910/// You may also be looking for:
911///
912/// - `separated_list!` - one or more values
913/// - `terminated_list!` - zero or more, allows trailing separator
914/// - `many0!` - zero or more, no separator
915///
David Tolnayf2222f02017-01-27 17:09:20 -0800916/// ```rust
917/// extern crate syn;
918/// #[macro_use] extern crate synom;
919///
920/// use syn::Ty;
921/// use syn::parse::ty;
922///
923/// // One or more Rust types separated by commas.
924/// named!(comma_separated_types -> Vec<Ty>,
David Tolnay1f16b602017-02-07 20:06:55 -0500925/// separated_nonempty_list!(punct!(","), ty)
926/// );
David Tolnayf2222f02017-01-27 17:09:20 -0800927///
928/// fn main() {
929/// let input = "&str, Map<K, V>, String";
930///
931/// let parsed = comma_separated_types(input).expect("comma-separated types");
932///
933/// assert_eq!(parsed.len(), 3);
934/// println!("{:?}", parsed);
935/// }
936/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500937#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700938macro_rules! separated_nonempty_list {
939 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
940 let mut res = ::std::vec::Vec::new();
941 let mut input = $i;
942
943 // get the first element
944 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500945 $crate::IResult::Error => $crate::IResult::Error,
946 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700947 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500948 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700949 } else {
950 res.push(o);
951 input = i;
952
Michael Layzell5bde96f2017-01-24 17:59:21 -0500953 while let $crate::IResult::Done(i2, _) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700954 if i2.len() == input.len() {
955 break;
956 }
957
Michael Layzell5bde96f2017-01-24 17:59:21 -0500958 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700959 if i3.len() == i2.len() {
960 break;
961 }
962 res.push(o3);
963 input = i3;
964 } else {
965 break;
966 }
967 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500968 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700969 }
970 }
971 }
972 }};
973
974 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700975 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700976 };
977
978 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700979 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700980 };
981
982 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700983 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700984 };
985}
986
David Tolnay1f16b602017-02-07 20:06:55 -0500987/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500988///
David Tolnay1f16b602017-02-07 20:06:55 -0500989/// - **Syntax:** `tuple!(A, B, C, ...)`
990/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500991///
992/// ```rust
993/// extern crate syn;
994/// #[macro_use] extern crate synom;
995///
996/// use syn::Ty;
997/// use syn::parse::ty;
998///
999/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
1000///
1001/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001002/// let input = "&str Map<K, V>";
Michael Layzell24645a32017-02-04 13:19:26 -05001003///
David Tolnay1f16b602017-02-07 20:06:55 -05001004/// let parsed = two_types(input).expect("two types");
Michael Layzell24645a32017-02-04 13:19:26 -05001005///
1006/// println!("{:?}", parsed);
1007/// }
1008/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001009#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001010macro_rules! tuple {
1011 ($i:expr, $($rest:tt)*) => {
1012 tuple_parser!($i, (), $($rest)*)
1013 };
1014}
1015
David Tolnay1f16b602017-02-07 20:06:55 -05001016/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -05001017#[doc(hidden)]
1018#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001019macro_rules! tuple_parser {
1020 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001021 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001022 };
1023
1024 ($i:expr, (), $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, (o), $($rest)*),
1029 }
1030 };
1031
1032 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
1033 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001034 $crate::IResult::Error => $crate::IResult::Error,
1035 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001036 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
1037 }
1038 };
1039
1040 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001041 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001042 };
1043
1044 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
1045 $submac!($i, $($args)*)
1046 };
1047
1048 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
1049 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001050 $crate::IResult::Error => $crate::IResult::Error,
1051 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -07001052 }
1053 };
1054
1055 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001056 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -07001057 };
1058}
1059
David Tolnay1f16b602017-02-07 20:06:55 -05001060/// Run a series of parsers, returning the result of the first one which
1061/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -05001062///
1063/// Optionally allows for the result to be transformed.
1064///
1065/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -05001066/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -05001067///
1068/// ```rust
1069/// extern crate syn;
1070/// #[macro_use] extern crate synom;
1071///
1072/// use syn::Ident;
1073/// use syn::parse::ident;
1074///
1075/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -05001076/// alt!(
1077/// ident
1078/// |
1079/// punct!("!") => { |_| "BANG".into() }
1080/// )
1081/// );
Michael Layzell24645a32017-02-04 13:19:26 -05001082///
1083/// fn main() {
Michael Layzell24645a32017-02-04 13:19:26 -05001084/// let input = "foo";
David Tolnay1f16b602017-02-07 20:06:55 -05001085/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1086/// assert_eq!(parsed, "foo");
1087///
1088/// let input = "!";
1089/// let parsed = ident_or_bang(input).expect("identifier or `!`");
1090/// assert_eq!(parsed, "BANG");
Michael Layzell24645a32017-02-04 13:19:26 -05001091/// }
1092/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001093#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001094macro_rules! alt {
1095 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001096 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001097 };
1098
1099 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
1100 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001101 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -07001102 _ => alt!($i, $($rest)*)
1103 }
1104 };
1105
1106 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
1107 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001108 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1109 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001110 }
1111 };
1112
1113 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001114 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001115 };
1116
1117 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001118 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -07001119 };
1120
1121 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
1122 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001123 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
1124 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -07001125 }
1126 };
1127
1128 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001129 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -07001130 };
1131
1132 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -07001133 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001134 };
1135}
1136
Michael Layzell24645a32017-02-04 13:19:26 -05001137/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -05001138/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -05001139///
David Tolnay1f16b602017-02-07 20:06:55 -05001140/// Produces the result of evaluating the final expression in parentheses with
1141/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -05001142///
David Tolnay1f16b602017-02-07 20:06:55 -05001143/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -05001144/// - **Output:** `RESULT`
1145///
1146/// ```rust
1147/// extern crate syn;
1148/// #[macro_use] extern crate synom;
1149///
1150/// use syn::{Ident, TokenTree};
1151/// use syn::parse::{ident, tt};
1152///
David Tolnay1f16b602017-02-07 20:06:55 -05001153/// // Parse a macro invocation like `stringify!($args)`.
Michael Layzell24645a32017-02-04 13:19:26 -05001154/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
1155/// name: ident >>
1156/// punct!("!") >>
1157/// body: tt >>
David Tolnay1f16b602017-02-07 20:06:55 -05001158/// (name, body)
1159/// ));
Michael Layzell24645a32017-02-04 13:19:26 -05001160///
1161/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -05001162/// let input = "stringify!($args)";
1163/// let (name, body) = simple_mac(input).expect("macro invocation");
1164/// println!("{:?}", name);
1165/// println!("{:?}", body);
Michael Layzell24645a32017-02-04 13:19:26 -05001166/// }
1167/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -05001168#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -07001169macro_rules! do_parse {
1170 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001171 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -07001172 };
1173
1174 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001175 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001176 };
1177
1178 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1179 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001180 $crate::IResult::Error => $crate::IResult::Error,
1181 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -07001182 do_parse!(i, $($rest)*),
1183 }
1184 };
1185
1186 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -07001187 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -07001188 };
1189
1190 ($i:expr, $field:ident : $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, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -07001194 let $field = o;
1195 do_parse!(i, $($rest)*)
1196 },
1197 }
1198 };
1199
David Tolnayfa0edf22016-09-23 22:58:24 -07001200 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -07001201 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -07001202 };
1203
1204 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
1205 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -05001206 $crate::IResult::Error => $crate::IResult::Error,
1207 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -07001208 let mut $field = o;
1209 do_parse!(i, $($rest)*)
1210 },
1211 }
1212 };
David Tolnayb5a7b142016-09-13 22:46:39 -07001213}
Michael Layzell416724e2017-05-24 21:12:34 -04001214
1215#[macro_export]
1216macro_rules! input_end {
1217 ($i:expr,) => {
1218 $crate::input_end($i)
1219 };
1220}
1221
1222// Not a public API
1223#[doc(hidden)]
1224pub fn input_end(input: &[TokenTree]) -> IResult<&'static [TokenTree], &'static str> {
1225 if input.is_empty() {
1226 IResult::Done(&[], "")
1227 } else {
1228 IResult::Error
1229 }
1230}