1use url::Url;
2
3mod display;
4#[cfg(feature = "serde_json")]
5mod from_serde_json;
6mod from_std;
7mod source;
8
9pub type LexResult<T> = Result<T, OakError>;
15
16pub type ParseResult<T> = Result<T, OakError>;
22
23#[derive(Debug, Clone)]
31pub struct OakDiagnostics<T> {
32 pub result: Result<T, OakError>,
35 pub diagnostics: Vec<OakError>,
37}
38
39#[derive(Clone)]
45pub struct OakError {
46 kind: Box<OakErrorKind>,
47}
48
49impl std::fmt::Debug for OakError {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 std::fmt::Display::fmt(self, f)
52 }
53}
54
55#[derive(Debug)]
61pub enum OakErrorKind {
62 IoError {
64 error: std::io::Error,
66 url: Option<Url>,
68 },
69 SyntaxError {
71 message: String,
73 offset: usize,
75 url: Option<Url>,
77 },
78 UnexpectedCharacter {
80 character: char,
82 offset: usize,
84 url: Option<Url>,
86 },
87
88 UnexpectedToken {
90 token: String,
92 offset: usize,
94 url: Option<Url>,
96 },
97
98 UnexpectedEof {
100 offset: usize,
102 url: Option<Url>,
104 },
105
106 CustomError {
108 message: String,
110 },
111
112 InvalidTheme {
114 message: String,
116 },
117
118 UnsupportedFormat {
120 format: String,
122 },
123
124 ColorParseError {
126 color: String,
128 },
129
130 FormatError {
132 message: String,
134 },
135
136 SemanticError {
138 message: String,
140 },
141
142 ProtocolError {
144 message: String,
146 },
147
148 ExpectedToken {
150 expected: String,
152 offset: usize,
154 url: Option<Url>,
156 },
157
158 ExpectedName {
160 name_kind: String,
162 offset: usize,
164 url: Option<Url>,
166 },
167
168 TrailingCommaNotAllowed {
170 offset: usize,
172 url: Option<Url>,
174 },
175
176 TestFailure {
178 path: std::path::PathBuf,
180 expected: String,
182 actual: String,
184 },
185
186 TestRegenerated {
188 path: std::path::PathBuf,
190 },
191}
192
193impl OakErrorKind {
194 pub fn key(&self) -> &'static str {
196 match self {
197 OakErrorKind::IoError { .. } => "error.io",
198 OakErrorKind::SyntaxError { .. } => "error.syntax",
199 OakErrorKind::UnexpectedCharacter { .. } => "error.unexpected_character",
200 OakErrorKind::UnexpectedToken { .. } => "error.unexpected_token",
201 OakErrorKind::UnexpectedEof { .. } => "error.unexpected_eof",
202 OakErrorKind::CustomError { .. } => "error.custom",
203 OakErrorKind::InvalidTheme { .. } => "error.invalid_theme",
204 OakErrorKind::UnsupportedFormat { .. } => "error.unsupported_format",
205 OakErrorKind::ColorParseError { .. } => "error.color_parse",
206 OakErrorKind::FormatError { .. } => "error.format",
207 OakErrorKind::SemanticError { .. } => "error.semantic",
208 OakErrorKind::ProtocolError { .. } => "error.protocol",
209 OakErrorKind::ExpectedToken { .. } => "error.expected_token",
210 OakErrorKind::ExpectedName { .. } => "error.expected_name",
211 OakErrorKind::TrailingCommaNotAllowed { .. } => "error.trailing_comma_not_allowed",
212 OakErrorKind::TestFailure { .. } => "error.test_failure",
213 OakErrorKind::TestRegenerated { .. } => "error.test_regenerated",
214 }
215 }
216}
217
218impl OakError {
219 pub fn test_failure(path: std::path::PathBuf, expected: String, actual: String) -> Self {
221 OakErrorKind::TestFailure { path, expected, actual }.into()
222 }
223
224 pub fn test_regenerated(path: std::path::PathBuf) -> Self {
226 OakErrorKind::TestRegenerated { path }.into()
227 }
228
229 pub fn io_error(error: std::io::Error, url: Url) -> Self {
247 OakErrorKind::IoError { error, url: Some(url) }.into()
248 }
249
250 pub fn syntax_error(message: impl Into<String>, offset: usize, url: Option<Url>) -> Self {
266 OakErrorKind::SyntaxError { message: message.into(), offset, url }.into()
267 }
268
269 pub fn unexpected_character(character: char, offset: usize, url: Option<Url>) -> Self {
285 OakErrorKind::UnexpectedCharacter { character, offset, url }.into()
286 }
287
288 pub fn unexpected_token(token: impl Into<String>, offset: usize, url: Option<Url>) -> Self {
290 OakErrorKind::UnexpectedToken { token: token.into(), offset, url }.into()
291 }
292
293 pub fn unexpected_eof(offset: usize, url: Option<Url>) -> Self {
295 OakErrorKind::UnexpectedEof { offset, url }.into()
296 }
297
298 pub fn expected_token(expected: impl Into<String>, offset: usize, url: Option<Url>) -> Self {
300 OakErrorKind::ExpectedToken { expected: expected.into(), offset, url }.into()
301 }
302
303 pub fn expected_name(name_kind: impl Into<String>, offset: usize, url: Option<Url>) -> Self {
305 OakErrorKind::ExpectedName { name_kind: name_kind.into(), offset, url }.into()
306 }
307
308 pub fn trailing_comma_not_allowed(offset: usize, url: Option<Url>) -> Self {
310 OakErrorKind::TrailingCommaNotAllowed { offset, url }.into()
311 }
312
313 pub fn custom_error(message: impl Into<String>) -> Self {
327 OakErrorKind::CustomError { message: message.into() }.into()
328 }
329
330 pub fn invalid_theme(message: impl Into<String>) -> Self {
332 OakErrorKind::InvalidTheme { message: message.into() }.into()
333 }
334
335 pub fn unsupported_format(format: impl Into<String>) -> Self {
337 OakErrorKind::UnsupportedFormat { format: format.into() }.into()
338 }
339
340 pub fn color_parse_error(color: impl Into<String>) -> Self {
342 OakErrorKind::ColorParseError { color: color.into() }.into()
343 }
344
345 pub fn format_error(message: impl Into<String>) -> Self {
347 OakErrorKind::FormatError { message: message.into() }.into()
348 }
349
350 pub fn semantic_error(message: impl Into<String>) -> Self {
352 OakErrorKind::SemanticError { message: message.into() }.into()
353 }
354
355 pub fn protocol_error(message: impl Into<String>) -> Self {
357 OakErrorKind::ProtocolError { message: message.into() }.into()
358 }
359
360 pub fn kind(&self) -> &OakErrorKind {
366 &self.kind
367 }
368
369 pub fn with_url(mut self, url: Url) -> Self {
371 match self.kind.as_mut() {
372 OakErrorKind::IoError { url: u, .. } => *u = Some(url),
373 OakErrorKind::SyntaxError { url: u, .. } => *u = Some(url),
374 OakErrorKind::UnexpectedCharacter { url: u, .. } => *u = Some(url),
375 OakErrorKind::UnexpectedToken { url: u, .. } => *u = Some(url),
376 OakErrorKind::ExpectedToken { url: u, .. } => *u = Some(url),
377 OakErrorKind::ExpectedName { url: u, .. } => *u = Some(url),
378 OakErrorKind::TrailingCommaNotAllowed { url: u, .. } => *u = Some(url),
379 _ => {}
380 }
381 self
382 }
383}
384
385impl Clone for OakErrorKind {
386 fn clone(&self) -> Self {
387 match self {
388 OakErrorKind::IoError { error, url } => {
389 let new_error = std::io::Error::new(error.kind(), error.to_string());
391 OakErrorKind::IoError { error: new_error, url: url.clone() }
392 }
393 OakErrorKind::SyntaxError { message, offset, url } => OakErrorKind::SyntaxError { message: message.clone(), offset: *offset, url: url.clone() },
394 OakErrorKind::UnexpectedCharacter { character, offset, url } => OakErrorKind::UnexpectedCharacter { character: *character, offset: *offset, url: url.clone() },
395 OakErrorKind::UnexpectedToken { token, offset, url } => OakErrorKind::UnexpectedToken { token: token.clone(), offset: *offset, url: url.clone() },
396 OakErrorKind::UnexpectedEof { offset, url } => OakErrorKind::UnexpectedEof { offset: *offset, url: url.clone() },
397 OakErrorKind::ExpectedToken { expected, offset, url } => OakErrorKind::ExpectedToken { expected: expected.clone(), offset: *offset, url: url.clone() },
398 OakErrorKind::ExpectedName { name_kind, offset, url } => OakErrorKind::ExpectedName { name_kind: name_kind.clone(), offset: *offset, url: url.clone() },
399 OakErrorKind::TrailingCommaNotAllowed { offset, url } => OakErrorKind::TrailingCommaNotAllowed { offset: *offset, url: url.clone() },
400 OakErrorKind::CustomError { message } => OakErrorKind::CustomError { message: message.clone() },
401 OakErrorKind::InvalidTheme { message } => OakErrorKind::InvalidTheme { message: message.clone() },
402 OakErrorKind::UnsupportedFormat { format } => OakErrorKind::UnsupportedFormat { format: format.clone() },
403 OakErrorKind::ColorParseError { color } => OakErrorKind::ColorParseError { color: color.clone() },
404 OakErrorKind::FormatError { message } => OakErrorKind::FormatError { message: message.clone() },
405 OakErrorKind::SemanticError { message } => OakErrorKind::SemanticError { message: message.clone() },
406 OakErrorKind::ProtocolError { message } => OakErrorKind::ProtocolError { message: message.clone() },
407 OakErrorKind::TestFailure { path, expected, actual } => OakErrorKind::TestFailure { path: path.clone(), expected: expected.clone(), actual: actual.clone() },
408 OakErrorKind::TestRegenerated { path } => OakErrorKind::TestRegenerated { path: path.clone() },
409 }
410 }
411}