1use std::fmt;
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Position {
7 pub offset: usize, pub line: usize, pub column: usize, }
11
12impl Position {
13 pub fn new(offset: usize, line: usize, column: usize) -> Self {
14 Self { offset, line, column }
15 }
16}
17
18impl fmt::Display for Position {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 write!(f, "line {}, column {}", self.line, self.column)
21 }
22}
23
24#[derive(Debug, thiserror::Error)]
26pub enum LexError {
27 #[error("Unexpected character '{ch}' at {pos}")]
28 UnexpectedChar { ch: char, pos: Position },
29
30 #[error("Unterminated string at {pos}")]
31 UnterminatedString { pos: Position },
32
33 #[error("Invalid escape sequence '\\{ch}' at {pos}")]
34 InvalidEscape { ch: char, pos: Position },
35
36 #[error("Unexpected end of input")]
37 UnexpectedEof,
38}
39
40#[derive(Debug, thiserror::Error)]
42pub enum ParseError {
43 #[error("Unexpected token {token:?} at {pos}")]
44 UnexpectedToken { token: String, pos: Position },
45
46 #[error("Expected {expected}, found {found} at {pos}")]
47 Expected { expected: String, found: String, pos: Position },
48
49 #[error("Unterminated list at {pos}")]
50 UnterminatedList { pos: Position },
51
52 #[error("Unexpected closing parenthesis at {pos}")]
53 UnexpectedCloseParen { pos: Position },
54
55 #[error("Empty input")]
56 EmptyInput,
57
58 #[error("Failed to read file {path:?}: {source}")]
59 FileReadError {
60 path: PathBuf,
61 #[source]
62 source: std::io::Error,
63 },
64
65 #[error("Lexer error: {0}")]
66 LexError(#[from] LexError),
67}
68
69pub type Result<T> = std::result::Result<T, ParseError>;