1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
//! Runtime errors.
use crate::Val;
use alloc::string::ToString;
use core::fmt;
/// Errors that can occur during filter execution.
///
/// Each variant shows an example of how it can be produced.
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Error {
/// `0 | error`
Val(Val),
/// Expected a value of given type, but got something else
Type(Val, Type),
/// `1 - "a"`
MathOp(Val, jaq_syn::MathOp, Val),
/// `{} | .[0]` or `[] | has("a")` or `{} | has(0)`
Index(Val, Val),
/// `[] | .[0] = 0`
IndexOutOfBounds(isize),
/// `0 |= .+1`
PathExp,
/// Tail-recursive call.
///
/// This is used internally to execute tail-recursive filters.
/// If this can be observed by users, then this is a bug.
TailCall(crate::filter::TailCall),
}
/// Types and sets of types.
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Type {
/// `[] | .["a"]` or `limit("a"; 0)` or `range(0; "a")`
Int,
/// `"1" | sin` or `pow(2; "3")` or `fma(2; 3; "4")`
Float,
/// `-"a"`, `"a" | round`
Num,
/// `{(0): 1}` or `0 | fromjson` or `0 | explode` or `"a b c" | split(0)`
Str,
/// `0 | sort` or `0 | implode` or `[] | .[0:] = 0`
Arr,
/// `0 | .[]` or `0 | .[0]` or `0 | keys` (array or object)
Iter,
/// `{}[0:1]` (string or array)
Range,
}
impl Error {
/// Convert the error into a value to be used by `catch` filters.
pub fn as_val(self) -> Val {
match self {
Self::Val(ev) => ev,
_ => Val::str(self.to_string()),
}
}
/// Build an error from something that can be converted to a string.
pub fn str(s: impl ToString) -> Self {
Self::Val(Val::str(s.to_string()))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Val(Val::Str(s)) => s.fmt(f),
Self::Val(v) => v.fmt(f),
Self::Type(v, ty) => write!(f, "cannot use {v} as {ty}"),
Self::MathOp(l, op, r) => write!(f, "cannot calculate {l} {op} {r}"),
Self::Index(v, i) => write!(f, "cannot index {v} with {i}"),
Self::IndexOutOfBounds(i) => write!(f, "index {i} is out of bounds"),
Self::PathExp => write!(f, "invalid path expression"),
Self::TailCall(_) => panic!(),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Int => "integer".fmt(f),
Self::Float => "floating-point number".fmt(f),
Self::Num => "number".fmt(f),
Self::Str => "string".fmt(f),
Self::Arr => "array".fmt(f),
Self::Iter => "iterable (array or object)".fmt(f),
Self::Range => "rangeable (array or string)".fmt(f),
}
}
}