use crate::frontend::FileError;
use crate::frontend::tokenizer::TokenizerError;
use crate::frontend::parser::ParserError;
use crate::frontend::type_propagation::TypePropogatorError;
use crate::mod_api::ModApiError;
use crate::arena::Arena;
use crate::ntstring::{NTStrPtr, NTStr};
use crate::nt;
pub use gruggers_core::runtime_error::RuntimeError;
use allocator_api2::vec::Vec;
use std::marker::PhantomData;
use std::io::Write;
#[derive(Debug)]
pub enum GrugError {
FileError(FileError),
TokenizerError(TokenizerError),
ParserError(ParserError),
ModApiError(ModApiError),
TypePropogatorError(TypePropogatorError),
}
impl std::error::Error for GrugError { }
impl From<FileError> for GrugError {
fn from (from: FileError) -> Self {
Self::FileError(from)
}
}
impl From<TokenizerError> for GrugError {
fn from (from: TokenizerError) -> Self {
Self::TokenizerError(from)
}
}
impl From<ParserError> for GrugError {
fn from (from: ParserError) -> Self {
Self::ParserError(from)
}
}
impl From<ModApiError> for GrugError {
fn from(other: ModApiError) -> Self {
Self::ModApiError(other)
}
}
impl From<TypePropogatorError> for GrugError {
fn from(other: TypePropogatorError) -> Self {
Self::TypePropogatorError(other)
}
}
impl std::fmt::Display for GrugError {
fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Self::TokenizerError(error) => write!(f, "{}", error),
Self::FileError(error) => write!(f, "{}", error),
Self::ParserError(error) => write!(f, "{}", error),
Self::TypePropogatorError(error) => write!(f, "{}", error),
err => write!(f, "{:?}", err),
}
}
}
#[allow(dead_code)]
pub struct SourceSpan {
pub offset: usize,
pub len: usize,
}
impl SourceSpan {
pub fn get_loc_in(&self, text: &str) -> Option<(usize, usize)> {
let mut lines = 0;
let mut last_new_line = 0;
let text = text.as_bytes();
for (i, ch) in text.get(..self.offset)?.iter().enumerate() {
if *ch == b'\n' {
lines += 1;
last_new_line = i;
}
}
Some((lines, self.offset - last_new_line))
}
}
#[allow(dead_code)]
struct Diagnostic<'a>(PhantomData<&'a ()>);
#[allow(non_camel_case_types)]
#[allow(dead_code)]
pub struct grug_error {
allocator: Arena,
error_string: NTStrPtr<'static>,
severity: NTStrPtr<'static>,
file_name: NTStrPtr<'static>,
file_text: NTStrPtr<'static>,
error_span: SourceSpan,
error_message: NTStrPtr<'static>,
_diagnostics: &'static [Diagnostic<'static>],
}
impl std::fmt::Display for grug_error {
fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str(self.error_string.to_str())
}
}
impl grug_error {
#[allow(dead_code)]
pub(crate) fn new_error(error_message: std::fmt::Arguments, file_name: &str, file_text: &str, span: SourceSpan) -> Self {
let arena = Arena::new();
let (line, col) = span.get_loc_in(file_text)
.expect("Source span offset greater than file size");
let file_text = unsafe{NTStr::box_from_str_in(file_text, &arena).as_ntstrptr().detach_lifetime()};
let file_name = unsafe{NTStr::box_from_str_in(file_name, &arena).as_ntstrptr().detach_lifetime()};
let severity = nt!("Error");
let mut err_string = Vec::new_in(&arena);
write!(err_string, "{} {}:{}:{}: {}\0", severity.as_str(), file_name, line, col, error_message)
.expect("writing into a vec should never fail");
let error_string = unsafe{
NTStr::from_str_unchecked(
str::from_utf8_unchecked(err_string.leak())
).as_ntstrptr().detach_lifetime()
};
let mut err_message = Vec::new_in(&arena);
write!(err_message, "{}\0", error_message)
.expect("writing into a vec should never fail");
let error_message = unsafe{
NTStr::from_str_unchecked(
str::from_utf8_unchecked(err_message.leak())
).as_ntstrptr().detach_lifetime()
};
Self {
allocator: arena,
error_string,
severity: severity.as_ntstrptr(),
file_name,
file_text,
error_span: span,
error_message,
_diagnostics: &[],
}
}
}
const _: () = const{
let x: &[Diagnostic] = &[];
unsafe{assert!(x.len() == (&x as *const _ as *const usize).add(1).read());}
};