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
37impl<T> OakDiagnostics<T> {
38 pub fn new(result: Result<T, OakError>) -> Self {
40 Self { result, diagnostics: Vec::new() }
41 }
42
43 pub fn success(value: T) -> Self {
45 Self { result: Ok(value), diagnostics: Vec::new() }
46 }
47
48 pub fn error(error: OakError) -> Self {
50 Self { result: Err(error), diagnostics: Vec::new() }
51 }
52
53 pub fn has_errors(&self) -> bool {
55 self.result.is_err() || !self.diagnostics.is_empty()
56 }
57}
58
59#[derive(Clone)]
65pub struct OakError {
66 kind: Box<OakErrorKind>,
68}
69
70impl OakError {
71 pub fn new(kind: OakErrorKind) -> Self {
73 Self { kind: Box::new(kind) }
74 }
75
76 pub fn custom_error(message: impl Into<String>) -> Self {
78 Self::new(OakErrorKind::CustomError { message: message.into() })
79 }
80}
81
82impl std::fmt::Debug for OakError {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 std::fmt::Display::fmt(self, f)
85 }
86}
87
88#[cfg(feature = "serde")]
89impl serde::ser::Error for OakError {
90 fn custom<T: std::fmt::Display>(msg: T) -> Self {
91 OakError::serde_error(msg.to_string())
92 }
93}
94
95#[cfg(feature = "serde")]
96impl serde::de::Error for OakError {
97 fn custom<T: std::fmt::Display>(msg: T) -> Self {
98 OakError::deserialize_error(msg.to_string())
99 }
100}
101
102#[derive(Debug)]
108pub enum OakErrorKind {
109 IoError {
111 error: std::io::Error,
113 source_id: Option<SourceId>,
115 },
116 SyntaxError {
118 message: String,
120 offset: usize,
122 source_id: Option<SourceId>,
124 },
125 UnexpectedCharacter {
127 character: char,
129 offset: usize,
131 source_id: Option<SourceId>,
133 },
134
135 UnexpectedToken {
137 token: String,
139 offset: usize,
141 source_id: Option<SourceId>,
143 },
144
145 UnexpectedEof {
147 offset: usize,
149 source_id: Option<SourceId>,
151 },
152
153 CustomError {
155 message: String,
157 },
158
159 InvalidTheme {
161 message: String,
163 },
164
165 UnsupportedFormat {
167 format: String,
169 },
170
171 ColorParseError {
173 color: String,
175 },
176
177 FormatError {
179 message: String,
181 },
182
183 SemanticError {
185 message: String,
187 },
188
189 ProtocolError {
191 message: String,
193 },
194
195 ExpectedToken {
197 expected: String,
199 offset: usize,
201 source_id: Option<SourceId>,
203 },
204
205 ExpectedName {
207 name_kind: String,
209 offset: usize,
211 source_id: Option<SourceId>,
213 },
214
215 TrailingCommaNotAllowed {
217 offset: usize,
219 source_id: Option<SourceId>,
221 },
222
223 TestFailure {
225 path: std::path::PathBuf,
227 expected: String,
229 actual: String,
231 },
232
233 TestRegenerated {
235 path: std::path::PathBuf,
237 },
238
239 SerdeError {
241 message: String,
243 },
244
245 DeserializeError {
247 message: String,
249 },
250
251 XmlError {
253 message: String,
255 },
256
257 ZipError {
259 message: String,
261 },
262
263 ParseError {
265 message: String,
267 },
268
269 InternalError {
271 message: String,
273 },
274}
275
276impl OakErrorKind {
277 pub fn key(&self) -> &'static str {
279 match self {
280 OakErrorKind::IoError { .. } => "error.io",
281 OakErrorKind::SyntaxError { .. } => "error.syntax",
282 OakErrorKind::UnexpectedCharacter { .. } => "error.unexpected_character",
283 OakErrorKind::UnexpectedToken { .. } => "error.unexpected_token",
284 OakErrorKind::UnexpectedEof { .. } => "error.unexpected_eof",
285 OakErrorKind::CustomError { .. } => "error.custom",
286 OakErrorKind::InvalidTheme { .. } => "error.invalid_theme",
287 OakErrorKind::UnsupportedFormat { .. } => "error.unsupported_format",
288 OakErrorKind::ColorParseError { .. } => "error.color_parse",
289 OakErrorKind::FormatError { .. } => "error.format",
290 OakErrorKind::SemanticError { .. } => "error.semantic",
291 OakErrorKind::ProtocolError { .. } => "error.protocol",
292 OakErrorKind::ExpectedToken { .. } => "error.expected_token",
293 OakErrorKind::ExpectedName { .. } => "error.expected_name",
294 OakErrorKind::TrailingCommaNotAllowed { .. } => "error.trailing_comma_not_allowed",
295 OakErrorKind::TestFailure { .. } => "error.test_failure",
296 OakErrorKind::TestRegenerated { .. } => "error.test_regenerated",
297 OakErrorKind::SerdeError { .. } => "error.serde",
298 OakErrorKind::DeserializeError { .. } => "error.deserialize",
299 OakErrorKind::XmlError { .. } => "error.xml",
300 OakErrorKind::ZipError { .. } => "error.zip",
301 OakErrorKind::ParseError { .. } => "error.parse",
302 OakErrorKind::InternalError { .. } => "error.internal",
303 }
304 }
305}
306
307impl OakError {
308 pub fn kind(&self) -> &OakErrorKind {
310 &self.kind
311 }
312
313 pub fn test_failure(path: std::path::PathBuf, expected: String, actual: String) -> Self {
315 OakErrorKind::TestFailure { path, expected, actual }.into()
316 }
317
318 pub fn test_regenerated(path: std::path::PathBuf) -> Self {
320 OakErrorKind::TestRegenerated { path }.into()
321 }
322
323 pub fn io_error(error: std::io::Error, source_id: SourceId) -> Self {
341 OakErrorKind::IoError { error, source_id: Some(source_id) }.into()
342 }
343
344 pub fn syntax_error(message: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
360 OakErrorKind::SyntaxError { message: message.into(), offset, source_id }.into()
361 }
362
363 pub fn unexpected_character(character: char, offset: usize, source_id: Option<SourceId>) -> Self {
379 OakErrorKind::UnexpectedCharacter { character, offset, source_id }.into()
380 }
381
382 pub fn unexpected_token(token: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
384 OakErrorKind::UnexpectedToken { token: token.into(), offset, source_id }.into()
385 }
386
387 pub fn unexpected_eof(offset: usize, source_id: Option<SourceId>) -> Self {
389 OakErrorKind::UnexpectedEof { offset, source_id }.into()
390 }
391
392 pub fn expected_token(expected: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
394 OakErrorKind::ExpectedToken { expected: expected.into(), offset, source_id }.into()
395 }
396
397 pub fn expected_name(name_kind: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
399 OakErrorKind::ExpectedName { name_kind: name_kind.into(), offset, source_id }.into()
400 }
401
402 pub fn trailing_comma_not_allowed(offset: usize, source_id: Option<SourceId>) -> Self {
404 OakErrorKind::TrailingCommaNotAllowed { offset, source_id }.into()
405 }
406
407 pub fn invalid_theme(message: impl Into<String>) -> Self {
409 OakErrorKind::InvalidTheme { message: message.into() }.into()
410 }
411
412 pub fn unsupported_format(format: impl Into<String>) -> Self {
414 OakErrorKind::UnsupportedFormat { format: format.into() }.into()
415 }
416
417 pub fn color_parse_error(color: impl Into<String>) -> Self {
419 OakErrorKind::ColorParseError { color: color.into() }.into()
420 }
421
422 pub fn format_error(message: impl Into<String>) -> Self {
424 OakErrorKind::FormatError { message: message.into() }.into()
425 }
426
427 pub fn semantic_error(message: impl Into<String>) -> Self {
429 OakErrorKind::SemanticError { message: message.into() }.into()
430 }
431
432 pub fn protocol_error(message: impl Into<String>) -> Self {
434 OakErrorKind::ProtocolError { message: message.into() }.into()
435 }
436
437 pub fn serde_error(message: impl Into<String>) -> Self {
439 OakErrorKind::SerdeError { message: message.into() }.into()
440 }
441
442 pub fn deserialize_error(message: impl Into<String>) -> Self {
444 OakErrorKind::DeserializeError { message: message.into() }.into()
445 }
446
447 pub fn xml_error(message: impl Into<String>) -> Self {
449 OakErrorKind::XmlError { message: message.into() }.into()
450 }
451
452 pub fn zip_error(message: impl Into<String>) -> Self {
454 OakErrorKind::ZipError { message: message.into() }.into()
455 }
456
457 pub fn parse_error(message: impl Into<String>) -> Self {
459 OakErrorKind::ParseError { message: message.into() }.into()
460 }
461
462 pub fn internal_error(message: impl Into<String>) -> Self {
464 OakErrorKind::InternalError { message: message.into() }.into()
465 }
466
467 pub fn with_source_id(mut self, source_id: SourceId) -> Self {
469 match self.kind.as_mut() {
470 OakErrorKind::IoError { source_id: u, .. } => *u = Some(source_id),
471 OakErrorKind::SyntaxError { source_id: u, .. } => *u = Some(source_id),
472 OakErrorKind::UnexpectedCharacter { source_id: u, .. } => *u = Some(source_id),
473 OakErrorKind::UnexpectedToken { source_id: u, .. } => *u = Some(source_id),
474 OakErrorKind::ExpectedToken { source_id: u, .. } => *u = Some(source_id),
475 OakErrorKind::ExpectedName { source_id: u, .. } => *u = Some(source_id),
476 OakErrorKind::TrailingCommaNotAllowed { source_id: u, .. } => *u = Some(source_id),
477 _ => {}
478 }
479 self
480 }
481}
482
483impl Clone for OakErrorKind {
484 fn clone(&self) -> Self {
485 match self {
486 OakErrorKind::IoError { error, source_id } => {
487 let new_error = std::io::Error::new(error.kind(), error.to_string());
489 OakErrorKind::IoError { error: new_error, source_id: *source_id }
490 }
491 OakErrorKind::SyntaxError { message, offset, source_id } => OakErrorKind::SyntaxError { message: message.clone(), offset: *offset, source_id: *source_id },
492 OakErrorKind::UnexpectedCharacter { character, offset, source_id } => OakErrorKind::UnexpectedCharacter { character: *character, offset: *offset, source_id: *source_id },
493 OakErrorKind::UnexpectedToken { token, offset, source_id } => OakErrorKind::UnexpectedToken { token: token.clone(), offset: *offset, source_id: *source_id },
494 OakErrorKind::UnexpectedEof { offset, source_id } => OakErrorKind::UnexpectedEof { offset: *offset, source_id: *source_id },
495 OakErrorKind::ExpectedToken { expected, offset, source_id } => OakErrorKind::ExpectedToken { expected: expected.clone(), offset: *offset, source_id: *source_id },
496 OakErrorKind::ExpectedName { name_kind, offset, source_id } => OakErrorKind::ExpectedName { name_kind: name_kind.clone(), offset: *offset, source_id: *source_id },
497 OakErrorKind::TrailingCommaNotAllowed { offset, source_id } => OakErrorKind::TrailingCommaNotAllowed { offset: *offset, source_id: *source_id },
498 OakErrorKind::CustomError { message } => OakErrorKind::CustomError { message: message.clone() },
499 OakErrorKind::InvalidTheme { message } => OakErrorKind::InvalidTheme { message: message.clone() },
500 OakErrorKind::UnsupportedFormat { format } => OakErrorKind::UnsupportedFormat { format: format.clone() },
501 OakErrorKind::ColorParseError { color } => OakErrorKind::ColorParseError { color: color.clone() },
502 OakErrorKind::FormatError { message } => OakErrorKind::FormatError { message: message.clone() },
503 OakErrorKind::SemanticError { message } => OakErrorKind::SemanticError { message: message.clone() },
504 OakErrorKind::ProtocolError { message } => OakErrorKind::ProtocolError { message: message.clone() },
505 OakErrorKind::TestFailure { path, expected, actual } => OakErrorKind::TestFailure { path: path.clone(), expected: expected.clone(), actual: actual.clone() },
506 OakErrorKind::TestRegenerated { path } => OakErrorKind::TestRegenerated { path: path.clone() },
507 OakErrorKind::SerdeError { message } => OakErrorKind::SerdeError { message: message.clone() },
508 OakErrorKind::DeserializeError { message } => OakErrorKind::DeserializeError { message: message.clone() },
509 OakErrorKind::XmlError { message } => OakErrorKind::XmlError { message: message.clone() },
510 OakErrorKind::ZipError { message } => OakErrorKind::ZipError { message: message.clone() },
511 OakErrorKind::ParseError { message } => OakErrorKind::ParseError { message: message.clone() },
512 OakErrorKind::InternalError { message } => OakErrorKind::InternalError { message: message.clone() },
513 }
514 }
515}