1use std::path::PathBuf;
2use std::fmt;
3use thiserror::Error;
4use crate::lexer::SourceLocation;
5
6#[derive(Error, Debug)]
7pub enum HlxError {
8 #[error("Configuration conversion failed: {field} - {details}")]
9 ConfigConversion {
10 field: String,
11 details: String,
12 suggestion: String
13 },
14
15 #[error("Dataset processing failed: {message}")]
16 DatasetProcessing {
17 message: String,
18 suggestion: String
19 },
20
21 #[error("Dataset quality validation failed: score {score:.2}")]
22 QualityValidation {
23 score: f64,
24 issues: Vec<String>,
25 suggestions: Vec<String>
26 },
27
28 #[error("Format conversion failed: {from} → {to}")]
29 FormatConversion {
30 from: String,
31 to: String,
32 suggestion: String
33 },
34
35 #[error("Algorithm '{algorithm}' not supported")]
36 UnsupportedAlgorithm {
37 algorithm: String,
38 supported: Vec<String>
39 },
40
41 #[error("Dataset not found: {path}")]
42 DatasetNotFound {
43 path: PathBuf,
44 suggestion: String
45 },
46
47 #[error("HLX processing failed: {message}")]
48 HlxProcessing {
49 message: String,
50 suggestion: String
51 },
52
53 #[error("Forge integration failed: {message}")]
54 ForgeIntegration {
55 message: String,
56 suggestion: String
57 },
58
59 #[error("Configuration validation failed: {field} = {value}")]
60 ConfigValidation {
61 field: String,
62 value: String,
63 suggestion: String
64 },
65}
66
67impl HlxError {
68 pub fn config_conversion(field: impl Into<String>, details: impl Into<String>) -> Self {
70 let field = field.into();
71 let details = details.into();
72 let suggestion = format!("Check your Forge.toml configuration for the '{}' field", field);
73 Self::ConfigConversion { field, details, suggestion }
74 }
75
76 pub fn dataset_processing(message: impl Into<String>) -> Self {
78 let message = message.into();
79 let suggestion = "Try running 'forge hlx dataset validate' to check dataset compatibility".to_string();
80 Self::DatasetProcessing { message, suggestion }
81 }
82
83 pub fn quality_validation(score: f64, issues: Vec<String>) -> Self {
85 let suggestions = vec![
86 "Run 'forge hlx dataset analyze' for detailed quality metrics".to_string(),
87 "Consider filtering or augmenting low-quality samples".to_string(),
88 "Check dataset format and required columns".to_string(),
89 ];
90 Self::QualityValidation { score, issues, suggestions }
91 }
92
93 pub fn format_conversion(from: impl Into<String>, to: impl Into<String>) -> Self {
95 let from = from.into();
96 let to = to.into();
97 let suggestion = format!("Ensure your dataset contains the required fields for {} format", to);
98 Self::FormatConversion { from, to, suggestion }
99 }
100
101 pub fn unsupported_algorithm(algorithm: impl Into<String>) -> Self {
103 let algorithm = algorithm.into();
104 let supported = vec!["bco", "dpo", "ppo", "sft"]
105 .into_iter()
106 .map(String::from)
107 .collect();
108 Self::UnsupportedAlgorithm { algorithm, supported }
109 }
110
111 pub fn dataset_not_found(path: PathBuf) -> Self {
113 let suggestion = format!("Ensure the dataset file exists at: {}", path.display());
114 Self::DatasetNotFound { path, suggestion }
115 }
116
117 pub fn suggestions(&self) -> Vec<String> {
119 match self {
120 Self::ConfigConversion { suggestion, .. } => vec![suggestion.clone()],
121 Self::DatasetProcessing { suggestion, .. } => vec![suggestion.clone()],
122 Self::QualityValidation { suggestions, .. } => suggestions.clone(),
123 Self::FormatConversion { suggestion, .. } => vec![suggestion.clone()],
124 Self::UnsupportedAlgorithm { supported, .. } => {
125 vec![format!("Supported algorithms: {}", supported.join(", "))]
126 }
127 Self::DatasetNotFound { suggestion, .. } => vec![suggestion.clone()],
128 Self::HlxProcessing { suggestion, .. } => vec![suggestion.clone()],
129 Self::ForgeIntegration { suggestion, .. } => vec![suggestion.clone()],
130 Self::ConfigValidation { suggestion, .. } => vec![suggestion.clone()],
131 }
132 }
133
134 pub fn is_recoverable(&self) -> bool {
136 match self {
137 Self::ConfigConversion { .. } => true,
138 Self::DatasetProcessing { .. } => true,
139 Self::QualityValidation { score, .. } => *score > 0.3, Self::FormatConversion { .. } => true,
141 Self::UnsupportedAlgorithm { .. } => false,
142 Self::DatasetNotFound { .. } => false,
143 Self::HlxProcessing { .. } => true,
144 Self::ForgeIntegration { .. } => true,
145 Self::ConfigValidation { .. } => true,
146 }
147 }
148}
149
150pub type HlxResult<T> = std::result::Result<T, HlxError>;
152
153#[derive(Debug)]
154pub enum HelixError {
155 Lexer(LexerError),
156 Parser(ParserError),
157 Semantic(SemanticError),
158 Compilation(CompilationError),
159 Runtime(RuntimeError),
160 Io(IoError),
161}
162#[derive(Debug)]
163pub struct LexerError {
164 pub message: String,
165 pub location: SourceLocation,
166 pub source_line: String,
167 pub suggestion: Option<String>,
168}
169#[derive(Debug)]
170pub struct ParserError {
171 pub message: String,
172 pub location: SourceLocation,
173 pub expected: Vec<String>,
174 pub found: String,
175 pub source_line: String,
176 pub suggestion: Option<String>,
177}
178#[derive(Debug)]
179pub struct SemanticError {
180 pub kind: SemanticErrorKind,
181 pub location: SourceLocation,
182 pub entity: String,
183 pub context: Vec<String>,
184}
185#[derive(Debug)]
186pub enum SemanticErrorKind {
187 UndefinedReference,
188 DuplicateDefinition,
189 TypeMismatch { expected: String, found: String },
190 CircularDependency,
191 InvalidValue,
192 MissingRequired,
193 DeprecatedFeature,
194}
195#[derive(Debug)]
196pub struct CompilationError {
197 pub stage: CompilationStage,
198 pub message: String,
199 pub file: Option<PathBuf>,
200 pub recoverable: bool,
201}
202#[derive(Debug)]
203pub enum CompilationStage {
204 Parsing,
205 Validation,
206 Optimization,
207 CodeGeneration,
208 Serialization,
209 Bundling,
210}
211#[derive(Debug)]
212pub struct RuntimeError {
213 pub kind: RuntimeErrorKind,
214 pub message: String,
215 pub stack_trace: Vec<String>,
216}
217#[derive(Debug, PartialEq)]
218pub enum RuntimeErrorKind {
219 InvalidInstruction,
220 StackUnderflow,
221 StackOverflow,
222 MemoryAccessViolation,
223 DivisionByZero,
224 TypeConversion,
225 ResourceNotFound,
226}
227#[derive(Debug)]
228pub struct IoError {
229 pub operation: IoOperation,
230 pub path: PathBuf,
231 pub message: String,
232}
233#[derive(Debug)]
234pub enum IoOperation {
235 Read,
236 Write,
237 Create,
238 Delete,
239 Rename,
240 Metadata,
241}
242impl fmt::Display for HelixError {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244 match self {
245 HelixError::Lexer(e) => write!(f, "{}", e),
246 HelixError::Parser(e) => write!(f, "{}", e),
247 HelixError::Semantic(e) => write!(f, "{}", e),
248 HelixError::Compilation(e) => write!(f, "{}", e),
249 HelixError::Runtime(e) => write!(f, "{}", e),
250 HelixError::Io(e) => write!(f, "{}", e),
251 }
252 }
253}
254impl fmt::Display for LexerError {
255 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256 writeln!(f, "Lexer error at {}:{}", self.location.line, self.location.column)?;
257 writeln!(f, " {}", self.message)?;
258 writeln!(f, " {}", self.source_line)?;
259 writeln!(f, " {}^", " ".repeat(self.location.column))?;
260 if let Some(suggestion) = &self.suggestion {
261 writeln!(f, " Suggestion: {}", suggestion)?;
262 }
263 Ok(())
264 }
265}
266impl fmt::Display for ParserError {
267 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 writeln!(f, "Parser error at {}:{}", self.location.line, self.location.column)?;
269 writeln!(f, " {}", self.message)?;
270 writeln!(f, " {}", self.source_line)?;
271 writeln!(f, " {}^", " ".repeat(self.location.column))?;
272 if !self.expected.is_empty() {
273 writeln!(f, " Expected: {}", self.expected.join(" | "))?;
274 }
275 writeln!(f, " Found: {}", self.found)?;
276 if let Some(suggestion) = &self.suggestion {
277 writeln!(f, " Suggestion: {}", suggestion)?;
278 }
279 Ok(())
280 }
281}
282impl fmt::Display for SemanticError {
283 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
284 write!(f, "Semantic error: ")?;
285 match &self.kind {
286 SemanticErrorKind::UndefinedReference => {
287 writeln!(f, "Undefined reference to '{}'", self.entity)?;
288 }
289 SemanticErrorKind::DuplicateDefinition => {
290 writeln!(f, "Duplicate definition of '{}'", self.entity)?;
291 }
292 SemanticErrorKind::TypeMismatch { expected, found } => {
293 writeln!(
294 f, "Type mismatch for '{}': expected {}, found {}", self.entity,
295 expected, found
296 )?;
297 }
298 SemanticErrorKind::CircularDependency => {
299 writeln!(f, "Circular dependency involving '{}'", self.entity)?;
300 }
301 SemanticErrorKind::InvalidValue => {
302 writeln!(f, "Invalid value for '{}'", self.entity)?;
303 }
304 SemanticErrorKind::MissingRequired => {
305 writeln!(f, "Missing required field '{}'", self.entity)?;
306 }
307 SemanticErrorKind::DeprecatedFeature => {
308 writeln!(f, "Use of deprecated feature '{}'", self.entity)?;
309 }
310 }
311 writeln!(f, " at {}:{}", self.location.line, self.location.column)?;
312 if !self.context.is_empty() {
313 writeln!(f, " Context:")?;
314 for ctx in &self.context {
315 writeln!(f, " - {}", ctx)?;
316 }
317 }
318 Ok(())
319 }
320}
321impl fmt::Display for CompilationError {
322 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323 write!(f, "Compilation error during {:?}: {}", self.stage, self.message)?;
324 if let Some(file) = &self.file {
325 write!(f, " in file {:?}", file)?;
326 }
327 if self.recoverable {
328 write!(f, " (recoverable)")?;
329 }
330 Ok(())
331 }
332}
333impl fmt::Display for RuntimeError {
334 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335 writeln!(f, "Runtime error: {:?}", self.kind)?;
336 writeln!(f, " {}", self.message)?;
337 if !self.stack_trace.is_empty() {
338 writeln!(f, " Stack trace:")?;
339 for frame in &self.stack_trace {
340 writeln!(f, " {}", frame)?;
341 }
342 }
343 Ok(())
344 }
345}
346impl fmt::Display for IoError {
347 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348 write!(
349 f, "IO error during {:?} operation on {:?}: {}", self.operation, self.path,
350 self.message
351 )
352 }
353}
354impl std::error::Error for HelixError {}
355impl std::error::Error for LexerError {}
356impl std::error::Error for ParserError {}
357impl std::error::Error for SemanticError {}
358impl std::error::Error for CompilationError {}
359impl std::error::Error for RuntimeError {}
360impl std::error::Error for IoError {}
361impl From<std::io::Error> for HelixError {
362 fn from(err: std::io::Error) -> Self {
363 HelixError::Io(IoError {
364 operation: IoOperation::Read,
365 path: PathBuf::new(),
366 message: err.to_string(),
367 })
368 }
369}
370pub type Result<T> = std::result::Result<T, HelixError>;
371pub struct ErrorRecovery;
372impl ErrorRecovery {
373 pub fn suggest_for_undefined_reference(name: &str) -> Option<String> {
374 if name == "agnet" {
375 return Some("Did you mean 'agent'?".to_string());
376 }
377 if name == "worfklow" || name == "workfow" {
378 return Some("Did you mean 'workflow'?".to_string());
379 }
380 None
381 }
382 pub fn suggest_for_syntax_error(found: &str, expected: &[String]) -> Option<String> {
383 if expected.contains(&"=".to_string()) && found == ":" {
384 return Some("Use '=' for assignment, not ':'".to_string());
385 }
386 if expected.contains(&"{".to_string()) && found == "(" {
387 return Some("Use '{' for block start, not '('".to_string());
388 }
389 None
390 }
391}