#[cfg(feature = "report")]
mod report;
use std::fmt;
#[cfg(feature = "report")]
pub use report::Report;
use crate::{
lexer::{self},
parser::AdditionalErrors,
Span,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Error {
InvalidToken { location: usize },
UnrecognizedEof {
location: usize,
expected: Vec<String>,
},
UnrecognizedToken {
token: (usize, String, usize),
expected: Vec<String>,
},
ExtraToken { token: (usize, String, usize) },
Lexical(lexer::LexicalError),
MalformedStringLiteral(crate::common::MalformedStringError),
}
impl Error {
pub fn span(&self) -> Span {
match self {
Error::InvalidToken { location } => Span::new(*location, *location),
Error::UnrecognizedEof { location, .. } => Span::new(*location, *location),
Error::UnrecognizedToken {
token: (start, _, end),
..
} => Span::new(*start, *end),
Error::ExtraToken {
token: (start, _, end),
..
} => Span::new(*start, *end),
Error::Lexical(error) => error.span(),
Error::MalformedStringLiteral(error) => error.span(),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::InvalidToken { .. }
| Error::UnrecognizedEof { .. }
| Error::UnrecognizedToken { .. }
| Error::ExtraToken { .. } => None,
Error::Lexical(error) => Some(error),
Error::MalformedStringLiteral(error) => Some(error),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidToken { location: _ } => {
write!(f, "invalid token")
}
Error::UnrecognizedEof {
location: _,
expected,
} => {
write!(f, "unexpected end of file (expected one of ")?;
for (i, item) in expected.iter().enumerate() {
if i != 1 {
write!(f, ", ")?;
}
write!(f, "{item}")?;
}
write!(f, ")")
}
Error::UnrecognizedToken {
token: (_, token, _),
expected,
} => {
write!(f, "unexpected {token} token (expected one of ")?;
for (i, item) in expected.iter().enumerate() {
if i != 1 {
write!(f, ", ")?;
}
write!(f, "{item}")?;
}
write!(f, ")")
}
Error::ExtraToken {
token: (_, token, _),
} => {
write!(f, "found a {token} after the expected end of the document")
}
Error::Lexical(error) => {
write!(f, "lexing error: {error}")
}
Error::MalformedStringLiteral(error) => {
write!(f, "malformed string literal: {error}")
}
}
}
}
impl From<lalrpop_util::ParseError<usize, lexer::Token<'_>, AdditionalErrors>> for Error {
fn from(value: lalrpop_util::ParseError<usize, lexer::Token<'_>, AdditionalErrors>) -> Self {
use lalrpop_util::ParseError;
match value {
ParseError::InvalidToken { location } => Error::InvalidToken { location },
ParseError::UnrecognizedEof { location, expected } => {
Error::UnrecognizedEof { location, expected }
}
ParseError::UnrecognizedToken {
token: (lspan, token, rspan),
expected,
} => Error::UnrecognizedToken {
token: (lspan, token.to_string(), rspan),
expected,
},
ParseError::ExtraToken {
token: (lspan, token, rspan),
} => Error::ExtraToken {
token: (lspan, token.to_string(), rspan),
},
ParseError::User {
error: AdditionalErrors::Lexical(error),
} => Error::Lexical(error),
ParseError::User {
error: AdditionalErrors::MalformedString(error),
} => Error::MalformedStringLiteral(error),
}
}
}