blob: e8ad32a76fed9a3d850d4bc3e6f109e0ddf80aeb [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
David Tolnayc7a5d3d2017-06-04 12:11:05 -070024extern crate proc_macro;
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
Alex Crichtonccbb45d2017-05-23 10:58:24 -070037#[cfg(feature = "parsing")]
David Tolnay5fe14fc2017-01-27 16:22:08 -080038#[doc(hidden)]
39pub mod helper;
Michael Layzell5bde96f2017-01-24 17:59:21 -050040
Alex Crichtonccbb45d2017-05-23 10:58:24 -070041pub mod delimited;
Alex Crichton7b9e02f2017-05-30 15:54:33 -070042pub mod tokens;
43pub mod span;
Michael Layzell2a60e252017-05-31 21:36:47 -040044pub mod cursor;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070045
Michael Layzell0a1a6632017-06-02 18:07:43 -040046pub use cursor::{SynomBuffer, Cursor};
David Tolnayb5a7b142016-09-13 22:46:39 -070047
Michael Layzell760fd662017-05-31 22:46:05 -040048/// The result of a parser
49pub type PResult<'a, O> = Result<(Cursor<'a>, O), ParseError>;
50
51/// An error with a default error message.
52///
53/// NOTE: We should provide better error messages in the future.
54pub fn parse_error<O>() -> PResult<'static, O> {
Michael Layzellad763b72017-06-01 00:25:31 -040055 Err(ParseError(None))
David Tolnayf2222f02017-01-27 17:09:20 -080056}
57
Alex Crichton7b9e02f2017-05-30 15:54:33 -070058pub trait Synom: Sized {
Michael Layzell760fd662017-05-31 22:46:05 -040059 fn parse(input: Cursor) -> PResult<Self>;
Alex Crichton954046c2017-05-30 21:49:42 -070060
61 fn description() -> Option<&'static str> {
62 None
63 }
Alex Crichton954046c2017-05-30 21:49:42 -070064}
65
66#[derive(Debug)]
Michael Layzellad763b72017-06-01 00:25:31 -040067pub struct ParseError(Option<String>);
Alex Crichton954046c2017-05-30 21:49:42 -070068
69impl Error for ParseError {
70 fn description(&self) -> &str {
Michael Layzellad763b72017-06-01 00:25:31 -040071 match self.0 {
72 Some(ref desc) => desc,
73 None => "failed to parse",
74 }
Alex Crichton954046c2017-05-30 21:49:42 -070075 }
76}
77
78impl fmt::Display for ParseError {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Michael Layzellad763b72017-06-01 00:25:31 -040080 <str as fmt::Display>::fmt(self.description(), f)
Alex Crichton954046c2017-05-30 21:49:42 -070081 }
82}
83
David Tolnayc7a5d3d2017-06-04 12:11:05 -070084impl From<proc_macro2::LexError> for ParseError {
85 fn from(_: proc_macro2::LexError) -> ParseError {
Michael Layzellad763b72017-06-01 00:25:31 -040086 ParseError(Some("error while lexing input string".to_owned()))
Alex Crichton954046c2017-05-30 21:49:42 -070087 }
88}
89
David Tolnayc7a5d3d2017-06-04 12:11:05 -070090impl From<proc_macro::LexError> for ParseError {
91 fn from(_: proc_macro::LexError) -> ParseError {
92 ParseError(Some("error while lexing input string".to_owned()))
93 }
94}
95
96impl ParseError {
97 // For syn use only. Not public API.
98 #[doc(hidden)]
99 pub fn new<T: Into<String>>(msg: T) -> Self {
100 ParseError(Some(msg.into()))
101 }
102}
103
Alex Crichton954046c2017-05-30 21:49:42 -0700104impl Synom for TokenStream {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400105 fn parse(input: Cursor) -> PResult<Self> {
106 Ok((Cursor::empty(), input.token_stream()))
Alex Crichton954046c2017-05-30 21:49:42 -0700107 }
Alex Crichton7b9e02f2017-05-30 15:54:33 -0700108}
109
Michael Layzell24645a32017-02-04 13:19:26 -0500110/// Define a function from a parser combination.
111///
David Tolnay1f16b602017-02-07 20:06:55 -0500112/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
113///
114/// ```rust
115/// # extern crate syn;
116/// # #[macro_use] extern crate synom;
117/// # use syn::Ty;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700118/// # use synom::delimited::Delimited;
David Tolnay1f16b602017-02-07 20:06:55 -0500119/// // One or more Rust types separated by commas.
David Tolnayf8db7ba2017-11-11 22:52:16 -0800120/// named!(pub comma_separated_types -> Delimited<Ty, Token![,]>,
Alex Crichton954046c2017-05-30 21:49:42 -0700121/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500122/// );
123/// # fn main() {}
124/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500125#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700126macro_rules! named {
127 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400128 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700129 $submac!(i, $($args)*)
130 }
131 };
132
133 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400134 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700135 $submac!(i, $($args)*)
136 }
137 };
Michael Layzellf8334e32017-06-04 19:01:08 -0400138
139 // These two variants are for defining named parsers which have custom
140 // arguments, and are called with `call!()`
141 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
142 fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
143 $submac!(i, $($args)*)
144 }
145 };
146
147 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
148 pub fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
149 $submac!(i, $($args)*)
150 }
151 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700152}
153
David Tolnay1f16b602017-02-07 20:06:55 -0500154/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500155///
156/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500157///
Michael Layzell760fd662017-05-31 22:46:05 -0400158/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500159/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500160#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700161macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700162 ($i:expr, $fun:expr $(, $args:expr)*) => {
163 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700164 };
165}
166
David Tolnay1f16b602017-02-07 20:06:55 -0500167/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500168///
David Tolnay1f16b602017-02-07 20:06:55 -0500169/// - **Syntax:** `map!(THING, FN)`
170/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500171///
172/// ```rust
173/// extern crate syn;
174/// #[macro_use] extern crate synom;
175///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700176/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500177///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700178/// fn get_cond(if_: ExprIf) -> Expr {
179/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500180/// }
181///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700182/// // Parses an `if` statement but returns the condition part only.
183/// named!(if_condition -> Expr,
184/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500185/// );
186///
187/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700188/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700189/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500190/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700191/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700192/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500193/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500194#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700195macro_rules! map {
196 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700197 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400198 ::std::result::Result::Err(err) =>
199 ::std::result::Result::Err(err),
200 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700201 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700202 }
203 };
David Tolnay1f16b602017-02-07 20:06:55 -0500204
205 ($i:expr, $f:expr, $g:expr) => {
206 map!($i, call!($f), $g)
207 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700208}
209
David Tolnaybc7d7d92017-06-03 20:54:05 -0700210// Somehow this helps with type inference in `map!`.
211//
212// Not public API.
213#[doc(hidden)]
214pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
215 f(t)
216}
217
David Tolnay1f16b602017-02-07 20:06:55 -0500218/// Parses successfully if the given parser fails to parse. Does not consume any
219/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500220///
221/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500222/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500223#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700224macro_rules! not {
225 ($i:expr, $submac:ident!( $($args:tt)* )) => {
226 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400227 ::std::result::Result::Ok(_) => $crate::parse_error(),
228 ::std::result::Result::Err(_) =>
229 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700230 }
231 };
232}
233
David Tolnay1f16b602017-02-07 20:06:55 -0500234/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500235///
David Tolnay1f16b602017-02-07 20:06:55 -0500236/// If you are familiar with nom, this is nom's `cond_with_error` parser.
237///
238/// - **Syntax:** `cond!(CONDITION, THING)`
239/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500240#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700241macro_rules! cond {
242 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
243 if $cond {
244 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400245 ::std::result::Result::Ok((i, o)) =>
246 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
247 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700248 }
249 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400250 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700251 }
David Tolnaycfe55022016-10-02 22:02:27 -0700252 };
253
254 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700255 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700256 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700257}
258
David Tolnay1f16b602017-02-07 20:06:55 -0500259/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500260///
David Tolnay1f16b602017-02-07 20:06:55 -0500261/// This is typically used inside of `option!` or `alt!`.
262///
263/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
264/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500265#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700266macro_rules! cond_reduce {
267 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
268 if $cond {
269 $submac!($i, $($args)*)
270 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400271 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700272 }
273 };
274
275 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700276 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700277 };
278}
279
David Tolnay1f16b602017-02-07 20:06:55 -0500280/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500281///
David Tolnay1f16b602017-02-07 20:06:55 -0500282/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500283/// - **Output:** `THING`
284///
285/// ```rust
286/// extern crate syn;
287/// #[macro_use] extern crate synom;
288///
289/// use syn::Expr;
Michael Layzell24645a32017-02-04 13:19:26 -0500290///
291/// // An expression terminated by ##.
292/// named!(expr_pound_pound -> Expr,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800293/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
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 {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400350 if input.eof() {
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)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400362 if i == input {
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 {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400390 if input.eof() {
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)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400400 if i == input {
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};
David Tolnay1f16b602017-02-07 20:06:55 -0500453///
454/// #[derive(Debug)]
455/// enum UnitType {
456/// Struct {
457/// name: Ident,
458/// },
459/// Enum {
460/// name: Ident,
461/// variant: Ident,
462/// },
463/// }
464///
465/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
466/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700467/// which: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800468/// keyword!(struct) => { |_| 0 }
Alex Crichton954046c2017-05-30 21:49:42 -0700469/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800470/// keyword!(enum) => { |_| 1 }
Alex Crichton954046c2017-05-30 21:49:42 -0700471/// ) >>
472/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500473/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700474/// 0 => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800475/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500476/// move |_| UnitType::Struct {
477/// name: id,
478/// }
479/// )
480/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700481/// 1 => map!(
482/// braces!(syn!(Ident)),
483/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500484/// name: id,
485/// variant: variant,
486/// }
487/// )
David Tolnay92a56512017-11-10 00:02:14 -0800488/// |
489/// _ => reject!()
David Tolnay1f16b602017-02-07 20:06:55 -0500490/// ) >>
491/// (item)
492/// ));
493///
Alex Crichton954046c2017-05-30 21:49:42 -0700494/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500495/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500496#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700497macro_rules! switch {
498 ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
499 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400500 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
501 ::std::result::Result::Ok((i, o)) => match o {
David Tolnayb5a7b142016-09-13 22:46:39 -0700502 $(
503 $p => $subrule!(i, $($args2)*),
504 )*
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///
David Tolnay92a56512017-11-10 00:02:14 -0800521/// use syn::Ident;
David Tolnay1f16b602017-02-07 20:06:55 -0500522///
523/// #[derive(Debug)]
524/// enum UnitType {
525/// Struct {
526/// name: Ident,
527/// },
528/// Enum {
529/// name: Ident,
530/// variant: Ident,
531/// },
532/// }
533///
534/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
535/// named!(unit_type -> UnitType, do_parse!(
David Tolnay92a56512017-11-10 00:02:14 -0800536/// is_struct: alt!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800537/// keyword!(struct) => { |_| true }
Alex Crichton954046c2017-05-30 21:49:42 -0700538/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800539/// keyword!(enum) => { |_| false }
Alex Crichton954046c2017-05-30 21:49:42 -0700540/// ) >>
541/// id: syn!(Ident) >>
David Tolnay92a56512017-11-10 00:02:14 -0800542/// item: switch!(value!(is_struct),
543/// true => map!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800544/// punct!(;),
David Tolnay1f16b602017-02-07 20:06:55 -0500545/// move |_| UnitType::Struct {
546/// name: id,
547/// }
548/// )
549/// |
David Tolnay92a56512017-11-10 00:02:14 -0800550/// false => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700551/// braces!(syn!(Ident)),
552/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500553/// name: id,
554/// variant: variant,
555/// }
556/// )
557/// ) >>
558/// (item)
559/// ));
560///
Alex Crichton954046c2017-05-30 21:49:42 -0700561/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500562/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500563#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700564macro_rules! value {
565 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400566 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700567 };
568}
569
David Tolnay92a56512017-11-10 00:02:14 -0800570/// Unconditionally fail to parse anything. This may be useful in ignoring some
571/// arms of a `switch!` parser.
572///
573/// - **Syntax:** `reject!()`
574/// - **Output:** never succeeds
575///
576/// ```rust
577/// extern crate syn;
578/// #[macro_use] extern crate synom;
579///
580/// use syn::Item;
581///
582/// // Parse any item, except for a module.
583/// named!(almost_any_item -> Item,
584/// switch!(syn!(Item),
585/// Item::Mod(_) => reject!()
586/// |
587/// ok => value!(ok)
588/// )
589/// );
590///
591/// # fn main() {}
592/// ```
593#[macro_export]
594macro_rules! reject {
595 ($i:expr,) => {
596 $crate::parse_error()
597 }
598}
599
David Tolnay1f16b602017-02-07 20:06:55 -0500600/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500601///
David Tolnay1f16b602017-02-07 20:06:55 -0500602/// - **Syntax:** `tuple!(A, B, C, ...)`
603/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500604///
605/// ```rust
606/// extern crate syn;
607/// #[macro_use] extern crate synom;
608///
609/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500610///
Alex Crichton954046c2017-05-30 21:49:42 -0700611/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500612///
Alex Crichton954046c2017-05-30 21:49:42 -0700613/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500614/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500615#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700616macro_rules! tuple {
617 ($i:expr, $($rest:tt)*) => {
618 tuple_parser!($i, (), $($rest)*)
619 };
620}
621
David Tolnay1f16b602017-02-07 20:06:55 -0500622/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500623#[doc(hidden)]
624#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700625macro_rules! tuple_parser {
626 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700627 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700628 };
629
630 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
631 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400632 ::std::result::Result::Err(err) =>
633 ::std::result::Result::Err(err),
634 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700635 tuple_parser!(i, (o), $($rest)*),
636 }
637 };
638
639 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
640 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400641 ::std::result::Result::Err(err) =>
642 ::std::result::Result::Err(err),
643 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700644 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
645 }
646 };
647
648 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700649 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700650 };
651
652 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
653 $submac!($i, $($args)*)
654 };
655
656 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
657 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400658 ::std::result::Result::Err(err) =>
659 ::std::result::Result::Err(err),
660 ::std::result::Result::Ok((i, o)) =>
661 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700662 }
663 };
664
665 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400666 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700667 };
668}
669
David Tolnay1f16b602017-02-07 20:06:55 -0500670/// Run a series of parsers, returning the result of the first one which
671/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500672///
673/// Optionally allows for the result to be transformed.
674///
675/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500676/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500677///
678/// ```rust
679/// extern crate syn;
680/// #[macro_use] extern crate synom;
681///
682/// use syn::Ident;
Michael Layzell24645a32017-02-04 13:19:26 -0500683///
684/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500685/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700686/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500687/// |
David Tolnayf8db7ba2017-11-11 22:52:16 -0800688/// punct!(!) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500689/// )
690/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500691///
Alex Crichton954046c2017-05-30 21:49:42 -0700692/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500693/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500694#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700695macro_rules! alt {
696 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700697 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700698 };
699
700 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
701 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400702 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700703 _ => alt!($i, $($rest)*)
704 }
705 };
706
707 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
708 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400709 ::std::result::Result::Ok((i, o)) =>
710 ::std::result::Result::Ok((i, $gen(o))),
711 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700712 }
713 };
714
715 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700716 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700717 };
718
719 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700720 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700721 };
722
723 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
724 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400725 ::std::result::Result::Ok((i, o)) =>
726 ::std::result::Result::Ok((i, $gen(o))),
727 ::std::result::Result::Err(err) =>
728 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700729 }
730 };
731
732 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700733 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700734 };
735
736 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700737 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700738 };
739}
740
Michael Layzell24645a32017-02-04 13:19:26 -0500741/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500742/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500743///
David Tolnay1f16b602017-02-07 20:06:55 -0500744/// Produces the result of evaluating the final expression in parentheses with
745/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500746///
David Tolnay1f16b602017-02-07 20:06:55 -0500747/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500748/// - **Output:** `RESULT`
749///
750/// ```rust
751/// extern crate syn;
752/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700753/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500754///
755/// use syn::{Ident, TokenTree};
David Tolnayf8db7ba2017-11-11 22:52:16 -0800756/// use synom::tokens::Paren;
Alex Crichton954046c2017-05-30 21:49:42 -0700757/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500758///
David Tolnay1f16b602017-02-07 20:06:55 -0500759/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700760/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
761/// name: syn!(Ident) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800762/// punct!(!) >>
Alex Crichton954046c2017-05-30 21:49:42 -0700763/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500764/// (name, body)
765/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500766///
Alex Crichton954046c2017-05-30 21:49:42 -0700767/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500768/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500769#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700770macro_rules! do_parse {
771 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400772 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700773 };
774
775 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700776 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700777 };
778
779 ($i:expr, $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, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700784 do_parse!(i, $($rest)*),
785 }
786 };
787
788 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700789 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700790 };
791
792 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
793 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400794 ::std::result::Result::Err(err) =>
795 ::std::result::Result::Err(err),
796 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700797 let $field = o;
798 do_parse!(i, $($rest)*)
799 },
800 }
801 };
802
David Tolnayfa0edf22016-09-23 22:58:24 -0700803 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700804 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700805 };
806
807 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
808 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400809 ::std::result::Result::Err(err) =>
810 ::std::result::Result::Err(err),
811 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700812 let mut $field = o;
813 do_parse!(i, $($rest)*)
814 },
815 }
816 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700817}
Michael Layzell416724e2017-05-24 21:12:34 -0400818
819#[macro_export]
820macro_rules! input_end {
821 ($i:expr,) => {
822 $crate::input_end($i)
823 };
824}
825
826// Not a public API
827#[doc(hidden)]
David Tolnay1fc4e492017-11-11 22:17:22 -0800828pub fn input_end(input: Cursor) -> PResult<'static, ()> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400829 if input.eof() {
David Tolnay1fc4e492017-11-11 22:17:22 -0800830 Ok((Cursor::empty(), ()))
Michael Layzell416724e2017-05-24 21:12:34 -0400831 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400832 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400833 }
834}