use crate::ast::*;
use smol_str::SmolStr;
use std::sync::Arc;
use thiserror::Error;
#[derive(Debug, PartialEq, Clone, Error)]
pub enum EvaluationError {
#[error("entity does not exist: {0}")]
EntityDoesNotExist(Arc<EntityUID>),
#[error("`{}` does not have the attribute: {}", &.entity, &.attr)]
EntityAttrDoesNotExist {
entity: Arc<EntityUID>,
attr: SmolStr,
},
#[error("cannot access attribute of unspecified entity: {0}")]
UnspecifiedEntityAccess(SmolStr),
#[error("record does not have the attribute: {0}. Available attributes: {1:?}")]
RecordAttrDoesNotExist(SmolStr, Vec<SmolStr>),
#[error(transparent)]
FailedExtensionFunctionLookup(#[from] crate::extensions::ExtensionsError),
#[error("{}", pretty_type_error(expected, actual))]
TypeError {
expected: Vec<Type>,
actual: Type,
},
#[error("wrong number of arguments provided to extension function {function_name}: expected {expected}, got {actual}")]
WrongNumArguments {
function_name: Name,
expected: usize,
actual: usize,
},
#[error(transparent)]
IntegerOverflow(#[from] IntegerOverflowError),
#[error(transparent)]
InvalidRestrictedExpression(#[from] RestrictedExpressionError),
#[error("template slot `{0}` was not linked")]
UnlinkedSlot(SlotId),
#[error("error while evaluating {extension_name} extension function: {msg}")]
FailedExtensionFunctionApplication {
extension_name: Name,
msg: String,
},
#[error("the expression contains unknown(s) (consider using the partial evaluation API): {0}")]
NonValue(Expr),
#[error("recursion limit reached")]
RecursionLimit,
}
fn pretty_type_error(expected: &[Type], actual: &Type) -> String {
match expected.len() {
#[allow(clippy::unreachable)]
0 => unreachable!("should expect at least one type"),
#[allow(clippy::indexing_slicing)]
1 => format!("type error: expected {}, got {}", expected[0], actual),
_ => {
use itertools::Itertools;
format!(
"type error: expected one of [{}], got {actual}",
expected.iter().join(", ")
)
}
}
}
#[derive(Debug, PartialEq, Clone, Error)]
pub enum IntegerOverflowError {
#[error("integer overflow while attempting to {} the values {arg1} and {arg2}", match .op { BinaryOp::Add => "add", BinaryOp::Sub => "subtract", _ => "perform an operation on" })]
BinaryOp {
op: BinaryOp,
arg1: Value,
arg2: Value,
},
#[error("integer overflow while attempting to multiply {arg} by {constant}")]
Multiplication {
arg: Value,
constant: i64,
},
#[error("integer overflow while attempting to {} the value {arg}", match .op { UnaryOp::Neg => "negate", _ => "perform an operation on" })]
UnaryOp {
op: UnaryOp,
arg: Value,
},
}
pub type Result<T> = std::result::Result<T, EvaluationError>;