blob: fc89c7b19ddfe23be3e5ba312ebe4f115d3b1b8f [file] [log] [blame]
Michael Layzell5bde96f2017-01-24 17:59:21 -05001use IResult;
David Tolnaydef66372016-10-24 21:51:32 -07002use space::{skip_whitespace, word_break};
Alex Crichtonccbb45d2017-05-23 10:58:24 -07003use delimited::Delimited;
David Tolnayb79ee962016-09-04 09:39:20 -07004
David Tolnay1f16b602017-02-07 20:06:55 -05005/// Parse a piece of punctuation like "+" or "+=".
6///
7/// See also `keyword!` for parsing keywords, which are subtly different from
8/// punctuation.
Michael Layzell24645a32017-02-04 13:19:26 -05009///
10/// - **Syntax:** `punct!("...")`
11/// - **Output:** `&str`
12///
13/// ```rust
14/// extern crate syn;
15/// #[macro_use] extern crate synom;
16///
David Tolnay1f16b602017-02-07 20:06:55 -050017/// // Parse zero or more bangs.
18/// named!(many_bangs -> Vec<&str>,
19/// many0!(punct!("!"))
20/// );
Michael Layzell24645a32017-02-04 13:19:26 -050021///
22/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050023/// let input = "!! !";
24/// let parsed = many_bangs(input).expect("bangs");
25/// assert_eq!(parsed, ["!", "!", "!"]);
Michael Layzell24645a32017-02-04 13:19:26 -050026/// }
27/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050028#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -070029macro_rules! punct {
30 ($i:expr, $punct:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080031 $crate::helper::punct($i, $punct)
David Tolnayb79ee962016-09-04 09:39:20 -070032 };
33}
34
David Tolnay5fe14fc2017-01-27 16:22:08 -080035// Not public API.
36#[doc(hidden)]
David Tolnay13e5da42016-09-04 16:18:34 -070037pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
David Tolnaydef66372016-10-24 21:51:32 -070038 let input = skip_whitespace(input);
David Tolnay14cbdeb2016-10-01 12:13:59 -070039 if input.starts_with(token) {
40 IResult::Done(&input[token.len()..], token)
41 } else {
42 IResult::Error
David Tolnay13e5da42016-09-04 16:18:34 -070043 }
David Tolnay13e5da42016-09-04 16:18:34 -070044}
45
David Tolnay1f16b602017-02-07 20:06:55 -050046/// Parse a keyword like "fn" or "struct".
47///
48/// See also `punct!` for parsing punctuation, which are subtly different from
49/// keywords.
Michael Layzell24645a32017-02-04 13:19:26 -050050///
51/// - **Syntax:** `keyword!("...")`
52/// - **Output:** `&str`
53///
54/// ```rust
55/// extern crate syn;
56/// #[macro_use] extern crate synom;
57///
David Tolnay1f16b602017-02-07 20:06:55 -050058/// use synom::IResult;
59///
60/// // Parse zero or more "bang" keywords.
61/// named!(many_bangs -> Vec<&str>,
62/// terminated!(
63/// many0!(keyword!("bang")),
64/// punct!(";")
65/// )
66/// );
Michael Layzell24645a32017-02-04 13:19:26 -050067///
68/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050069/// let input = "bang bang bang;";
70/// let parsed = many_bangs(input).expect("bangs");
71/// assert_eq!(parsed, ["bang", "bang", "bang"]);
72///
73/// let input = "bangbang;";
74/// let err = many_bangs(input);
75/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -050076/// }
77/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050078#[macro_export]
David Tolnay10413f02016-09-30 09:12:02 -070079macro_rules! keyword {
80 ($i:expr, $keyword:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080081 $crate::helper::keyword($i, $keyword)
David Tolnay10413f02016-09-30 09:12:02 -070082 };
83}
84
David Tolnay5fe14fc2017-01-27 16:22:08 -080085// Not public API.
86#[doc(hidden)]
David Tolnay10413f02016-09-30 09:12:02 -070087pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
88 match punct(input, token) {
89 IResult::Done(rest, _) => {
90 match word_break(rest) {
91 IResult::Done(_, _) => IResult::Done(rest, token),
92 IResult::Error => IResult::Error,
93 }
94 }
95 IResult::Error => IResult::Error,
96 }
97}
98
David Tolnay1f16b602017-02-07 20:06:55 -050099/// Turn a failed parse into `None` and a successful parse into `Some`.
Michael Layzell24645a32017-02-04 13:19:26 -0500100///
101/// - **Syntax:** `option!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500102/// - **Output:** `Option<THING>`
Michael Layzell24645a32017-02-04 13:19:26 -0500103///
104/// ```rust
105/// extern crate syn;
106/// #[macro_use] extern crate synom;
107///
108/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
109///
110/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500111/// let input = "!";
112/// let parsed = maybe_bang(input).expect("maybe bang");
113/// assert_eq!(parsed, Some("!"));
114///
Michael Layzell24645a32017-02-04 13:19:26 -0500115/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500116/// let parsed = maybe_bang(input).expect("maybe bang");
117/// assert_eq!(parsed, None);
Michael Layzell24645a32017-02-04 13:19:26 -0500118/// }
119/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500120#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700121macro_rules! option {
122 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -0700123 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500124 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
125 $crate::IResult::Error => $crate::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -0700126 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700127 };
David Tolnayf6ccb832016-09-04 15:00:56 -0700128
David Tolnayb5a7b142016-09-13 22:46:39 -0700129 ($i:expr, $f:expr) => {
130 option!($i, call!($f));
131 };
132}
133
David Tolnay1f16b602017-02-07 20:06:55 -0500134/// Turn a failed parse into an empty vector. The argument parser must itself
135/// return a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500136///
David Tolnay1f16b602017-02-07 20:06:55 -0500137/// This is often more convenient than `option!(...)` when the argument produces
138/// a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500139///
140/// - **Syntax:** `opt_vec!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500141/// - **Output:** `THING`, which must be `Vec<T>`
Michael Layzell24645a32017-02-04 13:19:26 -0500142///
143/// ```rust
144/// extern crate syn;
145/// #[macro_use] extern crate synom;
146///
David Tolnay1f16b602017-02-07 20:06:55 -0500147/// use syn::{Lifetime, Ty};
148/// use syn::parse::{lifetime, ty};
Michael Layzell24645a32017-02-04 13:19:26 -0500149///
David Tolnay1f16b602017-02-07 20:06:55 -0500150/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
151/// opt_vec!(do_parse!(
152/// keyword!("for") >>
153/// punct!("<") >>
154/// lifetimes: terminated_list!(punct!(","), lifetime) >>
155/// punct!(">") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700156/// (lifetimes.into_vec())
David Tolnay1f16b602017-02-07 20:06:55 -0500157/// )),
158/// ty
159/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500160///
161/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500162/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
163/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
164/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
165/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500166///
David Tolnay1f16b602017-02-07 20:06:55 -0500167/// let input = "From<String>";
168/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
169/// assert!(parsed.0.is_empty());
170/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500171/// }
172/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500173#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700174macro_rules! opt_vec {
175 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -0700176 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500177 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
178 $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -0700179 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700180 };
181}
David Tolnayb79ee962016-09-04 09:39:20 -0700182
Michael Layzell24645a32017-02-04 13:19:26 -0500183/// Parses nothing and always succeeds.
184///
David Tolnay1f16b602017-02-07 20:06:55 -0500185/// This can be useful as a fallthrough case in `alt!`.
186///
Michael Layzell24645a32017-02-04 13:19:26 -0500187/// - **Syntax:** `epsilon!()`
188/// - **Output:** `()`
189///
190/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500191/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500192/// #[macro_use] extern crate synom;
193///
David Tolnay1f16b602017-02-07 20:06:55 -0500194/// use syn::Mutability;
195///
196/// named!(mutability -> Mutability, alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700197/// keyword!("mut") => { |_| Mutability::Mutable(Default::default()) }
David Tolnay1f16b602017-02-07 20:06:55 -0500198/// |
199/// epsilon!() => { |_| Mutability::Immutable }
200/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500201///
202/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500203/// let input = "mut";
204/// let parsed = mutability(input).expect("mutability");
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700205/// assert_eq!(parsed, Mutability::Mutable(Default::default()));
David Tolnay1f16b602017-02-07 20:06:55 -0500206///
Michael Layzell24645a32017-02-04 13:19:26 -0500207/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// let parsed = mutability(input).expect("mutability");
209/// assert_eq!(parsed, Mutability::Immutable);
Michael Layzell24645a32017-02-04 13:19:26 -0500210/// }
211/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500212#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -0700213macro_rules! epsilon {
214 ($i:expr,) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500215 $crate::IResult::Done($i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700216 };
217}
218
Michael Layzell24645a32017-02-04 13:19:26 -0500219/// Run a parser, binding the result to a name, and then evaluating an
220/// expression.
221///
222/// Discards the result of the expression and parser.
223///
224/// - **Syntax:** `tap!(NAME : THING => EXPR)`
225/// - **Output:** `()`
226///
227/// ```rust
228/// extern crate syn;
229/// #[macro_use] extern crate synom;
230///
Alex Crichton62a0a592017-05-22 13:58:53 -0700231/// use syn::{Expr, ExprCall};
Michael Layzell24645a32017-02-04 13:19:26 -0500232/// use syn::parse::expr;
233///
David Tolnay1f16b602017-02-07 20:06:55 -0500234/// named!(expr_with_arrow_call -> Expr, do_parse!(
Michael Layzell24645a32017-02-04 13:19:26 -0500235/// mut e: expr >>
236/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
237/// e = Expr {
Alex Crichton62a0a592017-05-22 13:58:53 -0700238/// node: ExprCall {
239/// func: Box::new(e),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700240/// args: vec![arg.1].into(),
241/// paren_token: Default::default(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700242/// }.into(),
Michael Layzell24645a32017-02-04 13:19:26 -0500243/// attrs: Vec::new(),
244/// };
245/// })) >>
246/// (e)
247/// ));
248///
249/// fn main() {
250/// let input = "something => argument1 => argument2";
251///
David Tolnay1f16b602017-02-07 20:06:55 -0500252/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500253///
David Tolnay1f16b602017-02-07 20:06:55 -0500254/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500255/// }
256/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500257#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500258#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700259macro_rules! tap {
260 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
261 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500262 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700263 let $name = o;
264 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500265 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700266 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500267 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700268 }
269 };
270
271 ($i:expr, $name:ident : $f:expr => $e:expr) => {
272 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700273 };
274}
David Tolnay674258d2016-10-08 13:30:45 -0700275
David Tolnay1f16b602017-02-07 20:06:55 -0500276/// Zero or more values separated by some separator. Does not allow a trailing
277/// seperator.
Michael Layzell24645a32017-02-04 13:19:26 -0500278///
Michael Layzell24645a32017-02-04 13:19:26 -0500279/// - **Syntax:** `separated_list!(punct!("..."), THING)`
280/// - **Output:** `Vec<THING>`
281///
David Tolnay1f16b602017-02-07 20:06:55 -0500282/// You may also be looking for:
283///
284/// - `separated_nonempty_list!` - one or more values
285/// - `terminated_list!` - zero or more, allows trailing separator
286/// - `many0!` - zero or more, no separator
287///
Michael Layzell24645a32017-02-04 13:19:26 -0500288/// ```rust
289/// extern crate syn;
290/// #[macro_use] extern crate synom;
291///
292/// use syn::Expr;
293/// use syn::parse::expr;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700294/// use synom::delimited::Delimited;
Michael Layzell24645a32017-02-04 13:19:26 -0500295///
David Tolnay1f16b602017-02-07 20:06:55 -0500296/// named!(expr_list -> Vec<Expr>,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700297/// map!(separated_list!(punct!(","), expr),
298/// |v: Delimited<_, _>| v.into_vec())
David Tolnay1f16b602017-02-07 20:06:55 -0500299/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500300///
301/// fn main() {
302/// let input = "1 + 1, things, Construct { this: thing }";
303///
David Tolnay1f16b602017-02-07 20:06:55 -0500304/// let parsed = expr_list(input).expect("expr list");
305/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500306/// }
307/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800308///
309/// ```rust
310/// extern crate syn;
311/// #[macro_use] extern crate synom;
312///
313/// use syn::Ident;
314/// use syn::parse::ident;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700315/// use synom::delimited::Delimited;
David Tolnaydff18802017-02-27 11:57:03 -0800316///
317/// named!(run_on -> Vec<Ident>,
318/// terminated!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700319/// map!(
320/// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
321/// |v: Delimited<_, _>| v.into_vec()
322/// ),
David Tolnaydff18802017-02-27 11:57:03 -0800323/// punct!("...")
324/// )
325/// );
326///
327/// fn main() {
328/// let input = "$expr and $ident and $pat ...";
329///
330/// let parsed = run_on(input).expect("run-on sentence");
331/// assert_eq!(parsed.len(), 3);
332/// assert_eq!(parsed[0], "expr");
333/// assert_eq!(parsed[1], "ident");
334/// assert_eq!(parsed[2], "pat");
335/// }
336/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500337#[macro_export]
David Tolnay674258d2016-10-08 13:30:45 -0700338macro_rules! separated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800339 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700340 $crate::helper::separated_list($i,
341 |d| $sepmac!(d, $($separgs)*),
342 |d| $fmac!(d, $($fargs)*),
343 false)
David Tolnaydff18802017-02-27 11:57:03 -0800344 }};
345
346 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
Christopher Bacher9620ae02017-03-02 00:44:25 +0100347 separated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800348 };
349
350 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800351 separated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800352 };
353
354 ($i:expr, $sep:expr, $f:expr) => {
355 separated_list!($i, call!($sep), call!($f))
356 };
David Tolnay674258d2016-10-08 13:30:45 -0700357}
358
David Tolnay1f16b602017-02-07 20:06:55 -0500359/// Zero or more values separated by some separator. A trailing separator is
360/// allowed.
Michael Layzell24645a32017-02-04 13:19:26 -0500361///
Michael Layzell24645a32017-02-04 13:19:26 -0500362/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
363/// - **Output:** `Vec<THING>`
364///
David Tolnay1f16b602017-02-07 20:06:55 -0500365/// You may also be looking for:
366///
367/// - `separated_list!` - zero or more, allows trailing separator
368/// - `separated_nonempty_list!` - one or more values
369/// - `many0!` - zero or more, no separator
370///
Michael Layzell24645a32017-02-04 13:19:26 -0500371/// ```rust
372/// extern crate syn;
373/// #[macro_use] extern crate synom;
374///
375/// use syn::Expr;
376/// use syn::parse::expr;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700377/// use synom::delimited::Delimited;
Michael Layzell24645a32017-02-04 13:19:26 -0500378///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700379/// named!(expr_list -> Delimited<Expr, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500380/// terminated_list!(punct!(","), expr)
381/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500382///
383/// fn main() {
384/// let input = "1 + 1, things, Construct { this: thing },";
385///
David Tolnay1f16b602017-02-07 20:06:55 -0500386/// let parsed = expr_list(input).expect("expr list");
387/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500388/// }
389/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800390///
391/// ```rust
392/// extern crate syn;
393/// #[macro_use] extern crate synom;
394///
395/// use syn::Ident;
396/// use syn::parse::ident;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700397/// use synom::delimited::Delimited;
David Tolnaydff18802017-02-27 11:57:03 -0800398///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700399/// named!(run_on -> Delimited<Ident, &str>,
David Tolnaydff18802017-02-27 11:57:03 -0800400/// terminated!(
401/// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
402/// punct!("...")
403/// )
404/// );
405///
406/// fn main() {
407/// let input = "$expr and $ident and $pat and ...";
408///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700409/// let parsed = run_on(input).expect("run-on sentence").into_vec();
David Tolnaydff18802017-02-27 11:57:03 -0800410/// assert_eq!(parsed.len(), 3);
411/// assert_eq!(parsed[0], "expr");
412/// assert_eq!(parsed[1], "ident");
413/// assert_eq!(parsed[2], "pat");
414/// }
415/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500416#[macro_export]
David Tolnayff46fd22016-10-08 13:53:28 -0700417macro_rules! terminated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800418 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700419 $crate::helper::separated_list($i,
420 |d| $sepmac!(d, $($separgs)*),
421 |d| $fmac!(d, $($fargs)*),
422 true)
David Tolnaydff18802017-02-27 11:57:03 -0800423 }};
424
425 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800426 terminated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800427 };
428
429 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800430 terminated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800431 };
432
433 ($i:expr, $sep:expr, $f:expr) => {
434 terminated_list!($i, call!($sep), call!($f))
435 };
David Tolnayff46fd22016-10-08 13:53:28 -0700436}
437
David Tolnay5fe14fc2017-01-27 16:22:08 -0800438// Not public API.
439#[doc(hidden)]
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700440pub fn separated_list<'a, F1, D, F2, T>(mut input: &'a str,
441 mut sep: F1,
442 mut parse: F2,
443 terminated: bool)
444 -> IResult<&'a str, Delimited<T, D>>
445 where F1: FnMut(&'a str) -> IResult<&'a str, D>,
446 F2: FnMut(&'a str) -> IResult<&'a str, T>,
447{
448 let mut res = Delimited::new();
David Tolnay674258d2016-10-08 13:30:45 -0700449
450 // get the first element
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700451 match parse(input) {
David Tolnaydff18802017-02-27 11:57:03 -0800452 IResult::Error => IResult::Done(input, res),
David Tolnay674258d2016-10-08 13:30:45 -0700453 IResult::Done(i, o) => {
454 if i.len() == input.len() {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700455 return IResult::Error
David Tolnay674258d2016-10-08 13:30:45 -0700456 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700457 input = i;
458 res.push_first(o);
459
460 // get the separator first
461 while let IResult::Done(i2, s) = sep(input) {
462 if i2.len() == input.len() {
463 break;
464 }
465
466 // get the element next
467 if let IResult::Done(i3, o3) = parse(i2) {
468 if i3.len() == i2.len() {
469 break;
470 }
471 res.push_next(o3, s);
472 input = i3;
473 } else {
474 break;
475 }
476 }
477 if terminated {
478 if let IResult::Done(after, sep) = sep(input) {
479 res.push_trailing(sep);
480 input = after;
481 }
482 }
483 IResult::Done(input, res)
David Tolnay674258d2016-10-08 13:30:45 -0700484 }
485 }
486}