git.delta.rocks / jrsonnet / refs/commits / 458a1bc63c56

difftreelog

refactor extrace trace format to separate crate

Лач2020-07-16parent: #3b3945f.patch.diff
in: master

4 files changed

modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
11[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 them
16mimallocator = "0.1.3"16mimallocator = "0.1.3"
1717
18[dependencies.clap]18[dependencies.clap]
19version = "3.0.0-beta.1"19version = "3.0.0-beta.1"
20default-features = false
21features = ["std", "derive"]
2220
modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
1use 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};
67
26}27}
2728
28#[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}
6867
69#[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,
8685
87 #[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 }
151
152 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 };
157
152 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}
221
222fn print_error(err: &LocError, evaluator: EvaluationState, opts: &Opts) {
223 println!("Error: {:?}", err.0);
224 print_trace(&(err.1), evaluator, &opts);
225}
226
227fn 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 };
258
259 let dl = DisplayList::from(snippet);
260 println!("{}", dl);
261}
262
263fn 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 = evaluator
274 .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 };
306
307 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}
319
320fn 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 shows
329 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.column
338 );
339 }
340}
341224
addedcrates/jrsonnet-trace/Cargo.tomldiffbeforeafterboth

no changes

addedcrates/jrsonnet-trace/src/lib.rsdiffbeforeafterboth

no changes