difftreelog
feat locationless stack frames
in: master
4 files changed
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -132,7 +132,7 @@
#[derive(Clone, Debug)]
pub struct StackTraceElement {
- pub location: ExprLocation,
+ pub location: Option<ExprLocation>,
pub desc: String,
}
#[derive(Debug, Clone)]
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -132,11 +132,15 @@
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
- if let Some(v) = e {
- with_state(|s| s.push(v, frame_desc, f))
- } else {
- f()
- }
+ with_state(|s| s.push(e, frame_desc, f))
+}
+
+pub fn push_stack_frame<T>(
+ e: Option<&ExprLocation>,
+ frame_desc: impl FnOnce() -> String,
+ f: impl FnOnce() -> Result<T>,
+ ) -> Result<T> {
+ push(e, frame_desc, f)
}
/// Maintains stack trace and import resolution
@@ -271,7 +275,7 @@
/// Executes code creating a new stack frame
pub fn push<T>(
&self,
- e: &ExprLocation,
+ e: Option<&ExprLocation>,
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
@@ -290,7 +294,7 @@
self.data_mut().stack_depth -= 1;
if let Err(mut err) = result {
err.trace_mut().0.push(StackTraceElement {
- location: e.clone(),
+ location: e.cloned(),
desc: frame_desc(),
});
return Err(err);
@@ -336,11 +340,11 @@
pub fn with_tla(&self, val: Val) -> Result<Val> {
self.run_in_state(|| {
Ok(match val {
- Val::Func(func) => func.evaluate_map(
+ Val::Func(func) => push(None, || "during TLA call".to_owned(), || Ok(func.evaluate_map(
self.create_default_context()?,
&self.settings().tla_vars,
true,
- )?,
+ )?))?,
v => v,
})
})
crates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth1#[derive(Clone, PartialEq, Debug)]2pub struct CodeLocation {3 pub offset: usize,45 pub line: usize,6 pub column: usize,78 pub line_start_offset: usize,9 pub line_end_offset: usize,10}1112pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {13 if offsets.is_empty() {14 return vec![];15 }16 let mut line = 1;17 let mut column = 1;18 let max_offset = *offsets.iter().max().unwrap();1920 let mut offset_map = offsets21 .iter()22 .enumerate()23 .map(|(pos, offset)| (*offset, pos))24 .collect::<Vec<_>>();25 offset_map.sort_by_key(|v| v.0);26 offset_map.reverse();2728 let mut out = vec![29 CodeLocation {30 offset: 0,31 column: 0,32 line: 0,33 line_start_offset: 0,34 line_end_offset: 035 };36 offsets.len()37 ];38 let mut with_no_known_line_ending = vec![];39 let mut this_line_offset = 0;40 for (pos, ch) in file.chars().enumerate() {41 column += 1;42 match offset_map.last() {43 Some(x) if x.0 == pos => {44 let out_idx = x.1;45 with_no_known_line_ending.push(out_idx);46 out[out_idx].offset = pos;47 out[out_idx].line = line;48 out[out_idx].column = column;49 out[out_idx].line_start_offset = this_line_offset;50 offset_map.pop();51 }52 _ => {}53 }54 if ch == '\n' {55 line += 1;56 column = 1;5758 for idx in with_no_known_line_ending.drain(..) {59 out[idx].line_end_offset = pos;60 }61 this_line_offset = pos + 1;6263 if pos == max_offset + 1 {64 break;65 }66 }67 }68 let file_end = file.chars().count();69 for idx in with_no_known_line_ending {70 out[idx].line_end_offset = file_end;71 }7273 out74}7576#[cfg(test)]77pub mod tests {78 use super::{offset_to_location, CodeLocation};7980 #[test]81 fn test() {82 assert_eq!(83 offset_to_location(84 "hello world\n_______________________________________________________",85 &[0, 14]86 ),87 vec![88 CodeLocation {89 offset: 0,90 line: 1,91 column: 2,92 line_start_offset: 0,93 line_end_offset: 11,94 },95 CodeLocation {96 offset: 14,97 line: 2,98 column: 4,99 line_start_offset: 12,100 line_end_offset: 67101 }102 ]103 )104 }105}crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -118,21 +118,18 @@
.trace()
.0
.iter()
- .map(|el| {
- let resolved_path = self.resolver.resolve(&el.location.0);
+ .map(|el| el.location.as_ref().map(|l| {
+ use std::fmt::Write;
+ let mut resolved_path = self.resolver.resolve(&l.0);
// TODO: Process all trace elements first
let location = evaluation_state
- .map_source_locations(&el.location.0, &[el.location.1, el.location.2]);
- (resolved_path, location)
- })
- .map(|(mut n, location)| {
- use std::fmt::Write;
- write!(n, ":").unwrap();
- print_code_location(&mut n, &location[0], &location[1]).unwrap();
- n
- })
+ .map_source_locations(&l.0, &[l.1, l.2]);
+ write!(resolved_path, ":").unwrap();
+ print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();
+ resolved_path
+ }))
.collect::<Vec<_>>();
- let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);
+ let align = file_names.iter().flatten().map(|e| e.len()).max().unwrap_or(0);
for (i, (el, file)) in error.trace().0.iter().zip(file_names).enumerate() {
if i != 0 {
writeln!(out)?;
@@ -141,7 +138,7 @@
out,
"{:<p$}{:<w$}: {}",
"",
- file,
+ file.unwrap_or_else(|| "".to_owned()),
el.desc,
p = self.padding,
w = align
@@ -165,17 +162,24 @@
writeln!(out)?;
}
let desc = &item.desc;
- let source = item.location.clone();
- let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
+ if let Some (source) = &item.location {
+ let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
- write!(
- out,
- " at {} ({}:{}:{})",
- desc,
- source.0.to_str().unwrap(),
- start_end[0].line,
- start_end[0].column,
- )?;
+ write!(
+ out,
+ " at {} ({}:{}:{})",
+ desc,
+ source.0.to_str().unwrap(),
+ start_end[0].line,
+ start_end[0].column,
+ )?;
+ } else {
+ write!(
+ out,
+ " at {}",
+ desc,
+ )?;
+ }
}
Ok(())
}
@@ -225,17 +229,19 @@
let trace = &error.trace();
for item in trace.0.iter() {
let desc = &item.desc;
- let source = item.location.clone();
- let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
-
- self.print_snippet(
- out,
- &evaluation_state.get_source(&source.0).unwrap(),
- &source.0,
- &start_end[0],
- &start_end[1],
- desc,
- )?;
+ if let Some(source) = &item.location {
+ let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
+ self.print_snippet(
+ out,
+ &evaluation_state.get_source(&source.0).unwrap(),
+ &source.0,
+ &start_end[0],
+ &start_end[1],
+ desc,
+ )?;
+ } else {
+ write!(out, "{}", desc)?;
+ }
}
Ok(())
}