git.delta.rocks / jrsonnet / refs/commits / 06bf1b38ec36

difftreelog

refactor remove trace format from state

Yaroslav Bolyukin2022-11-09parent: #78be616.patch.diff
in: master

5 files changed

modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
before · cmds/jrsonnet/src/main.rs
1use std::{2	fs::{create_dir_all, File},3	io::{Read, Write},4};56use clap::{CommandFactory, Parser};7use clap_complete::Shell;8use jrsonnet_cli::{ConfigureState, GeneralOpts, ManifestOpts, OutputOpts, TraceOpts};9use jrsonnet_evaluator::{apply_tla, error::LocError, throw, ResultExt, State, Val};1011#[cfg(feature = "mimalloc")]12#[global_allocator]13static GLOBAL: mimallocator::Mimalloc = mimallocator::Mimalloc;1415#[derive(Parser)]16enum SubOpts {17	/// Generate completions for specified shell18	Generate {19		/// Target shell name20		shell: Shell,21	},22}2324#[derive(Parser)]25#[clap(next_help_heading = "DEBUG")]26struct DebugOpts {27	/// Required OS stack size.28	/// This shouldn't be changed unless jrsonnet is failing with stack overflow error.29	#[clap(long, name = "size")]30	pub os_stack: Option<usize>,31}3233#[derive(Parser)]34#[clap(next_help_heading = "INPUT")]35struct InputOpts {36	/// Treat input as code, evaluate them instead of reading file37	#[clap(long, short = 'e')]38	pub exec: bool,3940	/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself41	pub input: Option<String>,42}4344#[derive(Parser)]45#[clap(args_conflicts_with_subcommands = true, disable_version_flag = true)]46struct Opts {47	#[clap(subcommand)]48	sub: Option<SubOpts>,4950	#[clap(flatten)]51	input: InputOpts,52	#[clap(flatten)]53	general: GeneralOpts,54	#[clap(flatten)]55	manifest: ManifestOpts,56	#[clap(flatten)]57	output: OutputOpts,58	#[clap(flatten)]59	debug: DebugOpts,60}6162fn main() {63	let opts: Opts = Opts::parse();6465	if let Some(sub) = opts.sub {66		match sub {67			SubOpts::Generate { shell } => {68				use clap_complete::generate;69				let app = &mut Opts::command();70				let buf = &mut std::io::stdout();71				generate(shell, app, "jrsonnet", buf);72				std::process::exit(0)73			}74		}75	}7677	let success = if let Some(size) = opts.debug.os_stack {78		std::thread::Builder::new()79			.stack_size(size * 1024 * 1024)80			.spawn(|| main_catch(opts))81			.expect("new thread spawned")82			.join()83			.expect("thread finished successfully")84	} else {85		main_catch(opts)86	};87	if !success {88		std::process::exit(1);89	}90}9192#[derive(thiserror::Error, Debug)]93enum Error {94	// Handled differently95	#[error("evaluation error")]96	Evaluation(LocError),97	#[error("io error")]98	Io(#[from] std::io::Error),99	#[error("input is not utf8 encoded")]100	Utf8(#[from] std::str::Utf8Error),101	#[error("missing input argument")]102	MissingInputArgument,103}104impl From<LocError> for Error {105	fn from(e: LocError) -> Self {106		Self::Evaluation(e)107	}108}109impl From<jrsonnet_evaluator::error::Error> for Error {110	fn from(e: jrsonnet_evaluator::error::Error) -> Self {111		Self::from(LocError::from(e))112	}113}114115fn main_catch(opts: Opts) -> bool {116	let s = State::default();117	if let Err(e) = main_real(&s, opts) {118		if let Error::Evaluation(e) = e {119			eprintln!("{}", s.stringify_err(&e));120		} else {121			eprintln!("{}", e);122		}123		return false;124	}125	true126}127128fn main_real(s: &State, opts: Opts) -> Result<(), Error> {129	let (_stack_guard, tla, _gc_guard) = opts.general.configure(s)?;130	let manifest_format = opts.manifest.configure(s)?;131132	let input = opts.input.input.ok_or(Error::MissingInputArgument)?;133	let val = if opts.input.exec {134		s.evaluate_snippet("<cmdline>".to_owned(), &input as &str)?135	} else if input == "-" {136		let mut input = Vec::new();137		std::io::stdin().read_to_end(&mut input)?;138		let input_str = std::str::from_utf8(&input)?;139		s.evaluate_snippet("<stdin>".to_owned(), input_str)?140	} else {141		s.import(&input)?142	};143144	let val = apply_tla(s.clone(), &tla, val)?;145146	if let Some(multi) = opts.output.multi {147		if opts.output.create_output_dirs {148			let mut dir = multi.clone();149			dir.pop();150			create_dir_all(dir)?;151		}152		let Val::Obj(obj) = val else {153			throw!("value should be object for --multi manifest, got {}", val.value_type())154		};155		for (field, data) in obj.iter(156			#[cfg(feature = "exp-preserve-order")]157			opts.manifest.preserve_order,158		) {159			let data = data.with_description(|| format!("getting field {field} for manifest"))?;160161			let mut path = multi.clone();162			path.push(&field as &str);163			if opts.output.create_output_dirs {164				let mut dir = path.clone();165				dir.pop();166				create_dir_all(dir)?;167			}168			println!("{}", path.to_str().expect("path"));169			let mut file = File::create(path)?;170			writeln!(171				file,172				"{}",173				data.manifest(&manifest_format)174					.with_description(|| format!("manifesting {field}"))?175			)?;176		}177	} else if let Some(path) = opts.output.output_file {178		if opts.output.create_output_dirs {179			let mut dir = path.clone();180			dir.pop();181			create_dir_all(dir)?;182		}183		let mut file = File::create(path)?;184		writeln!(file, "{}", val.manifest(manifest_format)?)?;185	} else {186		let output = val.manifest(manifest_format)?;187		if !output.is_empty() {188			println!("{}", output);189		}190	}191192	Ok(())193}
after · cmds/jrsonnet/src/main.rs
1use std::{2	fs::{create_dir_all, File},3	io::{Read, Write},4};56use clap::{CommandFactory, Parser};7use clap_complete::Shell;8use jrsonnet_cli::{ConfigureState, GeneralOpts, ManifestOpts, OutputOpts, TraceOpts};9use jrsonnet_evaluator::{apply_tla, error::LocError, throw, ResultExt, State, Val};1011#[cfg(feature = "mimalloc")]12#[global_allocator]13static GLOBAL: mimallocator::Mimalloc = mimallocator::Mimalloc;1415#[derive(Parser)]16enum SubOpts {17	/// Generate completions for specified shell18	Generate {19		/// Target shell name20		shell: Shell,21	},22}2324#[derive(Parser)]25#[clap(next_help_heading = "DEBUG")]26struct DebugOpts {27	/// Required OS stack size.28	/// This shouldn't be changed unless jrsonnet is failing with stack overflow error.29	#[clap(long, name = "size")]30	pub os_stack: Option<usize>,31}3233#[derive(Parser)]34#[clap(next_help_heading = "INPUT")]35struct InputOpts {36	/// Treat input as code, evaluate them instead of reading file37	#[clap(long, short = 'e')]38	pub exec: bool,3940	/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself41	pub input: Option<String>,42}4344#[derive(Parser)]45#[clap(args_conflicts_with_subcommands = true, disable_version_flag = true)]46struct Opts {47	#[clap(subcommand)]48	sub: Option<SubOpts>,4950	#[clap(flatten)]51	input: InputOpts,52	#[clap(flatten)]53	general: GeneralOpts,5455	#[clap(flatten)]56	trace: TraceOpts,57	#[clap(flatten)]58	manifest: ManifestOpts,59	#[clap(flatten)]60	output: OutputOpts,61	#[clap(flatten)]62	debug: DebugOpts,63}6465fn main() {66	let opts: Opts = Opts::parse();6768	if let Some(sub) = opts.sub {69		match sub {70			SubOpts::Generate { shell } => {71				use clap_complete::generate;72				let app = &mut Opts::command();73				let buf = &mut std::io::stdout();74				generate(shell, app, "jrsonnet", buf);75				std::process::exit(0)76			}77		}78	}7980	let success = if let Some(size) = opts.debug.os_stack {81		std::thread::Builder::new()82			.stack_size(size * 1024 * 1024)83			.spawn(|| main_catch(opts))84			.expect("new thread spawned")85			.join()86			.expect("thread finished successfully")87	} else {88		main_catch(opts)89	};90	if !success {91		std::process::exit(1);92	}93}9495#[derive(thiserror::Error, Debug)]96enum Error {97	// Handled differently98	#[error("evaluation error")]99	Evaluation(LocError),100	#[error("io error")]101	Io(#[from] std::io::Error),102	#[error("input is not utf8 encoded")]103	Utf8(#[from] std::str::Utf8Error),104	#[error("missing input argument")]105	MissingInputArgument,106}107impl From<LocError> for Error {108	fn from(e: LocError) -> Self {109		Self::Evaluation(e)110	}111}112impl From<jrsonnet_evaluator::error::Error> for Error {113	fn from(e: jrsonnet_evaluator::error::Error) -> Self {114		Self::from(LocError::from(e))115	}116}117118fn main_catch(opts: Opts) -> bool {119	let s = State::default();120	let trace = opts121		.trace122		.configure(&s)123		.expect("this configurator doesn't fail");124	if let Err(e) = main_real(&s, opts) {125		if let Error::Evaluation(e) = e {126			let mut out = String::new();127			trace.write_trace(&mut out, &e).expect("format error");128			eprintln!("{out}")129		} else {130			eprintln!("{}", e);131		}132		return false;133	}134	true135}136137fn main_real(s: &State, opts: Opts) -> Result<(), Error> {138	let (_stack_guard, tla, _gc_guard) = opts.general.configure(s)?;139	let manifest_format = opts.manifest.configure(s)?;140141	let input = opts.input.input.ok_or(Error::MissingInputArgument)?;142	let val = if opts.input.exec {143		s.evaluate_snippet("<cmdline>".to_owned(), &input as &str)?144	} else if input == "-" {145		let mut input = Vec::new();146		std::io::stdin().read_to_end(&mut input)?;147		let input_str = std::str::from_utf8(&input)?;148		s.evaluate_snippet("<stdin>".to_owned(), input_str)?149	} else {150		s.import(&input)?151	};152153	let val = apply_tla(s.clone(), &tla, val)?;154155	if let Some(multi) = opts.output.multi {156		if opts.output.create_output_dirs {157			let mut dir = multi.clone();158			dir.pop();159			create_dir_all(dir)?;160		}161		let Val::Obj(obj) = val else {162			throw!("value should be object for --multi manifest, got {}", val.value_type())163		};164		for (field, data) in obj.iter(165			#[cfg(feature = "exp-preserve-order")]166			opts.manifest.preserve_order,167		) {168			let data = data.with_description(|| format!("getting field {field} for manifest"))?;169170			let mut path = multi.clone();171			path.push(&field as &str);172			if opts.output.create_output_dirs {173				let mut dir = path.clone();174				dir.pop();175				create_dir_all(dir)?;176			}177			println!("{}", path.to_str().expect("path"));178			let mut file = File::create(path)?;179			writeln!(180				file,181				"{}",182				data.manifest(&manifest_format)183					.with_description(|| format!("manifesting {field}"))?184			)?;185		}186	} else if let Some(path) = opts.output.output_file {187		if opts.output.create_output_dirs {188			let mut dir = path.clone();189			dir.pop();190			create_dir_all(dir)?;191		}192		let mut file = File::create(path)?;193		writeln!(file, "{}", val.manifest(manifest_format)?)?;194	} else {195		let output = val.manifest(manifest_format)?;196		if !output.is_empty() {197			println!("{}", output);198		}199	}200201	Ok(())202}
modifiedcrates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-cli/src/lib.rs
+++ b/crates/jrsonnet-cli/src/lib.rs
@@ -76,9 +76,6 @@
 	std: StdOpts,
 
 	#[clap(flatten)]
