jute/errors.rs
1use std::{fmt, path::PathBuf};
2
3use std::error::Error;
4
5#[derive(Debug)]
6pub(crate) enum TypeValidationError {
7 UnknownType,
8 AmbigousType,
9}
10
11/// Top-level error type for the Jute compiler and code generator.
12/// `JuteError` represents all possible failures that can occur during:
13/// - Lexing
14/// - Parsing
15/// - Dependency resolution
16/// - Type validation
17/// - Code generation
18/// - I/O operations
19/// This enum is marked as `#[non_exhaustive]` to allow adding new error
20/// variants in the future without breaking downstream code.
21/// Consumers should match using a wildcard arm (`_`) to remain forward-compatible.
22#[derive(Debug)]
23#[non_exhaustive]
24pub enum JuteError {
25 /// An invalid conversion was attempted from a token to a primitive type.
26 /// This usually indicates a invalid token where permetive type was excepted
27 InvalidConversionToPremitive {
28 /// The token that failed conversion.
29 token: String,
30 },
31 /// An unexpected token was encountered during parsing.
32 /// This typically means the input does not conform to the Jute grammar.
33 UnexpectedToken {
34 /// The token that was encountered (if any).
35 token: Option<String>,
36 /// Human-readable explanation of what was expected.
37 message: String,
38 },
39 /// An unexpected character was encountered during lexing.
40 UnexpectedChar {
41 /// The unexpected character.
42 c: char,
43 /// Additional context about the error.
44 message: String,
45 },
46 // The token stream ended unexpectedly.
47 /// This usually indicates malformed or truncated input.
48 UnexpectedEndOfTokenStream,
49 /// The end of the source file was reached unexpectedly.
50 /// Common causes include missing braces or incomplete declarations.
51 UnexpectedEndOfFile,
52 /// Failed to canonicalize a filesystem path.
53 ///
54 /// This can occur when resolving include paths or source file locations.
55 PathCanonicalizeError {
56 /// Additional context explaining the failure.
57 message: String,
58 },
59 /// A multiline comment (`/* ... */`) was not properly terminated.
60 UnTerminatedMultiLineComment,
61 /// A quoted string literal was not properly terminated.
62 UnTerminatedQuotedString,
63 /// A quoted string literal contains a newline character,
64 QuotedStringWithNewLineCharacter,
65
66 /// A referenced type could not be resolved.
67 /// Provides detailed context to help diagnose schema issues.
68 UnknownType {
69 /// Field name
70 name: String,
71 /// Type
72 _type: String,
73 /// Parrent record/class
74 record: String,
75 /// Parrent module
76 module: String,
77 /// Src File
78 file: PathBuf,
79 },
80 // A referenced type name resolved to multiple definitions.
81 /// This usually happens when two included modules define
82 /// the same type name.
83 AmbiguousType {
84 /// The ambiguous type name.
85 name: String,
86 /// The expected kind of the type.
87 _type: String,
88 /// Record in which the ambiguity occurred.
89 record: String,
90 /// Module containing the record.
91 module: String,
92 /// Source file where the error occurred.
93 file: PathBuf,
94 },
95 /// A circular dependency was detected between modules.
96 /// The `cycle` field describes the dependency loop.
97 CircularDependency {
98 /// Human-readable representation of the dependency cycle.
99 cycle: String,
100 },
101 /// Wrapper around [`std::io::Error`].
102 /// Used for filesystem and I/O related failures.
103 Io(std::io::Error),
104 /// Wrapper around [`std::fmt::Error`].
105 ///
106 /// Typically occurs during code generation.
107 Fmt(std::fmt::Error),
108 /// Wrapper around UTF-8 decoding errors.
109 Utf8(std::string::FromUtf8Error),
110 /// Duplicate module names detected across source files.
111 DuplicateModuleName {
112 /// Name of the duplicated module.
113 module_name: String,
114 /// File in which the duplicate was found.
115 file_name: PathBuf,
116 },
117 /// Duplicate class names detected within the same module.
118 DuplicateClassName {
119 /// Name of the duplicated class.
120 class_name: String,
121 /// Module containing the duplicate.
122 module_name: String,
123 /// File in which the duplicate was found.
124 file_name: PathBuf,
125 },
126
127 /// Duplicate field names detected within a class.
128 DuplicateFieldName {
129 /// Name of the duplicated field.
130 field_name: String,
131 /// Class containing the duplicate field.
132 class_name: String,
133 /// Module containing the class.
134 module_name: String,
135 /// File in which the duplicate was found.
136 file_name: PathBuf,
137 },
138 /// An invalid field type was used in a class definition.
139 InvalidFieldType {
140 /// The invalid field type.
141 field_type: String,
142 /// Field name.
143 field_name: String,
144 /// Class containing the field.
145 class_name: String,
146 /// Module containing the class.
147 module_name: String,
148 /// File in which the error occurred.
149 file_name: PathBuf,
150 },
151}
152
153impl From<std::io::Error> for JuteError {
154 fn from(err: std::io::Error) -> Self {
155 JuteError::Io(err)
156 }
157}
158
159impl From<std::fmt::Error> for JuteError {
160 fn from(err: std::fmt::Error) -> Self {
161 JuteError::Fmt(err)
162 }
163}
164
165impl From<std::string::FromUtf8Error> for JuteError {
166 fn from(err: std::string::FromUtf8Error) -> Self {
167 JuteError::Utf8(err)
168 }
169}
170
171impl fmt::Display for JuteError {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match self {
174 JuteError::UnexpectedChar { c, message } => {
175 write!(f, "unexpected character '{}': {}", c, message)
176 }
177
178 JuteError::UnexpectedToken { token, message } => {
179 write!(f, "unexpected token {:?}: {}", token, message)
180 }
181
182 JuteError::UnknownType {
183 name,
184 record,
185 module,
186 file,
187 ..
188 } => write!(
189 f,
190 "unknown type '{}' in record '{}' (module '{}') at {:?}",
191 name, record, module, file
192 ),
193
194 JuteError::AmbiguousType {
195 name,
196 record,
197 module,
198 file,
199 ..
200 } => write!(
201 f,
202 "ambiguous type '{}' in record '{}' (module '{}') at {:?}",
203 name, record, module, file
204 ),
205
206 JuteError::CircularDependency { cycle } => {
207 write!(f, "circular dependency detected: {}", cycle)
208 }
209
210 JuteError::Io(e) => write!(f, "io error: {}", e),
211 JuteError::Fmt(e) => write!(f, "formatting error: {}", e),
212
213 _ => write!(f, "{:?}", self),
214 }
215 }
216}
217
218impl Error for JuteError {
219 fn source(&self) -> Option<&(dyn Error + 'static)> {
220 match self {
221 JuteError::Io(e) => Some(e),
222 JuteError::Fmt(e) => Some(e),
223 JuteError::Utf8(e) => Some(e),
224 _ => None,
225 }
226 }
227}