Improved error reports

This commit is contained in:
Erin 2022-07-21 13:03:47 +02:00 committed by ondra05
parent 331506af1b
commit bbbfed7913
5 changed files with 114 additions and 7 deletions

16
Cargo.lock generated
View file

@ -61,6 +61,15 @@ dependencies = [
"x11rb", "x11rb",
] ]
[[package]]
name = "ariadne"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1cb2a2046bea8ce5e875551f5772024882de0b540c7f93dfc5d6cf1ca8b030c"
dependencies = [
"yansi",
]
[[package]] [[package]]
name = "atomic_refcell" name = "atomic_refcell"
version = "0.1.8" version = "0.1.8"
@ -1556,6 +1565,7 @@ dependencies = [
name = "web-lisp" name = "web-lisp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ariadne",
"chumsky", "chumsky",
"eframe", "eframe",
"logos", "logos",
@ -1745,3 +1755,9 @@ name = "xml-rs"
version = "0.8.4" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"

View file

@ -6,7 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
logos = "*" ariadne = "0.1"
eframe = "*"
chumsky = "0.8" chumsky = "0.8"
eframe = "*"
logos = "*"
ordered-float = "3.0" ordered-float = "3.0"

85
src/error.rs Normal file
View file

@ -0,0 +1,85 @@
use crate::lexer::Token;
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
use chumsky::error::{Simple, SimpleReason};
use std::fmt::Display;
#[derive(Debug, Clone)]
pub enum Error<'a> {
Parse(Simple<Token<'a>>),
}
impl<'a> Error<'a> {
pub fn report(&self, src: &str) -> std::io::Result<()> {
match self {
Error::Parse(e) => {
let report =
Report::<std::ops::Range<usize>>::build(ReportKind::Error, (), e.span().start);
match e.reason() {
SimpleReason::Unexpected => report
.with_message(match e.found() {
Some(Token::Error) => {
format!("Invalid token: {}", &src[e.span()].fg(Color::Yellow))
}
Some(t) => format!("Unexpected token `{t:?}`"),
None => "Unexpected end of input".to_owned(),
})
.with_label(
Label::new(e.span())
.with_message(format!(
"Expected: {}",
e.expected()
.map(|exp| match exp {
Some(expected) => format!("{expected:?}"),
None => "end of input".to_owned(),
})
.collect::<Vec<_>>()
.join(", ")
))
.with_color(Color::Red),
),
SimpleReason::Unclosed { span, delimiter } => {
let msg = format!(
"Unclosed delimiter: {:?}",
format!("{delimiter:?}").fg(Color::Yellow)
);
report
.with_message(&msg)
.with_label(
Label::new(span.clone())
.with_message(msg)
.with_color(Color::Red),
)
.with_label(
Label::new(e.span())
.with_message(format!(
"Must be closed before {}",
match e.found() {
Some(x) => format!("{x:?}"),
None => "the end of input".to_owned(),
}
))
.with_color(Color::Yellow),
)
}
SimpleReason::Custom(msg) => report.with_message(msg).with_label(
Label::new(e.span())
.with_message(msg.fg(Color::Red))
.with_color(Color::Red),
),
}
.finish()
.print(Source::from(&src))
}
}
}
}
impl<'a> Display for Error<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Parse(e) => write!(f, "{e:?}"),
}
}
}
impl<'a> std::error::Error for Error<'a> {}

View file

@ -1,3 +1,4 @@
pub mod error;
pub mod lexer; pub mod lexer;
pub mod list; pub mod list;
pub mod parser; pub mod parser;

View file

@ -1,17 +1,21 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use web_lisp::parser; use web_lisp::{error::Error, parser};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
match parser::read(&std::fs::read_to_string( let src = std::fs::read_to_string(std::env::args().nth(1).ok_or("no filename provided")?)?;
std::env::args().nth(1).ok_or("no filename provided")?,
)?) { match parser::read(&src) {
Ok(vals) => { Ok(vals) => {
for val in vals { for val in vals {
println!("{val}"); println!("{val}");
} }
} }
Err(e) => eprintln!("Parse error: {e:?}"), Err(errs) => {
for err in errs {
Error::Parse(err).report(&src)?;
}
}
} }
Ok(()) Ok(())