1use std::sync::Arc;
40use indexmap::IndexMap;
41use smallvec::SmallVec;
42
43use super::ast::*;
44
45pub mod value;
46pub mod util;
47pub mod methods;
48pub mod builtins;
49mod func_strings;
50mod func_arrays;
51mod func_objects;
52mod func_paths;
53mod func_aggregates;
54mod func_csv;
55mod func_search;
56
57pub use value::Val;
58pub use methods::{Method, MethodRegistry};
59use util::*;
60
61#[derive(Debug, Clone)]
64pub struct EvalError(pub String);
65
66impl std::fmt::Display for EvalError {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 write!(f, "eval error: {}", self.0)
69 }
70}
71impl std::error::Error for EvalError {}
72
73macro_rules! err {
74 ($($t:tt)*) => { Err(EvalError(format!($($t)*))) };
75}
76
77pub struct LamFrame {
85 prev_current: Val,
86 prev_var: LamVarPrev,
87}
88
89enum LamVarPrev {
90 None,
91 Pushed,
92 Replaced(usize, Val),
93}
94
95#[derive(Clone)]
96pub struct Env {
97 vars: SmallVec<[(Arc<str>, Val); 4]>,
98 pub root: Val,
99 pub current: Val,
100 registry: Arc<MethodRegistry>,
101 pub(crate) raw_bytes: Option<Arc<[u8]>>,
105}
106
107impl Env {
108 fn new(root: Val) -> Self {
109 Self {
110 vars: SmallVec::new(),
111 root: root.clone(),
112 current: root,
113 registry: Arc::new(MethodRegistry::new()),
114 raw_bytes: None,
115 }
116 }
117
118 pub fn new_with_registry(root: Val, registry: Arc<MethodRegistry>) -> Self {
119 Self { vars: SmallVec::new(), root: root.clone(), current: root, registry, raw_bytes: None }
120 }
121
122 pub fn new_with_raw(
125 root: Val,
126 registry: Arc<MethodRegistry>,
127 raw_bytes: Arc<[u8]>,
128 ) -> Self {
129 Self {
130 vars: SmallVec::new(),
131 root: root.clone(),
132 current: root,
133 registry,
134 raw_bytes: Some(raw_bytes),
135 }
136 }
137
138 #[inline]
139 pub(super) fn registry_ref(&self) -> &MethodRegistry { &self.registry }
140
141 #[inline]
142 pub fn with_current(&self, current: Val) -> Self {
143 Self {
144 vars: self.vars.clone(),
145 root: self.root.clone(),
146 current,
147 registry: self.registry.clone(),
148 raw_bytes: self.raw_bytes.clone(),
149 }
150 }
151
152 #[inline]
156 pub fn swap_current(&mut self, new: Val) -> Val {
157 std::mem::replace(&mut self.current, new)
158 }
159
160 #[inline]
161 pub fn restore_current(&mut self, old: Val) {
162 self.current = old;
163 }
164
165 #[inline]
166 pub fn get_var(&self, name: &str) -> Option<&Val> {
167 self.vars.iter().rev().find(|(k, _)| k.as_ref() == name).map(|(_, v)| v)
168 }
169
170 #[inline]
171 pub fn has_var(&self, name: &str) -> bool {
172 self.vars.iter().any(|(k, _)| k.as_ref() == name)
173 }
174
175 pub fn with_var(&self, name: &str, val: Val) -> Self {
176 let mut vars = self.vars.clone();
177 if let Some(pos) = vars.iter().position(|(k, _)| k.as_ref() == name) {
178 vars[pos].1 = val;
179 } else {
180 vars.push((Arc::from(name), val));
181 }
182 Self { vars, root: self.root.clone(), current: self.current.clone(), registry: self.registry.clone(), raw_bytes: self.raw_bytes.clone() }
183 }
184
185 #[inline]
190 pub fn push_lam(&mut self, name: Option<&str>, val: Val) -> LamFrame {
191 let prev_current = std::mem::replace(&mut self.current, val.clone());
192 let prev_var = match name {
193 None => LamVarPrev::None,
194 Some(n) => {
195 if let Some(pos) = self.vars.iter().position(|(k, _)| k.as_ref() == n) {
196 let prev = std::mem::replace(&mut self.vars[pos].1, val);
197 LamVarPrev::Replaced(pos, prev)
198 } else {
199 self.vars.push((Arc::from(n), val));
200 LamVarPrev::Pushed
201 }
202 }
203 };
204 LamFrame { prev_current, prev_var }
205 }
206
207 #[inline]
208 pub fn pop_lam(&mut self, frame: LamFrame) {
209 self.current = frame.prev_current;
210 match frame.prev_var {
211 LamVarPrev::None => {}
212 LamVarPrev::Pushed => { self.vars.pop(); }
213 LamVarPrev::Replaced(pos, prev) => { self.vars[pos].1 = prev; }
214 }
215 }
216
217}
218
219pub fn evaluate(expr: &Expr, root: &serde_json::Value) -> Result<serde_json::Value, EvalError> {
222 let val = Val::from(root);
223 Ok(eval(expr, &Env::new(val))?.into())
224}
225
226pub fn evaluate_with(
227 expr: &Expr,
228 root: &serde_json::Value,
229 registry: Arc<MethodRegistry>,
230) -> Result<serde_json::Value, EvalError> {
231 let val = Val::from(root);
232 Ok(eval(expr, &Env::new_with_registry(val, registry))?.into())
233}
234
235pub fn evaluate_with_raw(
238 expr: &Expr,
239 root: &serde_json::Value,
240 registry: Arc<MethodRegistry>,
241 raw_bytes: Arc<[u8]>,
242) -> Result<serde_json::Value, EvalError> {
243 let val = Val::from(root);
244 Ok(eval(expr, &Env::new_with_raw(val, registry, raw_bytes))?.into())
245}
246
247pub(super) fn eval(expr: &Expr, env: &Env) -> Result<Val, EvalError> {
250 match expr {
251 Expr::Null => Ok(Val::Null),
252 Expr::Bool(b) => Ok(Val::Bool(*b)),
253 Expr::Int(n) => Ok(Val::Int(*n)),
254 Expr::Float(f) => Ok(Val::Float(*f)),
255 Expr::Str(s) => Ok(Val::Str(Arc::from(s.as_str()))),
256
257 Expr::FString(parts) => eval_fstring(parts, env),
258
259 Expr::Root => Ok(env.root.clone()),
260 Expr::Current => Ok(env.current.clone()),
261
262 Expr::Ident(name) => {
263 if let Some(v) = env.get_var(name) { return Ok(v.clone()); }
264 Ok(env.current.get_field(name))
265 }
266
267 Expr::Chain(base, steps) => {
268 if let (Expr::Root, Some(Step::Method(name, args)), Some(bytes))
272 = (&**base, steps.first(), env.raw_bytes.as_ref())
273 {
274 if name == "deep_find" && !args.is_empty() {
275 if let Some(conjuncts) = canonical_field_eq_literals(args) {
276 let spans = if conjuncts.len() == 1 {
277 super::scan::find_enclosing_objects_eq(
278 bytes, &conjuncts[0].0, &conjuncts[0].1,
279 )
280 } else {
281 super::scan::find_enclosing_objects_eq_multi(
282 bytes, &conjuncts,
283 )
284 };
285 let mut vals: Vec<Val> = Vec::with_capacity(spans.len());
286 for s in &spans {
287 if let Ok(v) = serde_json::from_slice::<serde_json::Value>(
288 &bytes[s.start..s.end]
289 ) {
290 vals.push(Val::from(&v));
291 }
292 }
293 let mut val = Val::arr(vals);
294 for step in &steps[1..] { val = eval_step(val, step, env)?; }
295 return Ok(val);
296 }
297 if args.len() == 1 {
301 let e = match &args[0] { Arg::Pos(e) | Arg::Named(_, e) => e };
302 if let Some((field, op, thresh)) = canonical_field_cmp_literal(e) {
303 let spans = super::scan::find_enclosing_objects_cmp(
304 bytes, &field, op, thresh,
305 );
306 let mut vals: Vec<Val> = Vec::with_capacity(spans.len());
307 for s in &spans {
308 if let Ok(v) = serde_json::from_slice::<serde_json::Value>(
309 &bytes[s.start..s.end]
310 ) {
311 vals.push(Val::from(&v));
312 }
313 }
314 let mut val = Val::arr(vals);
315 for step in &steps[1..] { val = eval_step(val, step, env)?; }
316 return Ok(val);
317 }
318 }
319 if let Some(conjuncts) = canonical_field_mixed_predicates(args) {
324 let spans = super::scan::find_enclosing_objects_mixed(
325 bytes, &conjuncts,
326 );
327 let mut vals: Vec<Val> = Vec::with_capacity(spans.len());
328 for s in &spans {
329 if let Ok(v) = serde_json::from_slice::<serde_json::Value>(
330 &bytes[s.start..s.end]
331 ) {
332 vals.push(Val::from(&v));
333 }
334 }
335 let mut val = Val::arr(vals);
336 for step in &steps[1..] { val = eval_step(val, step, env)?; }
337 return Ok(val);
338 }
339 }
340 }
341 if let (Expr::Root, Some(Step::Descendant(name)), Some(bytes))
345 = (&**base, steps.first(), env.raw_bytes.as_ref())
346 {
347 let (mut val, consumed) = byte_chain_eval(bytes, name, steps);
348 for step in &steps[consumed..] { val = eval_step(val, step, env)?; }
349 return Ok(val);
350 }
351 let mut val = eval(base, env)?;
352 for step in steps { val = eval_step(val, step, env)?; }
353 Ok(val)
354 }
355
356 Expr::UnaryNeg(e) => match eval(e, env)? {
357 Val::Int(n) => Ok(Val::Int(-n)),
358 Val::Float(f) => Ok(Val::Float(-f)),
359 _ => err!("unary minus requires a number"),
360 },
361
362 Expr::Not(e) => Ok(Val::Bool(!is_truthy(&eval(e, env)?))),
363 Expr::BinOp(l, op, r) => eval_binop(l, *op, r, env),
364
365 Expr::Coalesce(lhs, rhs) => {
366 let v = eval(lhs, env)?;
367 if !v.is_null() { Ok(v) } else { eval(rhs, env) }
368 }
369
370 Expr::Kind { expr, ty, negate } => {
371 let v = eval(expr, env)?;
372 let m = kind_matches(&v, *ty);
373 Ok(Val::Bool(if *negate { !m } else { m }))
374 }
375
376 Expr::Object(fields) => eval_object(fields, env),
377
378 Expr::Array(elems) => {
379 let mut out = Vec::new();
380 for elem in elems {
381 match elem {
382 ArrayElem::Expr(e) => out.push(eval(e, env)?),
383 ArrayElem::Spread(e) => match eval(e, env)? {
384 Val::Arr(a) => {
385 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
386 out.extend(items);
387 }
388 Val::IntVec(a) => out.extend(a.iter().map(|n| Val::Int(*n))),
389 Val::FloatVec(a) => out.extend(a.iter().map(|f| Val::Float(*f))),
390 v => out.push(v),
391 },
392 }
393 }
394 Ok(Val::arr(out))
395 }
396
397 Expr::Pipeline { base, steps } => eval_pipeline(base, steps, env),
398
399 Expr::ListComp { expr, vars, iter, cond } => {
400 let items = eval_iter(iter, env)?;
401 let mut out = Vec::new();
402 let mut env_mut = env.clone();
403 for item in items {
404 let frames = bind_vars_mut(&mut env_mut, vars, item);
405 let keep = match cond {
406 Some(c) => match eval(c, &env_mut) {
407 Ok(v) => is_truthy(&v),
408 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
409 },
410 None => true,
411 };
412 if keep {
413 match eval(expr, &env_mut) {
414 Ok(v) => out.push(v),
415 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
416 }
417 }
418 unbind_vars_mut(&mut env_mut, frames);
419 }
420 Ok(Val::arr(out))
421 }
422
423 Expr::DictComp { key, val, vars, iter, cond } => {
424 let items = eval_iter(iter, env)?;
425 let mut map: IndexMap<Arc<str>, Val> = IndexMap::with_capacity(items.len());
426 let mut env_mut = env.clone();
427 for item in items {
428 let frames = bind_vars_mut(&mut env_mut, vars, item);
429 let keep = match cond {
430 Some(c) => match eval(c, &env_mut) {
431 Ok(v) => is_truthy(&v),
432 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
433 },
434 None => true,
435 };
436 if keep {
437 let k: Arc<str> = match eval(key, &env_mut) {
438 Ok(Val::Str(s)) => s,
439 Ok(other) => Arc::<str>::from(val_to_key(&other)),
440 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
441 };
442 match eval(val, &env_mut) {
443 Ok(v) => { map.insert(k, v); }
444 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
445 }
446 }
447 unbind_vars_mut(&mut env_mut, frames);
448 }
449 Ok(Val::obj(map))
450 }
451
452 Expr::SetComp { expr, vars, iter, cond } | Expr::GenComp { expr, vars, iter, cond } => {
453 let items = eval_iter(iter, env)?;
454 let mut seen: std::collections::HashSet<String> =
455 std::collections::HashSet::with_capacity(items.len());
456 let mut out = Vec::with_capacity(items.len());
457 let mut env_mut = env.clone();
458 for item in items {
459 let frames = bind_vars_mut(&mut env_mut, vars, item);
460 let keep = match cond {
461 Some(c) => match eval(c, &env_mut) {
462 Ok(v) => is_truthy(&v),
463 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
464 },
465 None => true,
466 };
467 if keep {
468 match eval(expr, &env_mut) {
469 Ok(v) => if seen.insert(val_to_key(&v)) { out.push(v); },
470 Err(e) => { unbind_vars_mut(&mut env_mut, frames); return Err(e); }
471 }
472 }
473 unbind_vars_mut(&mut env_mut, frames);
474 }
475 Ok(Val::arr(out))
476 }
477
478 Expr::Lambda { .. } => err!("lambda cannot be used as standalone value"),
479
480 Expr::Let { name, init, body } => {
481 let v = eval(init, env)?;
482 eval(body, &env.with_var(name, v))
483 }
484
485 Expr::IfElse { cond, then_, else_ } => {
486 if is_truthy(&eval(cond, env)?) { eval(then_, env) } else { eval(else_, env) }
487 }
488
489 Expr::GlobalCall { name, args } => eval_global(name, args, env),
490
491 Expr::Cast { expr, ty } => {
492 let v = eval(expr, env)?;
493 cast_val(&v, *ty)
494 }
495
496 Expr::Patch { root, ops } => eval_patch(root, ops, env),
497 Expr::DeleteMark =>
498 err!("DELETE can only appear as a patch-field value"),
499 }
500}
501
502use super::ast::{PatchOp, PathStep};
505
506enum PatchResult { Replace(Val), Delete }
507
508fn eval_patch(root: &Expr, ops: &[PatchOp], env: &Env) -> Result<Val, EvalError> {
509 let mut doc = eval(root, env)?;
510 for op in ops {
511 if let Some(c) = &op.cond {
512 let cenv = env.with_current(doc.clone());
513 if !is_truthy(&eval(c, &cenv)?) { continue; }
514 }
515 match apply_patch_step(doc, &op.path, 0, &op.val, env)? {
516 PatchResult::Replace(v) => doc = v,
517 PatchResult::Delete => doc = Val::Null,
518 }
519 }
520 Ok(doc)
521}
522
523fn apply_patch_step(
524 v: Val,
525 path: &[PathStep],
526 i: usize,
527 val_expr: &Expr,
528 env: &Env,
529) -> Result<PatchResult, EvalError> {
530 if i == path.len() {
531 if matches!(val_expr, Expr::DeleteMark) {
532 return Ok(PatchResult::Delete);
533 }
534 let nv = eval(val_expr, &env.with_current(v))?;
535 return Ok(PatchResult::Replace(nv));
536 }
537 match &path[i] {
538 PathStep::Field(name) => {
539 let mut m = v.into_map().unwrap_or_default();
543 let existing = if let Some(slot) = m.get_mut(name.as_str()) {
544 std::mem::replace(slot, Val::Null)
545 } else { Val::Null };
546 let child = apply_patch_step(existing, path, i+1, val_expr, env)?;
547 match child {
548 PatchResult::Delete => { m.shift_remove(name.as_str()); }
549 PatchResult::Replace(nv) => { m.insert(Arc::from(name.as_str()), nv); }
550 }
551 Ok(PatchResult::Replace(Val::obj(m)))
552 }
553 PathStep::Index(idx) => {
554 let mut a = v.into_vec().unwrap_or_default();
555 let resolved = resolve_idx(*idx, a.len() as i64);
556 let existing = if resolved < a.len() {
557 std::mem::replace(&mut a[resolved], Val::Null)
558 } else { Val::Null };
559 let child = apply_patch_step(existing, path, i+1, val_expr, env)?;
560 match child {
561 PatchResult::Delete => {
562 if resolved < a.len() { a.remove(resolved); }
563 }
564 PatchResult::Replace(nv) => {
565 if resolved < a.len() { a[resolved] = nv; }
566 }
567 }
568 Ok(PatchResult::Replace(Val::arr(a)))
569 }
570 PathStep::DynIndex(expr) => {
571 let idx_val = eval(expr, env)?;
572 let idx = idx_val.as_i64().ok_or_else(|| {
573 EvalError(format!("patch dyn-index: expected integer, got {}", idx_val.type_name()))
574 })?;
575 let mut a = v.into_vec().unwrap_or_default();
576 let resolved = resolve_idx(idx, a.len() as i64);
577 let existing = if resolved < a.len() {
578 std::mem::replace(&mut a[resolved], Val::Null)
579 } else { Val::Null };
580 let child = apply_patch_step(existing, path, i+1, val_expr, env)?;
581 match child {
582 PatchResult::Delete => {
583 if resolved < a.len() { a.remove(resolved); }
584 }
585 PatchResult::Replace(nv) => {
586 if resolved < a.len() { a[resolved] = nv; }
587 }
588 }
589 Ok(PatchResult::Replace(Val::arr(a)))
590 }
591 PathStep::Wildcard => {
592 let mut arr = v.into_vec().ok_or_else(|| EvalError("patch [*]: expected array".into()))?;
593 let mut write_idx = 0usize;
597 for read_idx in 0..arr.len() {
598 let item = std::mem::replace(&mut arr[read_idx], Val::Null);
599 match apply_patch_step(item, path, i+1, val_expr, env)? {
600 PatchResult::Delete => {}
601 PatchResult::Replace(nv) => {
602 arr[write_idx] = nv;
603 write_idx += 1;
604 }
605 }
606 }
607 arr.truncate(write_idx);
608 Ok(PatchResult::Replace(Val::arr(arr)))
609 }
610 PathStep::WildcardFilter(pred) => {
611 let mut arr = v.into_vec().ok_or_else(|| EvalError("patch [* if]: expected array".into()))?;
612 let mut env_mut = env.clone();
613 let mut write_idx = 0usize;
614 for read_idx in 0..arr.len() {
615 let item = std::mem::replace(&mut arr[read_idx], Val::Null);
616 let frame = env_mut.push_lam(None, item.clone());
617 let include = match eval(pred, &env_mut) {
618 Ok(v) => is_truthy(&v),
619 Err(e) => { env_mut.pop_lam(frame); return Err(e); }
620 };
621 env_mut.pop_lam(frame);
622 if include {
623 match apply_patch_step(item, path, i+1, val_expr, env)? {
624 PatchResult::Delete => {}
625 PatchResult::Replace(nv) => {
626 arr[write_idx] = nv;
627 write_idx += 1;
628 }
629 }
630 } else {
631 arr[write_idx] = item;
632 write_idx += 1;
633 }
634 }
635 arr.truncate(write_idx);
636 Ok(PatchResult::Replace(Val::arr(arr)))
637 }
638 PathStep::Descendant(name) => {
639 let v = descend_apply_patch(v, name, path, i, val_expr, env)?;
640 Ok(PatchResult::Replace(v))
641 }
642 }
643}
644
645fn descend_apply_patch(
651 v: Val,
652 name: &str,
653 path: &[PathStep],
654 i: usize,
655 val_expr: &Expr,
656 env: &Env,
657) -> Result<Val, EvalError> {
658 match v {
659 Val::Obj(m) => {
660 let mut map = Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone());
661 let n = map.len();
665 for idx in 0..n {
666 let child = if let Some((_, v)) = map.get_index_mut(idx) {
667 std::mem::replace(v, Val::Null)
668 } else { continue };
669 let replaced = descend_apply_patch(child, name, path, i, val_expr, env)?;
670 if let Some((_, slot)) = map.get_index_mut(idx) { *slot = replaced; }
671 }
672 if map.contains_key(name) {
674 let existing = map.get(name).cloned().unwrap_or(Val::Null);
675 let r = apply_patch_step(existing, path, i + 1, val_expr, env)?;
676 match r {
677 PatchResult::Delete => { map.shift_remove(name); }
678 PatchResult::Replace(nv) => { map.insert(Arc::from(name), nv); }
679 }
680 }
681 Ok(Val::obj(map))
682 }
683 Val::Arr(a) => {
684 let mut vec = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
685 for slot in vec.iter_mut() {
686 let old = std::mem::replace(slot, Val::Null);
687 *slot = descend_apply_patch(old, name, path, i, val_expr, env)?;
688 }
689 Ok(Val::arr(vec))
690 }
691 other => Ok(other),
692 }
693}
694
695fn cast_val(v: &Val, ty: super::ast::CastType) -> Result<Val, EvalError> {
700 use super::ast::CastType;
701 match ty {
702 CastType::Str => Ok(Val::Str(Arc::from(match v {
703 Val::Null => "null".to_string(),
704 Val::Bool(b) => b.to_string(),
705 Val::Int(n) => n.to_string(),
706 Val::Float(f) => f.to_string(),
707 Val::Str(s) => s.to_string(),
708 other => super::eval::util::val_to_string(other),
709 }.as_str()))),
710 CastType::Bool => Ok(Val::Bool(match v {
711 Val::Null => false,
712 Val::Bool(b) => *b,
713 Val::Int(n) => *n != 0,
714 Val::Float(f) => *f != 0.0,
715 Val::Str(s) => !s.is_empty(),
716 Val::StrSlice(r) => !r.is_empty(),
717 Val::Arr(a) => !a.is_empty(),
718 Val::IntVec(a) => !a.is_empty(),
719 Val::FloatVec(a) => !a.is_empty(),
720 Val::StrVec(a) => !a.is_empty(),
721 Val::StrSliceVec(a) => !a.is_empty(),
722 Val::ObjVec(d) => !d.rows.is_empty(),
723 Val::Obj(o) => !o.is_empty(),
724 Val::ObjSmall(p) => !p.is_empty(),
725 })),
726 CastType::Number | CastType::Float => match v {
727 Val::Int(n) => Ok(Val::Float(*n as f64)),
728 Val::Float(_) => Ok(v.clone()),
729 Val::Str(s) => s.parse::<f64>().map(Val::Float)
730 .map_err(|e| EvalError(format!("as float: {}", e))),
731 Val::Bool(b) => Ok(Val::Float(if *b { 1.0 } else { 0.0 })),
732 Val::Null => Ok(Val::Float(0.0)),
733 _ => err!("as float: cannot convert"),
734 },
735 CastType::Int => match v {
736 Val::Int(_) => Ok(v.clone()),
737 Val::Float(f) => Ok(Val::Int(*f as i64)),
738 Val::Str(s) => s.parse::<i64>().map(Val::Int)
739 .or_else(|_| s.parse::<f64>().map(|f| Val::Int(f as i64)))
740 .map_err(|e| EvalError(format!("as int: {}", e))),
741 Val::Bool(b) => Ok(Val::Int(if *b { 1 } else { 0 })),
742 Val::Null => Ok(Val::Int(0)),
743 _ => err!("as int: cannot convert"),
744 },
745 CastType::Array => match v {
746 Val::Arr(_) => Ok(v.clone()),
747 Val::Null => Ok(Val::arr(Vec::new())),
748 other => Ok(Val::arr(vec![other.clone()])),
749 },
750 CastType::Object => match v {
751 Val::Obj(_) => Ok(v.clone()),
752 _ => err!("as object: cannot convert non-object"),
753 },
754 CastType::Null => Ok(Val::Null),
755 }
756}
757
758fn eval_pipeline(base: &Expr, steps: &[PipeStep], env: &Env) -> Result<Val, EvalError> {
761 let mut current = eval(base, env)?;
762 let mut env = env.clone();
763 for step in steps {
764 match step {
765 PipeStep::Forward(rhs) => current = eval_pipe(current, rhs, &env)?,
766 PipeStep::Bind(target) => env = apply_bind(target, ¤t, env)?,
767 }
768 }
769 Ok(current)
770}
771
772fn apply_bind(target: &BindTarget, val: &Val, env: Env) -> Result<Env, EvalError> {
773 match target {
774 BindTarget::Name(name) => Ok(env.with_var(name, val.clone())),
775 BindTarget::Obj { fields, rest } => {
776 let obj = val.as_object()
777 .ok_or_else(|| EvalError("bind destructure: expected object".into()))?;
778 let mut e = env;
779 for f in fields {
780 e = e.with_var(f, obj.get(f.as_str()).cloned().unwrap_or(Val::Null));
781 }
782 if let Some(rest_name) = rest {
783 let mut remainder: IndexMap<Arc<str>, Val> = IndexMap::new();
784 for (k, v) in obj {
785 if !fields.iter().any(|f| f.as_str() == k.as_ref()) {
786 remainder.insert(k.clone(), v.clone());
787 }
788 }
789 e = e.with_var(rest_name, Val::obj(remainder));
790 }
791 Ok(e)
792 }
793 BindTarget::Arr(names) => {
794 let len = val.arr_len()
795 .ok_or_else(|| EvalError("bind destructure: expected array".into()))?;
796 let mut e = env;
797 for (i, name) in names.iter().enumerate() {
798 let v = if i < len { val.get_index(i as i64) } else { Val::Null };
799 e = e.with_var(name, v);
800 }
801 Ok(e)
802 }
803 }
804}
805
806fn eval_pipe(left: Val, rhs: &Expr, env: &Env) -> Result<Val, EvalError> {
807 match rhs {
808 Expr::Ident(name) => {
809 if env.has_var(name) {
810 eval(rhs, &env.with_current(left))
811 } else {
812 dispatch_method(left, name, &[], env)
813 }
814 }
815 Expr::Chain(base, steps) => {
816 if let Expr::Ident(name) = base.as_ref() {
817 if !env.has_var(name) {
818 let mut v = dispatch_method(left, name, &[], env)?;
819 for step in steps { v = eval_step(v, step, env)?; }
820 return Ok(v);
821 }
822 }
823 eval(rhs, &env.with_current(left))
824 }
825 _ => eval(rhs, &env.with_current(left)),
826 }
827}
828
829fn is_first_selector(step: &Step) -> bool {
843 match step {
844 Step::Quantifier(QuantifierKind::First) => true,
845 Step::Method(name, args) if args.is_empty() && name == "first" => true,
846 _ => false,
847 }
848}
849
850fn byte_chain_eval(
851 bytes: &[u8],
852 root_key: &str,
853 steps: &[Step],
854) -> (Val, usize) {
855 let first_after_initial = steps.get(1).map(is_first_selector).unwrap_or(false);
857 let mut spans: Vec<super::scan::ValueSpan> = if first_after_initial {
858 super::scan::find_first_key_value_span(bytes, root_key)
859 .into_iter().collect()
860 } else {
861 super::scan::find_key_value_spans(bytes, root_key)
862 };
863 let mut scalar = false;
864 let mut consumed = 1usize;
865
866 for (idx, step) in steps.iter().enumerate().skip(1) {
867 match step {
868 Step::Descendant(k) => {
869 let next_first = steps.get(idx + 1)
872 .map(is_first_selector).unwrap_or(false);
873 let mut next = Vec::with_capacity(spans.len());
874 for s in &spans {
875 let sub = &bytes[s.start..s.end];
876 if next_first {
877 if let Some(s2) = super::scan::find_first_key_value_span(sub, k) {
878 next.push(super::scan::ValueSpan {
879 start: s.start + s2.start,
880 end: s.start + s2.end,
881 });
882 }
883 } else {
884 for s2 in super::scan::find_key_value_spans(sub, k) {
885 next.push(super::scan::ValueSpan {
886 start: s.start + s2.start,
887 end: s.start + s2.end,
888 });
889 }
890 }
891 }
892 spans = next;
893 scalar = false;
894 }
895 Step::Quantifier(QuantifierKind::First) => {
896 spans.truncate(1);
897 scalar = true;
898 }
899 Step::Quantifier(QuantifierKind::One) => {
900 if spans.len() != 1 { break; }
901 scalar = true;
902 }
903 Step::Method(name, args) if args.is_empty() && name == "first" => {
905 spans.truncate(1);
906 scalar = true;
907 }
908 Step::Method(name, args) if args.is_empty() && name == "last" => {
909 if let Some(last) = spans.pop() { spans = vec![last]; }
910 scalar = true;
911 }
912 Step::InlineFilter(pred) => match canonical_eq_literal(pred) {
913 Some(lit) => {
914 spans.retain(|s| {
915 s.end - s.start == lit.len()
916 && &bytes[s.start..s.end] == &lit[..]
917 });
918 scalar = false;
919 }
920 None => break,
921 },
922 Step::Method(name, args)
923 if name == "filter" && args.len() == 1 =>
924 {
925 let pred = match &args[0] { Arg::Pos(e) | Arg::Named(_, e) => e };
926 match canonical_eq_literal(pred) {
927 Some(lit) => {
928 spans.retain(|s| {
929 s.end - s.start == lit.len()
930 && &bytes[s.start..s.end] == &lit[..]
931 });
932 scalar = false;
933 }
934 None => break,
935 }
936 }
937 _ => break,
938 }
939 consumed += 1;
940 }
941
942 if !scalar {
945 if let Some(Step::Method(name, args)) = steps.get(consumed) {
946 if args.is_empty() {
947 let tail_ok = steps.len() == consumed + 1;
948 if tail_ok {
949 match name.as_str() {
950 "count" | "len" => {
951 return (Val::Int(spans.len() as i64), consumed + 1);
952 }
953 "sum" => {
954 let f = super::scan::fold_nums(bytes, &spans);
955 let v = if f.count == 0 { Val::Int(0) }
956 else if f.is_float { Val::Float(f.float_sum) }
957 else { Val::Int(f.int_sum) };
958 return (v, consumed + 1);
959 }
960 "avg" => {
961 let f = super::scan::fold_nums(bytes, &spans);
962 let v = if f.count == 0 { Val::Null }
963 else { Val::Float(f.float_sum / f.count as f64) };
964 return (v, consumed + 1);
965 }
966 "min" => {
967 let f = super::scan::fold_nums(bytes, &spans);
968 let v = if !f.any { Val::Null }
969 else if f.is_float { Val::Float(f.min_f) }
970 else { Val::Int(f.min_i) };
971 return (v, consumed + 1);
972 }
973 "max" => {
974 let f = super::scan::fold_nums(bytes, &spans);
975 let v = if !f.any { Val::Null }
976 else if f.is_float { Val::Float(f.max_f) }
977 else { Val::Int(f.max_i) };
978 return (v, consumed + 1);
979 }
980 _ => {}
981 }
982 }
983 }
984 }
985 }
986
987 let mut materialised: Vec<Val> = Vec::with_capacity(spans.len());
988 for s in &spans {
989 match serde_json::from_slice::<serde_json::Value>(&bytes[s.start..s.end]) {
990 Ok(v) => materialised.push(Val::from(&v)),
991 Err(_) => {}
992 }
993 }
994
995 let out = if scalar {
996 materialised.into_iter().next().unwrap_or(Val::Null)
997 } else {
998 Val::arr(materialised)
999 };
1000 (out, consumed)
1001}
1002
1003fn canonical_eq_literal(pred: &Expr) -> Option<Vec<u8>> {
1009 let (l, r) = match pred {
1010 Expr::BinOp(l, BinOp::Eq, r) => (&**l, &**r),
1011 _ => return None,
1012 };
1013 let lit = match (l, r) {
1014 (Expr::Current, lit) => lit,
1015 (lit, Expr::Current) => lit,
1016 _ => return None,
1017 };
1018 match lit {
1019 Expr::Int(n) => Some(n.to_string().into_bytes()),
1020 Expr::Bool(b) => Some(if *b { b"true".to_vec() } else { b"false".to_vec() }),
1021 Expr::Null => Some(b"null".to_vec()),
1022 Expr::Str(s) => serde_json::to_vec(&serde_json::Value::String(s.clone())).ok(),
1023 _ => None,
1024 }
1025}
1026
1027pub(crate) fn canonical_field_eq_literals(args: &[Arg]) -> Option<Vec<(String, Vec<u8>)>> {
1035 if args.is_empty() || args.len() > 64 { return None; }
1036 let mut out = Vec::with_capacity(args.len());
1037 for a in args {
1038 let e = match a { Arg::Pos(e) | Arg::Named(_, e) => e };
1039 out.push(canonical_field_eq_literal(e)?);
1040 }
1041 Some(out)
1042}
1043
1044pub(crate) fn canonical_field_cmp_literal(
1050 pred: &Expr,
1051) -> Option<(String, super::scan::ScanCmp, f64)> {
1052 use super::scan::ScanCmp;
1053 let (l, op, r) = match pred {
1054 Expr::BinOp(l, op @ (BinOp::Lt | BinOp::Lte | BinOp::Gt | BinOp::Gte), r) =>
1055 (&**l, *op, &**r),
1056 _ => return None,
1057 };
1058 fn as_current_field(e: &Expr) -> Option<String> {
1059 if let Expr::Chain(base, steps) = e {
1060 if matches!(**base, Expr::Current) && steps.len() == 1 {
1061 if let Step::Field(name) = &steps[0] { return Some(name.clone()); }
1062 }
1063 }
1064 None
1065 }
1066 fn as_num(e: &Expr) -> Option<f64> {
1067 match e {
1068 Expr::Int(n) => Some(*n as f64),
1069 Expr::Float(f) => if f.is_finite() { Some(*f) } else { None },
1070 _ => None,
1071 }
1072 }
1073 let (field, thresh, flip) = match (as_current_field(l), as_num(r)) {
1074 (Some(f), Some(n)) => (f, n, false),
1075 _ => match (as_current_field(r), as_num(l)) {
1076 (Some(f), Some(n)) => (f, n, true),
1077 _ => return None,
1078 },
1079 };
1080 let scan_op = match (op, flip) {
1081 (BinOp::Lt, false) | (BinOp::Gt, true) => ScanCmp::Lt,
1082 (BinOp::Lte, false) | (BinOp::Gte, true) => ScanCmp::Lte,
1083 (BinOp::Gt, false) | (BinOp::Lt, true) => ScanCmp::Gt,
1084 (BinOp::Gte, false) | (BinOp::Lte, true) => ScanCmp::Gte,
1085 _ => return None,
1086 };
1087 Some((field, scan_op, thresh))
1088}
1089
1090pub(crate) fn canonical_field_mixed_predicates(
1095 args: &[Arg],
1096) -> Option<Vec<(String, super::scan::ScanPred)>> {
1097 use super::scan::ScanPred;
1098 if args.is_empty() || args.len() > 64 { return None; }
1099 let mut out = Vec::with_capacity(args.len());
1100 for a in args {
1101 let e = match a { Arg::Pos(e) | Arg::Named(_, e) => e };
1102 if let Some((k, lit)) = canonical_field_eq_literal(e) {
1103 out.push((k, ScanPred::Eq(lit)));
1104 } else if let Some((k, op, n)) = canonical_field_cmp_literal(e) {
1105 out.push((k, ScanPred::Cmp(op, n)));
1106 } else {
1107 return None;
1108 }
1109 }
1110 Some(out)
1111}
1112
1113pub(crate) fn canonical_field_eq_literal(pred: &Expr) -> Option<(String, Vec<u8>)> {
1114 let (l, r) = match pred {
1115 Expr::BinOp(l, BinOp::Eq, r) => (&**l, &**r),
1116 _ => return None,
1117 };
1118 fn as_current_field(e: &Expr) -> Option<String> {
1119 if let Expr::Chain(base, steps) = e {
1120 if matches!(**base, Expr::Current) && steps.len() == 1 {
1121 if let Step::Field(name) = &steps[0] {
1122 return Some(name.clone());
1123 }
1124 }
1125 }
1126 None
1127 }
1128 let (field, lit) = if let Some(f) = as_current_field(l) { (f, r) }
1129 else if let Some(f) = as_current_field(r) { (f, l) }
1130 else { return None };
1131 let bytes = match lit {
1132 Expr::Int(n) => n.to_string().into_bytes(),
1133 Expr::Bool(b) => if *b { b"true".to_vec() } else { b"false".to_vec() },
1134 Expr::Null => b"null".to_vec(),
1135 Expr::Str(s) => serde_json::to_vec(&serde_json::Value::String(s.clone())).ok()?,
1136 _ => return None,
1137 };
1138 Some((field, bytes))
1139}
1140
1141fn eval_step(val: Val, step: &Step, env: &Env) -> Result<Val, EvalError> {
1144 match step {
1145 Step::Field(name) => Ok(val.get_field(name)),
1146 Step::OptField(name) => {
1147 if val.is_null() { Ok(Val::Null) } else { Ok(val.get_field(name)) }
1148 }
1149 Step::Descendant(name) => {
1150 let mut found = Vec::new();
1151 collect_desc(&val, name, &mut found);
1152 Ok(Val::arr(found))
1153 }
1154 Step::DescendAll => {
1155 let mut found = Vec::new();
1156 collect_all(&val, &mut found);
1157 Ok(Val::arr(found))
1158 }
1159 Step::InlineFilter(pred) => {
1160 let items = match val {
1161 Val::Arr(a) => Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone()),
1162 other => vec![other],
1163 };
1164 let mut out = Vec::new();
1165 let mut env_mut = env.clone();
1166 for item in items {
1167 let frame = env_mut.push_lam(None, item.clone());
1168 let truthy = match eval(pred, &env_mut) {
1169 Ok(v) => is_truthy(&v),
1170 Err(e) => { env_mut.pop_lam(frame); return Err(e); }
1171 };
1172 env_mut.pop_lam(frame);
1173 if truthy { out.push(item); }
1174 }
1175 Ok(Val::arr(out))
1176 }
1177 Step::Quantifier(kind) => {
1178 use super::ast::QuantifierKind;
1179 match kind {
1180 QuantifierKind::First => {
1181 Ok(match val {
1182 Val::Arr(a) => a.first().cloned().unwrap_or(Val::Null),
1183 other => other,
1184 })
1185 }
1186 QuantifierKind::One => {
1187 match val {
1188 Val::Arr(a) if a.len() == 1 => Ok(a[0].clone()),
1189 Val::Arr(a) => err!("quantifier !: expected exactly one element, got {}", a.len()),
1190 other => Ok(other),
1191 }
1192 }
1193 }
1194 }
1195 Step::Index(i) => Ok(val.get_index(*i)),
1196 Step::DynIndex(expr) => {
1197 let key = eval(expr, env)?;
1198 match key {
1199 Val::Int(i) => Ok(val.get_index(i)),
1200 Val::Str(s) => Ok(val.get_field(s.as_ref())),
1201 _ => err!("dynamic index must be a number or string"),
1202 }
1203 }
1204 Step::Slice(from, to) => {
1205 match val {
1206 Val::Arr(a) => {
1207 let len = a.len() as i64;
1208 let s = resolve_idx(from.unwrap_or(0), len);
1209 let e = resolve_idx(to.unwrap_or(len), len);
1210 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
1211 let s = s.min(items.len());
1212 let e = e.min(items.len());
1213 Ok(Val::arr(items[s..e].to_vec()))
1214 }
1215 Val::IntVec(a) => {
1216 let len = a.len() as i64;
1217 let s = resolve_idx(from.unwrap_or(0), len);
1218 let e = resolve_idx(to.unwrap_or(len), len);
1219 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
1220 let s = s.min(items.len());
1221 let e = e.min(items.len());
1222 Ok(Val::int_vec(items[s..e].to_vec()))
1223 }
1224 Val::FloatVec(a) => {
1225 let len = a.len() as i64;
1226 let s = resolve_idx(from.unwrap_or(0), len);
1227 let e = resolve_idx(to.unwrap_or(len), len);
1228 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
1229 let s = s.min(items.len());
1230 let e = e.min(items.len());
1231 Ok(Val::float_vec(items[s..e].to_vec()))
1232 }
1233 _ => Ok(Val::Null),
1234 }
1235 }
1236 Step::Method(name, args) => dispatch_method(val, name, args, env),
1237 Step::OptMethod(name, args) => {
1238 if val.is_null() { Ok(Val::Null) } else { dispatch_method(val, name, args, env) }
1239 }
1240 }
1241}
1242
1243fn resolve_idx(i: i64, len: i64) -> usize {
1244 (if i < 0 { (len + i).max(0) } else { i }) as usize
1245}
1246
1247fn collect_desc(v: &Val, name: &str, out: &mut Vec<Val>) {
1248 match v {
1249 Val::Obj(m) => {
1250 if let Some(v) = m.get(name) { out.push(v.clone()); }
1251 for v in m.values() { collect_desc(v, name, out); }
1252 }
1253 Val::Arr(a) => { for item in a.as_ref() { collect_desc(item, name, out); } }
1254 _ => {}
1255 }
1256}
1257
1258fn collect_all(v: &Val, out: &mut Vec<Val>) {
1259 match v {
1260 Val::Obj(m) => {
1261 out.push(v.clone());
1262 for child in m.values() { collect_all(child, out); }
1263 }
1264 Val::Arr(a) => {
1265 for item in a.as_ref() { collect_all(item, out); }
1266 }
1267 other => out.push(other.clone()),
1268 }
1269}
1270
1271pub(super) fn dispatch_method(recv: Val, name: &str, args: &[Arg], env: &Env) -> Result<Val, EvalError> {
1274 if let Some(f) = builtins::global().get(name) {
1275 return f(recv, args, env);
1276 }
1277 if !env.registry.is_empty() {
1278 if let Some(method) = env.registry.get(name) {
1279 let evaluated: Result<Vec<Val>, EvalError> =
1280 args.iter().map(|a| eval_pos(a, env)).collect();
1281 return method.call(recv, &evaluated?);
1282 }
1283 }
1284 err!("unknown method '{}'", name)
1285}
1286
1287fn eval_object(fields: &[ObjField], env: &Env) -> Result<Val, EvalError> {
1290 let mut map: IndexMap<Arc<str>, Val> = IndexMap::new();
1291 for field in fields {
1292 match field {
1293 ObjField::Short(name) => {
1294 let v = if let Some(v) = env.get_var(name) { v.clone() }
1295 else { env.current.get_field(name) };
1296 if !v.is_null() { map.insert(Arc::from(name.as_str()), v); }
1297 }
1298 ObjField::Kv { key, val, optional, cond } => {
1299 if let Some(c) = cond {
1300 if !is_truthy(&eval(c, env)?) { continue; }
1301 }
1302 let v = eval(val, env)?;
1303 if *optional && v.is_null() { continue; }
1304 map.insert(Arc::from(key.as_str()), v);
1305 }
1306 ObjField::Dynamic { key, val } => {
1307 let k: Arc<str> = match eval(key, env)? {
1308 Val::Str(s) => s,
1309 other => Arc::<str>::from(val_to_key(&other)),
1310 };
1311 map.insert(k, eval(val, env)?);
1312 }
1313 ObjField::Spread(expr) => {
1314 if let Val::Obj(other) = eval(expr, env)? {
1315 let entries = Arc::try_unwrap(other).unwrap_or_else(|m| (*m).clone());
1316 for (k, v) in entries { map.insert(k, v); }
1317 }
1318 }
1319 ObjField::SpreadDeep(expr) => {
1320 if let Val::Obj(other) = eval(expr, env)? {
1321 let base = std::mem::take(&mut map);
1322 let merged = deep_merge_concat(Val::obj(base), Val::Obj(other));
1323 if let Val::Obj(m) = merged {
1324 map = Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone());
1325 }
1326 }
1327 }
1328 }
1329 }
1330 Ok(Val::obj(map))
1331}
1332
1333fn eval_fstring(parts: &[FStringPart], env: &Env) -> Result<Val, EvalError> {
1336 let mut out = String::new();
1337 for part in parts {
1338 match part {
1339 FStringPart::Lit(s) => out.push_str(s),
1340 FStringPart::Interp { expr, fmt } => {
1341 let val = eval(expr, env)?;
1342 let s = match fmt {
1343 None => val_to_string(&val),
1344 Some(FmtSpec::Spec(spec)) => apply_fmt_spec(&val, spec),
1345 Some(FmtSpec::Pipe(method)) => {
1346 val_to_string(&dispatch_method(val, method, &[], env)?)
1347 }
1348 };
1349 out.push_str(&s);
1350 }
1351 }
1352 }
1353 Ok(Val::Str(Arc::from(out.as_str())))
1354}
1355
1356fn apply_fmt_spec(val: &Val, spec: &str) -> String {
1357 if let Some(rest) = spec.strip_suffix('f') {
1358 if let Some(prec_str) = rest.strip_prefix('.') {
1359 if let Ok(prec) = prec_str.parse::<usize>() {
1360 if let Some(f) = val.as_f64() { return format!("{:.prec$}", f); }
1361 }
1362 }
1363 }
1364 if spec == "d" {
1365 if let Some(i) = val.as_i64() { return format!("{}", i); }
1366 }
1367 let s = val_to_string(val);
1368 if let Some(w) = spec.strip_prefix('>').and_then(|s| s.parse::<usize>().ok()) { return format!("{:>w$}", s); }
1369 if let Some(w) = spec.strip_prefix('<').and_then(|s| s.parse::<usize>().ok()) { return format!("{:<w$}", s); }
1370 if let Some(w) = spec.strip_prefix('^').and_then(|s| s.parse::<usize>().ok()) { return format!("{:^w$}", s); }
1371 if let Some(w) = spec.strip_prefix('0').and_then(|s| s.parse::<usize>().ok()) {
1372 if let Some(i) = val.as_i64() { return format!("{:0>w$}", i); }
1373 }
1374 s
1375}
1376
1377fn eval_binop(l: &Expr, op: BinOp, r: &Expr, env: &Env) -> Result<Val, EvalError> {
1380 match op {
1381 BinOp::And => {
1382 let lv = eval(l, env)?;
1383 if !is_truthy(&lv) { return Ok(Val::Bool(false)); }
1384 Ok(Val::Bool(is_truthy(&eval(r, env)?)))
1385 }
1386 BinOp::Or => {
1387 let lv = eval(l, env)?;
1388 if is_truthy(&lv) { return Ok(lv); }
1389 eval(r, env)
1390 }
1391 _ => {
1392 let lv = eval(l, env)?;
1393 let rv = eval(r, env)?;
1394 match op {
1395 BinOp::Add => add_vals(lv, rv),
1396 BinOp::Sub => num_op(lv, rv, |a, b| a - b, |a, b| a - b),
1397 BinOp::Mul => num_op(lv, rv, |a, b| a * b, |a, b| a * b),
1398 BinOp::Div => {
1399 let b = rv.as_f64().unwrap_or(0.0);
1400 if b == 0.0 { return err!("division by zero"); }
1401 Ok(Val::Float(lv.as_f64().unwrap_or(0.0) / b))
1402 }
1403 BinOp::Mod => num_op(lv, rv, |a, b| a % b, |a, b| a % b),
1404 BinOp::Eq => Ok(Val::Bool(vals_eq(&lv, &rv))),
1405 BinOp::Neq => Ok(Val::Bool(!vals_eq(&lv, &rv))),
1406 BinOp::Lt => Ok(Val::Bool(cmp_vals(&lv, &rv) == std::cmp::Ordering::Less)),
1407 BinOp::Lte => Ok(Val::Bool(cmp_vals(&lv, &rv) != std::cmp::Ordering::Greater)),
1408 BinOp::Gt => Ok(Val::Bool(cmp_vals(&lv, &rv) == std::cmp::Ordering::Greater)),
1409 BinOp::Gte => Ok(Val::Bool(cmp_vals(&lv, &rv) != std::cmp::Ordering::Less)),
1410 BinOp::Fuzzy => {
1411 let ls = match &lv { Val::Str(s) => s.to_lowercase(), _ => val_to_string(&lv).to_lowercase() };
1412 let rs = match &rv { Val::Str(s) => s.to_lowercase(), _ => val_to_string(&rv).to_lowercase() };
1413 Ok(Val::Bool(ls.contains(&rs) || rs.contains(&ls)))
1414 }
1415 BinOp::And | BinOp::Or => unreachable!(),
1416 }
1417 }
1418 }
1419}
1420
1421fn eval_global(name: &str, args: &[Arg], env: &Env) -> Result<Val, EvalError> {
1424 match name {
1425 "coalesce" => {
1426 for arg in args {
1427 let v = eval_pos(arg, env)?;
1428 if !v.is_null() { return Ok(v); }
1429 }
1430 Ok(Val::Null)
1431 }
1432 "chain" | "join" => {
1433 let mut out = Vec::new();
1434 for arg in args {
1435 match eval_pos(arg, env)? {
1436 Val::Arr(a) => {
1437 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
1438 out.extend(items);
1439 }
1440 Val::IntVec(a) => out.extend(a.iter().map(|n| Val::Int(*n))),
1441 Val::FloatVec(a) => out.extend(a.iter().map(|f| Val::Float(*f))),
1442 v => out.push(v),
1443 }
1444 }
1445 Ok(Val::arr(out))
1446 }
1447 "zip" => func_arrays::global_zip(args, env),
1448 "zip_longest" => func_arrays::global_zip_longest(args, env),
1449 "product" => func_arrays::global_product(args, env),
1450 "range" => eval_range(args, env),
1451 other => {
1452 if let Some(first) = args.first() {
1453 let recv = eval_pos(first, env)?;
1454 dispatch_method(recv, other, args.get(1..).unwrap_or(&[]), env)
1455 } else {
1456 dispatch_method(env.current.clone(), other, &[], env)
1457 }
1458 }
1459 }
1460}
1461
1462fn eval_range(args: &[Arg], env: &Env) -> Result<Val, EvalError> {
1473 let n = args.len();
1474 if n == 0 || n > 3 {
1475 return err!("range: expected 1..3 args, got {}", n);
1476 }
1477 let mut nums = Vec::with_capacity(n);
1478 for a in args {
1479 let v = eval_pos(a, env)?;
1480 let i = v.as_i64().ok_or_else(|| EvalError("range: expected integer arg".into()))?;
1481 nums.push(i);
1482 }
1483 let (from, upto, step) = match nums.as_slice() {
1484 [n] => (0, *n, 1i64),
1485 [f, u] => (*f, *u, 1i64),
1486 [f, u, s] => (*f, *u, *s),
1487 _ => unreachable!(),
1488 };
1489 if step == 0 { return Ok(Val::int_vec(Vec::new())); }
1490 let len_hint: usize = if step > 0 && upto > from {
1491 (((upto - from) + step - 1) / step).max(0) as usize
1492 } else if step < 0 && upto < from {
1493 (((from - upto) + (-step) - 1) / (-step)).max(0) as usize
1494 } else { 0 };
1495 let mut out: Vec<i64> = Vec::with_capacity(len_hint);
1496 let mut i = from;
1497 if step > 0 {
1498 while i < upto { out.push(i); i += step; }
1499 } else {
1500 while i > upto { out.push(i); i += step; }
1501 }
1502 Ok(Val::int_vec(out))
1503}
1504
1505pub(super) fn apply_item(item: Val, arg: &Arg, env: &Env) -> Result<Val, EvalError> {
1508 match arg {
1509 Arg::Pos(expr) | Arg::Named(_, expr) => apply_expr_item(item, expr, env),
1510 }
1511}
1512
1513#[inline]
1517pub(super) fn apply_item_mut(item: Val, arg: &Arg, env: &mut Env) -> Result<Val, EvalError> {
1518 let expr = match arg { Arg::Pos(e) | Arg::Named(_, e) => e };
1519 match expr {
1520 Expr::Lambda { params, body } => {
1521 let name = params.first().map(|s| s.as_str());
1522 let frame = env.push_lam(name, item);
1523 let r = eval(body, env);
1524 env.pop_lam(frame);
1525 r
1526 }
1527 _ => {
1528 let frame = env.push_lam(None, item);
1529 let r = eval(expr, env);
1530 env.pop_lam(frame);
1531 r
1532 }
1533 }
1534}
1535
1536#[inline]
1539pub(super) fn apply_item2_mut(a: Val, b: Val, arg: &Arg, env: &mut Env) -> Result<Val, EvalError> {
1540 match arg {
1541 Arg::Pos(Expr::Lambda { params, body }) | Arg::Named(_, Expr::Lambda { params, body }) => {
1542 match params.as_slice() {
1543 [] => {
1544 let frame = env.push_lam(None, b);
1545 let r = eval(body, env);
1546 env.pop_lam(frame);
1547 r
1548 }
1549 [p] => {
1550 let frame = env.push_lam(Some(p), b);
1551 let r = eval(body, env);
1552 env.pop_lam(frame);
1553 r
1554 }
1555 [p1, p2, ..] => {
1556 let f1 = env.push_lam(Some(p1), a);
1558 let f2 = env.push_lam(Some(p2), b);
1559 let r = eval(body, env);
1560 env.pop_lam(f2);
1561 env.pop_lam(f1);
1562 r
1563 }
1564 }
1565 }
1566 _ => apply_item_mut(b, arg, env),
1567 }
1568}
1569
1570fn apply_expr_item(item: Val, expr: &Expr, env: &Env) -> Result<Val, EvalError> {
1571 match expr {
1572 Expr::Lambda { params, body } => {
1573 let inner = if params.is_empty() {
1574 env.with_current(item)
1575 } else {
1576 let mut e = env.with_var(¶ms[0], item.clone());
1577 e.current = item;
1578 e
1579 };
1580 eval(body, &inner)
1581 }
1582 _ => eval(expr, &env.with_current(item)),
1583 }
1584}
1585
1586pub(super) fn eval_pos(arg: &Arg, env: &Env) -> Result<Val, EvalError> {
1587 match arg { Arg::Pos(e) | Arg::Named(_, e) => eval(e, env) }
1588}
1589
1590pub(super) fn first_i64_arg(args: &[Arg], env: &Env) -> Result<i64, EvalError> {
1591 args.first()
1592 .map(|a| eval_pos(a, env)?.as_i64().ok_or_else(|| EvalError("expected integer arg".into())))
1593 .transpose()
1594 .map(|v| v.unwrap_or(1))
1595}
1596
1597pub(super) fn str_arg(args: &[Arg], idx: usize, env: &Env) -> Result<String, EvalError> {
1598 args.get(idx)
1599 .map(|a| eval_pos(a, env))
1600 .transpose()?
1601 .map(|v| val_to_string(&v))
1602 .ok_or_else(|| EvalError(format!("missing string arg at position {}", idx)))
1603}
1604
1605fn eval_iter(iter: &Expr, env: &Env) -> Result<Vec<Val>, EvalError> {
1608 match eval(iter, env)? {
1609 Val::Arr(a) => Ok(Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone())),
1610 Val::Obj(m) => {
1611 let entries = Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone());
1612 Ok(entries.into_iter().map(|(k, v)| {
1613 let mut o: IndexMap<Arc<str>, Val> = IndexMap::new();
1614 o.insert(Arc::from("key"), Val::Str(k));
1615 o.insert(Arc::from("value"), v);
1616 Val::obj(o)
1617 }).collect())
1618 }
1619 other => Ok(vec![other]),
1620 }
1621}
1622
1623#[inline]
1627fn bind_vars_mut(env: &mut Env, vars: &[String], item: Val) -> (LamFrame, Option<LamFrame>) {
1628 match vars {
1629 [] => (env.push_lam(None, item), None),
1630 [v] => (env.push_lam(Some(v), item), None),
1631 [v1, v2, ..] => {
1632 let idx = item.get("index").cloned().unwrap_or(Val::Null);
1633 let val = item.get("value").cloned().unwrap_or_else(|| item.clone());
1634 let f1 = env.push_lam(Some(v1), idx);
1635 let f2 = env.push_lam(Some(v2), val);
1637 (f1, Some(f2))
1638 }
1639 }
1640}
1641
1642#[inline]
1643fn unbind_vars_mut(env: &mut Env, frames: (LamFrame, Option<LamFrame>)) {
1644 if let Some(f2) = frames.1 { env.pop_lam(f2); }
1645 env.pop_lam(frames.0);
1646}