blob: 3b64ac50289f136791f394e23e768df2ce38ee17 [file] [log] [blame]
Alex Crichton7b9e02f2017-05-30 15:54:33 -07001use proc_macro2::{TokenTree, TokenKind};
2
Michael Layzell5bde96f2017-01-24 17:59:21 -05003use IResult;
Alex Crichton7b9e02f2017-05-30 15:54:33 -07004use span::Span;
David Tolnay13e5da42016-09-04 16:18:34 -07005
David Tolnay1f16b602017-02-07 20:06:55 -05006/// Parse a keyword like "fn" or "struct".
7///
8/// See also `punct!` for parsing punctuation, which are subtly different from
9/// keywords.
Michael Layzell24645a32017-02-04 13:19:26 -050010///
11/// - **Syntax:** `keyword!("...")`
12/// - **Output:** `&str`
13///
14/// ```rust
15/// extern crate syn;
16/// #[macro_use] extern crate synom;
17///
David Tolnay1f16b602017-02-07 20:06:55 -050018/// use synom::IResult;
19///
20/// // Parse zero or more "bang" keywords.
21/// named!(many_bangs -> Vec<&str>,
22/// terminated!(
23/// many0!(keyword!("bang")),
24/// punct!(";")
25/// )
26/// );
Michael Layzell24645a32017-02-04 13:19:26 -050027///
28/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050029/// let input = "bang bang bang;";
30/// let parsed = many_bangs(input).expect("bangs");
31/// assert_eq!(parsed, ["bang", "bang", "bang"]);
32///
33/// let input = "bangbang;";
34/// let err = many_bangs(input);
35/// assert_eq!(err, IResult::Error);
Michael Layzell24645a32017-02-04 13:19:26 -050036/// }
37/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050038#[macro_export]
David Tolnay10413f02016-09-30 09:12:02 -070039macro_rules! keyword {
40 ($i:expr, $keyword:expr) => {
David Tolnay5fe14fc2017-01-27 16:22:08 -080041 $crate::helper::keyword($i, $keyword)
David Tolnay10413f02016-09-30 09:12:02 -070042 };
43}
44
David Tolnay5fe14fc2017-01-27 16:22:08 -080045// Not public API.
46#[doc(hidden)]
Alex Crichton7b9e02f2017-05-30 15:54:33 -070047pub fn keyword<'a>(input: &'a [TokenTree], token: &'static str) -> IResult<&'a [TokenTree], Span> {
Michael Layzell416724e2017-05-24 21:12:34 -040048 match input.first() {
Alex Crichton7b9e02f2017-05-30 15:54:33 -070049 Some(&TokenTree{ kind: TokenKind::Word(ref symbol), span }) => {
50 if symbol.as_str() == token {
51 IResult::Done(&input[1..], Span(span))
52 } else {
53 IResult::Error
54 }
55 }
Michael Layzell416724e2017-05-24 21:12:34 -040056 _ => IResult::Error,
David Tolnay10413f02016-09-30 09:12:02 -070057 }
58}
59
David Tolnay1f16b602017-02-07 20:06:55 -050060/// Turn a failed parse into `None` and a successful parse into `Some`.
Michael Layzell24645a32017-02-04 13:19:26 -050061///
62/// - **Syntax:** `option!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -050063/// - **Output:** `Option<THING>`
Michael Layzell24645a32017-02-04 13:19:26 -050064///
65/// ```rust
66/// extern crate syn;
67/// #[macro_use] extern crate synom;
68///
69/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
70///
71/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -050072/// let input = "!";
73/// let parsed = maybe_bang(input).expect("maybe bang");
74/// assert_eq!(parsed, Some("!"));
75///
Michael Layzell24645a32017-02-04 13:19:26 -050076/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -050077/// let parsed = maybe_bang(input).expect("maybe bang");
78/// assert_eq!(parsed, None);
Michael Layzell24645a32017-02-04 13:19:26 -050079/// }
80/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -050081#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -070082macro_rules! option {
83 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -070084 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -050085 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
86 $crate::IResult::Error => $crate::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -070087 }
David Tolnayb5a7b142016-09-13 22:46:39 -070088 };
David Tolnayf6ccb832016-09-04 15:00:56 -070089
David Tolnayb5a7b142016-09-13 22:46:39 -070090 ($i:expr, $f:expr) => {
91 option!($i, call!($f));
92 };
93}
94
David Tolnay1f16b602017-02-07 20:06:55 -050095/// Turn a failed parse into an empty vector. The argument parser must itself
96/// return a vector.
Michael Layzell24645a32017-02-04 13:19:26 -050097///
David Tolnay1f16b602017-02-07 20:06:55 -050098/// This is often more convenient than `option!(...)` when the argument produces
99/// a vector.
Michael Layzell24645a32017-02-04 13:19:26 -0500100///
101/// - **Syntax:** `opt_vec!(THING)`
David Tolnay1f16b602017-02-07 20:06:55 -0500102/// - **Output:** `THING`, which must be `Vec<T>`
Michael Layzell24645a32017-02-04 13:19:26 -0500103///
104/// ```rust
105/// extern crate syn;
106/// #[macro_use] extern crate synom;
107///
David Tolnay1f16b602017-02-07 20:06:55 -0500108/// use syn::{Lifetime, Ty};
109/// use syn::parse::{lifetime, ty};
Michael Layzell24645a32017-02-04 13:19:26 -0500110///
David Tolnay1f16b602017-02-07 20:06:55 -0500111/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
112/// opt_vec!(do_parse!(
113/// keyword!("for") >>
114/// punct!("<") >>
115/// lifetimes: terminated_list!(punct!(","), lifetime) >>
116/// punct!(">") >>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700117/// (lifetimes.into_vec())
David Tolnay1f16b602017-02-07 20:06:55 -0500118/// )),
119/// ty
120/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500121///
122/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500123/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
124/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
125/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
126/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500127///
David Tolnay1f16b602017-02-07 20:06:55 -0500128/// let input = "From<String>";
129/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
130/// assert!(parsed.0.is_empty());
131/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500132/// }
133/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500134#[macro_export]
David Tolnayb5a7b142016-09-13 22:46:39 -0700135macro_rules! opt_vec {
136 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -0700137 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500138 $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
139 $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -0700140 }
David Tolnayb5a7b142016-09-13 22:46:39 -0700141 };
142}
David Tolnayb79ee962016-09-04 09:39:20 -0700143
Michael Layzell24645a32017-02-04 13:19:26 -0500144/// Parses nothing and always succeeds.
145///
David Tolnay1f16b602017-02-07 20:06:55 -0500146/// This can be useful as a fallthrough case in `alt!`.
147///
Michael Layzell24645a32017-02-04 13:19:26 -0500148/// - **Syntax:** `epsilon!()`
149/// - **Output:** `()`
150///
151/// ```rust
David Tolnay1f16b602017-02-07 20:06:55 -0500152/// extern crate syn;
Michael Layzell24645a32017-02-04 13:19:26 -0500153/// #[macro_use] extern crate synom;
154///
David Tolnay1f16b602017-02-07 20:06:55 -0500155/// use syn::Mutability;
156///
157/// named!(mutability -> Mutability, alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700158/// keyword!("mut") => { |_| Mutability::Mutable(Default::default()) }
David Tolnay1f16b602017-02-07 20:06:55 -0500159/// |
160/// epsilon!() => { |_| Mutability::Immutable }
161/// ));
Michael Layzell24645a32017-02-04 13:19:26 -0500162///
163/// fn main() {
David Tolnay1f16b602017-02-07 20:06:55 -0500164/// let input = "mut";
165/// let parsed = mutability(input).expect("mutability");
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700166/// assert_eq!(parsed, Mutability::Mutable(Default::default()));
David Tolnay1f16b602017-02-07 20:06:55 -0500167///
Michael Layzell24645a32017-02-04 13:19:26 -0500168/// let input = "";
David Tolnay1f16b602017-02-07 20:06:55 -0500169/// let parsed = mutability(input).expect("mutability");
170/// assert_eq!(parsed, Mutability::Immutable);
Michael Layzell24645a32017-02-04 13:19:26 -0500171/// }
172/// ```
Michael Layzell5bde96f2017-01-24 17:59:21 -0500173#[macro_export]
David Tolnayb79ee962016-09-04 09:39:20 -0700174macro_rules! epsilon {
175 ($i:expr,) => {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500176 $crate::IResult::Done($i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700177 };
178}
179
Michael Layzell24645a32017-02-04 13:19:26 -0500180/// Run a parser, binding the result to a name, and then evaluating an
181/// expression.
182///
183/// Discards the result of the expression and parser.
184///
185/// - **Syntax:** `tap!(NAME : THING => EXPR)`
186/// - **Output:** `()`
187///
188/// ```rust
189/// extern crate syn;
190/// #[macro_use] extern crate synom;
191///
Alex Crichton62a0a592017-05-22 13:58:53 -0700192/// use syn::{Expr, ExprCall};
Michael Layzell24645a32017-02-04 13:19:26 -0500193/// use syn::parse::expr;
194///
David Tolnay1f16b602017-02-07 20:06:55 -0500195/// named!(expr_with_arrow_call -> Expr, do_parse!(
Michael Layzell24645a32017-02-04 13:19:26 -0500196/// mut e: expr >>
197/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
198/// e = Expr {
Alex Crichton62a0a592017-05-22 13:58:53 -0700199/// node: ExprCall {
200/// func: Box::new(e),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700201/// args: vec![arg.1].into(),
202/// paren_token: Default::default(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700203/// }.into(),
Michael Layzell24645a32017-02-04 13:19:26 -0500204/// attrs: Vec::new(),
205/// };
206/// })) >>
207/// (e)
208/// ));
209///
210/// fn main() {
211/// let input = "something => argument1 => argument2";
212///
David Tolnay1f16b602017-02-07 20:06:55 -0500213/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
Michael Layzell24645a32017-02-04 13:19:26 -0500214///
David Tolnay1f16b602017-02-07 20:06:55 -0500215/// println!("{:?}", parsed);
Michael Layzell24645a32017-02-04 13:19:26 -0500216/// }
217/// ```
David Tolnay1f16b602017-02-07 20:06:55 -0500218#[doc(hidden)]
Michael Layzell5bde96f2017-01-24 17:59:21 -0500219#[macro_export]
David Tolnayfa0edf22016-09-23 22:58:24 -0700220macro_rules! tap {
221 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
222 match $submac!($i, $($args)*) {
Michael Layzell5bde96f2017-01-24 17:59:21 -0500223 $crate::IResult::Done(i, o) => {
David Tolnayfa0edf22016-09-23 22:58:24 -0700224 let $name = o;
225 $e;
Michael Layzell5bde96f2017-01-24 17:59:21 -0500226 $crate::IResult::Done(i, ())
David Tolnayfa0edf22016-09-23 22:58:24 -0700227 }
Michael Layzell5bde96f2017-01-24 17:59:21 -0500228 $crate::IResult::Error => $crate::IResult::Error,
David Tolnayfa0edf22016-09-23 22:58:24 -0700229 }
230 };
231
232 ($i:expr, $name:ident : $f:expr => $e:expr) => {
233 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -0700234 };
235}