difftreelog
perf(evaluator) emove expr from stacktraces
in: master
4 files changed
cmds/jrsonnet/src/main.rsdiffbeforeafterboth1pub mod location;23use clap::Clap;4use jsonnet_evaluator::{EvaluationSettings, EvaluationState, LocError, StackTrace, Val};5use jsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParserSettings};6use location::{offset_to_location, CodeLocation};7use std::env::current_dir;8use std::{collections::HashMap, path::PathBuf, str::FromStr};910enum Format {11 None,12 Json,13 Yaml,14}1516impl FromStr for Format {17 type Err = &'static str;18 fn from_str(s: &str) -> Result<Self, Self::Err> {19 Ok(match s {20 "none" => Format::None,21 "json" => Format::Json,22 "yaml" => Format::Yaml,23 _ => return Err("no such format"),24 })25 }26}2728#[derive(PartialEq)]29enum TraceFormat {30 CppJsonnet,31 GoJsonnet,32 Custom,33}34impl FromStr for TraceFormat {35 type Err = &'static str;36 fn from_str(s: &str) -> Result<Self, Self::Err> {37 Ok(match s {38 "cpp" => TraceFormat::CppJsonnet,39 "go" => TraceFormat::GoJsonnet,40 "default" => TraceFormat::Custom,41 _ => return Err("no such format"),42 })43 }44}4546#[derive(Clone)]47struct ExtStr {48 name: String,49 value: String,50}51impl FromStr for ExtStr {52 type Err = &'static str;53 fn from_str(s: &str) -> Result<Self, Self::Err> {54 let out: Vec<_> = s.split('=').collect();55 match out.len() {56 1 => Ok(ExtStr {57 name: out[0].to_owned(),58 value: std::env::var(out[0]).or(Err("missing env var"))?,59 }),60 2 => Ok(ExtStr {61 name: out[0].to_owned(),62 value: out[1].to_owned(),63 }),64 _ => Err("bad ext-str syntax"),65 }66 }67}6869#[derive(Clap)]70#[clap(version = "0.1.0", author = "Lach <iam@lach.pw>")]71struct Opts {72 #[clap(long, about = "Disable global std variable")]73 no_stdlib: bool,74 #[clap(long, about = "Add external string")]75 ext_str: Vec<ExtStr>,76 #[clap(long, about = "Add external string from code")]77 ext_code: Vec<ExtStr>,78 #[clap(long, about = "Add TLA")]79 tla_str: Vec<ExtStr>,80 #[clap(long, about = "Add TLA from code")]81 tla_code: Vec<ExtStr>,82 #[clap(long, short = "f", default_value = "json", possible_values = &["none", "json", "yaml"], about = "Output format, wraps resulting value to corresponding std.manifest call")]83 format: Format,84 #[clap(long, default_value = "default", possible_values = &["cpp", "go", "default"], about = "Emulated needed stacktrace display")]85 trace_format: TraceFormat,8687 #[clap(88 long,89 short = "s",90 default_value = "200",91 about = "Number of allowed stack frames"92 )]93 max_stack: usize,94 #[clap(95 long,96 short = "t",97 default_value = "20",98 about = "Max length of stack trace before cropping"99 )]100 max_trace: usize,101102 #[clap(long, short = "J", about = "Library search dir")]103 jpath: Vec<PathBuf>,104105 #[clap(106 long,107 default_value = "3",108 about = "When using --format, this option specifies string to pad output with"109 )]110 line_padding: usize,111112 #[clap(about = "File to compile", index = 1)]113 input: String,114}115116fn main() {117 let opts: Opts = Opts::parse();118 let evaluator = jsonnet_evaluator::EvaluationState::new(119 EvaluationSettings {120 max_stack_trace_size: opts.max_trace,121 max_stack_frames: opts.max_stack,122 },123 Box::new(jsonnet_evaluator::FileImportResolver {124 library_paths: opts.jpath.clone(),125 }),126 );127 if !opts.no_stdlib {128 evaluator.with_stdlib();129 }130 for ExtStr { name, value } in opts.ext_str.iter().cloned() {131 evaluator.add_ext_var(name, Val::Str(value));132 }133 for ExtStr { name, value } in opts.ext_code.iter().cloned() {134 evaluator.add_ext_var(name, evaluator.parse_evaluate_raw(&value).unwrap());135 }136 let mut input = current_dir().unwrap();137 input.push(opts.input.clone());138 let code_string = String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap();139 if let Err(e) = evaluator.add_file(input.clone(), code_string.clone()) {140 print_syntax_error(e, &input, &code_string);141 std::process::exit(1);142 }143 let result = evaluator.evaluate_file(&input);144 match result {145 Ok(v) => {146 let v = match v {147 Val::Func(f) => {148 let mut desc_map = HashMap::new();149 for ExtStr { name, value } in opts.tla_str.iter().cloned() {150 desc_map.insert(name, el!(Expr::Str(value)));151 }152 for ExtStr { name, value } in opts.tla_code.iter().cloned() {153 desc_map.insert(154 name,155 jsonnet_parser::parse(156 &value,157 &ParserSettings {158 file_name: PathBuf::new(),159 loc_data: false,160 },161 )162 .unwrap(),163 );164 }165 evaluator.add_global("__tmp__tlf__".to_owned(), Val::Func(f));166 evaluator167 .evaluate_raw(el!(Expr::Apply(168 el!(Expr::Var("__tmp__tlf__".to_owned())),169 ArgsDesc(desc_map.into_iter().map(|(k, v)| Arg(Some(k), v)).collect()),170 false,171 )))172 .unwrap()173 }174 v => v,175 };176 let v = match opts.format {177 Format::Json => {178 if opts.no_stdlib {179 evaluator.with_stdlib();180 }181 evaluator.add_global("__tmp__to_json__".to_owned(), v);182 let v = evaluator.parse_evaluate_raw(&format!(183 "std.manifestJsonEx(__tmp__to_json__, \"{}\")",184 " ".repeat(opts.line_padding),185 ));186 match v {187 Ok(v) => v,188 Err(err) => {189 print_error(&err, evaluator, &opts);190 std::process::exit(1);191 }192 }193 }194 Format::Yaml => {195 if opts.no_stdlib {196 evaluator.with_stdlib();197 }198 evaluator.add_global("__tmp__to_yaml__".to_owned(), v);199 let v = evaluator200 .parse_evaluate_raw("std.manifestYamlDoc(__tmp__to_yaml__, \" \")");201 match v {202 Ok(v) => v,203 Err(err) => {204 print_error(&err, evaluator, &opts);205 std::process::exit(1);206 }207 }208 }209 _ => v,210 };211 match v {212 Val::Str(s) => println!("{}", s),213 Val::Num(n) => println!("{}", n),214 _v => eprintln!(215 "jsonnet output is not a string.\nDid you forgot to set --format, or wrap your data with std.manifestJson?"216 ),217 }218 }219 Err(err) => {220 print_error(&err, evaluator, &opts);221 std::process::exit(1);222 }223 }224}225226fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {227 println!("Error: {:?}", err.0);228 print_trace(&(err.1), evaluator, &opts);229}230231fn print_syntax_error(error: jsonnet_parser::ParseError, file: &PathBuf, code: &str) {232 use annotate_snippets::{233 display_list::{DisplayList, FormatOptions},234 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},235 };236 //&("Expected: ".to_owned() + error.expected)237 let origin = file.to_str().unwrap();238 let error_message = format!("Expected: {}", error.expected);239 let snippet = Snippet {240 opt: FormatOptions {241 color: true,242 ..Default::default()243 },244 title: Some(Annotation {245 label: Some(&error_message),246 id: None,247 annotation_type: AnnotationType::Error,248 }),249 footer: vec![],250 slices: vec![Slice {251 source: &code,252 line_start: 1,253 origin: Some(origin),254 fold: false,255 annotations: vec![SourceAnnotation {256 label: "At this position",257 annotation_type: AnnotationType::Error,258 range: (error.location.offset, error.location.offset + 1),259 }],260 }],261 };262263 let dl = DisplayList::from(snippet);264 println!("{}", dl);265}266267fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {268 use annotate_snippets::{269 display_list::{DisplayList, FormatOptions},270 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},271 };272 for item in trace.0.iter() {273 let desc = &item.1;274 if (item.0).1.is_none() {275 continue;276 }277 let source = (item.0).1.clone().unwrap();278 let code = evaluator.get_source(&source.0);279 if code.is_none() {280 continue;281 }282 let code = code.unwrap();283 let start_end = offset_to_location(&code, &[source.1, source.2]);284 if opts.trace_format == TraceFormat::Custom {285 let source_fragment: String = code286 .chars()287 .skip(start_end[0].line_start_offset)288 .take(start_end[1].line_end_offset - start_end[0].line_start_offset)289 .collect();290 let snippet = Snippet {291 opt: FormatOptions {292 color: true,293 ..Default::default()294 },295 title: Some(Annotation {296 label: Some(&item.1),297 id: None,298 annotation_type: AnnotationType::Error,299 }),300 footer: vec![],301 slices: vec![Slice {302 source: &source_fragment,303 line_start: start_end[0].line,304 origin: Some(&source.0.to_str().unwrap()),305 fold: false,306 annotations: vec![SourceAnnotation {307 label: desc,308 annotation_type: AnnotationType::Error,309 range: (310 source.1 - start_end[0].line_start_offset,311 source.2 - start_end[0].line_start_offset,312 ),313 }],314 }],315 };316317 let dl = DisplayList::from(snippet);318 println!("{}", dl);319 } else {320 print_jsonnet_pair(321 source.0.to_str().unwrap(),322 &start_end[0],323 &start_end[1],324 opts.trace_format == TraceFormat::GoJsonnet,325 );326 }327 }328}329330fn print_jsonnet_pair(file: &str, start: &CodeLocation, end: &CodeLocation, is_go: bool) {331 if is_go {332 print!(" ");333 } else {334 print!(" ");335 }336 print!("{}:", file);337 if start.line == end.line {338 // IDK why, but this is the behavior original jsonnet cpp impl shows339 if start.column == end.column || !is_go && start.column + 1 == end.column {340 println!("{}:{}", start.line, end.column)341 } else {342 println!("{}:{}-{}", start.line, start.column, end.column);343 }344 } else {345 println!(346 "({}:{})-({}:{})",347 start.line, end.column, start.line, end.column348 );349 }350}1pub mod location;23use clap::Clap;4use jsonnet_evaluator::{EvaluationSettings, EvaluationState, LocError, StackTrace, Val};5use jsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParserSettings};6use location::{offset_to_location, CodeLocation};7use std::env::current_dir;8use std::{collections::HashMap, path::PathBuf, str::FromStr};910enum Format {11 None,12 Json,13 Yaml,14}1516impl FromStr for Format {17 type Err = &'static str;18 fn from_str(s: &str) -> Result<Self, Self::Err> {19 Ok(match s {20 "none" => Format::None,21 "json" => Format::Json,22 "yaml" => Format::Yaml,23 _ => return Err("no such format"),24 })25 }26}2728#[derive(PartialEq)]29enum TraceFormat {30 CppJsonnet,31 GoJsonnet,32 Custom,33}34impl FromStr for TraceFormat {35 type Err = &'static str;36 fn from_str(s: &str) -> Result<Self, Self::Err> {37 Ok(match s {38 "cpp" => TraceFormat::CppJsonnet,39 "go" => TraceFormat::GoJsonnet,40 "default" => TraceFormat::Custom,41 _ => return Err("no such format"),42 })43 }44}4546#[derive(Clone)]47struct ExtStr {48 name: String,49 value: String,50}51impl FromStr for ExtStr {52 type Err = &'static str;53 fn from_str(s: &str) -> Result<Self, Self::Err> {54 let out: Vec<_> = s.split('=').collect();55 match out.len() {56 1 => Ok(ExtStr {57 name: out[0].to_owned(),58 value: std::env::var(out[0]).or(Err("missing env var"))?,59 }),60 2 => Ok(ExtStr {61 name: out[0].to_owned(),62 value: out[1].to_owned(),63 }),64 _ => Err("bad ext-str syntax"),65 }66 }67}6869#[derive(Clap)]70#[clap(version = "0.1.0", author = "Lach <iam@lach.pw>")]71struct Opts {72 #[clap(long, about = "Disable global std variable")]73 no_stdlib: bool,74 #[clap(long, about = "Add external string")]75 ext_str: Vec<ExtStr>,76 #[clap(long, about = "Add external string from code")]77 ext_code: Vec<ExtStr>,78 #[clap(long, about = "Add TLA")]79 tla_str: Vec<ExtStr>,80 #[clap(long, about = "Add TLA from code")]81 tla_code: Vec<ExtStr>,82 #[clap(long, short = "f", default_value = "json", possible_values = &["none", "json", "yaml"], about = "Output format, wraps resulting value to corresponding std.manifest call")]83 format: Format,84 #[clap(long, default_value = "default", possible_values = &["cpp", "go", "default"], about = "Emulated needed stacktrace display")]85 trace_format: TraceFormat,8687 #[clap(88 long,89 short = "s",90 default_value = "200",91 about = "Number of allowed stack frames"92 )]93 max_stack: usize,94 #[clap(95 long,96 short = "t",97 default_value = "20",98 about = "Max length of stack trace before cropping"99 )]100 max_trace: usize,101102 #[clap(long, short = "J", about = "Library search dir")]103 jpath: Vec<PathBuf>,104105 #[clap(106 long,107 default_value = "3",108 about = "When using --format, this option specifies string to pad output with"109 )]110 line_padding: usize,111112 #[clap(about = "File to compile", index = 1)]113 input: String,114}115116fn main() {117 let opts: Opts = Opts::parse();118 let evaluator = jsonnet_evaluator::EvaluationState::new(119 EvaluationSettings {120 max_stack_trace_size: opts.max_trace,121 max_stack_frames: opts.max_stack,122 },123 Box::new(jsonnet_evaluator::FileImportResolver {124 library_paths: opts.jpath.clone(),125 }),126 );127 if !opts.no_stdlib {128 evaluator.with_stdlib();129 }130 for ExtStr { name, value } in opts.ext_str.iter().cloned() {131 evaluator.add_ext_var(name, Val::Str(value));132 }133 for ExtStr { name, value } in opts.ext_code.iter().cloned() {134 evaluator.add_ext_var(name, evaluator.parse_evaluate_raw(&value).unwrap());135 }136 let mut input = current_dir().unwrap();137 input.push(opts.input.clone());138 let code_string = String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap();139 if let Err(e) = evaluator.add_file(input.clone(), code_string.clone()) {140 print_syntax_error(e, &input, &code_string);141 std::process::exit(1);142 }143 let result = evaluator.evaluate_file(&input);144 match result {145 Ok(v) => {146 let v = match v {147 Val::Func(f) => {148 let mut desc_map = HashMap::new();149 for ExtStr { name, value } in opts.tla_str.iter().cloned() {150 desc_map.insert(name, el!(Expr::Str(value)));151 }152 for ExtStr { name, value } in opts.tla_code.iter().cloned() {153 desc_map.insert(154 name,155 jsonnet_parser::parse(156 &value,157 &ParserSettings {158 file_name: PathBuf::new(),159 loc_data: false,160 },161 )162 .unwrap(),163 );164 }165 evaluator.add_global("__tmp__tlf__".to_owned(), Val::Func(f));166 evaluator167 .evaluate_raw(el!(Expr::Apply(168 el!(Expr::Var("__tmp__tlf__".to_owned())),169 ArgsDesc(desc_map.into_iter().map(|(k, v)| Arg(Some(k), v)).collect()),170 false,171 )))172 .unwrap()173 }174 v => v,175 };176 let v = match opts.format {177 Format::Json => {178 if opts.no_stdlib {179 evaluator.with_stdlib();180 }181 evaluator.add_global("__tmp__to_json__".to_owned(), v);182 let v = evaluator.parse_evaluate_raw(&format!(183 "std.manifestJsonEx(__tmp__to_json__, \"{}\")",184 " ".repeat(opts.line_padding),185 ));186 match v {187 Ok(v) => v,188 Err(err) => {189 print_error(&err, evaluator, &opts);190 std::process::exit(1);191 }192 }193 }194 Format::Yaml => {195 if opts.no_stdlib {196 evaluator.with_stdlib();197 }198 evaluator.add_global("__tmp__to_yaml__".to_owned(), v);199 let v = evaluator200 .parse_evaluate_raw("std.manifestYamlDoc(__tmp__to_yaml__, \" \")");201 match v {202 Ok(v) => v,203 Err(err) => {204 print_error(&err, evaluator, &opts);205 std::process::exit(1);206 }207 }208 }209 _ => v,210 };211 match v {212 Val::Str(s) => println!("{}", s),213 Val::Num(n) => println!("{}", n),214 _v => eprintln!(215 "jsonnet output is not a string.\nDid you forgot to set --format, or wrap your data with std.manifestJson?"216 ),217 }218 }219 Err(err) => {220 print_error(&err, evaluator, &opts);221 std::process::exit(1);222 }223 }224}225226fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {227 println!("Error: {:?}", err.0);228 print_trace(&(err.1), evaluator, &opts);229}230231fn print_syntax_error(error: jsonnet_parser::ParseError, file: &PathBuf, code: &str) {232 use annotate_snippets::{233 display_list::{DisplayList, FormatOptions},234 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},235 };236 //&("Expected: ".to_owned() + error.expected)237 let origin = file.to_str().unwrap();238 let error_message = format!("Expected: {}", error.expected);239 let snippet = Snippet {240 opt: FormatOptions {241 color: true,242 ..Default::default()243 },244 title: Some(Annotation {245 label: Some(&error_message),246 id: None,247 annotation_type: AnnotationType::Error,248 }),249 footer: vec![],250 slices: vec![Slice {251 source: &code,252 line_start: 1,253 origin: Some(origin),254 fold: false,255 annotations: vec![SourceAnnotation {256 label: "At this position",257 annotation_type: AnnotationType::Error,258 range: (error.location.offset, error.location.offset + 1),259 }],260 }],261 };262263 let dl = DisplayList::from(snippet);264 println!("{}", dl);265}266267fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {268 use annotate_snippets::{269 display_list::{DisplayList, FormatOptions},270 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},271 };272 for item in trace.0.iter() {273 let desc = &item.1;274 let source = item.0.clone();275 let code = evaluator.get_source(&source.0);276 if code.is_none() {277 continue;278 }279 let code = code.unwrap();280 let start_end = offset_to_location(&code, &[source.1, source.2]);281 if opts.trace_format == TraceFormat::Custom {282 let source_fragment: String = code283 .chars()284 .skip(start_end[0].line_start_offset)285 .take(start_end[1].line_end_offset - start_end[0].line_start_offset)286 .collect();287 let snippet = Snippet {288 opt: FormatOptions {289 color: true,290 ..Default::default()291 },292 title: Some(Annotation {293 label: Some(&item.1),294 id: None,295 annotation_type: AnnotationType::Error,296 }),297 footer: vec![],298 slices: vec![Slice {299 source: &source_fragment,300 line_start: start_end[0].line,301 origin: Some(&source.0.to_str().unwrap()),302 fold: false,303 annotations: vec![SourceAnnotation {304 label: desc,305 annotation_type: AnnotationType::Error,306 range: (307 source.1 - start_end[0].line_start_offset,308 source.2 - start_end[0].line_start_offset,309 ),310 }],311 }],312 };313314 let dl = DisplayList::from(snippet);315 println!("{}", dl);316 } else {317 print_jsonnet_pair(318 source.0.to_str().unwrap(),319 &start_end[0],320 &start_end[1],321 opts.trace_format == TraceFormat::GoJsonnet,322 );323 }324 }325}326327fn print_jsonnet_pair(file: &str, start: &CodeLocation, end: &CodeLocation, is_go: bool) {328 if is_go {329 print!(" ");330 } else {331 print!(" ");332 }333 print!("{}:", file);334 if start.line == end.line {335 // IDK why, but this is the behavior original jsonnet cpp impl shows336 if start.column == end.column || !is_go && start.column + 1 == end.column {337 println!("{}:{}", start.line, end.column)338 } else {339 println!("{}:{}-{}", start.line, start.column, end.column);340 }341 } else {342 println!(343 "({}:{})-({}:{})",344 start.line, end.column, start.line, end.column345 );346 }347}crates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth--- 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<ExprLocation>, pub String);
#[derive(Debug, Clone)]
pub struct StackTrace(pub Vec<StackTraceElement>);
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- 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<Val> {
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 ({:?}): {}",
crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/lib.rs
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -81,15 +81,21 @@
pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)
}
pub(crate) fn with_state<T>(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<T>(err: Error) -> Result<T> {
with_state(|s| s.error(err))
}
-pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
- with_state(|s| s.push(e, comment, f))
+pub(crate) fn push<T>(
+ e: &Option<Rc<ExprLocation>>,
+ comment: &str,
+ f: impl FnOnce() -> Result<T>,
+) -> Result<T> {
+ 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<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
+ pub fn push<T>(
+ &self,
+ e: Rc<ExprLocation>,
+ comment: String,
+ f: impl FnOnce() -> Result<T>,
+ ) -> Result<T> {
{
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();