1use std::cmp::Ordering;23use jrsonnet_parser::{BinaryOpType, Expr, Spanned, UnaryOpType};45use crate::{6 arr::ArrValue,7 bail,8 error::ErrorKind::*,9 evaluate,10 stdlib::std_format,11 typed::Typed,12 val::{equals, StrValue},13 Context, Result, Val,14};1516pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {17 use UnaryOpType::*;18 use Val::*;19 Ok(match (op, b) {20 (Plus, Num(n)) => Val::Num(*n),21 (Minus, Num(n)) => Val::try_num(-n.get())?,22 (Not, Bool(v)) => Bool(!v),23 (BitNot, Num(n)) => Val::try_num(!(n.get() as i64) as f64)?,24 (op, o) => bail!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())),25 })26}2728pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {29 use Val::*;30 Ok(match (a, b) {31 (Str(v1), Str(v2)) => Str(StrValue::concat(v1.clone(), v2.clone())),3233 (Num(a), Str(b)) => Val::string(format!("{a}{b}")),34 (Str(a), Num(b)) => Val::string(format!("{a}{b}")),3536 (Str(a), o) | (o, Str(a)) if a.is_empty() => Val::string(o.clone().to_string()?),37 (Str(a), o) => Val::string(format!("{a}{}", o.clone().to_string()?)),38 (o, Str(a)) => Val::string(format!("{}{a}", o.clone().to_string()?)),3940 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),41 (Arr(a), Arr(b)) => Val::Arr(ArrValue::extended(a.clone(), b.clone())),4243 (Num(v1), Num(v2)) => Val::try_num(v1.get() + v2.get())?,4445 #[cfg(feature = "exp-bigint")]46 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a + &**b)),4748 _ => bail!(BinaryOperatorDoesNotOperateOnValues(49 BinaryOpType::Add,50 a.value_type(),51 b.value_type(),52 )),53 })54}5556pub fn evaluate_sub_op(a: &Val, b: &Val) -> Result<Val> {57 use Val::*;58 Ok(match (a, b) {59 (Num(v1), Num(v2)) => Val::try_num(v1.get() - v2.get())?,6061 #[cfg(feature = "exp-bigint")]62 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a - &**b)),6364 65 _ => bail!(BinaryOperatorDoesNotOperateOnValues(66 BinaryOpType::Sub,67 a.value_type(),68 b.value_type(),69 )),70 })71}7273pub fn evaluate_mul_op(a: &Val, b: &Val) -> Result<Val> {74 use Val::*;75 Ok(match (a, b) {76 (Str(s), Num(c)) => Val::string(s.to_string().repeat(c.get() as usize)),77 (Num(c), Str(s)) => Val::string(s.to_string().repeat(c.get() as usize)),7879 (Num(v1), Num(v2)) => Val::try_num(v1.get() * v2.get())?,8081 #[cfg(feature = "exp-bigint")]82 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a * &**b)),8384 _ => bail!(BinaryOperatorDoesNotOperateOnValues(85 BinaryOpType::Mul,86 a.value_type(),87 b.value_type(),88 )),89 })90}9192fn is_attempt_to_divide_by_zero(a: &Val, b: &Val) -> bool {93 use Val::*;94 match (a, b) {95 96 (Str(_), _) => false,9798 (_, Num(b)) => return **b == 0.,99 #[cfg(feature = "exp-bigint")]100 (_, BigInt(b)) => return **b == num_bigint::BigInt::ZERO,101102 103 _ => false,104 }105}106107pub fn evaluate_div_op(a: &Val, b: &Val) -> Result<Val> {108 use Val::*;109110 if is_attempt_to_divide_by_zero(a, b) {111 bail!(DivisionByZero);112 }113114 Ok(match (a, b) {115 (Num(a), Num(b)) => Val::try_num(a.get() / b.get())?,116 #[cfg(feature = "exp-bigint")]117 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a / &**b)),118 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(119 BinaryOpType::Div,120 a.value_type(),121 b.value_type()122 )),123 })124}125126pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {127 use Val::*;128129 if is_attempt_to_divide_by_zero(a, b) {130 bail!(DivisionByZero);131 }132133 Ok(match (a, b) {134 (Num(a), Num(b)) => Val::try_num(a.get() % b.get())?,135 #[cfg(feature = "exp-bigint")]136 (BigInt(a), BigInt(b)) => BigInt(Box::new(&**a % &**b)),137 (Str(str), vals) => {138 String::into_untyped(std_format(&str.clone().into_flat(), vals.clone())?)?139 }140 (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues(141 BinaryOpType::Mod,142 a.value_type(),143 b.value_type()144 )),145 })146}147148pub fn evaluate_binary_op_special(149 ctx: Context,150 a: &Spanned<Expr>,151 op: BinaryOpType,152 b: &Spanned<Expr>,153) -> Result<Val> {154 use BinaryOpType::*;155 use Val::*;156 Ok(match (evaluate(ctx.clone(), a)?, op, b) {157 (Bool(true), Or, _o) => Val::Bool(true),158 (Bool(false), And, _o) => Val::Bool(false),159 #[cfg(feature = "exp-null-coaelse")]160 (Null, NullCoaelse, eb) => evaluate(ctx, eb)?,161 #[cfg(feature = "exp-null-coaelse")]162 (a, NullCoaelse, _o) => a,163 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,164 })165}166167pub fn evaluate_compare_op(a: &Val, b: &Val, op: BinaryOpType) -> Result<Ordering> {168 use Val::*;169 Ok(match (a, b) {170 (Str(a), Str(b)) => a.cmp(b),171172 (Num(a), Num(b)) => a.cmp(b),173174 #[cfg(feature = "exp-bigint")]175 (BigInt(a), BigInt(b)) => a.cmp(b),176177 (Arr(a), Arr(b)) => {178 let ai = a.iter();179 let bi = b.iter();180181 for (a, b) in ai.zip(bi) {182 let ord = evaluate_compare_op(&a?, &b?, op)?;183 if !ord.is_eq() {184 return Ok(ord);185 }186 }187 a.len().cmp(&b.len())188 }189 (_, _) => bail!(BinaryOperatorDoesNotOperateOnValues(190 op,191 a.value_type(),192 b.value_type()193 )),194 })195}196197pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {198 use BinaryOpType::*;199 use Val::*;200 Ok(match (a, op, b) {201 (a, Eq, b) => Bool(equals(a, b)?),202 (a, Neq, b) => Bool(!equals(a, b)?),203204 (a, Lt, b) => Bool(evaluate_compare_op(a, b, Lt)?.is_lt()),205 (a, Gt, b) => Bool(evaluate_compare_op(a, b, Gt)?.is_gt()),206 (a, Lte, b) => Bool(evaluate_compare_op(a, b, Lte)?.is_le()),207 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),208209 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone().into_flat(), true)),210211 212 (Bool(a), And, Bool(b)) => Bool(*a && *b),213 (Bool(a), Or, Bool(b)) => Bool(*a || *b),214215 (a, Add, b) => evaluate_add_op(a, b)?,216 (a, Sub, b) => evaluate_sub_op(a, b)?,217 (a, Mul, b) => evaluate_mul_op(a, b)?,218 (a, Div, b) => evaluate_div_op(a, b)?,219 (a, Mod, b) => evaluate_mod_op(a, b)?,220221 (Num(v1), BitAnd, Num(v2)) => {222 Val::try_num((v1.truncate_for_bitwise()? & v2.truncate_for_bitwise()?) as f64)?223 }224 (Num(v1), BitOr, Num(v2)) => {225 Val::try_num((v1.truncate_for_bitwise()? | v2.truncate_for_bitwise()?) as f64)?226 }227 (Num(v1), BitXor, Num(v2)) => {228 Val::try_num((v1.truncate_for_bitwise()? ^ v2.truncate_for_bitwise()?) as f64)?229 }230 (Num(v1), Lhs, Num(v2)) => {231 if v2.get() < 0.0 {232 bail!("shift by negative exponent")233 }234 let base = v1.truncate_for_bitwise()?;235 let exp = v2.truncate_for_bitwise()? % 64;236237 if exp >= 1 && base >= (1i64 << (63 - exp as u32)) {238 bail!("left shift would overflow")239 }240 Val::try_num(base.wrapping_shl(exp as u32) as f64)?241 }242 (Num(v1), Rhs, Num(v2)) => {243 if v2.get() < 0.0 {244 bail!("shift by negative exponent")245 }246 let exp = ((v2.get() as i64) & 63) as u32;247 Val::try_num(v1.truncate_for_bitwise()?.wrapping_shr(exp) as f64)?248 }249250 251 _ => bail!(BinaryOperatorDoesNotOperateOnValues(252 op,253 a.value_type(),254 b.value_type(),255 )),256 })257}