From a4e33306fffe87cada79c8ba47d4172d39f3fba5 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Tue, 29 Nov 2016 23:13:19 -0800 Subject: first pass at pretty-printing parser errors --- Cargo.lock | 10 +++++++++ Cargo.toml | 6 ++++++ src/bin/mt-tool.rs | 2 +- src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index d78a4ff..14c1291 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,7 @@ name = "modelthing" version = "0.1.0" dependencies = [ + "colored 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -60,6 +61,14 @@ name = "buf-read-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "colored" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cookie" version = "0.2.5" @@ -774,6 +783,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum buf-read-ext 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc384072fac32fb50f4a327c33e2004897d11c561d008dd6031fb7f19b04de2c" +"checksum colored 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "585756a5d597a0ecdf9c963be84c6eb0e25a3590b535ac6f27e98254266b4f4c" "checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626" "checksum diff 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e48977eec6d3b7707462c2dc2e1363ad91b5dd822cf942537ccdc2085dc87587" "checksum difference 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ffef4c144e881a906ed5bd6e1e749dc1955cd3f0c7969d3d34122a971981c5ea" diff --git a/Cargo.toml b/Cargo.toml index 3266ce5..57aa54b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ log = "0.3" env_logger = "0.3" lalrpop-util = "^0.12.4" markdown = "0.1" +colored = "1.3" # parser util rustc-serialize = "0.3" @@ -21,3 +22,8 @@ docopt = "0.6" # webface pencil = "0.3" + + +[features] +# this effectively enables the feature `no-color` of colored when testing +test = ["colored/no-color"] diff --git a/src/bin/mt-tool.rs b/src/bin/mt-tool.rs index 03f590a..61db3fe 100644 --- a/src/bin/mt-tool.rs +++ b/src/bin/mt-tool.rs @@ -31,7 +31,7 @@ fn parse_modelica_files(paths: Vec) { match result { Ok(_) => println!("Input `{}` ({}s): OK", input, elapsed), - Err(err) => println!("Input `{}` ({}s): parse error {:?}", input, elapsed, err), + Err(err) => println!("Input `{}` ({}sec): ERROR\n{}", input, elapsed, modelthing::pp_parseerror(&s, err)), } } } diff --git a/src/lib.rs b/src/lib.rs index c733dc7..3f6021d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ extern crate log; extern crate toml; +extern crate colored; +extern crate lalrpop_util; pub mod modelica_parser; pub mod modelica_ast; @@ -14,6 +16,9 @@ use std::fs; use std::io::Read; use std::fs::File; +use lalrpop_util::ParseError; +use colored::*; + #[derive(Debug, PartialEq)] pub struct ModelMetadata { pub name_en: String, @@ -119,6 +124,61 @@ pub fn search_models(p: &Path) -> Vec { } } +fn pp_segment(raw: &str, start: usize, end: usize) -> String { + let mut line_start = 0; + let mut num = 0; + let mut ret = String::new(); + for line in raw.lines() { + num += 1; + let line_end = line_start + line.len(); + if (line_start <= start) && (start < line_end) { + ret += &format!(" {}\n{:>3} {} {}{}{}\n {} {}{}\n", + "|".blue().bold(), + num.to_string().blue().bold(), + "|".blue().bold(), + raw[line_start..start].normal(), + raw[start..end].red().bold(), + if end < line_end { + raw[end..line_end].normal() + } else { + "".normal() + }, + "|".blue().bold(), + std::iter::repeat(" ").take(start - line_start).collect::(), + std::iter::repeat("^").take(end - start).collect::().red().bold()); + } + line_start += line.len() + 1; + if line_start > end { break }; + } + ret +} + +pub fn pp_parseerror(raw: &str, pe: ParseError) -> String { + match pe { + ParseError::InvalidToken{location} => { + format!("{} invalid token starting at:\n{}", + "parse error:".red().bold(), + pp_segment(raw, location, location+1)) }, + ParseError::UnrecognizedToken{token: Some((start, (_, tok), end)), expected} => { + format!("{} unrecognized token '{}' (expected one of {:?}):\n{}", + "parse error:".red().bold(), + tok, + expected, + pp_segment(raw, start, end)) }, + ParseError::UnrecognizedToken{token: None, expected} => { + format!("{} premature end-of-file (expected one of {:?})", + "parse error:".red().bold(), + expected) }, + ParseError::ExtraToken{token: (start, (_, tok), end)} => { + format!("{} unexpected extra token '{}':\n{}", + "parse error:".red().bold(), + tok, + pp_segment(raw, start, end)) }, + _ => { + format!("{} {:?}", "parse error:".red().bold(), pe) }, + } +} + /* ******************************** Tests ******************************* */ #[test] -- cgit v1.2.3