aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2016-11-29 23:13:19 -0800
committerbnewbold <bnewbold@robocracy.org>2016-11-29 23:23:06 -0800
commita4e33306fffe87cada79c8ba47d4172d39f3fba5 (patch)
tree82aaab103a35c306177fe4c5ba2dc63cdd48d03b /src
parent2eb8e3e5e3d3df5ccaf5d92cb5b53cbf321688d1 (diff)
downloadmodelthing-a4e33306fffe87cada79c8ba47d4172d39f3fba5.tar.gz
modelthing-a4e33306fffe87cada79c8ba47d4172d39f3fba5.zip
first pass at pretty-printing parser errors
Diffstat (limited to 'src')
-rw-r--r--src/bin/mt-tool.rs2
-rw-r--r--src/lib.rs60
2 files changed, 61 insertions, 1 deletions
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<String>) {
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<String> {
}
}
+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::<String>(),
+ std::iter::repeat("^").take(end - start).collect::<String>().red().bold());
+ }
+ line_start += line.len() + 1;
+ if line_start > end { break };
+ }
+ ret
+}
+
+pub fn pp_parseerror(raw: &str, pe: ParseError<usize, (usize, &str), ()>) -> 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]