jaq_syn/
filter.rs

1//! Functions from values to streams of values.
2use crate::{Call, MathOp, OrdOp, Path, Span, Spanned, Str};
3use alloc::{boxed::Box, string::String, vec::Vec};
4use core::fmt;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8/// Assignment operators, such as `=`, `|=` (update), and `+=`, `-=`, ...
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[derive(Clone, Debug)]
11pub enum AssignOp {
12    /// `=`
13    Assign,
14    /// `|=`
15    Update,
16    /// `+=`, `-=`, `*=`, `/=`, `%=`
17    UpdateWith(MathOp),
18}
19
20impl fmt::Display for AssignOp {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        match self {
23            Self::Assign => "=".fmt(f),
24            Self::Update => "|=".fmt(f),
25            Self::UpdateWith(op) => write!(f, "{op}="),
26        }
27    }
28}
29
30/// Binary operators, such as `|`, `,`, `//`, ...
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32#[derive(Clone, Debug)]
33pub enum BinaryOp {
34    /// Application, i.e. `l | r` if no string is given, else `l as $x | r`
35    Pipe(Option<String>),
36    /// Concatenation, i.e. `l, r`
37    Comma,
38    /// Alternation, i.e. `l // r`
39    Alt,
40    /// Logical disjunction, i.e. `l or r`
41    Or,
42    /// Logical conjunction, i.e. `l and r`
43    And,
44    /// Arithmetic operation, e.g. `l + r`, `l - r`, ...
45    Math(MathOp),
46    /// Assignment, i.e. `l = r`, `l |= r`, `l += r`, `l -= r`, ...
47    Assign(AssignOp),
48    /// Ordering operation, e.g. `l == r`, `l <= r`, ...
49    Ord(OrdOp),
50}
51
52/// An element of an object construction filter.
53///
54/// For example, the object construction filter `{(.): 1, b: 2}`
55/// consists of two elements, namely `(.): 1` and `b: 2`.
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57#[derive(Clone, Debug)]
58pub enum KeyVal<T> {
59    /// Both key and value are proper filters, e.g. `{(.+1): .+2}`
60    Filter(T, T),
61    /// Key is a string, and value is an optional filter, e.g. `{a: 1, b}`
62    /// (this is equivalent to `{("a"): 1, ("b"): .b}`)
63    Str(Str<T>, Option<T>),
64}
65
66impl<F> KeyVal<F> {
67    /// Apply a function to the contained filters.
68    pub fn map<G>(self, mut f: impl FnMut(F) -> G) -> KeyVal<G> {
69        match self {
70            Self::Filter(k, v) => KeyVal::Filter(f(k), f(v)),
71            Self::Str(k, v) => KeyVal::Str(k.map(&mut f), v.map(f)),
72        }
73    }
74}
75
76/// Common information for folding filters (such as `reduce` and `foreach`)
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78#[derive(Clone, Debug)]
79pub struct Fold<F> {
80    /// Generator
81    pub xs: F,
82    /// Name of assigned variable
83    pub x: String,
84    /// Initial values
85    pub init: F,
86    /// Updater
87    pub f: F,
88}
89
90/// Type of folding filter.
91#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92#[derive(Copy, Clone, Debug)]
93pub enum FoldType {
94    /// return only the final value of fold
95    Reduce,
96    /// return initial, intermediate, and final values of fold
97    For,
98    /// return intermediate and final values of fold
99    Foreach,
100}
101
102/// Function from value to stream of values, such as `.[] | add / length`.
103#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104#[derive(Clone, Debug)]
105pub enum Filter<C = String, V = String, Num = String> {
106    /// Call to another filter, e.g. `map(.+1)`
107    Call(C, Vec<Spanned<Self>>),
108    /// Variable, such as $x (without leading '$')
109    Var(V),
110
111    /// Integer or floating-point number.
112    Num(Num),
113    /// String
114    Str(Box<Str<Spanned<Self>>>),
115    /// Array, empty if `None`
116    Array(Option<Box<Spanned<Self>>>),
117    /// Object, specifying its key-value pairs
118    Object(Vec<KeyVal<Spanned<Self>>>),
119
120    /// Identity, i.e. `.`
121    Id,
122    /// Path such as `.`, `.a`, `.[][]."b"`
123    Path(Box<Spanned<Self>>, Path<Self>),
124    /// If-then-else
125    Ite(
126        Vec<(Spanned<Self>, Spanned<Self>)>,
127        Option<Box<Spanned<Self>>>,
128    ),
129    /// `reduce` and `foreach`, e.g. `reduce .[] as $x (0; .+$x)`
130    ///
131    /// The first field indicates whether to yield intermediate results
132    /// (`false` for `reduce` and `true` for `foreach`).
133    Fold(FoldType, Fold<Box<Spanned<Self>>>),
134    /// `try` and optional `catch`
135    TryCatch(Box<Spanned<Self>>, Option<Box<Spanned<Self>>>),
136    /// Error suppression, e.g. `keys?`
137    Try(Box<Spanned<Self>>),
138    /// Negation
139    Neg(Box<Spanned<Self>>),
140    /// Recursion (`..`)
141    Recurse,
142    /// Binary operation, such as `0, 1`, `[] | .[]`, `.[] += 1`, `0 == 0`, ...
143    Binary(Box<Spanned<Self>>, BinaryOp, Box<Spanned<Self>>),
144}
145
146impl From<Str<Spanned<Self>>> for Filter {
147    fn from(s: Str<Spanned<Self>>) -> Self {
148        Self::Str(Box::new(s))
149    }
150}
151
152impl From<Call<Spanned<Self>>> for Filter {
153    fn from(c: Call<Spanned<Self>>) -> Self {
154        Self::Call(c.name, c.args)
155    }
156}
157
158impl Filter {
159    /// Create a binary expression, such as `1 + 2`.
160    pub fn binary(a: Spanned<Self>, op: BinaryOp, b: Spanned<Self>) -> Spanned<Self> {
161        let span = a.1.start..b.1.end;
162        (Self::Binary(Box::new(a), op, Box::new(b)), span)
163    }
164
165    /// Create a path expression, such as `keys[]` or `.a.b`.
166    ///
167    /// Here, `f` is a filter on whose output the path is executed on,
168    /// such as `keys` and `.` in the example above.
169    pub fn path(f: Spanned<Self>, path: Path<Self>, span: Span) -> Spanned<Self> {
170        if path.is_empty() {
171            f
172        } else {
173            (Self::Path(Box::new(f), path), span)
174        }
175    }
176}