1use serde_json::{Number, Value};
23
24use crate::json_type::js_type_of;
25use super::ast::{LiteralValue, Node, PathSegment};
26
27enum Resolved {
32 Single(Value),
33 List(Vec<Value>),
34}
35
36pub struct Evaluator<'a> {
38 form_data: &'a Value,
39 current_path: &'a [String],
40 row_keys: &'a [usize],
41}
42
43pub fn relative_base(current_path: &[String], row_keys: &[usize], levels_up: usize) -> Vec<String> {
48 let mut base = current_path.to_vec();
49 for _ in 0..=levels_up {
50 if base.is_empty() {
51 break;
52 }
53 let leaving = if row_keys.contains(&(base.len() - 1)) {
54 2
55 } else {
56 1
57 };
58 base.truncate(base.len().saturating_sub(leaving));
59 }
60 base
61}
62
63impl<'a> Evaluator<'a> {
64 pub fn new(form_data: &'a Value, current_path: &'a [String], row_keys: &'a [usize]) -> Self {
68 Evaluator {
69 form_data,
70 current_path,
71 row_keys,
72 }
73 }
74
75 pub fn evaluate(&self, node: &Node) -> bool {
77 match node {
78 Node::Binary { .. } => self.evaluate_binary(node),
79 Node::Unary { .. } => self.evaluate_unary(node),
80 Node::In { .. } => self.evaluate_in(node),
81 Node::Group(expr) => self.evaluate(expr),
82 Node::Ternary { .. } => is_truthy(&self.evaluate_ternary(node)),
83 Node::Path { .. } | Node::Literal(_) => {
84 is_truthy(&self.resolve_value(node).into_single())
85 }
86 }
87 }
88
89 pub fn evaluate_value(&self, node: &Node) -> Value {
93 match node {
94 Node::Ternary { .. } => self.evaluate_ternary(node),
95 Node::Group(expr) => self.evaluate_value(expr),
96 _ => Value::Bool(self.evaluate(node)),
97 }
98 }
99
100 fn resolve_ternary_branch_value(&self, node: &Node) -> Value {
104 match node {
105 Node::Ternary { .. } => self.evaluate_ternary(node),
106 Node::Group(expr) => self.resolve_ternary_branch_value(expr),
107 Node::Literal(_) => self.resolve_value(node).into_single(),
108 Node::Path { .. } => self.resolve_value(node).into_single(),
109 Node::Binary { .. } => Value::Bool(self.evaluate_binary(node)),
110 Node::Unary { .. } => Value::Bool(self.evaluate_unary(node)),
111 Node::In { .. } => Value::Bool(self.evaluate_in(node)),
112 }
113 }
114
115 fn evaluate_ternary(&self, node: &Node) -> Value {
116 if let Node::Ternary {
117 condition,
118 true_value,
119 false_value,
120 } = node
121 {
122 if self.evaluate(condition) {
123 self.resolve_ternary_branch_value(true_value)
124 } else {
125 self.resolve_ternary_branch_value(false_value)
126 }
127 } else {
128 Value::Null
129 }
130 }
131
132 fn evaluate_binary(&self, node: &Node) -> bool {
133 let (operator, left, right) = match node {
134 Node::Binary {
135 operator,
136 left,
137 right,
138 } => (operator.as_str(), left, right),
139 _ => return false,
140 };
141
142 if operator == "&&" {
144 return self.evaluate(left) && self.evaluate(right);
145 }
146 if operator == "||" {
147 return self.evaluate(left) || self.evaluate(right);
148 }
149
150 let left_value = self.resolve_value(left);
151 let right_value = self.resolve_value(right).into_single();
152
153 match left_value {
155 Resolved::List(items) => items
156 .iter()
157 .any(|lv| compare_op(lv, &right_value, operator)),
158 Resolved::Single(lv) => compare_op(&lv, &right_value, operator),
159 }
160 }
161
162 fn evaluate_unary(&self, node: &Node) -> bool {
163 if let Node::Unary { operator, operand } = node {
164 if operator == "!" {
165 return !self.evaluate(operand);
166 }
167 }
168 false
169 }
170
171 fn evaluate_in(&self, node: &Node) -> bool {
172 let (negated, value, list) = match node {
173 Node::In {
174 negated,
175 value,
176 list,
177 } => (*negated, value, list),
178 _ => return false,
179 };
180
181 let probe = self.resolve_value(value);
182 let candidates: Vec<Value> = list
183 .iter()
184 .map(|n| self.resolve_value(n).into_single())
185 .collect();
186
187 match probe {
189 Resolved::List(items) => items.iter().any(|v| {
190 let included = in_list(v, &candidates);
191 if negated {
192 !included
193 } else {
194 included
195 }
196 }),
197 Resolved::Single(v) => {
198 let included = in_list(&v, &candidates);
199 if negated {
200 !included
201 } else {
202 included
203 }
204 }
205 }
206 }
207
208 fn resolve_value(&self, node: &Node) -> Resolved {
212 match node {
213 Node::Literal(lit) => Resolved::Single(literal_to_value(lit)),
214 Node::Path { .. } => self.resolve_path(node),
215 Node::Group(expr) => Resolved::Single(Value::Bool(self.evaluate(expr))),
216 _ => Resolved::Single(Value::Null),
217 }
218 }
219
220 fn resolve_path(&self, node: &Node) -> Resolved {
223 let mut resolved_path = self.resolve_path_segments(node);
224
225 if has_wildcard(&resolved_path) {
226 resolved_path = replace_wildcard_with_index(&resolved_path, self.current_path);
228
229 if has_wildcard(&resolved_path) {
230 let resolved = self.resolve_wildcard_path(&resolved_path);
232 return Resolved::List(resolved.into_iter().map(|(_, v)| v).collect());
233 }
234 }
235
236 Resolved::Single(self.get_value_by_path(&resolved_path))
237 }
238
239 fn resolve_path_segments(&self, node: &Node) -> Vec<String> {
241 let (relative, levels_up, segments) = match node {
242 Node::Path {
243 relative,
244 levels_up,
245 segments,
246 } => (*relative, *levels_up, segments),
247 _ => return Vec::new(),
248 };
249
250 let mut base_path: Vec<String> = if relative {
251 relative_base(self.current_path, self.row_keys, levels_up.max(0) as usize)
252 } else {
253 Vec::new()
254 };
255
256 for seg in segments {
257 match seg {
258 PathSegment::Identifier(v) => base_path.push(v.clone()),
259 PathSegment::Index(i) => base_path.push(i.to_string()),
260 PathSegment::Wildcard => base_path.push("*".to_string()),
261 }
262 }
263
264 base_path
265 }
266
267 fn get_value_by_path(&self, path: &[String]) -> Value {
270 let mut current = self.form_data;
271
272 for segment in path {
273 match current {
274 Value::Object(map) => match map.get(segment) {
275 Some(v) => current = v,
276 None => return Value::Null,
277 },
278 Value::Array(arr) => match segment.parse::<usize>() {
279 Ok(idx) => match arr.get(idx) {
280 Some(v) => current = v,
281 None => return Value::Null,
282 },
283 Err(_) => return Value::Null,
284 },
285 Value::Null => return Value::Null,
286 _ => return Value::Null,
287 }
288 }
289
290 current.clone()
291 }
292
293 fn resolve_wildcard_path(&self, path: &[String]) -> Vec<(Vec<String>, Value)> {
297 let wildcard_index = index_of_wildcard(path);
298 if wildcard_index.is_none() {
299 return vec![(path.to_vec(), self.get_value_by_path(path))];
300 }
301 let wildcard_index = wildcard_index.unwrap();
302
303 let array_path = &path[..wildcard_index];
304 let remaining_path = &path[wildcard_index + 1..];
305 let array_data = self.get_value_by_path(array_path);
306
307 match &array_data {
308 Value::Object(_) => {
310 let concrete: Vec<String> = array_path
311 .iter()
312 .cloned()
313 .chain(remaining_path.iter().cloned())
314 .collect();
315 self.resolve_wildcard_path(&concrete)
316 }
317 Value::Array(arr) => {
318 let mut results = Vec::new();
319 for i in 0..arr.len() {
320 let concrete: Vec<String> = array_path
321 .iter()
322 .cloned()
323 .chain(std::iter::once(i.to_string()))
324 .chain(remaining_path.iter().cloned())
325 .collect();
326 results.extend(self.resolve_wildcard_path(&concrete));
327 }
328 results
329 }
330 _ => Vec::new(),
331 }
332 }
333}
334
335impl Resolved {
336 fn into_single(self) -> Value {
337 match self {
338 Resolved::Single(v) => v,
339 Resolved::List(items) => Value::Array(items),
343 }
344 }
345}
346
347fn replace_wildcard_with_index(path: &[String], current_path: &[String]) -> Vec<String> {
351 let array_indices: Vec<String> = current_path
352 .iter()
353 .filter(|s| is_numeric_segment(s))
354 .cloned()
355 .collect();
356
357 let mut result = Vec::with_capacity(path.len());
358 let mut cursor = 0usize;
359 for segment in path {
360 if segment == "*" {
361 if cursor < array_indices.len() {
362 result.push(array_indices[cursor].clone());
363 cursor += 1;
364 } else {
365 result.push("*".to_string());
366 }
367 } else {
368 result.push(segment.clone());
369 }
370 }
371
372 result
373}
374
375fn has_wildcard(path: &[String]) -> bool {
376 path.iter().any(|s| s == "*")
377}
378
379fn index_of_wildcard(path: &[String]) -> Option<usize> {
380 path.iter().position(|s| s == "*")
381}
382
383fn is_numeric_segment(segment: &str) -> bool {
384 !segment.is_empty() && segment.bytes().all(|b| b.is_ascii_digit())
385}
386
387fn literal_to_value(lit: &LiteralValue) -> Value {
388 match lit {
389 LiteralValue::Str(s) => Value::String(s.clone()),
390 LiteralValue::Int(n) => Value::from(*n),
391 LiteralValue::Float(f) => Value::from(*f),
392 LiteralValue::Bool(b) => Value::Bool(*b),
393 LiteralValue::Null => Value::Null,
394 }
395}
396
397fn in_list(value: &Value, list: &[Value]) -> bool {
398 list.iter().any(|item| loose_equals(value, item))
399}
400
401fn compare_op(left: &Value, right: &Value, operator: &str) -> bool {
402 match operator {
403 "==" => loose_equals(left, right),
404 "!=" => !loose_equals(left, right),
405 ">" => coerce_number(left) > coerce_number(right),
406 ">=" => coerce_number(left) >= coerce_number(right),
407 "<" => coerce_number(left) < coerce_number(right),
408 "<=" => coerce_number(left) <= coerce_number(right),
409 _ => false,
410 }
411}
412
413pub fn is_truthy(value: &Value) -> bool {
418 match value {
419 Value::Null => false,
420 Value::Bool(b) => *b,
421 Value::Number(n) => {
422 if let Some(f) = n.as_f64() {
423 f != 0.0
424 } else {
425 true
426 }
427 }
428 Value::String(s) => !s.is_empty(),
429 Value::Array(_) => true,
431 Value::Object(_) => true,
432 }
433}
434
435fn loose_equals(a: &Value, b: &Value) -> bool {
439 if js_type_of(a) == js_type_of(b) {
440 return json_equals(a, b);
441 }
442
443 if a.is_null() {
444 return b.is_null();
445 }
446 if b.is_null() {
447 return false;
448 }
449
450 if let (Some(an), Some(bn)) = (js_number(a), js_number(b)) {
451 return an == bn;
452 }
453
454 to_string(a) == to_string(b)
455}
456
457pub(crate) fn numbers_equal(x: &Number, y: &Number) -> bool {
459 match (x.as_f64(), y.as_f64()) {
460 (Some(xf), Some(yf)) => xf == yf,
461 _ => x == y,
462 }
463}
464
465fn json_equals(a: &Value, b: &Value) -> bool {
470 match (a, b) {
471 (Value::Number(x), Value::Number(y)) => numbers_equal(x, y),
472 (Value::Array(x), Value::Array(y)) => {
473 x.len() == y.len()
474 && x.iter()
475 .zip(y)
476 .all(|(item, other)| json_equals(item, other))
477 }
478 (Value::Object(x), Value::Object(y)) => {
479 x.len() == y.len()
480 && x.iter()
481 .all(|(key, value)| y.get(key).is_some_and(|other| json_equals(value, other)))
482 }
483 _ => a == b,
484 }
485}
486
487#[allow(clippy::disallowed_methods, reason = "a string that does not parse is NaN")]
491fn js_number(value: &Value) -> Option<f64> {
492 match value {
493 Value::Number(n) => n.as_f64(),
494 Value::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
495 Value::String(s) => {
496 let trimmed = s.trim();
497 if trimmed.is_empty() {
498 return Some(0.0); }
500 trimmed.parse::<f64>().ok()
501 }
502 _ => None,
503 }
504}
505
506fn coerce_number(value: &Value) -> f64 {
509 match value {
510 Value::Number(n) => n.as_f64().unwrap_or(0.0),
511 Value::String(s) => parse_float_prefix(s).unwrap_or(0.0),
512 Value::Bool(true) => 1.0,
513 Value::Bool(false) => 0.0,
514 _ => 0.0,
515 }
516}
517
518fn parse_float_prefix(value: &str) -> Option<f64> {
522 let bytes = value.as_bytes();
523 let mut i = 0usize;
524
525 while i < bytes.len() && matches!(bytes[i], b' ' | b'\t' | b'\n' | b'\r') {
527 i += 1;
528 }
529
530 let start = i;
531
532 if i < bytes.len() && (bytes[i] == b'+' || bytes[i] == b'-') {
533 i += 1;
534 }
535
536 let mut has_int_digits = false;
537 while i < bytes.len() && bytes[i].is_ascii_digit() {
538 i += 1;
539 has_int_digits = true;
540 }
541
542 let mut has_frac_digits = false;
543 if i < bytes.len() && bytes[i] == b'.' {
544 i += 1;
545 while i < bytes.len() && bytes[i].is_ascii_digit() {
546 i += 1;
547 has_frac_digits = true;
548 }
549 }
550
551 if !has_int_digits && !has_frac_digits {
552 return None;
553 }
554
555 if i < bytes.len() && (bytes[i] == b'e' || bytes[i] == b'E') {
558 let exp_marker = i;
559 let mut j = i + 1;
560 if j < bytes.len() && (bytes[j] == b'+' || bytes[j] == b'-') {
561 j += 1;
562 }
563 let mut has_exp_digits = false;
564 while j < bytes.len() && bytes[j].is_ascii_digit() {
565 j += 1;
566 has_exp_digits = true;
567 }
568 if has_exp_digits {
569 i = j;
570 } else {
571 i = exp_marker;
572 }
573 }
574
575 Some(
578 value[start..i]
579 .parse::<f64>()
580 .expect("a numeric prefix with a digit parses as f64"),
581 )
582}
583
584fn to_string(value: &Value) -> String {
587 match value {
588 Value::Null => String::new(),
589 Value::String(s) => s.clone(),
590 Value::Bool(b) => {
591 if *b {
592 "true".to_string()
593 } else {
594 "false".to_string()
595 }
596 }
597 Value::Number(n) => {
598 if let Some(i) = n.as_i64() {
599 i.to_string()
600 } else if let Some(u) = n.as_u64() {
601 u.to_string()
602 } else if let Some(f) = n.as_f64() {
603 if f.is_finite() && f == f.floor() {
604 (f as i64).to_string()
605 } else {
606 f.to_string()
607 }
608 } else {
609 String::new()
610 }
611 }
612 _ => String::new(),
613 }
614}