better error reporting
This commit is contained in:
parent
8405d01303
commit
d12d129eb8
4 changed files with 90 additions and 13 deletions
|
@ -1,9 +1,10 @@
|
||||||
use eww_config::{ast::*, config::*};
|
use eww_config::{ast::*, config::*, format_diagnostic::ToDiagnostic};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut files = codespan_reporting::files::SimpleFiles::new();
|
let mut files = codespan_reporting::files::SimpleFiles::new();
|
||||||
|
|
||||||
let input = r#"(hi :bar 22 :baz {"hi" asdfasdf * 2} (foo) (baz))"#;
|
let input = r#"
|
||||||
|
(hi :bar 22 :baz {(foo == bar ? 12.K : 12)} (foo) (baz))"#;
|
||||||
|
|
||||||
let file_id = files.add("foo.eww", input);
|
let file_id = files.add("foo.eww", input);
|
||||||
let ast = eww_config::parse_string(file_id, input);
|
let ast = eww_config::parse_string(file_id, input);
|
||||||
|
@ -12,10 +13,12 @@ fn main() {
|
||||||
println!("{:?}", ast);
|
println!("{:?}", ast);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let diag = err.pretty_diagnostic(&files);
|
dbg!(&err);
|
||||||
|
let diag = err.to_diagnostic(&files);
|
||||||
use codespan_reporting::term;
|
use codespan_reporting::term;
|
||||||
|
let config = term::Config::default();
|
||||||
let mut writer = term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Always);
|
let mut writer = term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Always);
|
||||||
term::emit(&mut writer, &term::Config::default(), &files, &diag).unwrap();
|
term::emit(&mut writer, &config, &files, &diag).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,15 +30,6 @@ impl AstError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_diagnostic(&self, files: &files::SimpleFiles<&str, &str>) -> diagnostic::Diagnostic<usize> {
|
|
||||||
let diag = diagnostic::Diagnostic::error().with_message(format!("{}", self));
|
|
||||||
if let Some(span) = self.get_span() {
|
|
||||||
diag.with_labels(vec![diagnostic::Label::primary(span.2, span.0..span.1)])
|
|
||||||
} else {
|
|
||||||
diag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_parse_error(
|
pub fn from_parse_error(
|
||||||
file_id: usize,
|
file_id: usize,
|
||||||
err: lalrpop_util::ParseError<usize, lexer::Token, parse_error::ParseError>,
|
err: lalrpop_util::ParseError<usize, lexer::Token, parse_error::ParseError>,
|
||||||
|
|
81
src/format_diagnostic.rs
Normal file
81
src/format_diagnostic.rs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
use codespan_reporting::{diagnostic, files};
|
||||||
|
use simplexpr::dynval;
|
||||||
|
|
||||||
|
use crate::{ast::Span, error::AstError, parse_error};
|
||||||
|
use diagnostic::*;
|
||||||
|
|
||||||
|
fn span_to_label(span: Span) -> Label<usize> {
|
||||||
|
Label::primary(span.2, span.0..span.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToDiagnostic {
|
||||||
|
fn to_diagnostic(&self, files: &files::SimpleFiles<&str, &str>) -> Diagnostic<usize>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToDiagnostic for AstError {
|
||||||
|
fn to_diagnostic(&self, files: &files::SimpleFiles<&str, &str>) -> Diagnostic<usize> {
|
||||||
|
let diag = Diagnostic::error();
|
||||||
|
if let Some(span) = self.get_span() {
|
||||||
|
use lalrpop_util::ParseError::*;
|
||||||
|
match self {
|
||||||
|
AstError::InvalidDefinition(_) => todo!(),
|
||||||
|
|
||||||
|
AstError::MissingNode(_, expected) => diag
|
||||||
|
.with_message(format!("Missing {}", expected))
|
||||||
|
.with_labels(vec![span_to_label(span).with_message(format!("Expected `{}` here", expected))]),
|
||||||
|
|
||||||
|
AstError::WrongExprType(_, expected, actual) => diag
|
||||||
|
.with_message("Wrong type of expression")
|
||||||
|
.with_notes(vec![format!("Expected: {}\nGot: {}", expected, actual)])
|
||||||
|
.with_labels(vec![span_to_label(span).with_message(format!("Expected a `{}` here", expected))]),
|
||||||
|
|
||||||
|
AstError::ParseError { file_id, source } => {
|
||||||
|
lalrpop_error_to_diagnostic(source, diag, span, move |diag, error| match error {
|
||||||
|
parse_error::ParseError::SimplExpr(_, error) => simplexpr_error_to_diagnostic(error, diag, span),
|
||||||
|
parse_error::ParseError::LexicalError(_) => diag
|
||||||
|
.with_message("Invalid token")
|
||||||
|
.with_labels(vec![span_to_label(span).with_message("Invalid token")]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
diag.with_message(format!("{}", self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E>(
|
||||||
|
error: &lalrpop_util::ParseError<usize, T, E>,
|
||||||
|
diag: Diagnostic<usize>,
|
||||||
|
span: Span,
|
||||||
|
handle_user_error: impl FnOnce(Diagnostic<usize>, &E) -> Diagnostic<usize>,
|
||||||
|
) -> Diagnostic<usize> {
|
||||||
|
use lalrpop_util::ParseError::*;
|
||||||
|
match error {
|
||||||
|
InvalidToken { location } => diag.with_message("Invalid token").with_labels(vec![span_to_label(span)]),
|
||||||
|
UnrecognizedEOF { location, expected } => diag
|
||||||
|
.with_message("Input ended unexpectedly. Check if you have any unclosed delimiters")
|
||||||
|
.with_labels(vec![span_to_label(span)]),
|
||||||
|
UnrecognizedToken { token, expected } => diag
|
||||||
|
.with_message(format!("Unexpected token `{}` encoutered", token.1))
|
||||||
|
.with_labels(vec![span_to_label(span).with_message("Token unexpected")]),
|
||||||
|
|
||||||
|
ExtraToken { token } => diag.with_message(format!("Extra token encountered: `{}`", token.1)),
|
||||||
|
User { error } => handle_user_error(diag, error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simplexpr_error_to_diagnostic(error: &simplexpr::error::Error, diag: Diagnostic<usize>, span: Span) -> Diagnostic<usize> {
|
||||||
|
match error {
|
||||||
|
simplexpr::error::Error::ParseError { source } => lalrpop_error_to_diagnostic(source, diag, span, move |diag, error| {
|
||||||
|
diag.with_message("Invalid token").with_labels(vec![span_to_label(span).with_message("Invalid token")])
|
||||||
|
}),
|
||||||
|
simplexpr::error::Error::ConversionError(dynval::ConversionError { value, target_type, source }) => diag
|
||||||
|
.with_message(format!("{}", error))
|
||||||
|
.with_labels(vec![span_to_label(span).with_message(format!("{} is not of type `{}`", value, target_type))])
|
||||||
|
.with_notes(source.as_ref().map(|x| vec![format!("{}", x)]).unwrap_or_default()),
|
||||||
|
simplexpr::error::Error::Spanned(..) => todo!(),
|
||||||
|
simplexpr::error::Error::Eval(error) => diag.with_message(format!("{}", error)).with_labels(vec![span_to_label(span)]),
|
||||||
|
simplexpr::error::Error::Other(error) => diag.with_message(format!("{}", error)).with_labels(vec![span_to_label(span)]),
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,11 @@
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod format_diagnostic;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parse_error;
|
mod parse_error;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
use ast::Ast;
|
use ast::Ast;
|
||||||
use error::{AstError, AstResult};
|
use error::{AstError, AstResult};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue