use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseErrorKind {
UnexpectedToken,
UnexpectedEndOfInput,
InvalidSyntax,
InvalidNumber,
InvalidString,
InvalidRegex,
InvalidVariable,
MissingToken(String),
InvalidOperator,
InvalidIdentifier,
}
#[derive(Error, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ParseError {
#[error("Failed to parse input")]
ParseFailed,
#[error("Failed to serialize scanner state")]
SerializationFailed,
#[error("Failed to deserialize scanner state")]
DeserializationFailed,
#[error("Invalid token: {0}")]
InvalidToken(String),
#[error("Unexpected end of input")]
UnexpectedEof,
#[error("Invalid Unicode sequence")]
InvalidUnicode,
#[error("Invalid UTF-8: {0}")]
InvalidUtf8(String),
#[error("Scanner error: {0}")]
ScannerError(String),
#[error("Failed to load language")]
LanguageLoadFailed,
}
pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Error, Debug, Clone, PartialEq)]
pub enum ScannerError {
#[error("Invalid character: {0}")]
InvalidCharacter(char),
#[error("Unterminated string")]
UnterminatedString,
#[error("Unterminated comment")]
UnterminatedComment,
#[error("Invalid escape sequence: {0}")]
InvalidEscape(String),
#[error("Invalid Unicode sequence: {0}")]
InvalidUnicode(String),
#[error("Scanner state error: {0}")]
StateError(String),
}
#[derive(Error, Debug, Clone, PartialEq)]
pub enum UnicodeError {
#[error("Invalid Unicode code point: {0}")]
InvalidCodePoint(u32),
#[error("Invalid UTF-8 sequence")]
InvalidUtf8,
#[error("Unicode normalization failed: {0}")]
NormalizationFailed(String),
}
impl From<ScannerError> for ParseError {
fn from(err: ScannerError) -> Self {
ParseError::ScannerError(err.to_string())
}
}
impl From<UnicodeError> for ParseError {
fn from(err: UnicodeError) -> Self {
ParseError::ScannerError(err.to_string())
}
}
impl From<std::str::Utf8Error> for ParseError {
fn from(err: std::str::Utf8Error) -> Self {
ParseError::InvalidUtf8(err.to_string())
}
}
impl From<std::string::FromUtf8Error> for ParseError {
fn from(err: std::string::FromUtf8Error) -> Self {
ParseError::InvalidUtf8(err.to_string())
}
}
impl From<std::io::Error> for ParseError {
fn from(err: std::io::Error) -> Self {
ParseError::ScannerError(format!("I/O error: {}", err))
}
}
impl ParseError {
pub fn new(kind: ParseErrorKind, position: usize, message: String) -> Self {
let error_msg = match kind {
ParseErrorKind::UnexpectedToken => {
format!("Unexpected token at position {}: {}", position, message)
}
ParseErrorKind::UnexpectedEndOfInput => {
format!("Unexpected end of input at position {}: {}", position, message)
}
ParseErrorKind::InvalidSyntax => {
format!("Invalid syntax at position {}: {}", position, message)
}
ParseErrorKind::InvalidNumber => {
format!("Invalid number at position {}: {}", position, message)
}
ParseErrorKind::InvalidString => {
format!("Invalid string at position {}: {}", position, message)
}
ParseErrorKind::InvalidRegex => {
format!("Invalid regex at position {}: {}", position, message)
}
ParseErrorKind::InvalidVariable => {
format!("Invalid variable at position {}: {}", position, message)
}
ParseErrorKind::MissingToken(ref token) => {
format!("Missing {} at position {}: {}", token, position, message)
}
ParseErrorKind::InvalidOperator => {
format!("Invalid operator at position {}: {}", position, message)
}
ParseErrorKind::InvalidIdentifier => {
format!("Invalid identifier at position {}: {}", position, message)
}
};
ParseError::InvalidToken(error_msg)
}
pub fn unterminated_string(position: (usize, usize)) -> Self {
ParseError::ScannerError(format!(
"Unterminated string literal at line {}, column {}",
position.0, position.1
))
}
pub fn invalid_token(token: String, position: (usize, usize)) -> Self {
ParseError::InvalidToken(format!(
"Invalid token '{}' at line {}, column {}",
token, position.0, position.1
))
}
pub fn unicode_error(_message: &str) -> Self {
ParseError::InvalidUnicode
}
pub fn scanner_error_simple(message: &str) -> Self {
ParseError::ScannerError(message.to_string())
}
}