1use crate::source::SourceId;
2
3mod display;
4mod from_std;
5mod source;
6
7pub type LexResult<T> = Result<T, OakError>;
13
14pub type ParseResult<T> = Result<T, OakError>;
20
21#[derive(Debug, Clone)]
29pub struct OakDiagnostics<T> {
30 pub result: Result<T, OakError>,
33 pub diagnostics: Vec<OakError>,
35}
36
37#[derive(Clone)]
43pub struct OakError {
44 kind: Box<OakErrorKind>,
45}
46
47impl std::fmt::Debug for OakError {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 std::fmt::Display::fmt(self, f)
50 }
51}
52
53#[cfg(feature = "serde")]
54impl serde::ser::Error for OakError {
55 fn custom<T: std::fmt::Display>(msg: T) -> Self {
56 OakError::serde_error(msg.to_string())
57 }
58}
59
60#[cfg(feature = "serde")]
61impl serde::de::Error for OakError {
62 fn custom<T: std::fmt::Display>(msg: T) -> Self {
63 OakError::deserialize_error(msg.to_string())
64 }
65}
66
67#[derive(Debug)]
73pub enum OakErrorKind {
74 IoError {
76 error: std::io::Error,
78 source_id: Option<SourceId>,
80 },
81 SyntaxError {
83 message: String,
85 offset: usize,
87 source_id: Option<SourceId>,
89 },
90 UnexpectedCharacter {
92 character: char,
94 offset: usize,
96 source_id: Option<SourceId>,
98 },
99
100 UnexpectedToken {
102 token: String,
104 offset: usize,
106 source_id: Option<SourceId>,
108 },
109
110 UnexpectedEof {
112 offset: usize,
114 source_id: Option<SourceId>,
116 },
117
118 CustomError {
120 message: String,
122 },
123
124 InvalidTheme {
126 message: String,
128 },
129
130 UnsupportedFormat {
132 format: String,
134 },
135
136 ColorParseError {
138 color: String,
140 },
141
142 FormatError {
144 message: String,
146 },
147
148 SemanticError {
150 message: String,
152 },
153
154 ProtocolError {
156 message: String,
158 },
159
160 ExpectedToken {
162 expected: String,
164 offset: usize,
166 source_id: Option<SourceId>,
168 },
169
170 ExpectedName {
172 name_kind: String,
174 offset: usize,
176 source_id: Option<SourceId>,
178 },
179
180 TrailingCommaNotAllowed {
182 offset: usize,
184 source_id: Option<SourceId>,
186 },
187
188 TestFailure {
190 path: std::path::PathBuf,
192 expected: String,
194 actual: String,
196 },
197
198 TestRegenerated {
200 path: std::path::PathBuf,
202 },
203
204 SerdeError {
206 message: String,
208 },
209
210 DeserializeError {
212 message: String,
214 },
215
216 XmlError {
218 message: String,
220 },
221
222 ZipError {
224 message: String,
226 },
227
228 ParseError {
230 message: String,
232 },
233
234 InternalError {
236 message: String,
238 },
239}
240
241impl OakErrorKind {
242 pub fn key(&self) -> &'static str {
244 match self {
245 OakErrorKind::IoError { .. } => "error.io",
246 OakErrorKind::SyntaxError { .. } => "error.syntax",
247 OakErrorKind::UnexpectedCharacter { .. } => "error.unexpected_character",
248 OakErrorKind::UnexpectedToken { .. } => "error.unexpected_token",
249 OakErrorKind::UnexpectedEof { .. } => "error.unexpected_eof",
250 OakErrorKind::CustomError { .. } => "error.custom",
251 OakErrorKind::InvalidTheme { .. } => "error.invalid_theme",
252 OakErrorKind::UnsupportedFormat { .. } => "error.unsupported_format",
253 OakErrorKind::ColorParseError { .. } => "error.color_parse",
254 OakErrorKind::FormatError { .. } => "error.format",
255 OakErrorKind::SemanticError { .. } => "error.semantic",
256 OakErrorKind::ProtocolError { .. } => "error.protocol",
257 OakErrorKind::ExpectedToken { .. } => "error.expected_token",
258 OakErrorKind::ExpectedName { .. } => "error.expected_name",
259 OakErrorKind::TrailingCommaNotAllowed { .. } => "error.trailing_comma_not_allowed",
260 OakErrorKind::TestFailure { .. } => "error.test_failure",
261 OakErrorKind::TestRegenerated { .. } => "error.test_regenerated",
262 OakErrorKind::SerdeError { .. } => "error.serde",
263 OakErrorKind::DeserializeError { .. } => "error.deserialize",
264 OakErrorKind::XmlError { .. } => "error.xml",
265 OakErrorKind::ZipError { .. } => "error.zip",
266 OakErrorKind::ParseError { .. } => "error.parse",
267 OakErrorKind::InternalError { .. } => "error.internal",
268 }
269 }
270}
271
272impl OakError {
273 pub fn kind(&self) -> &OakErrorKind {
275 &self.kind
276 }
277
278 pub fn test_failure(path: std::path::PathBuf, expected: String, actual: String) -> Self {
280 OakErrorKind::TestFailure { path, expected, actual }.into()
281 }
282
283 pub fn test_regenerated(path: std::path::PathBuf) -> Self {
285 OakErrorKind::TestRegenerated { path }.into()
286 }
287
288 pub fn io_error(error: std::io::Error, source_id: SourceId) -> Self {
306 OakErrorKind::IoError { error, source_id: Some(source_id) }.into()
307 }
308
309 pub fn syntax_error(message: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
325 OakErrorKind::SyntaxError { message: message.into(), offset, source_id }.into()
326 }
327
328 pub fn unexpected_character(character: char, offset: usize, source_id: Option<SourceId>) -> Self {
344 OakErrorKind::UnexpectedCharacter { character, offset, source_id }.into()
345 }
346
347 pub fn unexpected_token(token: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
349 OakErrorKind::UnexpectedToken { token: token.into(), offset, source_id }.into()
350 }
351
352 pub fn unexpected_eof(offset: usize, source_id: Option<SourceId>) -> Self {
354 OakErrorKind::UnexpectedEof { offset, source_id }.into()
355 }
356
357 pub fn expected_token(expected: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
359 OakErrorKind::ExpectedToken { expected: expected.into(), offset, source_id }.into()
360 }
361
362 pub fn expected_name(name_kind: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
364 OakErrorKind::ExpectedName { name_kind: name_kind.into(), offset, source_id }.into()
365 }
366
367 pub fn trailing_comma_not_allowed(offset: usize, source_id: Option<SourceId>) -> Self {
369 OakErrorKind::TrailingCommaNotAllowed { offset, source_id }.into()
370 }
371
372 pub fn custom_error(message: impl Into<String>) -> Self {
386 OakErrorKind::CustomError { message: message.into() }.into()
387 }
388
389 pub fn invalid_theme(message: impl Into<String>) -> Self {
391 OakErrorKind::InvalidTheme { message: message.into() }.into()
392 }
393
394 pub fn unsupported_format(format: impl Into<String>) -> Self {
396 OakErrorKind::UnsupportedFormat { format: format.into() }.into()
397 }
398
399 pub fn color_parse_error(color: impl Into<String>) -> Self {
401 OakErrorKind::ColorParseError { color: color.into() }.into()
402 }
403
404 pub fn format_error(message: impl Into<String>) -> Self {
406 OakErrorKind::FormatError { message: message.into() }.into()
407 }
408
409 pub fn semantic_error(message: impl Into<String>) -> Self {
411 OakErrorKind::SemanticError { message: message.into() }.into()
412 }
413
414 pub fn protocol_error(message: impl Into<String>) -> Self {
416 OakErrorKind::ProtocolError { message: message.into() }.into()
417 }
418
419 pub fn serde_error(message: impl Into<String>) -> Self {
421 OakErrorKind::SerdeError { message: message.into() }.into()
422 }
423
424 pub fn deserialize_error(message: impl Into<String>) -> Self {
426 OakErrorKind::DeserializeError { message: message.into() }.into()
427 }
428
429 pub fn xml_error(message: impl Into<String>) -> Self {
431 OakErrorKind::XmlError { message: message.into() }.into()
432 }
433
434 pub fn zip_error(message: impl Into<String>) -> Self {
436 OakErrorKind::ZipError { message: message.into() }.into()
437 }
438
439 pub fn parse_error(message: impl Into<String>) -> Self {
441 OakErrorKind::ParseError { message: message.into() }.into()
442 }
443
444 pub fn internal_error(message: impl Into<String>) -> Self {
446 OakErrorKind::InternalError { message: message.into() }.into()
447 }
448
449 pub fn with_source_id(mut self, source_id: SourceId) -> Self {
451 match self.kind.as_mut() {
452 OakErrorKind::IoError { source_id: u, .. } => *u = Some(source_id),
453 OakErrorKind::SyntaxError { source_id: u, .. } => *u = Some(source_id),
454 OakErrorKind::UnexpectedCharacter { source_id: u, .. } => *u = Some(source_id),
455 OakErrorKind::UnexpectedToken { source_id: u, .. } => *u = Some(source_id),
456 OakErrorKind::ExpectedToken { source_id: u, .. } => *u = Some(source_id),
457 OakErrorKind::ExpectedName { source_id: u, .. } => *u = Some(source_id),
458 OakErrorKind::TrailingCommaNotAllowed { source_id: u, .. } => *u = Some(source_id),
459 _ => {}
460 }
461 self
462 }
463}
464
465impl Clone for OakErrorKind {
466 fn clone(&self) -> Self {
467 match self {
468 OakErrorKind::IoError { error, source_id } => {
469 let new_error = std::io::Error::new(error.kind(), error.to_string());
471 OakErrorKind::IoError { error: new_error, source_id: *source_id }
472 }
473 OakErrorKind::SyntaxError { message, offset, source_id } => OakErrorKind::SyntaxError { message: message.clone(), offset: *offset, source_id: *source_id },
474 OakErrorKind::UnexpectedCharacter { character, offset, source_id } => OakErrorKind::UnexpectedCharacter { character: *character, offset: *offset, source_id: *source_id },
475 OakErrorKind::UnexpectedToken { token, offset, source_id } => OakErrorKind::UnexpectedToken { token: token.clone(), offset: *offset, source_id: *source_id },
476 OakErrorKind::UnexpectedEof { offset, source_id } => OakErrorKind::UnexpectedEof { offset: *offset, source_id: *source_id },
477 OakErrorKind::ExpectedToken { expected, offset, source_id } => OakErrorKind::ExpectedToken { expected: expected.clone(), offset: *offset, source_id: *source_id },
478 OakErrorKind::ExpectedName { name_kind, offset, source_id } => OakErrorKind::ExpectedName { name_kind: name_kind.clone(), offset: *offset, source_id: *source_id },
479 OakErrorKind::TrailingCommaNotAllowed { offset, source_id } => OakErrorKind::TrailingCommaNotAllowed { offset: *offset, source_id: *source_id },
480 OakErrorKind::CustomError { message } => OakErrorKind::CustomError { message: message.clone() },
481 OakErrorKind::InvalidTheme { message } => OakErrorKind::InvalidTheme { message: message.clone() },
482 OakErrorKind::UnsupportedFormat { format } => OakErrorKind::UnsupportedFormat { format: format.clone() },
483 OakErrorKind::ColorParseError { color } => OakErrorKind::ColorParseError { color: color.clone() },
484 OakErrorKind::FormatError { message } => OakErrorKind::FormatError { message: message.clone() },
485 OakErrorKind::SemanticError { message } => OakErrorKind::SemanticError { message: message.clone() },
486 OakErrorKind::ProtocolError { message } => OakErrorKind::ProtocolError { message: message.clone() },
487 OakErrorKind::TestFailure { path, expected, actual } => OakErrorKind::TestFailure { path: path.clone(), expected: expected.clone(), actual: actual.clone() },
488 OakErrorKind::TestRegenerated { path } => OakErrorKind::TestRegenerated { path: path.clone() },
489 OakErrorKind::SerdeError { message } => OakErrorKind::SerdeError { message: message.clone() },
490 OakErrorKind::DeserializeError { message } => OakErrorKind::DeserializeError { message: message.clone() },
491 OakErrorKind::XmlError { message } => OakErrorKind::XmlError { message: message.clone() },
492 OakErrorKind::ZipError { message } => OakErrorKind::ZipError { message: message.clone() },
493 OakErrorKind::ParseError { message } => OakErrorKind::ParseError { message: message.clone() },
494 OakErrorKind::InternalError { message } => OakErrorKind::InternalError { message: message.clone() },
495 }
496 }
497}