blob: 9c69a2a0f0513f14a7cd281a389a7975623f6a7e [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)]
Michael Layzell416724e2017-05-24 21:12:34 -040037pub fn punct<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'a str> {
38 // Extract the chars from token, so we know how many tokens to expect, check
39 // if we are running past EOF, then confirm that the tokens exist as
40 // requested.
41 let expected = token.chars().collect::<Vec<_>>();
42 if input.len() < expected.len() {
43 return IResult::Error;
David Tolnay13e5da42016-09-04 16:18:34 -070044 }
Michael Layzell416724e2017-05-24 21:12:34 -040045 for i in 0..expected.len() {
46 if let TokenKind::Op(c, ok) = input[i].kind {
47 if c != expected[i] {
48 return IResult::Error;
49 }
50
51 // The last token in the sequence does not have to be marked as
52 // OpKind::Joint. Unfortunately OpKind doesn't implement
53 // Eq/PartialEq right now.
54 match ok {
55 OpKind::Alone if i != expected.len() - 1 => return IResult::Error,
56 _ => {}
57 }
58 } else {
59 return IResult::Error;
60 }
61 }
62
63 IResult::Done(&input[expected.len()..], token)
David Tolnay13e5da42016-09-04 16:18:34 -070064}
65
David Tolnay1f16b602017-02-07 20:06:55 -050066/// Parse a keyword like "fn" or "struct".
67///
68/// See also `punct!` for parsing punctuation, which are subtly different from
69/// keywords.
Michael Layzell24645a32017-02-04 13:19:26 -050070///
71/// - **Syntax:** `keyword!("...")`
72/// - **Output:** `&str`
73///
74/// ```rust
75/// extern crate syn;
76/// #[macro_use] extern crate synom;
77///
David Tolnay1f16b602017-02-07 20:06:55 -050078/// use synom::IResult;
79///
80/// // Parse zero or more "bang" keywords.
81/// named!(many_bangs -> Vec<&str>,
82/// terminated!(
83/// many0!(keyword!("bang")),
84/// punct!(";")
85/// )
86/// );
Michael Layzell24645a32017-02-04 13:19:26 -050087///
88/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050089/// let input = "bang bang bang;";
90/// let parsed = many_bangs(input).expect("bangs");
91/// assert_eq!(parsed, ["bang", "bang", "bang"]);
92///
93/// let input = "bangbang;";
94/// let err = many_bangs(input);
95/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -050096/// }
97/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050098#[macro_export]
David Tolnay10413f02016-09-30 09:12:02 -070099macro_rules! keyword {
100 ($i:expr, $keyword:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800101 $crate::helper::keyword($i, $keyword)
David Tolnay10413f02016-09-30 09:12:02 -0700102 };
103}
104
David Tolnay5fe14fc2017-01-27 16:22:08 -0800105// Not public API.
106#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400107pub fn keyword<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'static str> {
108 match input.first() {
109 Some(&TokenTree{ kind: TokenKind::Word(ref symbol), .. }) if &**symbol == token =>
110 IResult::Done(&input[1..], token),
111 _ => IResult::Error,
David Tolnay10413f02016-09-30 09:12:02 -0700112 }
113}
114
David Tolnay1f16b602017-02-07 20:06:55 -0500115/// Turn a failed parse into `None` and a successful parse into `Some`.
Michael Layzell24645a32017-02-04 13:19:26 -0500116///
117/// - **Syntax:** `option!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500118/// - **Output:** `Option<THING>`
Michael Layzell24645a32017-02-04 13:19:26 -0500119///
120/// ```rust
121/// extern crate syn;
122/// #[macro_use] extern crate synom;
123///
124/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
125///
126/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500127/// let input = "!";
128/// let parsed = maybe_bang(input).expect("maybe bang");
129/// assert_eq!(parsed, Some("!"));
130///
Michael Layzell24645a32017-02-04 13:19:26 -0500131/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500132/// let parsed = maybe_bang(input).expect("maybe bang");
133/// assert_eq!(parsed, None);
Michael Layzell24645a32017-02-04 13:19:26 -0500134/// }
135/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500136#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700137macro_rules! option {
138 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -0700139 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500140 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
141 $crate::IResult::Error => $crate::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -0700142 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700143 };
David Tolnayf6ccb832016-09-04 15:00:56 -0700144
David Tolnayb5a7b142016-09-13 22:46:39 -0700145 ($i:expr, $f:expr) => {
146 option!($i, call!($f));
147 };
148}
149
David Tolnay1f16b602017-02-07 20:06:55 -0500150/// Turn a failed parse into an empty vector. The argument parser must itself
151/// return a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500152///
David Tolnay1f16b602017-02-07 20:06:55 -0500153/// This is often more convenient than `option!(...)` when the argument produces
154/// a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500155///
156/// - **Syntax:** `opt_vec!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500157/// - **Output:** `THING`, which must be `Vec<T>`
Michael Layzell24645a32017-02-04 13:19:26 -0500158///
159/// ```rust
160/// extern crate syn;
161/// #[macro_use] extern crate synom;
162///
David Tolnay1f16b602017-02-07 20:06:55 -0500163/// use syn::{Lifetime, Ty};
164/// use syn::parse::{lifetime, ty};
Michael Layzell24645a32017-02-04 13:19:26 -0500165///
David Tolnay1f16b602017-02-07 20:06:55 -0500166/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
167/// opt_vec!(do_parse!(
168/// keyword!("for") >>
169/// punct!("<") >>
170/// lifetimes: terminated_list!(punct!(","), lifetime) >>
171/// punct!(">") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700172/// (lifetimes.into_vec())
David Tolnay1f16b602017-02-07 20:06:55 -0500173/// )),
174/// ty
175/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500176///
177/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500178/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
179/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
180/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
181/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500182///
David Tolnay1f16b602017-02-07 20:06:55 -0500183/// let input = "From<String>";
184/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
185/// assert!(parsed.0.is_empty());
186/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500187/// }
188/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500189#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700190macro_rules! opt_vec {
191 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -0700192 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500193 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
194 $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -0700195 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700196 };
197}
David Tolnayb79ee962016-09-04 09:39:20 -0700198
Michael Layzell24645a32017-02-04 13:19:26 -0500199/// Parses nothing and always succeeds.
200///
David Tolnay1f16b602017-02-07 20:06:55 -0500201/// This can be useful as a fallthrough case in `alt!`.
202///
Michael Layzell24645a32017-02-04 13:19:26 -0500203/// - **Syntax:** `epsilon!()`
204/// - **Output:** `()`
205///
206/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500207/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500208/// #[macro_use] extern crate synom;
209///
David Tolnay1f16b602017-02-07 20:06:55 -0500210/// use syn::Mutability;
211///
212/// named!(mutability -> Mutability, alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700213/// keyword!("mut") => { |_| Mutability::Mutable(Default::default()) }
David Tolnay1f16b602017-02-07 20:06:55 -0500214/// |
215/// epsilon!() => { |_| Mutability::Immutable }
216/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500217///
218/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500219/// let input = "mut";
220/// let parsed = mutability(input).expect("mutability");
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700221/// assert_eq!(parsed, Mutability::Mutable(Default::default()));
David Tolnay1f16b602017-02-07 20:06:55 -0500222///
Michael Layzell24645a32017-02-04 13:19:26 -0500223/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500224/// let parsed = mutability(input).expect("mutability");
225/// assert_eq!(parsed, Mutability::Immutable);
Michael Layzell24645a32017-02-04 13:19:26 -0500226/// }
227/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500228#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -0700229macro_rules! epsilon {
230 ($i:expr,) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500231 $crate::IResult::Done($i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700232 };
233}
234
Michael Layzell24645a32017-02-04 13:19:26 -0500235/// Run a parser, binding the result to a name, and then evaluating an
236/// expression.
237///
238/// Discards the result of the expression and parser.
239///
240/// - **Syntax:** `tap!(NAME : THING => EXPR)`
241/// - **Output:** `()`
242///
243/// ```rust
244/// extern crate syn;
245/// #[macro_use] extern crate synom;
246///
Alex Crichton62a0a592017-05-22 13:58:53 -0700247/// use syn::{Expr, ExprCall};
Michael Layzell24645a32017-02-04 13:19:26 -0500248/// use syn::parse::expr;
249///
David Tolnay1f16b602017-02-07 20:06:55 -0500250/// named!(expr_with_arrow_call -> Expr, do_parse!(
Michael Layzell24645a32017-02-04 13:19:26 -0500251/// mut e: expr >>
252/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
253/// e = Expr {
Alex Crichton62a0a592017-05-22 13:58:53 -0700254/// node: ExprCall {
255/// func: Box::new(e),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700256/// args: vec![arg.1].into(),
257/// paren_token: Default::default(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700258/// }.into(),
Michael Layzell24645a32017-02-04 13:19:26 -0500259/// attrs: Vec::new(),
260/// };
261/// })) >>
262/// (e)
263/// ));
264///
265/// fn main() {
266/// let input = "something => argument1 => argument2";
267///
David Tolnay1f16b602017-02-07 20:06:55 -0500268/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500269///
David Tolnay1f16b602017-02-07 20:06:55 -0500270/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500271/// }
272/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500273#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500274#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700275macro_rules! tap {
276 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
277 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500278 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700279 let $name = o;
280 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500281 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700282 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500283 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700284 }
285 };
286
287 ($i:expr, $name:ident : $f:expr => $e:expr) => {
288 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700289 };
290}
David Tolnay674258d2016-10-08 13:30:45 -0700291
David Tolnay1f16b602017-02-07 20:06:55 -0500292/// Zero or more values separated by some separator. Does not allow a trailing
293/// seperator.
Michael Layzell24645a32017-02-04 13:19:26 -0500294///
Michael Layzell24645a32017-02-04 13:19:26 -0500295/// - **Syntax:** `separated_list!(punct!("..."), THING)`
296/// - **Output:** `Vec<THING>`
297///
David Tolnay1f16b602017-02-07 20:06:55 -0500298/// You may also be looking for:
299///
300/// - `separated_nonempty_list!` - one or more values
301/// - `terminated_list!` - zero or more, allows trailing separator
302/// - `many0!` - zero or more, no separator
303///
Michael Layzell24645a32017-02-04 13:19:26 -0500304/// ```rust
305/// extern crate syn;
306/// #[macro_use] extern crate synom;
307///
308/// use syn::Expr;
309/// use syn::parse::expr;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700310/// use synom::delimited::Delimited;
Michael Layzell24645a32017-02-04 13:19:26 -0500311///
David Tolnay1f16b602017-02-07 20:06:55 -0500312/// named!(expr_list -> Vec<Expr>,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700313/// map!(separated_list!(punct!(","), expr),
314/// |v: Delimited<_, _>| v.into_vec())
David Tolnay1f16b602017-02-07 20:06:55 -0500315/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500316///
317/// fn main() {
318/// let input = "1 + 1, things, Construct { this: thing }";
319///
David Tolnay1f16b602017-02-07 20:06:55 -0500320/// let parsed = expr_list(input).expect("expr list");
321/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500322/// }
323/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800324///
325/// ```rust
326/// extern crate syn;
327/// #[macro_use] extern crate synom;
328///
329/// use syn::Ident;
330/// use syn::parse::ident;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700331/// use synom::delimited::Delimited;
David Tolnaydff18802017-02-27 11:57:03 -0800332///
333/// named!(run_on -> Vec<Ident>,
334/// terminated!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700335/// map!(
336/// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
337/// |v: Delimited<_, _>| v.into_vec()
338/// ),
David Tolnaydff18802017-02-27 11:57:03 -0800339/// punct!("...")
340/// )
341/// );
342///
343/// fn main() {
344/// let input = "$expr and $ident and $pat ...";
345///
346/// let parsed = run_on(input).expect("run-on sentence");
347/// assert_eq!(parsed.len(), 3);
348/// assert_eq!(parsed[0], "expr");
349/// assert_eq!(parsed[1], "ident");
350/// assert_eq!(parsed[2], "pat");
351/// }
352/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500353#[macro_export]
David Tolnay674258d2016-10-08 13:30:45 -0700354macro_rules! separated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800355 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700356 $crate::helper::separated_list($i,
357 |d| $sepmac!(d, $($separgs)*),
358 |d| $fmac!(d, $($fargs)*),
359 false)
David Tolnaydff18802017-02-27 11:57:03 -0800360 }};
361
362 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
Christopher Bacher9620ae02017-03-02 00:44:25 +0100363 separated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800364 };
365
366 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800367 separated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800368 };
369
370 ($i:expr, $sep:expr, $f:expr) => {
371 separated_list!($i, call!($sep), call!($f))
372 };
David Tolnay674258d2016-10-08 13:30:45 -0700373}
374
David Tolnay1f16b602017-02-07 20:06:55 -0500375/// Zero or more values separated by some separator. A trailing separator is
376/// allowed.
Michael Layzell24645a32017-02-04 13:19:26 -0500377///
Michael Layzell24645a32017-02-04 13:19:26 -0500378/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
379/// - **Output:** `Vec<THING>`
380///
David Tolnay1f16b602017-02-07 20:06:55 -0500381/// You may also be looking for:
382///
383/// - `separated_list!` - zero or more, allows trailing separator
384/// - `separated_nonempty_list!` - one or more values
385/// - `many0!` - zero or more, no separator
386///
Michael Layzell24645a32017-02-04 13:19:26 -0500387/// ```rust
388/// extern crate syn;
389/// #[macro_use] extern crate synom;
390///
391/// use syn::Expr;
392/// use syn::parse::expr;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700393/// use synom::delimited::Delimited;
Michael Layzell24645a32017-02-04 13:19:26 -0500394///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700395/// named!(expr_list -> Delimited<Expr, &str>,
David Tolnay1f16b602017-02-07 20:06:55 -0500396/// terminated_list!(punct!(","), expr)
397/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500398///
399/// fn main() {
400/// let input = "1 + 1, things, Construct { this: thing },";
401///
David Tolnay1f16b602017-02-07 20:06:55 -0500402/// let parsed = expr_list(input).expect("expr list");
403/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500404/// }
405/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800406///
407/// ```rust
408/// extern crate syn;
409/// #[macro_use] extern crate synom;
410///
411/// use syn::Ident;
412/// use syn::parse::ident;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700413/// use synom::delimited::Delimited;
David Tolnaydff18802017-02-27 11:57:03 -0800414///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700415/// named!(run_on -> Delimited<Ident, &str>,
David Tolnaydff18802017-02-27 11:57:03 -0800416/// terminated!(
417/// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
418/// punct!("...")
419/// )
420/// );
421///
422/// fn main() {
423/// let input = "$expr and $ident and $pat and ...";
424///
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700425/// let parsed = run_on(input).expect("run-on sentence").into_vec();
David Tolnaydff18802017-02-27 11:57:03 -0800426/// assert_eq!(parsed.len(), 3);
427/// assert_eq!(parsed[0], "expr");
428/// assert_eq!(parsed[1], "ident");
429/// assert_eq!(parsed[2], "pat");
430/// }
431/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500432#[macro_export]
David Tolnayff46fd22016-10-08 13:53:28 -0700433macro_rules! terminated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800434 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700435 $crate::helper::separated_list($i,
436 |d| $sepmac!(d, $($separgs)*),
437 |d| $fmac!(d, $($fargs)*),
438 true)
David Tolnaydff18802017-02-27 11:57:03 -0800439 }};
440
441 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800442 terminated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800443 };
444
445 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800446 terminated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800447 };
448
449 ($i:expr, $sep:expr, $f:expr) => {
450 terminated_list!($i, call!($sep), call!($f))
451 };
David Tolnayff46fd22016-10-08 13:53:28 -0700452}
453
David Tolnay5fe14fc2017-01-27 16:22:08 -0800454// Not public API.
455#[doc(hidden)]
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700456pub fn separated_list<'a, F1, D, F2, T>(mut input: &'a str,
457 mut sep: F1,
458 mut parse: F2,
459 terminated: bool)
460 -> IResult<&'a str, Delimited<T, D>>
461 where F1: FnMut(&'a str) -> IResult<&'a str, D>,
462 F2: FnMut(&'a str) -> IResult<&'a str, T>,
463{
464 let mut res = Delimited::new();
David Tolnay674258d2016-10-08 13:30:45 -0700465
466 // get the first element
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700467 match parse(input) {
David Tolnaydff18802017-02-27 11:57:03 -0800468 IResult::Error => IResult::Done(input, res),
David Tolnay674258d2016-10-08 13:30:45 -0700469 IResult::Done(i, o) => {
470 if i.len() == input.len() {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700471 return IResult::Error
David Tolnay674258d2016-10-08 13:30:45 -0700472 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700473 input = i;
474 res.push_first(o);
475
476 // get the separator first
477 while let IResult::Done(i2, s) = sep(input) {
478 if i2.len() == input.len() {
479 break;
480 }
481
482 // get the element next
483 if let IResult::Done(i3, o3) = parse(i2) {
484 if i3.len() == i2.len() {
485 break;
486 }
487 res.push_next(o3, s);
488 input = i3;
489 } else {
490 break;
491 }
492 }
493 if terminated {
494 if let IResult::Done(after, sep) = sep(input) {
495 res.push_trailing(sep);
496 input = after;
497 }
498 }
499 IResult::Done(input, res)
David Tolnay674258d2016-10-08 13:30:45 -0700500 }
501 }
502}
Michael Layzell416724e2017-05-24 21:12:34 -0400503
504#[macro_export]
505macro_rules! delim {
506 ($i:expr, $delim:ident, $fmac:ident!( $($fargs:tt)* )) => {
507 match $crate::helper::delim_impl($i, $crate::Delimiter::$delim) {
508 Some((i, ib)) => {
509 match $fmac!(&*ib, $($fargs)*) {
510 $crate::IResult::Done(rest, val) => {
511 if rest.is_empty() {
512 $crate::IResult::Done(i, val)
513 } else {
514 $crate::IResult::Error
515 }
516 }
517 _ => $crate::IResult::Error,
518 }
519 }
520 _ => $crate::IResult::Error,
521 }
522 };
523 ($i:expr, $delim:ident, $f:expr) => {
524 delim!($i, $delim, call!($f))
525 };
526}
527
528// Not a public API
529#[doc(hidden)]
530pub fn delim_impl(input: &[TokenTree],
531 expected_delim: Delimiter)
532 -> Option<(&[TokenTree], InputBuf)> {
533 // NOTE: The `as u32` hack is being used as `Delimiter` doesn't implement
534 // `PartialEq` or `Eq` despite being a simple c-style enum.
535 match input.first() {
536 Some(&TokenTree {
537 kind: TokenKind::Sequence(delim, ref stream),
538 ..
539 }) if delim as u32 == expected_delim as u32 => {
540 Some((&input[1..], InputBuf::new(stream.clone())))
541 }
542 _ => None
543 }
544}