mica/hl/
error.rs

1//! Error reporting.
2
3use std::{borrow::Cow, fmt};
4
5/// A raw [`ll`][crate::ll] error, with metadata such as stack traces.
6pub type LanguageError = crate::ll::error::LanguageError;
7/// A raw [`ll`][crate::ll] error kind.
8pub type LanguageErrorKind = crate::ll::error::LanguageErrorKind;
9
10/// An error.
11#[derive(Debug)]
12pub enum Error {
13    /// An error occured during compilation.
14    Compile(LanguageError),
15    /// An error occured during runtime.
16    Runtime(LanguageError),
17    /// There are too many globals.
18    TooManyGlobals,
19    /// Too many functions were created.
20    TooManyFunctions,
21    /// Too many methods with different signatures were declared.
22    TooManyMethods,
23    /// Too many arguments were passed to a method or a function.
24    TooManyArguments,
25    /// Too many traits were created.
26    TooManyTraits,
27    /// A trait method with too many parameters was created.
28    TooManyParametersInTraitMethod,
29    /// A type mismatch occured.
30    TypeMismatch {
31        /// The name of the expected type.
32        expected: Cow<'static, str>,
33        /// The name of the actual type obtained.
34        got: Cow<'static, str>,
35    },
36    /// Incorrect amount of arguments passed to a function.
37    ArgumentCount {
38        /// The number of arguments that was expected.
39        expected: usize,
40        /// The actual number of arguments obtained.
41        got: usize,
42    },
43    /// A type mismatch occured in function arguments.
44    ArgumentTypeMismatch {
45        /// Which argument had a type mismatch.
46        index: usize,
47        /// The name of the expected type.
48        expected: Cow<'static, str>,
49        /// The name of the actual type obtained.
50        got: Cow<'static, str>,
51    },
52    /// A value was mutably borrowed twice.
53    ReentrantMutableBorrow,
54    /// A user-defined error.
55    User(Box<dyn std::error::Error>),
56}
57
58impl From<LanguageError> for Error {
59    fn from(error: LanguageError) -> Self {
60        match &error {
61            LanguageError::Compile { .. } => Self::Compile(error),
62            LanguageError::Runtime { .. } => Self::Runtime(error),
63        }
64    }
65}
66
67impl fmt::Display for Error {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        match self {
70            Self::Compile(error) | Self::Runtime(error) => error.fmt(f),
71            Self::TooManyGlobals => f.write_str("too many globals"),
72            Self::TooManyFunctions => f.write_str("too many functions"),
73            Self::TooManyMethods => f.write_str("too many methods with different signatures"),
74            Self::TooManyArguments => f.write_str("too many arguments passed to a function"),
75            Self::TooManyTraits => f.write_str("too many traits"),
76            Self::TooManyParametersInTraitMethod => {
77                f.write_str("trait method with too many parameters")
78            }
79            Self::TypeMismatch { expected, got } => {
80                write!(f, "type mismatch, expected {expected} but got {got}")
81            }
82            Self::ArgumentCount { expected, got } => {
83                write!(f, "{expected} arguments expected but got {got}")
84            }
85            Self::ArgumentTypeMismatch { index, expected, got } => {
86                write!(
87                    f,
88                    "type mismatch at argument {}, expected {expected} but got {got}",
89                    index + 1
90                )
91            }
92            Self::ReentrantMutableBorrow => write!(f, "method receiver is in use already"),
93            Self::User(error) => write!(f, "{error}"),
94        }
95    }
96}
97
98impl std::error::Error for Error {}
99
100/// Extensions for converting [`Result`]s into a Mica FFI-friendly structure.
101pub trait MicaResultExt<T, E> {
102    /// Maps the error in the result to an [`Error`].
103    fn mica(self) -> Result<T, Error>;
104}
105
106/// Transparent wrapper that implements [`std::error::Error`] for a user-defined error.
107#[repr(transparent)]
108struct UserError<T>(T);
109
110impl<T> fmt::Debug for UserError<T>
111where
112    T: fmt::Debug,
113{
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        fmt::Debug::fmt(&self.0, f)
116    }
117}
118
119impl<T> fmt::Display for UserError<T>
120where
121    T: fmt::Display,
122{
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        fmt::Display::fmt(&self.0, f)
125    }
126}
127
128impl<T> std::error::Error for UserError<T> where T: fmt::Debug + fmt::Display {}
129
130impl<T, E> MicaResultExt<T, E> for Result<T, E>
131where
132    E: fmt::Debug + fmt::Display + 'static,
133{
134    fn mica(self) -> Result<T, Error> {
135        self.map_err(|error| Error::User(Box::new(UserError(error))))
136    }
137}
138
139pub(crate) fn wrap_in_language_error<T, E>(r: Result<T, E>) -> Result<T, LanguageErrorKind>
140where
141    E: std::error::Error + 'static,
142{
143    r.map_err(|error| LanguageErrorKind::User(Box::new(error)))
144}
145
146/// Extensions for converting [`Result`]s into a `mica-language` FFI-friendly structure.
147pub trait MicaLanguageResultExt<T> {
148    /// Maps the error in the result to a [`LanguageErrorKind`].
149    fn to_language_error(self) -> Result<T, LanguageErrorKind>;
150}
151
152impl<T> MicaLanguageResultExt<T> for Result<T, Error> {
153    fn to_language_error(self) -> Result<T, LanguageErrorKind> {
154        wrap_in_language_error(self)
155    }
156}