Skip to main content

shape_ast/error/
types.rs

1//! Core error types and enums for Shape
2//!
3//! This module contains the main error types used throughout Shape,
4//! including the unified ShapeError enum and location tracking structures.
5
6use std::io;
7use std::path::PathBuf;
8use thiserror::Error;
9
10use super::parse_error::StructuredParseError;
11
12/// The main error type for Shape operations
13#[derive(Debug, Error)]
14pub enum ShapeError {
15    /// Structured parse errors (preferred - provides rich context for rendering)
16    #[error("{0}")]
17    StructuredParse(#[source] Box<StructuredParseError>),
18
19    /// Legacy parser errors (kept for compatibility)
20    #[error("Parse error: {message}")]
21    ParseError {
22        message: String,
23        location: Option<SourceLocation>,
24    },
25
26    /// Lexer errors
27    #[error("Lexical error: {message}")]
28    LexError {
29        message: String,
30        location: Option<SourceLocation>,
31    },
32
33    /// Type system errors
34    #[error("Type error: {0}")]
35    TypeError(String),
36
37    /// Semantic analysis errors
38    #[error("Semantic error: {message}")]
39    SemanticError {
40        message: String,
41        location: Option<SourceLocation>,
42    },
43
44    /// Runtime evaluation errors
45    #[error("Runtime error: {message}")]
46    RuntimeError {
47        message: String,
48        location: Option<SourceLocation>,
49    },
50
51    /// VM execution errors
52    #[error("VM error: {0}")]
53    VMError(String),
54
55    /// Control flow errors (break/continue/return)
56    #[error("Control flow error")]
57    ControlFlow(std::sync::Arc<dyn std::any::Any + Send + Sync>),
58
59    /// Pattern matching errors
60    #[error("Pattern error: {message}")]
61    PatternError {
62        message: String,
63        pattern_name: Option<String>,
64    },
65
66    /// Data errors
67    #[error("Data error: {message}")]
68    DataError {
69        message: String,
70        symbol: Option<String>,
71        timeframe: Option<String>,
72    },
73
74    /// Module loading errors
75    #[error("Module error: {message}")]
76    ModuleError {
77        message: String,
78        module_path: Option<PathBuf>,
79    },
80
81    /// I/O errors
82    #[error("I/O error: {0}")]
83    IoError(#[from] io::Error),
84
85    /// Simulation execution errors
86    #[error("Simulation error: {message}")]
87    SimulationError {
88        message: String,
89        simulation_name: Option<String>,
90    },
91
92    /// Data provider errors
93    #[error("Data provider error: {message}")]
94    DataProviderError {
95        message: String,
96        provider: Option<String>,
97    },
98
99    /// Test framework errors
100    #[error("Test error: {message}")]
101    TestError {
102        message: String,
103        test_name: Option<String>,
104    },
105
106    /// Configuration errors
107    #[error("Configuration error: {message}")]
108    ConfigError { message: String },
109
110    /// Stream processing errors
111    #[error("Stream error: {message}")]
112    StreamError {
113        message: String,
114        stream_name: Option<String>,
115    },
116
117    /// Cache errors
118    #[error("Cache error: {message}")]
119    CacheError { message: String },
120
121    /// Alignment errors
122    #[error("Alignment error: {message}")]
123    AlignmentError { message: String, ids: Vec<String> },
124
125    /// Multiple errors collected during analysis
126    #[error("{}", MultiError::format(.0))]
127    MultiError(Vec<ShapeError>),
128
129    /// Execution interrupted by Ctrl+C (with optional snapshot hash)
130    #[error("Interrupted")]
131    Interrupted { snapshot_hash: Option<String> },
132
133    /// Generic errors with custom messages
134    #[error("{0}")]
135    Custom(String),
136}
137
138/// Helper for formatting MultiError
139pub struct MultiError;
140
141impl MultiError {
142    /// Format a list of errors separated by blank lines
143    pub fn format(errors: &[ShapeError]) -> String {
144        errors
145            .iter()
146            .map(|e| e.to_string())
147            .collect::<Vec<_>>()
148            .join("\n\n")
149    }
150}
151
152/// Source location information for error reporting
153#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
154pub struct SourceLocation {
155    pub file: Option<String>,
156    pub line: usize,
157    pub column: usize,
158    pub length: Option<usize>,
159    pub source_line: Option<String>,
160    pub hints: Vec<String>,
161    pub notes: Vec<ErrorNote>,
162    #[serde(default)]
163    pub is_synthetic: bool,
164}
165
166impl SourceLocation {
167    pub fn new(line: usize, column: usize) -> Self {
168        Self {
169            file: None,
170            line,
171            column,
172            length: None,
173            source_line: None,
174            hints: Vec::new(),
175            notes: Vec::new(),
176            is_synthetic: false,
177        }
178    }
179
180    pub fn with_file(mut self, file: String) -> Self {
181        self.file = Some(file);
182        self
183    }
184
185    pub fn with_length(mut self, length: usize) -> Self {
186        self.length = Some(length);
187        self
188    }
189
190    pub fn with_source_line(mut self, line: String) -> Self {
191        self.source_line = Some(line);
192        self
193    }
194}
195
196/// Error codes for structured error reporting
197#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
198pub enum ErrorCode {
199    E0001, // Unexpected token
200    E0002, // Unterminated string/comment
201    E0003, // Invalid number
202    E0004, // Missing semicolon
203    E0005, // Unbalanced delimiter
204    E0100, // Type mismatch
205    E0101, // Undefined identifier
206    E0102, // Missing property
207    E0103, // Invalid arguments
208    E0105, // Property access error
209    E0200, // Duplicate declaration
210    E0202, // Break outside loop
211    E0203, // Continue outside loop
212    E0204, // Return outside function
213    E0300, // Division by zero
214    E0301, // Index out of bounds
215    E0302, // Null pointer/reference
216    E0303, // Stack overflow
217    E0400, // Data access error
218    E0403, // Alignment error
219    ParseError,
220    TypeError,
221    SemanticError,
222    RuntimeError,
223    DataError,
224    ModuleError,
225}
226
227impl ErrorCode {
228    pub fn as_str(&self) -> &'static str {
229        match self {
230            ErrorCode::E0001 => "E0001",
231            ErrorCode::E0002 => "E0002",
232            ErrorCode::E0003 => "E0003",
233            ErrorCode::E0004 => "E0004",
234            ErrorCode::E0005 => "E0005",
235            ErrorCode::E0100 => "E0100",
236            ErrorCode::E0101 => "E0101",
237            ErrorCode::E0102 => "E0102",
238            ErrorCode::E0103 => "E0103",
239            ErrorCode::E0105 => "E0105",
240            ErrorCode::E0200 => "E0200",
241            ErrorCode::E0202 => "E0202",
242            ErrorCode::E0203 => "E0203",
243            ErrorCode::E0204 => "E0204",
244            ErrorCode::E0300 => "E0300",
245            ErrorCode::E0301 => "E0301",
246            ErrorCode::E0302 => "E0302",
247            ErrorCode::E0303 => "E0303",
248            ErrorCode::E0400 => "E0400",
249            ErrorCode::E0403 => "E0403",
250            ErrorCode::ParseError => "PARSE",
251            ErrorCode::TypeError => "TYPE",
252            ErrorCode::SemanticError => "SEMANTIC",
253            ErrorCode::RuntimeError => "RUNTIME",
254            ErrorCode::DataError => "DATA",
255            ErrorCode::ModuleError => "MODULE",
256        }
257    }
258}
259
260/// Additional notes for error messages
261#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
262pub struct ErrorNote {
263    pub message: String,
264    pub location: Option<SourceLocation>,
265}