diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index 23088cc9..1e983c0b 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -17,7 +17,7 @@ once_cell = { workspace = true } regex = { workspace = true, optional = true } regex-lite = { workspace = true, optional = true } serde = { workspace = true, features = ["rc", "derive"] } -serde_json = { workspace = true, features = ["arbitrary_precision"] } +serde_json = { workspace = true, features = [] } strum = { workspace = true } strum_macros = { workspace = true } thiserror = { workspace = true } @@ -36,6 +36,7 @@ serde_json5 = "0.1.0" default = ["regex-deprecated"] regex-deprecated = ["dep:regex"] regex-lite = ["dep:regex-lite"] +arbitrary_precision = ["serde_json/arbitrary_precision"] [[bench]] harness = false @@ -51,4 +52,4 @@ name = "unary" [[bench]] harness = false -name = "isolate" \ No newline at end of file +name = "isolate" diff --git a/core/expression/src/intellisense/types/provider.rs b/core/expression/src/intellisense/types/provider.rs index e17f7c20..41183b3f 100644 --- a/core/expression/src/intellisense/types/provider.rs +++ b/core/expression/src/intellisense/types/provider.rs @@ -6,6 +6,7 @@ use crate::variable::VariableType; use serde_json::{Number, Value}; use std::collections::HashMap; use std::rc::Rc; +use std::str::FromStr; #[derive(Debug)] pub struct TypesProvider { @@ -68,9 +69,16 @@ impl TypesProvider { false => V(VariableType::Bool), }, Node::Number(n) => match detailed { + #[cfg(feature = "arbitrary_precision")] true => Const(Value::Number(Number::from_string_unchecked( n.normalize().to_string(), ))), + #[cfg(not(feature = "arbitrary_precision"))] + true => Const(Value::Number( + Number::from_str(n.normalize().to_string().as_str()) + .map_err(|_| "Invalid number") + .unwrap(), + )), false => V(VariableType::Number), }, Node::String(s) => match detailed { diff --git a/core/expression/src/variable/conv.rs b/core/expression/src/variable/conv.rs index eb22e3b7..d330e60d 100644 --- a/core/expression/src/variable/conv.rs +++ b/core/expression/src/variable/conv.rs @@ -2,10 +2,11 @@ use crate::variable::Variable; use crate::vm::helpers::date_time; use crate::vm::VMError; use chrono::NaiveDateTime; -use rust_decimal::prelude::ToPrimitive; +use rust_decimal::prelude::{FromPrimitive, ToPrimitive}; use rust_decimal::Decimal; use serde_json::{Number, Value}; use std::rc::Rc; +use std::str::FromStr; impl From for Variable { fn from(value: Value) -> Self { @@ -13,7 +14,26 @@ impl From for Variable { Value::Null => Variable::Null, Value::Bool(b) => Variable::Bool(b), Value::Number(n) => { - Variable::Number(Decimal::from_str_exact(n.as_str()).expect("Allowed number")) + #[cfg(feature = "arbitrary_precision")] + { + Variable::Number(Decimal::from_str_exact(n.as_str()).expect("Allowed number")) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).expect("Allowed number"), + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).expect("Allowed number"), + None => panic!("Invalid number"), + }, + }, + }; + + Variable::Number(decimal) + } } Value::String(s) => Variable::String(Rc::from(s.as_str())), Value::Array(arr) => { @@ -34,7 +54,26 @@ impl From<&Value> for Variable { Value::Null => Variable::Null, Value::Bool(b) => Variable::Bool(*b), Value::Number(n) => { - Variable::Number(Decimal::from_str_exact(n.as_str()).expect("Allowed number")) + #[cfg(feature = "arbitrary_precision")] + { + Variable::Number(Decimal::from_str_exact(n.as_str()).expect("Allowed number")) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).expect("Allowed number"), + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).expect("Allowed number"), + None => panic!("Invalid number"), + }, + }, + }; + + Variable::Number(decimal) + } } Value::String(s) => Variable::String(Rc::from(s.as_str())), Value::Array(arr) => Variable::from_array(arr.iter().map(Variable::from).collect()), @@ -52,7 +91,20 @@ impl From for Value { match value { Variable::Null => Value::Null, Variable::Bool(b) => Value::Bool(b), - Variable::Number(n) => Value::Number(Number::from_string_unchecked(n.to_string())), + Variable::Number(n) => { + #[cfg(feature = "arbitrary_precision")] + { + Value::Number(Number::from_string_unchecked(n.to_string())) + } + #[cfg(not(feature = "arbitrary_precision"))] + { + Value::Number( + Number::from_str(n.normalize().to_string().as_str()) + .map_err(|_| "Invalid number") + .unwrap(), + ) + } + } Variable::String(s) => Value::String(s.to_string()), Variable::Array(arr) => { let vec = Rc::try_unwrap(arr) diff --git a/core/expression/tests/isolate.rs b/core/expression/tests/isolate.rs index 5299ae7c..37e6c974 100644 --- a/core/expression/tests/isolate.rs +++ b/core/expression/tests/isolate.rs @@ -96,6 +96,42 @@ fn isolate_standard_test() { }, ]), }, + TestEnv { + env: json!({ + "a": 3.14f64, + "b": 2, + "c": 3.141592653589793f64, + "d": 18446744073709551615u64, + "e": 9_223_372_036_854_775_807i64, + + }), + cases: Vec::from([ + TestCase { + expr: "a", + result: json!(3.14), + }, + TestCase { + expr: "b", + result: json!(2), + }, + TestCase { + expr: "e", + result: json!(9_223_372_036_854_775_807i64), + }, + TestCase { + expr: "a + b", + result: json!(5.14), + }, + TestCase { + expr: "(b + c) - (c + b)", + result: json!(0), + }, + TestCase { + expr: "d", + result: json!(18446744073709551615u64), + }, + ]), + }, TestEnv { env: json!({ "a": 3, diff --git a/core/expression/tests/standard.rs b/core/expression/tests/standard.rs index f534d354..be932c50 100644 --- a/core/expression/tests/standard.rs +++ b/core/expression/tests/standard.rs @@ -289,6 +289,14 @@ fn standard_test() { operator: Operator::Arithmetic(ArithmeticOperator::Add), }, }, + StandardTest { + src: "25 + 2.5", + result: &Node::Binary { + left: &Node::Number(D25), + right: &Node::Number(D2P5), + operator: Operator::Arithmetic(ArithmeticOperator::Add), + }, + }, ]); let mut lexer = Lexer::new();