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}