#[cfg(feature = "report")]
mod report;
use std::fmt;
#[cfg(feature = "report")]
pub use report::Report;
use crate::{
lexer,
parser::AdditionalErrors,
type_system::{DirectiveLocation, MalformedDirectiveLocation},
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),
MalformedDirectiveLocation(usize, String, usize),
VariableInConstPosition(usize, String, usize),
}
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(),
Error::MalformedDirectiveLocation(lhs, _, rhs) => Span::new(*lhs, *rhs),
Error::VariableInConstPosition(lhs, _, rhs) => Span::new(*lhs, *rhs),
}
}
}
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 { .. }
| Error::MalformedStringLiteral(..)
| Error::MalformedDirectiveLocation(..)
| Error::VariableInConstPosition(..) => None,
Error::Lexical(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, "{error}")
}
Error::MalformedStringLiteral(error) => {
write!(f, "malformed string literal: {error}")
}
Error::MalformedDirectiveLocation(_, location, _) => {
write!(
f,
"unknown directive location: {location}. expected one of "
)?;
for (i, location) in DirectiveLocation::all_locations().iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{location}")?;
}
Ok(())
}
Error::VariableInConstPosition(_, name, _) => {
write!(
f,
"the variable ${name} was found in a position that does not allow variables"
)?;
Ok(())
}
}
}
}
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),
ParseError::User {
error: AdditionalErrors::MalformedDirectiveLocation(lhs, location, rhs),
} => Error::MalformedDirectiveLocation(lhs, location, rhs),
ParseError::User {
error: AdditionalErrors::VariableInConstPosition(lhs, name, rhs),
} => Error::MalformedDirectiveLocation(lhs, name, rhs),
}
}
}
impl MalformedDirectiveLocation {
pub(crate) fn into_lalrpop_error<'a>(
self,
(lhs, rhs): (usize, usize),
) -> lalrpop_util::ParseError<usize, lexer::Token<'a>, AdditionalErrors> {
lalrpop_util::ParseError::User {
error: AdditionalErrors::MalformedDirectiveLocation(lhs, self.0, rhs),
}
}
}