Skip to main content

orrery_parser/error/
error_code.rs

1//! Error codes for the Orrery diagnostic system.
2//!
3//! Error codes are organized by phase:
4//! - `E0xx` - Lexer errors
5//! - `E1xx` - Parser errors
6//! - `E2xx` - Validation errors
7//! - `E3xx` - Elaboration errors
8//! - `E4xx` - Resolver errors
9
10use std::fmt;
11
12/// Error codes for categorizing diagnostic errors.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum ErrorCode {
15    // =========================================================================
16    // Lexer Errors (E0xx)
17    // =========================================================================
18    /// Unterminated string literal.
19    ///
20    /// A string was opened with a quote but never closed.
21    E001,
22
23    /// Unexpected character.
24    ///
25    /// A character was encountered that is not valid in this context.
26    E002,
27
28    /// Invalid escape sequence.
29    ///
30    /// An unrecognized escape sequence was used in a string literal.
31    /// Valid escapes are: `\n`, `\r`, `\t`, `\b`, `\f`, `\\`, `\/`, `\'`, `\"`, `\0`, `\u{...}`.
32    E003,
33
34    /// Invalid unicode escape format.
35    ///
36    /// A unicode escape sequence was malformed. Unicode escapes must use
37    /// the format `\u{XXXX}` with 1-6 hexadecimal digits.
38    E004,
39
40    /// Invalid unicode codepoint.
41    ///
42    /// The unicode codepoint is out of range or in the surrogate range.
43    /// Valid codepoints are 0x0000-0xD7FF and 0xE000-0x10FFFF.
44    E005,
45
46    /// Empty unicode escape.
47    ///
48    /// A unicode escape `\u{}` was found with no hexadecimal digits.
49    E006,
50
51    // =========================================================================
52    // Parser Errors (E1xx)
53    // =========================================================================
54    /// Unexpected token.
55    ///
56    /// The parser encountered a token it did not expect at this position.
57    E100,
58
59    /// Incomplete input.
60    ///
61    /// The input ended unexpectedly before a complete construct was parsed.
62    E101,
63
64    // =========================================================================
65    // Validation Errors (E2xx)
66    // =========================================================================
67    /// Undefined component reference.
68    ///
69    /// A component was referenced that has not been defined.
70    E200,
71
72    /// Unpaired activate statement.
73    ///
74    /// An `activate` statement has no matching `deactivate`.
75    E201,
76
77    /// Unpaired deactivate statement.
78    ///
79    /// A `deactivate` statement has no matching `activate`.
80    E202,
81
82    /// Invalid align value for diagram type.
83    ///
84    /// The specified alignment is not valid for this diagram type.
85    E203,
86
87    /// Unknown embed reference.
88    ///
89    /// An `embed <name>` references an identifier that doesn't match any
90    /// namespaced import in the current file.
91    E204,
92
93    // =========================================================================
94    // Elaboration Errors (E3xx)
95    // =========================================================================
96    /// Undefined type reference.
97    ///
98    /// A type was referenced that has not been defined.
99    E300,
100
101    /// Type override not supported.
102    ///
103    /// Overriding is not supported for this type.
104    E301,
105
106    /// Invalid attribute value.
107    ///
108    /// An attribute value is not valid for the expected type.
109    E302,
110
111    /// Unknown attribute.
112    ///
113    /// An attribute was specified that is not recognized.
114    E303,
115
116    /// Unsupported attribute for shape/type.
117    ///
118    /// The attribute is valid but not supported for this particular shape or type.
119    E304,
120
121    /// Nested diagram not allowed.
122    ///
123    /// A diagram definition was found inside another diagram.
124    E305,
125
126    /// Invalid diagram structure.
127    ///
128    /// The diagram structure is invalid or malformed.
129    E306,
130
131    /// Type mismatch.
132    ///
133    /// A type was used in a context where a different kind of type was expected
134    /// (e.g., using an Arrow type where a Shape type is required).
135    E307,
136
137    /// Shape does not support nested content.
138    ///
139    /// An attempt was made to add nested content to a shape type that
140    /// does not support it.
141    E308,
142
143    /// Unresolved embed reference.
144    ///
145    /// An `embed <name>` references a diagram that could not be resolved.
146    E309,
147
148    // =========================================================================
149    // Resolver Errors (E4xx)
150    // =========================================================================
151    /// File not found.
152    ///
153    /// A source file referenced by an import declaration or passed as the
154    /// root entry point could not be resolved or read.
155    E400,
156
157    /// Circular dependency.
158    ///
159    /// A file appears in its own import chain, forming a cycle.
160    E401,
161
162    /// Invalid import path.
163    ///
164    /// An import path is malformed (e.g., empty).
165    E402,
166
167    /// Invalid namespace derivation.
168    ///
169    /// A namespace identifier could not be derived from the import path
170    /// (e.g., the path has no file stem or contains non-UTF-8 components).
171    E403,
172}
173
174impl ErrorCode {
175    /// Returns the numeric code as a string (e.g., "E001").
176    pub fn as_str(&self) -> &'static str {
177        match self {
178            // Lexer errors
179            ErrorCode::E001 => "E001",
180            ErrorCode::E002 => "E002",
181            ErrorCode::E003 => "E003",
182            ErrorCode::E004 => "E004",
183            ErrorCode::E005 => "E005",
184            ErrorCode::E006 => "E006",
185            // Parser errors
186            ErrorCode::E100 => "E100",
187            ErrorCode::E101 => "E101",
188            // Validation errors
189            ErrorCode::E200 => "E200",
190            ErrorCode::E201 => "E201",
191            ErrorCode::E202 => "E202",
192            ErrorCode::E203 => "E203",
193            ErrorCode::E204 => "E204",
194            // Elaboration errors
195            ErrorCode::E300 => "E300",
196            ErrorCode::E301 => "E301",
197            ErrorCode::E302 => "E302",
198            ErrorCode::E303 => "E303",
199            ErrorCode::E304 => "E304",
200            ErrorCode::E305 => "E305",
201            ErrorCode::E306 => "E306",
202            ErrorCode::E307 => "E307",
203            ErrorCode::E308 => "E308",
204            ErrorCode::E309 => "E309",
205            // Resolver errors
206            ErrorCode::E400 => "E400",
207            ErrorCode::E401 => "E401",
208            ErrorCode::E402 => "E402",
209            ErrorCode::E403 => "E403",
210        }
211    }
212
213    /// Returns a short description of what this error code means.
214    pub fn description(&self) -> &'static str {
215        match self {
216            // Lexer errors
217            ErrorCode::E001 => "unterminated string literal",
218            ErrorCode::E002 => "unexpected character",
219            ErrorCode::E003 => "invalid escape sequence",
220            ErrorCode::E004 => "invalid unicode escape",
221            ErrorCode::E005 => "invalid unicode codepoint",
222            ErrorCode::E006 => "empty unicode escape",
223            // Parser errors
224            ErrorCode::E100 => "unexpected token",
225            ErrorCode::E101 => "incomplete input",
226            // Validation errors
227            ErrorCode::E200 => "undefined component",
228            ErrorCode::E201 => "unpaired activate",
229            ErrorCode::E202 => "unpaired deactivate",
230            ErrorCode::E203 => "invalid align value",
231            ErrorCode::E204 => "unknown embed reference",
232            // Elaboration errors
233            ErrorCode::E300 => "undefined type",
234            ErrorCode::E301 => "type override not supported",
235            ErrorCode::E302 => "invalid attribute value",
236            ErrorCode::E303 => "unknown attribute",
237            ErrorCode::E304 => "unsupported attribute",
238            ErrorCode::E305 => "nested diagram not allowed",
239            ErrorCode::E306 => "invalid diagram structure",
240            ErrorCode::E307 => "type mismatch",
241            ErrorCode::E308 => "shape does not support nested content",
242            ErrorCode::E309 => "unresolved embed reference",
243            // Resolver errors
244            ErrorCode::E400 => "file not found",
245            ErrorCode::E401 => "circular dependency",
246            ErrorCode::E402 => "invalid import path",
247            ErrorCode::E403 => "invalid namespace",
248        }
249    }
250}
251
252impl fmt::Display for ErrorCode {
253    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254        write!(f, "{}", self.as_str())
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use super::*;
261
262    #[test]
263    fn test_error_code_display() {
264        assert_eq!(ErrorCode::E001.to_string(), "E001");
265        assert_eq!(ErrorCode::E100.to_string(), "E100");
266        assert_eq!(ErrorCode::E200.to_string(), "E200");
267        assert_eq!(ErrorCode::E300.to_string(), "E300");
268        assert_eq!(ErrorCode::E400.to_string(), "E400");
269    }
270
271    #[test]
272    fn test_error_code_as_str() {
273        assert_eq!(ErrorCode::E001.as_str(), "E001");
274        assert_eq!(ErrorCode::E306.as_str(), "E306");
275    }
276
277    #[test]
278    fn test_error_code_description() {
279        assert_eq!(ErrorCode::E001.description(), "unterminated string literal");
280        assert_eq!(ErrorCode::E200.description(), "undefined component");
281        assert_eq!(ErrorCode::E301.description(), "type override not supported");
282        assert_eq!(ErrorCode::E400.description(), "file not found");
283    }
284}