1use crate::*;
2use std::sync::Arc;
3use std::any::Any;
4
5type Rows = usize;
11type Cols = usize;
12
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct CompilerSourceRange {
16 pub file: &'static str,
17 pub line: u32,
18}
19
20impl CompilerSourceRange {
21 #[track_caller]
22 pub fn here() -> Self {
23 let loc = std::panic::Location::caller();
24 Self {
25 file: loc.file(),
26 line: loc.line(),
27 }
28 }
29}
30
31#[macro_export]
32macro_rules! compiler_loc {
33 () => {
34 $crate::CompilerSourceRange {
35 file: file!(),
36 line: line!(),
37 }
38 };
39}
40
41trait ErrorKindCallbacks: Send + Sync {
42 fn name(&self, data: &dyn Any) -> String;
43 fn message(&self, data: &dyn Any) -> String;
44}
45
46struct CallbacksImpl<K> {
47 _marker: std::marker::PhantomData<K>,
49}
50
51impl<K> CallbacksImpl<K> {
52 fn new() -> Self {
53 Self { _marker: std::marker::PhantomData }
54 }
55}
56
57impl<K> ErrorKindCallbacks for CallbacksImpl<K>
58where
59 K: MechErrorKind2 + 'static,
60{
61 fn name(&self, data: &dyn Any) -> String {
62 let k = data.downcast_ref::<K>().expect("wrong kind type in vtable");
64 k.name().to_string()
65 }
66
67 fn message(&self, data: &dyn Any) -> String {
68 let k = data.downcast_ref::<K>().expect("wrong kind type in vtable");
69 k.message()
70 }
71}
72
73pub trait MechErrorKind2: std::fmt::Debug + Send + Sync + Clone {
74 fn name(&self) -> &str;
75 fn message(&self) -> String;
76}
77
78#[derive(Clone)]
81pub struct MechError2 {
82 kind_data: Arc<dyn Any + Send + Sync>,
83 kind_callbacks: Arc<dyn ErrorKindCallbacks>, pub program_range: Option<SourceRange>,
85 pub annotations: Vec<SourceRange>,
86 pub tokens: Vec<Token>,
87 pub compiler_location: Option<CompilerSourceRange>,
88 pub source: Option<Box<MechError2>>, pub message: Option<String>,
90}
91
92impl std::fmt::Debug for MechError2 {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 f.debug_struct("MechError2")
95 .field("kind name", &self.kind_name())
96 .field("kind message", &self.kind_message())
97 .field("message", &self.message)
98 .field("program_range", &self.program_range)
99 .field("annotations", &self.annotations)
100 .field("tokens", &self.tokens)
101 .field("compiler_location", &self.compiler_location)
102 .field("source", &self.source)
103 .finish()
104 }
105}
106
107impl MechError2 {
108 pub fn new<K: MechErrorKind2 + 'static>(
109 kind: K,
110 message: Option<String>
111 ) -> Self {
112 MechError2 {
113 kind_data: Arc::new(kind),
114 kind_callbacks: Arc::new(CallbacksImpl::<K>::new()),
115 program_range: None,
116 annotations: Vec::new(),
117 tokens: Vec::new(),
118 compiler_location: None,
119 source: None,
120 message,
121 }
122 }
123
124 pub fn kind_as<K: MechErrorKind2 + 'static>(&self) -> Option<&K> {
126 self.kind_data.downcast_ref::<K>()
127 }
128
129 pub fn kind_name(&self) -> String {
131 self.kind_callbacks.name(self.kind_data.as_ref())
132 }
133
134 pub fn kind_message(&self) -> String {
136 self.kind_callbacks.message(self.kind_data.as_ref())
137 }
138
139 pub fn display_message(&self) -> String {
141 if let Some(ref m) = self.message { m.clone() } else { self.kind_message() }
142 }
143
144 pub fn kind_downcast_ref<K: 'static>(&self) -> Option<&K> {
146 self.kind_data.downcast_ref::<K>()
147 }
148
149 #[track_caller]
151 pub fn with_compiler_loc(mut self) -> Self {
152 self.compiler_location = Some(CompilerSourceRange::here());
153 self
154 }
155
156 pub fn with_specific_compiler_loc(mut self, loc: CompilerSourceRange) -> Self {
158 self.compiler_location = Some(loc);
159 self
160 }
161
162 pub fn with_annotation(mut self, range: SourceRange) -> Self {
164 self.annotations.push(range);
165 self
166 }
167
168 pub fn with_annotations<I>(mut self, iter: I) -> Self
170 where
171 I: IntoIterator<Item = SourceRange>,
172 {
173 self.annotations.extend(iter);
174 self
175 }
176
177 pub fn with_tokens<I>(mut self, iter: I) -> Self
179 where
180 I: IntoIterator<Item = Token>,
181 {
182 self.tokens.extend(iter);
183 self
184 }
185
186 pub fn with_source(mut self, src: MechError2) -> Self {
188 self.source = Some(Box::new(src));
189 self
190 }
191
192 pub fn primary_range(&self) -> Option<SourceRange> {
194 self.program_range.clone()
195 }
196
197 pub fn simple_message(&self) -> String {
199 format!("{}: {}", self.kind_name(), self.kind_message())
200 }
201
202 pub fn full_chain_message(&self) -> String {
204 let mut out = self.simple_message();
205 let mut current = &self.source;
206
207 while let Some(err) = current {
208 out.push_str("\nCaused by: ");
209 out.push_str(&err.simple_message());
210 current = &err.source;
211 }
212
213 out
214 }
215
216 pub fn boxed(self) -> Box<Self> {
217 Box::new(self)
218 }
219}
220
221#[derive(Debug, Clone)]
222pub struct UndefinedKindError {
223 pub kind_id: u64,
224}
225impl MechErrorKind2 for UndefinedKindError {
226 fn name(&self) -> &str {
227 "UndefinedKind"
228 }
229 fn message(&self) -> String {
230 format!("Kind `{}` is not defined.", self.kind_id)
231 }
232}
233
234impl From<std::io::Error> for MechError2 {
235 fn from(err: std::io::Error) -> Self {
236 MechError2::new(
237 IoErrorWrapper { msg: err.to_string() },
238 None
239 )
240 .with_compiler_loc()
241 }
242}
243
244#[derive(Debug, Clone)]
245pub struct DimensionMismatch {
246 pub dims: Vec<usize>,
247}
248impl MechErrorKind2 for DimensionMismatch {
249 fn name(&self) -> &str { "DimensionMismatch" }
250 fn message(&self) -> String { format!("Matrix dimension mismatch: {:?}", self.dims) }
251}
252
253#[derive(Debug, Clone)]
254pub struct GenericError {
255 pub msg: String,
256}
257impl MechErrorKind2 for GenericError {
258 fn name(&self) -> &str { "GenericError" }
259
260 fn message(&self) -> String {
261 format!("Error: {}", self.msg)
262 }
263}
264
265#[derive(Debug, Clone)]
266pub struct FeatureNotEnabledError;
267impl MechErrorKind2 for FeatureNotEnabledError {
268 fn name(&self) -> &str { "FeatureNotEnabled" }
269
270 fn message(&self) -> String {
271 format!("Feature not enabled")
272 }
273}
274
275#[derive(Debug, Clone)]
276pub struct NotExecutableError {}
277impl MechErrorKind2 for NotExecutableError {
278 fn name(&self) -> &str { "NotExecutable" }
279
280 fn message(&self) -> String {
281 format!("Not executable")
282 }
283}
284
285#[derive(Debug, Clone)]
286pub struct IoErrorWrapper {
287 pub msg: String,
288}
289impl MechErrorKind2 for IoErrorWrapper {
290 fn name(&self) -> &str { "IoError" }
291
292 fn message(&self) -> String {
293 format!("IO error: {}", self.msg)
294 }
295}
296
297