// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // `pattern_type_mismatch` requires explicit `&`+`ref` patterns for tuple matches // on (&Value, &Value), which conflicts with `needless_borrowed_reference`. // Disable both to keep patterns consistent within this file. #![allow(clippy::pattern_type_mismatch, clippy::needless_borrowed_reference)] use alloc::collections::BTreeSet; use crate::number::Number; use crate::value::Value; use super::errors::{Result, VmError}; use super::machine::RegoVM; impl RegoVM { /// Add two values using interpreter's arithmetic logic pub(super) fn add_values(&self, a: &Value, b: &Value) -> Result { match (a, b) { (&Value::Number(ref x), &Value::Number(ref y)) => Ok(Value::from(x.add(y)?)), _ => Err(VmError::InvalidAddition { left: a.clone(), right: b.clone(), pc: self.pc, }), } } /// Subtract two values using interpreter's arithmetic logic pub(super) fn sub_values(&self, a: &Value, b: &Value) -> Result { match (a, b) { (&Value::Number(ref x), &Value::Number(ref y)) => Ok(Value::from(x.sub(y)?)), (&Value::Set(ref left), &Value::Set(ref right)) => { let diff: BTreeSet = left.difference(right).cloned().collect(); Ok(Value::from_set(diff)) } _ => Err(VmError::InvalidSubtraction { left: a.clone(), right: b.clone(), pc: self.pc, }), } } /// Multiply two values using interpreter's arithmetic logic pub(super) fn mul_values(&self, a: &Value, b: &Value) -> Result { match (a, b) { (&Value::Number(ref x), &Value::Number(ref y)) => Ok(Value::from(x.mul(y)?)), _ => Err(VmError::InvalidMultiplication { left: a.clone(), right: b.clone(), pc: self.pc, }), } } /// Divide two values using interpreter's arithmetic logic pub(super) fn div_values(&self, a: &Value, b: &Value) -> Result { match (a, b) { (&Value::Number(ref x), &Value::Number(ref y)) => { if *y == Number::from(0_u64) { if self.strict_builtin_errors { return Err(VmError::InvalidDivision { left: a.clone(), right: b.clone(), pc: self.pc, }); } return Ok(Value::Undefined); } Ok(Value::from(x.clone().divide(y)?)) } _ => Err(VmError::InvalidDivision { left: a.clone(), right: b.clone(), pc: self.pc, }), } } /// Modulo two values using interpreter's arithmetic logic pub(super) fn mod_values(&self, a: &Value, b: &Value) -> Result { match (a, b) { (&Value::Number(ref x), &Value::Number(ref y)) => { if *y == Number::from(0_u64) { if self.strict_builtin_errors { return Err(VmError::InvalidModulo { left: a.clone(), right: b.clone(), pc: self.pc, }); } return Ok(Value::Undefined); } if !x.is_integer() || !y.is_integer() { return Err(VmError::ModuloOnFloat { left: a.clone(), right: b.clone(), pc: self.pc, }); } Ok(Value::from(x.clone().modulo(y)?)) } _ => Err(VmError::InvalidModulo { left: a.clone(), right: b.clone(), pc: self.pc, }), } } pub(super) const fn to_bool(&self, value: &Value) -> Option { match *value { Value::Bool(b) => Some(b), Value::Null if !self.strict_builtin_errors => Some(true), _ => None, } } }