git.delta.rocks / jrsonnet / refs/commits / be66091d566e

difftreelog

refactor merge trace to evaluator

Лач2020-07-19parent: #1820422.patch.diff
in: master

6 files changed

modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -9,7 +9,7 @@
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [features]
-default = ["serialized-stdlib", "faster"]
+default = ["serialized-stdlib", "faster", "explaining-traces"]
 # Serializes standard library AST instead of parsing them every run
 serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"]
 # Same as above, but with generated code instead of serde. Reduces memory usage, but increases binary size and compilation time
@@ -17,17 +17,32 @@
 # Replace some standard library functions with faster implementations (I.e manifestJsonEx)
 # Library works fine without this feature, but requires more memory and time for std function calls
 faster = []
+# Rustc-like trace visualization
+explaining-traces = ["annotate-snippets"]
 
 [dependencies]
 jrsonnet-parser = { path = "../jrsonnet-parser", version = "1.0.0" }
+jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "1.0.0" }
+pathdiff = "0.2.0"
+
 closure = "0.3.0"
-jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "1.0.0" }
 indexmap = "1.4.0"
+
 md5 = "0.7.0"
 base64 = "0.12.3"
 
-serde = { version = "1.0.114", optional = true }
-bincode = { version = "1.3.1", optional = true }
+# Serialized stdlib
+[dependencies.serde]
+version = "1.0.114"
+optional = true
+[dependencies.bincode]
+version = "1.3.1"
+optional = true
+
+# Explaining traces
+[dependencies.annotate-snippets]
+version = "0.9.0"
+optional = true
 
 [build-dependencies]
 jrsonnet-parser = { path = "../jrsonnet-parser", features = ["dump", "serialize", "deserialize"], version = "1.0.0" }
