use std::fmt;
use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Position {
pub offset: usize, pub line: usize, pub column: usize, }
impl Position {
pub fn new(offset: usize, line: usize, column: usize) -> Self {
Self { offset, line, column }
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "line {}, column {}", self.line, self.column)
}
}
#[derive(Debug, thiserror::Error)]
pub enum LexError {
#[error("Unexpected character '{ch}' at {pos}")]
UnexpectedChar { ch: char, pos: Position },
#[error("Unterminated string at {pos}")]
UnterminatedString { pos: Position },
#[error("Invalid escape sequence '\\{ch}' at {pos}")]
InvalidEscape { ch: char, pos: Position },
#[error("Unexpected end of input")]
UnexpectedEof,
}
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
#[error("Unexpected token {token:?} at {pos}")]
UnexpectedToken { token: String, pos: Position },
#[error("Expected {expected}, found {found} at {pos}")]
Expected { expected: String, found: String, pos: Position },
#[error("Unterminated list at {pos}")]
UnterminatedList { pos: Position },
#[error("Unexpected closing parenthesis at {pos}")]
UnexpectedCloseParen { pos: Position },
#[error("Empty input")]
EmptyInput,
#[error("Failed to read file {path:?}: {source}")]
FileReadError {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("Lexer error: {0}")]
LexError(#[from] LexError),
}
pub type Result<T> = std::result::Result<T, ParseError>;