use crate::{ parsing::{Location, ParseError}, schala::{SourceReference, Stage}, symbol_table::SymbolError, type_inference::TypeError, }; pub struct SchalaError { errors: Vec, } impl SchalaError { pub(crate) fn display(&self) -> String { match self.errors[0] { Error::Parse(ref parse_err) => parse_err.to_string(), Error::Standard { ref text, .. } => text.as_ref().cloned().unwrap_or_default(), } } #[allow(dead_code)] pub(crate) fn from_type_error(err: TypeError) -> Self { Self { errors: vec![Error::Standard { location: None, text: Some(err.msg), stage: Stage::Typechecking }], } } pub(crate) fn from_symbol_table(symbol_errs: Vec) -> Self { //TODO this could be better let errors = symbol_errs .into_iter() .map(|_symbol_err| Error::Standard { location: None, text: Some("symbol table error".to_string()), stage: Stage::Symbols, }) .collect(); Self { errors } } pub(crate) fn from_string(text: String, stage: Stage) -> Self { Self { errors: vec![Error::Standard { location: None, text: Some(text), stage }] } } pub(crate) fn from_parse_error(parse_error: ParseError, source_reference: &SourceReference) -> Self { let formatted_parse_error = format_parse_error(parse_error, source_reference); Self { errors: vec![Error::Parse(formatted_parse_error)] } } } #[allow(dead_code)] enum Error { Standard { location: Option, text: Option, stage: Stage }, Parse(String), } fn format_parse_error(error: ParseError, source_reference: &SourceReference) -> String { let offset = error.location.offset; let (line_start, line_num, line_from_program) = source_reference.get_line(offset); let ch = offset - line_start; let location_pointer = format!("{}^", " ".repeat(ch)); let line_num_digits = format!("{}", line_num).chars().count(); let space_padding = " ".repeat(line_num_digits); format!( r#" {error_msg} {space_padding} | {line_num} | {} {space_padding} | {} "#, line_from_program, location_pointer, error_msg = error.msg, space_padding = space_padding, line_num = line_num, ) }