Skip to main content

litex/error/
error.rs

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
398// Display outputs a short placeholder; JSON: `display_runtime_error_json` in `crate::pipeline`.
399impl 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}