1#[macro_export]
19macro_rules! parser {
20 ($id:ident,$x:expr) => {
21 parser!(($id->&'static str) $x);
22 };
23 ($($doc:literal $(,)?)? ($id:ident -> $ot:ty) $(,)? $x:expr $(,)?) => {
24 parser!($($doc)? ($id->$ot) $x, Expected::Str(stringify!($id)));
25 };
26 ($id:ident,$x:expr,$exp:expr) => {
27 parser!(($id->&'static str) $x, $exp);
28 };
29 ($($doc:literal $(,)?)? ($id:ident -> $ot:ty) $(,)? $x:expr,$exp:expr $(,)?) => {
30 $(#[doc=$doc])?
31 #[derive(Copy, Clone)]
32 pub struct $id;
33 impl Parser for $id {
34 type Out = $ot;
35 fn parse<'a>(&self, it: &LCChars<'a>) -> ParseRes<'a, Self::Out> {
37 let name_e = it.err_p(self);
38 match (&$x).parse(it){
39 Ok(v)=> Ok(v),
40 Err(e)=> match (e.index,name_e.index) {
41 (Some(ei),Some(ii)) if (ii == ei) => it.err_rp(self),
42 _=>Err(e.join(name_e)),
43 }
44 }
45 }
46 fn expected(&self) -> Expected {
48 $exp
49 }
50 }
51 };
52}
53
54#[macro_export]
55macro_rules! parser_as {
56 (($ot:ty),(($id:ident->$res:expr) $(,)? $main:expr,$exp:expr $(,)?) ) => {
57 parser! {($id->$ot) ,$main.map(|_|$res),$exp}
58 };
59 (($ot:ty),(($id:ident->$res:expr) $(,)? $main:expr $(,)?) ) => {
60 parser! {($id->$ot) ,$main.map(|_|$res)}
61 };
62 (($ot:ty),($id:ident, $main:expr)) => {
63 parser! { ($id->$ot) $main}
64 };
65}
66
67#[macro_export]
68macro_rules! as_id {
69 ((($id:ident->$_x:expr) $($_t:tt)*) ) => {
70 $id
71 };
72 (($id:ident $($_t:tt)*) ) => {
73 $id
74 };
75}
76
77#[macro_export]
113macro_rules! enum_parser{
114 ( ($name:ident,$mod:ident,$ot:ty)=>$($mbit:tt),* $(,)?) =>{
115 pub mod $mod{
116 use $crate::*;
117 use super::*;
118 $( parser_as!{($ot),$mbit})*
119 parser!{ ($name->$ot) ( or!{ $(as_id!{$mbit}),*} )}
120 }
121 pub use $mod::$name;
122 }
123}
124
125#[macro_export]
126macro_rules! char_bool {
127 ($id:ident,$x:expr) => {
128 char_bool!($id, $x, Expected::CharIn(stringify!($id)));
129 };
130 ($id:ident,$x:expr,$s:literal) => {
131 char_bool!($id, $x, Expected::CharIn($s));
132 };
133 ($id:ident,$x:expr,$exp:expr) => {
134 #[derive(Copy, Clone)]
135 pub struct $id;
136 impl CharBool for $id {
137 fn char_bool(&self, c: char) -> bool {
138 (&$x).char_bool(c)
139 }
140 fn expected(&self) -> Expected {
141 $exp
142 }
143 }
144 };
145}
146
147#[macro_export]
148macro_rules! char_bools {
149 ( $( ($id:ident,$x:expr) ),*) => {$(char_bool!($id,$x);)*};
150}
151
152#[macro_export]
158macro_rules! or{
159 ($s:expr,$($x:expr),* $(,)?) => { $s$(.or($x))*;};
160}
161
162#[macro_export]
163macro_rules! or_ig{
164 ($s:expr,$($x:expr),* $(,)?) => { $s.ig()$(.or($x.ig()))*;};
165}
166
167#[cfg(test)]
168mod test {
169
170 fn size_of<T: Sized>(_t: &T) -> usize {
171 std::mem::size_of::<T>()
172 }
173
174 use crate::*;
175 parser!(DOG, "dog");
176 parser!(CAR, "car");
177 parser!(CAT, "cat");
178
179 parser!((GROW->Vec<&'static str>) star(or(CAT, DOG)));
180
181 #[test]
182 pub fn parser_makes_parser() {
183 assert_eq!(DOG.parse_s("dog "), Ok("dog"));
184 assert_eq!(CAT.parse_s("cat "), Ok("cat"));
185 assert_eq!(
186 GROW.parse_s("catdogcatcatno"),
187 Ok(vec!["cat", "dog", "cat", "cat"])
188 );
189 }
190
191 char_bool!(HOT, "hot");
192 char_bool!(MNUM, |c| c >= '0' && c <= '9');
193
194 #[test]
195 pub fn charbool_macro_makes_parser() {
196 use Expected::*;
197 let p = (HOT, MNUM);
198 assert_eq!(std::mem::size_of::<(HOT, MNUM)>(), 0);
199 assert_eq!(p.plus().parse_s("09h3f"), Ok("09h3".to_string()));
200 assert_eq!(p.expected(), OneOf(vec![CharIn("HOT"), CharIn("MNUM")]));
201 assert_eq!(size_of(&p), 0);
202 }
203 #[derive(Clone, PartialEq, Debug)]
204 pub enum Oper {
205 Add,
206 Sub,
207 Div,
208 Mul,
209 Var(String),
210 }
211
212 enum_parser! { (OPER,oper,Oper) =>
213 ((ADD->Oper::Add) '+'),
214 ((SUB->Oper::Sub) '-'),
215 ((DIV->Oper::Div) '/'),
216 ((MUL->Oper::Mul) '*'),
217 (VAR , Alpha.plus().map(|s|Oper::Var(s))),
218 }
219
220 #[test]
221 fn test_enum_group_make_parser() {
222 let v = star(OPER).parse_s("-cat").unwrap();
223 assert_eq!(v, vec![Oper::Sub, Oper::Var("cat".to_string())]);
224
225 let v2 = star(or!(oper::ADD, oper::SUB)).parse_s("-+-hello").unwrap();
226 assert_eq!(v2, vec![Oper::Sub, Oper::Add, Oper::Sub]);
227 }
228}