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
100
101
102
103
104
105
106
//! Runtime errors.
use crate::val::{Val, ValT};
use alloc::string::{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<V = Val> {
/// `0 | error`
Val(V),
/// Expected a value of given type, but got something else
Type(V, Type),
/// `1 - "a"`
MathOp(V, jaq_syn::MathOp, V),
/// `{} | .[0]` or `[] | has("a")` or `{} | has(0)`
Index(V, V),
/// `[] | .[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<V>),
}
/// 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<V: ValT> Error<V> {
/// Convert the error into a value to be used by `catch` filters.
pub fn as_val(self) -> V {
match self {
Self::Val(ev) => ev,
_ => V::from(self.to_string()),
}
}
}
impl<V: From<String>> Error<V> {
/// Build an error from something that can be converted to a string.
pub fn str(s: impl ToString) -> Self {
Self::Val(V::from(s.to_string()))
}
}
impl<V: ValT> fmt::Display for Error<V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Val(v) => {
if let Some(s) = v.as_str() {
write!(f, "{s}")
} else {
write!(f, "{v}")
}
}
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),
}
}
}