1use thiserror::Error;
4
5#[derive(Error, Debug, Clone, PartialEq)]
7pub enum XdlError {
8 #[error("Parse error: {message} at line {line}, column {column}")]
9 ParseError {
10 message: String,
11 line: usize,
12 column: usize,
13 },
14
15 #[error("Type mismatch: expected {expected}, got {actual}")]
16 TypeMismatch { expected: String, actual: String },
17
18 #[error("Dimension error: {0}")]
19 DimensionError(String),
20
21 #[error("Index error: {0}")]
22 IndexError(String),
23
24 #[error("Runtime error: {0}")]
25 RuntimeError(String),
26
27 #[error("Variable not found: {0}")]
28 VariableNotFound(String),
29
30 #[error("Function not found: {0}")]
31 FunctionNotFound(String),
32
33 #[error("Procedure not found: {0}")]
34 ProcedureNotFound(String),
35
36 #[error("Invalid argument: {0}")]
37 InvalidArgument(String),
38
39 #[error("IO error: {0}")]
40 IoError(String),
41
42 #[error("Math error: {0}")]
43 MathError(String),
44
45 #[error("Memory error: {0}")]
46 MemoryError(String),
47
48 #[error("System error: {0}")]
49 SystemError(String),
50
51 #[error("Compile error: {0}")]
52 CompileError(String),
53
54 #[error("Syntax error: {0}")]
55 SyntaxError(String),
56
57 #[error("File not found: {0}")]
58 FileNotFound(String),
59
60 #[error("Division by zero")]
61 DivisionByZero,
62
63 #[error("Overflow error in {operation}")]
64 Overflow { operation: String },
65
66 #[error("Underflow error in {operation}")]
67 Underflow { operation: String },
68
69 #[error("Not implemented: {0}")]
70 NotImplemented(String),
71
72 #[error("Internal error: {0}")]
73 InternalError(String),
74
75 #[error("Break")]
77 Break,
78
79 #[error("Continue")]
80 Continue,
81
82 #[error("Return")]
83 Return(crate::XdlValue),
84
85 #[error("Goto: {0}")]
86 Goto(String),
87
88 #[error("Invalid assignment target")]
89 InvalidAssignmentTarget,
90
91 #[error("Invalid value: {0}")]
92 InvalidValue(String),
93}
94
95impl From<std::io::Error> for XdlError {
96 fn from(err: std::io::Error) -> Self {
97 XdlError::IoError(err.to_string())
98 }
99}
100
101impl<T> From<plotters::drawing::DrawingAreaErrorKind<T>> for XdlError
103where
104 T: std::error::Error + Send + Sync + 'static,
105{
106 fn from(err: plotters::drawing::DrawingAreaErrorKind<T>) -> Self {
107 XdlError::SystemError(format!("Drawing error: {}", err))
108 }
109}
110
111pub type XdlResult<T> = Result<T, XdlError>;
113
114pub trait XdlErrorContext<T> {
116 fn gdl_context(self, context: &str) -> XdlResult<T>;
117}
118
119impl<T> XdlErrorContext<T> for Option<T> {
120 fn gdl_context(self, context: &str) -> XdlResult<T> {
121 self.ok_or_else(|| XdlError::RuntimeError(context.to_string()))
122 }
123}
124
125impl<T, E: std::error::Error> XdlErrorContext<T> for Result<T, E> {
126 fn gdl_context(self, context: &str) -> XdlResult<T> {
127 self.map_err(|e| XdlError::RuntimeError(format!("{}: {}", context, e)))
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_error_display() {
137 let err = XdlError::TypeMismatch {
138 expected: "FLOAT".to_string(),
139 actual: "STRING".to_string(),
140 };
141 assert_eq!(err.to_string(), "Type mismatch: expected FLOAT, got STRING");
142 }
143
144 #[test]
145 fn test_error_context() {
146 let none_val: Option<i32> = None;
147 let result = none_val.gdl_context("test operation");
148 assert!(matches!(result, Err(XdlError::RuntimeError(_))));
149 }
150}