blob: 59e46ee449563e5e48063912521e9c0316645498 [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};
David Tolnayb79ee962016-09-04 09:39:20 -07003
David Tolnay1f16b602017-02-07 20:06:55 -05004/// Parse a piece of punctuation like "+" or "+=".
5///
6/// See also `keyword!` for parsing keywords, which are subtly different from
7/// punctuation.
Michael Layzell24645a32017-02-04 13:19:26 -05008///
9/// - **Syntax:** `punct!("...")`
10/// - **Output:** `&str`
11///
12/// ```rust
13/// extern crate syn;
14/// #[macro_use] extern crate synom;
15///
David Tolnay1f16b602017-02-07 20:06:55 -050016/// // Parse zero or more bangs.
17/// named!(many_bangs -> Vec<&str>,
18/// many0!(punct!("!"))
19/// );
Michael Layzell24645a32017-02-04 13:19:26 -050020///
21/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050022/// let input = "!! !";
23/// let parsed = many_bangs(input).expect("bangs");
24/// assert_eq!(parsed, ["!", "!", "!"]);
Michael Layzell24645a32017-02-04 13:19:26 -050025/// }
26/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050027#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -070028macro_rules! punct {
29 ($i:expr, $punct:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080030 $crate::helper::punct($i, $punct)
David Tolnayb79ee962016-09-04 09:39:20 -070031 };
32}
33
David Tolnay5fe14fc2017-01-27 16:22:08 -080034// Not public API.
35#[doc(hidden)]
David Tolnay13e5da42016-09-04 16:18:34 -070036pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
David Tolnaydef66372016-10-24 21:51:32 -070037 let input = skip_whitespace(input);
David Tolnay14cbdeb2016-10-01 12:13:59 -070038 if input.starts_with(token) {
39 IResult::Done(&input[token.len()..], token)
40 } else {
41 IResult::Error
David Tolnay13e5da42016-09-04 16:18:34 -070042 }
David Tolnay13e5da42016-09-04 16:18:34 -070043}
44
David Tolnay1f16b602017-02-07 20:06:55 -050045/// Parse a keyword like "fn" or "struct".
46///
47/// See also `punct!` for parsing punctuation, which are subtly different from
48/// keywords.
Michael Layzell24645a32017-02-04 13:19:26 -050049///
50/// - **Syntax:** `keyword!("...")`
51/// - **Output:** `&str`
52///
53/// ```rust
54/// extern crate syn;
55/// #[macro_use] extern crate synom;
56///
David Tolnay1f16b602017-02-07 20:06:55 -050057/// use synom::IResult;
58///
59/// // Parse zero or more "bang" keywords.
60/// named!(many_bangs -> Vec<&str>,
61/// terminated!(
62/// many0!(keyword!("bang")),
63/// punct!(";")
64/// )
65/// );
Michael Layzell24645a32017-02-04 13:19:26 -050066///
67/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050068/// let input = "bang bang bang;";
69/// let parsed = many_bangs(input).expect("bangs");
70/// assert_eq!(parsed, ["bang", "bang", "bang"]);
71///
72/// let input = "bangbang;";
73/// let err = many_bangs(input);
74/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -050075/// }
76/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050077#[macro_export]
David Tolnay10413f02016-09-30 09:12:02 -070078macro_rules! keyword {
79 ($i:expr, $keyword:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080080 $crate::helper::keyword($i, $keyword)
David Tolnay10413f02016-09-30 09:12:02 -070081 };
82}
83
David Tolnay5fe14fc2017-01-27 16:22:08 -080084// Not public API.
85#[doc(hidden)]
David Tolnay10413f02016-09-30 09:12:02 -070086pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
87 match punct(input, token) {
88 IResult::Done(rest, _) => {
89 match word_break(rest) {
90 IResult::Done(_, _) => IResult::Done(rest, token),
91 IResult::Error => IResult::Error,
92 }
93 }
94 IResult::Error => IResult::Error,
95 }
96}
97
David Tolnay1f16b602017-02-07 20:06:55 -050098/// Turn a failed parse into `None` and a successful parse into `Some`.
Michael Layzell24645a32017-02-04 13:19:26 -050099///
100/// - **Syntax:** `option!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500101/// - **Output:** `Option<THING>`
Michael Layzell24645a32017-02-04 13:19:26 -0500102///
103/// ```rust
104/// extern crate syn;
105/// #[macro_use] extern crate synom;
106///
107/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
108///
109/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500110/// let input = "!";
111/// let parsed = maybe_bang(input).expect("maybe bang");
112/// assert_eq!(parsed, Some("!"));
113///
Michael Layzell24645a32017-02-04 13:19:26 -0500114/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500115/// let parsed = maybe_bang(input).expect("maybe bang");
116/// assert_eq!(parsed, None);
Michael Layzell24645a32017-02-04 13:19:26 -0500117/// }
118/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500119#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700120macro_rules! option {
121 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -0700122 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500123 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
124 $crate::IResult::Error => $crate::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -0700125 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700126 };
David Tolnayf6ccb832016-09-04 15:00:56 -0700127
David Tolnayb5a7b142016-09-13 22:46:39 -0700128 ($i:expr, $f:expr) => {
129 option!($i, call!($f));
130 };
131}
132
David Tolnay1f16b602017-02-07 20:06:55 -0500133/// Turn a failed parse into an empty vector. The argument parser must itself
134/// return a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500135///
David Tolnay1f16b602017-02-07 20:06:55 -0500136/// This is often more convenient than `option!(...)` when the argument produces
137/// a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500138///
139/// - **Syntax:** `opt_vec!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500140/// - **Output:** `THING`, which must be `Vec<T>`
Michael Layzell24645a32017-02-04 13:19:26 -0500141///
142/// ```rust
143/// extern crate syn;
144/// #[macro_use] extern crate synom;
145///
David Tolnay1f16b602017-02-07 20:06:55 -0500146/// use syn::{Lifetime, Ty};
147/// use syn::parse::{lifetime, ty};
Michael Layzell24645a32017-02-04 13:19:26 -0500148///
David Tolnay1f16b602017-02-07 20:06:55 -0500149/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
150/// opt_vec!(do_parse!(
151/// keyword!("for") >>
152/// punct!("<") >>
153/// lifetimes: terminated_list!(punct!(","), lifetime) >>
154/// punct!(">") >>
155/// (lifetimes)
156/// )),
157/// ty
158/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500159///
160/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500161/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
162/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
163/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
164/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500165///
David Tolnay1f16b602017-02-07 20:06:55 -0500166/// let input = "From<String>";
167/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
168/// assert!(parsed.0.is_empty());
169/// println!("{:?}", parsed);
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! opt_vec {
174 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -0700175 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500176 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
177 $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -0700178 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700179 };
180}
David Tolnayb79ee962016-09-04 09:39:20 -0700181
Michael Layzell24645a32017-02-04 13:19:26 -0500182/// Parses nothing and always succeeds.
183///
David Tolnay1f16b602017-02-07 20:06:55 -0500184/// This can be useful as a fallthrough case in `alt!`.
185///
Michael Layzell24645a32017-02-04 13:19:26 -0500186/// - **Syntax:** `epsilon!()`
187/// - **Output:** `()`
188///
189/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500190/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500191/// #[macro_use] extern crate synom;
192///
David Tolnay1f16b602017-02-07 20:06:55 -0500193/// use syn::Mutability;
194///
195/// named!(mutability -> Mutability, alt!(
196/// keyword!("mut") => { |_| Mutability::Mutable }
197/// |
198/// epsilon!() => { |_| Mutability::Immutable }
199/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500200///
201/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500202/// let input = "mut";
203/// let parsed = mutability(input).expect("mutability");
204/// assert_eq!(parsed, Mutability::Mutable);
205///
Michael Layzell24645a32017-02-04 13:19:26 -0500206/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500207/// let parsed = mutability(input).expect("mutability");
208/// assert_eq!(parsed, Mutability::Immutable);
Michael Layzell24645a32017-02-04 13:19:26 -0500209/// }
210/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500211#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -0700212macro_rules! epsilon {
213 ($i:expr,) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500214 $crate::IResult::Done($i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700215 };
216}
217
Michael Layzell24645a32017-02-04 13:19:26 -0500218/// Run a parser, binding the result to a name, and then evaluating an
219/// expression.
220///
221/// Discards the result of the expression and parser.
222///
223/// - **Syntax:** `tap!(NAME : THING => EXPR)`
224/// - **Output:** `()`
225///
226/// ```rust
227/// extern crate syn;
228/// #[macro_use] extern crate synom;
229///
230/// use syn::{Expr, ExprKind};
231/// use syn::parse::expr;
232///
David Tolnay1f16b602017-02-07 20:06:55 -0500233/// named!(expr_with_arrow_call -> Expr, do_parse!(
Michael Layzell24645a32017-02-04 13:19:26 -0500234/// mut e: expr >>
235/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
236/// e = Expr {
237/// node: ExprKind::Call(Box::new(e), vec![arg.1]),
238/// attrs: Vec::new(),
239/// };
240/// })) >>
241/// (e)
242/// ));
243///
244/// fn main() {
245/// let input = "something => argument1 => argument2";
246///
David Tolnay1f16b602017-02-07 20:06:55 -0500247/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500248///
David Tolnay1f16b602017-02-07 20:06:55 -0500249/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500250/// }
251/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500252#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500253#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700254macro_rules! tap {
255 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
256 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500257 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700258 let $name = o;
259 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500260 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700261 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500262 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700263 }
264 };
265
266 ($i:expr, $name:ident : $f:expr => $e:expr) => {
267 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700268 };
269}
David Tolnay674258d2016-10-08 13:30:45 -0700270
David Tolnay1f16b602017-02-07 20:06:55 -0500271/// Zero or more values separated by some separator. Does not allow a trailing
272/// seperator.
Michael Layzell24645a32017-02-04 13:19:26 -0500273///
Michael Layzell24645a32017-02-04 13:19:26 -0500274/// - **Syntax:** `separated_list!(punct!("..."), THING)`
275/// - **Output:** `Vec<THING>`
276///
David Tolnay1f16b602017-02-07 20:06:55 -0500277/// You may also be looking for:
278///
279/// - `separated_nonempty_list!` - one or more values
280/// - `terminated_list!` - zero or more, allows trailing separator
281/// - `many0!` - zero or more, no separator
282///
Michael Layzell24645a32017-02-04 13:19:26 -0500283/// ```rust
284/// extern crate syn;
285/// #[macro_use] extern crate synom;
286///
287/// use syn::Expr;
288/// use syn::parse::expr;
289///
David Tolnay1f16b602017-02-07 20:06:55 -0500290/// named!(expr_list -> Vec<Expr>,
291/// separated_list!(punct!(","), expr)
292/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500293///
294/// fn main() {
295/// let input = "1 + 1, things, Construct { this: thing }";
296///
David Tolnay1f16b602017-02-07 20:06:55 -0500297/// let parsed = expr_list(input).expect("expr list");
298/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500299/// }
300/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800301///
302/// ```rust
303/// extern crate syn;
304/// #[macro_use] extern crate synom;
305///
306/// use syn::Ident;
307/// use syn::parse::ident;
308///
309/// named!(run_on -> Vec<Ident>,
310/// terminated!(
311/// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
312/// punct!("...")
313/// )
314/// );
315///
316/// fn main() {
317/// let input = "$expr and $ident and $pat ...";
318///
319/// let parsed = run_on(input).expect("run-on sentence");
320/// assert_eq!(parsed.len(), 3);
321/// assert_eq!(parsed[0], "expr");
322/// assert_eq!(parsed[1], "ident");
323/// assert_eq!(parsed[2], "pat");
324/// }
325/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500326#[macro_export]
David Tolnay674258d2016-10-08 13:30:45 -0700327macro_rules! separated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800328 // Try to use this branch if possible - makes a difference in compile time.
David Tolnay0882b9c2017-02-27 13:07:15 -0800329 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800330 $crate::helper::separated_list($i, $sep, $f, false)
David Tolnay674258d2016-10-08 13:30:45 -0700331 };
David Tolnaydff18802017-02-27 11:57:03 -0800332
333 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
334 let mut res = ::std::vec::Vec::new();
335 let mut input = $i;
336
337 // get the first element
338 match $fmac!(input, $($fargs)*) {
339 $crate::IResult::Error => $crate::IResult::Done(input, res),
340 $crate::IResult::Done(i, o) => {
341 if i.len() == input.len() {
342 $crate::IResult::Error
343 } else {
344 res.push(o);
345 input = i;
346
347 // get the separator first
348 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
349 if i2.len() == input.len() {
350 break;
351 }
352
353 // get the element next
354 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
355 if i3.len() == i2.len() {
356 break;
357 }
358 res.push(o3);
359 input = i3;
360 } else {
361 break;
362 }
363 }
364 $crate::IResult::Done(input, res)
365 }
366 }
367 }
368 }};
369
370 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
371 separated_list!($i, $sepmac!($(separgs)*), call!($f))
372 };
373
374 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
375 separated_list!($i, call!($sep), $fmac!($(fargs)*))
376 };
377
378 ($i:expr, $sep:expr, $f:expr) => {
379 separated_list!($i, call!($sep), call!($f))
380 };
David Tolnay674258d2016-10-08 13:30:45 -0700381}
382
David Tolnay1f16b602017-02-07 20:06:55 -0500383/// Zero or more values separated by some separator. A trailing separator is
384/// allowed.
Michael Layzell24645a32017-02-04 13:19:26 -0500385///
Michael Layzell24645a32017-02-04 13:19:26 -0500386/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
387/// - **Output:** `Vec<THING>`
388///
David Tolnay1f16b602017-02-07 20:06:55 -0500389/// You may also be looking for:
390///
391/// - `separated_list!` - zero or more, allows trailing separator
392/// - `separated_nonempty_list!` - one or more values
393/// - `many0!` - zero or more, no separator
394///
Michael Layzell24645a32017-02-04 13:19:26 -0500395/// ```rust
396/// extern crate syn;
397/// #[macro_use] extern crate synom;
398///
399/// use syn::Expr;
400/// use syn::parse::expr;
401///
David Tolnay1f16b602017-02-07 20:06:55 -0500402/// named!(expr_list -> Vec<Expr>,
403/// terminated_list!(punct!(","), expr)
404/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500405///
406/// fn main() {
407/// let input = "1 + 1, things, Construct { this: thing },";
408///
David Tolnay1f16b602017-02-07 20:06:55 -0500409/// let parsed = expr_list(input).expect("expr list");
410/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500411/// }
412/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800413///
414/// ```rust
415/// extern crate syn;
416/// #[macro_use] extern crate synom;
417///
418/// use syn::Ident;
419/// use syn::parse::ident;
420///
421/// named!(run_on -> Vec<Ident>,
422/// terminated!(
423/// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
424/// punct!("...")
425/// )
426/// );
427///
428/// fn main() {
429/// let input = "$expr and $ident and $pat and ...";
430///
431/// let parsed = run_on(input).expect("run-on sentence");
432/// assert_eq!(parsed.len(), 3);
433/// assert_eq!(parsed[0], "expr");
434/// assert_eq!(parsed[1], "ident");
435/// assert_eq!(parsed[2], "pat");
436/// }
437/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500438#[macro_export]
David Tolnayff46fd22016-10-08 13:53:28 -0700439macro_rules! terminated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800440 // Try to use this branch if possible - makes a difference in compile time.
441 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800442 $crate::helper::separated_list($i, $sep, $f, true)
David Tolnayff46fd22016-10-08 13:53:28 -0700443 };
David Tolnaydff18802017-02-27 11:57:03 -0800444
445 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
446 let mut res = ::std::vec::Vec::new();
447 let mut input = $i;
448
449 // get the first element
450 match $fmac!(input, $($fargs)*) {
451 $crate::IResult::Error => $crate::IResult::Done(input, res),
452 $crate::IResult::Done(i, o) => {
453 if i.len() == input.len() {
454 $crate::IResult::Error
455 } else {
456 res.push(o);
457 input = i;
458
459 // get the separator first
460 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
461 if i2.len() == input.len() {
462 break;
463 }
464
465 // get the element next
466 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
467 if i3.len() == i2.len() {
468 break;
469 }
470 res.push(o3);
471 input = i3;
472 } else {
473 break;
474 }
475 }
476 if let $crate::IResult::Done(after, _) = $sepmac!(input, $($separgs)*) {
477 input = after;
478 }
479 $crate::IResult::Done(input, res)
480 }
481 }
482 }
483 }};
484
485 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
486 terminated_list!($i, $sepmac!($(separgs)*), call!($f))
487 };
488
489 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
490 terminated_list!($i, call!($sep), $fmac!($(fargs)*))
491 };
492
493 ($i:expr, $sep:expr, $f:expr) => {
494 terminated_list!($i, call!($sep), call!($f))
495 };
David Tolnayff46fd22016-10-08 13:53:28 -0700496}
497
David Tolnay5fe14fc2017-01-27 16:22:08 -0800498// Not public API.
499#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700500pub fn separated_list<'a, T>(mut input: &'a str,
501 sep: &'static str,
502 f: fn(&'a str) -> IResult<&'a str, T>,
503 terminated: bool)
504 -> IResult<&'a str, Vec<T>> {
David Tolnay674258d2016-10-08 13:30:45 -0700505 let mut res = Vec::new();
506
507 // get the first element
508 match f(input) {
David Tolnaydff18802017-02-27 11:57:03 -0800509 IResult::Error => IResult::Done(input, res),
David Tolnay674258d2016-10-08 13:30:45 -0700510 IResult::Done(i, o) => {
511 if i.len() == input.len() {
512 IResult::Error
513 } else {
514 res.push(o);
515 input = i;
516
517 // get the separator first
518 while let IResult::Done(i2, _) = punct(input, sep) {
519 if i2.len() == input.len() {
520 break;
521 }
522
523 // get the element next
524 if let IResult::Done(i3, o3) = f(i2) {
525 if i3.len() == i2.len() {
526 break;
527 }
528 res.push(o3);
529 input = i3;
530 } else {
531 break;
532 }
533 }
David Tolnayff46fd22016-10-08 13:53:28 -0700534 if terminated {
535 if let IResult::Done(after, _) = punct(input, sep) {
536 input = after;
537 }
538 }
David Tolnay674258d2016-10-08 13:30:45 -0700539 IResult::Done(input, res)
540 }
541 }
542 }
543}