git.delta.rocks / jrsonnet / refs/commits / d0fb5f4781e5

difftreelog

feat exp-bigint

Yaroslav Bolyukin2023-04-17parent: #205090d.patch.diff
in: master

16 files changed

modifiedCargo.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"
modifiedCargo.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"]
 
modifiedcmds/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"]
modifiedcrates/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]
modifiedcrates/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 }
modifiedcrates/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(),
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/integrations/serde.rs
1use std::borrow::Cow;23use jrsonnet_interner::IStr;4use serde::{5	de::Visitor,6	ser::{7		Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,8		SerializeTupleStruct, SerializeTupleVariant,9	},10	Deserialize, Serialize, Serializer,11};1213use crate::{14	arr::ArrValue,15	error::{Error as JrError, ErrorKind, Result},16	val::StrValue,17	ObjValue, ObjValueBuilder, State, Val,18};1920impl<'de> Deserialize<'de> for Val {21	fn deserialize<D>(deserializer: D) -> Result<Val, D::Error>22	where23		D: serde::Deserializer<'de>,24	{25		struct ValVisitor;2627		// macro_rules! visit_num {28		// 	($($method:ident => $ty:ty),* $(,)?) => {$(29		// 		fn $method<E>(self, v: $ty) -> Result<Self::Value, E>30		// 		where31		// 			E: serde::de::Error,32		// 		{33		// 			Ok(Val::Num(f64::from(v)))34		// 		}35		// 	)*};36		// }3738		impl<'de> Visitor<'de> for ValVisitor {39			type Value = Val;4041			fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>42			where43				E: serde::de::Error,44			{45				Ok(Val::Bool(v))46			}47			fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>48			where49				E: serde::de::Error,50			{51				if !v.is_finite() {52					return Err(E::custom("only finite numbers are supported"));53				}54				Ok(Val::Num(v))55			}56			fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>57			where58				E: serde::de::Error,59			{60				Ok(Val::Str(StrValue::Flat(v.into())))61			}6263			// visit_num! {64			// 	visit_i8 => i8,65			// 	visit_i16 => i16,66			// 	visit_i32 => i32,67			// 	visit_u8 => u8,68			// 	visit_u16 => u16,69			// 	visit_u32 => u32,70			// }71			fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>72			where73				E: serde::de::Error,74			{75				Ok(Val::Num(v as f64))76			}77			fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>78			where79				E: serde::de::Error,80			{81				Ok(Val::Num(v as f64))82			}8384			fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>85			where86				E: serde::de::Error,87			{88				Ok(Val::Arr(ArrValue::bytes(v.into())))89			}9091			fn visit_none<E>(self) -> Result<Self::Value, E>92			where93				E: serde::de::Error,94			{95				Ok(Val::Null)96			}97			fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>98			where99				D: serde::Deserializer<'de>,100			{101				deserializer.deserialize_any(self)102			}103104			fn visit_unit<E>(self) -> Result<Self::Value, E>105			where106				E: serde::de::Error,107			{108				Ok(Val::Null)109			}110111			fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>112			where113				D: serde::Deserializer<'de>,114			{115				deserializer.deserialize_any(self)116			}117118			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>119			where120				A: serde::de::SeqAccess<'de>,121			{122				let mut out = seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);123124				while let Some(val) = seq.next_element::<Val>()? {125					out.push(val);126				}127128				Ok(Val::Arr(ArrValue::eager(out)))129			}130131			fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>132			where133				A: serde::de::MapAccess<'de>,134			{135				let mut out = map136					.size_hint()137					.map_or_else(ObjValueBuilder::new, ObjValueBuilder::with_capacity);138139				while let Some((k, v)) = map.next_entry::<Cow<'de, str>, Val>()? {140					// Jsonnet ignores duplicate keys141					out.member(k.into()).value_unchecked(v);142				}143144				Ok(Val::Obj(out.build()))145			}146147			fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {148				write!(formatter, "any valid jsonnet value")149			}150		}151		deserializer.deserialize_any(ValVisitor)152	}153}154155impl Serialize for Val {156	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>157	where158		S: serde::Serializer,159	{160		match self {161			Val::Bool(v) => serializer.serialize_bool(*v),162			Val::Null => serializer.serialize_none(),163			Val::Str(s) => serializer.serialize_str(&s.clone().into_flat()),164			Val::Num(n) => serializer.serialize_f64(*n),165			Val::Arr(arr) => {166				let mut seq = serializer.serialize_seq(Some(arr.len()))?;167				for (i, element) in arr.iter().enumerate() {168					let mut serde_error = None;169					// TODO: rewrite using try{} after stabilization170					State::push_description(171						|| format!("array index [{i}]"),172						|| {173							let e = element?;174							if let Err(e) = seq.serialize_element(&e) {175								serde_error = Some(e);176							}177							Ok(())178						},179					)180					.map_err(|e| S::Error::custom(e.to_string()))?;181					if let Some(e) = serde_error {182						return Err(e);183					}184				}185				seq.end()186			}187			Val::Obj(obj) => {188				let mut map = serializer.serialize_map(Some(obj.len()))?;189				for (field, value) in obj.iter(190					#[cfg(feature = "exp-preserve-order")]191					true,192				) {193					let mut serde_error = None;194					// TODO: rewrite using try{} after stabilization195					State::push_description(196						|| format!("object field {field:?}"),197						|| {198							let v = value?;199							if let Err(e) = map.serialize_entry(field.as_str(), &v) {200								serde_error = Some(e);201							}202							Ok(())203						},204					)205					.map_err(|e| S::Error::custom(e.to_string()))?;206					if let Some(e) = serde_error {207						return Err(e);208					}209				}210				map.end()211			}212			Val::Func(_) => Err(S::Error::custom("tried to manifest function")),213		}214	}215}216217struct IntoVecValSerializer {218	variant: Option<IStr>,219	data: Vec<Val>,220}221impl IntoVecValSerializer {222	fn new() -> Self {223		Self {224			variant: None,225			data: Vec::new(),226		}227	}228	fn with_capacity(capacity: usize) -> Self {229		Self {230			variant: None,231			data: Vec::with_capacity(capacity),232		}233	}234	fn variant_with_capacity(variant: impl Into<IStr>, capacity: usize) -> Self {235		Self {236			variant: Some(variant.into()),237			data: Vec::with_capacity(capacity),238		}239	}240}241impl SerializeSeq for IntoVecValSerializer {242	type Ok = Val;243	type Error = JrError;244245	fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>246	where247		T: Serialize,248	{249		let value = value.serialize(IntoValSerializer)?;250		self.data.push(value);251		Ok(())252	}253254	fn end(self) -> Result<Val> {255		let inner = Val::Arr(ArrValue::eager(self.data));256		if let Some(variant) = self.variant {257			let mut out = ObjValue::builder_with_capacity(1);258			out.member(variant).value_unchecked(inner);259			Ok(Val::Obj(out.build()))260		} else {261			Ok(inner)262		}263	}264}265impl SerializeTuple for IntoVecValSerializer {266	type Ok = Val;267	type Error = JrError;268269	fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>270	where271		T: Serialize,272	{273		SerializeSeq::serialize_element(self, value)274	}275276	fn end(self) -> Result<Val> {277		SerializeSeq::end(self)278	}279}280impl SerializeTupleVariant for IntoVecValSerializer {281	type Ok = Val;282	type Error = JrError;283284	fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>285	where286		T: Serialize,287	{288		SerializeSeq::serialize_element(self, value)289	}290291	fn end(self) -> Result<Val> {292		SerializeSeq::end(self)293	}294}295impl SerializeTupleStruct for IntoVecValSerializer {296	type Ok = Val;297	type Error = JrError;298299	fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>300	where301		T: Serialize,302	{303		SerializeSeq::serialize_element(self, value)304	}305306	fn end(self) -> Result<Val> {307		SerializeSeq::end(self)308	}309}310311struct IntoObjValueSerializer {312	variant: Option<IStr>,313	data: ObjValueBuilder,314	key: Option<IStr>,315}316impl IntoObjValueSerializer {317	fn new() -> Self {318		Self {319			variant: None,320			data: ObjValue::builder(),321			key: None,322		}323	}324	fn with_capacity(capacity: usize) -> Self {325		Self {326			variant: None,327			data: ObjValue::builder_with_capacity(capacity),328			key: None,329		}330	}331	fn variant_with_capacity(variant: impl Into<IStr>, capacity: usize) -> Self {332		Self {333			variant: Some(variant.into()),334			data: ObjValue::builder_with_capacity(capacity),335			key: None,336		}337	}338}339impl SerializeMap for IntoObjValueSerializer {340	type Ok = Val;341	type Error = JrError;342343	fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>344	where345		T: Serialize,346	{347		let key = key.serialize(IntoValSerializer)?;348		let key = key.to_string()?;349		self.key = Some(key);350		Ok(())351	}352353	fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>354	where355		T: Serialize,356	{357		let key = self.key.take().expect("no serialize_key called");358		let value = value.serialize(IntoValSerializer)?;359		self.data.member(key).value(value)?;360		Ok(())361	}362363	// TODO: serialize_key/serialize_value364	fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<()>365	where366		K: Serialize,367		V: Serialize,368	{369		let key = key.serialize(IntoValSerializer)?;370		let key = key.to_string()?;371		let value = value.serialize(IntoValSerializer)?;372		self.data.member(key).value(value)?;373		Ok(())374	}375376	fn end(self) -> Result<Val> {377		let inner = Val::Obj(self.data.build());378		if let Some(variant) = self.variant {379			let mut out = ObjValue::builder_with_capacity(1);380			out.member(variant).value_unchecked(inner);381			Ok(Val::Obj(out.build()))382		} else {383			Ok(inner)384		}385	}386}387impl SerializeStruct for IntoObjValueSerializer {388	type Ok = Val;389	type Error = JrError;390391	fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>392	where393		T: Serialize,394	{395		SerializeMap::serialize_entry(self, key, value)?;396		Ok(())397	}398399	fn end(self) -> Result<Val> {400		SerializeMap::end(self)401	}402}403impl SerializeStructVariant for IntoObjValueSerializer {404	type Ok = Val;405406	type Error = JrError;407408	fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()>409	where410		T: Serialize,411	{412		SerializeMap::serialize_entry(self, key, value)?;413		Ok(())414	}415416	fn end(self) -> Result<Val> {417		SerializeMap::end(self)418	}419}420421struct IntoValSerializer;422impl Serializer for IntoValSerializer {423	type Ok = Val;424425	type Error = JrError;426427	type SerializeSeq = IntoVecValSerializer;428429	type SerializeTuple = IntoVecValSerializer;430431	type SerializeTupleStruct = IntoVecValSerializer;432433	type SerializeTupleVariant = IntoVecValSerializer;434435	type SerializeMap = IntoObjValueSerializer;436437	type SerializeStruct = IntoObjValueSerializer;438439	type SerializeStructVariant = IntoObjValueSerializer;440441	fn serialize_bool(self, v: bool) -> Result<Val> {442		Ok(Val::Bool(v))443	}444445	fn serialize_i8(self, v: i8) -> Result<Val> {446		Ok(Val::Num(f64::from(v)))447	}448449	fn serialize_i16(self, v: i16) -> Result<Val> {450		Ok(Val::Num(f64::from(v)))451	}452453	fn serialize_i32(self, v: i32) -> Result<Val> {454		Ok(Val::Num(f64::from(v)))455	}456457	fn serialize_i64(self, v: i64) -> Result<Val> {458		Ok(Val::Str(v.to_string().into()))459	}460461	fn serialize_u8(self, v: u8) -> Result<Val> {462		Ok(Val::Num(f64::from(v)))463	}464465	fn serialize_u16(self, v: u16) -> Result<Val> {466		Ok(Val::Num(f64::from(v)))467	}468469	fn serialize_u32(self, v: u32) -> Result<Val> {470		Ok(Val::Num(f64::from(v)))471	}472473	fn serialize_u64(self, v: u64) -> Result<Val> {474		Ok(Val::Str(v.to_string().into()))475	}476477	fn serialize_f32(self, v: f32) -> Result<Val> {478		Ok(Val::Num(f64::from(v)))479	}480481	fn serialize_f64(self, v: f64) -> Result<Val> {482		Ok(Val::Num(v))483	}484485	fn serialize_char(self, v: char) -> Result<Val> {486		Ok(Val::Str(v.to_string().into()))487	}488489	fn serialize_str(self, v: &str) -> Result<Val> {490		Ok(Val::Str(v.into()))491	}492493	fn serialize_bytes(self, v: &[u8]) -> Result<Val> {494		Ok(Val::Arr(ArrValue::bytes(v.into())))495	}496497	fn serialize_none(self) -> Result<Val> {498		Ok(Val::Null)499	}500501	fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Val>502	where503		T: Serialize,504	{505		value.serialize(self)506	}507508	fn serialize_unit(self) -> Result<Val> {509		Ok(Val::Null)510	}511512	fn serialize_unit_struct(self, _name: &'static str) -> Result<Val> {513		Ok(Val::Null)514	}515516	fn serialize_unit_variant(517		self,518		_name: &'static str,519		_variant_index: u32,520		variant: &'static str,521	) -> Result<Val> {522		Ok(Val::Str(variant.into()))523	}524525	fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<Val>526	where527		T: Serialize,528	{529		value.serialize(self)530	}531532	fn serialize_newtype_variant<T: ?Sized>(533		self,534		_name: &'static str,535		_variant_index: u32,536		variant: &'static str,537		value: &T,538	) -> Result<Val>539	where540		T: Serialize,541	{542		let mut out = ObjValue::builder_with_capacity(1);543		let value = value.serialize(self)?;544		out.member(variant.into()).value_unchecked(value);545		Ok(Val::Obj(out.build()))546	}547548	fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {549		Ok(len.map_or_else(550			IntoVecValSerializer::new,551			IntoVecValSerializer::with_capacity,552		))553	}554555	fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {556		Ok(IntoVecValSerializer::with_capacity(len))557	}558559	fn serialize_tuple_struct(560		self,561		_name: &'static str,562		len: usize,563	) -> Result<Self::SerializeTupleStruct, Self::Error> {564		Ok(IntoVecValSerializer::with_capacity(len))565	}566567	fn serialize_tuple_variant(568		self,569		_name: &'static str,570		_variant_index: u32,571		variant: &'static str,572		len: usize,573	) -> Result<Self::SerializeTupleVariant, Self::Error> {574		Ok(IntoVecValSerializer::variant_with_capacity(variant, len))575	}576577	fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {578		Ok(len.map_or_else(579			IntoObjValueSerializer::new,580			IntoObjValueSerializer::with_capacity,581		))582	}583584	fn serialize_struct(585		self,586		_name: &'static str,587		len: usize,588	) -> Result<Self::SerializeStruct, Self::Error> {589		Ok(IntoObjValueSerializer::with_capacity(len))590	}591592	fn serialize_struct_variant(593		self,594		_name: &'static str,595		_variant_index: u32,596		variant: &'static str,597		len: usize,598	) -> Result<Self::SerializeStructVariant, Self::Error> {599		Ok(IntoObjValueSerializer::variant_with_capacity(variant, len))600	}601}602603impl Val {604	pub fn from_serde(v: impl Serialize) -> Result<Val, JrError> {605		v.serialize(IntoValSerializer)606	}607}608609impl serde::ser::Error for JrError {610	fn custom<T>(msg: T) -> Self611	where612		T: std::fmt::Display,613	{614		JrError::new(ErrorKind::RuntimeError(format!("serde: {msg}").into()))615	}616}
modifiedcrates/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() {
modifiedcrates/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,
modifiedcrates/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
modifiedcrates/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"))
 	}
modifiedcrates/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
modifiedcrates/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("[]");
modifiedcrates/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("[]");
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
--- 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<Val> {
+	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::*;
modifiedcrates/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",