--- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -139,7 +139,7 @@ } fn main_real(s: &State, opts: Opts) -> Result<(), Error> { - let (_stack_guard, tla, _gc_guard) = opts.general.configure(s)?; + let (tla, _gc_guard) = opts.general.configure(s)?; let manifest_format = opts.manifest.configure(s)?; let input = opts.input.input.ok_or(Error::MissingInputArgument)?; --- a/crates/jrsonnet-cli/src/lib.rs +++ b/crates/jrsonnet-cli/src/lib.rs @@ -6,9 +6,7 @@ use std::{env, marker::PhantomData, path::PathBuf}; use clap::Parser; -use jrsonnet_evaluator::{ - error::Result, stack::StackDepthLimitOverrideGuard, FileImportResolver, State, -}; +use jrsonnet_evaluator::{error::Result, stack::set_stack_depth_limit, FileImportResolver, State}; use jrsonnet_gcmodule::with_thread_object_space; pub use manifest::*; pub use stdlib::*; @@ -48,7 +46,7 @@ jpath: Vec, } impl ConfigureState for MiscOpts { - type Guards = StackDepthLimitOverrideGuard; + type Guards = (); fn configure(&self, s: &State) -> Result { let mut library_paths = self.jpath.clone(); library_paths.reverse(); @@ -58,8 +56,8 @@ s.set_import_resolver(Box::new(FileImportResolver::new(library_paths))); - let _depth_limit = jrsonnet_evaluator::stack::limit_stack_depth(self.max_stack); - Ok(_depth_limit) + set_stack_depth_limit(self.max_stack); + Ok(()) } } @@ -81,17 +79,16 @@ impl ConfigureState for GeneralOpts { type Guards = ( - ::Guards, ::Guards, ::Guards, ); fn configure(&self, s: &State) -> Result { // Configure trace first, because tla-code/ext-code can throw - let misc_guards = self.misc.configure(s)?; + self.misc.configure(s)?; let tla_guards = self.tla.configure(s)?; self.std.configure(s)?; let gc_guards = self.gc.configure(s)?; - Ok((misc_guards, tla_guards, gc_guards)) + Ok((tla_guards, gc_guards)) } } --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -389,7 +389,7 @@ ctx.super_obj().clone().ok_or(NoSuperFound)?.with_this( ctx.this() .clone() - .expect("if super exists - then this should to"), + .expect("if super exists - then this should too"), ), ), Literal(LiteralType::Dollar) => { @@ -408,6 +408,21 @@ || format!("variable <{name}> access"), || ctx.binding(name.clone())?.evaluate(), )?, + Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => { + let name = evaluate(ctx.clone(), index)?; + let Val::Str(name) = name else { + throw!(ValueIndexMustBeTypeGot( + ValType::Obj, + ValType::Str, + name.value_type(), + )) + }; + ctx.super_obj() + .clone() + .expect("no super found") + .get_for(name, ctx.this().clone().expect("no this found"))? + .expect("value not found") + } Index(value, index) => match (evaluate(ctx.clone(), value)?, evaluate(ctx, index)?) { (Val::Obj(v), Val::Str(key)) => State::push( CallLocation::new(loc), --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -128,7 +128,7 @@ assertions: Cc>>, assertions_ran: RefCell>, this_entries: Cc>, - value_cache: RefCell>, + value_cache: RefCell), CacheValue>>, } #[derive(Clone, Trace)] @@ -387,7 +387,8 @@ pub fn get(&self, key: IStr) -> Result> { self.run_assertions()?; - if let Some(v) = self.0.value_cache.borrow().get(&key) { + let cache_key = (key.clone(), None); + if let Some(v) = self.0.value_cache.borrow().get(&cache_key) { return Ok(match v { CacheValue::Cached(v) => Some(v.clone()), CacheValue::NotFound => None, @@ -398,21 +399,48 @@ self.0 .value_cache .borrow_mut() - .insert(key.clone(), CacheValue::Pending); + .insert(cache_key.clone(), CacheValue::Pending); let value = self - .get_raw( - key.clone(), - self.0.this.clone().unwrap_or_else(|| self.clone()), - ) + .get_raw(key, self.0.this.clone().unwrap_or_else(|| self.clone())) .map_err(|e| { self.0 .value_cache .borrow_mut() - .insert(key.clone(), CacheValue::Errored(e.clone())); + .insert(cache_key.clone(), CacheValue::Errored(e.clone())); e })?; self.0.value_cache.borrow_mut().insert( - key, + cache_key, + value + .as_ref() + .map_or(CacheValue::NotFound, |v| CacheValue::Cached(v.clone())), + ); + Ok(value) + } + pub fn get_for(&self, key: IStr, this: Self) -> Result> { + self.run_assertions()?; + let cache_key = (key.clone(), Some(this.clone().downgrade())); + if let Some(v) = self.0.value_cache.borrow().get(&cache_key) { + return Ok(match v { + CacheValue::Cached(v) => Some(v.clone()), + CacheValue::NotFound => None, + CacheValue::Pending => throw!(InfiniteRecursionDetected), + CacheValue::Errored(e) => return Err(e.clone()), + }); + } + self.0 + .value_cache + .borrow_mut() + .insert(cache_key.clone(), CacheValue::Pending); + let value = self.get_raw(key, this).map_err(|e| { + self.0 + .value_cache + .borrow_mut() + .insert(cache_key.clone(), CacheValue::Errored(e.clone())); + e + })?; + self.0.value_cache.borrow_mut().insert( + cache_key, value .as_ref() .map_or(CacheValue::NotFound, |v| CacheValue::Cached(v.clone())),