fix(eval): allow expressions in functions

added:
- pass context to function calls
fixed:
- functions not evaluating expressions inside their params
This commit is contained in:
ozzy committed 2026-09-28 20:32:43 -05:00
1 parent 48a9837bef
commit 52bae6b034
2 files changed
+33 -25

No files matched your search

+3 -3
View File
@@ -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> {
+30 -22
View File
@@ -8,31 +8,39 @@ 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(&params[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(&params[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(&params[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(&params[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(&params[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(&params[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(&params[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(&params[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", |params: Vec<Expression>| { self.register_function("round", |ctx, params: Vec<Expression>| {
let decimal = if params.len() == 2 { let decimal = if params.len() == 2 {
if let Some(d) = get_decimal(&params[1]) { if let Some(d) = get_decimal(&params[1]) {
d d
@@ -45,15 +53,15 @@ impl Context {
.to_u32() .to_u32()
.expect("unable to parse decimal number"); .expect("unable to parse decimal number");
map_decimal(&params[0], |d| { map_decimal(&ctx.eval_expr(params[0].clone()), |d| {
d.round_dp_with_strategy(decimal, RoundingStrategy::MidpointAwayFromZero) d.round_dp_with_strategy(decimal, RoundingStrategy::MidpointAwayFromZero)
}) })
}); });
self.register_function("floor", |params: Vec<Expression>| { self.register_function("floor", |ctx, params: Vec<Expression>| {
map_decimal(&params[0], |d| d.floor()) map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.floor())
}); });
self.register_function("ceil", |params: Vec<Expression>| { self.register_function("ceil", |ctx, params: Vec<Expression>| {
map_decimal(&params[0], |d| d.ceil()) map_decimal(&ctx.eval_expr(params[0].clone()), |d| d.ceil())
}); });
} }
} }