use cljrs_value::Value;
use cljrs_value::ValueError;
#[derive(Debug, thiserror::Error)]
pub enum EvalError {
#[error("runtime error: {0}")]
Runtime(String),
#[error("gas exhausted")]
GasExhausted,
#[error("{0}")]
MemoryLimitExceeded(cljrs_gc::MemoryLimitExceeded),
#[error("effect forbidden in transaction function: {0}")]
ForbiddenEffect(String),
#[error("unbound symbol: {0}")]
UnboundSymbol(String),
#[error("arity error calling {name}: expected {expected}, got {got}")]
Arity {
name: String,
expected: String,
got: usize,
},
#[error("not callable: {0}")]
NotCallable(String),
#[error("{0}")]
Thrown(Value),
#[error("read error: {0}")]
Read(#[from] cljrs_types::error::CljxError),
#[doc(hidden)]
#[error("internal: recur outside loop or fn")]
Recur(Vec<Value>),
#[error(
"commit {commit:?} failed signature verification — \
refusing to execute versioned symbol (enable GPG/SSH trust or disable \
:verify-commit-signatures): {reason}"
)]
CommitSignatureVerificationFailed { commit: String, reason: String },
}
impl EvalError {
pub fn to_error_value(self) -> Value {
match self {
EvalError::Thrown(v) => v,
other => {
let msg = other.to_string();
let error = match other {
EvalError::MemoryLimitExceeded(fault) => {
cljrs_value::ValueError::MemoryLimitExceeded(fault)
}
_ => cljrs_value::ValueError::Other(msg.clone()),
};
Value::Error(cljrs_gc::GcPtr::new_critical(
cljrs_value::ExceptionInfo::new(error, msg, None, None),
))
}
}
}
}
pub fn value_error_to_eval_error(err: ValueError) -> EvalError {
match err {
ValueError::Thrown(v) => EvalError::Thrown(v),
ValueError::GasExhausted => EvalError::GasExhausted,
ValueError::MemoryLimitExceeded(fault) => {
let _ = cljrs_gc::governor::take_runtime_fault();
EvalError::MemoryLimitExceeded(fault)
}
other => {
let msg = other.to_string();
EvalError::Thrown(Value::Error(cljrs_gc::GcPtr::new_critical(
cljrs_value::ExceptionInfo::new(other, msg, None, None),
)))
}
}
}
pub type EvalResult<T = Value> = Result<T, EvalError>;