1use crate::prelude::*;
2use std::fmt;
3
4#[derive(Debug)]
5pub enum RuntimeError {
6 ArithmeticError(RuntimeErrorStruct),
7 NewAtomicFactError(RuntimeErrorStruct),
8 StoreFactError(RuntimeErrorStruct),
9 ParseError(RuntimeErrorStruct),
10 ExecStmtError(RuntimeErrorStruct),
11 WellDefinedError(RuntimeErrorStruct),
12 VerifyError(RuntimeErrorStruct),
13 UnknownError(RuntimeErrorStruct),
14 InferError(RuntimeErrorStruct),
15 NameAlreadyUsedError(RuntimeErrorStruct),
16 DefineParamsError(RuntimeErrorStruct),
17 InstantiateError(RuntimeErrorStruct),
18}
19
20#[derive(Debug)]
21pub struct RuntimeErrorStruct {
22 pub statement: Option<Stmt>,
23 pub msg: String,
24 pub conflict_with: Option<ConflictMsg>,
25 pub line_file: LineFile,
26 pub previous_error: Option<Box<RuntimeError>>,
27 pub inside_results: Vec<StmtResult>,
28}
29
30macro_rules! runtime_error_from_wrapper {
31 ($wrapper:ident, $variant:ident) => {
32 #[derive(Debug)]
33 pub struct $wrapper(pub RuntimeErrorStruct);
34 impl From<$wrapper> for RuntimeError {
35 fn from(w: $wrapper) -> Self {
36 RuntimeError::$variant(w.0)
37 }
38 }
39 };
40}
41
42runtime_error_from_wrapper!(ArithmeticRuntimeError, ArithmeticError);
43runtime_error_from_wrapper!(NewAtomicFactRuntimeError, NewAtomicFactError);
44runtime_error_from_wrapper!(StoreFactRuntimeError, StoreFactError);
45runtime_error_from_wrapper!(ParseRuntimeError, ParseError);
46runtime_error_from_wrapper!(WellDefinedRuntimeError, WellDefinedError);
47runtime_error_from_wrapper!(VerifyRuntimeError, VerifyError);
48runtime_error_from_wrapper!(UnknownRuntimeError, UnknownError);
49runtime_error_from_wrapper!(InferRuntimeError, InferError);
50runtime_error_from_wrapper!(NameAlreadyUsedRuntimeError, NameAlreadyUsedError);
51runtime_error_from_wrapper!(DefineParamsRuntimeError, DefineParamsError);
52runtime_error_from_wrapper!(InstantiateRuntimeError, InstantiateError);
53
54#[derive(Debug, Clone)]
55pub struct ConflictMsg {
56 pub msg: String,
57 pub line_file: LineFile,
58 pub stmt: Option<Stmt>,
59}
60
61impl RuntimeErrorStruct {
62 pub fn new(
63 statement: Option<Stmt>,
64 msg: String,
65 line_file: LineFile,
66 previous_error: Option<RuntimeError>,
67 ) -> Self {
68 RuntimeErrorStruct::new_with_conflict(
69 statement,
70 msg,
71 line_file,
72 None,
73 previous_error,
74 vec![],
75 )
76 }
77
78 pub fn new_with_conflict(
79 statement: Option<Stmt>,
80 msg: String,
81 line_file: LineFile,
82 conflict_with: Option<ConflictMsg>,
83 previous_error: Option<RuntimeError>,
84 inside_results: Vec<StmtResult>,
85 ) -> Self {
86 RuntimeErrorStruct {
87 statement,
88 msg,
89 conflict_with,
90 line_file,
91 previous_error: boxed_previous_error(previous_error),
92 inside_results,
93 }
94 }
95
96 pub fn new_with_msg_previous_error(msg: String, previous_error: Option<RuntimeError>) -> Self {
97 RuntimeErrorStruct::new(None, msg, default_line_file(), previous_error)
98 }
99
100 pub fn exec_stmt_new(
101 stmt: Option<Stmt>,
102 info: String,
103 previous_error: Option<RuntimeError>,
104 inside_results: Vec<StmtResult>,
105 ) -> Self {
106 let line_file = if let Some(ref stmt) = stmt {
107 stmt.line_file()
108 } else {
109 default_line_file()
110 };
111 RuntimeErrorStruct::new_with_conflict(
112 stmt,
113 info,
114 line_file,
115 None,
116 previous_error,
117 inside_results,
118 )
119 }
120
121 pub fn exec_stmt_new_with_stmt(
122 stmt: Stmt,
123 info: String,
124 previous_error: Option<RuntimeError>,
125 inside_results: Vec<StmtResult>,
126 ) -> Self {
127 let line_file = stmt.line_file();
128 RuntimeErrorStruct::new_with_conflict(
129 Some(stmt),
130 info,
131 line_file,
132 None,
133 previous_error,
134 inside_results,
135 )
136 }
137
138 pub fn exec_stmt_with_message_and_cause(
139 stmt: Stmt,
140 message: String,
141 cause: Option<RuntimeError>,
142 inside_results: Vec<StmtResult>,
143 ) -> Self {
144 let line_file = stmt.line_file();
145 let previous_error = if message.is_empty() {
146 cause
147 } else {
148 Some(
149 RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
150 message.clone(),
151 line_file,
152 None,
153 cause,
154 ),
155 )
156 };
157 RuntimeErrorStruct::exec_stmt_new_with_stmt(stmt, message, previous_error, inside_results)
158 }
159}
160
161impl std::error::Error for RuntimeError {}
162
163impl RuntimeError {
164 pub fn into_struct(self) -> RuntimeErrorStruct {
165 match self {
166 RuntimeError::ArithmeticError(s) => s,
167 RuntimeError::NewAtomicFactError(s) => s,
168 RuntimeError::StoreFactError(s) => s,
169 RuntimeError::ParseError(s) => s,
170 RuntimeError::ExecStmtError(s) => s,
171 RuntimeError::WellDefinedError(s) => s,
172 RuntimeError::VerifyError(s) => s,
173 RuntimeError::UnknownError(s) => s,
174 RuntimeError::InferError(s) => s,
175 RuntimeError::NameAlreadyUsedError(s) => s,
176 RuntimeError::DefineParamsError(s) => s,
177 RuntimeError::InstantiateError(s) => s,
178 }
179 }
180
181 pub fn line_file(&self) -> LineFile {
182 match self {
183 RuntimeError::ArithmeticError(e) => e.line_file.clone(),
184 RuntimeError::NewAtomicFactError(e) => e.line_file.clone(),
185 RuntimeError::StoreFactError(e) => e.line_file.clone(),
186 RuntimeError::ParseError(e) => e.line_file.clone(),
187 RuntimeError::ExecStmtError(e) => e.line_file.clone(),
188 RuntimeError::WellDefinedError(e) => e.line_file.clone(),
189 RuntimeError::VerifyError(e) => e.line_file.clone(),
190 RuntimeError::UnknownError(e) => e.line_file.clone(),
191 RuntimeError::InferError(e) => e.line_file.clone(),
192 RuntimeError::NameAlreadyUsedError(e) => e.line_file.clone(),
193 RuntimeError::DefineParamsError(e) => e.line_file.clone(),
194 RuntimeError::InstantiateError(e) => e.line_file.clone(),
195 }
196 }
197
198 pub fn display_label(&self) -> &'static str {
199 match self {
200 RuntimeError::ArithmeticError(_) => "ArithmeticError",
201 RuntimeError::NewAtomicFactError(_) => "NewAtomicFactError",
202 RuntimeError::StoreFactError(_) => "StoreFactError",
203 RuntimeError::ParseError(_) => "ParseError",
204 RuntimeError::ExecStmtError(_) => "ExecStmtError",
205 RuntimeError::WellDefinedError(_) => "WellDefinedError",
206 RuntimeError::VerifyError(_) => "VerifyError",
207 RuntimeError::UnknownError(_) => "UnknownError",
208 RuntimeError::InferError(_) => "InferError",
209 RuntimeError::NameAlreadyUsedError(_) => "NameAlreadyUsedError",
210 RuntimeError::DefineParamsError(_) => "DefineParamsError",
211 RuntimeError::InstantiateError(_) => "InstantiateError",
212 }
213 }
214
215 pub fn message_text_for_duplicate_used_name_without_line_file(name: &str) -> String {
216 format!(
217 "name `{}` is already used, cannot be used again for other definitions",
218 name
219 )
220 }
221
222 pub fn new_infer_error_with_msg_position_previous_error(
223 msg: String,
224 line_file: LineFile,
225 previous_error: Option<RuntimeError>,
226 ) -> Self {
227 InferRuntimeError(RuntimeErrorStruct::new(
228 None,
229 msg,
230 line_file,
231 previous_error,
232 ))
233 .into()
234 }
235
236 pub fn new_define_params_error_with_msg_previous_error_position(
237 msg: String,
238 previous_error: Option<RuntimeError>,
239 line_file: LineFile,
240 ) -> Self {
241 DefineParamsRuntimeError(RuntimeErrorStruct::new(
242 None,
243 msg,
244 line_file,
245 previous_error,
246 ))
247 .into()
248 }
249
250 pub fn new_parse_error_with_msg_position_previous_error(
251 msg: String,
252 line_file: LineFile,
253 previous_error: Option<RuntimeError>,
254 ) -> Self {
255 ParseRuntimeError(RuntimeErrorStruct::new(
256 None,
257 msg,
258 line_file,
259 previous_error,
260 ))
261 .into()
262 }
263
264 pub fn new_parse_error_for_block_unexpected_indent_at_line_file(line_file: LineFile) -> Self {
265 let (line_no, path) = (line_file.0, line_file.1.as_ref());
266 Self::new_parse_error_with_msg_position_previous_error(
267 format!("unexpected indent at line {} in {}", line_no, path),
268 line_file,
269 None,
270 )
271 }
272
273 pub fn new_parse_error_for_block_expected_indent_at_line_file(line_file: LineFile) -> Self {
274 let (line_no, path) = (line_file.0, line_file.1.as_ref());
275 Self::new_parse_error_with_msg_position_previous_error(
276 format!("expected indent at line {} in {}", line_no, path),
277 line_file,
278 None,
279 )
280 }
281
282 pub fn new_parse_error_for_block_missing_body_at_line_file(line_file: LineFile) -> Self {
283 let (line_no, path) = (line_file.0, line_file.1.as_ref());
284 Self::new_parse_error_with_msg_position_previous_error(
285 format!("block header missing body at line {} in {}", line_no, path),
286 line_file,
287 None,
288 )
289 }
290
291 pub fn new_parse_error_for_block_inconsistent_indent_at_line_file(line_file: LineFile) -> Self {
292 let (line_no, path) = (line_file.0, line_file.1.as_ref());
293 Self::new_parse_error_with_msg_position_previous_error(
294 format!("inconsistent indent at line {} in {}", line_no, path),
295 line_file,
296 None,
297 )
298 }
299
300 pub fn new_verify_error_with_fact_msg_position_previous_error(
301 fact: Fact,
302 msg: String,
303 line_file: LineFile,
304 previous_error: Option<RuntimeError>,
305 ) -> Self {
306 VerifyRuntimeError(RuntimeErrorStruct::new(
307 Some(fact.into_stmt()),
308 msg,
309 line_file,
310 previous_error,
311 ))
312 .into()
313 }
314
315 pub fn new_verify_error_with_msg_position_previous_error(
316 msg: String,
317 line_file: LineFile,
318 previous_error: Option<RuntimeError>,
319 ) -> Self {
320 VerifyRuntimeError(RuntimeErrorStruct::new(
321 None,
322 msg,
323 line_file,
324 previous_error,
325 ))
326 .into()
327 }
328
329 pub fn new_unknown_error_with_msg_position_optional_fact_previous_error(
330 msg: String,
331 line_file: LineFile,
332 fact: Option<Fact>,
333 previous_error: Option<RuntimeError>,
334 ) -> Self {
335 UnknownRuntimeError(RuntimeErrorStruct::new(
336 if let Some(fact) = fact {
337 Some(fact.into_stmt())
338 } else {
339 None
340 },
341 msg,
342 line_file,
343 previous_error,
344 ))
345 .into()
346 }
347
348 pub fn new_verify_result_unknown_with_fact_previous_error(
349 fact: Fact,
350 msg: String,
351 previous_error: Option<RuntimeError>,
352 ) -> Self {
353 let line_file = fact.line_file();
354 RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
355 msg,
356 line_file,
357 Some(fact),
358 previous_error,
359 )
360 }
361
362 pub fn new_well_defined_error_with_msg_previous_error_position(
363 msg: String,
364 previous_error: Option<RuntimeError>,
365 line_file: LineFile,
366 ) -> Self {
367 WellDefinedRuntimeError(RuntimeErrorStruct::new(
368 None,
369 msg,
370 line_file,
371 previous_error,
372 ))
373 .into()
374 }
375
376 pub fn new_well_defined_error_wrapping_verify_runtime_error(e: RuntimeError) -> RuntimeError {
377 match e {
378 RuntimeError::VerifyError(inner) => {
379 let line_file = inner.line_file.clone();
380 let msg_for_well_defined = if inner.msg.is_empty() {
381 "verify fact error:".to_string()
382 } else {
383 inner.msg.clone()
384 };
385 WellDefinedRuntimeError(RuntimeErrorStruct::new(
386 None,
387 msg_for_well_defined,
388 line_file,
389 Some(VerifyRuntimeError(inner).into()),
390 ))
391 .into()
392 }
393 _ => e,
394 }
395 }
396}
397
398impl fmt::Display for RuntimeError {
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 write!(f, "{}", "error")
402 }
403}
404
405impl fmt::Display for RuntimeErrorStruct {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 write!(f, "{}", self.msg)
408 }
409}
410
411impl std::error::Error for RuntimeErrorStruct {}
412
413impl From<RuntimeErrorStruct> for RuntimeError {
414 fn from(runtime_error_struct: RuntimeErrorStruct) -> Self {
415 runtime_error_struct.into()
416 }
417}
418
419fn boxed_previous_error(previous_error: Option<RuntimeError>) -> Option<Box<RuntimeError>> {
420 previous_error.map(Box::new)
421}