blob: 8b57b3dd193dc0852aa439f63f8f8689eefc1ec1 [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> {
Michael Layzellad763b72017-06-01 00:25:31 -040060 Err(ParseError(None))
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<_>>();
Michael Layzellad763b72017-06-01 00:25:31 -040072 let result = Self::parse(&tokens);
73 let err = match result {
Michael Layzell760fd662017-05-31 22:46:05 -040074 Ok((rest, t)) => {
Alex Crichton954046c2017-05-30 21:49:42 -070075 if rest.is_empty() {
76 return Ok(t)
77 } else if rest.len() == tokens.len() {
78 // parsed nothing
79 "failed to parse"
80 } else {
81 "unparsed tokens after"
82 }
83 }
Michael Layzellad763b72017-06-01 00:25:31 -040084 Err(ref err) => err.description(),
Alex Crichton954046c2017-05-30 21:49:42 -070085 };
86 match Self::description() {
Michael Layzellad763b72017-06-01 00:25:31 -040087 Some(s) => Err(ParseError(Some(format!("{} {}", err, s)))),
88 None => Err(ParseError(Some(err.to_string()))),
Alex Crichton954046c2017-05-30 21:49:42 -070089 }
90 }
91
92 fn parse_str_all(input: &str) -> Result<Self, ParseError> {
93 Self::parse_all(input.parse()?)
94 }
95
96 fn parse_all_unwrap(input: TokenStream) -> Self {
97 // TODO: eventually try to provide super nice error messages here as
98 // this is what most users will hit. Hopefully the compiler will give us
99 // an interface one day to give an extra-good error message here.
100 Self::parse_all(input).unwrap()
101 }
102}
103
104#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -0400105pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -0700106
107impl Error for ParseError {
108 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -0400109 match self.0 {
110 Some(ref desc) => desc,
111 None => "failed to parse",
112 }
Alex Crichton954046c2017-05-30 21:49:42 -0700113 }
114}
115
116impl fmt::Display for ParseError {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -0400118 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -0700119 }
120}
121
122impl From<LexError> for ParseError {
123 fn from(_: LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -0400124 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -0700125 }
126}
127
128impl Synom for TokenStream {
Michael Layzell760fd662017-05-31 22:46:05 -0400129 fn parse(input: &[TokenTree]) -> PResult<Self> {
130 Ok((&[], input.iter().cloned().collect()))
Alex Crichton954046c2017-05-30 21:49:42 -0700131 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700132}
133
Michael Layzell24645a32017-02-04 13:19:26 -0500134/// Define a function from a parser combination.
135///
David Tolnay1f16b602017-02-07 20:06:55 -0500136/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
137///
138/// ```rust
139/// # extern crate syn;
140/// # #[macro_use] extern crate synom;
141/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700142/// # use synom::delimited::Delimited;
Alex Crichton954046c2017-05-30 21:49:42 -0700143/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500144/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700145/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
146/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500147/// );
148/// # fn main() {}
149/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500150#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700151macro_rules! named {
152 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400153 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700154 $submac!(i, $($args)*)
155 }
156 };
157
158 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400159 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700160 $submac!(i, $($args)*)
161 }
162 };
163}
164
David Tolnay1f16b602017-02-07 20:06:55 -0500165/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500166///
167/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500168///
Michael Layzell760fd662017-05-31 22:46:05 -0400169/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500170/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500171#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700172macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700173 ($i:expr, $fun:expr $(, $args:expr)*) => {
174 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700175 };
176}
177
David Tolnay1f16b602017-02-07 20:06:55 -0500178/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500179///
David Tolnay1f16b602017-02-07 20:06:55 -0500180/// - **Syntax:** `map!(THING, FN)`
181/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500182///
183/// ```rust
184/// extern crate syn;
185/// #[macro_use] extern crate synom;
186///
187/// use syn::{Item, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500188///
189/// fn get_item_ident(item: Item) -> Ident {
190/// item.ident
191/// }
192///
David Tolnay1f16b602017-02-07 20:06:55 -0500193/// // Parses an item and returns the name (identifier) of the item only.
194/// named!(item_ident -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700195/// map!(syn!(Item), get_item_ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500196/// );
197///
198/// // Or equivalently:
199/// named!(item_ident2 -> Ident,
Alex Crichton954046c2017-05-30 21:49:42 -0700200/// map!(syn!(Item), |i: Item| i.ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500201/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500202///
Alex Crichton954046c2017-05-30 21:49:42 -0700203/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500204/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500205#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700206macro_rules! map {
207 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700208 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400209 ::std::result::Result::Err(err) =>
210 ::std::result::Result::Err(err),
211 ::std::result::Result::Ok((i, o)) =>
212 ::std::result::Result::Ok((i, call!(o, $g))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700213 }
214 };
David Tolnay1f16b602017-02-07 20:06:55 -0500215
216 ($i:expr, $f:expr, $g:expr) => {
217 map!($i, call!($f), $g)
218 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700219}
220
David Tolnay1f16b602017-02-07 20:06:55 -0500221/// Parses successfully if the given parser fails to parse. Does not consume any
222/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500223///
224/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500225/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500226#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700227macro_rules! not {
228 ($i:expr, $submac:ident!( $($args:tt)* )) => {
229 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400230 ::std::result::Result::Ok(_) => $crate::parse_error(),
231 ::std::result::Result::Err(_) =>
232 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700233 }
234 };
235}
236
David Tolnay1f16b602017-02-07 20:06:55 -0500237/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500238///
David Tolnay1f16b602017-02-07 20:06:55 -0500239/// If you are familiar with nom, this is nom's `cond_with_error` parser.
240///
241/// - **Syntax:** `cond!(CONDITION, THING)`
242/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500243#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700244macro_rules! cond {
245 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
246 if $cond {
247 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400248 ::std::result::Result::Ok((i, o)) =>
249 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
250 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700251 }
252 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400253 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700254 }
David Tolnaycfe55022016-10-02 22:02:27 -0700255 };
256
257 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700258 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700259 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700260}
261
David Tolnay1f16b602017-02-07 20:06:55 -0500262/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500263///
David Tolnay1f16b602017-02-07 20:06:55 -0500264/// This is typically used inside of `option!` or `alt!`.
265///
266/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
267/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500268#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700269macro_rules! cond_reduce {
270 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
271 if $cond {
272 $submac!($i, $($args)*)
273 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400274 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700275 }
276 };
277
278 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700279 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700280 };
281}
282
David Tolnay1f16b602017-02-07 20:06:55 -0500283/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500284///
David Tolnay1f16b602017-02-07 20:06:55 -0500285/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500286/// - **Output:** `THING`
287///
288/// ```rust
289/// extern crate syn;
290/// #[macro_use] extern crate synom;
291///
292/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700293/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500294///
295/// // An expression terminated by ##.
296/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700297/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500298/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500299///
Alex Crichton954046c2017-05-30 21:49:42 -0700300/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500301/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500302#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700303macro_rules! terminated {
304 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
305 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400306 ::std::result::Result::Ok((i, (o, _))) =>
307 ::std::result::Result::Ok((i, o)),
308 ::std::result::Result::Err(err) =>
309 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700310 }
311 };
312
313 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700314 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700315 };
316
317 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700318 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700319 };
320
321 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700322 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700323 };
324}
325
David Tolnay1f16b602017-02-07 20:06:55 -0500326/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500327///
328/// - **Syntax:** `many0!(THING)`
329/// - **Output:** `Vec<THING>`
330///
David Tolnay1f16b602017-02-07 20:06:55 -0500331/// You may also be looking for:
332///
Alex Crichton954046c2017-05-30 21:49:42 -0700333/// - `call!(Delimited::parse_separated)` - zero or more values with separator
334/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
335/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500336///
Michael Layzell24645a32017-02-04 13:19:26 -0500337/// ```rust
338/// extern crate syn;
339/// #[macro_use] extern crate synom;
340///
341/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500342///
Alex Crichton954046c2017-05-30 21:49:42 -0700343/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500344///
Alex Crichton954046c2017-05-30 21:49:42 -0700345/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500346#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700347macro_rules! many0 {
348 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
349 let ret;
350 let mut res = ::std::vec::Vec::new();
351 let mut input = $i;
352
353 loop {
354 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400355 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700356 break;
357 }
358
359 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400360 ::std::result::Result::Err(_) => {
361 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700362 break;
363 }
Michael Layzell760fd662017-05-31 22:46:05 -0400364 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700365 // loop trip must always consume (otherwise infinite loops)
David Tolnaybc84d5a2016-10-08 13:20:57 -0700366 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400367 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700368 break;
369 }
370
371 res.push(o);
372 input = i;
373 }
374 }
375 }
376
377 ret
378 }};
379
380 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500381 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700382 };
383}
384
David Tolnay1f16b602017-02-07 20:06:55 -0500385// Improve compile time by compiling this loop only once per type it is used
386// with.
387//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800388// Not public API.
389#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400390pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700391 let mut res = Vec::new();
392
393 loop {
394 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400395 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700396 }
397
398 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400399 Err(_) => {
400 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700401 }
Michael Layzell760fd662017-05-31 22:46:05 -0400402 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700403 // loop trip must always consume (otherwise infinite loops)
404 if i.len() == input.len() {
Michael Layzell760fd662017-05-31 22:46:05 -0400405 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700406 }
407
408 res.push(o);
409 input = i;
410 }
411 }
412 }
413}
414
David Tolnay1f16b602017-02-07 20:06:55 -0500415/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500416///
417/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500418/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500419///
420/// ```rust
421/// extern crate syn;
422/// #[macro_use] extern crate synom;
423///
Alex Crichton954046c2017-05-30 21:49:42 -0700424/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500425///
David Tolnay1f16b602017-02-07 20:06:55 -0500426/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700427/// named!(ident_expr -> (Ident, Expr),
428/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500429/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500430///
Alex Crichton954046c2017-05-30 21:49:42 -0700431/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500432/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500433#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700434macro_rules! peek {
435 ($i:expr, $submac:ident!( $($args:tt)* )) => {
436 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400437 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
438 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700439 }
440 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700441
David Tolnay1f16b602017-02-07 20:06:55 -0500442 ($i:expr, $f:expr) => {
443 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700444 };
445}
446
David Tolnay1f16b602017-02-07 20:06:55 -0500447/// Pattern-match the result of a parser to select which other parser to run.
448///
449/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
450/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
451///
452/// ```rust
453/// extern crate syn;
454/// #[macro_use] extern crate synom;
455///
456/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700457/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500458///
459/// #[derive(Debug)]
460/// enum UnitType {
461/// Struct {
462/// name: Ident,
463/// },
464/// Enum {
465/// name: Ident,
466/// variant: Ident,
467/// },
468/// }
469///
470/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
471/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700472/// which: alt!(
473/// syn!(Struct) => { |_| 0 }
474/// |
475/// syn!(Enum) => { |_| 1 }
476/// ) >>
477/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500478/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700479/// 0 => map!(
480/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500481/// move |_| UnitType::Struct {
482/// name: id,
483/// }
484/// )
485/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700486/// 1 => map!(
487/// braces!(syn!(Ident)),
488/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500489/// name: id,
490/// variant: variant,
491/// }
492/// )
493/// ) >>
494/// (item)
495/// ));
496///
Alex Crichton954046c2017-05-30 21:49:42 -0700497/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500498/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500499#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700500macro_rules! switch {
501 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
502 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400503 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
504 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700505 $(
506 $p => $subrule!(i, $($args2)*),
507 )*
Michael Layzell760fd662017-05-31 22:46:05 -0400508 _ => $crate::parse_error(),
David Tolnayb5a7b142016-09-13 22:46:39 -0700509 }
510 }
511 };
512}
513
Alex Crichton954046c2017-05-30 21:49:42 -0700514
David Tolnay1f16b602017-02-07 20:06:55 -0500515/// Produce the given value without parsing anything. Useful as an argument to
516/// `switch!`.
517///
518/// - **Syntax:** `value!(VALUE)`
519/// - **Output:** `VALUE`
520///
521/// ```rust
522/// extern crate syn;
523/// #[macro_use] extern crate synom;
524///
525/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700526/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500527///
528/// #[derive(Debug)]
529/// enum UnitType {
530/// Struct {
531/// name: Ident,
532/// },
533/// Enum {
534/// name: Ident,
535/// variant: Ident,
536/// },
537/// }
538///
539/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
540/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700541/// which: alt!(
542/// syn!(Struct) => { |_| 0 }
543/// |
544/// syn!(Enum) => { |_| 1 }
545/// ) >>
546/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500547/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700548/// 0 => map!(
549/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500550/// move |_| UnitType::Struct {
551/// name: id,
552/// }
553/// )
554/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700555/// 1 => map!(
556/// braces!(syn!(Ident)),
557/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500558/// name: id,
559/// variant: variant,
560/// }
561/// )
562/// ) >>
563/// (item)
564/// ));
565///
Alex Crichton954046c2017-05-30 21:49:42 -0700566/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500567/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500568#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700569macro_rules! value {
570 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400571 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700572 };
573}
574
David Tolnay1f16b602017-02-07 20:06:55 -0500575/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500576///
David Tolnay1f16b602017-02-07 20:06:55 -0500577/// - **Syntax:** `tuple!(A, B, C, ...)`
578/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500579///
580/// ```rust
581/// extern crate syn;
582/// #[macro_use] extern crate synom;
583///
584/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500585///
Alex Crichton954046c2017-05-30 21:49:42 -0700586/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500587///
Alex Crichton954046c2017-05-30 21:49:42 -0700588/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500589/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500590#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700591macro_rules! tuple {
592 ($i:expr, $($rest:tt)*) => {
593 tuple_parser!($i, (), $($rest)*)
594 };
595}
596
David Tolnay1f16b602017-02-07 20:06:55 -0500597/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500598#[doc(hidden)]
599#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700600macro_rules! tuple_parser {
601 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700602 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700603 };
604
605 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
606 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400607 ::std::result::Result::Err(err) =>
608 ::std::result::Result::Err(err),
609 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700610 tuple_parser!(i, (o), $($rest)*),
611 }
612 };
613
614 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
615 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400616 ::std::result::Result::Err(err) =>
617 ::std::result::Result::Err(err),
618 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700619 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
620 }
621 };
622
623 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700624 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700625 };
626
627 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
628 $submac!($i, $($args)*)
629 };
630
631 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
632 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400633 ::std::result::Result::Err(err) =>
634 ::std::result::Result::Err(err),
635 ::std::result::Result::Ok((i, o)) =>
636 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700637 }
638 };
639
640 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400641 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700642 };
643}
644
David Tolnay1f16b602017-02-07 20:06:55 -0500645/// Run a series of parsers, returning the result of the first one which
646/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500647///
648/// Optionally allows for the result to be transformed.
649///
650/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500651/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500652///
653/// ```rust
654/// extern crate syn;
655/// #[macro_use] extern crate synom;
656///
657/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700658/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500659///
660/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500661/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700662/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500663/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700664/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500665/// )
666/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500667///
Alex Crichton954046c2017-05-30 21:49:42 -0700668/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500669/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500670#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700671macro_rules! alt {
672 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700673 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700674 };
675
676 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
677 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400678 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700679 _ => alt!($i, $($rest)*)
680 }
681 };
682
683 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
684 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400685 ::std::result::Result::Ok((i, o)) =>
686 ::std::result::Result::Ok((i, $gen(o))),
687 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700688 }
689 };
690
691 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700692 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700693 };
694
695 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700696 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700697 };
698
699 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
700 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400701 ::std::result::Result::Ok((i, o)) =>
702 ::std::result::Result::Ok((i, $gen(o))),
703 ::std::result::Result::Err(err) =>
704 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700705 }
706 };
707
708 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700709 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700710 };
711
712 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700713 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700714 };
715}
716
Michael Layzell24645a32017-02-04 13:19:26 -0500717/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500718/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500719///
David Tolnay1f16b602017-02-07 20:06:55 -0500720/// Produces the result of evaluating the final expression in parentheses with
721/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500722///
David Tolnay1f16b602017-02-07 20:06:55 -0500723/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500724/// - **Output:** `RESULT`
725///
726/// ```rust
727/// extern crate syn;
728/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700729/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500730///
731/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700732/// use synom::tokens::{Bang, Paren};
733/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500734///
David Tolnay1f16b602017-02-07 20:06:55 -0500735/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700736/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
737/// name: syn!(Ident) >>
738/// syn!(Bang) >>
739/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500740/// (name, body)
741/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500742///
Alex Crichton954046c2017-05-30 21:49:42 -0700743/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500744/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500745#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700746macro_rules! do_parse {
747 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400748 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700749 };
750
751 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700752 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700753 };
754
755 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
756 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400757 ::std::result::Result::Err(err) =>
758 ::std::result::Result::Err(err),
759 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700760 do_parse!(i, $($rest)*),
761 }
762 };
763
764 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700765 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700766 };
767
768 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
769 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400770 ::std::result::Result::Err(err) =>
771 ::std::result::Result::Err(err),
772 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700773 let $field = o;
774 do_parse!(i, $($rest)*)
775 },
776 }
777 };
778
David Tolnayfa0edf22016-09-23 22:58:24 -0700779 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700780 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700781 };
782
783 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
784 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400785 ::std::result::Result::Err(err) =>
786 ::std::result::Result::Err(err),
787 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700788 let mut $field = o;
789 do_parse!(i, $($rest)*)
790 },
791 }
792 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700793}
Michael Layzell416724e2017-05-24 21:12:34 -0400794
795#[macro_export]
796macro_rules! input_end {
797 ($i:expr,) => {
798 $crate::input_end($i)
799 };
800}
801
802// Not a public API
803#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400804pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell416724e2017-05-24 21:12:34 -0400805 if input.is_empty() {
Michael Layzell760fd662017-05-31 22:46:05 -0400806 Ok((&[], ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400807 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400808 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400809 }
810}