use std::{borrow::Cow, fmt};
pub type LanguageError = crate::ll::error::LanguageError;
pub type LanguageErrorKind = crate::ll::error::LanguageErrorKind;
#[derive(Debug)]
pub enum Error {
Compile(LanguageError),
Runtime(LanguageError),
TooManyGlobals,
TooManyFunctions,
TooManyMethods,
TooManyArguments,
TooManyTraits,
TooManyParametersInTraitMethod,
TypeMismatch {
expected: Cow<'static, str>,
got: Cow<'static, str>,
},
ArgumentCount {
expected: usize,
got: usize,
},
ArgumentTypeMismatch {
index: usize,
expected: Cow<'static, str>,
got: Cow<'static, str>,
},
ReentrantMutableBorrow,
User(Box<dyn std::error::Error>),
}
impl From<LanguageError> for Error {
fn from(error: LanguageError) -> Self {
match &error {
LanguageError::Compile { .. } => Self::Compile(error),
LanguageError::Runtime { .. } => Self::Runtime(error),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Compile(error) | Self::Runtime(error) => error.fmt(f),
Self::TooManyGlobals => f.write_str("too many globals"),
Self::TooManyFunctions => f.write_str("too many functions"),
Self::TooManyMethods => f.write_str("too many methods with different signatures"),
Self::TooManyArguments => f.write_str("too many arguments passed to a function"),
Self::TooManyTraits => f.write_str("too many traits"),
Self::TooManyParametersInTraitMethod => {
f.write_str("trait method with too many parameters")
}
Self::TypeMismatch { expected, got } => {
write!(f, "type mismatch, expected {expected} but got {got}")
}
Self::ArgumentCount { expected, got } => {
write!(f, "{expected} arguments expected but got {got}")
}
Self::ArgumentTypeMismatch { index, expected, got } => {
write!(
f,
"type mismatch at argument {}, expected {expected} but got {got}",
index + 1
)
}
Self::ReentrantMutableBorrow => write!(f, "method receiver is in use already"),
Self::User(error) => write!(f, "{error}"),
}
}
}
impl std::error::Error for Error {}
pub trait MicaResultExt<T, E> {
fn mica(self) -> Result<T, Error>;
}
#[repr(transparent)]
struct UserError<T>(T);
impl<T> fmt::Debug for UserError<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<T> fmt::Display for UserError<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl<T> std::error::Error for UserError<T> where T: fmt::Debug + fmt::Display {}
impl<T, E> MicaResultExt<T, E> for Result<T, E>
where
E: fmt::Debug + fmt::Display + 'static,
{
fn mica(self) -> Result<T, Error> {
self.map_err(|error| Error::User(Box::new(UserError(error))))
}
}
pub(crate) fn wrap_in_language_error<T, E>(r: Result<T, E>) -> Result<T, LanguageErrorKind>
where
E: std::error::Error + 'static,
{
r.map_err(|error| LanguageErrorKind::User(Box::new(error)))
}
pub trait MicaLanguageResultExt<T> {
fn to_language_error(self) -> Result<T, LanguageErrorKind>;
}
impl<T> MicaLanguageResultExt<T> for Result<T, Error> {
fn to_language_error(self) -> Result<T, LanguageErrorKind> {
wrap_in_language_error(self)
}
}