git.delta.rocks / jrsonnet / refs/commits / 4a793257644c

difftreelog

feat sync jsonnet stdlib changes

yzozlsyrYaroslav Bolyukin2026-02-07parent: #6551086.patch.diff
in: master

8 files changed

modifiedcrates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/manifest.rs
@@ -413,18 +413,19 @@
 				val.value_type()
 			)
 		};
-		if !arr.is_empty() {
-			for (i, v) in arr.iter().enumerate() {
-				let v = v.with_description(|| format!("elem <{i}> evaluation"))?;
-				out.push_str("---\n");
-				in_description_frame(
-					|| format!("elem <{i}> manifestification"),
-					|| self.inner.manifest_buf(v, out),
-				)?;
+		for (i, v) in arr.iter().enumerate() {
+			if i != 0 {
 				out.push('\n');
 			}
+			let v = v.with_description(|| format!("elem <{i}> evaluation"))?;
+			out.push_str("---\n");
+			in_description_frame(
+				|| format!("elem <{i}> manifestification"),
+				|| self.inner.manifest_buf(v, out),
+			)?;
 		}
 		if self.c_document_end {
+			out.push('\n');
 			out.push_str("...");
 		}
 		if self.end_newline {
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -237,7 +237,11 @@
 				Expr::ArrComp(expr, specs)
 			}
 		pub rule number_expr(s: &ParserSettings) -> Expr
-			= n:number() { expr::Expr::Num(n) }
+			= n:number() {? if n.is_finite() {
+				Ok(expr::Expr::Num(n))
+			} else {
+				Err("!!!numbers are finite")
+			}}
 		pub rule var_expr(s: &ParserSettings) -> Expr
 			= n:id() { expr::Expr::Var(n) }
 		pub rule id_loc(s: &ParserSettings) -> LocExpr
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -3,6 +3,7 @@
 use std::{
 	cell::{Ref, RefCell, RefMut},
 	collections::HashMap,
+	f64,
 	rc::Rc,
 };
 
@@ -14,6 +15,7 @@
 	error::{ErrorKind::*, Result},
 	function::{CallLocation, FuncVal, TlaArg},
 	trace::PathResolver,
+	val::NumValue,
 	ContextBuilder, IStr, ObjValue, ObjValueBuilder, Thunk, Val,
 };
 use jrsonnet_gcmodule::{Acyclic, Cc, Trace};
@@ -63,6 +65,7 @@
 		("isObject", builtin_is_object::INST),
 		("isArray", builtin_is_array::INST),
 		("isFunction", builtin_is_function::INST),
+		("isNull", builtin_is_null::INST),
 		// Arrays
 		("makeArray", builtin_make_array::INST),
 		("repeat", builtin_repeat::INST),
@@ -104,6 +107,8 @@
 		("floor", builtin_floor::INST),
 		("ceil", builtin_ceil::INST),
 		("log", builtin_log::INST),
+		("log2", builtin_log2::INST),
+		("log10", builtin_log10::INST),
 		("pow", builtin_pow::INST),
 		("sqrt", builtin_sqrt::INST),
 		("sin", builtin_sin::INST),
@@ -121,6 +126,9 @@
 		("isOdd", builtin_is_odd::INST),
 		("isInteger", builtin_is_integer::INST),
 		("isDecimal", builtin_is_decimal::INST),
+		("deg2rad", builtin_deg2rad::INST),
+		("rad2deg", builtin_rad2deg::INST),
+		("hypot", builtin_hypot::INST),
 		// Operator
 		("mod", builtin_mod::INST),
 		("primitiveEquals", builtin_primitive_equals::INST),
@@ -201,6 +209,7 @@
 		("lstripChars", builtin_lstrip_chars::INST),
 		("rstripChars", builtin_rstrip_chars::INST),
 		("stripChars", builtin_strip_chars::INST),
+		("trim", builtin_trim::INST),
 		// Misc
 		("length", builtin_length::INST),
 		("get", builtin_get::INST),
@@ -248,6 +257,10 @@
 	builder.method("trace", builtin_trace { settings });
 	builder.method("id", FuncVal::Id);
 
+	builder.field("pi").hide().value(Val::Num(
+		NumValue::new(f64::consts::PI).expect("pi is finite"),
+	));
+
 	#[cfg(feature = "exp-regex")]
 	{
 		// Regex
modifiedcrates/jrsonnet-stdlib/src/math.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/math.rs
+++ b/crates/jrsonnet-stdlib/src/math.rs
@@ -1,3 +1,5 @@
+use std::f64;
+
 use jrsonnet_evaluator::{function::builtin, typed::PositiveF64};
 
 #[builtin]
@@ -56,6 +58,16 @@
 }
 
 #[builtin]
+pub fn builtin_log2(x: f64) -> f64 {
+	x.log2()
+}
+
+#[builtin]
+pub fn builtin_log10(x: f64) -> f64 {
+	x.log10()
+}
+
+#[builtin]
 pub fn builtin_pow(x: f64, n: f64) -> f64 {
 	x.powf(n)
 }
@@ -153,3 +165,18 @@
 pub fn builtin_is_decimal(x: f64) -> bool {
 	builtin_round(x) != x
 }
+
+#[builtin]
+pub fn builtin_deg2rad(x: f64) -> f64 {
+	x * f64::consts::PI / 180.0
+}
+
+#[builtin]
+pub fn builtin_rad2deg(x: f64) -> f64 {
+	x * 180.0 / f64::consts::PI
+}
+
+#[builtin]
+pub fn builtin_hypot(x: f64, y: f64) -> f64 {
+	x.hypot(y)
+}
modifiedcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -156,8 +156,16 @@
 		#[cfg(feature = "exp-preserve-order")]
 		true,
 	);
