use orchid_base::error::mk_errv; use orchid_base::interner::is; use orchid_base::number::Numeric; use orchid_extension::func_atom::get_arg; use orchid_extension::tree::{GenMember, fun, prefix}; use ordered_float::NotNan; use rust_decimal::prelude::ToPrimitive; use super::num_atom::{Float, HomoArray, Int, Num}; pub fn gen_num_lib() -> Vec { prefix("std::number", [ fun(false, "add", async |a: Num, b: Num| { Num(match HomoArray::new([a.0, b.0]) { HomoArray::Int([a, b]) => Numeric::Int(a + b), HomoArray::Float([a, b]) => Numeric::Float(a + b), }) }), fun(false, "sub", async |a: Num, b: Num| { Num(match HomoArray::new([a.0, b.0]) { HomoArray::Int([a, b]) => Numeric::Int(a - b), HomoArray::Float([a, b]) => Numeric::Float(a - b), }) }), fun(false, "neg", async |a: Num| { Num(match a.0 { Numeric::Int(i) => Numeric::Int(-i), Numeric::Float(f) => Numeric::Float(-f), }) }), fun(false, "mul", async |a: Num, b: Num| { Num(match HomoArray::new([a.0, b.0]) { HomoArray::Int([a, b]) => Numeric::Int(a * b), HomoArray::Float([a, b]) => Numeric::Float(a * b), }) }), fun(false, "idiv", async |a: Int, b: Int| Int(a.0 / b.0)), fun(false, "imod", async |a: Int, b: Int| Int(a.0 % b.0)), fun(false, "fdiv", async |a: Float, b: Float| Float(a.0 / b.0)), fun(false, "fmod", async |a: Float, b: Float| { Float(a.0 - NotNan::new((a.0 / b.0).trunc()).unwrap() * b.0) }), fun(false, "to_i", async |a: Num| { Ok(Int(match a.0 { Numeric::Int(i) => i, Numeric::Float(f) => match f.to_i64() { Some(i) => i, None => { return Err(mk_errv( is("Float out of range").await, format!("{f} is not representable as an integer"), [get_arg(0).pos().await], )); }, }, })) }), fun(false, "to_f", async |a: Num| Float(a.0.to_f64())), ]) }