difftreelog
refactor fix clippy warnings
in: master
27 files changed
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -150,6 +150,9 @@
redundant_pub_crate = "allow"
# Sometimes code is fancier without that
manual_let_else = "allow"
+# Something is broken about that lint, can't be allowed for
+# codegenerated-stdlib block
+similar_names = "allow"
#[profile.test]
#opt-level = 1
cmds/jrsonnet-fmt/src/tests.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/tests.rs
+++ b/cmds/jrsonnet-fmt/src/tests.rs
@@ -1,4 +1,4 @@
-use dprint_core::formatting::{PrintOptions, PrintItems};
+use dprint_core::formatting::{PrintItems, PrintOptions};
use indoc::indoc;
use crate::Printable;
cmds/jrsonnet/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet/src/main.rs
+++ b/cmds/jrsonnet/src/main.rs
@@ -153,7 +153,7 @@
if let Error::Evaluation(e) = e {
let mut out = String::new();
trace.write_trace(&mut out, &e).expect("format error");
- eprintln!("{out}")
+ eprintln!("{out}");
} else {
eprintln!("{e}");
}
crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-cli/src/lib.rs
+++ b/crates/jrsonnet-cli/src/lib.rs
@@ -10,7 +10,7 @@
stack::{limit_stack_depth, StackDepthLimitOverrideGuard},
FileImportResolver,
};
-use jrsonnet_gcmodule::with_thread_object_space;
+use jrsonnet_gcmodule::{with_thread_object_space, ObjectSpace};
pub use manifest::*;
pub use stdlib::*;
pub use tla::*;
@@ -88,7 +88,7 @@
impl Drop for LeakSpace {
fn drop(&mut self) {
- with_thread_object_space(|s| s.leak())
+ with_thread_object_space(ObjectSpace::leak);
}
}
@@ -102,6 +102,6 @@
let collected = jrsonnet_gcmodule::collect_thread_cycles();
eprintln!("Collected: {collected}");
}
- eprintln!("Tracked: {}", jrsonnet_gcmodule::count_thread_tracked())
+ eprintln!("Tracked: {}", jrsonnet_gcmodule::count_thread_tracked());
}
}
crates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth--- a/crates/jrsonnet-cli/src/stdlib.rs
+++ b/crates/jrsonnet-cli/src/stdlib.rs
@@ -39,11 +39,11 @@
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.find('=') {
- Some(idx) => Ok(ExtStr {
+ Some(idx) => Ok(Self {
name: s[..idx].to_owned(),
value: s[idx + 1..].to_owned(),
}),
- None => Ok(ExtStr {
+ None => Ok(Self {
name: s.to_owned(),
value: std::env::var(s).or(Err("missing env var"))?,
}),
@@ -109,16 +109,16 @@
return Ok(None);
}
let ctx = ContextInitializer::new(s.clone(), PathResolver::new_cwd_fallback());
- for ext in self.ext_str.iter() {
+ for ext in &self.ext_str {
ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
}
- for ext in self.ext_str_file.iter() {
+ for ext in &self.ext_str_file {
ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
}
- for ext in self.ext_code.iter() {
+ for ext in &self.ext_code {
ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;
}
- for ext in self.ext_code_file.iter() {
+ for ext in &self.ext_code_file {
ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;
}
Ok(Some(ctx))
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -42,7 +42,7 @@
Self::new(EagerArray(values))
}
- pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {
+ pub fn repeated(data: Self, repeats: usize) -> Option<Self> {
Some(Self::new(RepeatedArray::new(data, repeats)?))
}
@@ -70,7 +70,7 @@
Ok(Self::eager(out))
}
- pub fn extended(a: ArrValue, b: ArrValue) -> Self {
+ pub fn extended(a: Self, b: Self) -> Self {
// TODO: benchmark for an optimal value, currently just a arbitrary choice
const ARR_EXTEND_THRESHOLD: usize = 100;
crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/arglike.rs
+++ b/crates/jrsonnet-evaluator/src/function/arglike.rs
@@ -61,8 +61,8 @@
impl ArgLike for TlaArg {
fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {
match self {
- TlaArg::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),
- TlaArg::Code(code) => Ok(if tailstrict {
+ Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),
+ Self::Code(code) => Ok(if tailstrict {
Thunk::evaluated(evaluate(ctx, code)?)
} else {
Thunk::new(EvaluateThunk {
@@ -70,8 +70,8 @@
expr: code.clone(),
})
}),
- TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),
- TlaArg::Lazy(lazy) => Ok(lazy.clone()),
+ Self::Val(val) => Ok(Thunk::evaluated(val.clone())),
+ Self::Lazy(lazy) => Ok(lazy.clone()),
}
}
}
crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -237,7 +237,7 @@
pub fn evaluate_trivial(&self) -> Option<Val> {
match self {
- FuncVal::Normal(n) => n.evaluate_trivial(),
+ Self::Normal(n) => n.evaluate_trivial(),
_ => None,
}
}
crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/import.rs
+++ b/crates/jrsonnet-evaluator/src/import.rs
@@ -10,7 +10,7 @@
use fs::File;
use jrsonnet_gcmodule::Trace;
use jrsonnet_interner::IBytes;
-use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath, SourceFifo};
+use jrsonnet_parser::{SourceDirectory, SourceFifo, SourceFile, SourcePath};
use crate::{
bail,
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -15,7 +15,7 @@
};
impl<'de> Deserialize<'de> for Val {
- fn deserialize<D>(deserializer: D) -> Result<Val, D::Error>
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
@@ -155,10 +155,10 @@
S: serde::Serializer,
{
match self {
- Val::Bool(v) => serializer.serialize_bool(*v),
- Val::Null => serializer.serialize_none(),
- Val::Str(s) => serializer.serialize_str(&s.clone().into_flat()),
- Val::Num(n) => {
+ Self::Bool(v) => serializer.serialize_bool(*v),
+ Self::Null => serializer.serialize_none(),
+ Self::Str(s) => serializer.serialize_str(&s.clone().into_flat()),
+ Self::Num(n) => {
if n.fract() == 0.0 {
let n = *n as i64;
serializer.serialize_i64(n)
@@ -167,8 +167,8 @@
}
}
#[cfg(feature = "exp-bigint")]
- Val::BigInt(b) => b.serialize(serializer),
- Val::Arr(arr) => {
+ Self::BigInt(b) => b.serialize(serializer),
+ Self::Arr(arr) => {
let mut seq = serializer.serialize_seq(Some(arr.len()))?;
for (i, element) in arr.iter().enumerate() {
let mut serde_error = None;
@@ -190,7 +190,7 @@
}
seq.end()
}
- Val::Obj(obj) => {
+ Self::Obj(obj) => {
let mut map = serializer.serialize_map(Some(obj.len()))?;
for (field, value) in obj.iter(
#[cfg(feature = "exp-preserve-order")]
@@ -215,7 +215,7 @@
}
map.end()
}
- Val::Func(_) => Err(S::Error::custom("tried to manifest function")),
+ Self::Func(_) => Err(S::Error::custom("tried to manifest function")),
}
}
}
@@ -248,9 +248,9 @@
type Ok = Val;
type Error = JrError;
- fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where
- T: Serialize,
+ T: ?Sized + Serialize,
{
let value = value.serialize(IntoValSerializer)?;
self.data.push(value);
@@ -272,9 +272,9 @@
type Ok = Val;
type Error = JrError;
- fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where
- T: Serialize,
+ T: ?Sized + Serialize,
{
SerializeSeq::serialize_element(self, value)
}
@@ -287,9 +287,9 @@
type Ok = Val;
type Error = JrError;
- fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
where
- T: Serialize,
+ T: ?Sized + Serialize,
{
SerializeSeq::serialize_element(self, value)
}
@@ -302,9 +302,9 @@
type Ok = Val;
type Error = JrError;
- fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()>
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
where
- T: Serialize,
+ T: ?Sized + Serialize,
{
SerializeSeq::serialize_element(self, value)
}
@@ -607,7 +607,7 @@
}
impl Val {
- pub fn from_serde(v: impl Serialize) -> Result<Val, JrError> {
+ pub fn from_serde(v: impl Serialize) -> Result<Self, JrError> {
v.serialize(IntoValSerializer)
}
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -45,7 +45,7 @@
#[doc(hidden)]
pub use jrsonnet_macros;
pub use jrsonnet_parser as parser;
-use jrsonnet_parser::*;
+use jrsonnet_parser::{ExprLocation, LocExpr, ParserSettings, Source, SourcePath};
pub use obj::*;
use stack::check_depth;
pub use tla::apply_tla;
crates/jrsonnet-evaluator/src/stack.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/stack.rs
+++ b/crates/jrsonnet-evaluator/src/stack.rs
@@ -24,7 +24,7 @@
pub struct StackOverflowError;
impl From<StackOverflowError> for ErrorKind {
fn from(_: StackOverflowError) -> Self {
- ErrorKind::StackOverflow
+ Self::StackOverflow
}
}
impl From<StackOverflowError> for Error {
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -358,7 +358,7 @@
};
a.iter()
.map(|r| r.and_then(T::from_untyped))
- .collect::<Result<Vec<T>>>()
+ .collect::<Result<Self>>()
}
}
@@ -381,7 +381,7 @@
Self::TYPE.check(&value)?;
let obj = value.as_obj().expect("typecheck should fail");
- let mut out = BTreeMap::new();
+ let mut out = Self::new();
if V::wants_lazy() {
for key in obj.fields_ex(
false,
@@ -623,8 +623,8 @@
fn into_untyped(value: Self) -> Result<Val> {
match value {
- IndexableVal::Str(s) => Ok(Val::string(s)),
- IndexableVal::Arr(a) => Ok(Val::Arr(a)),
+ Self::Str(s) => Ok(Val::string(s)),
+ Self::Arr(a) => Ok(Val::Arr(a)),
}
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -147,7 +147,7 @@
T: ThunkValue<Output = V>,
{
fn from(value: T) -> Self {
- Thunk::new(value)
+ Self::new(value)
}
}
@@ -221,8 +221,8 @@
impl IndexableVal {
pub fn to_array(self) -> ArrValue {
match self {
- IndexableVal::Str(s) => ArrValue::chars(s.chars()),
- IndexableVal::Arr(arr) => arr,
+ Self::Str(s) => ArrValue::chars(s.chars()),
+ Self::Arr(arr) => arr,
}
}
/// Slice the value.
@@ -239,7 +239,7 @@
step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
) -> Result<Self> {
match &self {
- IndexableVal::Str(s) => {
+ Self::Str(s) => {
let mut computed_len = None;
let mut get_len = || {
computed_len.map_or_else(
@@ -277,7 +277,7 @@
.into(),
))
}
- IndexableVal::Arr(arr) => {
+ Self::Arr(arr) => {
let get_idx = |pos: Option<i32>, len: usize, default| match pos {
Some(v) if v < 0 => len.saturating_sub((-v) as usize),
Some(v) => (v as usize).min(len),
@@ -307,7 +307,7 @@
Tree(Rc<(StrValue, StrValue, usize)>),
}
impl StrValue {
- pub fn concat(a: StrValue, b: StrValue) -> Self {
+ pub fn concat(a: Self, b: Self) -> Self {
// TODO: benchmark for an optimal value, currently just a arbitrary choice
const STRING_EXTEND_THRESHOLD: usize = 100;
@@ -334,8 +334,8 @@
}
}
match self {
- StrValue::Flat(f) => f,
- StrValue::Tree(_) => {
+ Self::Flat(f) => f,
+ Self::Tree(_) => {
let mut buf = String::with_capacity(self.len());
write_buf(&self, &mut buf);
buf.into()
@@ -344,8 +344,8 @@
}
pub fn len(&self) -> usize {
match self {
- StrValue::Flat(v) => v.len(),
- StrValue::Tree(t) => t.2,
+ Self::Flat(v) => v.len(),
+ Self::Tree(t) => t.2,
}
}
pub fn is_empty(&self) -> bool {
@@ -367,8 +367,8 @@
impl Display for StrValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- StrValue::Flat(v) => write!(f, "{v}"),
- StrValue::Tree(t) => {
+ Self::Flat(v) => write!(f, "{v}"),
+ Self::Tree(t) => {
write!(f, "{}", t.0)?;
write!(f, "{}", t.1)
}
@@ -522,8 +522,8 @@
pub fn into_indexable(self) -> Result<IndexableVal> {
Ok(match self {
- Val::Str(s) => IndexableVal::Str(s.into_flat()),
- Val::Arr(arr) => IndexableVal::Arr(arr),
+ Self::Str(s) => IndexableVal::Str(s.into_flat()),
+ Self::Arr(arr) => IndexableVal::Arr(arr),
_ => bail!(ValueIsNotIndexable(self.value_type())),
})
}
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -1,3 +1,5 @@
+use std::string::String;
+
use proc_macro2::TokenStream;
use quote::quote;
use syn::{
@@ -205,6 +207,7 @@
}
}
+#[allow(clippy::too_many_lines)]
fn builtin_inner(
attr: BuiltinAttrs,
fun: ItemFn,
@@ -225,7 +228,7 @@
.map(|arg| ArgInfo::parse(&name, arg))
.collect::<Result<Vec<_>>>()?;
- let params_desc = args.iter().flat_map(|a| match a {
+ let params_desc = args.iter().filter_map(|a| match a {
ArgInfo::Normal {
is_option,
name,
@@ -234,8 +237,7 @@
} => {
let name = name
.as_ref()
- .map(|n| quote! {ParamName::new_static(#n)})
- .unwrap_or_else(|| quote! {None});
+ .map_or_else(|| quote! {None}, |n| quote! {ParamName::new_static(#n)});
Some(quote! {
#(#cfg_attrs)*
BuiltinParam::new(#name, #is_option),
@@ -244,15 +246,12 @@
ArgInfo::Lazy { is_option, name } => {
let name = name
.as_ref()
- .map(|n| quote! {ParamName::new_static(#n)})
- .unwrap_or_else(|| quote! {None});
+ .map_or_else(|| quote! {None}, |n| quote! {ParamName::new_static(#n)});
Some(quote! {
BuiltinParam::new(#name, #is_option),
})
}
- ArgInfo::Context => None,
- ArgInfo::Location => None,
- ArgInfo::This => None,
+ ArgInfo::Context | ArgInfo::Location | ArgInfo::This => None,
});
let mut id = 0usize;
@@ -275,7 +274,7 @@
name,
cfg_attrs,
} => {
- let name = name.as_ref().map(|v| v.as_str()).unwrap_or("<unnamed>");
+ let name = name.as_ref().map_or("<unnamed>", String::as_str);
let eval = quote! {jrsonnet_evaluator::State::push_description(
|| format!("argument <{}> evaluation", #name),
|| <#ty>::from_untyped(value.evaluate()?),
@@ -390,6 +389,7 @@
}
#[derive(Default)]
+#[allow(clippy::struct_excessive_bools)]
struct TypedAttr {
rename: Option<String>,
flatten: bool,
@@ -467,11 +467,8 @@
"this field should appear in output object, but it has no visible name",
));
};
- let (is_option, ty) = if let Some(ty) = extract_type_from_option(&field.ty)? {
- (true, ty.clone())
- } else {
- (false, field.ty.clone())
- };
+ let (is_option, ty) = extract_type_from_option(&field.ty)?
+ .map_or_else(|| (false, field.ty.clone()), |ty| (true, ty.clone()));
if is_option && attr.flatten {
if !attr.flatten_ok {
return Err(Error::new(
@@ -551,48 +548,53 @@
#ident: #value,
}
}
- fn expand_serialize(&self) -> Result<TokenStream> {
+ fn expand_serialize(&self) -> TokenStream {
let ident = &self.ident;
let ty = &self.ty;
- Ok(if let Some(name) = self.name() {
- let hide = if self.attr.hide {
- quote! {.hide()}
- } else {
- quote! {}
- };
- let add = if self.attr.add {
- quote! {.add()}
- } else {
- quote! {}
- };
- if self.is_option {
- quote! {
- if let Some(value) = self.#ident {
+ self.name().map_or_else(
+ || {
+ if self.is_option {
+ quote! {
+ if let Some(value) = self.#ident {
+ <#ty as TypedObj>::serialize(value, out)?;
+ }
+ }
+ } else {
+ quote! {
+ <#ty as TypedObj>::serialize(self.#ident, out)?;
+ }
+ }
+ },
+ |name| {
+ let hide = if self.attr.hide {
+ quote! {.hide()}
+ } else {
+ quote! {}
+ };
+ let add = if self.attr.add {
+ quote! {.add()}
+ } else {
+ quote! {}
+ };
+ if self.is_option {
+ quote! {
+ if let Some(value) = self.#ident {
+ out.field(#name)
+ #hide
+ #add
+ .try_value(<#ty as Typed>::into_untyped(value)?)?;
+ }
+ }
+ } else {
+ quote! {
out.field(#name)
#hide
#add
- .try_value(<#ty as Typed>::into_untyped(value)?)?;
+ .try_value(<#ty as Typed>::into_untyped(self.#ident)?)?;
}
}
- } else {
- quote! {
- out.field(#name)
- #hide
- #add
- .try_value(<#ty as Typed>::into_untyped(self.#ident)?)?;
- }
- }
- } else if self.is_option {
- quote! {
- if let Some(value) = self.#ident {
- <#ty as TypedObj>::serialize(value, out)?;
- }
- }
- } else {
- quote! {
- <#ty as TypedObj>::serialize(self.#ident, out)?;
- }
- })
+ },
+ )
}
}
@@ -623,7 +625,7 @@
let typed = {
let fields = fields
.iter()
- .flat_map(TypedField::expand_field)
+ .filter_map(TypedField::expand_field)
.collect::<Vec<_>>();
quote! {
impl #impl_generics Typed for #ident #ty_generics #where_clause {
@@ -650,7 +652,7 @@
let fields_serialize = fields
.iter()
.map(TypedField::expand_serialize)
- .collect::<Result<Vec<_>>>()?;
+ .collect::<Vec<_>>();
Ok(quote! {
const _: () = {
@@ -767,7 +769,7 @@
}
}
-/// IStr formatting helper
+/// `IStr` formatting helper
///
/// Using `format!("literal with no codes").into()` is slower than just `"literal with no codes".into()`
/// This macro looks for formatting codes in the input string, and uses
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/parser.rs
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -758,10 +758,10 @@
} else if p.at(T![...]) {
// let m_err = p.start_ranger();
destruct_rest(p);
- // if had_rest {
- // p.custom_error(m_err.finish(p), "only one rest can be present in array");
- // }
- // had_rest = true;
+ // if had_rest {
+ // p.custom_error(m_err.finish(p), "only one rest can be present in array");
+ // }
+ // had_rest = true;
} else {
destruct(p);
}
crates/jrsonnet-stdlib/build.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/build.rs
+++ b/crates/jrsonnet-stdlib/build.rs
@@ -26,7 +26,9 @@
let dest_path = Path::new(&out_dir).join("stdlib.rs");
let mut f = File::create(dest_path).unwrap();
f.write_all(
- ("#[allow(clippy::redundant_clone)]".to_owned() + &v.to_string()).as_bytes(),
+ ("#[allow(clippy::redundant_clone, clippy::similar_names)]".to_owned()
+ + &v.to_string())
+ .as_bytes(),
)
.unwrap();
}
crates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -9,7 +9,7 @@
Either, IStr, ObjValueBuilder, Result, ResultExt, Thunk, Val,
};
-pub(crate) fn eval_on_empty(on_empty: Option<Thunk<Val>>) -> Result<Val> {
+pub fn eval_on_empty(on_empty: Option<Thunk<Val>>) -> Result<Val> {
if let Some(on_empty) = on_empty {
on_empty.evaluate()
} else {
@@ -270,8 +270,8 @@
let newArrRight = arr.slice(Some(at + 1), None, None);
Ok(ArrValue::extended(
- newArrLeft.unwrap_or(ArrValue::empty()),
- newArrRight.unwrap_or(ArrValue::empty()),
+ newArrLeft.unwrap_or_else(ArrValue::empty),
+ newArrRight.unwrap_or_else(ArrValue::empty),
))
}
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth1use std::{2 cell::{Ref, RefCell, RefMut},3 collections::HashMap,4 rc::Rc,5};67use jrsonnet_evaluator::{8 error::{ErrorKind::*, Result},9 function::{CallLocation, FuncVal, TlaArg},10 tb,11 trace::PathResolver,12 ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val,13};14use jrsonnet_gcmodule::Trace;15use jrsonnet_parser::Source;1617mod expr;18mod types;19pub use types::*;20mod arrays;21pub use arrays::*;22mod math;23pub use math::*;24mod operator;25pub use operator::*;26mod sort;27pub use sort::*;28mod hash;29pub use hash::*;30mod encoding;31pub use encoding::*;32mod objects;33pub use objects::*;34mod manifest;35pub use manifest::*;36mod parse;37pub use parse::*;38mod strings;39pub use strings::*;40mod misc;41pub use misc::*;42mod sets;43pub use sets::*;44mod compat;45pub use compat::*;46#[cfg(feature = "exp-regex")]47mod regex;48#[cfg(feature = "exp-regex")]49pub use crate::regex::*;5051#[allow(clippy::too_many_lines)]52pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {53 let mut builder = ObjValueBuilder::new();5455 let expr = expr::stdlib_expr();56 let eval = jrsonnet_evaluator::evaluate(ContextBuilder::dangerous_empty_state().build(), &expr)57 .expect("stdlib.jsonnet should have no errors")58 .as_obj()59 .expect("stdlib.jsonnet should evaluate to object");6061 builder.with_super(eval);6263 // FIXME: Use PHF64 for (name, builtin) in [65 // Types66 ("type", builtin_type::INST),67 ("isString", builtin_is_string::INST),68 ("isNumber", builtin_is_number::INST),69 ("isBoolean", builtin_is_boolean::INST),70 ("isObject", builtin_is_object::INST),71 ("isArray", builtin_is_array::INST),72 ("isFunction", builtin_is_function::INST),73 // Arrays74 ("makeArray", builtin_make_array::INST),75 ("repeat", builtin_repeat::INST),76 ("slice", builtin_slice::INST),77 ("map", builtin_map::INST),78 ("flatMap", builtin_flatmap::INST),79 ("filter", builtin_filter::INST),80 ("foldl", builtin_foldl::INST),81 ("foldr", builtin_foldr::INST),82 ("range", builtin_range::INST),83 ("join", builtin_join::INST),84 ("reverse", builtin_reverse::INST),85 ("any", builtin_any::INST),86 ("all", builtin_all::INST),87 ("member", builtin_member::INST),88 ("contains", builtin_contains::INST),89 ("count", builtin_count::INST),90 ("avg", builtin_avg::INST),91 ("removeAt", builtin_remove_at::INST),92 ("remove", builtin_remove::INST),93 ("flattenArrays", builtin_flatten_arrays::INST),94 ("flattenDeepArray", builtin_flatten_deep_array::INST),95 ("prune", builtin_prune::INST),96 ("filterMap", builtin_filter_map::INST),97 // Math98 ("abs", builtin_abs::INST),99 ("sign", builtin_sign::INST),100 ("max", builtin_max::INST),101 ("min", builtin_min::INST),102 ("sum", builtin_sum::INST),103 ("modulo", builtin_modulo::INST),104 ("floor", builtin_floor::INST),105 ("ceil", builtin_ceil::INST),106 ("log", builtin_log::INST),107 ("pow", builtin_pow::INST),108 ("sqrt", builtin_sqrt::INST),109 ("sin", builtin_sin::INST),110 ("cos", builtin_cos::INST),111 ("tan", builtin_tan::INST),112 ("asin", builtin_asin::INST),113 ("acos", builtin_acos::INST),114 ("atan", builtin_atan::INST),115 ("atan2", builtin_atan2::INST),116 ("exp", builtin_exp::INST),117 ("mantissa", builtin_mantissa::INST),118 ("exponent", builtin_exponent::INST),119 ("round", builtin_round::INST),120 ("isEven", builtin_is_even::INST),121 ("isOdd", builtin_is_odd::INST),122 ("isInteger", builtin_is_integer::INST),123 ("isDecimal", builtin_is_decimal::INST),124 // Operator125 ("mod", builtin_mod::INST),126 ("primitiveEquals", builtin_primitive_equals::INST),127 ("equals", builtin_equals::INST),128 ("xor", builtin_xor::INST),129 ("xnor", builtin_xnor::INST),130 ("format", builtin_format::INST),131 // Sort132 ("sort", builtin_sort::INST),133 ("uniq", builtin_uniq::INST),134 ("set", builtin_set::INST),135 ("minArray", builtin_min_array::INST),136 ("maxArray", builtin_max_array::INST),137 // Hash138 ("md5", builtin_md5::INST),139 ("sha1", builtin_sha1::INST),140 ("sha256", builtin_sha256::INST),141 ("sha512", builtin_sha512::INST),142 ("sha3", builtin_sha3::INST),143 // Encoding144 ("encodeUTF8", builtin_encode_utf8::INST),145 ("decodeUTF8", builtin_decode_utf8::INST),146 ("base64", builtin_base64::INST),147 ("base64Decode", builtin_base64_decode::INST),148 ("base64DecodeBytes", builtin_base64_decode_bytes::INST),149 // Objects150 ("objectFieldsEx", builtin_object_fields_ex::INST),151 ("objectFields", builtin_object_fields::INST),152 ("objectFieldsAll", builtin_object_fields_all::INST),153 ("objectValues", builtin_object_values::INST),154 ("objectValuesAll", builtin_object_values_all::INST),155 ("objectKeysValues", builtin_object_keys_values::INST),156 ("objectKeysValuesAll", builtin_object_keys_values_all::INST),157 ("objectHasEx", builtin_object_has_ex::INST),158 ("objectHas", builtin_object_has::INST),159 ("objectHasAll", builtin_object_has_all::INST),160 ("objectRemoveKey", builtin_object_remove_key::INST),161 // Manifest162 ("escapeStringJson", builtin_escape_string_json::INST),163 ("manifestJsonEx", builtin_manifest_json_ex::INST),164 ("manifestYamlDoc", builtin_manifest_yaml_doc::INST),165 ("manifestTomlEx", builtin_manifest_toml_ex::INST),166 ("toString", builtin_to_string::INST),167 // Parsing168 ("parseJson", builtin_parse_json::INST),169 ("parseYaml", builtin_parse_yaml::INST),170 // Strings171 ("codepoint", builtin_codepoint::INST),172 ("substr", builtin_substr::INST),173 ("char", builtin_char::INST),174 ("strReplace", builtin_str_replace::INST),175 ("isEmpty", builtin_is_empty::INST),176 ("equalsIgnoreCase", builtin_equals_ignore_case::INST),177 ("splitLimit", builtin_splitlimit::INST),178 ("asciiUpper", builtin_ascii_upper::INST),179 ("asciiLower", builtin_ascii_lower::INST),180 ("findSubstr", builtin_find_substr::INST),181 ("parseInt", builtin_parse_int::INST),182 #[cfg(feature = "exp-bigint")]183 ("bigint", builtin_bigint::INST),184 ("parseOctal", builtin_parse_octal::INST),185 ("parseHex", builtin_parse_hex::INST),186 ("stringChars", builtin_string_chars::INST),187 // Misc188 ("length", builtin_length::INST),189 ("startsWith", builtin_starts_with::INST),190 ("endsWith", builtin_ends_with::INST),191 // Sets192 ("setMember", builtin_set_member::INST),193 ("setInter", builtin_set_inter::INST),194 ("setDiff", builtin_set_diff::INST),195 ("setUnion", builtin_set_union::INST),196 // Regex197 #[cfg(feature = "exp-regex")]198 ("regexQuoteMeta", builtin_regex_quote_meta::INST),199 // Compat200 ("__compare", builtin___compare::INST),201 ]202 .iter()203 .copied()204 {205 builder.method(name, builtin);206 }207208 builder.method(209 "extVar",210 builtin_ext_var {211 settings: settings.clone(),212 },213 );214 builder.method(215 "native",216 builtin_native {217 settings: settings.clone(),218 },219 );220 builder.method("trace", builtin_trace { settings });221 builder.method("id", FuncVal::Id);222223 #[cfg(feature = "exp-regex")]224 {225 // Regex226 let regex_cache = RegexCache::default();227 builder.method(228 "regexFullMatch",229 builtin_regex_full_match {230 cache: regex_cache.clone(),231 },232 );233 builder.method(234 "regexPartialMatch",235 builtin_regex_partial_match {236 cache: regex_cache.clone(),237 },238 );239 builder.method(240 "regexReplace",241 builtin_regex_replace {242 cache: regex_cache.clone(),243 },244 );245 builder.method(246 "regexGlobalReplace",247 builtin_regex_global_replace {248 cache: regex_cache.clone(),249 },250 );251 };252253 builder.build()254}255256pub trait TracePrinter {257 fn print_trace(&self, loc: CallLocation, value: IStr);258}259260pub struct StdTracePrinter {261 resolver: PathResolver,262}263impl StdTracePrinter {264 pub fn new(resolver: PathResolver) -> Self {265 Self { resolver }266 }267}268impl TracePrinter for StdTracePrinter {269 fn print_trace(&self, loc: CallLocation, value: IStr) {270 eprint!("TRACE:");271 if let Some(loc) = loc.0 {272 let locs = loc.0.map_source_locations(&[loc.1]);273 eprint!(274 " {}:{}",275 loc.0.source_path().path().map_or_else(276 || loc.0.source_path().to_string(),277 |p| self.resolver.resolve(p)278 ),279 locs[0].line280 );281 }282 eprintln!(" {value}");283 }284}285286pub struct Settings {287 /// Used for `std.extVar`288 pub ext_vars: HashMap<IStr, TlaArg>,289 /// Used for `std.native`290 pub ext_natives: HashMap<IStr, FuncVal>,291 /// Used for `std.trace`292 pub trace_printer: Box<dyn TracePrinter>,293 /// Used for `std.thisFile`294 pub path_resolver: PathResolver,295}296297fn extvar_source(name: &str, code: impl Into<IStr>) -> Source {298 let source_name = format!("<extvar:{name}>");299 Source::new_virtual(source_name.into(), code.into())300}301302#[derive(Trace, Clone)]303pub struct ContextInitializer {304 /// When we don't need to support legacy-this-file, we can reuse same context for all files305 #[cfg(not(feature = "legacy-this-file"))]306 context: jrsonnet_evaluator::Context,307 /// For `populate`308 #[cfg(not(feature = "legacy-this-file"))]309 stdlib_thunk: Thunk<Val>,310 /// Otherwise, we can only keep first stdlib layer, and then stack thisFile on top of it311 #[cfg(feature = "legacy-this-file")]312 stdlib_obj: ObjValue,313 settings: Rc<RefCell<Settings>>,314}315impl ContextInitializer {316 pub fn new(_s: State, resolver: PathResolver) -> Self {317 let settings = Settings {318 ext_vars: Default::default(),319 ext_natives: Default::default(),320 trace_printer: Box::new(StdTracePrinter::new(resolver.clone())),321 path_resolver: resolver,322 };323 let settings = Rc::new(RefCell::new(settings));324 let stdlib_obj = stdlib_uncached(settings.clone());325 #[cfg(not(feature = "legacy-this-file"))]326 let stdlib_thunk = Thunk::evaluated(Val::Obj(stdlib_obj));327 Self {328 #[cfg(not(feature = "legacy-this-file"))]329 context: {330 let mut context = ContextBuilder::with_capacity(_s, 1);331 context.bind("std", stdlib_thunk.clone());332 context.build()333 },334 #[cfg(not(feature = "legacy-this-file"))]335 stdlib_thunk,336 #[cfg(feature = "legacy-this-file")]337 stdlib_obj,338 settings,339 }340 }341 pub fn settings(&self) -> Ref<Settings> {342 self.settings.borrow()343 }344 pub fn settings_mut(&self) -> RefMut<Settings> {345 self.settings.borrow_mut()346 }347 pub fn add_ext_var(&self, name: IStr, value: Val) {348 self.settings_mut()349 .ext_vars350 .insert(name, TlaArg::Val(value));351 }352 pub fn add_ext_str(&self, name: IStr, value: IStr) {353 self.settings_mut()354 .ext_vars355 .insert(name, TlaArg::String(value));356 }357 pub fn add_ext_code(&self, name: &str, code: impl Into<IStr>) -> Result<()> {358 let code = code.into();359 let source = extvar_source(name, code.clone());360 let parsed = jrsonnet_parser::parse(361 &code,362 &jrsonnet_parser::ParserSettings {363 source: source.clone(),364 },365 )366 .map_err(|e| ImportSyntaxError {367 path: source,368 error: Box::new(e),369 })?;370 // self.data_mut().volatile_files.insert(source_name, code);371 self.settings_mut()372 .ext_vars373 .insert(name.into(), TlaArg::Code(parsed));374 Ok(())375 }376 pub fn add_native(&self, name: impl Into<IStr>, cb: impl Into<FuncVal>) {377 self.settings_mut()378 .ext_natives379 .insert(name.into(), cb.into());380 }381}382impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {383 fn reserve_vars(&self) -> usize {384 1385 }386 #[cfg(not(feature = "legacy-this-file"))]387 fn initialize(&self, _s: State, _source: Source) -> jrsonnet_evaluator::Context {388 self.context.clone()389 }390 #[cfg(not(feature = "legacy-this-file"))]391 fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {392 builder.bind("std", self.stdlib_thunk.clone());393 }394 #[cfg(feature = "legacy-this-file")]395 fn populate(&self, source: Source, builder: &mut ContextBuilder) {396 use jrsonnet_evaluator::val::StrValue;397398 let mut std = ObjValueBuilder::new();399 std.with_super(self.stdlib_obj.clone());400 std.field("thisFile")401 .hide()402 .value(match source.source_path().path() {403 Some(p) => self.settings().path_resolver.resolve(p),404 None => source.source_path().to_string(),405 });406 let stdlib_with_this_file = std.build();407408 builder.bind("std", Thunk::evaluated(Val::Obj(stdlib_with_this_file)));409 }410 fn as_any(&self) -> &dyn std::any::Any {411 self412 }413}414415pub trait StateExt {416 /// This method was previously implemented in jrsonnet-evaluator itself417 fn with_stdlib(&self);418}419420impl StateExt for State {421 fn with_stdlib(&self) {422 let initializer = ContextInitializer::new(self.clone(), PathResolver::new_cwd_fallback());423 self.settings_mut().context_initializer = tb!(initializer);424 }425}1use std::{2 cell::{Ref, RefCell, RefMut},3 collections::HashMap,4 rc::Rc,5};67use jrsonnet_evaluator::{8 error::{ErrorKind::*, Result},9 function::{CallLocation, FuncVal, TlaArg},10 tb,11 trace::PathResolver,12 ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val,13};14use jrsonnet_gcmodule::Trace;15use jrsonnet_parser::Source;1617mod expr;18mod types;19pub use types::*;20mod arrays;21pub use arrays::*;22mod math;23pub use math::*;24mod operator;25pub use operator::*;26mod sort;27pub use sort::*;28mod hash;29pub use hash::*;30mod encoding;31pub use encoding::*;32mod objects;33pub use objects::*;34mod manifest;35pub use manifest::*;36mod parse;37pub use parse::*;38mod strings;39pub use strings::*;40mod misc;41pub use misc::*;42mod sets;43pub use sets::*;44mod compat;45pub use compat::*;46#[cfg(feature = "exp-regex")]47mod regex;48#[cfg(feature = "exp-regex")]49pub use crate::regex::*;5051#[allow(clippy::too_many_lines)]52pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {53 let mut builder = ObjValueBuilder::new();5455 let expr = expr::stdlib_expr();56 let eval = jrsonnet_evaluator::evaluate(ContextBuilder::dangerous_empty_state().build(), &expr)57 .expect("stdlib.jsonnet should have no errors")58 .as_obj()59 .expect("stdlib.jsonnet should evaluate to object");6061 builder.with_super(eval);6263 // FIXME: Use PHF64 for (name, builtin) in [65 // Types66 ("type", builtin_type::INST),67 ("isString", builtin_is_string::INST),68 ("isNumber", builtin_is_number::INST),69 ("isBoolean", builtin_is_boolean::INST),70 ("isObject", builtin_is_object::INST),71 ("isArray", builtin_is_array::INST),72 ("isFunction", builtin_is_function::INST),73 // Arrays74 ("makeArray", builtin_make_array::INST),75 ("repeat", builtin_repeat::INST),76 ("slice", builtin_slice::INST),77 ("map", builtin_map::INST),78 ("flatMap", builtin_flatmap::INST),79 ("filter", builtin_filter::INST),80 ("foldl", builtin_foldl::INST),81 ("foldr", builtin_foldr::INST),82 ("range", builtin_range::INST),83 ("join", builtin_join::INST),84 ("reverse", builtin_reverse::INST),85 ("any", builtin_any::INST),86 ("all", builtin_all::INST),87 ("member", builtin_member::INST),88 ("contains", builtin_contains::INST),89 ("count", builtin_count::INST),90 ("avg", builtin_avg::INST),91 ("removeAt", builtin_remove_at::INST),92 ("remove", builtin_remove::INST),93 ("flattenArrays", builtin_flatten_arrays::INST),94 ("flattenDeepArray", builtin_flatten_deep_array::INST),95 ("prune", builtin_prune::INST),96 ("filterMap", builtin_filter_map::INST),97 // Math98 ("abs", builtin_abs::INST),99 ("sign", builtin_sign::INST),100 ("max", builtin_max::INST),101 ("min", builtin_min::INST),102 ("sum", builtin_sum::INST),103 ("modulo", builtin_modulo::INST),104 ("floor", builtin_floor::INST),105 ("ceil", builtin_ceil::INST),106 ("log", builtin_log::INST),107 ("pow", builtin_pow::INST),108 ("sqrt", builtin_sqrt::INST),109 ("sin", builtin_sin::INST),110 ("cos", builtin_cos::INST),111 ("tan", builtin_tan::INST),112 ("asin", builtin_asin::INST),113 ("acos", builtin_acos::INST),114 ("atan", builtin_atan::INST),115 ("atan2", builtin_atan2::INST),116 ("exp", builtin_exp::INST),117 ("mantissa", builtin_mantissa::INST),118 ("exponent", builtin_exponent::INST),119 ("round", builtin_round::INST),120 ("isEven", builtin_is_even::INST),121 ("isOdd", builtin_is_odd::INST),122 ("isInteger", builtin_is_integer::INST),123 ("isDecimal", builtin_is_decimal::INST),124 // Operator125 ("mod", builtin_mod::INST),126 ("primitiveEquals", builtin_primitive_equals::INST),127 ("equals", builtin_equals::INST),128 ("xor", builtin_xor::INST),129 ("xnor", builtin_xnor::INST),130 ("format", builtin_format::INST),131 // Sort132 ("sort", builtin_sort::INST),133 ("uniq", builtin_uniq::INST),134 ("set", builtin_set::INST),135 ("minArray", builtin_min_array::INST),136 ("maxArray", builtin_max_array::INST),137 // Hash138 ("md5", builtin_md5::INST),139 ("sha1", builtin_sha1::INST),140 ("sha256", builtin_sha256::INST),141 ("sha512", builtin_sha512::INST),142 ("sha3", builtin_sha3::INST),143 // Encoding144 ("encodeUTF8", builtin_encode_utf8::INST),145 ("decodeUTF8", builtin_decode_utf8::INST),146 ("base64", builtin_base64::INST),147 ("base64Decode", builtin_base64_decode::INST),148 ("base64DecodeBytes", builtin_base64_decode_bytes::INST),149 // Objects150 ("objectFieldsEx", builtin_object_fields_ex::INST),151 ("objectFields", builtin_object_fields::INST),152 ("objectFieldsAll", builtin_object_fields_all::INST),153 ("objectValues", builtin_object_values::INST),154 ("objectValuesAll", builtin_object_values_all::INST),155 ("objectKeysValues", builtin_object_keys_values::INST),156 ("objectKeysValuesAll", builtin_object_keys_values_all::INST),157 ("objectHasEx", builtin_object_has_ex::INST),158 ("objectHas", builtin_object_has::INST),159 ("objectHasAll", builtin_object_has_all::INST),160 ("objectRemoveKey", builtin_object_remove_key::INST),161 // Manifest162 ("escapeStringJson", builtin_escape_string_json::INST),163 ("manifestJsonEx", builtin_manifest_json_ex::INST),164 ("manifestYamlDoc", builtin_manifest_yaml_doc::INST),165 ("manifestTomlEx", builtin_manifest_toml_ex::INST),166 ("toString", builtin_to_string::INST),167 // Parsing168 ("parseJson", builtin_parse_json::INST),169 ("parseYaml", builtin_parse_yaml::INST),170 // Strings171 ("codepoint", builtin_codepoint::INST),172 ("substr", builtin_substr::INST),173 ("char", builtin_char::INST),174 ("strReplace", builtin_str_replace::INST),175 ("isEmpty", builtin_is_empty::INST),176 ("equalsIgnoreCase", builtin_equals_ignore_case::INST),177 ("splitLimit", builtin_splitlimit::INST),178 ("asciiUpper", builtin_ascii_upper::INST),179 ("asciiLower", builtin_ascii_lower::INST),180 ("findSubstr", builtin_find_substr::INST),181 ("parseInt", builtin_parse_int::INST),182 #[cfg(feature = "exp-bigint")]183 ("bigint", builtin_bigint::INST),184 ("parseOctal", builtin_parse_octal::INST),185 ("parseHex", builtin_parse_hex::INST),186 ("stringChars", builtin_string_chars::INST),187 // Misc188 ("length", builtin_length::INST),189 ("startsWith", builtin_starts_with::INST),190 ("endsWith", builtin_ends_with::INST),191 // Sets192 ("setMember", builtin_set_member::INST),193 ("setInter", builtin_set_inter::INST),194 ("setDiff", builtin_set_diff::INST),195 ("setUnion", builtin_set_union::INST),196 // Regex197 #[cfg(feature = "exp-regex")]198 ("regexQuoteMeta", builtin_regex_quote_meta::INST),199 // Compat200 ("__compare", builtin___compare::INST),201 ]202 .iter()203 .copied()204 {205 builder.method(name, builtin);206 }207208 builder.method(209 "extVar",210 builtin_ext_var {211 settings: settings.clone(),212 },213 );214 builder.method(215 "native",216 builtin_native {217 settings: settings.clone(),218 },219 );220 builder.method("trace", builtin_trace { settings });221 builder.method("id", FuncVal::Id);222223 #[cfg(feature = "exp-regex")]224 {225 // Regex226 let regex_cache = RegexCache::default();227 builder.method(228 "regexFullMatch",229 builtin_regex_full_match {230 cache: regex_cache.clone(),231 },232 );233 builder.method(234 "regexPartialMatch",235 builtin_regex_partial_match {236 cache: regex_cache.clone(),237 },238 );239 builder.method(240 "regexReplace",241 builtin_regex_replace {242 cache: regex_cache.clone(),243 },244 );245 builder.method(246 "regexGlobalReplace",247 builtin_regex_global_replace {248 cache: regex_cache.clone(),249 },250 );251 };252253 builder.build()254}255256pub trait TracePrinter {257 fn print_trace(&self, loc: CallLocation, value: IStr);258}259260pub struct StdTracePrinter {261 resolver: PathResolver,262}263impl StdTracePrinter {264 pub fn new(resolver: PathResolver) -> Self {265 Self { resolver }266 }267}268impl TracePrinter for StdTracePrinter {269 fn print_trace(&self, loc: CallLocation, value: IStr) {270 eprint!("TRACE:");271 if let Some(loc) = loc.0 {272 let locs = loc.0.map_source_locations(&[loc.1]);273 eprint!(274 " {}:{}",275 loc.0.source_path().path().map_or_else(276 || loc.0.source_path().to_string(),277 |p| self.resolver.resolve(p)278 ),279 locs[0].line280 );281 }282 eprintln!(" {value}");283 }284}285286pub struct Settings {287 /// Used for `std.extVar`288 pub ext_vars: HashMap<IStr, TlaArg>,289 /// Used for `std.native`290 pub ext_natives: HashMap<IStr, FuncVal>,291 /// Used for `std.trace`292 pub trace_printer: Box<dyn TracePrinter>,293 /// Used for `std.thisFile`294 pub path_resolver: PathResolver,295}296297fn extvar_source(name: &str, code: impl Into<IStr>) -> Source {298 let source_name = format!("<extvar:{name}>");299 Source::new_virtual(source_name.into(), code.into())300}301302#[derive(Trace, Clone)]303pub struct ContextInitializer {304 /// When we don't need to support legacy-this-file, we can reuse same context for all files305 #[cfg(not(feature = "legacy-this-file"))]306 context: jrsonnet_evaluator::Context,307 /// For `populate`308 #[cfg(not(feature = "legacy-this-file"))]309 stdlib_thunk: Thunk<Val>,310 /// Otherwise, we can only keep first stdlib layer, and then stack thisFile on top of it311 #[cfg(feature = "legacy-this-file")]312 stdlib_obj: ObjValue,313 settings: Rc<RefCell<Settings>>,314}315impl ContextInitializer {316 pub fn new(s: State, resolver: PathResolver) -> Self {317 let settings = Settings {318 ext_vars: HashMap::new(),319 ext_natives: HashMap::new(),320 trace_printer: Box::new(StdTracePrinter::new(resolver.clone())),321 path_resolver: resolver,322 };323 let settings = Rc::new(RefCell::new(settings));324 let stdlib_obj = stdlib_uncached(settings.clone());325 #[cfg(not(feature = "legacy-this-file"))]326 let stdlib_thunk = Thunk::evaluated(Val::Obj(stdlib_obj));327 #[cfg(feature = "legacy-this-file")]328 let _ = s;329 Self {330 #[cfg(not(feature = "legacy-this-file"))]331 context: {332 let mut context = ContextBuilder::with_capacity(s, 1);333 context.bind("std", stdlib_thunk.clone());334 context.build()335 },336 #[cfg(not(feature = "legacy-this-file"))]337 stdlib_thunk,338 #[cfg(feature = "legacy-this-file")]339 stdlib_obj,340 settings,341 }342 }343 pub fn settings(&self) -> Ref<Settings> {344 self.settings.borrow()345 }346 pub fn settings_mut(&self) -> RefMut<Settings> {347 self.settings.borrow_mut()348 }349 pub fn add_ext_var(&self, name: IStr, value: Val) {350 self.settings_mut()351 .ext_vars352 .insert(name, TlaArg::Val(value));353 }354 pub fn add_ext_str(&self, name: IStr, value: IStr) {355 self.settings_mut()356 .ext_vars357 .insert(name, TlaArg::String(value));358 }359 pub fn add_ext_code(&self, name: &str, code: impl Into<IStr>) -> Result<()> {360 let code = code.into();361 let source = extvar_source(name, code.clone());362 let parsed = jrsonnet_parser::parse(363 &code,364 &jrsonnet_parser::ParserSettings {365 source: source.clone(),366 },367 )368 .map_err(|e| ImportSyntaxError {369 path: source,370 error: Box::new(e),371 })?;372 // self.data_mut().volatile_files.insert(source_name, code);373 self.settings_mut()374 .ext_vars375 .insert(name.into(), TlaArg::Code(parsed));376 Ok(())377 }378 pub fn add_native(&self, name: impl Into<IStr>, cb: impl Into<FuncVal>) {379 self.settings_mut()380 .ext_natives381 .insert(name.into(), cb.into());382 }383}384impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {385 fn reserve_vars(&self) -> usize {386 1387 }388 #[cfg(not(feature = "legacy-this-file"))]389 fn initialize(&self, _s: State, _source: Source) -> jrsonnet_evaluator::Context {390 self.context.clone()391 }392 #[cfg(not(feature = "legacy-this-file"))]393 fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {394 builder.bind("std", self.stdlib_thunk.clone());395 }396 #[cfg(feature = "legacy-this-file")]397 fn populate(&self, source: Source, builder: &mut ContextBuilder) {398 use jrsonnet_evaluator::val::StrValue;399400 let mut std = ObjValueBuilder::new();401 std.with_super(self.stdlib_obj.clone());402 std.field("thisFile")403 .hide()404 .value(match source.source_path().path() {405 Some(p) => self.settings().path_resolver.resolve(p),406 None => source.source_path().to_string(),407 });408 let stdlib_with_this_file = std.build();409410 builder.bind("std", Thunk::evaluated(Val::Obj(stdlib_with_this_file)));411 }412 fn as_any(&self) -> &dyn std::any::Any {413 self414 }415}416417pub trait StateExt {418 /// This method was previously implemented in jrsonnet-evaluator itself419 fn with_stdlib(&self);420}421422impl StateExt for State {423 fn with_stdlib(&self) {424 let initializer = ContextInitializer::new(self.clone(), PathResolver::new_cwd_fallback());425 self.settings_mut().context_initializer = tb!(initializer);426 }427}crates/jrsonnet-stdlib/src/manifest/toml.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/toml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs
@@ -180,7 +180,9 @@
options.preserve_order,
) {
let value = value?;
- if !is_section(&value)? {
+ if is_section(&value)? {
+ sections.push((key, value));
+ } else {
if !first {
buf.push('\n');
}
@@ -189,8 +191,6 @@
escape_key_toml_buf(&key, buf);
buf.push_str(" = ");
manifest_value(&value, false, buf, cur_padding, options)?;
- } else {
- sections.push((key, value));
}
}
for (k, v) in sections {
crates/jrsonnet-stdlib/src/math.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/math.rs
+++ b/crates/jrsonnet-stdlib/src/math.rs
@@ -131,16 +131,19 @@
}
#[builtin]
+#[allow(clippy::float_cmp)]
pub fn builtin_is_odd(x: f64) -> bool {
builtin_round(x) % 2.0 == 1.0
}
#[builtin]
+#[allow(clippy::float_cmp)]
pub fn builtin_is_integer(x: f64) -> bool {
builtin_round(x) == x
}
#[builtin]
+#[allow(clippy::float_cmp)]
pub fn builtin_is_decimal(x: f64) -> bool {
builtin_round(x) != x
}
crates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -67,11 +67,7 @@
v => v.manifest(JsonFormat::debug())?.into(),
},
);
- if let Some(rest) = rest {
- rest.evaluate()
- } else {
- Ok(str)
- }
+ rest.map_or_else(|| Ok(str), |rest| rest.evaluate())
}
#[allow(clippy::comparison_chain)]
@@ -84,16 +80,15 @@
return Ok(false);
} else if b.len() == a.len() {
return equals(&Val::Arr(a), &Val::Arr(b));
- } else {
- for (a, b) in a.iter().take(b.len()).zip(b.iter()) {
- let a = a?;
- let b = b?;
- if !equals(&a, &b)? {
- return Ok(false);
- }
+ }
+ for (a, b) in a.iter().take(b.len()).zip(b.iter()) {
+ let a = a?;
+ let b = b?;
+ if !equals(&a, &b)? {
+ return Ok(false);
}
- true
}
+ true
}
_ => bail!("both arguments should be of the same type"),
})
@@ -109,17 +104,16 @@
return Ok(false);
} else if b.len() == a.len() {
return equals(&Val::Arr(a), &Val::Arr(b));
- } else {
- let a_len = a.len();
- for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) {
- let a = a?;
- let b = b?;
- if !equals(&a, &b)? {
- return Ok(false);
- }
+ }
+ let a_len = a.len();
+ for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) {
+ let a = a?;
+ let b = b?;
+ if !equals(&a, &b)? {
+ return Ok(false);
}
- true
}
+ true
}
_ => bail!("both arguments should be of the same type"),
})
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -155,7 +155,7 @@
if k == key {
continue;
}
- new_obj.field(k).value(v.unwrap())
+ new_obj.field(k).value(v.unwrap());
}
new_obj.build()
crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -36,7 +36,7 @@
fn get_sort_type<T>(values: &[T], key_getter: impl Fn(&T) -> &Val) -> Result<SortKeyType> {
let mut sort_type = SortKeyType::Unknown;
- for i in values.iter() {
+ for i in values {
let i = key_getter(i);
match (i, sort_type) {
(Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -75,7 +75,7 @@
.enumerate()
{
if &strb[i..i + pat.len()] == pat {
- out.push(Val::Num(ch_idx as f64))
+ out.push(Val::Num(ch_idx as f64));
}
}
out.into()
@@ -117,11 +117,6 @@
}
fn parse_nat<const BASE: u32>(raw: &str) -> Result<f64> {
- debug_assert!(
- 1 <= BASE && BASE <= 16,
- "integer base should be between 1 and 16"
- );
-
const ZERO_CODE: u32 = '0' as u32;
const UPPER_A_CODE: u32 = 'A' as u32;
const LOWER_A_CODE: u32 = 'a' as u32;
@@ -135,10 +130,17 @@
}
}
- let base = BASE as f64;
+ debug_assert!(
+ 1 <= BASE && BASE <= 16,
+ "integer base should be between 1 and 16"
+ );
+
+ let base = f64::from(BASE);
raw.chars().try_fold(0f64, |aggregate, digit| {
let digit = digit as u32;
+ // if-let-else looks better here than Option combinators
+ #[allow(clippy::option_if_let_else)]
let digit = if let Some(digit) = checked_sub_if(BASE > 10, digit, LOWER_A_CODE) {
digit + 10
} else if let Some(digit) = checked_sub_if(BASE > 10, digit, UPPER_A_CODE) {
@@ -148,7 +150,7 @@
};
if digit < BASE {
- Ok(base * aggregate + digit as f64)
+ Ok(base.mul_add(aggregate, f64::from(digit)))
} else {
bail!("{raw:?} is not a base {BASE} integer");
}
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-types/src/lib.rs
+++ b/crates/jrsonnet-types/src/lib.rs
@@ -166,9 +166,9 @@
fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if *a == ComplexValType::Any {
- write!(f, "array")?
+ write!(f, "array")?;
} else {
- write!(f, "Array<{a}>")?
+ write!(f, "Array<{a}>")?;
}
Ok(())
}
@@ -176,18 +176,20 @@
impl Display for ComplexValType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
- ComplexValType::Any => write!(f, "any")?,
- ComplexValType::Simple(s) => write!(f, "{s}")?,
- ComplexValType::Char => write!(f, "char")?,
- ComplexValType::BoundedNumber(a, b) => write!(
+ Self::Any => write!(f, "any")?,
+ Self::Simple(s) => write!(f, "{s}")?,
+ Self::Char => write!(f, "char")?,
+ Self::BoundedNumber(a, b) => write!(
f,
"BoundedNumber<{}, {}>",
- a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),
- b.map(|e| e.to_string()).unwrap_or_else(|| "".into())
+ a.map(|e| e.to_string())
+ .unwrap_or_else(|| "open".to_owned()),
+ b.map(|e| e.to_string())
+ .unwrap_or_else(|| "open".to_owned())
)?,
- ComplexValType::ArrayRef(a) => print_array(a, f)?,
- ComplexValType::Array(a) => print_array(a, f)?,
- ComplexValType::ObjectRef(fields) => {
+ Self::ArrayRef(a) => print_array(a, f)?,
+ Self::Array(a) => print_array(a, f)?,
+ Self::ObjectRef(fields) => {
write!(f, "{{")?;
for (i, (k, v)) in fields.iter().enumerate() {
if i != 0 {
@@ -197,18 +199,18 @@
}
write!(f, "}}")?;
}
- ComplexValType::AttrsOf(a) => {
- if matches!(a, ComplexValType::Any) {
+ Self::AttrsOf(a) => {
+ if matches!(a, Self::Any) {
write!(f, "object")?;
} else {
write!(f, "AttrsOf<{a}>")?;
}
}
- ComplexValType::Union(v) => write_union(f, true, v.iter())?,
- ComplexValType::UnionRef(v) => write_union(f, true, v.iter().copied())?,
- ComplexValType::Sum(v) => write_union(f, false, v.iter())?,
- ComplexValType::SumRef(v) => write_union(f, false, v.iter().copied())?,
- ComplexValType::Lazy(lazy) => write!(f, "Lazy<{lazy}>")?,
+ Self::Union(v) => write_union(f, true, v.iter())?,
+ Self::UnionRef(v) => write_union(f, true, v.iter().copied())?,
+ Self::Sum(v) => write_union(f, false, v.iter())?,
+ Self::SumRef(v) => write_union(f, false, v.iter().copied())?,
+ Self::Lazy(lazy) => write!(f, "Lazy<{lazy}>")?,
};
Ok(())
}
tests/suite/std_param_names.jsonnetdiffbeforeafterboth--- a/tests/suite/std_param_names.jsonnet
+++ b/tests/suite/std_param_names.jsonnet
@@ -49,6 +49,7 @@
min: ['a', 'b'],
clamp: ['x', 'minVal', 'maxVal'],
flattenArrays: ['arrs'],
+ flattenDeepArray: ['value'],
manifestIni: ['ini'],
manifestToml: ['value'],
manifestTomlEx: ['value', 'indent'],