From d0fb5f4781e55709a849c8cf7315d4fb1a73a5a6 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Mon, 17 Apr 2023 16:16:00 +0000 Subject: [PATCH] feat: exp-bigint --- --- a/Cargo.lock +++ b/Cargo.lock @@ -298,6 +298,7 @@ "jrsonnet-macros", "jrsonnet-parser", "jrsonnet-types", + "num-bigint", "pathdiff", "rustc-hash", "serde", @@ -370,6 +371,7 @@ "jrsonnet-macros", "jrsonnet-parser", "md5", + "num-bigint", "serde", "serde_json", "serde_yaml_with_quirks", @@ -449,6 +451,37 @@ ] [[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -package.version = "0.5.0" +package.version = "0.5.0-pre7" members = ["crates/*", "bindings/jsonnet", "cmds/jrsonnet", "tests"] default-members = ["cmds/jrsonnet"] --- a/cmds/jrsonnet/Cargo.toml +++ b/cmds/jrsonnet/Cargo.toml @@ -19,6 +19,8 @@ exp-destruct = ["jrsonnet-evaluator/exp-destruct"] # Iteration over objects yields [key, value] elements exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"] +# Bigint type +exp-bigint = ["jrsonnet-evaluator/exp-bigint", "jrsonnet-cli/exp-bigint"] # std.thisFile support legacy-this-file = ["jrsonnet-cli/legacy-this-file"] --- a/crates/jrsonnet-cli/Cargo.toml +++ b/crates/jrsonnet-cli/Cargo.toml @@ -11,6 +11,10 @@ "jrsonnet-evaluator/exp-preserve-order", "jrsonnet-stdlib/exp-preserve-order", ] +exp-bigint = [ + "jrsonnet-evaluator/exp-bigint", + "jrsonnet-stdlib/exp-bigint", +] legacy-this-file = ["jrsonnet-stdlib/legacy-this-file"] [dependencies] --- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -24,6 +24,8 @@ exp-destruct = ["jrsonnet-parser/exp-destruct"] # Iteration over objects yields [key, value] elements exp-object-iteration = [] +# Bigint type +exp-bigint = ["num-bigint"] # Improves performance, and implements some useful things using nightly-only features nightly = ["hashbrown/nightly"] @@ -54,3 +56,5 @@ annotate-snippets = { version = "0.9.1", features = ["color"], optional = true } # Async imports async-trait = { version = "0.1.60", optional = true } +# Bigint +num-bigint = { version = "0.4.3", features = ["serde"], optional = true } --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -47,6 +47,8 @@ (Arr(a), Arr(b)) => Val::Arr(ArrValue::extended(a.clone(), b.clone())), (Num(v1), Num(v2)) => Val::new_checked_num(v1 + v2)?, + #[cfg(feature = "exp-bigint")] + (BigInt(a), BigInt(b)) => BigInt(Box::new((&**a).clone() + (&**b).clone())), _ => throw!(BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Add, a.value_type(), @@ -95,6 +97,8 @@ Ok(match (a, b) { (Str(a), Str(b)) => a.cmp(b), (Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"), + #[cfg(feature = "exp-bigint")] + (BigInt(a), BigInt(b)) => a.cmp(b), (Arr(a), Arr(b)) => { if let (Some(ai), Some(bi)) = (a.iter_cheap(), b.iter_cheap()) { for (a, b) in ai.zip(bi) { @@ -174,6 +178,12 @@ Num(f64::from((*v1 as i32) >> (*v2 as i32))) } + // Bigint X Bigint + #[cfg(feature = "exp-bigint")] + (BigInt(a), Mul, BigInt(b)) => BigInt(Box::new((&**a).clone() * (&**b).clone())), + #[cfg(feature = "exp-bigint")] + (BigInt(a), Sub, BigInt(b)) => BigInt(Box::new((&**a).clone() - (&**b).clone())), + _ => throw!(BinaryOperatorDoesNotOperateOnValues( op, a.value_type(), --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -162,6 +162,8 @@ Val::Null => serializer.serialize_none(), Val::Str(s) => serializer.serialize_str(&s.clone().into_flat()), Val::Num(n) => serializer.serialize_f64(*n), + #[cfg(feature = "exp-bigint")] + Val::BigInt(b) => b.serialize(serializer), Val::Arr(arr) => { let mut seq = serializer.serialize_seq(Some(arr.len()))?; for (i, element) in arr.iter().enumerate() { --- a/crates/jrsonnet-evaluator/src/manifest.rs +++ b/crates/jrsonnet-evaluator/src/manifest.rs @@ -149,6 +149,8 @@ Val::Null => buf.push_str("null"), Val::Str(s) => escape_string_json_buf(&s.clone().into_flat(), buf), Val::Num(n) => write!(buf, "{n}").unwrap(), + #[cfg(feature = "exp-bigint")] + Val::BigInt(n) => write!(buf, "{n}").unwrap(), Val::Arr(items) => { buf.push('['); if !items.is_empty() { --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -311,6 +311,9 @@ /// Should be finite, and not NaN /// This restriction isn't enforced by enum, as enum field can't be marked as private Num(f64), + /// Experimental bigint + #[cfg(feature = "exp-bigint")] + BigInt(#[trace(skip)] Box), /// Represents a Jsonnet array. Arr(ArrValue), /// Represents a Jsonnet object. @@ -389,6 +392,8 @@ match self { Self::Str(..) => ValType::Str, Self::Num(..) => ValType::Num, + #[cfg(feature = "exp-bigint")] + Self::BigInt(..) => ValType::BigInt, Self::Arr(..) => ValType::Arr, Self::Obj(..) => ValType::Obj, Self::Bool(_) => ValType::Bool, --- a/crates/jrsonnet-stdlib/Cargo.toml +++ b/crates/jrsonnet-stdlib/Cargo.toml @@ -17,6 +17,8 @@ exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"] # Add nonstandard `std.sha256` function exp-more-hashes = ["dep:sha2"] +# Bigint type +exp-bigint = ["num-bigint", "jrsonnet-evaluator/exp-bigint"] [dependencies] jrsonnet-evaluator.workspace = true @@ -39,6 +41,7 @@ serde_yaml_with_quirks = "0.8.24" sha2 = { version = "0.10.6", optional = true } +num-bigint = { version = "0.4.3", optional = true } [build-dependencies] jrsonnet-parser.workspace = true --- a/crates/jrsonnet-stdlib/src/expr.rs +++ b/crates/jrsonnet-stdlib/src/expr.rs @@ -83,7 +83,7 @@ pub(super) use std::{option::Option, rc::Rc, vec}; pub(super) use jrsonnet_parser::*; - }; + } include!(concat!(env!("OUT_DIR"), "/stdlib.rs")) } --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -143,6 +143,8 @@ ("asciiLower", builtin_ascii_lower::INST), ("findSubstr", builtin_find_substr::INST), ("parseInt", builtin_parse_int::INST), + #[cfg(feature = "exp-bigint")] + ("bigint", builtin_bigint::INST), ("parseOctal", builtin_parse_octal::INST), ("parseHex", builtin_parse_hex::INST), // Misc --- a/crates/jrsonnet-stdlib/src/manifest/toml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs @@ -103,6 +103,8 @@ escape_string_json_buf(&s.clone().into_flat(), buf); } Val::Num(n) => write!(buf, "{n}").unwrap(), + #[cfg(feature = "exp-bigint")] + Val::BigInt(n) => write!(buf, "{n}").unwrap(), Val::Arr(a) => { if a.is_empty() { buf.push_str("[]"); --- a/crates/jrsonnet-stdlib/src/manifest/yaml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/yaml.rs @@ -140,6 +140,8 @@ } } Val::Num(n) => write!(buf, "{}", *n).unwrap(), + #[cfg(feature = "exp-bigint")] + Val::BigInt(n) => write!(buf, "{}", *n).unwrap(), Val::Arr(a) => { if a.is_empty() { buf.push_str("[]"); --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -151,6 +151,20 @@ }) } +#[cfg(feature = "exp-bigint")] +#[builtin] +pub fn builtin_bigint(v: Either![f64, IStr]) -> Result { + use Either2::*; + Ok(match v { + A(a) => Val::BigInt(Box::new((a as i64).into())), + B(b) => Val::BigInt(Box::new( + b.as_str() + .parse() + .map_err(|e| RuntimeError(format!("bad bigint: {e}").into()))?, + )), + }) +} + #[cfg(test)] mod tests { use super::*; --- a/crates/jrsonnet-types/src/lib.rs +++ b/crates/jrsonnet-types/src/lib.rs @@ -88,6 +88,8 @@ Null, Str, Num, + #[cfg(feature = "exp-bigint")] + BigInt, Arr, Obj, Func, @@ -101,6 +103,8 @@ Null => "null", Str => "string", Num => "number", + #[cfg(feature = "exp-bigint")] + BigInt => "bigint", Arr => "array", Obj => "object", Func => "function", -- gitstuff