#![deny(missing_docs)]
pub struct Location {
pub file: Option<String>,
pub line: usize,
pub col: usize,
}
impl Location {
pub fn new(file: Option<String>, line: usize, col: usize) -> Self {
Location { file, line, col }
}
}
impl std::fmt::Display for Location {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(file) = &self.file {
write!(formatter, "{}:{}:{}", file, self.line, self.col)
} else {
write!(formatter, "{}:{}", self.line, self.col)
}
}
}
impl std::fmt::Debug for Location {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "{}", &self)
}
}
#[derive(Debug)]
pub enum Error {
Configuration(String),
Parse(Option<Location>, String),
Internal(Option<Location>, String),
TestFailure(Option<Location>, String),
}
impl std::error::Error for Error {}
impl Error {
pub fn configuration(err: impl std::fmt::Display) -> Self {
Error::Configuration(err.to_string())
}
pub fn parse(location: Option<Location>, err: impl std::fmt::Display) -> Self {
Error::Parse(location, err.to_string())
}
pub fn internal(location: Option<Location>, err: impl Into<String>) -> Self {
Error::Internal(location, err.into())
}
pub fn test_failure(location: Option<Location>, err: impl Into<String>) -> Self {
Error::TestFailure(location, err.into())
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (prefix, loc, err) = match &self {
Error::Configuration(err) => ("Configuration error", &None, err.to_string()),
Error::Parse(loc, err) => ("Parse error", loc, err.to_string()),
Error::Internal(loc, err) => ("Internal error", loc, err.to_string()),
Error::TestFailure(loc, err) => ("Test failure", loc, err.to_string()),
};
match loc {
Some(loc) => write!(f, "{}: {}: {}", prefix, loc, err),
None => write!(f, "{}: {}", prefix, err),
}
}
}
#[macro_export]
macro_rules! test_error {
($err:expr) => {
Error::test_failure(
Some(Location::new(Some(file!().to_string()), line!() as usize, column!() as usize)),
$err,
)
};
}