git.delta.rocks / jrsonnet / refs/commits / 0d591aa205cc

difftreelog

feat locationless stack frames

Yaroslav Bolyukin2021-01-25parent: #a682d0e.patch.diff
in: master

4 files changed

modifiedcrates/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)]
modifiedcrates/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,
 			})
 		})
modifiedcrates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/trace/location.rs
1#[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}
after · crates/jrsonnet-evaluator/src/trace/location.rs
1#[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().chain(std::iter::once((file.len(), ' '))) {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}
modifiedcrates/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(())
 	}