--- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -271,10 +271,7 @@ }; for item in trace.0.iter() { let desc = &item.1; - if (item.0).1.is_none() { - continue; - } - let source = (item.0).1.clone().unwrap(); + let source = item.0.clone(); let code = evaluator.get_source(&source.0); if code.is_none() { continue; --- a/crates/jsonnet-evaluator/src/error.rs +++ b/crates/jsonnet-evaluator/src/error.rs @@ -1,6 +1,6 @@ use crate::ValType; -use jsonnet_parser::LocExpr; -use std::path::PathBuf; +use jsonnet_parser::ExprLocation; +use std::{path::PathBuf, rc::Rc}; #[derive(Debug, Clone)] pub enum Error { @@ -38,7 +38,7 @@ } #[derive(Clone, Debug)] -pub struct StackTraceElement(pub LocExpr, pub String); +pub struct StackTraceElement(pub Rc, pub String); #[derive(Debug, Clone)] pub struct StackTrace(pub Vec); --- a/crates/jsonnet-evaluator/src/evaluate.rs +++ b/crates/jsonnet-evaluator/src/evaluate.rs @@ -35,7 +35,7 @@ b.name.clone(), LazyBinding::Bindable(Rc::new(move |this, super_obj| { Ok(lazy_val!(closure!(clone context_creator, clone b, || - push(b.value.clone(), "thunk".to_owned(), ||{ + push(&b.value.1, "thunk", ||{ evaluate( context_creator.0(this.clone(), super_obj.clone())?, &b.value @@ -255,7 +255,7 @@ visibility: visibility.clone(), invoke: LazyBinding::Bindable(Rc::new( closure!(clone name, clone value, clone context_creator, |this, super_obj| { - Ok(LazyVal::new_resolved(push(value.clone(), "object ".to_owned()+&name+" field", ||{ + Ok(LazyVal::new_resolved(push(&value.1, "object field", ||{ let context = context_creator.0(this, super_obj)?; evaluate( context, @@ -371,7 +371,6 @@ pub fn evaluate(context: Context, expr: &LocExpr) -> Result { use Expr::*; - let locexpr = expr.clone(); let LocExpr(expr, loc) = expr; Ok(match &**expr { Literal(LiteralType::This) => Val::Obj( @@ -394,7 +393,7 @@ Num(v) => Val::Num(*v), BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?, UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?, - Var(name) => push(locexpr, "var".to_owned(), || { + Var(name) => push(loc, "var", || { Val::Lazy(context.binding(&name)?).unwrap_if_lazy() })?, Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => { @@ -733,7 +732,7 @@ if *tailstrict { body()? } else { - push(locexpr, "function call".to_owned(), body)? + push(loc, "function call", body)? } } _ => panic!("{:?} is not a function", value), @@ -741,16 +740,12 @@ } Function(params, body) => evaluate_method(context, params.clone(), body.clone()), AssertExpr(AssertStmt(value, msg), returned) => { - let assertion_result = push(value.clone(), "assertion condition".to_owned(), || { + let assertion_result = push(&value.1, "assertion condition", || { evaluate(context.clone(), &value)? .try_cast_bool("assertion condition should be boolean") })?; if assertion_result { - push( - returned.clone(), - "assert 'return' branch".to_owned(), - || evaluate(context, returned), - )? + evaluate(context, returned)? } else if let Some(msg) = msg { panic!( "assertion failed ({:?}): {}", --- a/crates/jsonnet-evaluator/src/lib.rs +++ b/crates/jsonnet-evaluator/src/lib.rs @@ -81,15 +81,21 @@ pub(crate) static EVAL_STATE: RefCell> = RefCell::new(None) } pub(crate) fn with_state(f: impl FnOnce(&EvaluationState) -> T) -> T { - EVAL_STATE.with( - |s| f(s.borrow().as_ref().unwrap()), - ) + EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap())) } pub(crate) fn create_error(err: Error) -> Result { with_state(|s| s.error(err)) } -pub(crate) fn push(e: LocExpr, comment: String, f: impl FnOnce() -> Result) -> Result { - with_state(|s| s.push(e, comment, f)) +pub(crate) fn push( + e: &Option>, + comment: &str, + f: impl FnOnce() -> Result, +) -> Result { + if e.is_some() { + with_state(|s| s.push(e.clone().unwrap(), comment.to_owned(), f)) + } else { + f() + } } /// Maintains stack trace and import resolution @@ -247,7 +253,12 @@ Context::new().extend_unbound(new_bindings, None, None, None) } - pub fn push(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result) -> Result { + pub fn push( + &self, + e: Rc, + comment: String, + f: impl FnOnce() -> Result, + ) -> Result { { let mut stack = self.0.stack.borrow_mut(); if stack.len() > self.0.settings.max_stack_frames { @@ -302,26 +313,18 @@ use super::Val; use crate::EvaluationState; use jsonnet_parser::*; - use std::path::PathBuf; + use std::{path::PathBuf, rc::Rc}; #[test] fn eval_state_stacktrace() { let state = EvaluationState::default(); state .push( - loc_expr!( - Expr::Num(0.0), - true, - (PathBuf::from("test1.jsonnet"), 10, 20) - ), + Rc::new(ExprLocation(PathBuf::from("test1.jsonnet"), 10, 20)), "outer".to_owned(), || { state.push( - loc_expr!( - Expr::Num(0.0), - true, - (PathBuf::from("test2.jsonnet"), 30, 40) - ), + Rc::new(ExprLocation(PathBuf::from("test2.jsonnet"), 30, 40)), "inner".to_owned(), || { state.print_stack_trace();