blob: bf199713a4dde8b988238cce13e7eee7c3146f3e [file] [log] [blame]
David Tolnay14cbdeb2016-10-01 12:13:59 -07001use nom::IResult;
David Tolnaydef66372016-10-24 21:51:32 -07002use space::{skip_whitespace, word_break};
David Tolnayb79ee962016-09-04 09:39:20 -07003
4macro_rules! punct {
5 ($i:expr, $punct:expr) => {
David Tolnay13e5da42016-09-04 16:18:34 -07006 $crate::helper::punct($i, $punct)
David Tolnayb79ee962016-09-04 09:39:20 -07007 };
8}
9
David Tolnay13e5da42016-09-04 16:18:34 -070010pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
David Tolnaydef66372016-10-24 21:51:32 -070011 let input = skip_whitespace(input);
David Tolnay14cbdeb2016-10-01 12:13:59 -070012 if input.starts_with(token) {
13 IResult::Done(&input[token.len()..], token)
14 } else {
15 IResult::Error
David Tolnay13e5da42016-09-04 16:18:34 -070016 }
David Tolnay13e5da42016-09-04 16:18:34 -070017}
18
David Tolnay10413f02016-09-30 09:12:02 -070019macro_rules! keyword {
20 ($i:expr, $keyword:expr) => {
21 $crate::helper::keyword($i, $keyword)
22 };
23}
24
25pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
26 match punct(input, token) {
27 IResult::Done(rest, _) => {
28 match word_break(rest) {
29 IResult::Done(_, _) => IResult::Done(rest, token),
30 IResult::Error => IResult::Error,
31 }
32 }
33 IResult::Error => IResult::Error,
34 }
35}
36
David Tolnayb5a7b142016-09-13 22:46:39 -070037macro_rules! option {
38 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayf6ccb832016-09-04 15:00:56 -070039 match $submac!($i, $($args)*) {
David Tolnayfa0edf22016-09-23 22:58:24 -070040 $crate::nom::IResult::Done(i, o) => $crate::nom::IResult::Done(i, Some(o)),
41 $crate::nom::IResult::Error => $crate::nom::IResult::Done($i, None),
David Tolnayf6ccb832016-09-04 15:00:56 -070042 }
David Tolnayb5a7b142016-09-13 22:46:39 -070043 };
David Tolnayf6ccb832016-09-04 15:00:56 -070044
David Tolnayb5a7b142016-09-13 22:46:39 -070045 ($i:expr, $f:expr) => {
46 option!($i, call!($f));
47 };
48}
49
50macro_rules! opt_vec {
51 ($i:expr, $submac:ident!( $($args:tt)* )) => {
David Tolnayb79ee962016-09-04 09:39:20 -070052 match $submac!($i, $($args)*) {
David Tolnayfa0edf22016-09-23 22:58:24 -070053 $crate::nom::IResult::Done(i, o) => $crate::nom::IResult::Done(i, o),
54 $crate::nom::IResult::Error => $crate::nom::IResult::Done($i, Vec::new()),
David Tolnayb79ee962016-09-04 09:39:20 -070055 }
David Tolnayb5a7b142016-09-13 22:46:39 -070056 };
57}
David Tolnayb79ee962016-09-04 09:39:20 -070058
59macro_rules! epsilon {
60 ($i:expr,) => {
David Tolnayfa0edf22016-09-23 22:58:24 -070061 $crate::nom::IResult::Done($i, ())
62 };
63}
64
65macro_rules! tap {
66 ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
67 match $submac!($i, $($args)*) {
68 $crate::nom::IResult::Done(i, o) => {
69 let $name = o;
70 $e;
71 $crate::nom::IResult::Done(i, ())
72 }
73 $crate::nom::IResult::Error => $crate::nom::IResult::Error,
74 }
75 };
76
77 ($i:expr, $name:ident : $f:expr => $e:expr) => {
78 tap!($i, $name: call!($f) => $e);
David Tolnayb79ee962016-09-04 09:39:20 -070079 };
80}
David Tolnay674258d2016-10-08 13:30:45 -070081
82macro_rules! separated_list {
83 ($i:expr, punct!($sep:expr), $f:expr) => {
David Tolnayff46fd22016-10-08 13:53:28 -070084 $crate::helper::separated_list($i, $sep, $f, false)
David Tolnay674258d2016-10-08 13:30:45 -070085 };
86}
87
David Tolnayff46fd22016-10-08 13:53:28 -070088macro_rules! terminated_list {
89 ($i:expr, punct!($sep:expr), $f:expr) => {
90 $crate::helper::separated_list($i, $sep, $f, true)
91 };
92}
93
David Tolnayc7f646a2016-10-16 10:54:39 -070094pub fn separated_list<'a, T>(mut input: &'a str,
95 sep: &'static str,
96 f: fn(&'a str) -> IResult<&'a str, T>,
97 terminated: bool)
98 -> IResult<&'a str, Vec<T>> {
David Tolnay674258d2016-10-08 13:30:45 -070099 let mut res = Vec::new();
100
101 // get the first element
102 match f(input) {
103 IResult::Error => IResult::Done(input, Vec::new()),
104 IResult::Done(i, o) => {
105 if i.len() == input.len() {
106 IResult::Error
107 } else {
108 res.push(o);
109 input = i;
110
111 // get the separator first
112 while let IResult::Done(i2, _) = punct(input, sep) {
113 if i2.len() == input.len() {
114 break;
115 }
116
117 // get the element next
118 if let IResult::Done(i3, o3) = f(i2) {
119 if i3.len() == i2.len() {
120 break;
121 }
122 res.push(o3);
123 input = i3;
124 } else {
125 break;
126 }
127 }
David Tolnayff46fd22016-10-08 13:53:28 -0700128 if terminated {
129 if let IResult::Done(after, _) = punct(input, sep) {
130 input = after;
131 }
132 }
David Tolnay674258d2016-10-08 13:30:45 -0700133 IResult::Done(input, res)
134 }
135 }
136 }
137}