use std::borrow::Cow;
use std::fmt::Display;
use crate::parser::core::Span;
use crate::prelude::PInput;
#[derive(Clone, Debug, PartialEq)]
pub enum TokenPattern<'a, K>
where
K: Clone,
{
Token(Cow<'a, K>),
Tokens(Cow<'a, [K]>),
String(Cow<'a, str>),
}
pub trait ErrorDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result;
}
impl ErrorDisplay for &[u8] {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", String::from_utf8(self.to_vec()).unwrap())
}
}
impl ErrorDisplay for u8 {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", String::from_utf8(vec![*self]).unwrap())
}
}
impl<'a, K> Display for TokenPattern<'a, K>
where
K: Clone + ErrorDisplay,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TokenPattern::Token(Cow::Borrowed(token)) => token.fmt(f),
TokenPattern::Token(Cow::Owned(token)) => token.fmt(f),
TokenPattern::Tokens(Cow::Borrowed(tokens)) => {
tokens.iter().try_for_each(|tok| tok.fmt(f))
}
TokenPattern::Tokens(Cow::Owned(tokens)) => {
tokens.iter().try_for_each(|tok| tok.fmt(f))
}
TokenPattern::String(Cow::Borrowed(str)) => write!(f, "{str}"),
TokenPattern::String(Cow::Owned(str)) => write!(f, "{str}"),
}
}
}
#[derive(Clone, Debug)]
pub enum ErrorKind<'a, K>
where
K: Clone,
{
Custom(String),
EOF,
Unexpected {
expected: Vec<TokenPattern<'a, K>>,
found: TokenPattern<'a, K>,
},
}
impl<'a, K> PartialEq for ErrorKind<'a, K>
where
K: Clone + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Custom(l0), Self::Custom(r0)) => l0 == r0,
(
Self::Unexpected {
expected: l_expected,
found: l_found,
},
Self::Unexpected {
expected: r_expected,
found: r_found,
},
) => l_expected.iter().zip(r_expected).all(|(a, b)| a == b) && l_found == r_found,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
impl<'a, K> Display for ErrorKind<'a, K>
where
K: Clone + ErrorDisplay,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ErrorKind::Custom(str) => write!(f, "{str}"),
ErrorKind::EOF => write!(f, "No tokens to read: reached end of file"),
ErrorKind::Unexpected { expected, found } => write!(
f,
"Expected: {} by found: \"{found}\"",
expected
.iter()
.map(|tok_pat| format!("{tok_pat}"))
.collect::<Vec<String>>()
.join(","),
),
}
}
}
#[derive(Debug)]
pub struct Error<'a, K>
where
K: PartialEq + Clone + 'a,
{
pub kind: Vec<ErrorKind<'a, K>>,
pub span: Span,
pub state: PInput<'a, K>,
}
impl<'a, K> Error<'a, K>
where
K: PartialEq + Clone + 'a,
{
pub fn new(kind: Vec<ErrorKind<'a, K>>, span: Span, state: PInput<'a, K>) -> Self {
Error { kind, span, state }
}
}
impl<'a, K> Display for Error<'a, K>
where
K: PartialEq + Clone + ErrorDisplay + 'a,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.kind
.iter()
.map(|err| format!("{err}"))
.collect::<Vec<String>>()
.join("\n")
)
}
}