1use crate::source::SourceId;
2
3pub type ParseResult<T> = Result<T, OakError>;
5
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
11pub struct OakDiagnostics<T> {
12 pub result: Result<T, OakError>,
15 pub diagnostics: Vec<OakError>,
17}
18
19impl<T: Clone> Clone for OakDiagnostics<T> {
20 fn clone(&self) -> Self {
21 Self { result: self.result.clone(), diagnostics: self.diagnostics.clone() }
22 }
23}
24
25impl<T> OakDiagnostics<T> {
26 pub fn new(result: Result<T, OakError>) -> Self {
28 Self { result, diagnostics: Vec::new() }
29 }
30
31 pub fn success(value: T) -> Self {
33 Self { result: Ok(value), diagnostics: Vec::new() }
34 }
35
36 pub fn error(error: OakError) -> Self {
38 Self { result: Err(error), diagnostics: Vec::new() }
39 }
40
41 pub fn has_errors(&self) -> bool {
43 self.result.is_err() || !self.diagnostics.is_empty()
44 }
45}
46
47impl<'a, L: crate::Language> OakDiagnostics<&'a crate::tree::GreenNode<'a, L>> {
48 pub fn green(&self) -> &'a crate::tree::GreenNode<'a, L> {
50 self.result.as_ref().expect("Failed to get green node from parse output")
51 }
52}
53
54#[derive(Clone)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub struct OakError {
62 kind: Box<OakErrorKind>,
64}
65
66impl OakError {
67 pub fn new(kind: OakErrorKind) -> Self {
69 Self { kind: Box::new(kind) }
70 }
71
72 pub fn custom_error(message: impl Into<String>) -> Self {
74 Self::new(OakErrorKind::CustomError { message: message.into() })
75 }
76}
77
78impl From<OakErrorKind> for OakError {
79 fn from(kind: OakErrorKind) -> Self {
80 Self { kind: Box::new(kind) }
81 }
82}
83
84impl std::fmt::Debug for OakError {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 std::fmt::Display::fmt(self, f)
87 }
88}
89
90impl std::fmt::Display for OakError {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 write!(f, "{:?}", self.kind)
93 }
94}
95
96impl std::error::Error for OakError {}
97
98#[cfg(feature = "serde")]
99impl serde::ser::Error for OakError {
100 fn custom<T: std::fmt::Display>(msg: T) -> Self {
101 OakError::serde_error(msg.to_string())
102 }
103}
104
105#[cfg(feature = "serde")]
106impl serde::de::Error for OakError {
107 fn custom<T: std::fmt::Display>(msg: T) -> Self {
108 OakError::deserialize_error(msg.to_string())
109 }
110}
111
112#[cfg(feature = "serde")]
113mod serde_io_error {
114 pub fn serialize<S>(error: &std::io::Error, serializer: S) -> Result<S::Ok, S::Error>
115 where
116 S: serde::Serializer,
117 {
118 serde::Serialize::serialize(&error.to_string(), serializer)
119 }
120
121 pub fn deserialize<'de, D>(deserializer: D) -> Result<std::io::Error, D::Error>
122 where
123 D: serde::Deserializer<'de>,
124 {
125 let s = <String as serde::Deserialize>::deserialize(deserializer)?;
126 Ok(std::io::Error::new(std::io::ErrorKind::Other, s))
127 }
128}
129
130#[derive(Debug)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137pub enum OakErrorKind {
138 IoError {
140 #[cfg_attr(feature = "serde", serde(with = "crate::errors::serde_io_error"))]
142 error: std::io::Error,
143 source_id: Option<SourceId>,
145 },
146 SyntaxError {
148 message: String,
150 offset: usize,
152 source_id: Option<SourceId>,
154 },
155 UnexpectedCharacter {
157 character: char,
159 offset: usize,
161 source_id: Option<SourceId>,
163 },
164
165 UnexpectedToken {
167 token: String,
169 offset: usize,
171 source_id: Option<SourceId>,
173 },
174
175 UnexpectedEof {
177 offset: usize,
179 source_id: Option<SourceId>,
181 },
182
183 CustomError {
185 message: String,
187 },
188
189 InvalidTheme {
191 message: String,
193 },
194
195 UnsupportedFormat {
197 format: String,
199 },
200
201 ColorParseError {
203 color: String,
205 },
206
207 FormatError {
209 message: String,
211 },
212
213 SemanticError {
215 message: String,
217 },
218
219 ProtocolError {
221 message: String,
223 },
224
225 ExpectedToken {
227 expected: String,
229 offset: usize,
231 source_id: Option<SourceId>,
233 },
234
235 ExpectedName {
237 name_kind: String,
239 offset: usize,
241 source_id: Option<SourceId>,
243 },
244
245 TrailingCommaNotAllowed {
247 offset: usize,
249 source_id: Option<SourceId>,
251 },
252
253 TestFailure {
255 path: std::path::PathBuf,
257 expected: String,
259 actual: String,
261 },
262
263 TestRegenerated {
265 path: std::path::PathBuf,
267 },
268
269 SerdeError {
271 message: String,
273 },
274
275 DeserializeError {
277 message: String,
279 },
280
281 XmlError {
283 message: String,
285 },
286
287 ZipError {
289 message: String,
291 },
292
293 ParseError {
295 message: String,
297 },
298
299 InternalError {
301 message: String,
303 },
304}
305
306impl OakErrorKind {
307 pub fn key(&self) -> &'static str {
309 match self {
310 OakErrorKind::IoError { .. } => "error.io",
311 OakErrorKind::SyntaxError { .. } => "error.syntax",
312 OakErrorKind::UnexpectedCharacter { .. } => "error.unexpected_character",
313 OakErrorKind::UnexpectedToken { .. } => "error.unexpected_token",
314 OakErrorKind::UnexpectedEof { .. } => "error.unexpected_eof",
315 OakErrorKind::CustomError { .. } => "error.custom",
316 OakErrorKind::InvalidTheme { .. } => "error.invalid_theme",
317 OakErrorKind::UnsupportedFormat { .. } => "error.unsupported_format",
318 OakErrorKind::ColorParseError { .. } => "error.color_parse",
319 OakErrorKind::FormatError { .. } => "error.format",
320 OakErrorKind::SemanticError { .. } => "error.semantic",
321 OakErrorKind::ProtocolError { .. } => "error.protocol",
322 OakErrorKind::ExpectedToken { .. } => "error.expected_token",
323 OakErrorKind::ExpectedName { .. } => "error.expected_name",
324 OakErrorKind::TrailingCommaNotAllowed { .. } => "error.trailing_comma_not_allowed",
325 OakErrorKind::TestFailure { .. } => "error.test_failure",
326 OakErrorKind::TestRegenerated { .. } => "error.test_regenerated",
327 OakErrorKind::SerdeError { .. } => "error.serde",
328 OakErrorKind::DeserializeError { .. } => "error.deserialize",
329 OakErrorKind::XmlError { .. } => "error.xml",
330 OakErrorKind::ZipError { .. } => "error.zip",
331 OakErrorKind::ParseError { .. } => "error.parse",
332 OakErrorKind::InternalError { .. } => "error.internal",
333 }
334 }
335}
336
337impl std::fmt::Display for OakErrorKind {
338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339 match self {
340 OakErrorKind::IoError { error, source_id } => {
341 if let Some(id) = source_id {
342 write!(f, "I/O error in {}: {}", id, error)
343 }
344 else {
345 write!(f, "I/O error: {}", error)
346 }
347 }
348 OakErrorKind::SyntaxError { message, offset, source_id } => {
349 if let Some(id) = source_id {
350 write!(f, "Syntax error in {} at offset {}: {}", id, offset, message)
351 }
352 else {
353 write!(f, "Syntax error at offset {}: {}", offset, message)
354 }
355 }
356 OakErrorKind::UnexpectedCharacter { character, offset, source_id } => {
357 if let Some(id) = source_id {
358 write!(f, "Unexpected character '{}' in {} at offset {}", character, id, offset)
359 }
360 else {
361 write!(f, "Unexpected character '{}' at offset {}", character, offset)
362 }
363 }
364 OakErrorKind::UnexpectedToken { token, offset, source_id } => {
365 if let Some(id) = source_id {
366 write!(f, "Unexpected token '{}' in {} at offset {}", token, id, offset)
367 }
368 else {
369 write!(f, "Unexpected token '{}' at offset {}", token, offset)
370 }
371 }
372 OakErrorKind::UnexpectedEof { offset, source_id } => {
373 if let Some(id) = source_id {
374 write!(f, "Unexpected end of file in {} at offset {}", id, offset)
375 }
376 else {
377 write!(f, "Unexpected end of file at offset {}", offset)
378 }
379 }
380 OakErrorKind::ExpectedToken { expected, offset, source_id } => {
381 if let Some(id) = source_id {
382 write!(f, "Expected token '{}' in {} at offset {}", expected, id, offset)
383 }
384 else {
385 write!(f, "Expected token '{}' at offset {}", expected, offset)
386 }
387 }
388 OakErrorKind::ExpectedName { name_kind, offset, source_id } => {
389 if let Some(id) = source_id {
390 write!(f, "Expected {} in {} at offset {}", name_kind, id, offset)
391 }
392 else {
393 write!(f, "Expected {} at offset {}", name_kind, offset)
394 }
395 }
396 OakErrorKind::TrailingCommaNotAllowed { offset, source_id } => {
397 if let Some(id) = source_id {
398 write!(f, "Trailing comma not allowed in {} at offset {}", id, offset)
399 }
400 else {
401 write!(f, "Trailing comma not allowed at offset {}", offset)
402 }
403 }
404 OakErrorKind::CustomError { message } => {
405 write!(f, "Custom error: {}", message)
406 }
407 OakErrorKind::InvalidTheme { message } => {
408 write!(f, "Invalid theme: {}", message)
409 }
410 OakErrorKind::UnsupportedFormat { format } => {
411 write!(f, "Unsupported format: {}", format)
412 }
413 OakErrorKind::ColorParseError { color } => {
414 write!(f, "Invalid color: {}", color)
415 }
416 OakErrorKind::FormatError { message } => {
417 write!(f, "Format error: {}", message)
418 }
419 OakErrorKind::SemanticError { message } => {
420 write!(f, "Semantic error: {}", message)
421 }
422 OakErrorKind::ProtocolError { message } => {
423 write!(f, "Protocol error: {}", message)
424 }
425 OakErrorKind::TestFailure { path, expected, actual } => {
426 write!(f, "Test failed for {}: expected '{}', got '{}'", path.display(), expected, actual)
427 }
428 OakErrorKind::TestRegenerated { path } => {
429 write!(f, "Test regenerated for {}", path.display())
430 }
431 OakErrorKind::SerdeError { message } => {
432 write!(f, "Serialization error: {}", message)
433 }
434 OakErrorKind::DeserializeError { message } => {
435 write!(f, "Deserialization error: {}", message)
436 }
437 OakErrorKind::XmlError { message } => {
438 write!(f, "XML error: {}", message)
439 }
440 OakErrorKind::ZipError { message } => {
441 write!(f, "ZIP error: {}", message)
442 }
443 OakErrorKind::ParseError { message } => {
444 write!(f, "Parse error: {}", message)
445 }
446 OakErrorKind::InternalError { message } => {
447 write!(f, "Internal error: {}", message)
448 }
449 }
450 }
451}
452
453impl OakError {
454 pub fn kind(&self) -> &OakErrorKind {
456 &self.kind
457 }
458
459 pub fn test_failure(path: std::path::PathBuf, expected: String, actual: String) -> Self {
461 OakErrorKind::TestFailure { path, expected, actual }.into()
462 }
463
464 pub fn test_regenerated(path: std::path::PathBuf) -> Self {
466 OakErrorKind::TestRegenerated { path }.into()
467 }
468
469 pub fn io_error(error: std::io::Error, source_id: SourceId) -> Self {
471 OakErrorKind::IoError { error, source_id: Some(source_id) }.into()
472 }
473
474 pub fn syntax_error(message: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
476 OakErrorKind::SyntaxError { message: message.into(), offset, source_id }.into()
477 }
478
479 pub fn unexpected_character(character: char, offset: usize, source_id: Option<SourceId>) -> Self {
481 OakErrorKind::UnexpectedCharacter { character, offset, source_id }.into()
482 }
483
484 pub fn unexpected_token(token: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
486 OakErrorKind::UnexpectedToken { token: token.into(), offset, source_id }.into()
487 }
488
489 pub fn unexpected_eof(offset: usize, source_id: Option<SourceId>) -> Self {
491 OakErrorKind::UnexpectedEof { offset, source_id }.into()
492 }
493
494 pub fn expected_token(expected: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
496 OakErrorKind::ExpectedToken { expected: expected.into(), offset, source_id }.into()
497 }
498
499 pub fn expected_name(name_kind: impl Into<String>, offset: usize, source_id: Option<SourceId>) -> Self {
501 OakErrorKind::ExpectedName { name_kind: name_kind.into(), offset, source_id }.into()
502 }
503
504 pub fn trailing_comma_not_allowed(offset: usize, source_id: Option<SourceId>) -> Self {
506 OakErrorKind::TrailingCommaNotAllowed { offset, source_id }.into()
507 }
508
509 pub fn invalid_theme(message: impl Into<String>) -> Self {
511 OakErrorKind::InvalidTheme { message: message.into() }.into()
512 }
513
514 pub fn unsupported_format(format: impl Into<String>) -> Self {
516 OakErrorKind::UnsupportedFormat { format: format.into() }.into()
517 }
518
519 pub fn color_parse_error(color: impl Into<String>) -> Self {
521 OakErrorKind::ColorParseError { color: color.into() }.into()
522 }
523
524 pub fn format_error(message: impl Into<String>) -> Self {
526 OakErrorKind::FormatError { message: message.into() }.into()
527 }
528
529 pub fn semantic_error(message: impl Into<String>) -> Self {
531 OakErrorKind::SemanticError { message: message.into() }.into()
532 }
533
534 pub fn protocol_error(message: impl Into<String>) -> Self {
536 OakErrorKind::ProtocolError { message: message.into() }.into()
537 }
538
539 pub fn serde_error(message: impl Into<String>) -> Self {
541 OakErrorKind::SerdeError { message: message.into() }.into()
542 }
543
544 pub fn deserialize_error(message: impl Into<String>) -> Self {
546 OakErrorKind::DeserializeError { message: message.into() }.into()
547 }
548
549 pub fn xml_error(message: impl Into<String>) -> Self {
551 OakErrorKind::XmlError { message: message.into() }.into()
552 }
553
554 pub fn zip_error(message: impl Into<String>) -> Self {
556 OakErrorKind::ZipError { message: message.into() }.into()
557 }
558
559 pub fn parse_error(message: impl Into<String>) -> Self {
561 OakErrorKind::ParseError { message: message.into() }.into()
562 }
563
564 pub fn internal_error(message: impl Into<String>) -> Self {
566 OakErrorKind::InternalError { message: message.into() }.into()
567 }
568
569 pub fn with_source_id(mut self, source_id: SourceId) -> Self {
571 match self.kind.as_mut() {
572 OakErrorKind::IoError { source_id: u, .. } => *u = Some(source_id),
573 OakErrorKind::SyntaxError { source_id: u, .. } => *u = Some(source_id),
574 OakErrorKind::UnexpectedCharacter { source_id: u, .. } => *u = Some(source_id),
575 OakErrorKind::UnexpectedToken { source_id: u, .. } => *u = Some(source_id),
576 OakErrorKind::ExpectedToken { source_id: u, .. } => *u = Some(source_id),
577 OakErrorKind::ExpectedName { source_id: u, .. } => *u = Some(source_id),
578 OakErrorKind::TrailingCommaNotAllowed { source_id: u, .. } => *u = Some(source_id),
579 _ => {}
580 }
581 self
582 }
583}
584
585impl Clone for OakErrorKind {
586 fn clone(&self) -> Self {
587 match self {
588 OakErrorKind::IoError { error, source_id } => {
589 let new_error = std::io::Error::new(error.kind(), error.to_string());
591 OakErrorKind::IoError { error: new_error, source_id: *source_id }
592 }
593 OakErrorKind::SyntaxError { message, offset, source_id } => OakErrorKind::SyntaxError { message: message.clone(), offset: *offset, source_id: *source_id },
594 OakErrorKind::UnexpectedCharacter { character, offset, source_id } => OakErrorKind::UnexpectedCharacter { character: *character, offset: *offset, source_id: *source_id },
595 OakErrorKind::UnexpectedToken { token, offset, source_id } => OakErrorKind::UnexpectedToken { token: token.clone(), offset: *offset, source_id: *source_id },
596 OakErrorKind::UnexpectedEof { offset, source_id } => OakErrorKind::UnexpectedEof { offset: *offset, source_id: *source_id },
597 OakErrorKind::ExpectedToken { expected, offset, source_id } => OakErrorKind::ExpectedToken { expected: expected.clone(), offset: *offset, source_id: *source_id },
598 OakErrorKind::ExpectedName { name_kind, offset, source_id } => OakErrorKind::ExpectedName { name_kind: name_kind.clone(), offset: *offset, source_id: *source_id },
599 OakErrorKind::TrailingCommaNotAllowed { offset, source_id } => OakErrorKind::TrailingCommaNotAllowed { offset: *offset, source_id: *source_id },
600 OakErrorKind::CustomError { message } => OakErrorKind::CustomError { message: message.clone() },
601 OakErrorKind::InvalidTheme { message } => OakErrorKind::InvalidTheme { message: message.clone() },
602 OakErrorKind::UnsupportedFormat { format } => OakErrorKind::UnsupportedFormat { format: format.clone() },
603 OakErrorKind::ColorParseError { color } => OakErrorKind::ColorParseError { color: color.clone() },
604 OakErrorKind::FormatError { message } => OakErrorKind::FormatError { message: message.clone() },
605 OakErrorKind::SemanticError { message } => OakErrorKind::SemanticError { message: message.clone() },
606 OakErrorKind::ProtocolError { message } => OakErrorKind::ProtocolError { message: message.clone() },
607 OakErrorKind::TestFailure { path, expected, actual } => OakErrorKind::TestFailure { path: path.clone(), expected: expected.clone(), actual: actual.clone() },
608 OakErrorKind::TestRegenerated { path } => OakErrorKind::TestRegenerated { path: path.clone() },
609 OakErrorKind::SerdeError { message } => OakErrorKind::SerdeError { message: message.clone() },
610 OakErrorKind::DeserializeError { message } => OakErrorKind::DeserializeError { message: message.clone() },
611 OakErrorKind::XmlError { message } => OakErrorKind::XmlError { message: message.clone() },
612 OakErrorKind::ZipError { message } => OakErrorKind::ZipError { message: message.clone() },
613 OakErrorKind::ParseError { message } => OakErrorKind::ParseError { message: message.clone() },
614 OakErrorKind::InternalError { message } => OakErrorKind::InternalError { message: message.clone() },
615 }
616 }
617}