blob: ce2f6add6ee47a3808a874dbaf054e64b4a4f748 [file] [log] [blame]
David Tolnayb5a7b142016-09-13 22:46:39 -07001// Adapted from nom <https://github.com/Geal/nom> by removing the
2// IResult::Incomplete variant, which we don't use and which unfortunately more
3// than doubles the compilation time.
4
Michael Layzell5bde96f2017-01-24 17:59:21 -05005extern crate unicode_xid;
6
7pub mod space;
8
David Tolnay5fe14fc2017-01-27 16:22:08 -08009#[doc(hidden)]
10pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050011
Michael Layzell24645a32017-02-04 13:19:26 -050012/// The result of a parser.
David Tolnayb5a7b142016-09-13 22:46:39 -070013#[derive(Debug, PartialEq, Eq, Clone)]
14pub enum IResult<I, O> {
David Tolnayf2222f02017-01-27 17:09:20 -080015 /// Parsing succeeded. The first field contains the rest of the unparsed
16 /// data and the second field contains the parse result.
David Tolnayb5a7b142016-09-13 22:46:39 -070017 Done(I, O),
David Tolnayf2222f02017-01-27 17:09:20 -080018 /// Parsing failed.
David Tolnayb5a7b142016-09-13 22:46:39 -070019 Error,
20}
21
David Tolnayf2222f02017-01-27 17:09:20 -080022impl<'a, O> IResult<&'a str, O> {
Michael Layzell24645a32017-02-04 13:19:26 -050023 /// Unwraps the result, asserting the the parse is complete. Panics with a
24 /// message based on the given string if the parse failed or is incomplete.
David Tolnayf2222f02017-01-27 17:09:20 -080025 pub fn expect(self, name: &str) -> O {
26 match self {
27 IResult::Done(mut rest, o) => {
28 rest = space::skip_whitespace(rest);
29 if rest.is_empty() {
30 o
31 } else {
32 panic!("unparsed tokens after {}: {:?}", name, rest)
33 }
34 }
35 IResult::Error => panic!("failed to parse {}", name),
36 }
37 }
38}
39
Michael Layzell24645a32017-02-04 13:19:26 -050040/// Define a function from a parser combination.
41///
42/// - **Syntax:** `named!(NAME -> TYPE, THING)`
Michael Layzell5bde96f2017-01-24 17:59:21 -050043#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070044macro_rules! named {
45 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -050046 fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070047 $submac!(i, $($args)*)
48 }
49 };
50
51 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -050052 pub fn $name(i: &str) -> $crate::IResult<&str, $o> {
David Tolnayb5a7b142016-09-13 22:46:39 -070053 $submac!(i, $($args)*)
54 }
55 };
56}
57
Michael Layzell24645a32017-02-04 13:19:26 -050058/// Invoke the function with the passed in arguments as a parser.
59///
60/// - **Syntax:** `call!(FUNCTION, ARGS...)`
61/// - **Output:** The result of invoking the function `FUNCTION`
62///
63/// ```rust
64/// #[macro_use] extern crate synom;
65///
66/// use synom::IResult;
67///
68/// fn parse_char(input: &str, ch: char) -> IResult<&str, char> {
69/// if input.starts_with(ch) {
70/// IResult::Done(&input[ch.len_utf8()..], ch)
71/// } else {
72/// IResult::Error
73/// }
74/// }
75///
76/// named!(an_a -> char, call!(parse_char, 'a'));
77///
78/// fn main() {
79/// let input = "a";
80///
81/// let parsed = an_a(input).expect("an a");
82///
83/// println!("{:?}", parsed);
84/// }
85/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050086#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070087macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -070088 ($i:expr, $fun:expr $(, $args:expr)*) => {
89 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -070090 };
91}
92
Michael Layzell24645a32017-02-04 13:19:26 -050093/// Perform a transformation on the result of a parser.
94///
95/// - **Syntax:** `map!(THING, TRANSFORM)`
96/// - **Output:** `THING` after being transformed by `TRANSFORM`
97///
98/// ```rust
99/// extern crate syn;
100/// #[macro_use] extern crate synom;
101///
102/// use syn::{Item, Ident};
103/// use syn::parse::item;
104///
105/// fn get_item_ident(item: Item) -> Ident {
106/// item.ident
107/// }
108///
109/// named!(item_ident -> Ident, map!(item, get_item_ident));
110///
111/// fn main() {
112/// let input = "fn foo() {}";
113///
114/// let parsed = item_ident(input).expect("item identifier");
115///
116/// assert_eq!(parsed.as_ref(), "foo");
117/// }
118/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500119#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700120macro_rules! map {
121 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700122 map_impl!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700123 };
124
125 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700126 map_impl!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700127 };
128}
129
130/// Internal parser, do not use directly
Michael Layzell5bde96f2017-01-24 17:59:21 -0500131#[doc(hidden)]
132#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700133macro_rules! map_impl {
134 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
135 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500136 $crate::IResult::Error => $crate::IResult::Error,
137 $crate::IResult::Done(i, o) => {
138 $crate::IResult::Done(i, $submac2!(o, $($args2)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700139 }
140 }
141 };
142}
143
Michael Layzell24645a32017-02-04 13:19:26 -0500144/// Parses successfully if the passed-in parser fails to parse.
145///
146/// - **Syntax:** `not!(THING)`
147/// - **Output:** `""`
148///
149/// ```rust
150/// extern crate syn;
151/// #[macro_use] extern crate synom;
152///
153/// use syn::parse::expr;
154///
155/// // Parse not an expression
156/// named!(not_an_expr -> &'static str, not!(call!(expr)));
157///
158/// fn main() {
159/// let input = "";
160///
161/// let parsed = not_an_expr(input).expect("not an expr");
162/// assert_eq!(parsed, "");
163/// }
164/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500165#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700166macro_rules! not {
167 ($i:expr, $submac:ident!( $($args:tt)* )) => {
168 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500169 $crate::IResult::Done(_, _) => $crate::IResult::Error,
170 $crate::IResult::Error => $crate::IResult::Done($i, ""),
David Tolnayb5a7b142016-09-13 22:46:39 -0700171 }
172 };
173}
174
David Tolnayeea28d62016-10-25 20:44:08 -0700175// This is actually nom's cond_with_error.
Michael Layzell24645a32017-02-04 13:19:26 -0500176/// Conditionally execute the passed-in parser.
177///
178/// - **Syntax:** `cond!(CONDITION, PARSER)`
179/// - **Output:** `Option<PARSER>`
180///
181/// ```rust
182/// #[macro_use] extern crate synom;
183///
184/// named!(maybe_bang_bang -> bool,
185/// do_parse!(
186/// bang: option!(punct!("!")) >>
187/// cond!(bang.is_some(), punct!("!")) >>
188/// (bang.is_some())));
189///
190/// fn main() {
191/// let input = "";
192/// let parsed = maybe_bang_bang(input).expect("not bang bang");
193/// assert_eq!(parsed, false);
194///
195/// let input = "!!";
196/// let parsed = maybe_bang_bang(input).expect("yes bang bang");
197/// assert_eq!(parsed, true);
198/// }
199/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500200#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700201macro_rules! cond {
202 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
203 if $cond {
204 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500205 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ::std::option::Option::Some(o)),
206 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700207 }
208 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500209 $crate::IResult::Done($i, ::std::option::Option::None)
David Tolnayb5a7b142016-09-13 22:46:39 -0700210 }
David Tolnaycfe55022016-10-02 22:02:27 -0700211 };
212
213 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700214 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700215 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700216}
217
Michael Layzell24645a32017-02-04 13:19:26 -0500218/// Fails with an error if CONDITION is not true. Otherwise parses PARSER
219///
220/// - **Syntax:** `cond_reduce!(CONDITION, PARSER)`
221/// - **Output:** `PARSER`
222///
223/// ```rust
224/// #[macro_use] extern crate synom;
225///
226/// named!(maybe_bang_bang -> bool,
227/// do_parse!(
228/// bang: option!(punct!("!")) >>
229/// cond!(bang.is_some(), punct!("!")) >>
230/// (bang.is_some())));
231///
232/// fn main() {
233/// let input = "!!";
234/// let parsed = maybe_bang_bang(input).expect("yes bang bang");
235/// assert_eq!(parsed, true);
236/// }
237/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500238#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700239macro_rules! cond_reduce {
240 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
241 if $cond {
242 $submac!($i, $($args)*)
243 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500244 $crate::IResult::Error
David Tolnayaf2557e2016-10-24 11:52:21 -0700245 }
246 };
247
248 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700249 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700250 };
251}
252
Michael Layzell24645a32017-02-04 13:19:26 -0500253/// Value preceded by another macro
254///
255/// - **Syntax:** `preceded!(OPEN, THING)`
256/// - **Output:** `THING`
257///
258/// ```rust
259/// extern crate syn;
260/// #[macro_use] extern crate synom;
261///
262/// use syn::Expr;
263/// use syn::parse::expr;
264///
265/// // An expression preceded by ##.
266/// named!(pound_pound_expr -> Expr,
267/// preceded!(
268/// punct!("##"),
269/// expr));
270///
271/// fn main() {
272/// let input = "## 1 + 1";
273///
274/// let parsed = pound_pound_expr(input).expect("pound pound expr");
275///
276/// println!("{:?}", parsed);
277/// }
278/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500279#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700280macro_rules! preceded {
281 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
282 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500283 $crate::IResult::Done(remaining, (_, o)) => $crate::IResult::Done(remaining, o),
284 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700285 }
286 };
287
288 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700289 preceded!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700290 };
291
292 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700293 preceded!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700294 };
295
296 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700297 preceded!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700298 };
299}
300
Michael Layzell24645a32017-02-04 13:19:26 -0500301/// Value followed by a terminator.
302///
303/// - **Syntax:** `terminated!(THING, CLOSE)`
304/// - **Output:** `THING`
305///
306/// ```rust
307/// extern crate syn;
308/// #[macro_use] extern crate synom;
309///
310/// use syn::Expr;
311/// use syn::parse::expr;
312///
313/// // An expression terminated by ##.
314/// named!(expr_pound_pound -> Expr,
315/// terminated!(
316/// expr,
317/// punct!("##")));
318///
319/// fn main() {
320/// let input = "1 + 1 ##";
321///
322/// let parsed = expr_pound_pound(input).expect("expr pound pound");
323///
324/// println!("{:?}", parsed);
325/// }
326/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500327#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700328macro_rules! terminated {
329 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
330 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500331 $crate::IResult::Done(remaining, (o, _)) => $crate::IResult::Done(remaining, o),
332 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700333 }
334 };
335
336 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700337 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700338 };
339
340 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700341 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700342 };
343
344 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700345 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700346 };
347}
348
Michael Layzell24645a32017-02-04 13:19:26 -0500349/// A value repeated 0 or more times.
350///
351/// - **Syntax:** `many0!(THING)`
352/// - **Output:** `Vec<THING>`
353///
354/// ```rust
355/// extern crate syn;
356/// #[macro_use] extern crate synom;
357///
358/// use syn::Item;
359/// use syn::parse::item;
360///
361/// named!(items -> Vec<Item>, many0!(item));
362///
363/// fn main() {
364/// let input = "fn a() {} fn b() {}";
365///
366/// let parsed = items(input).expect("items");
367///
368/// println!("{:?}", parsed);
369/// }
370/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500371#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700372macro_rules! many0 {
373 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
374 let ret;
375 let mut res = ::std::vec::Vec::new();
376 let mut input = $i;
377
378 loop {
379 if input.is_empty() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500380 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700381 break;
382 }
383
384 match $submac!(input, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500385 $crate::IResult::Error => {
386 ret = $crate::IResult::Done(input, res);
David Tolnayb5a7b142016-09-13 22:46:39 -0700387 break;
388 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500389 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700390 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700391 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500392 ret = $crate::IResult::Error;
David Tolnayb5a7b142016-09-13 22:46:39 -0700393 break;
394 }
395
396 res.push(o);
397 input = i;
398 }
399 }
400 }
401
402 ret
403 }};
404
405 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500406 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700407 };
408}
409
David Tolnay5fe14fc2017-01-27 16:22:08 -0800410// Not public API.
411#[doc(hidden)]
David Tolnayc7f646a2016-10-16 10:54:39 -0700412pub fn many0<'a, T>(mut input: &'a str,
413 f: fn(&'a str) -> IResult<&'a str, T>)
414 -> IResult<&'a str, Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700415 let mut res = Vec::new();
416
417 loop {
418 if input.is_empty() {
419 return IResult::Done(input, res);
420 }
421
422 match f(input) {
423 IResult::Error => {
424 return IResult::Done(input, res);
425 }
426 IResult::Done(i, o) => {
427 // loop trip must always consume (otherwise infinite loops)
428 if i.len() == input.len() {
429 return IResult::Error;
430 }
431
432 res.push(o);
433 input = i;
434 }
435 }
436 }
437}
438
Michael Layzell24645a32017-02-04 13:19:26 -0500439/// look for a value without consuming it.
440///
441/// - **Syntax:** `peek!(THING)`
442/// - **Output:** `Vec<THING>`
443///
444/// ```rust
445/// extern crate syn;
446/// #[macro_use] extern crate synom;
447///
448/// use syn::Ident;
449/// use syn::parse::{ident, expr};
450///
451/// named!(ident_expr -> Ident,
452/// do_parse!(
453/// i: peek!(call!(ident)) >>
454/// expr >>
455/// (i)));
456///
457/// fn main() {
458/// let input = "apple";
459///
460/// let parsed = ident_expr(input).expect("ident");
461///
462/// println!("{:?}", parsed);
463/// }
464/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500465#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700466macro_rules! peek {
467 ($i:expr, $submac:ident!( $($args:tt)* )) => {
468 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500469 $crate::IResult::Done(_, o) => $crate::IResult::Done($i, o),
470 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700471 }
472 };
473}
474
Michael Layzell5bde96f2017-01-24 17:59:21 -0500475#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700476macro_rules! take_while1 {
477 ($input:expr, $submac:ident!( $($args:tt)* )) => {{
478 let mut offset = $input.len();
479 for (o, c) in $input.char_indices() {
480 if !$submac!(c, $($args)*) {
481 offset = o;
482 break;
483 }
484 }
485 if offset == 0 {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500486 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700487 } else if offset < $input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500488 $crate::IResult::Done(&$input[offset..], &$input[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700489 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500490 $crate::IResult::Done("", $input)
David Tolnayb5a7b142016-09-13 22:46:39 -0700491 }
492 }};
493
494 ($input:expr, $f:expr) => {
495 take_while1!($input, call!($f));
496 };
497}
498
Michael Layzell5bde96f2017-01-24 17:59:21 -0500499#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700500macro_rules! take_until {
501 ($input:expr, $substr:expr) => {{
502 if $substr.len() > $input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500503 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700504 } else {
David Tolnayf2c452b2016-12-21 22:45:28 -0500505 let substr_vec: Vec<char> = $substr.chars().collect();
David Tolnayb5a7b142016-09-13 22:46:39 -0700506 let mut window: Vec<char> = vec![];
507 let mut offset = $input.len();
508 let mut parsed = false;
509 for (o, c) in $input.char_indices() {
510 window.push(c);
511 if window.len() > substr_vec.len() {
512 window.remove(0);
513 }
514 if window == substr_vec {
515 parsed = true;
516 window.pop();
517 let window_len: usize = window.iter()
518 .map(|x| x.len_utf8())
519 .fold(0, |x, y| x + y);
520 offset = o - window_len;
521 break;
522 }
523 }
524 if parsed {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500525 $crate::IResult::Done(&$input[offset..], &$input[..offset])
David Tolnayb5a7b142016-09-13 22:46:39 -0700526 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500527 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700528 }
529 }
530 }};
531}
532
Michael Layzell5bde96f2017-01-24 17:59:21 -0500533#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700534macro_rules! tag {
535 ($i:expr, $tag: expr) => {
David Tolnay0b154ea2016-10-01 15:42:50 -0700536 if $i.starts_with($tag) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500537 $crate::IResult::Done(&$i[$tag.len()..], &$i[0..$tag.len()])
David Tolnayb5a7b142016-09-13 22:46:39 -0700538 } else {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500539 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700540 }
541 };
542}
543
Michael Layzell5bde96f2017-01-24 17:59:21 -0500544#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700545macro_rules! switch {
546 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
547 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500548 $crate::IResult::Error => $crate::IResult::Error,
549 $crate::IResult::Done(i, o) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700550 $(
551 $p => $subrule!(i, $($args2)*),
552 )*
Michael Layzell5bde96f2017-01-24 17:59:21 -0500553 _ => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700554 }
555 }
556 };
557}
558
Michael Layzell5bde96f2017-01-24 17:59:21 -0500559#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700560macro_rules! value {
561 ($i:expr, $res:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500562 $crate::IResult::Done($i, $res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700563 };
564}
565
David Tolnayf2222f02017-01-27 17:09:20 -0800566/// Value surrounded by a pair of delimiters.
567///
568/// - **Syntax:** `delimited!(OPEN, THING, CLOSE)`
569/// - **Output:** `THING`
570///
571/// ```rust
572/// extern crate syn;
573/// #[macro_use] extern crate synom;
574///
575/// use syn::Expr;
576/// use syn::parse::expr;
577///
578/// // An expression surrounded by [[ ... ]].
579/// named!(double_bracket_expr -> Expr,
580/// delimited!(
581/// punct!("[["),
582/// expr,
583/// punct!("]]")));
584///
585/// fn main() {
586/// let input = "[[ 1 + 1 ]]";
587///
588/// let parsed = double_bracket_expr(input).expect("double bracket expr");
589///
590/// println!("{:?}", parsed);
591/// }
592/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500593#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700594macro_rules! delimited {
595 ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
596 match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500597 $crate::IResult::Error => $crate::IResult::Error,
598 $crate::IResult::Done(i1, (_, o, _)) => $crate::IResult::Done(i1, o)
David Tolnayb5a7b142016-09-13 22:46:39 -0700599 }
600 };
601
602 ($i:expr, $f:expr, $($rest:tt)+) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700603 delimited!($i, call!($f), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700604 };
605}
606
David Tolnayf2222f02017-01-27 17:09:20 -0800607/// One or more of something separated by some separator.
608///
609/// - **Syntax:** `separated_nonempty_list!(SEPARATOR, THING)`
610/// - **Output:** `Vec<THING>`
611///
612/// ```rust
613/// extern crate syn;
614/// #[macro_use] extern crate synom;
615///
616/// use syn::Ty;
617/// use syn::parse::ty;
618///
619/// // One or more Rust types separated by commas.
620/// named!(comma_separated_types -> Vec<Ty>,
621/// separated_nonempty_list!(
622/// punct!(","),
623/// ty));
624///
625/// fn main() {
626/// let input = "&str, Map<K, V>, String";
627///
628/// let parsed = comma_separated_types(input).expect("comma-separated types");
629///
630/// assert_eq!(parsed.len(), 3);
631/// println!("{:?}", parsed);
632/// }
633/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500634#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700635macro_rules! separated_nonempty_list {
636 ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => {{
637 let mut res = ::std::vec::Vec::new();
638 let mut input = $i;
639
640 // get the first element
641 match $submac!(input, $($args2)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500642 $crate::IResult::Error => $crate::IResult::Error,
643 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700644 if i.len() == input.len() {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500645 $crate::IResult::Error
David Tolnayb5a7b142016-09-13 22:46:39 -0700646 } else {
647 res.push(o);
648 input = i;
649
Michael Layzell5bde96f2017-01-24 17:59:21 -0500650 while let $crate::IResult::Done(i2, _) = $sep!(input, $($args)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700651 if i2.len() == input.len() {
652 break;
653 }
654
Michael Layzell5bde96f2017-01-24 17:59:21 -0500655 if let $crate::IResult::Done(i3, o3) = $submac!(i2, $($args2)*) {
David Tolnayb5a7b142016-09-13 22:46:39 -0700656 if i3.len() == i2.len() {
657 break;
658 }
659 res.push(o3);
660 input = i3;
661 } else {
662 break;
663 }
664 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500665 $crate::IResult::Done(input, res)
David Tolnayb5a7b142016-09-13 22:46:39 -0700666 }
667 }
668 }
669 }};
670
671 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700672 separated_nonempty_list!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700673 };
674
675 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700676 separated_nonempty_list!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700677 };
678
679 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700680 separated_nonempty_list!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700681 };
682}
683
Michael Layzell24645a32017-02-04 13:19:26 -0500684/// Run a series of parsers, and produce all of the results in a tuple.
685///
686/// - **Syntax:** `tuple!(THING1, THING2, ...)`
687/// - **Output:** `(THING1, THING2, ...)`
688///
689/// ```rust
690/// extern crate syn;
691/// #[macro_use] extern crate synom;
692///
693/// use syn::Ty;
694/// use syn::parse::ty;
695///
696/// named!(two_types -> (Ty, Ty), tuple!(ty, ty));
697///
698/// fn main() {
699/// let input = "&str Map<K, V>";
700///
701/// let parsed = two_types(input).expect("two_types");
702///
703/// println!("{:?}", parsed);
704/// }
705/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500706#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700707macro_rules! tuple {
708 ($i:expr, $($rest:tt)*) => {
709 tuple_parser!($i, (), $($rest)*)
710 };
711}
712
713/// Internal parser, do not use directly
Michael Layzell5bde96f2017-01-24 17:59:21 -0500714#[doc(hidden)]
715#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700716macro_rules! tuple_parser {
717 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700718 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700719 };
720
721 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
722 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500723 $crate::IResult::Error => $crate::IResult::Error,
724 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700725 tuple_parser!(i, (o), $($rest)*),
726 }
727 };
728
729 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
730 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500731 $crate::IResult::Error => $crate::IResult::Error,
732 $crate::IResult::Done(i, o) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700733 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
734 }
735 };
736
737 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700738 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700739 };
740
741 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
742 $submac!($i, $($args)*)
743 };
744
745 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
746 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500747 $crate::IResult::Error => $crate::IResult::Error,
748 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, ($($parsed),*, o))
David Tolnayb5a7b142016-09-13 22:46:39 -0700749 }
750 };
751
752 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500753 $crate::IResult::Done($i, ($($parsed),*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700754 };
755}
756
Michael Layzell24645a32017-02-04 13:19:26 -0500757/// Run a series of parsers, returning the result of the first one which succeeds.
758///
759/// Optionally allows for the result to be transformed.
760///
761/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
762/// - **Output:** Either `THING1` or `FUNC(THING2)` or ...
763///
764/// ```rust
765/// extern crate syn;
766/// #[macro_use] extern crate synom;
767///
768/// use syn::Ident;
769/// use syn::parse::ident;
770///
771/// named!(ident_or_bang -> Ident,
772/// alt!(ident |
773/// punct!("!") => { |_| "BANG".into() }));
774///
775/// fn main() {
776/// let input = "!";
777/// ident_or_bang(input).expect("ident_or_bang");
778///
779/// let input = "foo";
780/// ident_or_bang(input).expect("ident_or_bang");
781/// }
782/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500783#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700784macro_rules! alt {
785 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700786 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700787 };
788
789 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
790 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500791 res @ $crate::IResult::Done(_, _) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700792 _ => alt!($i, $($rest)*)
793 }
794 };
795
796 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
797 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500798 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
799 $crate::IResult::Error => alt!($i, $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700800 }
801 };
802
803 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700804 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700805 };
806
807 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700808 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700809 };
810
811 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
812 match $subrule!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500813 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, $gen(o)),
814 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayb5a7b142016-09-13 22:46:39 -0700815 }
816 };
817
818 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700819 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700820 };
821
822 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700823 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700824 };
825}
826
Michael Layzell24645a32017-02-04 13:19:26 -0500827/// Run a series of parsers, one after another, optionally assigning the results
828/// a name. Fails if any of the parsers fail.
829///
830/// Produces the result of evaluating the final expression in brackets with all
831/// of the previously named results bound.
832///
833/// The variable bindings may be marked as `mut`.
834///
835/// - **Syntax:** `alt!(name: THING1 >> THING2 >> (RESULT))`
836/// - **Output:** `RESULT`
837///
838/// ```rust
839/// extern crate syn;
840/// #[macro_use] extern crate synom;
841///
842/// use syn::{Ident, TokenTree};
843/// use syn::parse::{ident, tt};
844///
845/// named!(simple_mac -> (Ident, TokenTree), do_parse!(
846/// name: ident >>
847/// punct!("!") >>
848/// body: tt >>
849/// ((name, body))));
850///
851/// fn main() {
852/// let input = "foo!(some, random, junk)";
853/// simple_mac(input).expect("macro");
854/// }
855/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500856#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700857macro_rules! do_parse {
858 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500859 $crate::IResult::Done($i, ( $($rest),* ))
David Tolnayb5a7b142016-09-13 22:46:39 -0700860 };
861
862 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700863 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700864 };
865
866 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
867 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500868 $crate::IResult::Error => $crate::IResult::Error,
869 $crate::IResult::Done(i, _) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700870 do_parse!(i, $($rest)*),
871 }
872 };
873
874 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700875 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700876 };
877
878 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
879 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500880 $crate::IResult::Error => $crate::IResult::Error,
881 $crate::IResult::Done(i, o) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700882 let $field = o;
883 do_parse!(i, $($rest)*)
884 },
885 }
886 };
887
David Tolnayfa0edf22016-09-23 22:58:24 -0700888 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700889 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700890 };
891
892 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
893 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500894 $crate::IResult::Error => $crate::IResult::Error,
895 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700896 let mut $field = o;
897 do_parse!(i, $($rest)*)
898 },
899 }
900 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700901}