difftreelog
refactor extrace trace format to separate crate
in: master
4 files changed
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth11[dependencies]11[dependencies]12jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "1.0.0" }12jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "1.0.0" }13jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "1.0.0" }13jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "1.0.0" }14annotate-snippets = "0.8.0"14jrsonnet-trace = { path = "../../crates/jrsonnet-trace", version = "1.0.0" }15# TODO: Fix mimalloc compile errors, and use them15# TODO: Fix mimalloc compile errors, and use them16mimallocator = "0.1.3"16mimallocator = "0.1.3"171718[dependencies.clap]18[dependencies.clap]19version = "3.0.0-beta.1"19version = "3.0.0-beta.1"20default-features = false21features = ["std", "derive"]2220cmds/jrsonnet/src/main.rsdiffbeforeafterboth1use clap::Clap;1use clap::Clap;2use jrsonnet_evaluator::{trace::CodeLocation, EvaluationState, LocError, StackTrace, Val};2use jrsonnet_evaluator::Val;3use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParserSettings};3use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParserSettings};4use jrsonnet_trace::{CompactFormat, ExplainingFormat, PathResolver, TraceFormat};4use std::env::current_dir;5use std::env::current_dir;5use std::{collections::HashMap, path::PathBuf, rc::Rc, str::FromStr};6use std::{collections::HashMap, path::PathBuf, rc::Rc, str::FromStr};6726}27}272828#[derive(PartialEq)]29#[derive(PartialEq)]29enum TraceFormat {30enum TraceFormatName {30 CppJsonnet,31 Compact,31 GoJsonnet,32 Explaining,32 Custom,33}33}34impl FromStr for TraceFormat {34impl FromStr for TraceFormatName {35 type Err = &'static str;35 type Err = &'static str;36 fn from_str(s: &str) -> Result<Self, Self::Err> {36 fn from_str(s: &str) -> Result<Self, Self::Err> {37 Ok(match s {37 Ok(match s {38 "cpp" => TraceFormat::CppJsonnet,38 "compact" => TraceFormatName::Compact,39 "go" => TraceFormat::GoJsonnet,40 "default" => TraceFormat::Custom,39 "explaining" => TraceFormatName::Explaining,41 _ => return Err("no such format"),40 _ => return Err("no such format"),42 })41 })43 }42 }67}66}686769#[derive(Clap)]68#[derive(Clap)]70#[clap(version = "0.1.0", author = "Lach <iam@lach.pw>")]69#[clap(name = "jrsonnet", version, author)]71struct Opts {70pub struct Opts {72 #[clap(long, about = "Disable global std variable")]71 #[clap(long, about = "Disable global std variable")]73 no_stdlib: bool,72 no_stdlib: bool,74 #[clap(long, about = "Add external string", number_of_values = 1)]73 #[clap(long, about = "Add external string", number_of_values = 1)]81 tla_code: Vec<ExtStr>,80 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")]81 #[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,82 format: Format,84 #[clap(long, default_value = "default", possible_values = &["cpp", "go", "default"], about = "Emulated needed stacktrace display")]83 #[clap(long, default_value = "compact", possible_values = &["compact", "explaining"], about = "Choose format of displayed stacktraces")]85 trace_format: TraceFormat,84 trace_format: TraceFormatName,868587 #[clap(86 #[clap(88 long,87 long,150 evaluator.add_ext_var(name.into(), evaluator.parse_evaluate_raw(&value).unwrap());149 evaluator.add_ext_var(name.into(), evaluator.parse_evaluate_raw(&value).unwrap());151 }150 }151152 let resolver = PathResolver::Relative(std::env::current_dir().unwrap());153 let trace_format: Box<dyn TraceFormat> = match opts.trace_format {154 TraceFormatName::Compact => Box::new(CompactFormat { resolver }),155 TraceFormatName::Explaining => Box::new(ExplainingFormat { resolver }),156 };157152 let mut input = current_dir().unwrap();158 let mut input = current_dir().unwrap();153 input.push(opts.input.clone());159 input.push(opts.input.clone());154 let code_string = String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap();160 let code_string = String::from_utf8(std::fs::read(opts.input.clone()).unwrap()).unwrap();155 if let Err(e) = evaluator.add_file(Rc::new(input.clone()), code_string.clone().into()) {161 if let Err(e) = evaluator.add_file(Rc::new(input.clone()), code_string.into()) {156 print_syntax_error(e, &input, &code_string);162 trace_format.print_trace(&evaluator, &e).unwrap();157 std::process::exit(1);163 std::process::exit(1);158 }164 }159 let result = evaluator.evaluate_file(&input);165 let result = evaluator.evaluate_file(&input);191 };197 };192 let v = evaluator.run_in_state(|| match opts.format {198 let v = evaluator.run_in_state(|| match opts.format {193 Format::Json => Ok(Val::Str(v.into_json(opts.line_padding)?)),199 Format::Json => Ok(Val::Str(v.into_json(opts.line_padding)?)),194 Format::Yaml => {200 Format::Yaml => Ok(Val::Str(v.into_yaml(opts.line_padding)?)),195 evaluator.add_global("__tmp__to_yaml__".into(), v);196 evaluator.parse_evaluate_raw("std.manifestYamlDoc(__tmp__to_yaml__, \" \")")197 }198 _ => Ok(v),201 _ => Ok(v),199 });202 });200 let v = match v {203 let v = match v {201 Ok(v) => v,204 Ok(v) => v,202 Err(err) => {205 Err(err) => {203 print_error(&err, evaluator, &opts);206 trace_format.print_trace(&evaluator, &err).unwrap();204 std::process::exit(1);207 std::process::exit(1);205 }208 }206 };209 };213 }216 }214 }217 }215 Err(err) => {218 Err(err) => {216 print_error(&err, evaluator, &opts);219 trace_format.print_trace(&evaluator, &err).unwrap();217 std::process::exit(1);220 std::process::exit(1);218 }221 }219 }222 }220}223}221222fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {223 println!("Error: {:?}", err.0);224 print_trace(&(err.1), evaluator, &opts);225}226227fn print_syntax_error(error: jrsonnet_parser::ParseError, file: &PathBuf, code: &str) {228 use annotate_snippets::{229 display_list::{DisplayList, FormatOptions},230 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},231 };232 //&("Expected: ".to_owned() + error.expected)233 let origin = file.to_str().unwrap();234 let error_message = format!("Expected: {}", error.expected);235 let snippet = Snippet {236 opt: FormatOptions {237 color: true,238 ..Default::default()239 },240 title: Some(Annotation {241 label: Some(&error_message),242 id: None,243 annotation_type: AnnotationType::Error,244 }),245 footer: vec![],246 slices: vec![Slice {247 source: &code,248 line_start: 1,249 origin: Some(origin),250 fold: false,251 annotations: vec![SourceAnnotation {252 label: "At this position",253 annotation_type: AnnotationType::Error,254 range: (error.location.offset, error.location.offset + 1),255 }],256 }],257 };258259 let dl = DisplayList::from(snippet);260 println!("{}", dl);261}262263fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {264 use annotate_snippets::{265 display_list::{DisplayList, FormatOptions},266 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},267 };268 for item in trace.0.iter() {269 let desc = &item.1;270 let source = item.0.clone();271 let start_end = evaluator.map_source_locations(&source.0, &[source.1, source.2]);272 if opts.trace_format == TraceFormat::Custom {273 let source_fragment: String = evaluator274 .get_source(&source.0)275 .unwrap()276 .chars()277 .skip(start_end[0].line_start_offset)278 .take(start_end[1].line_end_offset - start_end[0].line_start_offset)279 .collect();280 let snippet = Snippet {281 opt: FormatOptions {282 color: true,283 ..Default::default()284 },285 title: Some(Annotation {286 label: Some(&item.1),287 id: None,288 annotation_type: AnnotationType::Error,289 }),290 footer: vec![],291 slices: vec![Slice {292 source: &source_fragment,293 line_start: start_end[0].line,294 origin: Some(&source.0.to_str().unwrap()),295 fold: false,296 annotations: vec![SourceAnnotation {297 label: desc,298 annotation_type: AnnotationType::Error,299 range: (300 source.1 - start_end[0].line_start_offset,301 source.2 - start_end[0].line_start_offset,302 ),303 }],304 }],305 };306307 let dl = DisplayList::from(snippet);308 println!("{}", dl);309 } else {310 print_jsonnet_pair(311 source.0.to_str().unwrap(),312 &start_end[0],313 &start_end[1],314 opts.trace_format == TraceFormat::GoJsonnet,315 );316 }317 }318}319320fn print_jsonnet_pair(file: &str, start: &CodeLocation, end: &CodeLocation, is_go: bool) {321 if is_go {322 print!(" ");323 } else {324 print!(" ");325 }326 print!("{}:", file);327 if start.line == end.line {328 // IDK why, but this is the behavior original jsonnet cpp impl shows329 if start.column == end.column || !is_go && start.column + 1 == end.column {330 println!("{}:{}", start.line, end.column)331 } else {332 println!("{}:{}-{}", start.line, start.column, end.column);333 }334 } else {335 println!(336 "({}:{})-({}:{})",337 start.line, end.column, start.line, end.column338 );339 }340}341224crates/jrsonnet-trace/Cargo.tomldiffbeforeafterbothno changes
crates/jrsonnet-trace/src/lib.rsdiffbeforeafterbothno changes