use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseErrorKind {
Incomplete,
TrailingData,
UnexpectedToken {
found: String,
expected: &'static [&'static str],
},
InvalidEncoding(&'static str),
InvalidNumber,
DepthLimit,
Message(&'static str),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LineCol {
pub line: u32,
pub col: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError {
pub kind: ParseErrorKind,
pub pos: usize,
pub line_col: Option<LineCol>,
pub context: Option<String>,
}
impl ParseError {
pub fn new(kind: ParseErrorKind, pos: usize) -> Self {
Self {
kind,
pos,
line_col: None,
context: None,
}
}
pub fn with_context(mut self, ctx: impl Into<String>) -> Self {
self.context = Some(ctx.into());
self
}
pub fn with_line_col(mut self, lc: LineCol) -> Self {
self.line_col = Some(lc);
self
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
ParseErrorKind::Incomplete => write!(f, "incomplete input at pos {}", self.pos)?,
ParseErrorKind::TrailingData => write!(f, "trailing data at pos {}", self.pos)?,
ParseErrorKind::UnexpectedToken { found, expected } => {
write!(f, "unexpected token {found:?} at pos {}", self.pos)?;
if !expected.is_empty() {
write!(f, ", expected one of: {:?}", expected)?;
}
Ok(())
}?,
ParseErrorKind::InvalidEncoding(msg) => write!(f, "invalid encoding ({msg}) at pos {}", self.pos)?,
ParseErrorKind::InvalidNumber => write!(f, "invalid number at pos {}", self.pos)?,
ParseErrorKind::DepthLimit => write!(f, "depth limit exceeded at pos {}", self.pos)?,
ParseErrorKind::Message(msg) => write!(f, "{msg} at pos {}", self.pos)?,
}
if let Some(lc) = self.line_col {
write!(f, " (line {}, col {})", lc.line, lc.col)?;
}
if let Some(ctx) = &self.context {
write!(f, " - {}", ctx)?;
}
Ok(())
}
}
impl std::error::Error for ParseError {}