blob: 5bae69b76bebb092858198451c1dcb73d075683c [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///
Alex Crichton62a0a592017-05-22 13:58:53 -0700230/// use syn::{Expr, ExprCall};
Michael Layzell24645a32017-02-04 13:19:26 -0500231/// 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 {
Alex Crichton62a0a592017-05-22 13:58:53 -0700237/// node: ExprCall {
238/// func: Box::new(e),
239/// args: vec![arg.1],
240/// }.into(),
Michael Layzell24645a32017-02-04 13:19:26 -0500241/// attrs: Vec::new(),
242/// };
243/// })) >>
244/// (e)
245/// ));
246///
247/// fn main() {
248/// let input = "something => argument1 => argument2";
249///
David Tolnay1f16b602017-02-07 20:06:55 -0500250/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500251///
David Tolnay1f16b602017-02-07 20:06:55 -0500252/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500253/// }
254/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500255#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500256#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700257macro_rules! tap {
258 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
259 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500260 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700261 let $name = o;
262 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500263 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700264 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500265 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700266 }
267 };
268
269 ($i:expr, $name:ident : $f:expr => $e:expr) => {
270 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700271 };
272}
David Tolnay674258d2016-10-08 13:30:45 -0700273
David Tolnay1f16b602017-02-07 20:06:55 -0500274/// Zero or more values separated by some separator. Does not allow a trailing
275/// seperator.
Michael Layzell24645a32017-02-04 13:19:26 -0500276///
Michael Layzell24645a32017-02-04 13:19:26 -0500277/// - **Syntax:** `separated_list!(punct!("..."), THING)`
278/// - **Output:** `Vec<THING>`
279///
David Tolnay1f16b602017-02-07 20:06:55 -0500280/// You may also be looking for:
281///
282/// - `separated_nonempty_list!` - one or more values
283/// - `terminated_list!` - zero or more, allows trailing separator
284/// - `many0!` - zero or more, no separator
285///
Michael Layzell24645a32017-02-04 13:19:26 -0500286/// ```rust
287/// extern crate syn;
288/// #[macro_use] extern crate synom;
289///
290/// use syn::Expr;
291/// use syn::parse::expr;
292///
David Tolnay1f16b602017-02-07 20:06:55 -0500293/// named!(expr_list -> Vec<Expr>,
294/// separated_list!(punct!(","), expr)
295/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500296///
297/// fn main() {
298/// let input = "1 + 1, things, Construct { this: thing }";
299///
David Tolnay1f16b602017-02-07 20:06:55 -0500300/// let parsed = expr_list(input).expect("expr list");
301/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500302/// }
303/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800304///
305/// ```rust
306/// extern crate syn;
307/// #[macro_use] extern crate synom;
308///
309/// use syn::Ident;
310/// use syn::parse::ident;
311///
312/// named!(run_on -> Vec<Ident>,
313/// terminated!(
314/// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
315/// punct!("...")
316/// )
317/// );
318///
319/// fn main() {
320/// let input = "$expr and $ident and $pat ...";
321///
322/// let parsed = run_on(input).expect("run-on sentence");
323/// assert_eq!(parsed.len(), 3);
324/// assert_eq!(parsed[0], "expr");
325/// assert_eq!(parsed[1], "ident");
326/// assert_eq!(parsed[2], "pat");
327/// }
328/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500329#[macro_export]
David Tolnay674258d2016-10-08 13:30:45 -0700330macro_rules! separated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800331 // Try to use this branch if possible - makes a difference in compile time.
David Tolnay0882b9c2017-02-27 13:07:15 -0800332 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800333 $crate::helper::separated_list($i, $sep, $f, false)
David Tolnay674258d2016-10-08 13:30:45 -0700334 };
David Tolnaydff18802017-02-27 11:57:03 -0800335
336 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
337 let mut res = ::std::vec::Vec::new();
338 let mut input = $i;
339
340 // get the first element
341 match $fmac!(input, $($fargs)*) {
342 $crate::IResult::Error => $crate::IResult::Done(input, res),
343 $crate::IResult::Done(i, o) => {
344 if i.len() == input.len() {
345 $crate::IResult::Error
346 } else {
347 res.push(o);
348 input = i;
349
350 // get the separator first
351 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
352 if i2.len() == input.len() {
353 break;
354 }
355
356 // get the element next
357 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
358 if i3.len() == i2.len() {
359 break;
360 }
361 res.push(o3);
362 input = i3;
363 } else {
364 break;
365 }
366 }
367 $crate::IResult::Done(input, res)
368 }
369 }
370 }
371 }};
372
373 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
Christopher Bacher9620ae02017-03-02 00:44:25 +0100374 separated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800375 };
376
377 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800378 separated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800379 };
380
381 ($i:expr, $sep:expr, $f:expr) => {
382 separated_list!($i, call!($sep), call!($f))
383 };
David Tolnay674258d2016-10-08 13:30:45 -0700384}
385
David Tolnay1f16b602017-02-07 20:06:55 -0500386/// Zero or more values separated by some separator. A trailing separator is
387/// allowed.
Michael Layzell24645a32017-02-04 13:19:26 -0500388///
Michael Layzell24645a32017-02-04 13:19:26 -0500389/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
390/// - **Output:** `Vec<THING>`
391///
David Tolnay1f16b602017-02-07 20:06:55 -0500392/// You may also be looking for:
393///
394/// - `separated_list!` - zero or more, allows trailing separator
395/// - `separated_nonempty_list!` - one or more values
396/// - `many0!` - zero or more, no separator
397///
Michael Layzell24645a32017-02-04 13:19:26 -0500398/// ```rust
399/// extern crate syn;
400/// #[macro_use] extern crate synom;
401///
402/// use syn::Expr;
403/// use syn::parse::expr;
404///
David Tolnay1f16b602017-02-07 20:06:55 -0500405/// named!(expr_list -> Vec<Expr>,
406/// terminated_list!(punct!(","), expr)
407/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500408///
409/// fn main() {
410/// let input = "1 + 1, things, Construct { this: thing },";
411///
David Tolnay1f16b602017-02-07 20:06:55 -0500412/// let parsed = expr_list(input).expect("expr list");
413/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500414/// }
415/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800416///
417/// ```rust
418/// extern crate syn;
419/// #[macro_use] extern crate synom;
420///
421/// use syn::Ident;
422/// use syn::parse::ident;
423///
424/// named!(run_on -> Vec<Ident>,
425/// terminated!(
426/// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
427/// punct!("...")
428/// )
429/// );
430///
431/// fn main() {
432/// let input = "$expr and $ident and $pat and ...";
433///
434/// let parsed = run_on(input).expect("run-on sentence");
435/// assert_eq!(parsed.len(), 3);
436/// assert_eq!(parsed[0], "expr");
437/// assert_eq!(parsed[1], "ident");
438/// assert_eq!(parsed[2], "pat");
439/// }
440/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500441#[macro_export]
David Tolnayff46fd22016-10-08 13:53:28 -0700442macro_rules! terminated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800443 // Try to use this branch if possible - makes a difference in compile time.
444 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800445 $crate::helper::separated_list($i, $sep, $f, true)
David Tolnayff46fd22016-10-08 13:53:28 -0700446 };
David Tolnaydff18802017-02-27 11:57:03 -0800447
448 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
449 let mut res = ::std::vec::Vec::new();
450 let mut input = $i;
451
452 // get the first element
453 match $fmac!(input, $($fargs)*) {
454 $crate::IResult::Error => $crate::IResult::Done(input, res),
455 $crate::IResult::Done(i, o) => {
456 if i.len() == input.len() {
457 $crate::IResult::Error
458 } else {
459 res.push(o);
460 input = i;
461
462 // get the separator first
463 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
464 if i2.len() == input.len() {
465 break;
466 }
467
468 // get the element next
469 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
470 if i3.len() == i2.len() {
471 break;
472 }
473 res.push(o3);
474 input = i3;
475 } else {
476 break;
477 }
478 }
479 if let $crate::IResult::Done(after, _) = $sepmac!(input, $($separgs)*) {
480 input = after;
481 }
482 $crate::IResult::Done(input, res)
483 }
484 }
485 }
486 }};
487
488 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800489 terminated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800490 };
491
492 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800493 terminated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800494 };
495
496 ($i:expr, $sep:expr, $f:expr) => {
497 terminated_list!($i, call!($sep), call!($f))
498 };
David Tolnayff46fd22016-10-08 13:53:28 -0700499}
500
David Tolnay5fe14fc2017-01-27 16:22:08 -0800501// Not public API.
502#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700503pub fn separated_list<'a, T>(mut input: &'a str,
504 sep: &'static str,
505 f: fn(&'a str) -> IResult<&'a str, T>,
506 terminated: bool)
507 -> IResult<&'a str, Vec<T>> {
David Tolnay674258d2016-10-08 13:30:45 -0700508 let mut res = Vec::new();
509
510 // get the first element
511 match f(input) {
David Tolnaydff18802017-02-27 11:57:03 -0800512 IResult::Error => IResult::Done(input, res),
David Tolnay674258d2016-10-08 13:30:45 -0700513 IResult::Done(i, o) => {
514 if i.len() == input.len() {
515 IResult::Error
516 } else {
517 res.push(o);
518 input = i;
519
520 // get the separator first
521 while let IResult::Done(i2, _) = punct(input, sep) {
522 if i2.len() == input.len() {
523 break;
524 }
525
526 // get the element next
527 if let IResult::Done(i3, o3) = f(i2) {
528 if i3.len() == i2.len() {
529 break;
530 }
531 res.push(o3);
532 input = i3;
533 } else {
534 break;
535 }
536 }
David Tolnayff46fd22016-10-08 13:53:28 -0700537 if terminated {
538 if let IResult::Done(after, _) = punct(input, sep) {
539 input = after;
540 }
541 }
David Tolnay674258d2016-10-08 13:30:45 -0700542 IResult::Done(input, res)
543 }
544 }
545 }
546}