use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use crate::error::ThrowSite;
use crate::parser::ParserState;
pub(crate) type Result<T> = std::result::Result<T, ParseError>;
#[derive(Debug, Default)]
pub struct ParseError {
pub throw_site: ThrowSite,
pub xml_site: Option<XmlSite>,
pub message: Option<String>,
pub source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}
#[derive(Debug, Clone, Eq, PartialOrd, PartialEq, Hash, Default)]
pub struct XmlSite {
pub line: u64,
pub column: u64,
pub position: u64,
pub character: char,
}
pub(super) fn display_char(c: char) -> String {
match c {
'\n' => "\\n".into(),
'\t' => "\\t".into(),
'\r' => "\\r".into(),
'\u{000B}' => "\\u000B".into(),
'\u{000C}' => "\\u000C".into(),
' ' => "%20".into(),
_ => format!("{}", c),
}
}
impl Display for XmlSite {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"position: {}, line: {}, column: {}, character: '{}'",
self.position,
self.line,
self.column,
display_char(self.character)
)
}
}
impl XmlSite {
pub(crate) fn from_parser(p: &ParserState) -> Self {
Self {
line: p.position.line,
column: p.position.column,
position: p.position.absolute,
character: p.c,
}
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.throw_site, f)?;
if let Some(xml_site) = &self.xml_site {
write!(f, " xml ")?;
Display::fmt(&xml_site, f)?;
}
if let Some(msg) = &self.message {
if !msg.is_empty() {
write!(f, " - {}", msg)?;
}
}
if let Some(e) = &self.source {
write!(f, " - caused by: ")?;
Display::fmt(&e, f)?;
}
Ok(())
}
}
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(|e| e.as_ref() as &dyn std::error::Error)
}
}
pub(super) fn parse_err<S, E>(
parser_state: &ParserState,
throw_site: ThrowSite,
message: Option<S>,
source: Option<E>,
) -> crate::parser::error::ParseError
where
S: Into<String>,
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
crate::parser::error::ParseError {
throw_site,
xml_site: Some(XmlSite::from_parser(&parser_state)),
message: message.map(|s| s.into()),
source: source.map(|e| e.into()),
}
}