use std::{fmt, sync::Arc};
use serde::{Deserialize, Serialize};
use crate::Span;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ParseErrorKind {
UnbalancedParen,
UnclosedClass,
InvalidEscape(char),
DanglingQuantifier,
InvalidRange { lo: char, hi: char },
InvalidCounted,
DuplicateGroupName(Box<str>),
UnsupportedFeature(&'static str),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseError {
pub kind: ParseErrorKind,
pub span: Span,
pub src: Arc<str>,
}
impl ParseError {
pub(crate) fn new(kind: ParseErrorKind, span: Span, src: &Arc<str>) -> Self {
Self {
kind,
span,
src: Arc::clone(src),
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let message = match &self.kind {
ParseErrorKind::UnbalancedParen => "unbalanced closing parenthesis".to_owned(),
ParseErrorKind::UnclosedClass => "unclosed character class".to_owned(),
ParseErrorKind::InvalidEscape(c) => format!("invalid escape: \\{c}"),
ParseErrorKind::DanglingQuantifier => "quantifier has no preceding atom".to_owned(),
ParseErrorKind::InvalidRange { lo, hi } => format!("invalid class range: {lo}-{hi}"),
ParseErrorKind::InvalidCounted => "invalid counted repetition".to_owned(),
ParseErrorKind::DuplicateGroupName(name) => format!("duplicate group name: {name}"),
ParseErrorKind::UnsupportedFeature(feature) => {
format!("unsupported regular-expression feature: {feature}")
}
};
writeln!(formatter, "{message}")?;
writeln!(formatter, "{}", self.src)?;
let width = (self.span.end - self.span.start).max(1) as usize;
write!(
formatter,
"{}{}",
" ".repeat(self.span.start as usize),
"^".repeat(width)
)
}
}
impl std::error::Error for ParseError {}