blob: 89571b848e7c88da07c3c23989793ee70b2e7ae3 [file] [log] [blame]
David Tolnay30a36002017-02-08 14:24:12 -08001//! Adapted from [`nom`](https://github.com/Geal/nom) by removing the
Michael Layzell760fd662017-05-31 22:46:05 -04002//! `IPResult::Incomplete` variant which:
David Tolnay30a36002017-02-08 14:24:12 -08003//!
4//! - we don't need,
5//! - is an unintuitive footgun when working with non-streaming use cases, and
6//! - more than doubles compilation time.
7//!
8//! ## Whitespace handling strategy
9//!
10//! As (sy)nom is a parser combinator library, the parsers provided here and
11//! that you implement yourself are all made up of successively more primitive
12//! parsers, eventually culminating in a small number of fundamental parsers
13//! that are implemented in Rust. Among these are `punct!` and `keyword!`.
14//!
15//! All synom fundamental parsers (those not combined out of other parsers)
16//! should be written to skip over leading whitespace in their input. This way,
17//! as long as every parser eventually boils down to some combination of
18//! fundamental parsers, we get correct whitespace handling at all levels for
19//! free.
20//!
21//! For our use case, this strategy is a huge improvement in usability,
22//! correctness, and compile time over nom's `ws!` strategy.
David Tolnayb5a7b142016-09-13 22:46:39 -070023
Michael Layzell5bde96f2017-01-24 17:59:21 -050024extern crate unicode_xid;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070025extern crate proc_macro2;
Michael Layzell5bde96f2017-01-24 17:59:21 -050026
Alex Crichtonccbb45d2017-05-23 10:58:24 -070027#[cfg(feature = "printing")]
28extern crate quote;
29
David Tolnay30a36002017-02-08 14:24:12 -080030#[doc(hidden)]
Alex Crichton954046c2017-05-30 21:49:42 -070031pub use proc_macro2::{TokenTree, TokenStream};
32
33use std::convert::From;
34use std::error::Error;
35use std::fmt;
36
37use proc_macro2::LexError;
Michael Layzell5bde96f2017-01-24 17:59:21 -050038
Alex Crichtonccbb45d2017-05-23 10:58:24 -070039#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080040#[doc(hidden)]
41pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050042
Alex Crichtonccbb45d2017-05-23 10:58:24 -070043pub mod delimited;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070044pub mod tokens;
45pub mod span;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070046
Michael Layzell760fd662017-05-31 22:46:05 -040047/// A cursor into a Vec<TokenTree>.
48///
49/// NOTE: This type is currently unnecessary, but will make future refactorings
50/// which change this type easier.
51pub type Cursor<'a> = &'a [TokenTree];
David Tolnayb5a7b142016-09-13 22:46:39 -070052
Michael Layzell760fd662017-05-31 22:46:05 -040053/// The result of a parser
54pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
55
56/// An error with a default error message.
57///
58/// NOTE: We should provide better error messages in the future.
59pub fn parse_error<O>() -> PResult<'static, O> {
60 Err(ParseError("error parsing value".to_string()))
David Tolnayf2222f02017-01-27 17:09:20 -080061}
62
Alex Crichton7b9e02f2017-05-30 15:54:33 -070063pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040064 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070065
66 fn description() -> Option<&'static str> {
67 None
68 }
69
70 fn parse_all(input: TokenStream) -> Result<Self, ParseError> {
71 let tokens = input.into_iter().collect::<Vec<_>>();
72 let err = match Self::parse(&tokens) {
Michael Layzell760fd662017-05-31 22:46:05 -040073 Ok((rest, t)) => {
Alex Crichton954046c2017-05-30 21:49:42 -070074 if rest.is_empty() {
75 return Ok(t)
76 } else if rest.len() == tokens.len() {
77 // parsed nothing
78 "failed to parse"
79 } else {
80 "unparsed tokens after"
81 }
82 }
Michael Layzell760fd662017-05-31 22:46:05 -040083 Err(_) => "failed to parse"
Alex Crichton954046c2017-05-30 21:49:42 -070084 };
85 match Self::description() {
86 Some(s) => Err(ParseError(format!("{} {}", err, s))),
87 None => Err(ParseError(err.to_string())),
88 }
89 }
90
91 fn parse_str_all(input: &str) -> Result<Self, ParseError> {
92 Self::parse_all(input.parse()?)
93 }
94
95 fn parse_all_unwrap(input: TokenStream) -> Self {
96 // TODO: eventually try to provide super nice error messages here as
97 // this is what most users will hit. Hopefully the compiler will give us
98 // an interface one day to give an extra-good error message here.
99 Self::parse_all(input).unwrap()
100 }
101}
102
103#[derive(Debug)]
104pub struct ParseError(String);
105
106impl Error for ParseError {
107 fn description(&self) -> &str {
108 &self.0
109 }
110}
111
112impl fmt::Display for ParseError {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 <String as fmt::Display>::fmt(&self.0, f)
115 }
116}
117
118impl From<LexError> for ParseError {
119 fn from(_: LexError) -> ParseError {
120 ParseError("error while lexing input string".to_owned())
121 }
122}
123
124impl Synom for TokenStream {
Michael Layzell760fd662017-05-31 22:46:05 -0400125 fn parse(input: &[TokenTree]) -> PResult<Self> {
126 Ok((&[], input.iter().cloned().collect()))
Alex Crichton954046c2017-05-30 21:49:42 -0700127 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700128}
129
Michael Layzell24645a32017-02-04 13:19:26 -0500130/// Define a function from a parser combination.
131///
David Tolnay1f16b602017-02-07 20:06:55 -0500132/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
133///
134/// ```rust
135/// # extern crate syn;
136/// # #[macro_use] extern crate synom;
137/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700138/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700139/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500140/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700141/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
142/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500143/// );
144/// # fn main() {}
145/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500146#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700147macro_rules! named {
148 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400149 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700150 $submac!(i, $($args)*)
151 }
152 };
153
154 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400155 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700156 $submac!(i, $($args)*)
157 }
158 };
159}
160
David Tolnay1f16b602017-02-07 20:06:55 -0500161/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500162///
163/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500164///
Michael Layzell760fd662017-05-31 22:46:05 -0400165/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500166/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500167#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700168macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700169 ($i:expr, $fun:expr $(, $args:expr)*) => {
170 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700171 };
172}
173
David Tolnay1f16b602017-02-07 20:06:55 -0500174/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500175///
David Tolnay1f16b602017-02-07 20:06:55 -0500176/// - **Syntax:** `map!(THING, FN)`
177/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500178///
179/// ```rust
180/// extern crate syn;
181/// #[macro_use] extern crate synom;
182///
183/// use syn::{Item, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500184///
185/// fn get_item_ident(item: Item) -> Ident {
186/// item.ident
187/// }
188///
David Tolnay1f16b602017-02-07 20:06:55 -0500189/// // Parses an item and returns the name (identifier) of the item only.
190/// named!(item_ident -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700191/// map!(syn!(Item), get_item_ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500192/// );
193///
194/// // Or equivalently:
195/// named!(item_ident2 -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700196/// map!(syn!(Item), |i: Item| i.ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500197/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500198///
Alex Crichton954046c2017-05-30 21:49:42 -0700199/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500200/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500201#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700202macro_rules! map {
203 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700204 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400205 ::std::result::Result::Err(err) =>
206 ::std::result::Result::Err(err),
207 ::std::result::Result::Ok((i, o)) =>
208 ::std::result::Result::Ok((i, call!(o, $g))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700209 }
210 };
David Tolnay1f16b602017-02-07 20:06:55 -0500211
212 ($i:expr, $f:expr, $g:expr) => {
213 map!($i, call!($f), $g)
214 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700215}
216
David Tolnay1f16b602017-02-07 20:06:55 -0500217/// Parses successfully if the given parser fails to parse. Does not consume any
218/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500219///
220/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500221/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500222#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700223macro_rules! not {
224 ($i:expr, $submac:ident!( $($args:tt)* )) => {
225 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400226 ::std::result::Result::Ok(_) => $crate::parse_error(),
227 ::std::result::Result::Err(_) =>
228 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700229 }
230 };
231}
232
David Tolnay1f16b602017-02-07 20:06:55 -0500233/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500234///
David Tolnay1f16b602017-02-07 20:06:55 -0500235/// If you are familiar with nom, this is nom's `cond_with_error` parser.
236///
237/// - **Syntax:** `cond!(CONDITION, THING)`
238/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500239#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700240macro_rules! cond {
241 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
242 if $cond {
243 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400244 ::std::result::Result::Ok((i, o)) =>
245 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
246 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700247 }
248 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400249 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700250 }
David Tolnaycfe55022016-10-02 22:02:27 -0700251 };
252
253 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700254 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700255 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700256}
257
David Tolnay1f16b602017-02-07 20:06:55 -0500258/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500259///
David Tolnay1f16b602017-02-07 20:06:55 -0500260/// This is typically used inside of `option!` or `alt!`.
261///
262/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
263/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500264#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700265macro_rules! cond_reduce {
266 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
267 if $cond {
268 $submac!($i, $($args)*)
269 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400270 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700271 }
272 };
273
274 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700275 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700276 };
277}
278
David Tolnay1f16b602017-02-07 20:06:55 -0500279/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500280///
David Tolnay1f16b602017-02-07 20:06:55 -0500281/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500282/// - **Output:** `THING`
283///
284/// ```rust
285/// extern crate syn;
286/// #[macro_use] extern crate synom;
287///
288/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700289/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500290///
291/// // An expression terminated by ##.
292/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700293/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500294/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500295///
Alex Crichton954046c2017-05-30 21:49:42 -0700296/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500297/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500298#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700299macro_rules! terminated {
300 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
301 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400302 ::std::result::Result::Ok((i, (o, _))) =>
303 ::std::result::Result::Ok((i, o)),
304 ::std::result::Result::Err(err) =>
305 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700306 }
307 };
308
309 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700310 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700311 };
312
313 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700314 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700315 };
316
317 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700318 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700319 };
320}
321
David Tolnay1f16b602017-02-07 20:06:55 -0500322/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500323///
324/// - **Syntax:** `many0!(THING)`
325/// - **Output:** `Vec<THING>`
326///
David Tolnay1f16b602017-02-07 20:06:55 -0500327/// You may also be looking for:
328///
Alex Crichton954046c2017-05-30 21:49:42 -0700329/// - `call!(Delimited::parse_separated)` - zero or more values with separator
330/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
331/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500332///
Michael Layzell24645a32017-02-04 13:19:26 -0500333/// ```rust
334/// extern crate syn;
335/// #[macro_use] extern crate synom;
336///
337/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500338///
Alex Crichton954046c2017-05-30 21:49:42 -0700339/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500340///
Alex Crichton954046c2017-05-30 21:49:42 -0700341/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500342#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700343macro_rules! many0 {
344 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
345 let ret;
346 let mut res = ::std::vec::Vec::new();
347 let mut input = $i;
348
349 loop {
350 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400351 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700352 break;
353 }
354
355 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400356 ::std::result::Result::Err(_) => {
357 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700358 break;
359 }
Michael Layzell760fd662017-05-31 22:46:05 -0400360 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700361 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700362 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400363 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700364 break;
365 }
366
367 res.push(o);
368 input = i;
369 }
370 }
371 }
372
373 ret
374 }};
375
376 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500377 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700378 };
379}
380
David Tolnay1f16b602017-02-07 20:06:55 -0500381// Improve compile time by compiling this loop only once per type it is used
382// with.
383//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800384// Not public API.
385#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400386pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700387 let mut res = Vec::new();
388
389 loop {
390 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400391 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700392 }
393
394 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400395 Err(_) => {
396 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700397 }
Michael Layzell760fd662017-05-31 22:46:05 -0400398 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700399 // loop trip must always consume (otherwise infinite loops)
400 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400401 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700402 }
403
404 res.push(o);
405 input = i;
406 }
407 }
408 }
409}
410
David Tolnay1f16b602017-02-07 20:06:55 -0500411/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500412///
413/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500414/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500415///
416/// ```rust
417/// extern crate syn;
418/// #[macro_use] extern crate synom;
419///
Alex Crichton954046c2017-05-30 21:49:42 -0700420/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500421///
David Tolnay1f16b602017-02-07 20:06:55 -0500422/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700423/// named!(ident_expr -> (Ident, Expr),
424/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500425/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500426///
Alex Crichton954046c2017-05-30 21:49:42 -0700427/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500428/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500429#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700430macro_rules! peek {
431 ($i:expr, $submac:ident!( $($args:tt)* )) => {
432 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400433 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
434 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700435 }
436 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700437
David Tolnay1f16b602017-02-07 20:06:55 -0500438 ($i:expr, $f:expr) => {
439 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700440 };
441}
442
David Tolnay1f16b602017-02-07 20:06:55 -0500443/// Pattern-match the result of a parser to select which other parser to run.
444///
445/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
446/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
447///
448/// ```rust
449/// extern crate syn;
450/// #[macro_use] extern crate synom;
451///
452/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700453/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500454///
455/// #[derive(Debug)]
456/// enum UnitType {
457/// Struct {
458/// name: Ident,
459/// },
460/// Enum {
461/// name: Ident,
462/// variant: Ident,
463/// },
464/// }
465///
466/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
467/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700468/// which: alt!(
469/// syn!(Struct) => { |_| 0 }
470/// |
471/// syn!(Enum) => { |_| 1 }
472/// ) >>
473/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500474/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700475/// 0 => map!(
476/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500477/// move |_| UnitType::Struct {
478/// name: id,
479/// }
480/// )
481/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700482/// 1 => map!(
483/// braces!(syn!(Ident)),
484/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500485/// name: id,
486/// variant: variant,
487/// }
488/// )
489/// ) >>
490/// (item)
491/// ));
492///
Alex Crichton954046c2017-05-30 21:49:42 -0700493/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500494/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500495#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700496macro_rules! switch {
497 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
498 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400499 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
500 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700501 $(
502 $p => $subrule!(i, $($args2)*),
503 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400504 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700505 }
506 }
507 };
508}
509
Alex Crichton954046c2017-05-30 21:49:42 -0700510
David Tolnay1f16b602017-02-07 20:06:55 -0500511/// Produce the given value without parsing anything. Useful as an argument to
512/// `switch!`.
513///
514/// - **Syntax:** `value!(VALUE)`
515/// - **Output:** `VALUE`
516///
517/// ```rust
518/// extern crate syn;
519/// #[macro_use] extern crate synom;
520///
521/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700522/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500523///
524/// #[derive(Debug)]
525/// enum UnitType {
526/// Struct {
527/// name: Ident,
528/// },
529/// Enum {
530/// name: Ident,
531/// variant: Ident,
532/// },
533/// }
534///
535/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
536/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700537/// which: alt!(
538/// syn!(Struct) => { |_| 0 }
539/// |
540/// syn!(Enum) => { |_| 1 }
541/// ) >>
542/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500543/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700544/// 0 => map!(
545/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500546/// move |_| UnitType::Struct {
547/// name: id,
548/// }
549/// )
550/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700551/// 1 => map!(
552/// braces!(syn!(Ident)),
553/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500554/// name: id,
555/// variant: variant,
556/// }
557/// )
558/// ) >>
559/// (item)
560/// ));
561///
Alex Crichton954046c2017-05-30 21:49:42 -0700562/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500563/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500564#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700565macro_rules! value {
566 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400567 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700568 };
569}
570
David Tolnay1f16b602017-02-07 20:06:55 -0500571/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500572///
David Tolnay1f16b602017-02-07 20:06:55 -0500573/// - **Syntax:** `tuple!(A, B, C, ...)`
574/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500575///
576/// ```rust
577/// extern crate syn;
578/// #[macro_use] extern crate synom;
579///
580/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500581///
Alex Crichton954046c2017-05-30 21:49:42 -0700582/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500583///
Alex Crichton954046c2017-05-30 21:49:42 -0700584/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500585/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500586#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700587macro_rules! tuple {
588 ($i:expr, $($rest:tt)*) => {
589 tuple_parser!($i, (), $($rest)*)
590 };
591}
592
David Tolnay1f16b602017-02-07 20:06:55 -0500593/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500594#[doc(hidden)]
595#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700596macro_rules! tuple_parser {
597 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700598 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700599 };
600
601 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
602 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400603 ::std::result::Result::Err(err) =>
604 ::std::result::Result::Err(err),
605 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700606 tuple_parser!(i, (o), $($rest)*),
607 }
608 };
609
610 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
611 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400612 ::std::result::Result::Err(err) =>
613 ::std::result::Result::Err(err),
614 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700615 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
616 }
617 };
618
619 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700620 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700621 };
622
623 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
624 $submac!($i, $($args)*)
625 };
626
627 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
628 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400629 ::std::result::Result::Err(err) =>
630 ::std::result::Result::Err(err),
631 ::std::result::Result::Ok((i, o)) =>
632 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700633 }
634 };
635
636 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400637 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700638 };
639}
640
David Tolnay1f16b602017-02-07 20:06:55 -0500641/// Run a series of parsers, returning the result of the first one which
642/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500643///
644/// Optionally allows for the result to be transformed.
645///
646/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500647/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500648///
649/// ```rust
650/// extern crate syn;
651/// #[macro_use] extern crate synom;
652///
653/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700654/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500655///
656/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500657/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700658/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500659/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700660/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500661/// )
662/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500663///
Alex Crichton954046c2017-05-30 21:49:42 -0700664/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500665/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500666#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700667macro_rules! alt {
668 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700669 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700670 };
671
672 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
673 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400674 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700675 _ => alt!($i, $($rest)*)
676 }
677 };
678
679 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
680 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400681 ::std::result::Result::Ok((i, o)) =>
682 ::std::result::Result::Ok((i, $gen(o))),
683 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700684 }
685 };
686
687 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700688 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700689 };
690
691 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700692 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700693 };
694
695 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
696 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400697 ::std::result::Result::Ok((i, o)) =>
698 ::std::result::Result::Ok((i, $gen(o))),
699 ::std::result::Result::Err(err) =>
700 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700701 }
702 };
703
704 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700705 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700706 };
707
708 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700709 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700710 };
711}
712
Michael Layzell24645a32017-02-04 13:19:26 -0500713/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500714/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500715///
David Tolnay1f16b602017-02-07 20:06:55 -0500716/// Produces the result of evaluating the final expression in parentheses with
717/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500718///
David Tolnay1f16b602017-02-07 20:06:55 -0500719/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500720/// - **Output:** `RESULT`
721///
722/// ```rust
723/// extern crate syn;
724/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700725/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500726///
727/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700728/// use synom::tokens::{Bang, Paren};
729/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500730///
David Tolnay1f16b602017-02-07 20:06:55 -0500731/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700732/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
733/// name: syn!(Ident) >>
734/// syn!(Bang) >>
735/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500736/// (name, body)
737/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500738///
Alex Crichton954046c2017-05-30 21:49:42 -0700739/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500740/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500741#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700742macro_rules! do_parse {
743 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400744 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700745 };
746
747 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700748 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700749 };
750
751 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
752 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400753 ::std::result::Result::Err(err) =>
754 ::std::result::Result::Err(err),
755 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700756 do_parse!(i, $($rest)*),
757 }
758 };
759
760 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700761 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700762 };
763
764 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
765 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400766 ::std::result::Result::Err(err) =>
767 ::std::result::Result::Err(err),
768 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700769 let $field = o;
770 do_parse!(i, $($rest)*)
771 },
772 }
773 };
774
David Tolnayfa0edf22016-09-23 22:58:24 -0700775 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700776 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700777 };
778
779 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
780 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400781 ::std::result::Result::Err(err) =>
782 ::std::result::Result::Err(err),
783 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700784 let mut $field = o;
785 do_parse!(i, $($rest)*)
786 },
787 }
788 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700789}
Michael Layzell416724e2017-05-24 21:12:34 -0400790
791#[macro_export]
792macro_rules! input_end {
793 ($i:expr,) => {
794 $crate::input_end($i)
795 };
796}
797
798// Not a public API
799#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400800pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell416724e2017-05-24 21:12:34 -0400801 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400802 Ok((&[], ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400803 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400804 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400805 }
806}