use super::super::{ArgsError, Name};
use crate::css::{BadSelector, Value};
use crate::input::SourcePos;
use crate::output::Format;
use crate::{Error, Invalid, ScopeError};
use std::fmt;
#[derive(Debug)]
pub enum CallError {
Invalid(Invalid),
BadArgument(Name, String),
Args(ArgsError, SourcePos),
Wrap(Box<Error>),
}
impl CallError {
pub fn msg<S: ToString>(msg: S) -> Self {
Self::Invalid(Invalid::AtError(msg.to_string()))
}
pub fn incompatible_values<T: Into<Value>>(a: T, b: T) -> Self {
Self::msg(format!(
"{} and {} are incompatible.",
a.into().format(Format::introspect()),
b.into().format(Format::introspect()),
))
}
pub fn called_from(self, call_pos: &SourcePos, name: &str) -> Error {
match self {
Self::Invalid(Invalid::AtError(msg)) => {
Error::BadCall(msg, call_pos.clone().opt_in_calc(), None)
}
Self::Invalid(err) => {
Error::BadCall(format!("{err:?}"), call_pos.clone(), None)
}
Self::BadArgument(name, problem) => Error::BadCall(
if name.as_ref().is_empty() {
problem
} else {
format!("${name}: {problem}")
},
call_pos.clone(),
None,
),
Self::Args(ArgsError::Eval(err), _decl) => *err,
Self::Args(err, decl) => Error::BadCall(
err.to_string(),
if decl.is_builtin() {
call_pos.clone()
} else {
call_pos.in_call(name)
},
Some(decl),
),
Self::Wrap(err) => *err,
}
}
}
impl std::error::Error for CallError {}
impl From<ScopeError> for CallError {
fn from(err: ScopeError) -> Self {
Self::Invalid(Invalid::InScope(err))
}
}
impl From<Invalid> for CallError {
fn from(err: Invalid) -> Self {
Self::Invalid(err)
}
}
impl From<BadSelector> for CallError {
fn from(e: BadSelector) -> Self {
Self::msg(e)
}
}
impl From<Error> for CallError {
fn from(e: Error) -> Self {
Self::Wrap(Box::new(e))
}
}
impl fmt::Display for CallError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {self:?}")
}
}