use std::{
borrow::Cow,
convert::Infallible,
error::Error,
fmt::{self, Debug, Display, Formatter},
ops::Range,
path::PathBuf,
};
mod error_std;
pub type Result<T> = std::result::Result<T, TailwindError>;
pub type MaybeRanged = Option<Range<usize>>;
#[derive(Debug)]
pub struct TailwindError {
pub kind: Box<TailwindErrorKind>,
pub file: Option<PathBuf>,
pub range: Option<Range<usize>>,
}
#[derive(Debug)]
pub enum TailwindErrorKind {
IOError(std::io::Error),
FormatError(std::fmt::Error),
SyntaxError(String),
TypeMismatch(String),
RuntimeError(String),
UndefinedVariable {
name: String,
},
Incomplete,
Unreachable,
}
impl TailwindError {
#[inline]
pub fn set_path(&mut self, url: &std::path::Path) -> Result<()> {
self.file = Some(PathBuf::from(url));
Ok(())
}
#[inline]
pub fn set_range(&mut self, start: usize, end: usize) {
self.range = Some(Range { start, end });
}
#[inline]
pub fn incomplete() -> Self {
Self { kind: Box::new(TailwindErrorKind::Incomplete), file: None, range: None }
}
#[inline]
pub fn unreachable() -> Self {
Self { kind: Box::new(TailwindErrorKind::Unreachable), file: None, range: None }
}
#[inline]
pub fn undefined_variable(name: impl Into<String>) -> TailwindError {
let kind = TailwindErrorKind::UndefinedVariable { name: name.into() };
Self { kind: Box::new(kind), file: None, range: None }
}
}
impl TailwindError {
pub fn is_deprecated(&self) -> bool {
false
}
pub fn is_unnecessary(&self) -> bool {
false
}
}
macro_rules! error_msg {
($name:ident => $t:ident) => {
pub fn $name(msg: impl Into<String>) -> TailwindError {
let kind = TailwindErrorKind::$t(msg.into());
Self { kind: Box::new(kind), file: None, range: None }
}
};
($($name:ident => $t:ident),+ $(,)?) => (
impl TailwindError { $(error_msg!($name=>$t);)+ }
);
}
error_msg![
syntax_error => SyntaxError,
type_mismatch => TypeMismatch,
runtime_error => RuntimeError,
];
impl Error for TailwindError {}
impl Display for TailwindError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let path = match &self.file {
Some(s) => s.to_string_lossy(),
None => Cow::from("<Anonymous>"),
};
match &self.range {
Some(s) => writeln!(f, "at ({}, {}) of {}", s.start, s.end, path)?,
None => writeln!(f, "at {}", path)?,
}
write!(f, "{:indent$}{}", "", self.kind, indent = 4)
}
}
impl Display for TailwindErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::IOError(e) => {
write!(f, "{}", e)
},
Self::FormatError(e) => {
write!(f, "{}", e)
},
Self::SyntaxError(msg) => {
f.write_str("SyntaxError: ")?;
f.write_str(msg)
},
Self::TypeMismatch(msg) => {
f.write_str("TypeError: ")?;
f.write_str(msg)
},
Self::RuntimeError(msg) => {
f.write_str("RuntimeError: ")?;
f.write_str(msg)
},
Self::UndefinedVariable { name } => {
write!(f, "RuntimeError: Variable {} not found in scope", name)
},
Self::Incomplete => {
f.write_str("InternalError: ")?;
f.write_str("Parsing incomplete!")
},
Self::Unreachable => {
f.write_str("InternalError: ")?;
f.write_str("Entered unreachable code!")
},
}
}
}