difftreelog
feat sync jsonnet stdlib changes
in: master
8 files changed
crates/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 {
crates/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
crates/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
crates/jrsonnet-stdlib/src/math.rsdiffbeforeafterboth1use jrsonnet_evaluator::{function::builtin, typed::PositiveF64};23#[builtin]4pub fn builtin_abs(n: f64) -> f64 {5 n.abs()6}78#[builtin]9pub fn builtin_sign(n: f64) -> f64 {10 if n == 0. {11 0.12 } else {13 n.signum()14 }15}1617#[builtin]18pub fn builtin_max(a: f64, b: f64) -> f64 {19 a.max(b)20}2122#[builtin]23pub fn builtin_min(a: f64, b: f64) -> f64 {24 a.min(b)25}2627#[allow(non_snake_case)]28#[builtin]29pub fn builtin_clamp(x: f64, minVal: f64, maxVal: f64) -> f64 {30 x.clamp(minVal, maxVal)31}3233#[builtin]34pub fn builtin_sum(arr: Vec<f64>) -> f64 {35 arr.iter().sum()36}3738#[builtin]39pub fn builtin_modulo(x: f64, y: f64) -> f64 {40 x % y41}4243#[builtin]44pub fn builtin_floor(x: f64) -> f64 {45 x.floor()46}4748#[builtin]49pub fn builtin_ceil(x: f64) -> f64 {50 x.ceil()51}5253#[builtin]54pub fn builtin_log(x: f64) -> f64 {55 x.ln()56}5758#[builtin]59pub fn builtin_pow(x: f64, n: f64) -> f64 {60 x.powf(n)61}6263#[builtin]64pub fn builtin_sqrt(x: PositiveF64) -> f64 {65 x.0.sqrt()66}6768#[builtin]69pub fn builtin_sin(x: f64) -> f64 {70 x.sin()71}7273#[builtin]74pub fn builtin_cos(x: f64) -> f64 {75 x.cos()76}7778#[builtin]79pub fn builtin_tan(x: f64) -> f64 {80 x.tan()81}8283#[builtin]84pub fn builtin_asin(x: f64) -> f64 {85 x.asin()86}8788#[builtin]89pub fn builtin_acos(x: f64) -> f64 {90 x.acos()91}9293#[builtin]94pub fn builtin_atan(x: f64) -> f64 {95 x.atan()96}9798#[builtin]99pub fn builtin_atan2(y: f64, x: f64) -> f64 {100 y.atan2(x)101}102103#[builtin]104pub fn builtin_exp(x: f64) -> f64 {105 x.exp()106}107108fn frexp(s: f64) -> (f64, i16) {109 if s == 0.0 {110 (s, 0)111 } else {112 let lg = s.abs().log2();113 let x = (lg - lg.floor() - 1.0).exp2();114 let exp = lg.floor() + 1.0;115 (s.signum() * x, exp as i16)116 }117}118119#[builtin]120pub fn builtin_mantissa(x: f64) -> f64 {121 frexp(x).0122}123124#[builtin]125pub fn builtin_exponent(x: f64) -> i16 {126 frexp(x).1127}128129#[builtin]130pub fn builtin_round(x: f64) -> f64 {131 x.round()132}133134#[builtin]135pub fn builtin_is_even(x: f64) -> bool {136 builtin_round(x) % 2.0 == 0.0137}138139#[builtin]140#[allow(clippy::float_cmp)]141pub fn builtin_is_odd(x: f64) -> bool {142 builtin_round(x) % 2.0 == 1.0143}144145#[builtin]146#[allow(clippy::float_cmp)]147pub fn builtin_is_integer(x: f64) -> bool {148 builtin_round(x) == x149}150151#[builtin]152#[allow(clippy::float_cmp)]153pub fn builtin_is_decimal(x: f64) -> bool {154 builtin_round(x) != x155}1use std::f64;23use jrsonnet_evaluator::{function::builtin, typed::PositiveF64};45#[builtin]6pub fn builtin_abs(n: f64) -> f64 {7 n.abs()8}910#[builtin]11pub fn builtin_sign(n: f64) -> f64 {12 if n == 0. {13 0.14 } else {15 n.signum()16 }17}1819#[builtin]20pub fn builtin_max(a: f64, b: f64) -> f64 {21 a.max(b)22}2324#[builtin]25pub fn builtin_min(a: f64, b: f64) -> f64 {26 a.min(b)27}2829#[allow(non_snake_case)]30#[builtin]31pub fn builtin_clamp(x: f64, minVal: f64, maxVal: f64) -> f64 {32 x.clamp(minVal, maxVal)33}3435#[builtin]36pub fn builtin_sum(arr: Vec<f64>) -> f64 {37 arr.iter().sum()38}3940#[builtin]41pub fn builtin_modulo(x: f64, y: f64) -> f64 {42 x % y43}4445#[builtin]46pub fn builtin_floor(x: f64) -> f64 {47 x.floor()48}4950#[builtin]51pub fn builtin_ceil(x: f64) -> f64 {52 x.ceil()53}5455#[builtin]56pub fn builtin_log(x: f64) -> f64 {57 x.ln()58}5960#[builtin]61pub fn builtin_log2(x: f64) -> f64 {62 x.log2()63}6465#[builtin]66pub fn builtin_log10(x: f64) -> f64 {67 x.log10()68}6970#[builtin]71pub fn builtin_pow(x: f64, n: f64) -> f64 {72 x.powf(n)73}7475#[builtin]76pub fn builtin_sqrt(x: PositiveF64) -> f64 {77 x.0.sqrt()78}7980#[builtin]81pub fn builtin_sin(x: f64) -> f64 {82 x.sin()83}8485#[builtin]86pub fn builtin_cos(x: f64) -> f64 {87 x.cos()88}8990#[builtin]91pub fn builtin_tan(x: f64) -> f64 {92 x.tan()93}9495#[builtin]96pub fn builtin_asin(x: f64) -> f64 {97 x.asin()98}99100#[builtin]101pub fn builtin_acos(x: f64) -> f64 {102 x.acos()103}104105#[builtin]106pub fn builtin_atan(x: f64) -> f64 {107 x.atan()108}109110#[builtin]111pub fn builtin_atan2(y: f64, x: f64) -> f64 {112 y.atan2(x)113}114115#[builtin]116pub fn builtin_exp(x: f64) -> f64 {117 x.exp()118}119120fn frexp(s: f64) -> (f64, i16) {121 if s == 0.0 {122 (s, 0)123 } else {124 let lg = s.abs().log2();125 let x = (lg - lg.floor() - 1.0).exp2();126 let exp = lg.floor() + 1.0;127 (s.signum() * x, exp as i16)128 }129}130131#[builtin]132pub fn builtin_mantissa(x: f64) -> f64 {133 frexp(x).0134}135136#[builtin]137pub fn builtin_exponent(x: f64) -> i16 {138 frexp(x).1139}140141#[builtin]142pub fn builtin_round(x: f64) -> f64 {143 x.round()144}145146#[builtin]147pub fn builtin_is_even(x: f64) -> bool {148 builtin_round(x) % 2.0 == 0.0149}150151#[builtin]152#[allow(clippy::float_cmp)]153pub fn builtin_is_odd(x: f64) -> bool {154 builtin_round(x) % 2.0 == 1.0155}156157#[builtin]158#[allow(clippy::float_cmp)]159pub fn builtin_is_integer(x: f64) -> bool {160 builtin_round(x) == x161}162163#[builtin]164#[allow(clippy::float_cmp)]165pub fn builtin_is_decimal(x: f64) -> bool {166 builtin_round(x) != x167}168169#[builtin]170pub fn builtin_deg2rad(x: f64) -> f64 {171 x * f64::consts::PI / 180.0172}173174#[builtin]175pub fn builtin_rad2deg(x: f64) -> f64 {176 x * 180.0 / f64::consts::PI177}178179#[builtin]180pub fn builtin_hypot(x: f64, y: f64) -> f64 {181 x.hypot(y)182}crates/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)?);
}
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -1,7 +1,8 @@
use jrsonnet_evaluator::{
function::builtin,
+ rustc_hash::FxHashSet,
val::{ArrValue, Val},
- IStr, ObjValue, ObjValueBuilder,
+ IStr, MaybeUnbound, ObjValue, ObjValueBuilder, Thunk,
};
#[builtin]
@@ -166,14 +167,31 @@
preserve_order: bool,
) -> ObjValue {
let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);
- for (k, v) in obj.iter(
+ let all_fields = obj.fields_ex(
+ true,
#[cfg(feature = "exp-preserve-order")]
preserve_order,
- ) {
- if k == key {
+ );
+ let visible_fields = obj
+ .fields_ex(
+ false,
+ #[cfg(feature = "exp-preserve-order")]
+ preserve_order,
+ )
+ .into_iter()
+ .collect::<FxHashSet<_>>();
+
+ for field in &all_fields {
+ if *field == key {
continue;
}
- new_obj.field(k).value(v.unwrap());
+ let mut b = new_obj.field(field.clone());
+ if !visible_fields.contains(&field) {
+ b = b.hide();
+ }
+ let _ = b.binding(MaybeUnbound::Bound(Thunk::result(
+ obj.get(field.clone()).transpose().expect("field exists"),
+ )));
}
new_obj.build()
crates/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(),
crates/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)
+}