git.delta.rocks / jrsonnet / refs/commits / 8954130fcd4f

difftreelog

feat more math operations for bigint (#198)

Valera Klachkov2026-02-03parent: #a03224f.patch.diff
in: master
* feat: properly implement math ops for bigint

* feat: remove bigint x string and bigint x num ops

every op now requires explicit conversion

* fix: remove dead code

1 file changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
22
3use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};3use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};
44
5#[cfg(feature = "exp-bigint")]
6use num_traits::{FromPrimitive, ToPrimitive};
7
8#[cfg(feature = "exp-bigint")]
9use crate::val::NumValue;
5use crate::{10use crate::{
6 arr::ArrValue,11 arr::ArrValue,
7 bail,12 bail,
51 })58 })
52}59}
60
61pub fn evaluate_sub_op(a: &Val, b: &Val) -> Result<Val> {
62 use Val::*;
63 Ok(match (a, b) {
64 (Num(v1), Num(v2)) => Val::try_num(v1.get() - v2.get())?,
65
66 #[cfg(feature = "exp-bigint")]
67 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a - &**b)),
68
69 // TODO: Support objects and arrays
70 _ => bail!(BinaryOperatorDoesNotOperateOnValues(
71 BinaryOpType::Sub,
72 a.value_type(),
73 b.value_type(),
74 )),
75 })
76}
77
78pub fn evaluate_mul_op(a: &Val, b: &Val) -> Result<Val> {
79 use Val::*;
80 Ok(match (a, b) {
81 (Str(s), Num(c)) => Val::string(s.to_string().repeat(c.get() as usize)),
82 (Num(c), Str(s)) => Val::string(s.to_string().repeat(c.get() as usize)),
83
84 (Num(v1), Num(v2)) => Val::try_num(v1.get() * v2.get())?,
85
86 #[cfg(feature = "exp-bigint")]
87 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a * &**b)),
88
89 _ => bail!(BinaryOperatorDoesNotOperateOnValues(
90 BinaryOpType::Mul,
91 a.value_type(),
92 b.value_type(),
93 )),
94 })
95}
96
97fn is_attempt_to_divide_by_zero(a: &Val, b: &Val) -> bool {
98 use Val::*;
99 match (a, b) {
100 // string format
101 (Str(_), _) => false,
102
103 (_, Num(b)) => return **b == 0.,
104 #[cfg(feature = "exp-bigint")]
105 (_, BigInt(b)) => return **b == num_bigint::BigInt::ZERO,
106
107 // something else
108 _ => false,
109 }
110}
111
112pub fn evaluate_div_op(a: &Val, b: &Val) -> Result<Val> {
113 use Val::*;
114
115 if is_attempt_to_divide_by_zero(a, b) {
116 bail!(DivisionByZero);
117 }
118
119 Ok(match (a, b) {
120 (Num(a), Num(b)) => Val::try_num(a.get() / b.get())?,
121 #[cfg(feature = "exp-bigint")]
122 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a / &**b)),
123 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(
124 BinaryOpType::Div,
125 a.value_type(),
126 b.value_type()
127 )),
128 })
129}
53130
54pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {131pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {
55 use Val::*;132 use Val::*;
133
134 if is_attempt_to_divide_by_zero(a, b) {
135 bail!(DivisionByZero);
136 }
137
56 match (a, b) {138 Ok(match (a, b) {
57 (Num(a), Num(b)) => {139 (Num(a), Num(b)) => Val::try_num(a.get() % b.get())?,
58 if b.get() == 0.0 {140 #[cfg(feature = "exp-bigint")]
59 bail!(DivisionByZero)141 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a % &**b)),
60 }
61 Ok(Val::try_num(a.get() % b.get())?)
62 }
63 (Str(str), vals) => {142 (Str(str), vals) => {
64 String::into_untyped(std_format(&str.clone().into_flat(), vals.clone())?)143 String::into_untyped(std_format(&str.clone().into_flat(), vals.clone())?)?
65 }144 }
66 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(145 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(
67 BinaryOpType::Mod,146 BinaryOpType::Mod,
68 a.value_type(),147 a.value_type(),
69 b.value_type()148 b.value_type()
70 )),149 )),
71 }150 })
72}151}
73152
74pub fn evaluate_binary_op_special(153pub fn evaluate_binary_op_special(
121 use BinaryOpType::*;203 use BinaryOpType::*;
122 use Val::*;204 use Val::*;
123 Ok(match (a, op, b) {205 Ok(match (a, op, b) {
124 (a, Add, b) => evaluate_add_op(a, b)?,
125
126 (a, Eq, b) => Bool(equals(a, b)?),206 (a, Eq, b) => Bool(equals(a, b)?),
127 (a, Neq, b) => Bool(!equals(a, b)?),207 (a, Neq, b) => Bool(!equals(a, b)?),
132 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),212 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),
133213
134 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone().into_flat(), true)),214 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone().into_flat(), true)),
135 (a, Mod, b) => evaluate_mod_op(a, b)?,
136
137 (Str(v1), Mul, Num(v2)) => Val::string(v1.to_string().repeat(v2.get() as usize)),
138215
139 // Bool X Bool216 // Bool X Bool
140 (Bool(a), And, Bool(b)) => Bool(*a && *b),217 (Bool(a), And, Bool(b)) => Bool(*a && *b),
141 (Bool(a), Or, Bool(b)) => Bool(*a || *b),218 (Bool(a), Or, Bool(b)) => Bool(*a || *b),
142219
143 // Num X Num220 (a, Add, b) => evaluate_add_op(a, b)?,
221 (a, Sub, b) => evaluate_sub_op(a, b)?,
144 (Num(v1), Mul, Num(v2)) => Val::try_num(v1.get() * v2.get())?,222 (a, Mul, b) => evaluate_mul_op(a, b)?,
145 (Num(v1), Div, Num(v2)) => {223 (a, Div, b) => evaluate_div_op(a, b)?,
146 if v2.get() == 0.0 {
147 bail!(DivisionByZero)
148 }
149 Val::try_num(v1.get() / v2.get())?
150 }
151
152 (Num(v1), Sub, Num(v2)) => Val::try_num(v1.get() - v2.get())?,224 (a, Mod, b) => evaluate_mod_op(a, b)?,
153225
154 (Num(v1), BitAnd, Num(v2)) => Val::try_num((v1.get() as i64 & v2.get() as i64) as f64)?,226 (Num(v1), BitAnd, Num(v2)) => Val::try_num((v1.get() as i64 & v2.get() as i64) as f64)?,
155 (Num(v1), BitOr, Num(v2)) => Val::try_num((v1.get() as i64 | v2.get() as i64) as f64)?,227 (Num(v1), BitOr, Num(v2)) => Val::try_num((v1.get() as i64 | v2.get() as i64) as f64)?,
170 }242 }
171243
172 // Bigint X Bigint244 // Bigint X Bigint
173 #[cfg(feature = "exp-bigint")]
174 (BigInt(a), Mul, BigInt(b)) => BigInt(Box::new(&**a * &**b)),
175 #[cfg(feature = "exp-bigint")]
176 (BigInt(a), Sub, BigInt(b)) => BigInt(Box::new(&**a - &**b)),
177
178 _ => bail!(BinaryOperatorDoesNotOperateOnValues(245 _ => bail!(BinaryOperatorDoesNotOperateOnValues(
179 op,246 op,