1use std::fmt;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Error, Debug)]
11pub enum Error {
12 #[error("Lexer error at line {line}, column {column}: {message}")]
14 LexerError {
15 line: usize,
17 column: usize,
19 message: String,
21 },
22
23 #[error("Parse error at line {line}: {message}")]
25 ParseError {
26 line: usize,
28 message: String,
30 },
31
32 #[error("Runtime error: {message}")]
34 RuntimeError {
35 message: String,
37 stack_trace: Option<Vec<String>>,
39 },
40
41 #[error("Variable '{name}' is not defined")]
43 UndefinedVariable {
44 name: String,
46 },
47
48 #[error("Function '{name}' is not defined")]
50 UndefinedFunction {
51 name: String,
53 },
54
55 #[error("Type error: expected {expected}, got {actual}")]
57 TypeError {
58 expected: String,
60 actual: String,
62 },
63
64 #[error("Argument error: expected {expected} arguments, got {actual}")]
66 ArgumentError {
67 expected: usize,
69 actual: usize,
71 },
72
73 #[error("IO error: {0}")]
75 IoError(#[from] std::io::Error),
76
77 #[error("Network error: {0}")]
79 NetworkError(String),
80
81 #[error("AI service error: {0}")]
83 AiError(String),
84
85 #[error("JSON error: {0}")]
87 JsonError(#[from] serde_json::Error),
88
89 #[error("Internal error: {0}")]
91 InternalError(String),
92}
93
94impl Error {
95 pub fn lexer_error(line: usize, column: usize, message: impl Into<String>) -> Self {
97 Self::LexerError {
98 line,
99 column,
100 message: message.into(),
101 }
102 }
103
104 pub fn parse_error(line: usize, message: impl Into<String>) -> Self {
106 Self::ParseError {
107 line,
108 message: message.into(),
109 }
110 }
111
112 pub fn runtime_error(message: impl Into<String>) -> Self {
114 Self::RuntimeError {
115 message: message.into(),
116 stack_trace: None,
117 }
118 }
119
120 pub fn runtime_error_with_trace(
122 message: impl Into<String>,
123 stack_trace: Vec<String>,
124 ) -> Self {
125 Self::RuntimeError {
126 message: message.into(),
127 stack_trace: Some(stack_trace),
128 }
129 }
130
131 pub fn undefined_variable(name: impl Into<String>) -> Self {
133 Self::UndefinedVariable { name: name.into() }
134 }
135
136 pub fn undefined_function(name: impl Into<String>) -> Self {
138 Self::UndefinedFunction { name: name.into() }
139 }
140
141 pub fn type_error(expected: impl Into<String>, actual: impl Into<String>) -> Self {
143 Self::TypeError {
144 expected: expected.into(),
145 actual: actual.into(),
146 }
147 }
148
149 pub fn argument_error(expected: usize, actual: usize) -> Self {
151 Self::ArgumentError { expected, actual }
152 }
153
154 pub fn network_error(message: impl Into<String>) -> Self {
156 Self::NetworkError(message.into())
157 }
158
159 pub fn ai_error(message: impl Into<String>) -> Self {
161 Self::AiError(message.into())
162 }
163
164 pub fn internal_error(message: impl Into<String>) -> Self {
166 Self::InternalError(message.into())
167 }
168
169 pub fn is_recoverable(&self) -> bool {
171 matches!(
172 self,
173 Error::UndefinedVariable { .. }
174 | Error::UndefinedFunction { .. }
175 | Error::TypeError { .. }
176 | Error::ArgumentError { .. }
177 )
178 }
179
180 pub fn severity(&self) -> ErrorSeverity {
182 match self {
183 Error::LexerError { .. } | Error::ParseError { .. } => ErrorSeverity::Fatal,
184 Error::RuntimeError { .. } => ErrorSeverity::Error,
185 Error::UndefinedVariable { .. }
186 | Error::UndefinedFunction { .. }
187 | Error::TypeError { .. }
188 | Error::ArgumentError { .. } => ErrorSeverity::Error,
189 Error::IoError(_) | Error::NetworkError(_) | Error::AiError(_) => ErrorSeverity::Warning,
190 Error::JsonError(_) | Error::InternalError(_) => ErrorSeverity::Fatal,
191 }
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub enum ErrorSeverity {
198 Fatal,
200 Error,
202 Warning,
204}
205
206impl fmt::Display for ErrorSeverity {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 match self {
209 ErrorSeverity::Fatal => write!(f, "FATAL"),
210 ErrorSeverity::Error => write!(f, "ERROR"),
211 ErrorSeverity::Warning => write!(f, "WARNING"),
212 }
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn test_error_creation() {
222 let err = Error::lexer_error(1, 10, "Unexpected character");
223 assert!(matches!(err, Error::LexerError { line: 1, column: 10, .. }));
224 assert_eq!(err.severity(), ErrorSeverity::Fatal);
225 }
226
227 #[test]
228 fn test_error_recoverability() {
229 let recoverable = Error::undefined_variable("x");
230 assert!(recoverable.is_recoverable());
231
232 let fatal = Error::lexer_error(1, 1, "Invalid token");
233 assert!(!fatal.is_recoverable());
234 }
235}