Built-in interop between FLOAT/Decimal and INT.

This commit is contained in:
Stephen Chung 2021-02-19 11:47:26 +08:00
parent 7b8322b6e1
commit bd5ff457d2
4 changed files with 287 additions and 299 deletions

View File

@ -9,10 +9,15 @@ Bug fixes
* Bug in `Position::is_beginning_of_line` is fixed. * Bug in `Position::is_beginning_of_line` is fixed.
Enhancements New features
------------ ------------
* Comparisons between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now built in. * Comparisons between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now built in.
Enhancements
------------
* Built-in operators between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now implemented for more speed under those cases.
* Error position in `eval` statements is now wrapped in an `EvalAltResult::ErrorInFunctionCall`. * Error position in `eval` statements is now wrapped in an `EvalAltResult::ErrorInFunctionCall`.
* `Position` now implements `Add` and `AddAssign`. * `Position` now implements `Add` and `AddAssign`.
* `Scope` now implements `IntoIterator`. * `Scope` now implements `IntoIterator`.

View File

@ -32,6 +32,9 @@ use crate::FLOAT;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::Map; use crate::Map;
#[cfg(feature = "decimal")]
use rust_decimal::Decimal;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use num_traits::float::Float; use num_traits::float::Float;
@ -1347,33 +1350,115 @@ pub fn run_builtin_binary_op(
x: &Dynamic, x: &Dynamic,
y: &Dynamic, y: &Dynamic,
) -> Result<Option<Dynamic>, Box<EvalAltResult>> { ) -> Result<Option<Dynamic>, Box<EvalAltResult>> {
let args_type = x.type_id(); let first_type = x.type_id();
let second_type = y.type_id(); let second_type = y.type_id();
if second_type != args_type { let type_id = (first_type, second_type);
if args_type == TypeId::of::<char>() && second_type == TypeId::of::<ImmutableString>() {
#[cfg(not(feature = "no_float"))]
if let Some((x, y)) = if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<FLOAT>()) {
Some((x.clone().cast::<FLOAT>(), y.clone().cast::<FLOAT>()))
} else if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<INT>()) {
Some((x.clone().cast::<FLOAT>(), y.clone().cast::<INT>() as FLOAT))
} else if type_id == (TypeId::of::<INT>(), TypeId::of::<FLOAT>()) {
Some((x.clone().cast::<INT>() as FLOAT, y.clone().cast::<FLOAT>()))
} else {
None
} {
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"*" => return Ok(Some((x * y).into())),
"/" => return Ok(Some((x / y).into())),
"%" => return Ok(Some((x % y).into())),
"**" => return Ok(Some(x.powf(y).into())),
"==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())),
">" => return Ok(Some((x > y).into())),
">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())),
_ => return Ok(None),
}
}
#[cfg(feature = "decimal")]
if let Some((x, y)) = if type_id == (TypeId::of::<Decimal>(), TypeId::of::<Decimal>()) {
Some((
*x.read_lock::<Decimal>().unwrap(),
*y.read_lock::<Decimal>().unwrap(),
))
} else if type_id == (TypeId::of::<Decimal>(), TypeId::of::<INT>()) {
Some((
*x.read_lock::<Decimal>().unwrap(),
y.clone().cast::<INT>().into(),
))
} else if type_id == (TypeId::of::<INT>(), TypeId::of::<Decimal>()) {
Some((
x.clone().cast::<INT>().into(),
*y.read_lock::<Decimal>().unwrap(),
))
} else {
None
} {
if cfg!(not(feature = "unchecked")) {
use crate::packages::arithmetic::decimal_functions::*;
match op {
"+" => return add(x, y).map(Some),
"-" => return subtract(x, y).map(Some),
"*" => return multiply(x, y).map(Some),
"/" => return divide(x, y).map(Some),
"%" => return modulo(x, y).map(Some),
_ => (),
}
} else {
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"*" => return Ok(Some((x * y).into())),
"/" => return Ok(Some((x / y).into())),
"%" => return Ok(Some((x % y).into())),
_ => (),
}
}
match op {
"==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())),
">" => return Ok(Some((x > y).into())),
">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())),
_ => return Ok(None),
}
}
if second_type != first_type {
if type_id == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
let x = x.clone().cast::<char>(); let x = x.clone().cast::<char>();
let y = &*y.read_lock::<ImmutableString>().unwrap(); let y = &*y.read_lock::<ImmutableString>().unwrap();
match op { match op {
"+" => return Ok(Some(format!("{}{}", x, y).into())), "+" => return Ok(Some(format!("{}{}", x, y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<ImmutableString>() }
&& second_type == TypeId::of::<char>()
{ if type_id == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let x = &*x.read_lock::<ImmutableString>().unwrap(); let x = &*x.read_lock::<ImmutableString>().unwrap();
let y = y.clone().cast::<char>(); let y = y.clone().cast::<char>();
match op { match op {
"+" => return Ok(Some((x + y).into())), "+" => return Ok(Some((x + y).into())),
_ => (), _ => return Ok(None),
} }
} }
return Ok(None); return Ok(None);
} }
if args_type == TypeId::of::<INT>() { if first_type == TypeId::of::<INT>() {
let x = x.clone().cast::<INT>(); let x = x.clone().cast::<INT>();
let y = y.clone().cast::<INT>(); let y = y.clone().cast::<INT>();
@ -1415,9 +1500,11 @@ pub fn run_builtin_binary_op(
"&" => return Ok(Some((x & y).into())), "&" => return Ok(Some((x & y).into())),
"|" => return Ok(Some((x | y).into())), "|" => return Ok(Some((x | y).into())),
"^" => return Ok(Some((x ^ y).into())), "^" => return Ok(Some((x ^ y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<bool>() { }
if first_type == TypeId::of::<bool>() {
let x = x.clone().cast::<bool>(); let x = x.clone().cast::<bool>();
let y = y.clone().cast::<bool>(); let y = y.clone().cast::<bool>();
@ -1427,9 +1514,11 @@ pub fn run_builtin_binary_op(
"^" => return Ok(Some((x ^ y).into())), "^" => return Ok(Some((x ^ y).into())),
"==" => return Ok(Some((x == y).into())), "==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())), "!=" => return Ok(Some((x != y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<ImmutableString>() { }
if first_type == TypeId::of::<ImmutableString>() {
let x = &*x.read_lock::<ImmutableString>().unwrap(); let x = &*x.read_lock::<ImmutableString>().unwrap();
let y = &*y.read_lock::<ImmutableString>().unwrap(); let y = &*y.read_lock::<ImmutableString>().unwrap();
@ -1441,9 +1530,11 @@ pub fn run_builtin_binary_op(
">=" => return Ok(Some((x >= y).into())), ">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())), "<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())), "<=" => return Ok(Some((x <= y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<char>() { }
if first_type == TypeId::of::<char>() {
let x = x.clone().cast::<char>(); let x = x.clone().cast::<char>();
let y = y.clone().cast::<char>(); let y = y.clone().cast::<char>();
@ -1455,73 +1546,15 @@ pub fn run_builtin_binary_op(
">=" => return Ok(Some((x >= y).into())), ">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())), "<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())), "<=" => return Ok(Some((x <= y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<()>() { }
if first_type == TypeId::of::<()>() {
match op { match op {
"==" => return Ok(Some(true.into())), "==" => return Ok(Some(true.into())),
"!=" | ">" | ">=" | "<" | "<=" => return Ok(Some(false.into())), "!=" | ">" | ">=" | "<" | "<=" => return Ok(Some(false.into())),
_ => (), _ => return Ok(None),
}
}
#[cfg(not(feature = "no_float"))]
if args_type == TypeId::of::<FLOAT>() {
let x = x.clone().cast::<FLOAT>();
let y = y.clone().cast::<FLOAT>();
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"*" => return Ok(Some((x * y).into())),
"/" => return Ok(Some((x / y).into())),
"%" => return Ok(Some((x % y).into())),
"**" => return Ok(Some(x.powf(y).into())),
"==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())),
">" => return Ok(Some((x > y).into())),
">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())),
_ => (),
}
}
#[cfg(feature = "decimal")]
if args_type == TypeId::of::<rust_decimal::Decimal>() {
let x = x.clone().cast::<rust_decimal::Decimal>();
let y = y.clone().cast::<rust_decimal::Decimal>();
if cfg!(not(feature = "unchecked")) {
use crate::packages::arithmetic::decimal_functions::*;
match op {
"+" => return add(x, y).map(Some),
"-" => return subtract(x, y).map(Some),
"*" => return multiply(x, y).map(Some),
"/" => return divide(x, y).map(Some),
"%" => return modulo(x, y).map(Some),
_ => (),
}
} else {
match op {
"+" => return Ok(Some((x + y).into())),
"-" => return Ok(Some((x - y).into())),
"*" => return Ok(Some((x * y).into())),
"/" => return Ok(Some((x / y).into())),
"%" => return Ok(Some((x % y).into())),
_ => (),
}
}
match op {
"==" => return Ok(Some((x == y).into())),
"!=" => return Ok(Some((x != y).into())),
">" => return Ok(Some((x > y).into())),
">=" => return Ok(Some((x >= y).into())),
"<" => return Ok(Some((x < y).into())),
"<=" => return Ok(Some((x <= y).into())),
_ => (),
} }
} }
@ -1534,24 +1567,80 @@ pub fn run_builtin_op_assignment(
x: &mut Dynamic, x: &mut Dynamic,
y: &Dynamic, y: &Dynamic,
) -> Result<Option<()>, Box<EvalAltResult>> { ) -> Result<Option<()>, Box<EvalAltResult>> {
let args_type = x.type_id(); let first_type = x.type_id();
let second_type = y.type_id(); let second_type = y.type_id();
if second_type != args_type { let type_id = (first_type, second_type);
if args_type == TypeId::of::<ImmutableString>() && second_type == TypeId::of::<char>() {
#[cfg(not(feature = "no_float"))]
if let Some((mut x, y)) = if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<FLOAT>()) {
let y = y.clone().cast::<FLOAT>();
Some((x.write_lock::<FLOAT>().unwrap(), y))
} else if type_id == (TypeId::of::<FLOAT>(), TypeId::of::<INT>()) {
let y = y.clone().cast::<INT>() as FLOAT;
Some((x.write_lock::<FLOAT>().unwrap(), y))
} else {
None
} {
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
"*=" => return Ok(Some(*x *= y)),
"/=" => return Ok(Some(*x /= y)),
"%=" => return Ok(Some(*x %= y)),
"**=" => return Ok(Some(*x = x.powf(y))),
_ => return Ok(None),
}
}
#[cfg(feature = "decimal")]
if let Some((mut x, y)) = if type_id == (TypeId::of::<Decimal>(), TypeId::of::<Decimal>()) {
let y = *y.read_lock::<Decimal>().unwrap();
Some((x.write_lock::<Decimal>().unwrap(), y))
} else if type_id == (TypeId::of::<Decimal>(), TypeId::of::<INT>()) {
let y = y.clone().cast::<INT>().into();
Some((x.write_lock::<Decimal>().unwrap(), y))
} else {
None
} {
if cfg!(not(feature = "unchecked")) {
use crate::packages::arithmetic::decimal_functions::*;
match op {
"+=" => return Ok(Some(*x = add(*x, y)?.as_decimal().unwrap())),
"-=" => return Ok(Some(*x = subtract(*x, y)?.as_decimal().unwrap())),
"*=" => return Ok(Some(*x = multiply(*x, y)?.as_decimal().unwrap())),
"/=" => return Ok(Some(*x = divide(*x, y)?.as_decimal().unwrap())),
"%=" => return Ok(Some(*x = modulo(*x, y)?.as_decimal().unwrap())),
_ => (),
}
} else {
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
"*=" => return Ok(Some(*x *= y)),
"/=" => return Ok(Some(*x /= y)),
"%=" => return Ok(Some(*x %= y)),
_ => (),
}
}
}
if second_type != first_type {
if type_id == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
let y = y.read_lock::<char>().unwrap().deref().clone(); let y = y.read_lock::<char>().unwrap().deref().clone();
let mut x = x.write_lock::<ImmutableString>().unwrap(); let mut x = x.write_lock::<ImmutableString>().unwrap();
match op { match op {
"+=" => return Ok(Some(*x += y)), "+=" => return Ok(Some(*x += y)),
_ => (), _ => return Ok(None),
} }
} }
return Ok(None); return Ok(None);
} }
if args_type == TypeId::of::<INT>() { if first_type == TypeId::of::<INT>() {
let y = y.clone().cast::<INT>(); let y = y.clone().cast::<INT>();
let mut x = x.write_lock::<INT>().unwrap(); let mut x = x.write_lock::<INT>().unwrap();
@ -1587,76 +1676,38 @@ pub fn run_builtin_op_assignment(
"&=" => return Ok(Some(*x &= y)), "&=" => return Ok(Some(*x &= y)),
"|=" => return Ok(Some(*x |= y)), "|=" => return Ok(Some(*x |= y)),
"^=" => return Ok(Some(*x ^= y)), "^=" => return Ok(Some(*x ^= y)),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<bool>() { }
if first_type == TypeId::of::<bool>() {
let y = y.clone().cast::<bool>(); let y = y.clone().cast::<bool>();
let mut x = x.write_lock::<bool>().unwrap(); let mut x = x.write_lock::<bool>().unwrap();
match op { match op {
"&=" => return Ok(Some(*x = *x && y)), "&=" => return Ok(Some(*x = *x && y)),
"|=" => return Ok(Some(*x = *x || y)), "|=" => return Ok(Some(*x = *x || y)),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<char>() { }
if first_type == TypeId::of::<char>() {
let y = y.read_lock::<char>().unwrap().deref().clone(); let y = y.read_lock::<char>().unwrap().deref().clone();
let mut x = x.write_lock::<Dynamic>().unwrap(); let mut x = x.write_lock::<Dynamic>().unwrap();
match op { match op {
"+=" => return Ok(Some(*x = format!("{}{}", *x, y).into())), "+=" => return Ok(Some(*x = format!("{}{}", *x, y).into())),
_ => (), _ => return Ok(None),
} }
} else if args_type == TypeId::of::<ImmutableString>() { }
if first_type == TypeId::of::<ImmutableString>() {
let y = y.read_lock::<ImmutableString>().unwrap().deref().clone(); let y = y.read_lock::<ImmutableString>().unwrap().deref().clone();
let mut x = x.write_lock::<ImmutableString>().unwrap(); let mut x = x.write_lock::<ImmutableString>().unwrap();
match op { match op {
"+=" => return Ok(Some(*x += y)), "+=" => return Ok(Some(*x += y)),
_ => (), _ => return Ok(None),
}
}
#[cfg(not(feature = "no_float"))]
if args_type == TypeId::of::<FLOAT>() {
let y = y.clone().cast::<FLOAT>();
let mut x = x.write_lock::<FLOAT>().unwrap();
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
"*=" => return Ok(Some(*x *= y)),
"/=" => return Ok(Some(*x /= y)),
"%=" => return Ok(Some(*x %= y)),
"**=" => return Ok(Some(*x = x.powf(y))),
_ => (),
}
}
#[cfg(feature = "decimal")]
if args_type == TypeId::of::<rust_decimal::Decimal>() {
let y = y.clone().cast::<rust_decimal::Decimal>();
let mut x = x.write_lock::<rust_decimal::Decimal>().unwrap();
if cfg!(not(feature = "unchecked")) {
use crate::packages::arithmetic::decimal_functions::*;
match op {
"+=" => return Ok(Some(*x = add(*x, y)?.as_decimal().unwrap())),
"-=" => return Ok(Some(*x = subtract(*x, y)?.as_decimal().unwrap())),
"*=" => return Ok(Some(*x = multiply(*x, y)?.as_decimal().unwrap())),
"/=" => return Ok(Some(*x = divide(*x, y)?.as_decimal().unwrap())),
"%=" => return Ok(Some(*x = modulo(*x, y)?.as_decimal().unwrap())),
_ => (),
}
} else {
match op {
"+=" => return Ok(Some(*x += y)),
"-=" => return Ok(Some(*x -= y)),
"*=" => return Ok(Some(*x *= y)),
"/=" => return Ok(Some(*x /= y)),
"%=" => return Ok(Some(*x %= y)),
_ => (),
}
} }
} }

View File

@ -254,7 +254,6 @@ mod f32_functions {
pub fn pow_f_f(x: f32, y: f32) -> f32 { pub fn pow_f_f(x: f32, y: f32) -> f32 {
x.powf(y) x.powf(y)
} }
}
#[rhai_fn(name = "+")] #[rhai_fn(name = "+")]
pub fn add_if(x: INT, y: f32) -> f32 { pub fn add_if(x: INT, y: f32) -> f32 {
@ -296,6 +295,7 @@ mod f32_functions {
pub fn modulo_fi(x: f32, y: INT) -> f32 { pub fn modulo_fi(x: f32, y: INT) -> f32 {
(x as f32) % (y as f32) (x as f32) % (y as f32)
} }
}
#[rhai_fn(name = "-")] #[rhai_fn(name = "-")]
pub fn neg(x: f32) -> f32 { pub fn neg(x: f32) -> f32 {
@ -359,7 +359,6 @@ mod f64_functions {
pub fn pow_f_f(x: f64, y: f64) -> f64 { pub fn pow_f_f(x: f64, y: f64) -> f64 {
x.powf(y) x.powf(y)
} }
}
#[rhai_fn(name = "+")] #[rhai_fn(name = "+")]
pub fn add_if(x: INT, y: f64) -> f64 { pub fn add_if(x: INT, y: f64) -> f64 {
@ -401,6 +400,7 @@ mod f64_functions {
pub fn modulo_fi(x: f64, y: INT) -> f64 { pub fn modulo_fi(x: f64, y: INT) -> f64 {
(x as f64) % (y as f64) (x as f64) % (y as f64)
} }
}
#[rhai_fn(name = "-")] #[rhai_fn(name = "-")]
pub fn neg(x: f64) -> f64 { pub fn neg(x: f64) -> f64 {
@ -440,61 +440,37 @@ mod f64_functions {
mod decimal_functions { mod decimal_functions {
use rust_decimal::{prelude::Zero, Decimal}; use rust_decimal::{prelude::Zero, Decimal};
#[rhai_fn(name = "+", return_raw)] #[rhai_fn(skip, return_raw)]
pub fn add(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> { pub fn add(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
x.checked_add(y) x.checked_add(y)
.ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))) .ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
.map(Dynamic::from) .map(Into::<Dynamic>::into)
} else { } else {
Ok(Dynamic::from(x + y)) Ok(Dynamic::from(x + y))
} }
} }
#[rhai_fn(name = "+", return_raw)] #[rhai_fn(skip, return_raw)]
pub fn add_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
add(x.into(), y)
}
#[rhai_fn(name = "+", return_raw)]
pub fn add_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
add(x, y.into())
}
#[rhai_fn(name = "-", return_raw)]
pub fn subtract(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> { pub fn subtract(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
x.checked_sub(y) x.checked_sub(y)
.ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))) .ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
.map(Dynamic::from) .map(Into::<Dynamic>::into)
} else { } else {
Ok(Dynamic::from(x - y)) Ok(Dynamic::from(x - y))
} }
} }
#[rhai_fn(name = "-", return_raw)] #[rhai_fn(skip, return_raw)]
pub fn subtract_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
subtract(x.into(), y)
}
#[rhai_fn(name = "-", return_raw)]
pub fn subtract_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
subtract(x, y.into())
}
#[rhai_fn(name = "*", return_raw)]
pub fn multiply(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> { pub fn multiply(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
x.checked_mul(y) x.checked_mul(y)
.ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))) .ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
.map(Dynamic::from) .map(Into::<Dynamic>::into)
} else { } else {
Ok(Dynamic::from(x * y)) Ok(Dynamic::from(x * y))
} }
} }
#[rhai_fn(name = "*", return_raw)] #[rhai_fn(skip, return_raw)]
pub fn multiply_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
multiply(x.into(), y)
}
#[rhai_fn(name = "*", return_raw)]
pub fn multiply_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
multiply(x, y.into())
}
#[rhai_fn(name = "/", return_raw)]
pub fn divide(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> { pub fn divide(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
// Detect division by zero // Detect division by zero
@ -503,21 +479,13 @@ mod decimal_functions {
} else { } else {
x.checked_div(y) x.checked_div(y)
.ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y))) .ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
.map(Dynamic::from) .map(Into::<Dynamic>::into)
} }
} else { } else {
Ok(Dynamic::from(x / y)) Ok(Dynamic::from(x / y))
} }
} }
#[rhai_fn(name = "/", return_raw)] #[rhai_fn(skip, return_raw)]
pub fn divide_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
divide(x.into(), y)
}
#[rhai_fn(name = "/", return_raw)]
pub fn divide_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
divide(x, y.into())
}
#[rhai_fn(name = "%", return_raw)]
pub fn modulo(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> { pub fn modulo(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
x.checked_rem(y) x.checked_rem(y)
@ -527,19 +495,11 @@ mod decimal_functions {
x, y x, y
)) ))
}) })
.map(Dynamic::from) .map(Into::<Dynamic>::into)
} else { } else {
Ok(Dynamic::from(x % y)) Ok(Dynamic::from(x % y))
} }
} }
#[rhai_fn(name = "%", return_raw)]
pub fn modulo_id(x: INT, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
modulo(x.into(), y)
}
#[rhai_fn(name = "%", return_raw)]
pub fn modulo_di(x: Decimal, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
modulo(x, y.into())
}
#[rhai_fn(name = "-")] #[rhai_fn(name = "-")]
pub fn neg(x: Decimal) -> Decimal { pub fn neg(x: Decimal) -> Decimal {
-x -x

View File

@ -3167,48 +3167,20 @@ pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
Union::Float(value, _) => Some(Expr::FloatConstant(value, pos)), Union::Float(value, _) => Some(Expr::FloatConstant(value, pos)),
#[cfg(feature = "decimal")]
Union::Decimal(value, _) => Some(Expr::DynamicConstant(Box::new((*value).into()), pos)),
Union::Unit(_, _) => Some(Expr::Unit(pos)), Union::Unit(_, _) => Some(Expr::Unit(pos)),
Union::Int(value, _) => Some(Expr::IntegerConstant(value, pos)), Union::Int(value, _) => Some(Expr::IntegerConstant(value, pos)),
Union::Char(value, _) => Some(Expr::CharConstant(value, pos)), Union::Char(value, _) => Some(Expr::CharConstant(value, pos)),
Union::Str(value, _) => Some(Expr::StringConstant(value, pos)), Union::Str(value, _) => Some(Expr::StringConstant(value, pos)),
Union::Bool(value, _) => Some(Expr::BoolConstant(value, pos)), Union::Bool(value, _) => Some(Expr::BoolConstant(value, pos)),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Union::Array(array, _) => { Union::Array(array, _) => Some(Expr::DynamicConstant(Box::new((*array).into()), pos)),
let items: Vec<_> = array
.into_iter()
.map(|x| map_dynamic_to_expr(x, pos))
.collect();
if items.iter().all(Option::is_some) {
Some(Expr::Array(
Box::new(items.into_iter().map(Option::unwrap).collect()),
pos,
))
} else {
None
}
}
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Union::Map(map, _) => { Union::Map(map, _) => Some(Expr::DynamicConstant(Box::new((*map).into()), pos)),
let items: Vec<_> = map
.into_iter()
.map(|(name, value)| (Ident { name, pos }, map_dynamic_to_expr(value, pos)))
.collect();
if items.iter().all(|(_, expr)| expr.is_some()) {
Some(Expr::Map(
Box::new(
items
.into_iter()
.map(|(k, expr)| (k, expr.unwrap()))
.collect(),
),
pos,
))
} else {
None
}
}
_ => None, _ => None,
} }