1#![doc(html_root_url = "https://docs.rs/compile_ops/0.1.3/")]
2#![no_std]
3extern crate proc_macro;
30extern crate alloc;
31
32use proc_macro::TokenStream;
33use core::hint::unreachable_unchecked;
34use alloc::{ string::{String, ToString}, vec::Vec, format };
35
36#[proc_macro]
38pub fn add(input: TokenStream) -> TokenStream {
39 let input = input.to_string();
40
41 let mut err = String::with_capacity(64);
42
43 let mut it: Vec<String> = input.split(',').map(|e| {
44 let mut trigger = false;
45 let mut string = String::with_capacity(e.len()+1);
46
47 string.push('0');
48
49 string.extend(e.chars().filter(|c| {
50 if *c == '!' {
51 trigger = true;
52 }
53
54 c.is_numeric() && !trigger
55 }));
56
57 string
58 }).collect();
59
60 let mut result: usize = it[0].parse().unwrap_or_else(|_| {
61 err.push_str("compile_error!(\"Error at parsing first operand.\")");
62 0
63 });
64
65 if err != "" {
66 return err.parse().unwrap();
67 }
68
69 for (i, e) in it.drain(1..).enumerate() {
70 let e: usize = e.parse().unwrap_or_else(|_| {
71 err.push_str("compile_error!(\"Error at parsing operand number ");
72 err.push_str(i.to_string().as_ref());
73 err.push_str(".\")");
74 0
75 });
76
77 if err != "" {
78 return err.parse().unwrap();
79 }
80
81 result += e;
82 }
83
84 result.to_string().parse().unwrap()
85}
86
87#[proc_macro]
89pub fn sub(input: TokenStream) -> TokenStream {
90 let input = input.to_string();
91 let mut err = String::with_capacity(64);
92
93 let mut it: Vec<String> = input.split(',').map(|e| {
94 let mut trigger = false;
95 let mut string = String::with_capacity(e.len()+1);
96
97 string.push('0');
98
99 string.extend(e.chars().filter(|c| {
100 if *c == '!' {
101 trigger = true;
102 }
103
104 c.is_numeric() && !trigger
105 }));
106
107 string
108 }).collect();
109
110 let mut result: isize = it[0].parse().unwrap_or_else(|_| {
111 err.push_str("compile_error!(\"Error at parsing first operand.\")");
112 0
113 });
114
115 if err != "" {
116 return err.parse().unwrap();
117 }
118
119 for (i, e) in it.drain(1..).enumerate() {
120
121 if e == "" {
122 return ("compile_error!(\"Error at parsing operand number ".to_string() +
123 i.to_string().as_ref() +
124 ".\")").parse().unwrap()
125 }
126
127 let e: isize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
128
129 if err != "" {
130 return err.parse().unwrap();
131 }
132
133 result -= e;
134 }
135
136 result.to_string().parse().unwrap()
137}
138
139#[proc_macro]
141pub fn mul(input: TokenStream) -> TokenStream {
142 let input = input.to_string();
143 let mut err = String::with_capacity(64);
144
145 let mut it: Vec<String> = input.split(',').map(|e| {
146 let mut trigger = false;
147 let mut string = String::with_capacity(e.len()+1);
148
149 string.push('0');
150
151 string.extend(e.chars().filter(|c| {
152 if *c == '!' {
153 trigger = true;
154 }
155
156 c.is_numeric() && !trigger
157 }));
158
159 string
160 }).collect();
161
162 let mut result: usize = it[0].parse().unwrap_or_else(|_| {
163 err.push_str("compile_error!(\"Error at parsing first operand.\")");
164 0
165 });
166
167 if err != "" {
168 return err.parse().unwrap();
169 }
170
171 for (i, e) in it.drain(1..).enumerate() {
172 if e == "" {
173 return ("compile_error!(\"Error at parsing operand number ".to_string() +
174 i.to_string().as_ref() +
175 ".\")").parse().unwrap()
176 }
177
178 let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
179
180 if err != "" {
181 return err.parse().unwrap();
182 }
183
184 result *= e;
185 }
186
187 result.to_string().parse().unwrap()
188}
189
190#[proc_macro]
192pub fn div(input: TokenStream) -> TokenStream {
193 let input = input.to_string();
194 let mut err = String::with_capacity(64);
195
196 let mut it: Vec<String> = input.split(',').map(|e| {
197 let mut trigger = false;
198 let mut string = String::with_capacity(e.len()+1);
199
200 string.push('0');
201
202 string.extend(e.chars().filter(|c| {
203 if *c == '!' {
204 trigger = true;
205 }
206
207 c.is_numeric() && !trigger
208 }));
209
210 string
211 }).collect();
212
213 let mut result: usize = it[0].parse().unwrap_or_else(|_| {
214 err.push_str("compile_error!(\"Error at parsing first operand.\")");
215 0
216 });
217
218 if err != "" {
219 return err.parse().unwrap();
220 }
221
222 for (i, e) in it.drain(1..).enumerate() {
223 if e == "" {
224 return ("compile_error!(\"Error at parsing operand number ".to_string() +
225 i.to_string().as_ref() +
226 ".\")").parse().unwrap()
227 }
228
229 let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
230
231 result /= e;
232 }
233
234 result.to_string().parse().unwrap()
235}
236
237#[proc_macro]
239pub fn rem(input: TokenStream) -> TokenStream {
240 let input = input.to_string();
241 let mut err = String::with_capacity(64);
242
243 let mut it: Vec<String> = input.split(',').map(|e| {
244 let mut trigger = false;
245 let mut string = String::with_capacity(e.len()+1);
246
247 string.push('0');
248
249 string.extend(e.chars().filter(|c| {
250 if *c == '!' {
251 trigger = true;
252 }
253
254 c.is_numeric() && !trigger
255 }));
256
257 string
258 }).collect();
259
260 let mut result: usize = it[0].parse().unwrap_or_else(|_| {
261 err.push_str("compile_error!(\"Error at parsing first operand.\")");
262 0
263 });
264
265 if err != "" {
266 return err.parse().unwrap();
267 }
268
269 for (i, e) in it.drain(1..).enumerate() {
270 if e == "" {
271 return ("compile_error!(\"Error at parsing operand number ".to_string() +
272 i.to_string().as_ref() +
273 ".\")").parse().unwrap()
274 }
275
276 let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
277
278 result %= e;
279 }
280
281 result.to_string().parse().unwrap()
282}
283
284#[proc_macro]
286pub fn pow(input: TokenStream) -> TokenStream {
287 let input = input.to_string();
288 let mut err = String::with_capacity(64);
289
290 let mut it: Vec<String> = input.split(',').map(|e| {
291 let mut trigger = false;
292 let mut string = String::with_capacity(e.len()+1);
293
294 string.push('0');
295
296 string.extend(e.chars().filter(|c| {
297 if *c == '!' {
298 trigger = true;
299 }
300
301 c.is_numeric() && !trigger
302 }));
303
304 string
305 }).collect();
306
307 let mut result: usize = it[0].parse().unwrap_or_else(|_| {
308 err.push_str("compile_error!(\"Error at parsing first operand.\")");
309 0
310 });
311
312 if err != "" {
313 return err.parse().unwrap();
314 }
315
316 for (i, e) in it.drain(1..).enumerate() {
317 if e == "" {
318 return ("compile_error!(\"Error at parsing operand number ".to_string() +
319 i.to_string().as_ref() +
320 ".\")").parse().unwrap()
321 }
322
323 let e: u32 = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
324
325 result = result.pow(e);
326 }
327
328 result.to_string().parse().unwrap()
329}
330
331#[proc_macro]
336pub fn ops(input: TokenStream) -> TokenStream {
337 let input = input.to_string();
338
339 let mut operators = String::with_capacity(input.len());
340 let mut err = String::with_capacity(64);
341
342 let mut it: Vec<String> = input.split(|c: char| {
343 match c {
344 '+' => {operators.push('+'); true},
345 '-' => {operators.push('-'); true},
346 '*' => {operators.push('*'); true},
347 '/' => {operators.push('/'); true},
348 '%' => {operators.push('%'); true},
349 '^' => {operators.push('^'); true},
350 _ => false
351 }
352 }).map(|e| {
353 let mut trigger = false;
354 let mut string = String::with_capacity(e.len()+1);
355
356 string.push('0');
357
358 string.extend(e.chars().filter(|c| {
359 if *c == '!' {
360 trigger = true;
361 }
362
363 c.is_numeric() && !trigger
364 }));
365
366 string
367 }).collect();
368
369 let mut result: isize = it[0].parse().unwrap_or_else(|_| {
370 err.push_str("compile_error!(\"Error at parsing first operand.\")");
371 0
372 });
373
374 if err != "" {
375 return err.parse().unwrap();
376 }
377
378 for (i, (e, op)) in it.drain(1..).zip(operators.chars()).enumerate() {
379
380 if e == "" {
381 return format!("compile_error!(\"Error at parsing operand number {}.\")", i+1).parse().unwrap()
382 }
383
384 let e: isize = match e.parse() {
385 Ok(i) => i,
386 Err(_) => return format!("compile_error!(\"Error operand number {} overflows an isize.\")", i+1).parse().unwrap(),
387 };
388
389 match op {
390 '+' => result = match result.checked_add(e) {
391 Some(i) => i,
392 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
393 },
394
395 '-' => result = match result.checked_sub(e) {
396 Some(i) => i,
397 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
398 },
399
400 '*' => result = match result.checked_mul(e) {
401 Some(i) => i,
402 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
403 },
404
405 '/' => result = match result.checked_div(e) {
406 Some(i) => i,
407 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
408 },
409
410 '%' => result = match result.checked_rem(e) {
411 Some(i) => i,
412 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
413 },
414
415 '^' => result = match result.checked_pow(e as u32) {
416 Some(i) => i,
417 None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
418 },
419
420 _ => ()
421 }
422 }
423
424 result.to_string().parse().unwrap()
425}
426
427#[proc_macro]
457pub fn ternary(input: TokenStream) -> TokenStream {
458 let input = input.to_string();
459 let mut expansion = String::with_capacity(input.len()+16);
460
461 let mut index = input.find('?').unwrap_or_else(|| { expansion.push_str("compile_error!(\"Question mark character(?) not found in ternary operation.\")"); 0});
462
463 if expansion != "" {
464 return expansion.parse().unwrap();
465 }
466
467 if index == 0 {
468 return "compile_error!(\"Missing boolean expresion behind the question mark character(?).\")".to_string().parse().unwrap();
469 }
470
471 let mut else_case = true;
472 let (bool_expr, mut other) = input.split_at(index);
473
474 other = &other[1..];
475
476 index = other.rfind('!').unwrap_or_else(|| {else_case = false; 0});
477
478 let (code, mut else_code) = if else_case { other.split_at(index) } else { (other, "") };
479
480 if else_case {
481 else_code = &else_code[1..];
482 }
483
484 expansion.push_str("if ");
485 expansion.push_str(bool_expr);
486 expansion.push_str(" {");
487 expansion.push_str(code);
488 expansion.push_str(" }");
489
490 if else_case {
491 expansion.push_str(" else { ");
492 expansion.push_str(else_code);
493 expansion.push_str(" }");
494 }
495
496 expansion.parse().unwrap()
497}