blob: 9b5fafbf8b4ed59c5bd911ecc9bbeb78283dcaf5 [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;
Alex Crichton954046c2017-05-30 21:49:42 -0700119/// # use synom::tokens::Comma;
David Tolnay1f16b602017-02-07 20:06:55 -0500120/// // One or more Rust types separated by commas.
Alex Crichton954046c2017-05-30 21:49:42 -0700121/// named!(pub comma_separated_types -> Delimited<Ty, Comma>,
122/// call!(Delimited::parse_separated_nonempty)
David Tolnay1f16b602017-02-07 20:06:55 -0500123/// );
124/// # fn main() {}
125/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500126#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700127macro_rules! named {
128 ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400129 fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700130 $submac!(i, $($args)*)
131 }
132 };
133
134 (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400135 pub fn $name(i: $crate::Cursor) -> $crate::PResult<$o> {
David Tolnayb5a7b142016-09-13 22:46:39 -0700136 $submac!(i, $($args)*)
137 }
138 };
Michael Layzellf8334e32017-06-04 19:01:08 -0400139
140 // These two variants are for defining named parsers which have custom
141 // arguments, and are called with `call!()`
142 ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
143 fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
144 $submac!(i, $($args)*)
145 }
146 };
147
148 (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
149 pub fn $name(i: $crate::Cursor, $($params)*) -> $crate::PResult<$o> {
150 $submac!(i, $($args)*)
151 }
152 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700153}
154
David Tolnay1f16b602017-02-07 20:06:55 -0500155/// Invoke the given parser function with the passed in arguments.
Michael Layzell24645a32017-02-04 13:19:26 -0500156///
157/// - **Syntax:** `call!(FUNCTION, ARGS...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500158///
Michael Layzell760fd662017-05-31 22:46:05 -0400159/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
David Tolnay1f16b602017-02-07 20:06:55 -0500160/// - **Output:** `T`, the result of invoking the function `FUNCTION`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500161#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700162macro_rules! call {
David Tolnayaf2557e2016-10-24 11:52:21 -0700163 ($i:expr, $fun:expr $(, $args:expr)*) => {
164 $fun($i $(, $args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700165 };
166}
167
David Tolnay1f16b602017-02-07 20:06:55 -0500168/// Transform the result of a parser by applying a function or closure.
Michael Layzell24645a32017-02-04 13:19:26 -0500169///
David Tolnay1f16b602017-02-07 20:06:55 -0500170/// - **Syntax:** `map!(THING, FN)`
171/// - **Output:** the return type of function FN applied to THING
Michael Layzell24645a32017-02-04 13:19:26 -0500172///
173/// ```rust
174/// extern crate syn;
175/// #[macro_use] extern crate synom;
176///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700177/// use syn::{Expr, ExprIf};
Michael Layzell24645a32017-02-04 13:19:26 -0500178///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700179/// fn get_cond(if_: ExprIf) -> Expr {
180/// *if_.cond
Michael Layzell24645a32017-02-04 13:19:26 -0500181/// }
182///
David Tolnayb21bb0c2017-06-03 20:39:19 -0700183/// // Parses an `if` statement but returns the condition part only.
184/// named!(if_condition -> Expr,
185/// map!(syn!(ExprIf), get_cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500186/// );
187///
188/// // Or equivalently:
David Tolnayb21bb0c2017-06-03 20:39:19 -0700189/// named!(if_condition2 -> Expr,
David Tolnaybc7d7d92017-06-03 20:54:05 -0700190/// map!(syn!(ExprIf), |if_| *if_.cond)
David Tolnay1f16b602017-02-07 20:06:55 -0500191/// );
David Tolnayb21bb0c2017-06-03 20:39:19 -0700192/// #
Alex Crichton954046c2017-05-30 21:49:42 -0700193/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500194/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500195#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700196macro_rules! map {
197 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700198 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400199 ::std::result::Result::Err(err) =>
200 ::std::result::Result::Err(err),
201 ::std::result::Result::Ok((i, o)) =>
David Tolnaybc7d7d92017-06-03 20:54:05 -0700202 ::std::result::Result::Ok((i, $crate::invoke($g, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700203 }
204 };
David Tolnay1f16b602017-02-07 20:06:55 -0500205
206 ($i:expr, $f:expr, $g:expr) => {
207 map!($i, call!($f), $g)
208 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700209}
210
David Tolnaybc7d7d92017-06-03 20:54:05 -0700211// Somehow this helps with type inference in `map!`.
212//
213// Not public API.
214#[doc(hidden)]
215pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
216 f(t)
217}
218
David Tolnay1f16b602017-02-07 20:06:55 -0500219/// Parses successfully if the given parser fails to parse. Does not consume any
220/// of the input.
Michael Layzell24645a32017-02-04 13:19:26 -0500221///
222/// - **Syntax:** `not!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500223/// - **Output:** `()`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500224#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700225macro_rules! not {
226 ($i:expr, $submac:ident!( $($args:tt)* )) => {
227 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400228 ::std::result::Result::Ok(_) => $crate::parse_error(),
229 ::std::result::Result::Err(_) =>
230 ::std::result::Result::Ok(($i, ())),
David Tolnayb5a7b142016-09-13 22:46:39 -0700231 }
232 };
233}
234
David Tolnay1f16b602017-02-07 20:06:55 -0500235/// Conditionally execute the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500236///
David Tolnay1f16b602017-02-07 20:06:55 -0500237/// If you are familiar with nom, this is nom's `cond_with_error` parser.
238///
239/// - **Syntax:** `cond!(CONDITION, THING)`
240/// - **Output:** `Some(THING)` if the condition is true, else `None`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500241#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700242macro_rules! cond {
243 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
244 if $cond {
245 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400246 ::std::result::Result::Ok((i, o)) =>
247 ::std::result::Result::Ok((i, ::std::option::Option::Some(o))),
248 ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
David Tolnayb5a7b142016-09-13 22:46:39 -0700249 }
250 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400251 ::std::result::Result::Ok(($i, ::std::option::Option::None))
David Tolnayb5a7b142016-09-13 22:46:39 -0700252 }
David Tolnaycfe55022016-10-02 22:02:27 -0700253 };
254
255 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700256 cond!($i, $cond, call!($f))
David Tolnaycfe55022016-10-02 22:02:27 -0700257 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700258}
259
David Tolnay1f16b602017-02-07 20:06:55 -0500260/// Fail to parse if condition is false, otherwise parse the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500261///
David Tolnay1f16b602017-02-07 20:06:55 -0500262/// This is typically used inside of `option!` or `alt!`.
263///
264/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
265/// - **Output:** `THING`
Michael Layzell5bde96f2017-01-24 17:59:21 -0500266#[macro_export]
David Tolnayaf2557e2016-10-24 11:52:21 -0700267macro_rules! cond_reduce {
268 ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
269 if $cond {
270 $submac!($i, $($args)*)
271 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400272 $crate::parse_error()
David Tolnayaf2557e2016-10-24 11:52:21 -0700273 }
274 };
275
276 ($i:expr, $cond:expr, $f:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700277 cond_reduce!($i, $cond, call!($f))
David Tolnayaf2557e2016-10-24 11:52:21 -0700278 };
279}
280
David Tolnay1f16b602017-02-07 20:06:55 -0500281/// Parse two things, returning the value of the first.
Michael Layzell24645a32017-02-04 13:19:26 -0500282///
David Tolnay1f16b602017-02-07 20:06:55 -0500283/// - **Syntax:** `terminated!(THING, AFTER)`
Michael Layzell24645a32017-02-04 13:19:26 -0500284/// - **Output:** `THING`
285///
286/// ```rust
287/// extern crate syn;
288/// #[macro_use] extern crate synom;
289///
290/// use syn::Expr;
Alex Crichton954046c2017-05-30 21:49:42 -0700291/// use synom::tokens::Pound;
Michael Layzell24645a32017-02-04 13:19:26 -0500292///
293/// // An expression terminated by ##.
294/// named!(expr_pound_pound -> Expr,
Alex Crichton954046c2017-05-30 21:49:42 -0700295/// terminated!(syn!(Expr), tuple!(syn!(Pound), syn!(Pound)))
David Tolnay1f16b602017-02-07 20:06:55 -0500296/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500297///
Alex Crichton954046c2017-05-30 21:49:42 -0700298/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500299/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500300#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700301macro_rules! terminated {
302 ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
303 match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
Michael Layzell760fd662017-05-31 22:46:05 -0400304 ::std::result::Result::Ok((i, (o, _))) =>
305 ::std::result::Result::Ok((i, o)),
306 ::std::result::Result::Err(err) =>
307 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700308 }
309 };
310
311 ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700312 terminated!($i, $submac!($($args)*), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700313 };
314
315 ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700316 terminated!($i, call!($f), $submac!($($args)*))
David Tolnayb5a7b142016-09-13 22:46:39 -0700317 };
318
319 ($i:expr, $f:expr, $g:expr) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700320 terminated!($i, call!($f), call!($g))
David Tolnayb5a7b142016-09-13 22:46:39 -0700321 };
322}
323
David Tolnay1f16b602017-02-07 20:06:55 -0500324/// Parse zero or more values using the given parser.
Michael Layzell24645a32017-02-04 13:19:26 -0500325///
326/// - **Syntax:** `many0!(THING)`
327/// - **Output:** `Vec<THING>`
328///
David Tolnay1f16b602017-02-07 20:06:55 -0500329/// You may also be looking for:
330///
Alex Crichton954046c2017-05-30 21:49:42 -0700331/// - `call!(Delimited::parse_separated)` - zero or more values with separator
332/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
333/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
David Tolnay1f16b602017-02-07 20:06:55 -0500334///
Michael Layzell24645a32017-02-04 13:19:26 -0500335/// ```rust
336/// extern crate syn;
337/// #[macro_use] extern crate synom;
338///
339/// use syn::Item;
Michael Layzell24645a32017-02-04 13:19:26 -0500340///
Alex Crichton954046c2017-05-30 21:49:42 -0700341/// named!(items -> Vec<Item>, many0!(syn!(Item)));
Michael Layzell24645a32017-02-04 13:19:26 -0500342///
Alex Crichton954046c2017-05-30 21:49:42 -0700343/// # fn main() {}
Michael Layzell5bde96f2017-01-24 17:59:21 -0500344#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700345macro_rules! many0 {
346 ($i:expr, $submac:ident!( $($args:tt)* )) => {{
347 let ret;
348 let mut res = ::std::vec::Vec::new();
349 let mut input = $i;
350
351 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400352 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400353 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700354 break;
355 }
356
357 match $submac!(input, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400358 ::std::result::Result::Err(_) => {
359 ret = ::std::result::Result::Ok((input, res));
David Tolnayb5a7b142016-09-13 22:46:39 -0700360 break;
361 }
Michael Layzell760fd662017-05-31 22:46:05 -0400362 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700363 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400364 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400365 ret = $crate::parse_error();
David Tolnayb5a7b142016-09-13 22:46:39 -0700366 break;
367 }
368
369 res.push(o);
370 input = i;
371 }
372 }
373 }
374
375 ret
376 }};
377
378 ($i:expr, $f:expr) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500379 $crate::many0($i, $f)
David Tolnayb5a7b142016-09-13 22:46:39 -0700380 };
381}
382
David Tolnay1f16b602017-02-07 20:06:55 -0500383// Improve compile time by compiling this loop only once per type it is used
384// with.
385//
David Tolnay5fe14fc2017-01-27 16:22:08 -0800386// Not public API.
387#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400388pub fn many0<'a, T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700389 let mut res = Vec::new();
390
391 loop {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400392 if input.eof() {
Michael Layzell760fd662017-05-31 22:46:05 -0400393 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700394 }
395
396 match f(input) {
Michael Layzell760fd662017-05-31 22:46:05 -0400397 Err(_) => {
398 return Ok((input, res));
David Tolnaybc84d5a2016-10-08 13:20:57 -0700399 }
Michael Layzell760fd662017-05-31 22:46:05 -0400400 Ok((i, o)) => {
David Tolnaybc84d5a2016-10-08 13:20:57 -0700401 // loop trip must always consume (otherwise infinite loops)
Michael Layzell0a1a6632017-06-02 18:07:43 -0400402 if i == input {
Michael Layzell760fd662017-05-31 22:46:05 -0400403 return parse_error();
David Tolnaybc84d5a2016-10-08 13:20:57 -0700404 }
405
406 res.push(o);
407 input = i;
408 }
409 }
410 }
411}
412
David Tolnay1f16b602017-02-07 20:06:55 -0500413/// Parse a value without consuming it from the input data.
Michael Layzell24645a32017-02-04 13:19:26 -0500414///
415/// - **Syntax:** `peek!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500416/// - **Output:** `THING`
Michael Layzell24645a32017-02-04 13:19:26 -0500417///
418/// ```rust
419/// extern crate syn;
420/// #[macro_use] extern crate synom;
421///
Alex Crichton954046c2017-05-30 21:49:42 -0700422/// use syn::{Expr, Ident};
Michael Layzell24645a32017-02-04 13:19:26 -0500423///
David Tolnay1f16b602017-02-07 20:06:55 -0500424/// // Parse an expression that begins with an identifier.
Alex Crichton954046c2017-05-30 21:49:42 -0700425/// named!(ident_expr -> (Ident, Expr),
426/// tuple!(peek!(syn!(Ident)), syn!(Expr))
David Tolnay1f16b602017-02-07 20:06:55 -0500427/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500428///
Alex Crichton954046c2017-05-30 21:49:42 -0700429/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500430/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500431#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700432macro_rules! peek {
433 ($i:expr, $submac:ident!( $($args:tt)* )) => {
434 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400435 ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
436 ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700437 }
438 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700439
David Tolnay1f16b602017-02-07 20:06:55 -0500440 ($i:expr, $f:expr) => {
441 peek!($i, call!($f))
David Tolnayb5a7b142016-09-13 22:46:39 -0700442 };
443}
444
David Tolnay1f16b602017-02-07 20:06:55 -0500445/// Pattern-match the result of a parser to select which other parser to run.
446///
447/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
448/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
449///
450/// ```rust
451/// extern crate syn;
452/// #[macro_use] extern crate synom;
453///
454/// use syn::{Ident, Ty};
Alex Crichton954046c2017-05-30 21:49:42 -0700455/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500456///
457/// #[derive(Debug)]
458/// enum UnitType {
459/// Struct {
460/// name: Ident,
461/// },
462/// Enum {
463/// name: Ident,
464/// variant: Ident,
465/// },
466/// }
467///
468/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
469/// named!(unit_type -> UnitType, do_parse!(
Alex Crichton954046c2017-05-30 21:49:42 -0700470/// which: alt!(
471/// syn!(Struct) => { |_| 0 }
472/// |
473/// syn!(Enum) => { |_| 1 }
474/// ) >>
475/// id: syn!(Ident) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500476/// item: switch!(value!(which),
Alex Crichton954046c2017-05-30 21:49:42 -0700477/// 0 => map!(
478/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500479/// move |_| UnitType::Struct {
480/// name: id,
481/// }
482/// )
483/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700484/// 1 => map!(
485/// braces!(syn!(Ident)),
486/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500487/// name: id,
488/// variant: variant,
489/// }
490/// )
David Tolnay92a56512017-11-10 00:02:14 -0800491/// |
492/// _ => reject!()
David Tolnay1f16b602017-02-07 20:06:55 -0500493/// ) >>
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 )*
David Tolnayb5a7b142016-09-13 22:46:39 -0700508 }
509 }
510 };
511}
512
Alex Crichton954046c2017-05-30 21:49:42 -0700513
David Tolnay1f16b602017-02-07 20:06:55 -0500514/// Produce the given value without parsing anything. Useful as an argument to
515/// `switch!`.
516///
517/// - **Syntax:** `value!(VALUE)`
518/// - **Output:** `VALUE`
519///
520/// ```rust
521/// extern crate syn;
522/// #[macro_use] extern crate synom;
523///
David Tolnay92a56512017-11-10 00:02:14 -0800524/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700525/// use synom::tokens::*;
David Tolnay1f16b602017-02-07 20:06:55 -0500526///
527/// #[derive(Debug)]
528/// enum UnitType {
529/// Struct {
530/// name: Ident,
531/// },
532/// Enum {
533/// name: Ident,
534/// variant: Ident,
535/// },
536/// }
537///
538/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
539/// named!(unit_type -> UnitType, do_parse!(
David Tolnay92a56512017-11-10 00:02:14 -0800540/// is_struct: alt!(
541/// syn!(Struct) => { |_| true }
Alex Crichton954046c2017-05-30 21:49:42 -0700542/// |
David Tolnay92a56512017-11-10 00:02:14 -0800543/// syn!(Enum) => { |_| false }
Alex Crichton954046c2017-05-30 21:49:42 -0700544/// ) >>
545/// id: syn!(Ident) >>
David Tolnay92a56512017-11-10 00:02:14 -0800546/// item: switch!(value!(is_struct),
547/// true => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700548/// syn!(Semi),
David Tolnay1f16b602017-02-07 20:06:55 -0500549/// move |_| UnitType::Struct {
550/// name: id,
551/// }
552/// )
553/// |
David Tolnay92a56512017-11-10 00:02:14 -0800554/// false => map!(
Alex Crichton954046c2017-05-30 21:49:42 -0700555/// braces!(syn!(Ident)),
556/// move |(variant, _)| UnitType::Enum {
David Tolnay1f16b602017-02-07 20:06:55 -0500557/// name: id,
558/// variant: variant,
559/// }
560/// )
561/// ) >>
562/// (item)
563/// ));
564///
Alex Crichton954046c2017-05-30 21:49:42 -0700565/// # fn main() {}
David Tolnay1f16b602017-02-07 20:06:55 -0500566/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500567#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700568macro_rules! value {
569 ($i:expr, $res:expr) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400570 ::std::result::Result::Ok(($i, $res))
David Tolnayb5a7b142016-09-13 22:46:39 -0700571 };
572}
573
David Tolnay92a56512017-11-10 00:02:14 -0800574/// Unconditionally fail to parse anything. This may be useful in ignoring some
575/// arms of a `switch!` parser.
576///
577/// - **Syntax:** `reject!()`
578/// - **Output:** never succeeds
579///
580/// ```rust
581/// extern crate syn;
582/// #[macro_use] extern crate synom;
583///
584/// use syn::Item;
585///
586/// // Parse any item, except for a module.
587/// named!(almost_any_item -> Item,
588/// switch!(syn!(Item),
589/// Item::Mod(_) => reject!()
590/// |
591/// ok => value!(ok)
592/// )
593/// );
594///
595/// # fn main() {}
596/// ```
597#[macro_export]
598macro_rules! reject {
599 ($i:expr,) => {
600 $crate::parse_error()
601 }
602}
603
David Tolnay1f16b602017-02-07 20:06:55 -0500604/// Run a series of parsers and produce all of the results in a tuple.
Michael Layzell24645a32017-02-04 13:19:26 -0500605///
David Tolnay1f16b602017-02-07 20:06:55 -0500606/// - **Syntax:** `tuple!(A, B, C, ...)`
607/// - **Output:** `(A, B, C, ...)`
Michael Layzell24645a32017-02-04 13:19:26 -0500608///
609/// ```rust
610/// extern crate syn;
611/// #[macro_use] extern crate synom;
612///
613/// use syn::Ty;
Michael Layzell24645a32017-02-04 13:19:26 -0500614///
Alex Crichton954046c2017-05-30 21:49:42 -0700615/// named!(two_types -> (Ty, Ty), tuple!(syn!(Ty), syn!(Ty)));
Michael Layzell24645a32017-02-04 13:19:26 -0500616///
Alex Crichton954046c2017-05-30 21:49:42 -0700617/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500618/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500619#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700620macro_rules! tuple {
621 ($i:expr, $($rest:tt)*) => {
622 tuple_parser!($i, (), $($rest)*)
623 };
624}
625
David Tolnay1f16b602017-02-07 20:06:55 -0500626/// Internal parser, do not use directly.
Michael Layzell5bde96f2017-01-24 17:59:21 -0500627#[doc(hidden)]
628#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700629macro_rules! tuple_parser {
630 ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700631 tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700632 };
633
634 ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
635 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400636 ::std::result::Result::Err(err) =>
637 ::std::result::Result::Err(err),
638 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700639 tuple_parser!(i, (o), $($rest)*),
640 }
641 };
642
643 ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
644 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400645 ::std::result::Result::Err(err) =>
646 ::std::result::Result::Err(err),
647 ::std::result::Result::Ok((i, o)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700648 tuple_parser!(i, ($($parsed)* , o), $($rest)*),
649 }
650 };
651
652 ($i:expr, ($($parsed:tt),*), $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700653 tuple_parser!($i, ($($parsed),*), call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700654 };
655
656 ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
657 $submac!($i, $($args)*)
658 };
659
660 ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
661 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400662 ::std::result::Result::Err(err) =>
663 ::std::result::Result::Err(err),
664 ::std::result::Result::Ok((i, o)) =>
665 ::std::result::Result::Ok((i, ($($parsed),*, o))),
David Tolnayb5a7b142016-09-13 22:46:39 -0700666 }
667 };
668
669 ($i:expr, ($($parsed:expr),*)) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400670 ::std::result::Result::Ok(($i, ($($parsed),*)))
David Tolnayb5a7b142016-09-13 22:46:39 -0700671 };
672}
673
David Tolnay1f16b602017-02-07 20:06:55 -0500674/// Run a series of parsers, returning the result of the first one which
675/// succeeds.
Michael Layzell24645a32017-02-04 13:19:26 -0500676///
677/// Optionally allows for the result to be transformed.
678///
679/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
David Tolnay1f16b602017-02-07 20:06:55 -0500680/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
Michael Layzell24645a32017-02-04 13:19:26 -0500681///
682/// ```rust
683/// extern crate syn;
684/// #[macro_use] extern crate synom;
685///
686/// use syn::Ident;
Alex Crichton954046c2017-05-30 21:49:42 -0700687/// use synom::tokens::Bang;
Michael Layzell24645a32017-02-04 13:19:26 -0500688///
689/// named!(ident_or_bang -> Ident,
David Tolnay1f16b602017-02-07 20:06:55 -0500690/// alt!(
Alex Crichton954046c2017-05-30 21:49:42 -0700691/// syn!(Ident)
David Tolnay1f16b602017-02-07 20:06:55 -0500692/// |
Alex Crichton954046c2017-05-30 21:49:42 -0700693/// syn!(Bang) => { |_| "BANG".into() }
David Tolnay1f16b602017-02-07 20:06:55 -0500694/// )
695/// );
Michael Layzell24645a32017-02-04 13:19:26 -0500696///
Alex Crichton954046c2017-05-30 21:49:42 -0700697/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500698/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500699#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700700macro_rules! alt {
701 ($i:expr, $e:ident | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700702 alt!($i, call!($e) | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700703 };
704
705 ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
706 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400707 res @ ::std::result::Result::Ok(_) => res,
David Tolnayb5a7b142016-09-13 22:46:39 -0700708 _ => alt!($i, $($rest)*)
709 }
710 };
711
712 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
713 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400714 ::std::result::Result::Ok((i, o)) =>
715 ::std::result::Result::Ok((i, $gen(o))),
716 ::std::result::Result::Err(_) => alt!($i, $($rest)*),
David Tolnayb5a7b142016-09-13 22:46:39 -0700717 }
718 };
719
720 ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700721 alt!($i, call!($e) => { $gen } | $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700722 };
723
724 ($i:expr, $e:ident => { $gen:expr }) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700725 alt!($i, call!($e) => { $gen })
David Tolnayb5a7b142016-09-13 22:46:39 -0700726 };
727
728 ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
729 match $subrule!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400730 ::std::result::Result::Ok((i, o)) =>
731 ::std::result::Result::Ok((i, $gen(o))),
732 ::std::result::Result::Err(err) =>
733 ::std::result::Result::Err(err),
David Tolnayb5a7b142016-09-13 22:46:39 -0700734 }
735 };
736
737 ($i:expr, $e:ident) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700738 alt!($i, call!($e))
David Tolnayb5a7b142016-09-13 22:46:39 -0700739 };
740
741 ($i:expr, $subrule:ident!( $($args:tt)*)) => {
David Tolnay5377b172016-10-25 01:13:12 -0700742 $subrule!($i, $($args)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700743 };
744}
745
Michael Layzell24645a32017-02-04 13:19:26 -0500746/// Run a series of parsers, one after another, optionally assigning the results
David Tolnay1f16b602017-02-07 20:06:55 -0500747/// a name. Fail if any of the parsers fails.
Michael Layzell24645a32017-02-04 13:19:26 -0500748///
David Tolnay1f16b602017-02-07 20:06:55 -0500749/// Produces the result of evaluating the final expression in parentheses with
750/// all of the previously named results bound.
Michael Layzell24645a32017-02-04 13:19:26 -0500751///
David Tolnay1f16b602017-02-07 20:06:55 -0500752/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
Michael Layzell24645a32017-02-04 13:19:26 -0500753/// - **Output:** `RESULT`
754///
755/// ```rust
756/// extern crate syn;
757/// #[macro_use] extern crate synom;
Alex Crichton954046c2017-05-30 21:49:42 -0700758/// extern crate proc_macro2;
Michael Layzell24645a32017-02-04 13:19:26 -0500759///
760/// use syn::{Ident, TokenTree};
Alex Crichton954046c2017-05-30 21:49:42 -0700761/// use synom::tokens::{Bang, Paren};
762/// use proc_macro2::TokenStream;
Michael Layzell24645a32017-02-04 13:19:26 -0500763///
David Tolnay1f16b602017-02-07 20:06:55 -0500764/// // Parse a macro invocation like `stringify!($args)`.
Alex Crichton954046c2017-05-30 21:49:42 -0700765/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
766/// name: syn!(Ident) >>
767/// syn!(Bang) >>
768/// body: parens!(syn!(TokenStream)) >>
David Tolnay1f16b602017-02-07 20:06:55 -0500769/// (name, body)
770/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500771///
Alex Crichton954046c2017-05-30 21:49:42 -0700772/// # fn main() {}
Michael Layzell24645a32017-02-04 13:19:26 -0500773/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500774#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700775macro_rules! do_parse {
776 ($i:expr, ( $($rest:expr),* )) => {
Michael Layzell760fd662017-05-31 22:46:05 -0400777 ::std::result::Result::Ok(($i, ( $($rest),* )))
David Tolnayb5a7b142016-09-13 22:46:39 -0700778 };
779
780 ($i:expr, $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700781 do_parse!($i, call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700782 };
783
784 ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
785 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400786 ::std::result::Result::Err(err) =>
787 ::std::result::Result::Err(err),
788 ::std::result::Result::Ok((i, _)) =>
David Tolnayb5a7b142016-09-13 22:46:39 -0700789 do_parse!(i, $($rest)*),
790 }
791 };
792
793 ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnayb81c7a42016-10-25 10:12:12 -0700794 do_parse!($i, $field: call!($e) >> $($rest)*)
David Tolnayb5a7b142016-09-13 22:46:39 -0700795 };
796
797 ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
798 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400799 ::std::result::Result::Err(err) =>
800 ::std::result::Result::Err(err),
801 ::std::result::Result::Ok((i, o)) => {
David Tolnayb5a7b142016-09-13 22:46:39 -0700802 let $field = o;
803 do_parse!(i, $($rest)*)
804 },
805 }
806 };
807
David Tolnayfa0edf22016-09-23 22:58:24 -0700808 ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
David Tolnay7184b132016-10-30 10:06:37 -0700809 do_parse!($i, mut $field: call!($e) >> $($rest)*)
David Tolnayfa0edf22016-09-23 22:58:24 -0700810 };
811
812 ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
813 match $submac!($i, $($args)*) {
Michael Layzell760fd662017-05-31 22:46:05 -0400814 ::std::result::Result::Err(err) =>
815 ::std::result::Result::Err(err),
816 ::std::result::Result::Ok((i, o)) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700817 let mut $field = o;
818 do_parse!(i, $($rest)*)
819 },
820 }
821 };
David Tolnayb5a7b142016-09-13 22:46:39 -0700822}
Michael Layzell416724e2017-05-24 21:12:34 -0400823
824#[macro_export]
825macro_rules! input_end {
826 ($i:expr,) => {
827 $crate::input_end($i)
828 };
829}
830
831// Not a public API
832#[doc(hidden)]
Michael Layzell760fd662017-05-31 22:46:05 -0400833pub fn input_end(input: Cursor) -> PResult<'static, &'static str> {
Michael Layzell0a1a6632017-06-02 18:07:43 -0400834 if input.eof() {
835 Ok((Cursor::empty(), ""))
Michael Layzell416724e2017-05-24 21:12:34 -0400836 } else {
Michael Layzell760fd662017-05-31 22:46:05 -0400837 parse_error()
Michael Layzell416724e2017-05-24 21:12:34 -0400838 }
839}