use std::{error::Error, fmt};
#[derive(Debug, PartialEq, Eq)]
pub struct ParseError {
pub original: String,
pub span: std::ops::Range<usize>,
pub reason: Reason,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Reason {
InvalidNot(usize),
InvalidCharacters,
UnclosedParens,
UnopenedParens,
UnclosedQuotes,
UnopenedQuotes,
Empty,
Unexpected(&'static [&'static str]),
InvalidInteger,
MultipleRootPredicates,
InvalidHasAtomic,
UnknownBuiltin,
}
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 | Reason::UnopenedQuotes) => {
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, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
UnopenedParens, UnopenedQuotes,
};
match self {
InvalidCharacters => f.write_str("invalid character(s)"),
UnclosedParens => f.write_str("unclosed parens"),
UnopenedParens => f.write_str("unopened parens"),
UnclosedQuotes => f.write_str("unclosed quotes"),
UnopenedQuotes => f.write_str("unopened 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}")),
InvalidInteger => f.write_str("invalid integer"),
MultipleRootPredicates => f.write_str("multiple root predicates"),
InvalidHasAtomic => f.write_str("expected integer or \"ptr\""),
UnknownBuiltin => f.write_str("unknown built-in"),
}
}
}
impl Error for ParseError {
fn description(&self) -> &str {
use Reason::{
Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
UnopenedParens, UnopenedQuotes,
};
match self.reason {
InvalidCharacters => "invalid character(s)",
UnclosedParens => "unclosed parens",
UnopenedParens => "unopened parens",
UnclosedQuotes => "unclosed quotes",
UnopenedQuotes => "unopened quotes",
Empty => "empty expression",
Unexpected(_) => "unexpected term",
InvalidNot(_) => "not() takes 1 predicate",
InvalidInteger => "invalid integer",
MultipleRootPredicates => "multiple root predicates",
InvalidHasAtomic => "expected integer or \"ptr\"",
UnknownBuiltin => "unknown built-in",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HasAtomicParseError {
pub(crate) input: String,
}
impl fmt::Display for HasAtomicParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "expected integer or \"ptr\", found {}", self.input)
}
}
impl Error for HasAtomicParseError {}