difftreelog
feat exp-bigint
in: master
16 files changed
Cargo.lockdiffbeforeafterboth--- 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"
Cargo.tomldiffbeforeafterboth--- 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"]
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- 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"]
crates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth--- 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]
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- 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 }
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth--- 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(),
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- 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() {
crates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth--- 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() {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- 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<num_bigint::BigInt>),
/// 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,
crates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth--- 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
crates/jrsonnet-stdlib/src/expr.rsdiffbeforeafterboth--- 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"))
}
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth--- 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
crates/jrsonnet-stdlib/src/manifest/toml.rsdiffbeforeafterboth--- 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("[]");
crates/jrsonnet-stdlib/src/manifest/yaml.rsdiffbeforeafterboth--- 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("[]");
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth1use jrsonnet_evaluator::{2 error::{ErrorKind::*, Result},3 function::builtin,4 throw,5 typed::{Either2, M1},6 val::{ArrValue, StrValue},7 Either, IStr, Val,8};910#[builtin]11pub const fn builtin_codepoint(str: char) -> u32 {12 str as u3213}1415#[builtin]16pub fn builtin_substr(str: IStr, from: usize, len: usize) -> String {17 str.chars().skip(from).take(len).collect()18}1920#[builtin]21pub fn builtin_char(n: u32) -> Result<char> {22 Ok(std::char::from_u32(n).ok_or_else(|| InvalidUnicodeCodepointGot(n))?)23}2425#[builtin]26pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> String {27 str.replace(&from as &str, &to as &str)28}2930#[builtin]31pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> ArrValue {32 use Either2::*;33 match maxsplits {34 A(n) => str35 .splitn(n + 1, &c as &str)36 .map(|s| Val::Str(StrValue::Flat(s.into())))37 .collect(),38 B(_) => str39 .split(&c as &str)40 .map(|s| Val::Str(StrValue::Flat(s.into())))41 .collect(),42 }43}4445#[builtin]46pub fn builtin_ascii_upper(str: IStr) -> String {47 str.to_ascii_uppercase()48}4950#[builtin]51pub fn builtin_ascii_lower(str: IStr) -> String {52 str.to_ascii_lowercase()53}5455#[builtin]56pub fn builtin_find_substr(pat: IStr, str: IStr) -> ArrValue {57 if pat.is_empty() || str.is_empty() || pat.len() > str.len() {58 return ArrValue::empty();59 }6061 let str = str.as_str();62 let pat = pat.as_bytes();63 let strb = str.as_bytes();6465 let max_pos = str.len() - pat.len();6667 let mut out: Vec<Val> = Vec::new();68 for (ch_idx, (i, _)) in str69 .char_indices()70 .take_while(|(i, _)| i <= &max_pos)71 .enumerate()72 {73 if &strb[i..i + pat.len()] == pat {74 out.push(Val::Num(ch_idx as f64))75 }76 }77 out.into()78}7980#[builtin]81pub fn builtin_parse_int(str: IStr) -> Result<f64> {82 if let Some(raw) = str.strip_prefix('-') {83 if raw.is_empty() {84 throw!("integer only consists of a minus")85 }8687 parse_nat::<10>(raw).map(|value| -value)88 } else {89 if str.is_empty() {90 throw!("empty integer")91 }9293 parse_nat::<10>(str.as_str())94 }95}9697#[builtin]98pub fn builtin_parse_octal(str: IStr) -> Result<f64> {99 if str.is_empty() {100 throw!("empty octal integer");101 }102103 parse_nat::<8>(str.as_str())104}105106#[builtin]107pub fn builtin_parse_hex(str: IStr) -> Result<f64> {108 if str.is_empty() {109 throw!("empty hexadecimal integer");110 }111112 parse_nat::<16>(str.as_str())113}114115fn parse_nat<const BASE: u32>(raw: &str) -> Result<f64> {116 debug_assert!(117 1 <= BASE && BASE <= 16,118 "integer base should be between 1 and 16"119 );120121 const ZERO_CODE: u32 = '0' as u32;122 const UPPER_A_CODE: u32 = 'A' as u32;123 const LOWER_A_CODE: u32 = 'a' as u32;124125 #[inline]126 fn checked_sub_if(condition: bool, lhs: u32, rhs: u32) -> Option<u32> {127 if condition {128 lhs.checked_sub(rhs)129 } else {130 None131 }132 }133134 let base = BASE as f64;135136 raw.chars().try_fold(0f64, |aggregate, digit| {137 let digit = digit as u32;138 let digit = if let Some(digit) = checked_sub_if(BASE > 10, digit, LOWER_A_CODE) {139 digit + 10140 } else if let Some(digit) = checked_sub_if(BASE > 10, digit, UPPER_A_CODE) {141 digit + 10142 } else {143 digit.checked_sub(ZERO_CODE).unwrap_or(BASE)144 };145146 if digit < BASE {147 Ok(base * aggregate + digit as f64)148 } else {149 throw!("{raw:?} is not a base {BASE} integer",);150 }151 })152}153154#[cfg(test)]155mod tests {156 use super::*;157158 #[test]159 fn parse_nat_base_8() {160 assert_eq!(parse_nat::<8>("0").unwrap(), 0.);161 assert_eq!(parse_nat::<8>("5").unwrap(), 5.);162 assert_eq!(parse_nat::<8>("32").unwrap(), 0o32 as f64);163 assert_eq!(parse_nat::<8>("761").unwrap(), 0o761 as f64);164 }165166 #[test]167 fn parse_nat_base_10() {168 assert_eq!(parse_nat::<10>("0").unwrap(), 0.);169 assert_eq!(parse_nat::<10>("3").unwrap(), 3.);170 assert_eq!(parse_nat::<10>("27").unwrap(), 27.);171 assert_eq!(parse_nat::<10>("123").unwrap(), 123.);172 }173174 #[test]175 fn parse_nat_base_16() {176 assert_eq!(parse_nat::<16>("0").unwrap(), 0.);177 assert_eq!(parse_nat::<16>("A").unwrap(), 10.);178 assert_eq!(parse_nat::<16>("a9").unwrap(), 0xA9 as f64);179 assert_eq!(parse_nat::<16>("BbC").unwrap(), 0xBBC as f64);180 }181}crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- 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",