1use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
10pub struct Span {
11 pub start: usize,
13 pub end: usize,
15}
16
17impl Span {
18 pub fn new(start: usize, end: usize) -> Self {
20 Self { start, end }
21 }
22
23 pub fn point(pos: usize) -> Self {
25 Self {
26 start: pos,
27 end: pos + 1,
28 }
29 }
30
31 pub fn empty(pos: usize) -> Self {
33 Self {
34 start: pos,
35 end: pos,
36 }
37 }
38
39 pub fn merge(self, other: Span) -> Span {
41 Span {
42 start: self.start.min(other.start),
43 end: self.end.max(other.end),
44 }
45 }
46
47 pub fn len(&self) -> usize {
49 self.end.saturating_sub(self.start)
50 }
51
52 pub fn is_empty(&self) -> bool {
54 self.start >= self.end
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
60pub enum ErrorKind {
61 UnexpectedCharacter(char),
63 UnterminatedString,
64 UnterminatedBlockComment,
65 InvalidEscapeSequence(String),
66 InvalidNumber(String),
67 InvalidHexLiteral,
68 InvalidBytesLiteral,
69
70 UnexpectedToken {
72 expected: String,
73 found: String,
74 },
75 UnexpectedEof,
76 ExpectedExpression,
77 ExpectedIdentifier,
78 ExpectedKeyword(String),
79 InvalidSyntax(String),
80 UnsupportedFeature(String),
81
82 UndefinedColumn(String),
84 UndefinedTable(String),
85 UndefinedFunction(String),
86 AmbiguousColumn(String),
87 TypeMismatch {
88 expected: String,
89 found: String,
90 },
91 InvalidArgumentCount {
92 function: String,
93 expected: usize,
94 found: usize,
95 },
96 DuplicateColumn(String),
97 DuplicateAlias(String),
98 InvalidGroupBy(String),
99 InvalidOrderBy(String),
100 InvalidAggregateUsage(String),
101 InvalidWindowFunction(String),
102
103 Internal(String),
105}
106
107impl fmt::Display for ErrorKind {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 match self {
110 ErrorKind::UnexpectedCharacter(c) => write!(f, "unexpected character '{}'", c),
112 ErrorKind::UnterminatedString => write!(f, "unterminated string literal"),
113 ErrorKind::UnterminatedBlockComment => write!(f, "unterminated block comment"),
114 ErrorKind::InvalidEscapeSequence(s) => write!(f, "invalid escape sequence '{}'", s),
115 ErrorKind::InvalidNumber(s) => write!(f, "invalid number '{}'", s),
116 ErrorKind::InvalidHexLiteral => write!(f, "invalid hexadecimal literal"),
117 ErrorKind::InvalidBytesLiteral => write!(f, "invalid bytes literal"),
118
119 ErrorKind::UnexpectedToken { expected, found } => {
121 write!(f, "expected {}, found {}", expected, found)
122 }
123 ErrorKind::UnexpectedEof => write!(f, "unexpected end of input"),
124 ErrorKind::ExpectedExpression => write!(f, "expected expression"),
125 ErrorKind::ExpectedIdentifier => write!(f, "expected identifier"),
126 ErrorKind::ExpectedKeyword(kw) => write!(f, "expected keyword '{}'", kw),
127 ErrorKind::InvalidSyntax(msg) => write!(f, "invalid syntax: {}", msg),
128 ErrorKind::UnsupportedFeature(feat) => write!(f, "unsupported feature: {}", feat),
129
130 ErrorKind::UndefinedColumn(name) => write!(f, "undefined column '{}'", name),
132 ErrorKind::UndefinedTable(name) => write!(f, "undefined table '{}'", name),
133 ErrorKind::UndefinedFunction(name) => write!(f, "undefined function '{}'", name),
134 ErrorKind::AmbiguousColumn(name) => write!(f, "ambiguous column reference '{}'", name),
135 ErrorKind::TypeMismatch { expected, found } => {
136 write!(f, "type mismatch: expected {}, found {}", expected, found)
137 }
138 ErrorKind::InvalidArgumentCount {
139 function,
140 expected,
141 found,
142 } => {
143 write!(
144 f,
145 "function '{}' expects {} arguments, found {}",
146 function, expected, found
147 )
148 }
149 ErrorKind::DuplicateColumn(name) => write!(f, "duplicate column '{}'", name),
150 ErrorKind::DuplicateAlias(name) => write!(f, "duplicate alias '{}'", name),
151 ErrorKind::InvalidGroupBy(msg) => write!(f, "invalid GROUP BY: {}", msg),
152 ErrorKind::InvalidOrderBy(msg) => write!(f, "invalid ORDER BY: {}", msg),
153 ErrorKind::InvalidAggregateUsage(msg) => write!(f, "invalid aggregate usage: {}", msg),
154 ErrorKind::InvalidWindowFunction(msg) => write!(f, "invalid window function: {}", msg),
155
156 ErrorKind::Internal(msg) => write!(f, "internal error: {}", msg),
158 }
159 }
160}
161
162#[derive(Debug, Clone)]
164pub struct Error {
165 pub kind: ErrorKind,
167 span: Option<Span>,
169 context: Option<String>,
171}
172
173impl Error {
174 pub fn new(kind: ErrorKind) -> Self {
176 Self {
177 kind,
178 span: None,
179 context: None,
180 }
181 }
182
183 pub fn with_span(kind: ErrorKind, span: Span) -> Self {
185 Self {
186 kind,
187 span: Some(span),
188 context: None,
189 }
190 }
191
192 pub fn with_context(mut self, context: impl Into<String>) -> Self {
194 self.context = Some(context.into());
195 self
196 }
197
198 pub fn span(&self) -> Option<Span> {
200 self.span
201 }
202
203 pub fn kind(&self) -> &ErrorKind {
205 &self.kind
206 }
207
208 pub fn unexpected_char(c: char, pos: usize) -> Self {
210 Self::with_span(ErrorKind::UnexpectedCharacter(c), Span::point(pos))
211 }
212
213 pub fn unexpected_token(
214 expected: impl Into<String>,
215 found: impl Into<String>,
216 span: Span,
217 ) -> Self {
218 Self::with_span(
219 ErrorKind::UnexpectedToken {
220 expected: expected.into(),
221 found: found.into(),
222 },
223 span,
224 )
225 }
226
227 pub fn unexpected_eof(pos: usize) -> Self {
228 Self::with_span(ErrorKind::UnexpectedEof, Span::point(pos))
229 }
230
231 pub fn expected_expression(span: Span) -> Self {
232 Self::with_span(ErrorKind::ExpectedExpression, span)
233 }
234
235 pub fn expected_identifier(span: Span) -> Self {
236 Self::with_span(ErrorKind::ExpectedIdentifier, span)
237 }
238
239 pub fn expected_keyword(keyword: impl Into<String>, span: Span) -> Self {
240 Self::with_span(ErrorKind::ExpectedKeyword(keyword.into()), span)
241 }
242
243 pub fn invalid_syntax(msg: impl Into<String>, span: Span) -> Self {
244 Self::with_span(ErrorKind::InvalidSyntax(msg.into()), span)
245 }
246
247 pub fn unsupported(feature: impl Into<String>, span: Span) -> Self {
248 Self::with_span(ErrorKind::UnsupportedFeature(feature.into()), span)
249 }
250
251 pub fn unterminated_string(span: Span) -> Self {
252 Self::with_span(ErrorKind::UnterminatedString, span)
253 }
254
255 pub fn unterminated_comment(span: Span) -> Self {
256 Self::with_span(ErrorKind::UnterminatedBlockComment, span)
257 }
258
259 pub fn invalid_escape(seq: impl Into<String>, span: Span) -> Self {
260 Self::with_span(ErrorKind::InvalidEscapeSequence(seq.into()), span)
261 }
262
263 pub fn invalid_number(num: impl Into<String>, span: Span) -> Self {
264 Self::with_span(ErrorKind::InvalidNumber(num.into()), span)
265 }
266
267 pub fn analyzer(msg: impl Into<String>) -> Self {
269 Self::new(ErrorKind::Internal(msg.into()))
270 }
271}
272
273impl fmt::Display for Error {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 write!(f, "{}", self.kind)?;
276 if let Some(ref ctx) = self.context {
277 write!(f, " ({})", ctx)?;
278 }
279 if let Some(span) = self.span {
280 write!(f, " at position {}", span.start)?;
281 }
282 Ok(())
283 }
284}
285
286impl std::error::Error for Error {}
287
288pub type Result<T> = std::result::Result<T, Error>;
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn test_span_merge() {
297 let span1 = Span::new(10, 20);
298 let span2 = Span::new(15, 30);
299 let merged = span1.merge(span2);
300 assert_eq!(merged.start, 10);
301 assert_eq!(merged.end, 30);
302 }
303
304 #[test]
305 fn test_error_display() {
306 let err = Error::unexpected_char('$', 5);
307 let msg = format!("{}", err);
308 assert!(msg.contains("unexpected character"));
309 assert!(msg.contains("$"));
310 }
311
312 #[test]
313 fn test_error_with_context() {
314 let err = Error::new(ErrorKind::UnexpectedEof).with_context("parsing SELECT clause");
315 let msg = format!("{}", err);
316 assert!(msg.contains("parsing SELECT clause"));
317 }
318}