use alloc::boxed::Box;
use core::fmt;
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct ParseError {
pub(crate) original: Box<str>,
pub(crate) span: core::ops::Range<usize>,
pub(crate) reason: Reason,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum Reason {
InvalidNot(usize),
UnclosedParens,
UnopenedParens,
UnclosedQuotes,
Empty,
Unexpected(&'static [&'static str]),
MultipleRootPredicates,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.original)?;
f.write_str("\n")?;
for _ in 0..self.span.start {
f.write_str(" ")?;
}
match &self.reason {
r @ (Reason::UnclosedParens | Reason::UnclosedQuotes) => {
f.write_fmt(format_args!("- {r}"))
}
r @ Reason::UnopenedParens => f.write_fmt(format_args!("^ {r}")),
other => {
for _ in self.span.start..self.span.end {
f.write_str("^")?;
}
f.write_fmt(format_args!(" {other}"))
}
}
}
}
impl fmt::Display for Reason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Reason::{
Empty, InvalidNot, MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected,
UnopenedParens,
};
match self {
UnclosedParens => f.write_str("unclosed parens"),
UnopenedParens => f.write_str("unopened parens"),
UnclosedQuotes => f.write_str("unclosed quotes"),
Empty => f.write_str("empty expression"),
Unexpected(expected) => {
if expected.len() > 1 {
f.write_str("expected one of ")?;
for (i, exp) in expected.iter().enumerate() {
f.write_fmt(format_args!("{}`{exp}`", if i > 0 { ", " } else { "" }))?;
}
f.write_str(" here")
} else if !expected.is_empty() {
f.write_fmt(format_args!("expected a `{}` here", expected[0]))
} else {
f.write_str("the term was not expected here")
}
}
InvalidNot(np) => f.write_fmt(format_args!("not() takes 1 predicate, found {np}")),
MultipleRootPredicates => f.write_str("multiple root predicates"),
}
}
}
impl core::error::Error for ParseError {}