deletedcrates/jrsonnet-evaluator/src/trace.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/trace.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-#[derive(Clone, PartialEq, Debug)]
-pub struct CodeLocation {
-	pub line: usize,
-	pub column: usize,
-
-	pub line_start_offset: usize,
-	pub line_end_offset: usize,
-}
-
-pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {
-	if offsets.is_empty() {
-		return vec![];
-	}
-	let mut line = 1;
-	let mut column = 1;
-	let max_offset = *offsets.iter().max().unwrap();
-
-	let mut offset_map = offsets
-		.iter()
-		.enumerate()
-		.map(|(pos, offset)| (*offset, pos))
-		.collect::<Vec<_>>();
-	offset_map.sort_by_key(|v| v.0);
-	offset_map.reverse();
-
-	let mut out = vec![
-		CodeLocation {
-			column: 0,
-			line: 0,
-			line_start_offset: 0,
-			line_end_offset: 0
-		};
-		offsets.len()
-	];
-	let mut with_no_known_line_ending = vec![];
-	let mut this_line_offset = 0;
-	for (pos, ch) in file.chars().enumerate() {
-		column += 1;
-		match offset_map.last() {
-			Some(x) if x.0 == pos => {
-				let out_idx = x.1;
-				with_no_known_line_ending.push(out_idx);
-				out[out_idx].line = line;
-				out[out_idx].column = column;
-				out[out_idx].line_start_offset = this_line_offset;
-				offset_map.pop();
-			}
-			_ => {}
-		}
-		if ch == '\n' {
-			line += 1;
-			column = 1;
-
-			for idx in with_no_known_line_ending.drain(..) {
-				out[idx].line_end_offset = pos;
-			}
-			this_line_offset = pos + 1;
-
-			if pos == max_offset + 1 {
-				break;
-			}
-		}
-	}
-	let file_end = file.chars().count();
-	for idx in with_no_known_line_ending {
-		out[idx].line_end_offset = file_end;
-	}
-
-	out
-}
-
-#[cfg(test)]
-pub mod tests {
-	use super::{offset_to_location, CodeLocation};
-
-	#[test]
-	fn test() {
-		assert_eq!(
-			offset_to_location(
-				"hello world\n_______________________________________________________",
-				&[0, 14]
-			),
-			vec![
-				CodeLocation {
-					line: 1,
-					column: 1,
-					line_start_offset: 0,
-					line_end_offset: 11
-				},
-				CodeLocation {
-					line: 2,
-					column: 3,
-					line_start_offset: 11,
-					line_end_offset: 67
-				}
-			]
-		)
-	}
-}
addedcrates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-evaluator/src/trace/location.rs
@@ -0,0 +1,99 @@
+#[derive(Clone, PartialEq, Debug)]
+pub struct CodeLocation {
+	pub line: usize,
+	pub column: usize,
+
+	pub line_start_offset: usize,
+	pub line_end_offset: usize,
+}
+
+pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {
+	if offsets.is_empty() {
+		return vec![];
+	}
+	let mut line = 1;
+	let mut column = 1;
+	let max_offset = *offsets.iter().max().unwrap();
+
+	let mut offset_map = offsets
+		.iter()
+		.enumerate()
+		.map(|(pos, offset)| (*offset, pos))
+		.collect::<Vec<_>>();
+	offset_map.sort_by_key(|v| v.0);
+	offset_map.reverse();
+
+	let mut out = vec![
+		CodeLocation {
+			column: 0,
+			line: 0,
+			line_start_offset: 0,
+			line_end_offset: 0
+		};
+		offsets.len()
+	];
+	let mut with_no_known_line_ending = vec![];
+	let mut this_line_offset = 0;
+	for (pos, ch) in file.chars().enumerate() {
+		column += 1;
+		match offset_map.last() {
+			Some(x) if x.0 == pos => {
+				let out_idx = x.1;
+				with_no_known_line_ending.push(out_idx);
+				out[out_idx].line = line;
+				out[out_idx].column = column;
+				out[out_idx].line_start_offset = this_line_offset;
+				offset_map.pop();
+			}
+			_ => {}
+		}
+		if ch == '\n' {
+			line += 1;
+			column = 1;
+
+			for idx in with_no_known_line_ending.drain(..) {
+				out[idx].line_end_offset = pos;
+			}
+			this_line_offset = pos + 1;
+
+			if pos == max_offset + 1 {
+				break;
+			}
+		}
+	}
+	let file_end = file.chars().count();
+	for idx in with_no_known_line_ending {
+		out[idx].line_end_offset = file_end;
+	}
+
+	out
+}
+
+#[cfg(test)]
+pub mod tests {
+	use super::{offset_to_location, CodeLocation};
+
+	#[test]
+	fn test() {
+		assert_eq!(
+			offset_to_location(
+				"hello world\n_______________________________________________________",
+				&[0, 14]
+			),
+			vec![
+				CodeLocation {
+					line: 1,
+					column: 1,
+					line_start_offset: 0,
+					line_end_offset: 11
+				},
+				CodeLocation {
+					line: 2,
+					column: 3,
+					line_start_offset: 11,
+					line_end_offset: 67
+				}
+			]
+		)
+	}
+}
addedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
after · crates/jrsonnet-evaluator/src/trace/mod.rs
1mod location;23use crate::{EvaluationState, LocError};4pub use location::*;5use std::path::PathBuf;67/// How paths should be displayed8pub enum PathResolver {9	/// Only filename will be shown10	FileName,11	/// Absolute path of file12	Absolute,13	/// Relative path from base directory14	Relative(PathBuf),15}1617impl PathResolver {18	pub fn resolve(&self, from: &PathBuf) -> String {19		match self {20			PathResolver::FileName => from.file_name().unwrap().to_string_lossy().into_owned(),21			PathResolver::Absolute => from.to_string_lossy().into_owned(),22			PathResolver::Relative(base) => {23				if from.is_relative() {24					return from.to_string_lossy().into_owned();25				}26				pathdiff::diff_paths(from, base)27					.unwrap()28					.to_string_lossy()29					.into_owned()30			}31		}32	}33}3435/// Implements trace to string pretty-printing36pub trait TraceFormat {37	fn write_trace(38		&self,39		out: &mut dyn std::fmt::Write,40		evaluation_state: &EvaluationState,41		error: &LocError,42	) -> Result<(), std::fmt::Error>;43	// fn print_trace(44	// 	&self,45	// 	evaluation_state: &EvaluationState,46	// 	error: &LocError,47	// ) -> Result<(), std::fmt::Error> {48	// 	self.write_trace(&mut std::fmt::stdout(), evaluation_state, error)49	// }50}5152fn print_code_location(53	out: &mut impl std::fmt::Write,54	start: &CodeLocation,55	end: &CodeLocation,56) -> Result<(), std::fmt::Error> {57	if start.line == end.line {58		if start.column == end.column {59			write!(out, "{}:{}", start.line, end.column - 1)?;60		} else {61			write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;62		}63	} else {64		write!(65			out,66			"{}:{}-{}:{}",67			start.line,68			end.column - 1,69			start.line,70			end.column71		)?;72	}73	Ok(())74}7576/// vanilla jsonnet like formatting77pub struct CompactFormat {78	pub resolver: PathResolver,79	pub padding: usize,80}8182impl TraceFormat for CompactFormat {83	fn write_trace(84		&self,85		out: &mut dyn std::fmt::Write,86		evaluation_state: &EvaluationState,87		error: &LocError,88	) -> Result<(), std::fmt::Error> {89		writeln!(out, "{:?}", error.0)?;90		let file_names = (error.1)91			.092			.iter()93			.map(|el| {94				let resolved_path = self.resolver.resolve(&el.location.0);95				// TODO: Process all trace elements first96				let location = evaluation_state97					.map_source_locations(&el.location.0, &[el.location.1, el.location.2]);98				(resolved_path, location)99			})100			.map(|(mut n, location)| {101				use std::fmt::Write;102				write!(n, ":").unwrap();103				print_code_location(&mut n, &location[0], &location[1]).unwrap();104				n105			})106			.collect::<Vec<_>>();107		let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);108		for (i, (el, file)) in (error.1).0.iter().zip(file_names).enumerate() {109			if i != 0 {110				writeln!(out)?;111			}112			write!(113				out,114				"{:<p$}{:<w$}: {}",115				"",116				file,117				el.desc,118				p = self.padding,119				w = align120			)?;121		}122		Ok(())123	}124}125126pub struct JSFormat;127impl TraceFormat for JSFormat {128	fn write_trace(129		&self,130		out: &mut dyn std::fmt::Write,131		evaluation_state: &EvaluationState,132		error: &LocError,133	) -> Result<(), std::fmt::Error> {134		writeln!(out, "{:?}", error.0)?;135		for (i, item) in (error.1).0.iter().enumerate() {136			if i != 0 {137				writeln!(out)?;138			}139			let desc = &item.desc;140			let source = item.location.clone();141			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);142143			write!(144				out,145				"    at {} ({}:{}:{})",146				desc,147				source.0.to_str().unwrap(),148				start_end[0].line,149				start_end[0].column,150			)?;151		}152		Ok(())153	}154}155156/// rustc-like trace displaying157#[cfg(feature = "explaining-traces")]158pub struct ExplainingFormat {159	pub resolver: PathResolver,160}161#[cfg(feature = "explaining-traces")]162impl TraceFormat for ExplainingFormat {163	fn write_trace(164		&self,165		out: &mut dyn std::fmt::Write,166		evaluation_state: &EvaluationState,167		error: &LocError,168	) -> Result<(), std::fmt::Error> {169		use annotate_snippets::{170			display_list::{DisplayList, FormatOptions},171			snippet::{AnnotationType, Slice, Snippet, SourceAnnotation},172		};173		writeln!(out, "{:?}", error.0)?;174		let trace = &error.1;175		for item in trace.0.iter() {176			let desc = &item.desc;177			let source = item.location.clone();178			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);179180			let source_fragment: String = evaluation_state181				.get_source(&source.0)182				.unwrap()183				.chars()184				.skip(start_end[0].line_start_offset)185				.take(start_end[1].line_end_offset - start_end[0].line_start_offset)186				.collect();187188			let origin = self.resolver.resolve(&source.0);189			let snippet = Snippet {190				opt: FormatOptions {191					color: true,192					..Default::default()193				},194				title: None,195				footer: vec![],196				slices: vec![Slice {197					source: &source_fragment,198					line_start: start_end[0].line,199					origin: Some(&origin),200					fold: false,201					annotations: vec![SourceAnnotation {202						label: desc,203						annotation_type: AnnotationType::Error,204						range: (205							source.1 - start_end[0].line_start_offset,206							source.2 - start_end[0].line_start_offset,207						),208					}],209				}],210			};211212			let dl = DisplayList::from(snippet);213			writeln!(out, "{}", dl)?;214		}215		Ok(())216	}217}
deletedcrates/jrsonnet-trace/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-trace/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "jrsonnet-trace"
-version = "1.0.0"
-authors = ["Лач <iam@lach.pw>"]
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-jrsonnet-evaluator = { path = "../jrsonnet-evaluator", version = "1.0.0" }
-jrsonnet-parser = { path = "../jrsonnet-parser", version = "1.0.0" }
-pathdiff = "0.2.0"
-annotate-snippets = "0.9.0"
deletedcrates/jrsonnet-trace/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-trace/src/lib.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-use jrsonnet_evaluator::{trace::CodeLocation, EvaluationState, LocError};
-use std::path::PathBuf;
-
-/// How paths should be displayed
-pub enum PathResolver {
-	/// Only filename will be shown
-	FileName,
-	/// Absolute path of file
-	Absolute,
-	/// Relative path from base directory
-	Relative(PathBuf),
-}
-
-impl PathResolver {
-	pub fn resolve(&self, from: &PathBuf) -> String {
-		match self {
-			PathResolver::FileName => from.file_name().unwrap().to_string_lossy().into_owned(),
-			PathResolver::Absolute => from.to_string_lossy().into_owned(),
-			PathResolver::Relative(base) => {
-				if from.is_relative() {
-					return from.to_string_lossy().into_owned();
-				}
-				pathdiff::diff_paths(from, base)
-					.unwrap()
-					.to_string_lossy()
-					.into_owned()
-			}
-		}
-	}
-}
-
-/// Implements trace to string pretty-printing
-pub trait TraceFormat {
-	fn write_trace(
-		&self,
-		out: &mut dyn std::io::Write,
-		evaluation_state: &EvaluationState,
-		error: &LocError,
-	) -> Result<(), std::io::Error>;
-	fn print_trace(
-		&self,
-		evaluation_state: &EvaluationState,
-		error: &LocError,
-	) -> Result<(), std::io::Error> {
-		self.write_trace(&mut std::io::stdout(), evaluation_state, error)
-	}
-}
-
-fn print_code_location(
-	out: &mut impl std::fmt::Write,
-	start: &CodeLocation,
-	end: &CodeLocation,
-) -> Result<(), std::fmt::Error> {
-	if start.line == end.line {
-		if start.column == end.column {
-			write!(out, "{}:{}", start.line, end.column - 1)?;
-		} else {
-			write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;
-		}
-	} else {
-		write!(
-			out,
-			"{}:{}-{}:{}",
-			start.line,
-			end.column - 1,
-			start.line,
-			end.column
-		)?;
-	}
-	Ok(())
-}
-
-/// vanilla jsonnet like formatting
-pub struct CompactFormat {
-	pub resolver: PathResolver,
-}
-
-impl TraceFormat for CompactFormat {
-	fn write_trace(
-		&self,
-		out: &mut dyn std::io::Write,
-		evaluation_state: &EvaluationState,
-		error: &LocError,
-	) -> Result<(), std::io::Error> {
-		writeln!(out, "{:?}", error.0)?;
-		let file_names = (error.1)
-			.0
-			.iter()
-			.map(|el| {
-				let resolved_path = self.resolver.resolve(&(el.0).0);
-				// TODO: Process all trace elements first
-				let location =
-					evaluation_state.map_source_locations(&(el.0).0, &[(el.0).1, (el.0).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
-			})
-			.collect::<Vec<_>>();
-		let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);
-		for (i, (el, file)) in (error.1).0.iter().zip(file_names).enumerate() {
-			if i != 0 {
-				writeln!(out)?;
-			}
-			write!(out, "{:<w$}: {}", file, el.1, w = align)?;
-		}
-		Ok(())
-	}
-}
-
-/// rustc-like trace displaying
-pub struct ExplainingFormat {
-	pub resolver: PathResolver,
-}
-impl TraceFormat for ExplainingFormat {
-	fn write_trace(
-		&self,
-		out: &mut dyn std::io::Write,
-		evaluation_state: &EvaluationState,
-		error: &LocError,
-	) -> Result<(), std::io::Error> {
-		use annotate_snippets::{
-			display_list::{DisplayList, FormatOptions},
-			snippet::{AnnotationType, Slice, Snippet, SourceAnnotation},
-		};
-		writeln!(out, "{:?}", error.0)?;
-		let trace = &error.1;
-		for item in trace.0.iter() {
-			let desc = &item.1;
-			let source = item.0.clone();
-			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
-
-			let source_fragment: String = evaluation_state
-				.get_source(&source.0)
-				.unwrap()
-				.chars()
-				.skip(start_end[0].line_start_offset)
-				.take(start_end[1].line_end_offset - start_end[0].line_start_offset)
-				.collect();
-
-			let origin = self.resolver.resolve(&source.0);
-			let snippet = Snippet {
-				opt: FormatOptions {
-					color: true,
-					..Default::default()
-				},
-				title: None,
-				footer: vec![],
-				slices: vec![Slice {
-					source: &source_fragment,
-					line_start: start_end[0].line,
-					origin: Some(&origin),
-					fold: false,
-					annotations: vec![SourceAnnotation {
-						label: desc,
-						annotation_type: AnnotationType::Error,
-						range: (
-							source.1 - start_end[0].line_start_offset,
-							source.2 - start_end[0].line_start_offset,
-						),
-					}],
-				}],
-			};
-
-			let dl = DisplayList::from(snippet);
-			writeln!(out, "{}", dl)?;
-		}
-		Ok(())
-	}
-}