1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_reporting::Annotation;
5use mago_reporting::Issue;
6use mago_span::HasPosition;
7use mago_span::HasSpan;
8use mago_span::Position;
9use mago_span::Span;
10
11#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
12pub enum SyntaxError {
13 UnexpectedToken(u8, Position),
14 UnrecognizedToken(u8, Position),
15 UnexpectedEndOfFile(Position),
16}
17
18impl HasSpan for SyntaxError {
19 fn span(&self) -> Span {
20 let position = match self {
21 Self::UnexpectedToken(_, p) => *p,
22 Self::UnrecognizedToken(_, p) => *p,
23 Self::UnexpectedEndOfFile(p) => *p,
24 };
25
26 Span::new(position, Position { offset: position.offset + 1, ..position })
27 }
28}
29
30impl std::fmt::Display for SyntaxError {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 let message = match self {
33 Self::UnexpectedToken(token, _) => &format!("Unexpected token `{}` (0x{:02X})", *token as char, token),
34 Self::UnrecognizedToken(token, _) => &format!("Unrecognised token `{}` (0x{:02X})", *token as char, token),
35 Self::UnexpectedEndOfFile(_) => "Unexpected end of file",
36 };
37
38 write!(f, "{}", message)
39 }
40}
41
42impl std::error::Error for SyntaxError {}
43
44impl From<SyntaxError> for Issue {
45 fn from(error: SyntaxError) -> Issue {
46 let position = error.position();
47 let span = Span::new(position, Position { offset: position.offset + 1, ..position });
48
49 Issue::error(error.to_string()).with_annotation(Annotation::primary(span).with_message("Syntax error."))
50 }
51}