blob: 800874a37102b85c9bb43cff873eefe3a05d71c4 [file] [log] [blame]
Michael Layzell416724e2017-05-24 21:12:34 -04001use {IResult, TokenTree, TokenKind, OpKind, Delimiter, InputBuf};
David Tolnayb79ee962016-09-04 09:39:20 -07002
David Tolnay1f16b602017-02-07 20:06:55 -05003/// Parse a piece of punctuation like "+" or "+=".
4///
5/// See also `keyword!` for parsing keywords, which are subtly different from
6/// punctuation.
Michael Layzell24645a32017-02-04 13:19:26 -05007///
8/// - **Syntax:** `punct!("...")`
9/// - **Output:** `&str`
10///
11/// ```rust
12/// extern crate syn;
13/// #[macro_use] extern crate synom;
14///
David Tolnay1f16b602017-02-07 20:06:55 -050015/// // Parse zero or more bangs.
16/// named!(many_bangs -> Vec<&str>,
17/// many0!(punct!("!"))
18/// );
Michael Layzell24645a32017-02-04 13:19:26 -050019///
20/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050021/// let input = "!! !";
22/// let parsed = many_bangs(input).expect("bangs");
23/// assert_eq!(parsed, ["!", "!", "!"]);
Michael Layzell24645a32017-02-04 13:19:26 -050024/// }
25/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050026#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -070027macro_rules! punct {
28 ($i:expr, $punct:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080029 $crate::helper::punct($i, $punct)
David Tolnayb79ee962016-09-04 09:39:20 -070030 };
31}
32
David Tolnay5fe14fc2017-01-27 16:22:08 -080033// Not public API.
34#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -040035pub fn punct<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'a str> {
36 // Extract the chars from token, so we know how many tokens to expect, check
37 // if we are running past EOF, then confirm that the tokens exist as
38 // requested.
39 let expected = token.chars().collect::<Vec<_>>();
40 if input.len() < expected.len() {
41 return IResult::Error;
David Tolnay13e5da42016-09-04 16:18:34 -070042 }
Michael Layzell416724e2017-05-24 21:12:34 -040043 for i in 0..expected.len() {
44 if let TokenKind::Op(c, ok) = input[i].kind {
45 if c != expected[i] {
46 return IResult::Error;
47 }
48
49 // The last token in the sequence does not have to be marked as
50 // OpKind::Joint. Unfortunately OpKind doesn't implement
51 // Eq/PartialEq right now.
52 match ok {
53 OpKind::Alone if i != expected.len() - 1 => return IResult::Error,
54 _ => {}
55 }
56 } else {
57 return IResult::Error;
58 }
59 }
60
61 IResult::Done(&input[expected.len()..], token)
David Tolnay13e5da42016-09-04 16:18:34 -070062}
63
David Tolnay1f16b602017-02-07 20:06:55 -050064/// Parse a keyword like "fn" or "struct".
65///
66/// See also `punct!` for parsing punctuation, which are subtly different from
67/// keywords.
Michael Layzell24645a32017-02-04 13:19:26 -050068///
69/// - **Syntax:** `keyword!("...")`
70/// - **Output:** `&str`
71///
72/// ```rust
73/// extern crate syn;
74/// #[macro_use] extern crate synom;
75///
David Tolnay1f16b602017-02-07 20:06:55 -050076/// use synom::IResult;
77///
78/// // Parse zero or more "bang" keywords.
79/// named!(many_bangs -> Vec<&str>,
80/// terminated!(
81/// many0!(keyword!("bang")),
82/// punct!(";")
83/// )
84/// );
Michael Layzell24645a32017-02-04 13:19:26 -050085///
86/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050087/// let input = "bang bang bang;";
88/// let parsed = many_bangs(input).expect("bangs");
89/// assert_eq!(parsed, ["bang", "bang", "bang"]);
90///
91/// let input = "bangbang;";
92/// let err = many_bangs(input);
93/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -050094/// }
95/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050096#[macro_export]
David Tolnay10413f02016-09-30 09:12:02 -070097macro_rules! keyword {
98 ($i:expr, $keyword:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080099 $crate::helper::keyword($i, $keyword)
David Tolnay10413f02016-09-30 09:12:02 -0700100 };
101}
102
David Tolnay5fe14fc2017-01-27 16:22:08 -0800103// Not public API.
104#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400105pub fn keyword<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], &'static str> {
106 match input.first() {
107 Some(&TokenTree{ kind: TokenKind::Word(ref symbol), .. }) if &**symbol == token =>
108 IResult::Done(&input[1..], token),
109 _ => IResult::Error,
David Tolnay10413f02016-09-30 09:12:02 -0700110 }
111}
112
David Tolnay1f16b602017-02-07 20:06:55 -0500113/// Turn a failed parse into `None` and a successful parse into `Some`.
Michael Layzell24645a32017-02-04 13:19:26 -0500114///
115/// - **Syntax:** `option!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500116/// - **Output:** `Option<THING>`
Michael Layzell24645a32017-02-04 13:19:26 -0500117///
118/// ```rust
119/// extern crate syn;
120/// #[macro_use] extern crate synom;
121///
122/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
123///
124/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500125/// let input = "!";
126/// let parsed = maybe_bang(input).expect("maybe bang");
127/// assert_eq!(parsed, Some("!"));
128///
Michael Layzell24645a32017-02-04 13:19:26 -0500129/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500130/// let parsed = maybe_bang(input).expect("maybe bang");
131/// assert_eq!(parsed, None);
Michael Layzell24645a32017-02-04 13:19:26 -0500132/// }
133/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500134#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700135macro_rules! option {
136 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -0700137 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500138 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
139 $crate::IResult::Error => $crate::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -0700140 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700141 };
David Tolnayf6ccb832016-09-04 15:00:56 -0700142
David Tolnayb5a7b142016-09-13 22:46:39 -0700143 ($i:expr, $f:expr) => {
144 option!($i, call!($f));
145 };
146}
147
David Tolnay1f16b602017-02-07 20:06:55 -0500148/// Turn a failed parse into an empty vector. The argument parser must itself
149/// return a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500150///
David Tolnay1f16b602017-02-07 20:06:55 -0500151/// This is often more convenient than `option!(...)` when the argument produces
152/// a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500153///
154/// - **Syntax:** `opt_vec!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500155/// - **Output:** `THING`, which must be `Vec<T>`
Michael Layzell24645a32017-02-04 13:19:26 -0500156///
157/// ```rust
158/// extern crate syn;
159/// #[macro_use] extern crate synom;
160///
David Tolnay1f16b602017-02-07 20:06:55 -0500161/// use syn::{Lifetime, Ty};
162/// use syn::parse::{lifetime, ty};
Michael Layzell24645a32017-02-04 13:19:26 -0500163///
David Tolnay1f16b602017-02-07 20:06:55 -0500164/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
165/// opt_vec!(do_parse!(
166/// keyword!("for") >>
167/// punct!("<") >>
168/// lifetimes: terminated_list!(punct!(","), lifetime) >>
169/// punct!(">") >>
170/// (lifetimes)
171/// )),
172/// ty
173/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500174///
175/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500176/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
177/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
178/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
179/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500180///
David Tolnay1f16b602017-02-07 20:06:55 -0500181/// let input = "From<String>";
182/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
183/// assert!(parsed.0.is_empty());
184/// println!("{:?}", parsed);
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! opt_vec {
189 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -0700190 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500191 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
192 $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -0700193 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700194 };
195}
David Tolnayb79ee962016-09-04 09:39:20 -0700196
Michael Layzell24645a32017-02-04 13:19:26 -0500197/// Parses nothing and always succeeds.
198///
David Tolnay1f16b602017-02-07 20:06:55 -0500199/// This can be useful as a fallthrough case in `alt!`.
200///
Michael Layzell24645a32017-02-04 13:19:26 -0500201/// - **Syntax:** `epsilon!()`
202/// - **Output:** `()`
203///
204/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500205/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500206/// #[macro_use] extern crate synom;
207///
David Tolnay1f16b602017-02-07 20:06:55 -0500208/// use syn::Mutability;
209///
210/// named!(mutability -> Mutability, alt!(
211/// keyword!("mut") => { |_| Mutability::Mutable }
212/// |
213/// epsilon!() => { |_| Mutability::Immutable }
214/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500215///
216/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500217/// let input = "mut";
218/// let parsed = mutability(input).expect("mutability");
219/// assert_eq!(parsed, Mutability::Mutable);
220///
Michael Layzell24645a32017-02-04 13:19:26 -0500221/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500222/// let parsed = mutability(input).expect("mutability");
223/// assert_eq!(parsed, Mutability::Immutable);
Michael Layzell24645a32017-02-04 13:19:26 -0500224/// }
225/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500226#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -0700227macro_rules! epsilon {
228 ($i:expr,) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500229 $crate::IResult::Done($i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700230 };
231}
232
Michael Layzell24645a32017-02-04 13:19:26 -0500233/// Run a parser, binding the result to a name, and then evaluating an
234/// expression.
235///
236/// Discards the result of the expression and parser.
237///
238/// - **Syntax:** `tap!(NAME : THING => EXPR)`
239/// - **Output:** `()`
240///
241/// ```rust
242/// extern crate syn;
243/// #[macro_use] extern crate synom;
244///
245/// use syn::{Expr, ExprKind};
246/// use syn::parse::expr;
247///
David Tolnay1f16b602017-02-07 20:06:55 -0500248/// named!(expr_with_arrow_call -> Expr, do_parse!(
Michael Layzell24645a32017-02-04 13:19:26 -0500249/// mut e: expr >>
250/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
251/// e = Expr {
252/// node: ExprKind::Call(Box::new(e), vec![arg.1]),
253/// attrs: Vec::new(),
254/// };
255/// })) >>
256/// (e)
257/// ));
258///
259/// fn main() {
260/// let input = "something => argument1 => argument2";
261///
David Tolnay1f16b602017-02-07 20:06:55 -0500262/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500263///
David Tolnay1f16b602017-02-07 20:06:55 -0500264/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500265/// }
266/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500267#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500268#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700269macro_rules! tap {
270 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
271 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500272 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700273 let $name = o;
274 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500275 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700276 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500277 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700278 }
279 };
280
281 ($i:expr, $name:ident : $f:expr => $e:expr) => {
282 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700283 };
284}
David Tolnay674258d2016-10-08 13:30:45 -0700285
David Tolnay1f16b602017-02-07 20:06:55 -0500286/// Zero or more values separated by some separator. Does not allow a trailing
287/// seperator.
Michael Layzell24645a32017-02-04 13:19:26 -0500288///
Michael Layzell24645a32017-02-04 13:19:26 -0500289/// - **Syntax:** `separated_list!(punct!("..."), THING)`
290/// - **Output:** `Vec<THING>`
291///
David Tolnay1f16b602017-02-07 20:06:55 -0500292/// You may also be looking for:
293///
294/// - `separated_nonempty_list!` - one or more values
295/// - `terminated_list!` - zero or more, allows trailing separator
296/// - `many0!` - zero or more, no separator
297///
Michael Layzell24645a32017-02-04 13:19:26 -0500298/// ```rust
299/// extern crate syn;
300/// #[macro_use] extern crate synom;
301///
302/// use syn::Expr;
303/// use syn::parse::expr;
304///
David Tolnay1f16b602017-02-07 20:06:55 -0500305/// named!(expr_list -> Vec<Expr>,
306/// separated_list!(punct!(","), expr)
307/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500308///
309/// fn main() {
310/// let input = "1 + 1, things, Construct { this: thing }";
311///
David Tolnay1f16b602017-02-07 20:06:55 -0500312/// let parsed = expr_list(input).expect("expr list");
313/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500314/// }
315/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800316///
317/// ```rust
318/// extern crate syn;
319/// #[macro_use] extern crate synom;
320///
321/// use syn::Ident;
322/// use syn::parse::ident;
323///
324/// named!(run_on -> Vec<Ident>,
325/// terminated!(
326/// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
327/// punct!("...")
328/// )
329/// );
330///
331/// fn main() {
332/// let input = "$expr and $ident and $pat ...";
333///
334/// let parsed = run_on(input).expect("run-on sentence");
335/// assert_eq!(parsed.len(), 3);
336/// assert_eq!(parsed[0], "expr");
337/// assert_eq!(parsed[1], "ident");
338/// assert_eq!(parsed[2], "pat");
339/// }
340/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500341#[macro_export]
David Tolnay674258d2016-10-08 13:30:45 -0700342macro_rules! separated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800343 // Try to use this branch if possible - makes a difference in compile time.
David Tolnay0882b9c2017-02-27 13:07:15 -0800344 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800345 $crate::helper::separated_list($i, $sep, $f, false)
David Tolnay674258d2016-10-08 13:30:45 -0700346 };
David Tolnaydff18802017-02-27 11:57:03 -0800347
348 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
349 let mut res = ::std::vec::Vec::new();
350 let mut input = $i;
351
352 // get the first element
353 match $fmac!(input, $($fargs)*) {
354 $crate::IResult::Error => $crate::IResult::Done(input, res),
355 $crate::IResult::Done(i, o) => {
356 if i.len() == input.len() {
357 $crate::IResult::Error
358 } else {
359 res.push(o);
360 input = i;
361
362 // get the separator first
363 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
364 if i2.len() == input.len() {
365 break;
366 }
367
368 // get the element next
369 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
370 if i3.len() == i2.len() {
371 break;
372 }
373 res.push(o3);
374 input = i3;
375 } else {
376 break;
377 }
378 }
379 $crate::IResult::Done(input, res)
380 }
381 }
382 }
383 }};
384
385 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
Christopher Bacher9620ae02017-03-02 00:44:25 +0100386 separated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800387 };
388
389 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800390 separated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800391 };
392
393 ($i:expr, $sep:expr, $f:expr) => {
394 separated_list!($i, call!($sep), call!($f))
395 };
David Tolnay674258d2016-10-08 13:30:45 -0700396}
397
David Tolnay1f16b602017-02-07 20:06:55 -0500398/// Zero or more values separated by some separator. A trailing separator is
399/// allowed.
Michael Layzell24645a32017-02-04 13:19:26 -0500400///
Michael Layzell24645a32017-02-04 13:19:26 -0500401/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
402/// - **Output:** `Vec<THING>`
403///
David Tolnay1f16b602017-02-07 20:06:55 -0500404/// You may also be looking for:
405///
406/// - `separated_list!` - zero or more, allows trailing separator
407/// - `separated_nonempty_list!` - one or more values
408/// - `many0!` - zero or more, no separator
409///
Michael Layzell24645a32017-02-04 13:19:26 -0500410/// ```rust
411/// extern crate syn;
412/// #[macro_use] extern crate synom;
413///
414/// use syn::Expr;
415/// use syn::parse::expr;
416///
David Tolnay1f16b602017-02-07 20:06:55 -0500417/// named!(expr_list -> Vec<Expr>,
418/// terminated_list!(punct!(","), expr)
419/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500420///
421/// fn main() {
422/// let input = "1 + 1, things, Construct { this: thing },";
423///
David Tolnay1f16b602017-02-07 20:06:55 -0500424/// let parsed = expr_list(input).expect("expr list");
425/// assert_eq!(parsed.len(), 3);
Michael Layzell24645a32017-02-04 13:19:26 -0500426/// }
427/// ```
David Tolnaydff18802017-02-27 11:57:03 -0800428///
429/// ```rust
430/// extern crate syn;
431/// #[macro_use] extern crate synom;
432///
433/// use syn::Ident;
434/// use syn::parse::ident;
435///
436/// named!(run_on -> Vec<Ident>,
437/// terminated!(
438/// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
439/// punct!("...")
440/// )
441/// );
442///
443/// fn main() {
444/// let input = "$expr and $ident and $pat and ...";
445///
446/// let parsed = run_on(input).expect("run-on sentence");
447/// assert_eq!(parsed.len(), 3);
448/// assert_eq!(parsed[0], "expr");
449/// assert_eq!(parsed[1], "ident");
450/// assert_eq!(parsed[2], "pat");
451/// }
452/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500453#[macro_export]
David Tolnayff46fd22016-10-08 13:53:28 -0700454macro_rules! terminated_list {
David Tolnaydff18802017-02-27 11:57:03 -0800455 // Try to use this branch if possible - makes a difference in compile time.
456 ($i:expr, punct!($sep:expr), $f:ident) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -0800457 $crate::helper::separated_list($i, $sep, $f, true)
David Tolnayff46fd22016-10-08 13:53:28 -0700458 };
David Tolnaydff18802017-02-27 11:57:03 -0800459
460 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
461 let mut res = ::std::vec::Vec::new();
462 let mut input = $i;
463
464 // get the first element
465 match $fmac!(input, $($fargs)*) {
466 $crate::IResult::Error => $crate::IResult::Done(input, res),
467 $crate::IResult::Done(i, o) => {
468 if i.len() == input.len() {
469 $crate::IResult::Error
470 } else {
471 res.push(o);
472 input = i;
473
474 // get the separator first
475 while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
476 if i2.len() == input.len() {
477 break;
478 }
479
480 // get the element next
481 if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
482 if i3.len() == i2.len() {
483 break;
484 }
485 res.push(o3);
486 input = i3;
487 } else {
488 break;
489 }
490 }
491 if let $crate::IResult::Done(after, _) = $sepmac!(input, $($separgs)*) {
492 input = after;
493 }
494 $crate::IResult::Done(input, res)
495 }
496 }
497 }
498 }};
499
500 ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800501 terminated_list!($i, $sepmac!($($separgs)*), call!($f))
David Tolnaydff18802017-02-27 11:57:03 -0800502 };
503
504 ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
David Tolnay6e825ca2017-03-01 15:53:40 -0800505 terminated_list!($i, call!($sep), $fmac!($($fargs)*))
David Tolnaydff18802017-02-27 11:57:03 -0800506 };
507
508 ($i:expr, $sep:expr, $f:expr) => {
509 terminated_list!($i, call!($sep), call!($f))
510 };
David Tolnayff46fd22016-10-08 13:53:28 -0700511}
512
David Tolnay5fe14fc2017-01-27 16:22:08 -0800513// Not public API.
514#[doc(hidden)]
Michael Layzell416724e2017-05-24 21:12:34 -0400515pub fn separated_list<'a, T>(mut input: &'a [TokenTree],
David Tolnayc7f646a2016-10-16 10:54:39 -0700516 sep: &'static str,
Michael Layzell416724e2017-05-24 21:12:34 -0400517 f: fn(&'a [TokenTree]) -> IResult<&'a [TokenTree], T>,
David Tolnayc7f646a2016-10-16 10:54:39 -0700518 terminated: bool)
Michael Layzell416724e2017-05-24 21:12:34 -0400519 -> IResult<&'a [TokenTree], Vec<T>> {
David Tolnay674258d2016-10-08 13:30:45 -0700520 let mut res = Vec::new();
521
522 // get the first element
523 match f(input) {
David Tolnaydff18802017-02-27 11:57:03 -0800524 IResult::Error => IResult::Done(input, res),
David Tolnay674258d2016-10-08 13:30:45 -0700525 IResult::Done(i, o) => {
526 if i.len() == input.len() {
527 IResult::Error
528 } else {
529 res.push(o);
530 input = i;
531
532 // get the separator first
533 while let IResult::Done(i2, _) = punct(input, sep) {
534 if i2.len() == input.len() {
535 break;
536 }
537
538 // get the element next
539 if let IResult::Done(i3, o3) = f(i2) {
540 if i3.len() == i2.len() {
541 break;
542 }
543 res.push(o3);
544 input = i3;
545 } else {
546 break;
547 }
548 }
David Tolnayff46fd22016-10-08 13:53:28 -0700549 if terminated {
550 if let IResult::Done(after, _) = punct(input, sep) {
551 input = after;
552 }
553 }
David Tolnay674258d2016-10-08 13:30:45 -0700554 IResult::Done(input, res)
555 }
556 }
557 }
558}
Michael Layzell416724e2017-05-24 21:12:34 -0400559
560#[macro_export]
561macro_rules! delim {
562 ($i:expr, $delim:ident, $fmac:ident!( $($fargs:tt)* )) => {
563 match $crate::helper::delim_impl($i, $crate::Delimiter::$delim) {
564 Some((i, ib)) => {
565 match $fmac!(&*ib, $($fargs)*) {
566 $crate::IResult::Done(rest, val) => {
567 if rest.is_empty() {
568 $crate::IResult::Done(i, val)
569 } else {
570 $crate::IResult::Error
571 }
572 }
573 _ => $crate::IResult::Error,
574 }
575 }
576 _ => $crate::IResult::Error,
577 }
578 };
579 ($i:expr, $delim:ident, $f:expr) => {
580 delim!($i, $delim, call!($f))
581 };
582}
583
584// Not a public API
585#[doc(hidden)]
586pub fn delim_impl(input: &[TokenTree],
587 expected_delim: Delimiter)
588 -> Option<(&[TokenTree], InputBuf)> {
589 // NOTE: The `as u32` hack is being used as `Delimiter` doesn't implement
590 // `PartialEq` or `Eq` despite being a simple c-style enum.
591 match input.first() {
592 Some(&TokenTree {
593 kind: TokenKind::Sequence(delim, ref stream),
594 ..
595 }) if delim as u32 == expected_delim as u32 => {
596 Some((&input[1..], InputBuf::new(stream.clone())))
597 }
598 _ => None
599 }
600}