diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index 457e932..8da186b 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -580,6 +580,18 @@ pub struct PlatformSelectionQuotePlan { pub diagnostics: Vec, } +fn platform_safe_div(lhs: f64, rhs: f64, fallback: f64) -> f64 { + if rhs.abs() <= f64::EPSILON { + fallback + } else { + lhs / rhs + } +} + +fn platform_safe_div_default(lhs: f64, rhs: f64) -> f64 { + platform_safe_div(lhs, rhs, 0.0) +} + impl PlatformExprStrategy { fn market_cap_storage_to_strategy_unit(value: f64) -> f64 { value @@ -608,18 +620,40 @@ impl PlatformExprStrategy { |value: f64, fallback: f64| if value.is_finite() { value } else { fallback }, ); engine.register_fn("safe_div", |lhs: f64, rhs: f64, fallback: f64| { - if rhs.abs() <= f64::EPSILON { - fallback - } else { - lhs / rhs - } + platform_safe_div(lhs, rhs, fallback) + }); + engine.register_fn("safe_div", |lhs: f64, rhs: i64, fallback: f64| { + platform_safe_div(lhs, rhs as f64, fallback) + }); + engine.register_fn("safe_div", |lhs: f64, rhs: f64, fallback: i64| { + platform_safe_div(lhs, rhs, fallback as f64) + }); + engine.register_fn("safe_div", |lhs: f64, rhs: i64, fallback: i64| { + platform_safe_div(lhs, rhs as f64, fallback as f64) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: f64, fallback: f64| { + platform_safe_div(lhs as f64, rhs, fallback) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: i64, fallback: f64| { + platform_safe_div(lhs as f64, rhs as f64, fallback) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: f64, fallback: i64| { + platform_safe_div(lhs as f64, rhs, fallback as f64) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: i64, fallback: i64| { + platform_safe_div(lhs as f64, rhs as f64, fallback as f64) }); engine.register_fn("safe_div", |lhs: f64, rhs: f64| { - if rhs.abs() <= f64::EPSILON { - 0.0 - } else { - lhs / rhs - } + platform_safe_div_default(lhs, rhs) + }); + engine.register_fn("safe_div", |lhs: f64, rhs: i64| { + platform_safe_div_default(lhs, rhs as f64) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: f64| { + platform_safe_div_default(lhs as f64, rhs) + }); + engine.register_fn("safe_div", |lhs: i64, rhs: i64| { + platform_safe_div_default(lhs as f64, rhs as f64) }); engine.register_fn( "iff", @@ -8440,6 +8474,27 @@ mod tests { .expect("two-arg safe_div should evaluate"), 2.0 ); + assert_eq!( + strategy + .engine + .eval::("safe_div(6.0, 3)") + .expect("two-arg safe_div should accept integer rhs"), + 2.0 + ); + assert_eq!( + strategy + .engine + .eval::("safe_div(6, 3.0)") + .expect("two-arg safe_div should accept integer lhs"), + 2.0 + ); + assert_eq!( + strategy + .engine + .eval::("safe_div(6, 3)") + .expect("two-arg safe_div should accept integer literals"), + 2.0 + ); assert_eq!( strategy .engine @@ -8454,6 +8509,20 @@ mod tests { .expect("three-arg safe_div should preserve explicit fallback"), -1.0 ); + assert_eq!( + strategy + .engine + .eval::("safe_div(6.0, 0, -1)") + .expect("three-arg safe_div should accept integer rhs and fallback"), + -1.0 + ); + assert_eq!( + strategy + .engine + .eval::("safe_div(6, 0.0, -1)") + .expect("three-arg safe_div should accept integer lhs and fallback"), + -1.0 + ); } #[test]