--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -16,10 +16,11 @@ error::{suggest_object_fields, ErrorKind::*}, evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, function::{CallLocation, FuncDesc, FuncVal}, + in_frame, typed::Typed, val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk, ThunkValue}, Context, Error, GcHashMap, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, - ResultExt, State, Unbound, Val, + ResultExt, Unbound, Val, }; pub mod destructure; pub mod operator; @@ -71,7 +72,7 @@ pub fn evaluate_field_name(ctx: Context, field_name: &FieldName) -> Result> { Ok(match field_name { FieldName::Fixed(n) => Some(n.clone()), - FieldName::Dyn(expr) => State::push( + FieldName::Dyn(expr) => in_frame( CallLocation::new(&expr.span()), || "evaluating field name".to_string(), || { @@ -374,7 +375,7 @@ if tailstrict { body()? } else { - State::push(loc, || format!("function <{}> call", f.name()), body)? + in_frame(loc, || format!("function <{}> call", f.name()), body)? } } v => bail!(OnlyFunctionsCanBeCalledGot(v.value_type())), @@ -384,13 +385,13 @@ pub fn evaluate_assert(ctx: Context, assertion: &AssertStmt) -> Result<()> { let value = &assertion.0; let msg = &assertion.1; - let assertion_result = State::push( + let assertion_result = in_frame( CallLocation::new(&value.span()), || "assertion condition".to_owned(), || bool::from_untyped(evaluate(ctx.clone(), value)?), )?; if !assertion_result { - State::push( + in_frame( CallLocation::new(&value.span()), || "assertion failure".to_owned(), || { @@ -457,7 +458,7 @@ } BinaryOp(v1, o, v2) => evaluate_binary_op_special(ctx, v1, *o, v2)?, UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?, - Var(name) => State::push( + Var(name) => in_frame( CallLocation::new(&loc), || format!("variable <{name}> access"), || ctx.binding(name.clone())?.evaluate(), @@ -645,7 +646,7 @@ evaluate_assert(ctx.clone(), assert)?; evaluate(ctx, returned)? } - ErrorStmt(e) => State::push( + ErrorStmt(e) => in_frame( CallLocation::new(&loc), || "error statement".to_owned(), || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)), @@ -655,7 +656,7 @@ cond_then, cond_else, } => { - if State::push( + if in_frame( CallLocation::new(&loc), || "if condition".to_owned(), || bool::from_untyped(evaluate(ctx.clone(), &cond.0)?), @@ -676,7 +677,7 @@ desc: &'static str, ) -> Result> { if let Some(value) = expr { - Ok(Some(State::push( + Ok(Some(in_frame( loc, || format!("slice {desc}"), || T::from_untyped(evaluate(ctx.clone(), value)?), @@ -703,7 +704,7 @@ let s = ctx.state(); let resolved_path = s.resolve_from(tmp.source_path(), path as &str)?; match i { - Import(_) => State::push( + Import(_) => in_frame( CallLocation::new(&loc), || format!("import {:?}", path.clone()), || s.import_resolved(resolved_path), --- a/crates/jrsonnet-evaluator/src/import.rs +++ b/crates/jrsonnet-evaluator/src/import.rs @@ -1,6 +1,5 @@ use std::{ any::Any, - cell::RefCell, env::current_dir, fs, io::{ErrorKind, Read}, @@ -41,8 +40,10 @@ /// this cannot be resolved using associated type, as evaluator uses object instead of generic for [`ImportResolver`] fn load_file_contents(&self, resolved: &SourcePath) -> Result>; - /// For downcasts + // For downcasts, will be removed after trait_upcasting_coercion + // stabilization. fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; } /// Dummy resolver, can't resolve/load any file @@ -56,6 +57,9 @@ fn as_any(&self) -> &dyn Any { self } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } } #[allow(clippy::use_self)] impl Default for Box { @@ -69,17 +73,15 @@ pub struct FileImportResolver { /// Library directories to search for file. /// Referred to as `jpath` in original jsonnet implementation. - library_paths: RefCell>, + library_paths: Vec, } impl FileImportResolver { - pub fn new(jpath: Vec) -> Self { - Self { - library_paths: RefCell::new(jpath), - } + pub fn new(library_paths: Vec) -> Self { + Self { library_paths } } /// Dynamically add new jpath, used by bindings - pub fn add_jpath(&self, path: PathBuf) { - self.library_paths.borrow_mut().push(path); + pub fn add_jpath(&mut self, path: PathBuf) { + self.library_paths.push(path); } } @@ -132,7 +134,7 @@ if let Some(direct) = check_path(&direct)? { return Ok(direct); } - for library_path in self.library_paths.borrow().iter() { + for library_path in &self.library_paths { let mut cloned = library_path.clone(); cloned.push(path); if let Some(cloned) = check_path(&cloned)? { @@ -165,11 +167,15 @@ Ok(out) } + fn resolve_from_default(&self, path: &str) -> Result { + self.resolve_from(&SourcePath::default(), path) + } + fn as_any(&self) -> &dyn Any { self } - fn resolve_from_default(&self, path: &str) -> Result { - self.resolve_from(&SourcePath::default(), path) + fn as_any_mut(&mut self) -> &mut dyn Any { + self } } --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -11,8 +11,8 @@ }; use crate::{ - arr::ArrValue, runtime_error, val::NumValue, Error as JrError, ObjValue, ObjValueBuilder, - Result, State, Val, + arr::ArrValue, in_description_frame, runtime_error, val::NumValue, Error as JrError, ObjValue, + ObjValueBuilder, Result, Val, }; impl<'de> Deserialize<'de> for Val { @@ -173,8 +173,7 @@ let mut seq = serializer.serialize_seq(Some(arr.len()))?; for (i, element) in arr.iter().enumerate() { let mut serde_error = None; - // TODO: rewrite using try{} after stabilization - State::push_description( + in_description_frame( || format!("array index [{i}]"), || { let e = element?; @@ -199,7 +198,7 @@ ) { let mut serde_error = None; // TODO: rewrite using try{} after stabilization - State::push_description( + in_description_frame( || format!("object field {field:?}"), || { let v = value?; --- 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::{LocExpr, ParserSettings, Source, SourcePath, Span}; +use jrsonnet_parser::{LocExpr, ParserSettings, Source, SourcePath}; pub use obj::*; use stack::check_depth; pub use tla::apply_tla; @@ -376,38 +376,6 @@ context_initializer.populate(source, &mut builder); builder.build() - } - - /// Executes code creating a new stack frame - pub fn push( - e: CallLocation<'_>, - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, - ) -> Result { - let _guard = check_depth()?; - - f().with_description_src(e, frame_desc) - } - - /// Executes code creating a new stack frame - pub fn push_val( - &self, - e: &Span, - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, - ) -> Result { - let _guard = check_depth()?; - - f().with_description_src(e, frame_desc) - } - /// Executes code creating a new stack frame - pub fn push_description( - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, - ) -> Result { - let _guard = check_depth()?; - - f().with_description(frame_desc) } } @@ -417,6 +385,26 @@ self.0.file_cache.borrow_mut() } } +/// Executes code creating a new stack frame, to be replaced with try{} +pub fn in_frame( + e: CallLocation<'_>, + frame_desc: impl FnOnce() -> String, + f: impl FnOnce() -> Result, +) -> Result { + let _guard = check_depth()?; + + f().with_description_src(e, frame_desc) +} + +/// Executes code creating a new stack frame, to be replaced with try{} +pub fn in_description_frame( + frame_desc: impl FnOnce() -> String, + f: impl FnOnce() -> Result, +) -> Result { + let _guard = check_depth()?; + + f().with_description(frame_desc) +} #[derive(Trace)] pub struct InitialUnderscore(pub Thunk); --- a/crates/jrsonnet-evaluator/src/manifest.rs +++ b/crates/jrsonnet-evaluator/src/manifest.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, fmt::Write, ptr}; -use crate::{bail, Result, ResultExt, State, Val}; +use crate::{bail, in_description_frame, Result, ResultExt, Val}; pub trait ManifestFormat { fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()>; @@ -242,7 +242,7 @@ Minify | ToString => {} }; - State::push_description( + in_description_frame( || format!("elem <{i}> manifestification"), || manifest_json_ex_buf(&item, buf, cur_padding, options), )?; @@ -304,7 +304,7 @@ escape_string_json_buf(&key, buf); buf.push_str(options.key_val_sep); - State::push_description( + in_description_frame( || format!("field <{key}> manifestification"), || manifest_json_ex_buf(&value, buf, cur_padding, options), )?; @@ -412,7 +412,7 @@ for (i, v) in arr.iter().enumerate() { let v = v.with_description(|| format!("elem <{i}> evaluation"))?; out.push_str("---\n"); - State::push_description( + in_description_frame( || format!("elem <{i}> manifestification"), || self.inner.manifest_buf(v, out), )?; --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -17,10 +17,11 @@ error::{suggest_object_fields, Error, ErrorKind::*}, function::{CallLocation, FuncVal}, gc::{GcHashMap, GcHashSet, TraceBox}, + in_frame, operator::evaluate_add_op, tb, val::{ArrValue, ThunkValue}, - MaybeUnbound, Result, State, Thunk, Unbound, Val, + MaybeUnbound, Result, Thunk, Unbound, Val, }; #[cfg(not(feature = "exp-preserve-order"))] @@ -969,7 +970,7 @@ let location = member.location.clone(); let old = receiver.0.map.insert(name.clone(), member); if old.is_some() { - State::push( + in_frame( CallLocation(location.as_ref()), || format!("field <{}> initializtion", name.clone()), || bail!(DuplicateFieldName(name.clone())), --- a/crates/jrsonnet-evaluator/src/stdlib/mod.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/mod.rs @@ -3,12 +3,12 @@ use format::{format_arr, format_obj}; -use crate::{function::CallLocation, Result, State, Val}; +use crate::{function::CallLocation, in_frame, Result, Val}; pub mod format; pub fn std_format(str: &str, vals: Val) -> Result { - State::push( + in_frame( CallLocation::native(), || format!("std.format of {str}"), || { --- a/crates/jrsonnet-evaluator/src/tla.rs +++ b/crates/jrsonnet-evaluator/src/tla.rs @@ -3,12 +3,12 @@ use crate::{ function::{ArgsLike, CallLocation}, - Result, State, Val, + in_description_frame, Result, State, Val, }; pub fn apply_tla(s: State, args: &A, val: Val) -> Result { Ok(if let Val::Func(func) = val { - State::push_description( + in_description_frame( || "during TLA call".to_owned(), || { func.evaluate( --- a/crates/jrsonnet-evaluator/src/typed/mod.rs +++ b/crates/jrsonnet-evaluator/src/typed/mod.rs @@ -8,7 +8,7 @@ use crate::{ error::{Error, ErrorKind, Result}, - State, Val, + in_description_frame, Val, }; #[derive(Debug, Error, Clone, Trace)] @@ -89,7 +89,7 @@ path: impl Fn() -> ValuePathItem, item: impl Fn() -> Result<()>, ) -> Result<()> { - State::push_description(error_reason, || match item() { + in_description_frame(error_reason, || match item() { Ok(()) => Ok(()), Err(mut e) => { if let ErrorKind::TypeError(e) = &mut e.error_mut() { --- a/crates/jrsonnet-interner/src/lib.rs +++ b/crates/jrsonnet-interner/src/lib.rs @@ -235,6 +235,7 @@ use crate::{PoolMap, POOL}; + /// Type-erased interned string pool pub enum PoolState {} /// Dump current interned string pool, to be restored by --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -290,7 +290,7 @@ cfg_attrs, } => { let name = name.as_ref().map_or("", String::as_str); - let eval = quote! {jrsonnet_evaluator::State::push_description( + let eval = quote! {jrsonnet_evaluator::in_description_frame( || format!("argument <{}> evaluation", #name), || <#ty>::from_untyped(value.evaluate()?), )?}; --- a/crates/jrsonnet-stdlib/src/manifest/toml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs @@ -1,10 +1,10 @@ use std::borrow::Cow; use jrsonnet_evaluator::{ - bail, + bail, in_description_frame, manifest::{escape_string_json_buf, ManifestFormat}, val::ArrValue, - IStr, ObjValue, Result, ResultExt, State, Val, + IStr, ObjValue, Result, ResultExt, Val, }; pub struct TomlFormat<'s> { @@ -124,7 +124,7 @@ buf.push_str(&options.padding); } - State::push_description( + in_description_frame( || format!("elem <{i}> manifestification"), || manifest_value(&e, true, buf, "", options), )?; @@ -161,7 +161,7 @@ escape_key_toml_buf(&k, buf); buf.push_str(" = "); - State::push_description( + in_description_frame( || format!("field <{k}> manifestification"), || manifest_value(&v, true, buf, "", options), )?; --- a/crates/jrsonnet-stdlib/src/manifest/xml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs @@ -1,9 +1,9 @@ use jrsonnet_evaluator::{ - bail, + bail, in_description_frame, manifest::{ManifestFormat, ToStringFormat}, typed::{ComplexValType, Either2, Typed, ValType}, val::ArrValue, - Either, ObjValue, Result, ResultExt, State, Val, + Either, ObjValue, Result, ResultExt, Val, }; pub struct XmlJsonmlFormat { @@ -70,7 +70,7 @@ Ok(Self::Tag { tag, attrs, - children: State::push_description( + children: in_description_frame( || "parsing children".to_owned(), || { Typed::from_untyped(Val::Arr(arr.slice( --- a/crates/jrsonnet-stdlib/src/manifest/yaml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/yaml.rs @@ -1,9 +1,9 @@ use std::{borrow::Cow, fmt::Write}; use jrsonnet_evaluator::{ - bail, + bail, in_description_frame, manifest::{escape_string_json_buf, ManifestFormat}, - Result, ResultExt, State, Val, + Result, ResultExt, Val, }; pub struct YamlFormat<'s> { @@ -178,7 +178,7 @@ if extra_padding { cur_padding.push_str(&options.padding); } - State::push_description( + in_description_frame( || format!("elem <{i}> manifestification"), || manifest_yaml_ex_buf(&item, buf, cur_padding, options), )?; @@ -225,7 +225,7 @@ } _ => buf.push(' '), } - State::push_description( + in_description_frame( || format!("field <{key}> manifestification"), || manifest_yaml_ex_buf(&value, buf, cur_padding, options), )?;