iowo/crates/lang/src/err_reporting.rs

88 lines
2.5 KiB
Rust

use std::{collections::HashMap, fs};
use ariadne::{sources, Label, Report, Source};
use chumsky::{
error::{self, Rich},
ParseResult,
};
use indexmap::IndexMap;
use crate::{
parser::{ast::File, Span},
tokens::Token,
};
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum Stage {
Lex,
Parse,
}
impl Stage {
fn variants() -> [Stage; 2] {
[Stage::Lex, Stage::Parse]
}
}
pub struct ErrorCollector<'filename, 'tokens, 'src> {
files: HashMap<&'filename str, &'src str>,
raw_errors: IndexMap<(&'filename str, Stage), Vec<error::Rich<'tokens, Token<'src>, Span>>>,
}
impl<'filename, 'tokens, 'src> ErrorCollector<'filename, 'tokens, 'src> {
pub fn new(files: Vec<(&'filename str, &'src str)>) -> Self {
Self {
files: HashMap::from_iter(files.clone()),
raw_errors: files
.iter()
.flat_map(|(name, _)| Stage::variants().map(|s| (name, s)))
.map(|(name, stage)| ((*name, stage), Vec::new()))
.collect(),
}
}
pub fn insert_many(
&mut self,
file: &'filename str,
curr_stage: Stage,
mut errs: Vec<error::Rich<'tokens, Token<'src>, Span>>,
) {
let err_vec = self
.raw_errors
.get_mut(&(file, curr_stage))
.expect("filename should exist");
err_vec.append(&mut errs);
}
pub fn analyze_and_report(self) {
let ErrorCollector { files, raw_errors } = self;
todo!()
}
pub fn report_raw(self) {
let ErrorCollector { files, raw_errors } = self;
for ((file, stage), errs) in raw_errors.into_iter() {
for err in errs {
eprintln!("e: {err:?}");
Report::build(ariadne::ReportKind::Error, file, err.span().start)
.with_message(format!("error at stage {stage:?}, {:?}", err.reason()))
.with_label(
Label::new((file, err.span().into_range())).with_message(format!(
"found: {:?}",
err.found().expect("errors should have a reason")
)),
)
.with_help(format!(
"expected: {:?}",
err.expected().collect::<Vec<_>>()
))
.finish()
.print((file, Source::from(files[file])));
}
}
}
}
#[derive(Debug, PartialEq, Eq)]
struct Loc<'filename>(&'filename str, Span);