1use super::*;
2use crate::eval::EvalCtx;
3use either::Either;
4use std::borrow::Cow;
5
6use crate::utils::ValueExt;
7use serde_json::Value;
8
9fn flatten_recur<'a>(collect: &mut Vec<&'a Value>, a: &'a Value) {
10 collect.push(a);
11 a.iter().for_each(|a| flatten_recur(collect, a));
12}
13
14impl Path {
15 pub(crate) fn has_parent(&self) -> bool {
16 for op in &self.segments {
17 let result = match op {
18 Segment::Dot(_, RawSelector::Parent(_))
19 | Segment::Recursive(_, Some(RawSelector::Parent(_)))
20 | Segment::Bracket(_, BracketSelector::Parent(_)) => true,
21 Segment::Bracket(_, BracketSelector::Path(p)) => p.has_parent(),
22 Segment::Bracket(_, BracketSelector::Filter(f)) => f.has_parent(),
23 _ => false,
24 };
25
26 if result {
27 return true;
28 }
29 }
30 false
31 }
32
33 pub(crate) fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
34 for op in &self.segments {
35 op.eval(ctx);
36 }
37 if self.tilde.is_some() {
38 unimplemented!(
39 "Tilde at the top level isn't yet supported due to API design questions. Please \
40 raise an issue with your use case"
41 )
42 }
43 }
44}
45
46impl Segment {
47 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
48 match self {
49 Segment::Dot(_, op) => op.eval(ctx),
50 Segment::Bracket(_, op) => op.eval(ctx),
51 Segment::Recursive(_, op) => {
52 ctx.apply_matched(|_, a| {
53 let mut all = Vec::new();
54 flatten_recur(&mut all, a);
55 all
56 });
57 if let Some(inner) = op {
58 inner.eval(ctx);
59 }
60 }
61 }
62 }
63}
64
65impl RawSelector {
66 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
67 match self {
68 RawSelector::Wildcard(_) => ctx.apply_matched(|_, a| a.iter()),
69 RawSelector::Parent(_) => {
70 ctx.apply_matched(|ctx, a| ctx.parent_of(a));
71 }
72 RawSelector::Name(name) => ctx.apply_matched(|_, a| match a {
73 Value::Object(m) => m.get(name.as_str()),
74 _ => None,
75 }),
76 }
77 }
78}
79
80fn step_handle(val: i64) -> (bool, usize) {
81 if val < 0 {
82 (true, val.abs() as usize)
83 } else {
84 (false, val as usize)
85 }
86}
87
88fn idx_handle(val: i64, slice: &[Value]) -> Option<usize> {
89 if val < 0 {
90 slice.len().checked_sub(val.abs() as usize)
91 } else {
92 Some(val as usize)
93 }
94}
95
96fn range(slice: &[Value], start: usize, end: usize) -> &[Value] {
97 if start > end || start > slice.len() {
98 &[]
99 } else if end >= slice.len() {
100 &slice[start..]
101 } else {
102 &slice[start..end]
103 }
104}
105
106impl StepRange {
107 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
108 let start = self.start.as_ref().map_or(0, |i| i.as_int());
109 let end = self.end.as_ref().map_or(i64::MAX, |i| i.as_int());
110 let step = self.step.as_ref().map_or(1, |i| i.as_int().get());
111
112 let (rev, step) = step_handle(step);
113
114 ctx.apply_matched(|_, a| match a {
115 Value::Array(v) => {
116 let start = idx_handle(start, v).unwrap_or(0);
117 let end = idx_handle(end, v).unwrap_or(0);
118
119 let iter = range(v, start, end).iter();
120
121 if rev {
122 Either::Left(iter.rev().step_by(step))
123 } else {
124 Either::Right(iter.step_by(step))
125 }
126 }
127 _ => Either::Right([].iter().step_by(1)),
128 });
129 }
130}
131
132impl Range {
133 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
134 let start = self.start.as_ref().map_or(0, |i| i.as_int());
135 let end = self.end.as_ref().map_or(i64::MAX, |i| i.as_int());
136
137 ctx.apply_matched(|_, a| match a {
138 Value::Array(v) => {
139 let start = idx_handle(start, v).unwrap_or(0);
140 let end = idx_handle(end, v).unwrap_or(0);
141
142 range(v, start, end)
143 }
144 _ => &[],
145 });
146 }
147}
148
149impl UnionComponent {
150 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
151 match self {
152 UnionComponent::StepRange(step_range) => step_range.eval(ctx),
153 UnionComponent::Range(range) => range.eval(ctx),
154 UnionComponent::Parent(_) => {
155 ctx.apply_matched(|ctx, a| ctx.parent_of(a));
156 }
157 UnionComponent::Path(path) => {
158 path.eval_match(ctx);
159 }
160 UnionComponent::Filter(filter) => {
161 filter.eval(ctx);
162 }
163 UnionComponent::Literal(lit) => {
164 lit.eval(ctx);
165 }
166 }
167 }
168}
169
170impl BracketSelector {
171 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
172 match self {
173 BracketSelector::Union(components) => {
174 let mut new_matched = Vec::new();
175 let old_matched = ctx.get_matched().to_owned();
176 for component in components {
177 ctx.set_matched(old_matched.clone());
178 component.eval(ctx);
179 new_matched.extend(ctx.get_matched());
180 }
181 ctx.set_matched(new_matched);
182 }
183 BracketSelector::StepRange(step_range) => step_range.eval(ctx),
184 BracketSelector::Range(range) => range.eval(ctx),
185 BracketSelector::Wildcard(_) => ctx.apply_matched(|_, a| a.iter()),
186 BracketSelector::Parent(_) => {
187 ctx.apply_matched(|ctx, a| ctx.parent_of(a));
188 }
189 BracketSelector::Path(path) => {
190 path.eval_match(ctx);
191 }
192 BracketSelector::Filter(filter) => {
193 filter.eval(ctx);
194 }
195 BracketSelector::Literal(lit) => {
196 lit.eval(ctx);
197 }
198 }
199 }
200}
201
202impl BracketLit {
203 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
204 match self {
205 BracketLit::Int(i) => ctx.apply_matched(|_, a| match a {
206 Value::Array(v) => idx_handle(i.as_int(), v).and_then(|idx| v.get(idx)),
207 _ => None,
208 }),
209 BracketLit::String(s) => ctx.apply_matched(|_, a| match a {
210 Value::Object(m) => m.get(s.as_str()),
211 _ => None,
212 }),
213 }
214 }
215}
216
217impl SubPath {
218 pub(crate) fn has_parent(&self) -> bool {
219 for op in &self.segments {
220 let result = match op {
221 Segment::Dot(_, RawSelector::Parent(_))
222 | Segment::Recursive(_, Some(RawSelector::Parent(_)))
223 | Segment::Bracket(_, BracketSelector::Parent(_)) => true,
224 Segment::Bracket(_, BracketSelector::Path(p)) => p.has_parent(),
225 Segment::Bracket(_, BracketSelector::Filter(f)) => f.has_parent(),
226 _ => false,
227 };
228
229 if result {
230 return true;
231 }
232 }
233 false
234 }
235
236 fn eval_expr<'a>(&self, ctx: &EvalCtx<'a, '_>, a: &'a Value) -> Option<Cow<'a, Value>> {
237 let relative = match self.kind {
238 PathKind::Root(_) => false,
239 PathKind::Relative(_) => true,
240 };
241
242 let new_root = if relative { a } else { ctx.root() };
243
244 let mut new_ctx = EvalCtx::new_parents(new_root, ctx.all_parents());
245 for op in &self.segments {
246 op.eval(&mut new_ctx);
247 }
248 let matched = new_ctx.into_matched();
249
250 if matched.len() == 1 {
251 let matched = if self.tilde.is_some() {
252 Cow::Owned(ctx.idx_of(matched[0])?.into())
253 } else {
254 Cow::Borrowed(matched[0])
255 };
256
257 Some(matched)
258 } else {
259 None
260 }
261 }
262
263 fn eval_match(&self, ctx: &mut EvalCtx<'_, '_>) {
264 let relative = match self.kind {
265 PathKind::Root(_) => false,
266 PathKind::Relative(_) => true,
267 };
268
269 ctx.set_matched(ctx.apply_matched_ref(|ctx, a| {
270 let new_root = if relative { a } else { ctx.root() };
271
272 let mut new_ctx = EvalCtx::new_parents(new_root, ctx.all_parents());
273 for op in &self.segments {
274 op.eval(&mut new_ctx);
275 }
276
277 let id = self.tilde.is_some();
278
279 new_ctx
280 .into_matched()
281 .into_iter()
282 .map(move |a| {
283 if id {
284 Cow::Owned(ctx.idx_of(a).unwrap().into())
285 } else {
286 Cow::Borrowed(a)
287 }
288 })
289 .flat_map(move |mat| match a {
290 Value::Array(v) => {
291 let idx = match &*mat {
292 Value::Number(n) => idx_handle(n.as_i64().unwrap(), v),
293 _ => None,
294 };
295 idx.and_then(|i| v.get(i))
296 }
297 Value::Object(m) => {
298 let idx = match &*mat {
299 Value::String(s) => Some(s.to_string()),
300 Value::Number(n) => Some(n.to_string()),
301 _ => None,
302 };
303
304 idx.and_then(|i| m.get(&i))
305 }
306 _ => None,
307 })
308 }));
309 }
310}
311
312impl Filter {
313 fn has_parent(&self) -> bool {
314 self.inner.has_parent()
315 }
316
317 fn eval(&self, ctx: &mut EvalCtx<'_, '_>) {
318 ctx.set_matched(ctx.apply_matched_ref(|ctx, a| {
319 a.iter().filter(|&a| {
320 self.inner
321 .eval_expr(ctx, a)
322 .map_or(false, |c| c.as_bool() == Some(true))
323 })
324 }));
325 }
326}
327
328impl FilterExpr {
329 fn has_parent(&self) -> bool {
330 match self {
331 FilterExpr::Unary(_, inner) => inner.has_parent(),
332 FilterExpr::Binary(left, _, right) => left.has_parent() || right.has_parent(),
333 FilterExpr::Parens(_, inner) => inner.has_parent(),
334 FilterExpr::Path(p) => p.has_parent(),
335 _ => false,
336 }
337 }
338
339 fn eval_expr<'a>(&self, ctx: &EvalCtx<'a, '_>, val: &'a Value) -> Option<Cow<'a, Value>> {
340 match self {
341 FilterExpr::Unary(op, inner) => {
342 let inner = inner.eval_expr(ctx, val)?;
343
344 match op {
345 UnOp::Neg(_) => match &*inner {
346 Value::Number(n) => {
347 let out = n
348 .as_i64()
349 .map(|i| Value::from(-i))
350 .or_else(|| n.as_u64().map(|i| Value::from(-(i as i64))))
351 .or_else(|| n.as_f64().map(|f| Value::from(-f)));
352 Some(Cow::Owned(out.unwrap()))
353 }
354 _ => None,
355 },
356 UnOp::Not(_) => match &*inner {
357 Value::Bool(b) => Some(Cow::Owned(Value::from(!b))),
358 _ => None,
359 },
360 }
361 }
362 FilterExpr::Binary(lhs, op, rhs) => {
363 let lhs = lhs.eval_expr(ctx, val)?;
364 let rhs = rhs.eval_expr(ctx, val)?;
365
366 match op {
367 BinOp::And(_) => {
368 let lhs = lhs.as_bool()?;
369 let rhs = rhs.as_bool()?;
370 Some(Cow::Owned(Value::Bool(lhs && rhs)))
371 }
372 BinOp::Or(_) => {
373 let lhs = lhs.as_bool()?;
374 let rhs = rhs.as_bool()?;
375 Some(Cow::Owned(Value::Bool(lhs || rhs)))
376 }
377
378 BinOp::Eq(_) => Some(Cow::Owned(Value::Bool(lhs == rhs))),
379 BinOp::Le(_) => {
380 let lhs = lhs.as_f64()?;
381 let rhs = rhs.as_f64()?;
382
383 Some(Cow::Owned(Value::Bool(lhs <= rhs)))
384 }
385 BinOp::Lt(_) => {
386 let lhs = lhs.as_f64()?;
387 let rhs = rhs.as_f64()?;
388
389 Some(Cow::Owned(Value::Bool(lhs < rhs)))
390 }
391 BinOp::Gt(_) => {
392 let lhs = lhs.as_f64()?;
393 let rhs = rhs.as_f64()?;
394
395 Some(Cow::Owned(Value::Bool(lhs > rhs)))
396 }
397 BinOp::Ge(_) => {
398 let lhs = lhs.as_f64()?;
399 let rhs = rhs.as_f64()?;
400
401 Some(Cow::Owned(Value::Bool(lhs >= rhs)))
402 }
403
404 BinOp::Add(_) => {
405 if lhs.is_f64() && rhs.is_f64() {
406 let lhs = lhs.as_f64()?;
407 let rhs = rhs.as_f64()?;
408
409 Some(Cow::Owned(Value::from(lhs + rhs)))
410 } else if lhs.is_string() && rhs.is_string() {
411 let lhs = lhs.as_str()?;
412 let rhs = rhs.as_str()?;
413
414 Some(Cow::Owned(Value::String(format!("{lhs}{rhs}"))))
415 } else {
416 None
417 }
418 }
419 BinOp::Sub(_) => {
420 let lhs = lhs.as_f64()?;
421 let rhs = rhs.as_f64()?;
422
423 Some(Cow::Owned(Value::from(lhs - rhs)))
424 }
425 BinOp::Mul(_) => {
426 let lhs = lhs.as_f64()?;
427 let rhs = rhs.as_f64()?;
428
429 Some(Cow::Owned(Value::from(lhs * rhs)))
430 }
431 BinOp::Div(_) => {
432 let lhs = lhs.as_f64()?;
433 let rhs = rhs.as_f64()?;
434
435 Some(Cow::Owned(Value::from(lhs / rhs)))
436 }
437 BinOp::Rem(_) => {
438 let lhs = lhs.as_i64()?;
439 let rhs = rhs.as_i64()?;
440
441 Some(Cow::Owned(Value::from(lhs % rhs)))
442 }
443 }
444 }
445 FilterExpr::Path(path) => path.eval_expr(ctx, val),
446 FilterExpr::Lit(lit) => Some(Cow::Owned(match lit {
447 ExprLit::Int(i) => Value::from(i.as_int()),
448 ExprLit::String(s) => Value::from(s.as_str()),
449 ExprLit::Bool(b) => Value::from(b.as_bool()),
450 ExprLit::Null(_) => Value::Null,
451 })),
452 FilterExpr::Parens(_, inner) => inner.eval_expr(ctx, val),
453 }
454 }
455}