86 lines
3.5 KiB
Rust
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> {}
|