-	trace: TraceOpts,
-
-	#[clap(flatten)]
 	gc: GcOpts,
 }
 
@@ -90,7 +87,6 @@
 	);
 	fn configure(&self, s: &State) -> Result<Self::Guards> {
 		// Configure trace first, because tla-code/ext-code can throw
-		self.trace.configure(s)?;
 		let misc_guards = self.misc.configure(s)?;
 		let tla_guards = self.tla.configure(s)?;
 		self.std.configure(s)?;
modifiedcrates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth
--- a/crates/jrsonnet-cli/src/trace.rs
+++ b/crates/jrsonnet-cli/src/trace.rs
@@ -1,7 +1,7 @@
 use clap::{Parser, ValueEnum};
 use jrsonnet_evaluator::{
 	error::Result,
-	trace::{CompactFormat, ExplainingFormat, PathResolver},
+	trace::{CompactFormat, ExplainingFormat, PathResolver, TraceFormat},
 	State,
 };
 
@@ -27,21 +27,25 @@
 	max_trace: usize,
 }
 impl ConfigureState for TraceOpts {
-	type Guards = ();
-	fn configure(&self, s: &State) -> Result<()> {
+	type Guards = Box<dyn TraceFormat>;
+	fn configure(&self, _s: &State) -> Result<Self::Guards> {
 		let resolver = PathResolver::new_cwd_fallback();
-		match self
+		let max_trace = self.max_trace;
+		let format: Box<dyn TraceFormat> = match self
 			.trace_format
 			.as_ref()
 			.unwrap_or(&TraceFormatName::Compact)
 		{
-			TraceFormatName::Compact => s.set_trace_format(CompactFormat {
+			TraceFormatName::Compact => Box::new(CompactFormat {
 				resolver,
 				padding: 4,
+				max_trace,
 			}),
-			TraceFormatName::Explaining => s.set_trace_format(ExplainingFormat { resolver }),
-		}
-		s.set_max_trace(self.max_trace);
-		Ok(())
+			TraceFormatName::Explaining => Box::new(ExplainingFormat {
+				resolver,
+				max_trace,
+			}),
+		};
+		Ok(format)
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -262,7 +262,6 @@
 			write!(f, "\t{}", el.desc)?;
 			if let Some(loc) = &el.location {
 				write!(f, "at {}", loc.0 .0 .0)?;
-				// loc.0
 				loc.0.map_source_locations(&[loc.1, loc.2]);
 			}
 			writeln!(f)?;
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -1,9 +1,12 @@
-use std::path::{Path, PathBuf};
+use std::{
+	any::Any,
+	path::{Path, PathBuf},
+};
 
 use jrsonnet_gcmodule::Trace;
 use jrsonnet_parser::{CodeLocation, Source};
 
-use crate::{error::Error, LocError, State};
+use crate::{error::Error, LocError};
 
 /// The way paths should be displayed
 #[derive(Clone, Trace)]
@@ -48,9 +51,15 @@
 	fn write_trace(
 		&self,
 		out: &mut dyn std::fmt::Write,
-		s: &State,
 		error: &LocError,
 	) -> Result<(), std::fmt::Error>;
+	fn format(&self, error: &LocError) -> Result<String, std::fmt::Error> {
+		let mut out = String::new();
+		self.write_trace(&mut out, error)?;
+		Ok(out)
+	}
+	fn as_any(&self) -> &dyn Any;
+	fn as_any_mut(&mut self) -> &mut dyn Any;
 }
 
 fn print_code_location(
@@ -81,14 +90,23 @@
 #[derive(Trace)]
 pub struct CompactFormat {
 	pub resolver: PathResolver,
+	pub max_trace: usize,
 	pub padding: usize,
 }
+impl Default for CompactFormat {
+	fn default() -> Self {
+		Self {
+			resolver: PathResolver::Absolute,
+			max_trace: 20,
+			padding: 4,
+		}
+	}
+}
 
 impl TraceFormat for CompactFormat {
 	fn write_trace(
 		&self,
 		out: &mut dyn std::fmt::Write,
-		_s: &State,
 		error: &LocError,
 	) -> Result<(), std::fmt::Error> {
 		write!(out, "{}", error.error())?;
@@ -168,15 +186,24 @@
 		}
 		Ok(())
 	}
+
+	fn as_any(&self) -> &dyn Any {
+		self
+	}
+
+	fn as_any_mut(&mut self) -> &mut dyn Any {
+		self
+	}
 }
 
 #[derive(Trace)]
-pub struct JsFormat;
+pub struct JsFormat {
+	pub max_trace: usize,
+}
 impl TraceFormat for JsFormat {
 	fn write_trace(
 		&self,
 		out: &mut dyn std::fmt::Write,
-		_s: &State,
 		error: &LocError,
 	) -> Result<(), std::fmt::Error> {
 		write!(out, "{}", error.error())?;
@@ -201,6 +228,14 @@
 		}
 		Ok(())
 	}
+
+	fn as_any(&self) -> &dyn Any {
+		self
+	}
+
+	fn as_any_mut(&mut self) -> &mut dyn Any {
+		self
+	}
 }
 
 /// rustc-like trace displaying
@@ -208,13 +243,13 @@
 #[derive(Trace)]
 pub struct ExplainingFormat {
 	pub resolver: PathResolver,
+	pub max_trace: usize,
 }
 #[cfg(feature = "explaining-traces")]
 impl TraceFormat for ExplainingFormat {
 	fn write_trace(
 		&self,
 		out: &mut dyn std::fmt::Write,
-		_s: &State,
 		error: &LocError,
 	) -> Result<(), std::fmt::Error> {
 		write!(out, "{}", error.error())?;
@@ -258,6 +293,14 @@
 		}
 		Ok(())
 	}
+
+	fn as_any(&self) -> &dyn Any {
+		self
+	}
+
+	fn as_any_mut(&mut self) -> &mut dyn Any {
+		self
+	}
 }
 
 impl ExplainingFormat {