#![doc(html_root_url = "https://docs.rs/compile_ops/0.1.2/")]
#![no_std]
extern crate proc_macro;
extern crate alloc;
use proc_macro::TokenStream;
use core::hint::unreachable_unchecked;
use alloc::{ string::{String, ToString}, vec::Vec, format };
#[proc_macro]
pub fn add(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: usize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
let e: usize = e.parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing operand number ");
err.push_str(i.to_string().as_ref());
err.push_str(".\")");
0
});
if err != "" {
return err.parse().unwrap();
}
result += e;
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn sub(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: isize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
if e == "" {
return ("compile_error!(\"Error at parsing operand number ".to_string() +
i.to_string().as_ref() +
".\")").parse().unwrap()
}
let e: isize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
if err != "" {
return err.parse().unwrap();
}
result -= e;
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn mul(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: usize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
if e == "" {
return ("compile_error!(\"Error at parsing operand number ".to_string() +
i.to_string().as_ref() +
".\")").parse().unwrap()
}
let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
if err != "" {
return err.parse().unwrap();
}
result *= e;
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn div(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: usize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
if e == "" {
return ("compile_error!(\"Error at parsing operand number ".to_string() +
i.to_string().as_ref() +
".\")").parse().unwrap()
}
let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
result /= e;
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn rem(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: usize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
if e == "" {
return ("compile_error!(\"Error at parsing operand number ".to_string() +
i.to_string().as_ref() +
".\")").parse().unwrap()
}
let e: usize = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
result %= e;
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn pow(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(',').map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: usize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, e) in it.drain(1..).enumerate() {
if e == "" {
return ("compile_error!(\"Error at parsing operand number ".to_string() +
i.to_string().as_ref() +
".\")").parse().unwrap()
}
let e: u32 = e.parse().unwrap_or_else(|_| unsafe { unreachable_unchecked() });
result = result.pow(e);
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn ops(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut operators = String::with_capacity(input.len());
let mut err = String::with_capacity(64);
let mut it: Vec<String> = input.split(|c: char| {
match c {
'+' => {operators.push('+'); true},
'-' => {operators.push('-'); true},
'*' => {operators.push('*'); true},
'/' => {operators.push('/'); true},
'%' => {operators.push('%'); true},
'^' => {operators.push('^'); true},
_ => false
}
}).map(|e| {
let mut trigger = false;
let mut string = String::with_capacity(e.len()+1);
string.push('0');
string.extend(e.chars().filter(|c| {
if *c == '!' {
trigger = true;
}
c.is_numeric() && !trigger
}));
string
}).collect();
let mut result: isize = it[0].parse().unwrap_or_else(|_| {
err.push_str("compile_error!(\"Error at parsing first operand.\")");
0
});
if err != "" {
return err.parse().unwrap();
}
for (i, (e, op)) in it.drain(1..).zip(operators.chars()).enumerate() {
if e == "" {
return format!("compile_error!(\"Error at parsing operand number {}.\")", i+1).parse().unwrap()
}
let e: isize = match e.parse() {
Ok(i) => i,
Err(_) => return format!("compile_error!(\"Error operand number {} overflows an isize.\")", i+1).parse().unwrap(),
};
match op {
'+' => result = match result.checked_add(e) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
'-' => result = match result.checked_sub(e) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
'*' => result = match result.checked_mul(e) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
'/' => result = match result.checked_div(e) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
'%' => result = match result.checked_rem(e) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
'^' => result = match result.checked_pow(e as u32) {
Some(i) => i,
None => return format!("compile_error!(\"operation number {} failed.\")", i+1).parse().unwrap(),
},
_ => ()
}
}
result.to_string().parse().unwrap()
}
#[proc_macro]
pub fn ternary(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut expansion = String::with_capacity(input.len()+16);
let mut index = input.find('?').unwrap_or_else(|| { expansion.push_str("compile_error!(\"Question mark character(?) not found in ternary operation.\")"); 0});
if expansion != "" {
return expansion.parse().unwrap();
}
if index == 0 {
return "compile_error!(\"Missing boolean expresion behind the question mark character(?).\")".to_string().parse().unwrap();
}
let mut else_case = true;
let (bool_expr, mut other) = input.split_at(index);
other = &other[1..];
index = other.rfind('!').unwrap_or_else(|| {else_case = false; 0});
let (code, mut else_code) = if else_case { other.split_at(index) } else { (other, "!") };
else_code = &else_code[1..];
expansion.push_str("if ");
expansion.push_str(bool_expr);
expansion.push_str(" {");
expansion.push_str(code);
expansion.push_str(" } else { ");
expansion.push_str(else_code);
expansion.push_str(" }");
expansion.parse().unwrap()
}