wisp/src/error.rs

86 lines
3.5 KiB
Rust

use crate::syntax::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.fg(Color::Yellow)),
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: {}",
delimiter.to_string().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) => x.to_string(),
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> {}