Anita is a JIT compiler that allows runtime compilation of math expressions.
Anita compiles a given expression and returns a structure with a function that follows a given signature. This can be achieved by using the compile_expression! macro.
let expression: String = "x+1".to_owned(); // This can be anything implementing AsRef<str>
let function: CompiledFunction<fn(f32) -> f32> = compile_expression!(expression, (x) -> f32).unwrap();
assert_eq!(function(4_f32), 5_f32);This is the current state of features in anita
Anita can support any type implementing the AnitaType trait but only can support one type at a time which is speccified by the return type in the compile_expression! macro.
| Type | Status |
|---|---|
| f32 | supported |
| f64 | untested |
| Operator | Description |
|---|---|
| ^ | Exponentiation |
| * | Product |
| / | Division |
| % | Modulo |
| + | Sum |
| - | Difference |
| < | Lower than |
| > | Greater than |
| <= | Lower than or equal |
| >= | Greater than or equal |
| == | Equal |
| != | Not equal |
| && | Logical and |
| || | Logical or |
| = | Assignment |
| ; | Expression Chaining |
| - (unary) | Negation |
| ! | Logical not |
Anita ships with a set of default functions for the f32 type. If these are not used the no-default-functions feature can be enabled to reduce compiler overhead.
| Identifier | Argument Amount | Description |
|---|---|---|
min |
2 | see core::f32::min |
max |
2 | see core::f32::max |
floor |
1 | see std::f32::floor |
round |
1 | see std::f32::round |
ceil |
1 | see std::f32::ceil |
if |
3 | If the first argument is normal and not equal to 0.0, returns the second argument, otherwise, returns the third |
is_nan |
1 | see core::f32::is_nan. The return value is mapped to 1.0 if true and 0.0 if false |
is_finite |
1 | see core::f32::is_finite. The return value is mapped to 1.0 if true and 0.0 if false |
is_infinite |
1 | see core::f32::is_infinite. The return value is mapped to 1.0 if true and 0.0 if false |
is_normal |
1 | see core::f32::is_normal. The return value is mapped to 1.0 if true and 0.0 if false |
mod |
2 | see core::f32::rem |
ln |
1 | see std::f32::ln |
log |
2 | see std::f32::log |
log2 |
1 | see std::f32::log2 |
log10 |
1 | see std::f32::log10 |
exp |
1 | see std::f32::exp |
exp2 |
1 | see std::f32::exp2 |
pow |
2 | see std::f32::powf |
cos |
1 | see std::f32::cos |
acos |
1 | see std::f32::acos |
cosh |
1 | see std::f32::cosh |
acosh |
1 | see std::f32::acosh |
sin |
1 | see std::f32::sin |
asin |
1 | see std::f32::asin |
sinh |
1 | see std::f32::sinh |
asinh |
1 | see std::f32::asinh |
tan |
1 | see std::f32::tan |
atan |
1 | see std::f32::atan |
atan2 |
2 | see std::f32::atan2 |
tanh |
1 | see std::f32::tanh |
atanh |
1 | see std::f32::atanh |
sqrt |
1 | see std::f32::sqrt |
cbrt |
1 | see std::f32::cbrt |
hypot |
2 | see std::f32::hypot |
abs |
1 | see core::f32::abs |
If different functions are needed, they can be introduced using the FunctionManager trait.
To construct a function Manager it is advised to use the #[function_manager] macro attribute.
By default using the custom functions will have the same name as they are declared with. This can be overwritten using the #[name = "other_name"] attribute.
struct CustomFunctions {}
#[function_manager]
impl CustomFunctions {
fn custom(x: f32) -> f32 {
x + 1.0
}
#[name = "not_zero"]
fn custom_if_not_zero(x: f32) -> f32 {
(x != 0.0) as u8 as f32
}
}
#[cfg(tests)]
mod test {
#[test]
fn it_works() {
let function: CompiledFunction<fn(f32) -> f32> = compile_expression!("not_zero(custom(x))", (x) -> f32, CustomFunctions).unwrap();
assert_eq(function(-1.0), 0.0);
assert_eq(function(42.0), 1.0);
}
}TODO!
Anita uses a custom language frontend inspired by the evalexpr crate.
The name anita is inspired by the first all-electronic desktop calculator ANITA