From 63d9cd178954a65bd0616ff75164de9872004197 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 10 Jan 2022 00:57:02 -0500 Subject: improve parsing error messages --- src/parse.rs | 43 +++++++++++++++++++++++++++++++++++++++---- src/parse/ast.rs | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 7abc525..09cdb91 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -102,11 +102,11 @@ impl Direction { #[derive(Debug)] pub struct Error { input: String, - e: anyhow::Error, + e: pest::error::Error, } impl Error { - fn new(input: &str, e: anyhow::Error) -> Self { + fn new(input: &str, e: pest::error::Error) -> Self { Self { input: input.to_string(), e, @@ -116,12 +116,47 @@ impl Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse {}: {}", self.input, self.e) + match &self.e.variant { + pest::error::ErrorVariant::ParsingError { + positives, + negatives, + } => { + if !positives.is_empty() { + write!(f, "expected {:?}", positives[0])?; + for rule in &positives[1..] { + write!(f, ", {:?}", rule)?; + } + if !negatives.is_empty() { + write!(f, "; ")?; + } + } + if !negatives.is_empty() { + write!(f, "unexpected {:?}", negatives[0])?; + for rule in &negatives[1..] { + write!(f, ", {:?}", rule)?; + } + } + writeln!(f)?; + writeln!(f, "{}", self.input)?; + match &self.e.location { + pest::error::InputLocation::Pos(i) => { + write!(f, "{}^", " ".repeat(*i))?; + } + pest::error::InputLocation::Span((i, j)) => { + write!(f, "{}{}", " ".repeat(*i), "^".repeat(j - i))?; + } + } + } + pest::error::ErrorVariant::CustomError { message } => { + write!(f, "{}", message)?; + } + } + Ok(()) } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - Some(&*self.e) + Some(&self.e) } } diff --git a/src/parse/ast.rs b/src/parse/ast.rs index d331863..9cf583a 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -15,7 +15,7 @@ impl Commands { pub fn parse(full_cmd: &str) -> Result { Ok(Self::build_ast( Shell::parse(Rule::line, full_cmd) - .map_err(|e| super::Error::new(full_cmd, anyhow::anyhow!(e)))? + .map_err(|e| super::Error::new(full_cmd, e))? .next() .unwrap() .into_inner() -- cgit v1.2.3-54-g00ecf