-	let a = a.manifest(&format).description("<a> manifestification")?;
-	let b = b.manifest(&format).description("<b> manifestification")?;
+	let a = if let Some(a) = a.as_str() {
+		format!("<A>\n{a}\n</A>")
+	} else {
+		a.manifest(&format).description("<a> manifestification")?
+	};
+	let b = if let Some(b) = b.as_str() {
+		format!("<B>\n{b}\n</B>")
+	} else {
+		b.manifest(&format).description("<b> manifestification")?
+	};
 	bail!("assertion failed: A != B\nA: {a}\nB: {b}")
 }
 
@@ -166,9 +174,7 @@
 	let Some(patch) = patch.as_obj() else {
 		return Ok(patch);
 	};
-	let Some(target) = target.as_obj() else {
-		return Ok(Val::Obj(patch));
-	};
+	let target = target.as_obj().unwrap_or_else(|| ObjValue::new_empty());
 	let target_fields = target
 		.fields(
 			// FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?
@@ -203,10 +209,7 @@
 		if matches!(field_patch, Val::Null) {
 			continue;
 		}
-		let Some(field_target) = target.get(field.clone())? else {
-			out.field(field.clone()).value(field_patch);
-			continue;
-		};
+		let field_target = target.get(field.clone())?.unwrap_or(Val::Null);
 		out.field(field.clone())
 			.value(builtin_merge_patch(field_target, field_patch)?);
 	}
