1#[macro_export]
2macro_rules! helper {
3 (exists_or_zero;) => {
4 1
5 };
6 (exists_or_zero;$t:tt) => {
7 $t
8 };
9 (exists;,$then:ty) => {
10 $then
11 };
12 (exists;$t:tt, $then:ty) => {
13 Vec<$then>
14 };
15 (exists_flag;,$then:ty) => {
16 Option<$then>
17 };
18 (exists_flag;$t:tt, $then:ty) => {
19 Vec<$then>
20 };
21 (exists_add;,$var:ident, $type:ty, $d:ident, $db:ident) => {
22 $var = <$type>::from($d.get($db).expect("this is an error on line 22, please report this bug").clone());
23 $d.remove($db);
24 };
25 (exists_add;$t:tt,$var:ident, $type:ty, $d:ident, $db:ident) => {
26 for _ in 0..$t {
27 $var.push(<$type>::from($d.get($db).expect("this is an error on line 27, please report this bug").clone()));
28 $d.remove($db);
29 }
30 };
31 (exists_add_flag;,$var:ident, $type:ty, $d:ident, $db:expr) => {
32 $var = Some(<$type>::from($d.get($db).expect("this is an error on line 32, please report this bug").clone()));
33 $d.remove($db);
34 };
35 (exists_add_flag;$t:tt,$var:ident, $type:ty, $d:ident, $db:expr) => {
36 for _ in 0..$t {
37 $var.push(<$type>::from($d.get($db).expect("this is an error on line 37, please report this bug").clone()));
38 $d.remove($db);
39 }
40 };
41 (exists_declare;,$var:ident, $type:ty) => {
42 let $var: $type;
43 };
44 (exists_declare;$t:tt,$var:ident, $type:ty) => {
45 let mut $var: Vec<$type> = Vec::new();
46 };
47 (exists_declare_flag;,$var:ident, $type:ty) => {
48 let mut $var: Option<$type> = None;
49 };
50 (exists_declare_flag;$t:tt,$var:ident, $type:ty) => {
51 let mut $var: Vec<$type> = Vec::new();
52 };
53}
54
55#[macro_export]
56macro_rules! cmd {
57 ($name:ident; help:$help:literal; $($fname:ident => $($str:literal)|*),*$(,)?) => {
58 struct $name;
59 impl $name {
60 pub fn run(v: Vec<String>) {
61 let cmd = v.get(0).expect($help).clone();
62 if cmd == "help" {
63 println!($help);
64 std::process::exit(0);
65 } else
66 $(
67 if $(cmd == $str)||* {
68 $fname(v);
69 } else
70 )* {
71 eprintln!($help);
72 std::process::exit(101);
73 }
74 }
75 }
76 };
77 (help:$help:literal; $($fname:ident => $($str:literal)|*),*$(,)?) => {
78 fn main() {
79 _Main::run(std::env::args().skip(1).collect());
80 }
81 $crate::cmd!{
82 _Main;
83 help:$help;
84 $($fname => $($str)|*),*
85 }
86 };
87}
88
89#[macro_export]
90macro_rules! define {
91 ($name:ident; help: $help:literal; flags {
92 $($fname:ident: $ftype:ty = $($flag:literal)|* $(=> [$fnum:literal])?),*$(,)?
93 }; args {
94 $($aname:ident: $atype:ty $(=> [$num:literal])?),*$(,)?
95 };
96 $(rest => $rname:ident: $rtype:ty;)?) => {
97 #[derive(Debug, Clone)]
98 struct $name {
99 $($fname: tt_call::tt_if!{
100 condition = [{tt_equal::tt_equal}]
101 input = [{ $ftype bool }]
102 true = [{
103 bool
104 }]
105 false = [{
106 $crate::helper!(exists_flag;$($fnum)?, $ftype)
107 }]
108 },)*
109 $(
110 $aname: $crate::helper!(exists;$($num)?, $atype),
111 )*
112 $(
113 $rname: Vec<$rtype>
114 )?
115 }
116 impl $name {
117 pub fn from(mut __args: Vec<String>) -> Self{
118 let mut __handle_flags = true;
119 $(
120 tt_call::tt_if!{
121 condition = [{tt_equal::tt_equal}]
122 input = [{ $ftype bool }]
123 true = [{
124 let mut $fname: bool = false;
125 }]
126 false = [{
127 $crate::helper!(exists_declare_flag;$($fnum)?, $fname, $ftype);
128 }]
129 }
130 )*
131 $(
132 $crate::helper!(exists_declare;$($num)?,$aname, $atype);
133 )*
134 $(
135 let mut $rname: Vec<$rtype> = Vec::new();
136 )?
137 if __args.contains(&"-help".to_string()) || __args.contains(&"--help".to_string()) {
138 eprintln!($help);
139 std::process::exit(0);
140 }
141 let mut __i = 0;
142 $(
143 if __args.len() == 0 {
144 eprintln!("missing argument: '{}'", stringify!($aname));
145 std::process::exit(101);
146 }
147 while __args.get(__i).expect("there is an error on line 146, please report this bug").starts_with("-") && __handle_flags {
148 let v = Self::has_args(__args.get(__i).expect("there is an error on line 147, please report this bug").clone());
149 __args.get_mut(__i).expect("there is an error on line 148, please report this bug").insert(0, '-');
150 if v.0 {
151 __i += v.1;
152 if __args.get(__i).expect("there is an error on line 151, please report this bug").starts_with("-") && __handle_flags {
153 eprintln!("the flag requires an argument");
154 std::process::exit(101);
155 }
156 }
157 __i += 1;
158 }
159
160 $crate::helper!(exists_add; $($num)?, $aname, $atype, __args, __i);
161 )*
162 $(
163 while __args.len() - __i > 0 {
164 if __args.get(__i).expect("there is an error on line 163, please report this bug").starts_with("-") && __handle_flags {
165 if $rname.len() > 0 {
166 break;
167 }
168 while __args.get(__i).unwrap_or(&String::new()).starts_with("-") && __handle_flags {
169 let v = Self::has_args(__args.get(__i).expect("there is an error on line 168, please report this bug").clone());
170 if __args[__i] == "--" {
171 __handle_flags = false;
172 __args.remove(__i);
173 break;
174 }
175 __args.get_mut(__i).expect("there is an error on line 169, please report this bug").insert(0, '-');
176 if v.0 {
177 __i += v.1;
178 if __args.get(__i).unwrap_or(&String::from("-")).starts_with("-") && __handle_flags {
179 eprintln!("the flag requires an argument");
180 std::process::exit(101);
181 }
182 }
183 __i += 1;
184 }
185 }
186
187 if let Some(s) = __args.get(__i) {
188 $rname.push(<$rtype>::from(s.clone()));
189 __args.remove(__i);
190 }
191
192 }
193 )?
194 while __args.len() > 0 {
195 let mut __ch = __args.get(0).expect("there is an error on line 186, please report this bug").clone();
196 if !(__ch.starts_with("-") && __handle_flags) {
197 eprintln!("too many arguments");
198 std::process::exit(101);
199 }
200 __ch.remove(0);
201 if __ch.starts_with("-") && __handle_flags {
202 __ch.remove(0);
203 }
204 $(
205 if $(__ch == $flag)||* {
206 tt_call::tt_if!{
207 condition = [{tt_equal::tt_equal}]
208 input = [{ $ftype bool }]
209 true = [{
210 $fname = true;
211 }]
212 false = [{
213 if __args[1].starts_with("-") && __handle_flags {
214 eprintln!("flags requires an argument");
215 std::process::exit(101);
216 }
217 $crate::helper!(exists_add_flag;$($fnum)?, $fname, $ftype, __args, 1);
218 }]
219 }
220 __args.remove(0);
221 continue;
222 } else
223 )*
224 if (__ch == "-") {
225 __handle_flags = false;
226 __args.remove(0);
227 break
228 }
229 eprintln!("invalid flag {}", __ch);
230 std::process::exit(101);
231 }
232 return Self {
233 $($fname,)*
234 $($aname,)*
235 $($rname)?
236 }
237 }
238 fn has_args(v: String) -> (bool, usize) {
239 $(
240 if $(v == concat!("-", $flag) || v == concat!("--", $flag))||* {
241 tt_call::tt_if!{
242 condition = [{tt_equal::tt_equal}]
243 input = [{ $ftype bool }]
244 true = [{
245 return (false, 0);
246 }]
247 false = [{
248 return (true, $crate::helper!(exists_or_zero;$($fnum)?));
249 }]
250 }
251 } else
252 )*
253 if(v == "--") {
254 return (false, 0);
255 }
256 eprintln!("invalid flag {}", v);
257 std::process::exit(101);
258 }
259 }
260 };
261}