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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//! Functions from values to streams of values.
use crate::{Call, MathOp, OrdOp, Path, Span, Spanned, Str};
use alloc::{boxed::Box, string::String, vec::Vec};
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// Assignment operators, such as `=`, `|=` (update), and `+=`, `-=`, ...
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum AssignOp {
/// `=`
Assign,
/// `|=`
Update,
/// `+=`, `-=`, `*=`, `/=`, `%=`
UpdateWith(MathOp),
}
impl fmt::Display for AssignOp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Assign => "=".fmt(f),
Self::Update => "|=".fmt(f),
Self::UpdateWith(op) => write!(f, "{op}="),
}
}
}
/// Binary operators, such as `|`, `,`, `//`, ...
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum BinaryOp {
/// Application, i.e. `l | r` if no string is given, else `l as $x | r`
Pipe(Option<String>),
/// Concatenation, i.e. `l, r`
Comma,
/// Alternation, i.e. `l // r`
Alt,
/// Logical disjunction, i.e. `l or r`
Or,
/// Logical conjunction, i.e. `l and r`
And,
/// Arithmetic operation, e.g. `l + r`, `l - r`, ...
Math(MathOp),
/// Assignment, i.e. `l = r`, `l |= r`, `l += r`, `l -= r`, ...
Assign(AssignOp),
/// Ordering operation, e.g. `l == r`, `l <= r`, ...
Ord(OrdOp),
}
/// An element of an object construction filter.
///
/// For example, the object construction filter `{(.): 1, b: 2}`
/// consists of two elements, namely `(.): 1` and `b: 2`.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum KeyVal<T> {
/// Both key and value are proper filters, e.g. `{(.+1): .+2}`
Filter(T, T),
/// Key is a string, and value is an optional filter, e.g. `{a: 1, b}`
/// (this is equivalent to `{("a"): 1, ("b"): .b}`)
Str(Str<T>, Option<T>),
}
impl<F> KeyVal<F> {
/// Apply a function to the contained filters.
pub fn map<G>(self, mut f: impl FnMut(F) -> G) -> KeyVal<G> {
match self {
Self::Filter(k, v) => KeyVal::Filter(f(k), f(v)),
Self::Str(k, v) => KeyVal::Str(k.map(&mut f), v.map(f)),
}
}
}
/// Common information for folding filters (such as `reduce` and `foreach`)
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Fold<F> {
/// Generator
pub xs: F,
/// Name of assigned variable
pub x: String,
/// Initial values
pub init: F,
/// Updater
pub f: F,
}
/// Type of folding filter.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug)]
pub enum FoldType {
/// return only the final value of fold
Reduce,
/// return initial, intermediate, and final values of fold
For,
/// return intermediate and final values of fold
Foreach,
}
/// Function from value to stream of values, such as `.[] | add / length`.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum Filter<C = String, V = String, Num = String> {
/// Call to another filter, e.g. `map(.+1)`
Call(C, Vec<Spanned<Self>>),
/// Variable, such as $x (without leading '$')
Var(V),
/// Integer or floating-point number.
Num(Num),
/// String
Str(Box<Str<Spanned<Self>>>),
/// Array, empty if `None`
Array(Option<Box<Spanned<Self>>>),
/// Object, specifying its key-value pairs
Object(Vec<KeyVal<Spanned<Self>>>),
/// Identity, i.e. `.`
Id,
/// Path such as `.`, `.a`, `.[][]."b"`
Path(Box<Spanned<Self>>, Path<Self>),
/// If-then-else
Ite(
Vec<(Spanned<Self>, Spanned<Self>)>,
Option<Box<Spanned<Self>>>,
),
/// `reduce` and `foreach`, e.g. `reduce .[] as $x (0; .+$x)`
///
/// The first field indicates whether to yield intermediate results
/// (`false` for `reduce` and `true` for `foreach`).
Fold(FoldType, Fold<Box<Spanned<Self>>>),
/// `try` and optional `catch`
TryCatch(Box<Spanned<Self>>, Option<Box<Spanned<Self>>>),
/// Error suppression, e.g. `keys?`
Try(Box<Spanned<Self>>),
/// Negation
Neg(Box<Spanned<Self>>),
/// Recursion (`..`)
Recurse,
/// Binary operation, such as `0, 1`, `[] | .[]`, `.[] += 1`, `0 == 0`, ...
Binary(Box<Spanned<Self>>, BinaryOp, Box<Spanned<Self>>),
}
impl From<Str<Spanned<Filter>>> for Filter {
fn from(s: Str<Spanned<Filter>>) -> Self {
Self::Str(Box::new(s))
}
}
impl From<Call<Spanned<Filter>>> for Filter {
fn from(c: Call<Spanned<Filter>>) -> Self {
Self::Call(c.name, c.args)
}
}
impl Filter {
/// Create a binary expression, such as `1 + 2`.
pub fn binary(a: Spanned<Self>, op: BinaryOp, b: Spanned<Self>) -> Spanned<Self> {
let span = a.1.start..b.1.end;
(Filter::Binary(Box::new(a), op, Box::new(b)), span)
}
/// Create a path expression, such as `keys[]` or `.a.b`.
///
/// Here, `f` is a filter on whose output the path is executed on,
/// such as `keys` and `.` in the example above.
pub fn path(f: Spanned<Self>, path: Path<Self>, span: Span) -> Spanned<Self> {
if path.is_empty() {
f
} else {
(Filter::Path(Box::new(f), path), span)
}
}
}