Compare commits
2
Commits
143a1ee22f
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52bae6b034
|
||
|
|
48a9837bef
|
No files matched your search
+3
-3
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use crate::math::{lexer, parser, types::Expression};
|
use crate::math::{lexer, parser, types::Expression};
|
||||||
|
|
||||||
type FunctionCallback = Box<dyn Fn(Vec<Expression>) -> Expression>;
|
type FunctionCallback = Box<dyn Fn(&Context, Vec<Expression>) -> Expression>;
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
variables: HashMap<String, Expression>,
|
variables: HashMap<String, Expression>,
|
||||||
@@ -26,7 +26,7 @@ impl Context {
|
|||||||
|
|
||||||
pub fn register_function<F>(&mut self, name: &str, callback: F)
|
pub fn register_function<F>(&mut self, name: &str, callback: F)
|
||||||
where
|
where
|
||||||
F: Fn(Vec<Expression>) -> Expression + 'static,
|
F: Fn(&Context, Vec<Expression>) -> Expression + 'static,
|
||||||
{
|
{
|
||||||
self.functions.insert(name.to_owned(), Box::new(callback));
|
self.functions.insert(name.to_owned(), Box::new(callback));
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let func = func.unwrap();
|
let func = func.unwrap();
|
||||||
func(params)
|
func(self, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_variable(&self, name: &str) -> Option<&Expression> {
|
pub fn get_variable(&self, name: &str) -> Option<&Expression> {
|
||||||
|
|||||||
+64
-18
@@ -2,45 +2,91 @@ use crate::math::context::Context;
|
|||||||
use crate::math::types::Expression;
|
use crate::math::types::Expression;
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
use rust_decimal::MathematicalOps;
|
use rust_decimal::MathematicalOps;
|
||||||
|
use rust_decimal::RoundingStrategy;
|
||||||
|
use rust_decimal::dec;
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn register_builtin_functions(&mut self) {
|
pub fn register_builtin_functions(&mut self) {
|
||||||
self.register_function("abs", |params: Vec<Expression>| {
|
self.register_function("abs", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| d.abs())
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.abs())
|
||||||
});
|
});
|
||||||
self.register_function("sqrt", |params: Vec<Expression>| {
|
self.register_function("sqrt", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| d.abs().sqrt().unwrap())
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
|
||||||
|
d.abs().sqrt().unwrap()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
self.register_function("sin", |params: Vec<Expression>| {
|
self.register_function("sin", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| d.sin())
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.sin())
|
||||||
});
|
});
|
||||||
self.register_function("cos", |params: Vec<Expression>| {
|
self.register_function("cos", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| d.cos())
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.cos())
|
||||||
});
|
});
|
||||||
self.register_function("tan", |params: Vec<Expression>| {
|
self.register_function("tan", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| d.tan())
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.tan())
|
||||||
});
|
});
|
||||||
self.register_function("asin", |params: Vec<Expression>| {
|
self.register_function("asin", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| map_f64(&d, |f| f.asin()))
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
|
||||||
|
map_f64(&d, |f| f.asin())
|
||||||
|
})
|
||||||
});
|
});
|
||||||
self.register_function("acos", |params: Vec<Expression>| {
|
self.register_function("acos", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| map_f64(&d, |f| f.acos()))
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
|
||||||
|
map_f64(&d, |f| f.acos())
|
||||||
|
})
|
||||||
});
|
});
|
||||||
self.register_function("atan", |params: Vec<Expression>| {
|
self.register_function("atan", |ctx, params: Vec<Expression>| {
|
||||||
map_decimal(¶ms[0], |d| map_f64(&d, |f| f.atan()))
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
|
||||||
|
map_f64(&d, |f| f.atan())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
self.register_function("round", |ctx, params: Vec<Expression>| {
|
||||||
|
let decimal = if params.len() == 2 {
|
||||||
|
if let Some(d) = get_decimal(¶ms[1]) {
|
||||||
|
d
|
||||||
|
} else {
|
||||||
|
dec!(0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dec!(0)
|
||||||
|
}
|
||||||
|
.to_u32()
|
||||||
|
.expect("unable to parse decimal number");
|
||||||
|
|
||||||
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
|
||||||
|
d.round_dp_with_strategy(decimal, RoundingStrategy::MidpointAwayFromZero)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
self.register_function("floor", |ctx, params: Vec<Expression>| {
|
||||||
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.floor())
|
||||||
|
});
|
||||||
|
self.register_function("ceil", |ctx, params: Vec<Expression>| {
|
||||||
|
map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.ceil())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_decimal(expr: &Expression, f: fn(Decimal) -> Decimal) -> Expression {
|
fn get_decimal(expr: &Expression) -> Option<Decimal> {
|
||||||
|
match expr {
|
||||||
|
Expression::Number(d) => Some(*d),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_decimal<F>(expr: &Expression, f: F) -> Expression
|
||||||
|
where
|
||||||
|
F: Fn(Decimal) -> Decimal,
|
||||||
|
{
|
||||||
match expr {
|
match expr {
|
||||||
Expression::Number(d) => Expression::Number(f(*d)),
|
Expression::Number(d) => Expression::Number(f(*d)),
|
||||||
_ => panic!("expected decimal"),
|
_ => panic!("expected decimal"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_f64(decimal: &Decimal, f: fn(f64) -> f64) -> Decimal {
|
fn map_f64<F>(decimal: &Decimal, f: F) -> Decimal
|
||||||
|
where
|
||||||
|
F: Fn(f64) -> f64,
|
||||||
|
{
|
||||||
let num = decimal.to_f64().expect("unable to unwrap decimal");
|
let num = decimal.to_f64().expect("unable to unwrap decimal");
|
||||||
let num = f(num);
|
let num = f(num);
|
||||||
Decimal::from_f64_retain(num).expect("unable to wrap decimal")
|
Decimal::from_f64_retain(num).expect("unable to wrap decimal")
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use crate::math::types::Expression;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user