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, 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, 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 { 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::>() )) .finish() .print((file, Source::from(files[file]))); } } } } #[derive(Debug, PartialEq, Eq)] struct Loc<'filename>(&'filename str, Span);