use lalrpop_util as lalr;
use std::fmt::Display;
use thiserror::Error;
#[derive(Debug, Error, PartialEq, Clone)]
pub enum ParseError {
#[error("{0}")]
ToCST(String),
#[error("poorly formed: {0}")]
ToAST(String),
#[error("error while {context}: {}", MultipleParseErrors(errs))]
WithContext {
context: String,
errs: Vec<ParseError>,
},
#[error(transparent)]
RestrictedExpressionError(#[from] crate::ast::RestrictedExpressionError),
}
impl<L: Display, T: Display, E: Display> From<lalr::ParseError<L, T, E>> for ParseError {
fn from(e: lalr::ParseError<L, T, E>) -> Self {
ParseError::ToCST(format!("{}", e))
}
}
impl<L: Display, T: Display, E: Display> From<lalr::ErrorRecovery<L, T, E>> for ParseError {
fn from(e: lalr::ErrorRecovery<L, T, E>) -> Self {
e.error.into()
}
}
#[derive(Debug, Error)]
pub struct ParseErrors(pub Vec<ParseError>);
impl ParseErrors {
pub fn errors_as_strings(&self) -> Vec<String> {
self.0
.iter()
.map(|parser_error| format!("{}", parser_error))
.collect()
}
}
impl std::fmt::Display for ParseErrors {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", MultipleParseErrors(&self.0))
}
}
impl From<ParseError> for ParseErrors {
fn from(e: ParseError) -> ParseErrors {
ParseErrors(vec![e])
}
}
#[derive(Debug, Error)]
pub struct MultipleParseErrors<'a>(pub &'a [ParseError]);
impl<'a> std::fmt::Display for MultipleParseErrors<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0.is_empty() {
write!(f, "no errors found")
} else {
for err in self.0 {
write!(f, "\n {}", err)?;
}
Ok(())
}
}
}
impl From<Vec<ParseError>> for ParseErrors {
fn from(errs: Vec<ParseError>) -> Self {
ParseErrors(errs)
}
}
impl FromIterator<ParseError> for ParseErrors {
fn from_iter<T: IntoIterator<Item = ParseError>>(errs: T) -> Self {
ParseErrors(errs.into_iter().collect())
}
}
impl IntoIterator for ParseErrors {
type Item = ParseError;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a ParseErrors {
type Item = &'a ParseError;
type IntoIter = std::slice::Iter<'a, ParseError>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut ParseErrors {
type Item = &'a mut ParseError;
type IntoIter = std::slice::IterMut<'a, ParseError>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}