use super::*;
use std::fmt;
pub type EvalResult<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Clone)]
pub struct Error {
    inner: Box<ErrorInner>,
}
impl Error {
    pub(super) fn new<T>(kind: T) -> Error
    where
        T: Into<ErrorKind>,
    {
        Error::new_with_expr(kind, None)
    }
    pub(super) fn new_with_expr<T>(kind: T, expr: Option<Expression>) -> Error
    where
        T: Into<ErrorKind>,
    {
        Error {
            inner: Box::new(ErrorInner::new(kind.into(), expr)),
        }
    }
    pub(super) fn unexpected<T>(value: T, expected: &'static str) -> Error
    where
        T: Into<Value>,
    {
        Error::new(ErrorKind::Unexpected(value.into(), expected))
    }
    pub fn kind(&self) -> &ErrorKind {
        &self.inner.kind
    }
    pub fn expr(&self) -> Option<&Expression> {
        self.inner.expr.as_ref()
    }
    pub fn into_kind(self) -> ErrorKind {
        self.inner.kind
    }
}
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, f)
    }
}
impl From<ErrorKind> for Error {
    fn from(kind: ErrorKind) -> Self {
        Error::new(kind)
    }
}
impl From<crate::Error> for Error {
    fn from(err: crate::Error) -> Self {
        Error::new(ErrorKind::Message(err.to_string()))
    }
}
impl std::error::Error for Error {}
#[derive(Debug, Clone)]
struct ErrorInner {
    kind: ErrorKind,
    expr: Option<Expression>,
}
impl ErrorInner {
    fn new(kind: ErrorKind, expr: Option<Expression>) -> ErrorInner {
        ErrorInner { kind, expr }
    }
}
impl fmt::Display for ErrorInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.kind)?;
        if let Some(expr) = &self.expr {
            write!(f, " in expression `{expr}`")?;
        }
        Ok(())
    }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
    Message(String),
    UndefinedVar(Identifier),
    UndefinedFunc(Identifier),
    Unexpected(Value, &'static str),
    Index(usize),
    UnaryOp(UnaryOperator, Value),
    BinaryOp(Value, BinaryOperator, Value),
    NoSuchKey(String),
    KeyExists(String),
    FuncCall(Identifier, String),
    #[deprecated(
        since = "0.16.3",
        note = "Support for raw expressions will be removed in an upcoming release"
    )]
    RawExpression,
}
impl From<Error> for ErrorKind {
    fn from(err: Error) -> Self {
        err.into_kind()
    }
}
impl From<&str> for ErrorKind {
    fn from(msg: &str) -> Self {
        ErrorKind::Message(msg.to_owned())
    }
}
impl From<String> for ErrorKind {
    fn from(msg: String) -> Self {
        ErrorKind::Message(msg)
    }
}
impl fmt::Display for ErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ErrorKind::Message(msg) => f.write_str(msg),
            ErrorKind::UndefinedVar(ident) => {
                write!(f, "undefined variable `{ident}`")
            }
            ErrorKind::UndefinedFunc(ident) => {
                write!(f, "undefined function `{ident}`")
            }
            ErrorKind::Unexpected(value, expected) => {
                write!(f, "unexpected value `{value}`, expected {expected}")
            }
            ErrorKind::Index(index) => write!(f, "index out of bounds: {index}"),
            ErrorKind::NoSuchKey(key) => write!(f, "no such key: `{key}`"),
            ErrorKind::KeyExists(key) => write!(f, "key `{key}` already exists"),
            ErrorKind::UnaryOp(operator, value) => write!(
                f,
                "unary operator `{operator}` is not applicable to `{value}`",
            ),
            ErrorKind::BinaryOp(lhs, operator, rhs) => write!(
                f,
                "binary operator `{operator}` is not applicable to `{lhs}` and `{rhs}`",
            ),
            ErrorKind::FuncCall(name, msg) => {
                write!(f, "error calling function `{name}`: {msg}")
            }
            #[allow(deprecated)]
            ErrorKind::RawExpression => f.write_str("raw expressions cannot be evaluated"),
        }
    }
}