modifiedcrates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth
before · crates/jrsonnet-stdlib/src/objects.rs
1use jrsonnet_evaluator::{2	function::builtin,3	val::{ArrValue, Val},4	IStr, ObjValue, ObjValueBuilder,5};67#[builtin]8pub fn builtin_object_fields_ex(9	obj: ObjValue,10	hidden: bool,1112	#[default(false)]13	#[cfg(feature = "exp-preserve-order")]14	preserve_order: bool,15) -> Vec<Val> {16	let out = obj.fields_ex(17		hidden,18		#[cfg(feature = "exp-preserve-order")]19		preserve_order,20	);21	out.into_iter().map(Val::string).collect::<Vec<_>>()22}2324#[builtin]25pub fn builtin_object_fields(26	o: ObjValue,2728	#[default(false)]29	#[cfg(feature = "exp-preserve-order")]30	preserve_order: bool,31) -> Vec<Val> {32	builtin_object_fields_ex(33		o,34		false,35		#[cfg(feature = "exp-preserve-order")]36		preserve_order,37	)38}3940#[builtin]41pub fn builtin_object_fields_all(42	o: ObjValue,4344	#[default(false)]45	#[cfg(feature = "exp-preserve-order")]46	preserve_order: bool,47) -> Vec<Val> {48	builtin_object_fields_ex(49		o,50		true,51		#[cfg(feature = "exp-preserve-order")]52		preserve_order,53	)54}5556pub fn builtin_object_values_ex(57	o: ObjValue,58	include_hidden: bool,5960	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,61) -> ArrValue {62	o.values_ex(63		include_hidden,64		#[cfg(feature = "exp-preserve-order")]65		preserve_order,66	)67}68#[builtin]69pub fn builtin_object_values(70	o: ObjValue,7172	#[default(false)]73	#[cfg(feature = "exp-preserve-order")]74	preserve_order: bool,75) -> ArrValue {76	builtin_object_values_ex(77		o,78		false,79		#[cfg(feature = "exp-preserve-order")]80		preserve_order,81	)82}83#[builtin]84pub fn builtin_object_values_all(85	o: ObjValue,8687	#[default(false)]88	#[cfg(feature = "exp-preserve-order")]89	preserve_order: bool,90) -> ArrValue {91	builtin_object_values_ex(92		o,93		true,94		#[cfg(feature = "exp-preserve-order")]95		preserve_order,96	)97}9899pub fn builtin_object_keys_values_ex(100	o: ObjValue,101	include_hidden: bool,102103	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,104) -> ArrValue {105	o.key_values_ex(106		include_hidden,107		#[cfg(feature = "exp-preserve-order")]108		preserve_order,109	)110}111#[builtin]112pub fn builtin_object_keys_values(113	o: ObjValue,114115	#[default(false)]116	#[cfg(feature = "exp-preserve-order")]117	preserve_order: bool,118) -> ArrValue {119	builtin_object_keys_values_ex(120		o,121		false,122		#[cfg(feature = "exp-preserve-order")]123		preserve_order,124	)125}126#[builtin]127pub fn builtin_object_keys_values_all(128	o: ObjValue,129130	#[default(false)]131	#[cfg(feature = "exp-preserve-order")]132	preserve_order: bool,133) -> ArrValue {134	builtin_object_keys_values_ex(135		o,136		true,137		#[cfg(feature = "exp-preserve-order")]138		preserve_order,139	)140}141142#[builtin]143pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {144	obj.has_field_ex(fname, hidden)145}146147#[builtin]148pub fn builtin_object_has(o: ObjValue, f: IStr) -> bool {149	o.has_field(f)150}151152#[builtin]153pub fn builtin_object_has_all(o: ObjValue, f: IStr) -> bool {154	o.has_field_include_hidden(f)155}156157#[builtin]158pub fn builtin_object_remove_key(159	obj: ObjValue,160	key: IStr,161162	// Standard implementation uses std.objectFields without such argument, we can't163	// assume order preservation should always be enabled/disabled164	#[default(false)]165	#[cfg(feature = "exp-preserve-order")]166	preserve_order: bool,167) -> ObjValue {168	let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);169	for (k, v) in obj.iter(170		#[cfg(feature = "exp-preserve-order")]171		preserve_order,172	) {173		if k == key {174			continue;175		}176		new_obj.field(k).value(v.unwrap());177	}178179	new_obj.build()180}
after · crates/jrsonnet-stdlib/src/objects.rs
1use jrsonnet_evaluator::{2	function::builtin,3	rustc_hash::FxHashSet,4	val::{ArrValue, Val},5	IStr, MaybeUnbound, ObjValue, ObjValueBuilder, Thunk,6};78#[builtin]9pub fn builtin_object_fields_ex(10	obj: ObjValue,11	hidden: bool,1213	#[default(false)]14	#[cfg(feature = "exp-preserve-order")]15	preserve_order: bool,16) -> Vec<Val> {17	let out = obj.fields_ex(18		hidden,19		#[cfg(feature = "exp-preserve-order")]20		preserve_order,21	);22	out.into_iter().map(Val::string).collect::<Vec<_>>()23}2425#[builtin]26pub fn builtin_object_fields(27	o: ObjValue,2829	#[default(false)]30	#[cfg(feature = "exp-preserve-order")]31	preserve_order: bool,32) -> Vec<Val> {33	builtin_object_fields_ex(34		o,35		false,36		#[cfg(feature = "exp-preserve-order")]37		preserve_order,38	)39}4041#[builtin]42pub fn builtin_object_fields_all(43	o: ObjValue,4445	#[default(false)]46	#[cfg(feature = "exp-preserve-order")]47	preserve_order: bool,48) -> Vec<Val> {49	builtin_object_fields_ex(50		o,51		true,52		#[cfg(feature = "exp-preserve-order")]53		preserve_order,54	)55}5657pub fn builtin_object_values_ex(58	o: ObjValue,59	include_hidden: bool,6061	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,62) -> ArrValue {63	o.values_ex(64		include_hidden,65		#[cfg(feature = "exp-preserve-order")]66		preserve_order,67	)68}69#[builtin]70pub fn builtin_object_values(71	o: ObjValue,7273	#[default(false)]74	#[cfg(feature = "exp-preserve-order")]75	preserve_order: bool,76) -> ArrValue {77	builtin_object_values_ex(78		o,79		false,80		#[cfg(feature = "exp-preserve-order")]81		preserve_order,82	)83}84#[builtin]85pub fn builtin_object_values_all(86	o: ObjValue,8788	#[default(false)]89	#[cfg(feature = "exp-preserve-order")]90	preserve_order: bool,91) -> ArrValue {92	builtin_object_values_ex(93		o,94		true,95		#[cfg(feature = "exp-preserve-order")]96		preserve_order,97	)98}99100pub fn builtin_object_keys_values_ex(101	o: ObjValue,102	include_hidden: bool,103104	#[cfg(feature = "exp-preserve-order")] preserve_order: bool,105) -> ArrValue {106	o.key_values_ex(107		include_hidden,108		#[cfg(feature = "exp-preserve-order")]109		preserve_order,110	)111}112#[builtin]113pub fn builtin_object_keys_values(114	o: ObjValue,115116	#[default(false)]117	#[cfg(feature = "exp-preserve-order")]118	preserve_order: bool,119) -> ArrValue {120	builtin_object_keys_values_ex(121		o,122		false,123		#[cfg(feature = "exp-preserve-order")]124		preserve_order,125	)126}127#[builtin]128pub fn builtin_object_keys_values_all(129	o: ObjValue,130131	#[default(false)]132	#[cfg(feature = "exp-preserve-order")]133	preserve_order: bool,134) -> ArrValue {135	builtin_object_keys_values_ex(136		o,137		true,138		#[cfg(feature = "exp-preserve-order")]139		preserve_order,140	)141}142143#[builtin]144pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {145	obj.has_field_ex(fname, hidden)146}147148#[builtin]149pub fn builtin_object_has(o: ObjValue, f: IStr) -> bool {150	o.has_field(f)151}152153#[builtin]154pub fn builtin_object_has_all(o: ObjValue, f: IStr) -> bool {155	o.has_field_include_hidden(f)156}157158#[builtin]159pub fn builtin_object_remove_key(160	obj: ObjValue,161	key: IStr,162163	// Standard implementation uses std.objectFields without such argument, we can't164	// assume order preservation should always be enabled/disabled165	#[default(false)]166	#[cfg(feature = "exp-preserve-order")]167	preserve_order: bool,168) -> ObjValue {169	let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);170	let all_fields = obj.fields_ex(171		true,172		#[cfg(feature = "exp-preserve-order")]173		preserve_order,174	);175	let visible_fields = obj176		.fields_ex(177			false,178			#[cfg(feature = "exp-preserve-order")]179			preserve_order,180		)181		.into_iter()182		.collect::<FxHashSet<_>>();183184	for field in &all_fields {185		if *field == key {186			continue;187		}188		let mut b = new_obj.field(field.clone());189		if !visible_fields.contains(&field) {190			b = b.hide();191		}192		let _ = b.binding(MaybeUnbound::Bound(Thunk::result(193			obj.get(field.clone()).transpose().expect("field exists"),194		)));195	}196197	new_obj.build()198}
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -254,6 +254,19 @@
 	Ok(str.as_str().trim_matches(pattern).into())
 }
 
+#[builtin]
+pub fn builtin_trim(str: IStr) -> String {
+	let filter =
+		|v: char| {
+			v == ' '
+				|| v == '\t' || v == '\n'
+				|| v == '\u{000c}'
+				|| v == '\r' || v == '\u{0085}'
+				|| v == '\u{00a0}'
+		};
+	str.as_str().trim_matches(filter).to_string()
+}
+
 fn new_trim_pattern(chars: IndexableVal) -> Result<impl Fn(char) -> bool> {
 	let chars: BTreeSet<char> = match chars {
 		IndexableVal::Str(chars) => chars.chars().collect(),
modifiedcrates/jrsonnet-stdlib/src/types.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/types.rs
+++ b/crates/jrsonnet-stdlib/src/types.rs
@@ -29,3 +29,7 @@
 pub fn builtin_is_function(v: Val) -> bool {
 	matches!(v, Val::Func(_))
 }
+#[builtin]
+pub fn builtin_is_null(v: Val) -> bool {
+	matches!(v, Val::Null)
+}