oak_core/errors/mod.rs
1use crate::source::SourceLocation;
2
3use url::Url;
4
5mod display;
6#[cfg(feature = "serde_json")]
7mod from_serde_json;
8mod from_std;
9mod source;
10
11/// Result type for lexical analysis operations.
12///
13/// This type alias represents the result of tokenization operations,
14/// where successful operations return a value of type `T` and failed
15/// operations return an [`OakError`].
16pub type LexResult<T> = Result<T, OakError>;
17
18/// Result type for parsing operations.
19///
20/// This type alias represents the result of parsing operations,
21/// where successful operations return a value of type `T` and failed
22/// operations return an [`OakError`].
23pub type ParseResult<T> = Result<T, OakError>;
24
25/// Container for parsing results with associated diagnostics.
26///
27/// This struct holds both the primary result of a parsing operation
28/// and any diagnostic language that were encountered during parsing.
29/// This allows for error recovery where parsing can continue even
30/// after encountering language, collecting all issues for later analysis.
31
32#[derive(Debug, Clone)]
33pub struct OakDiagnostics<T> {
34 /// The primary result of the parsing operation.
35 /// May contain either a successful value or a fatal error.
36 pub result: Result<T, OakError>,
37 /// A collection of non-fatal errors or warnings encountered during the operation.
38 pub diagnostics: Vec<OakError>,
39}
40
41/// The main error type for the Oak Core parsing framework.
42///
43/// `OakError` represents all possible language that can occur during
44/// lexical analysis and parsing operations. It provides detailed
45/// error information including error kind and precise source location.
46#[derive(Debug, Clone)]
47pub struct OakError {
48 kind: Box<OakErrorKind>,
49}
50
51/// Enumeration of all possible error kinds in the Oak Core framework.
52///
53/// This enum categorizes different types of language that can occur
54/// during parsing operations, each with specific associated data
55/// relevant to that error type.
56#[derive(Debug)]
57pub enum OakErrorKind {
58 /// I/O error that occurred while reading source files.
59 IoError {
60 /// The underlying I/O error.
61 error: std::io::Error,
62 /// Optional URL of the file that caused the error.
63 url: Option<Url>,
64 },
65 /// Syntax error encountered during parsing.
66 SyntaxError {
67 /// Human-readable error message describing the kind issue.
68 message: String,
69 /// Location in the source code where the error occurred.
70 source: SourceLocation,
71 },
72 /// Unexpected character encountered during lexical analysis.
73 UnexpectedCharacter {
74 /// The character that was not expected at this position.
75 character: char,
76 /// Location in the source code where the unexpected character was found.
77 source: SourceLocation,
78 },
79
80 /// Custom error for user-defined error conditions.
81 CustomError {
82 /// The error message describing the custom error condition.
83 message: String,
84 },
85}
86
87impl OakError {
88 /// Creates an I/O error with optional file URL.
89 ///
90 /// # Arguments
91 ///
92 /// * `error` - The underlying I/O error
93 /// * `url` - URL of the file that caused the error
94 ///
95 /// # Examples
96 ///
97 /// ```rust
98 /// # use oak_core::OakError;
99 /// # use std::io;
100 ///
101 /// let io_err = io::Error::new(io::ErrorKind::NotFound, "File not found");
102 /// let error = OakError::io_error(io_err, url::Url::parse("file:///main.rs").unwrap());
103 /// ```
104
105 pub fn io_error(error: std::io::Error, url: Url) -> Self {
106 OakErrorKind::IoError { error, url: Some(url) }.into()
107 }
108
109 /// Creates a kind error with a message and location.
110 ///
111 /// # Arguments
112 ///
113 /// * `message` - Description of the kind error
114 /// * `source` - Location in the source where the error occurred
115 ///
116 /// # Examples
117 ///
118 /// ```rust
119 /// # use oak_core::{OakError, SourceLocation};
120 ///
121 /// let location = SourceLocation { line: 1, column: 5, url: None };
122 /// let error = OakError::syntax_error("Unexpected token", location);
123 /// ```
124 pub fn syntax_error(message: impl Into<String>, source: SourceLocation) -> Self {
125 OakErrorKind::SyntaxError { message: message.into(), source }.into()
126 }
127
128 /// Creates an unexpected character error.
129 ///
130 /// # Arguments
131 ///
132 /// * `character` - The unexpected character
133 /// * `source` - Location where the character was found
134 ///
135 /// # Examples
136 ///
137 /// ```rust
138 /// # use oak_core::{OakError, SourceLocation};
139 ///
140 /// let location = SourceLocation { line: 1, column: 0, url: None };
141 /// let error = OakError::unexpected_character('$', location);
142 /// ```
143 pub fn unexpected_character(character: char, source: SourceLocation) -> Self {
144 OakErrorKind::UnexpectedCharacter { character, source }.into()
145 }
146
147 /// Creates a custom error with a message.
148 ///
149 /// # Arguments
150 ///
151 /// * `message` - The error message describing what went wrong
152 ///
153 /// # Examples
154 ///
155 /// ```rust
156 /// # use oak_core::OakError;
157 ///
158 /// let error = OakError::custom_error("Invalid configuration");
159 /// ```
160 pub fn custom_error(message: impl Into<String>) -> Self {
161 OakErrorKind::CustomError { message: message.into() }.into()
162 }
163
164 /// Returns a reference to the error kind.
165 ///
166 /// # Returns
167 ///
168 /// A reference to the [`OakErrorKind`] enum that categorizes this error.
169 pub fn kind(&self) -> &OakErrorKind {
170 &self.kind
171 }
172}
173
174impl Clone for OakErrorKind {
175 fn clone(&self) -> Self {
176 match self {
177 OakErrorKind::IoError { error, url } => {
178 // 由于 std::io::Error 不支持 Clone,我们创建一个新的错误
179 let new_error = std::io::Error::new(error.kind(), error.to_string());
180 OakErrorKind::IoError { error: new_error, url: url.clone() }
181 }
182 OakErrorKind::SyntaxError { message, source } => {
183 OakErrorKind::SyntaxError { message: message.clone(), source: source.clone() }
184 }
185 OakErrorKind::UnexpectedCharacter { character, source } => {
186 OakErrorKind::UnexpectedCharacter { character: *character, source: source.clone() }
187 }
188 OakErrorKind::CustomError { message } => OakErrorKind::CustomError { message: message.clone() },
189 }
190 }
191}