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;
55
56pub use value::Val;
57pub use methods::{Method, MethodRegistry};
58use util::*;
59
60#[derive(Debug, Clone)]
63pub struct EvalError(pub String);
64
65impl std::fmt::Display for EvalError {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "eval error: {}", self.0)
68 }
69}
70impl std::error::Error for EvalError {}
71
72macro_rules! err {
73 ($($t:tt)*) => { Err(EvalError(format!($($t)*))) };
74}
75
76#[derive(Clone)]
81pub struct Env {
82 vars: SmallVec<[(Arc<str>, Val); 4]>,
83 pub root: Val,
84 pub current: Val,
85 registry: Arc<MethodRegistry>,
86}
87
88impl Env {
89 fn new(root: Val) -> Self {
90 Self {
91 vars: SmallVec::new(),
92 root: root.clone(),
93 current: root,
94 registry: Arc::new(MethodRegistry::new()),
95 }
96 }
97
98 pub fn new_with_registry(root: Val, registry: Arc<MethodRegistry>) -> Self {
99 Self { vars: SmallVec::new(), root: root.clone(), current: root, registry }
100 }
101
102 #[inline]
103 pub(super) fn registry_ref(&self) -> &MethodRegistry { &self.registry }
104
105 #[inline]
106 pub fn with_current(&self, current: Val) -> Self {
107 Self {
108 vars: self.vars.clone(),
109 root: self.root.clone(),
110 current,
111 registry: self.registry.clone(),
112 }
113 }
114
115 #[inline]
119 pub fn swap_current(&mut self, new: Val) -> Val {
120 std::mem::replace(&mut self.current, new)
121 }
122
123 #[inline]
124 pub fn restore_current(&mut self, old: Val) {
125 self.current = old;
126 }
127
128 #[inline]
129 pub fn get_var(&self, name: &str) -> Option<&Val> {
130 self.vars.iter().rev().find(|(k, _)| k.as_ref() == name).map(|(_, v)| v)
131 }
132
133 #[inline]
134 pub fn has_var(&self, name: &str) -> bool {
135 self.vars.iter().any(|(k, _)| k.as_ref() == name)
136 }
137
138 pub fn with_var(&self, name: &str, val: Val) -> Self {
139 let mut vars = self.vars.clone();
140 if let Some(pos) = vars.iter().position(|(k, _)| k.as_ref() == name) {
141 vars[pos].1 = val;
142 } else {
143 vars.push((Arc::from(name), val));
144 }
145 Self { vars, root: self.root.clone(), current: self.current.clone(), registry: self.registry.clone() }
146 }
147
148 fn with_vars2(&self, n1: &str, v1: Val, n2: &str, v2: Val) -> Self {
149 let mut vars = self.vars.clone();
150 if let Some(p) = vars.iter().position(|(k, _)| k.as_ref() == n1) { vars[p].1 = v1; }
151 else { vars.push((Arc::from(n1), v1)); }
152 if let Some(p) = vars.iter().position(|(k, _)| k.as_ref() == n2) { vars[p].1 = v2; }
153 else { vars.push((Arc::from(n2), v2)); }
154 Self { vars, root: self.root.clone(), current: self.current.clone(), registry: self.registry.clone() }
155 }
156
157 fn extend_vars(&self, extra: impl IntoIterator<Item = (Arc<str>, Val)>) -> Self {
158 let mut vars = self.vars.clone();
159 for (name, val) in extra {
160 if let Some(pos) = vars.iter().position(|(k, _)| *k == name) {
161 vars[pos].1 = val;
162 } else {
163 vars.push((name, val));
164 }
165 }
166 Self { vars, root: self.root.clone(), current: self.current.clone(), registry: self.registry.clone() }
167 }
168}
169
170pub fn evaluate(expr: &Expr, root: &serde_json::Value) -> Result<serde_json::Value, EvalError> {
173 let val = Val::from(root);
174 Ok(eval(expr, &Env::new(val))?.into())
175}
176
177pub fn evaluate_with(
178 expr: &Expr,
179 root: &serde_json::Value,
180 registry: Arc<MethodRegistry>,
181) -> Result<serde_json::Value, EvalError> {
182 let val = Val::from(root);
183 Ok(eval(expr, &Env::new_with_registry(val, registry))?.into())
184}
185
186pub(super) fn eval(expr: &Expr, env: &Env) -> Result<Val, EvalError> {
189 match expr {
190 Expr::Null => Ok(Val::Null),
191 Expr::Bool(b) => Ok(Val::Bool(*b)),
192 Expr::Int(n) => Ok(Val::Int(*n)),
193 Expr::Float(f) => Ok(Val::Float(*f)),
194 Expr::Str(s) => Ok(Val::Str(Arc::from(s.as_str()))),
195
196 Expr::FString(parts) => eval_fstring(parts, env),
197
198 Expr::Root => Ok(env.root.clone()),
199 Expr::Current => Ok(env.current.clone()),
200
201 Expr::Ident(name) => {
202 if let Some(v) = env.get_var(name) { return Ok(v.clone()); }
203 Ok(env.current.get_field(name))
204 }
205
206 Expr::Chain(base, steps) => {
207 let mut val = eval(base, env)?;
208 for step in steps { val = eval_step(val, step, env)?; }
209 Ok(val)
210 }
211
212 Expr::UnaryNeg(e) => match eval(e, env)? {
213 Val::Int(n) => Ok(Val::Int(-n)),
214 Val::Float(f) => Ok(Val::Float(-f)),
215 _ => err!("unary minus requires a number"),
216 },
217
218 Expr::Not(e) => Ok(Val::Bool(!is_truthy(&eval(e, env)?))),
219 Expr::BinOp(l, op, r) => eval_binop(l, *op, r, env),
220
221 Expr::Coalesce(lhs, rhs) => {
222 let v = eval(lhs, env)?;
223 if !v.is_null() { Ok(v) } else { eval(rhs, env) }
224 }
225
226 Expr::Kind { expr, ty, negate } => {
227 let v = eval(expr, env)?;
228 let m = kind_matches(&v, *ty);
229 Ok(Val::Bool(if *negate { !m } else { m }))
230 }
231
232 Expr::Object(fields) => eval_object(fields, env),
233
234 Expr::Array(elems) => {
235 let mut out = Vec::new();
236 for elem in elems {
237 match elem {
238 ArrayElem::Expr(e) => out.push(eval(e, env)?),
239 ArrayElem::Spread(e) => match eval(e, env)? {
240 Val::Arr(a) => {
241 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
242 out.extend(items);
243 }
244 v => out.push(v),
245 },
246 }
247 }
248 Ok(Val::arr(out))
249 }
250
251 Expr::Pipeline { base, steps } => eval_pipeline(base, steps, env),
252
253 Expr::ListComp { expr, vars, iter, cond } => {
254 let items = eval_iter(iter, env)?;
255 let mut out = Vec::new();
256 for item in items {
257 let ie = bind_vars(env, vars, item);
258 if let Some(c) = cond { if !is_truthy(&eval(c, &ie)?) { continue; } }
259 out.push(eval(expr, &ie)?);
260 }
261 Ok(Val::arr(out))
262 }
263
264 Expr::DictComp { key, val, vars, iter, cond } => {
265 let items = eval_iter(iter, env)?;
266 let mut map: IndexMap<Arc<str>, Val> = IndexMap::new();
267 for item in items {
268 let ie = bind_vars(env, vars, item);
269 if let Some(c) = cond { if !is_truthy(&eval(c, &ie)?) { continue; } }
270 let k: Arc<str> = Arc::from(val_to_key(&eval(key, &ie)?).as_str());
271 map.insert(k, eval(val, &ie)?);
272 }
273 Ok(Val::obj(map))
274 }
275
276 Expr::SetComp { expr, vars, iter, cond } | Expr::GenComp { expr, vars, iter, cond } => {
277 let items = eval_iter(iter, env)?;
278 let mut seen: Vec<String> = Vec::new();
279 let mut out = Vec::new();
280 for item in items {
281 let ie = bind_vars(env, vars, item);
282 if let Some(c) = cond { if !is_truthy(&eval(c, &ie)?) { continue; } }
283 let v = eval(expr, &ie)?;
284 let k = val_to_key(&v);
285 if !seen.contains(&k) { seen.push(k); out.push(v); }
286 }
287 Ok(Val::arr(out))
288 }
289
290 Expr::Lambda { .. } => err!("lambda cannot be used as standalone value"),
291
292 Expr::Let { name, init, body } => {
293 let v = eval(init, env)?;
294 eval(body, &env.with_var(name, v))
295 }
296
297 Expr::GlobalCall { name, args } => eval_global(name, args, env),
298
299 Expr::Cast { expr, ty } => {
300 let v = eval(expr, env)?;
301 cast_val(&v, *ty)
302 }
303
304 Expr::Patch { root, ops } => eval_patch(root, ops, env),
305 Expr::DeleteMark =>
306 err!("DELETE can only appear as a patch-field value"),
307 }
308}
309
310use super::ast::{PatchOp, PathStep};
313
314enum PatchResult { Replace(Val), Delete }
315
316fn eval_patch(root: &Expr, ops: &[PatchOp], env: &Env) -> Result<Val, EvalError> {
317 let mut doc = eval(root, env)?;
318 for op in ops {
319 if let Some(c) = &op.cond {
320 let cenv = env.with_current(doc.clone());
321 if !is_truthy(&eval(c, &cenv)?) { continue; }
322 }
323 match apply_patch_step(doc, &op.path, 0, &op.val, env)? {
324 PatchResult::Replace(v) => doc = v,
325 PatchResult::Delete => doc = Val::Null,
326 }
327 }
328 Ok(doc)
329}
330
331fn apply_patch_step(
332 v: Val,
333 path: &[PathStep],
334 i: usize,
335 val_expr: &Expr,
336 env: &Env,
337) -> Result<PatchResult, EvalError> {
338 if i == path.len() {
339 if matches!(val_expr, Expr::DeleteMark) {
340 return Ok(PatchResult::Delete);
341 }
342 let nv = eval(val_expr, &env.with_current(v))?;
343 return Ok(PatchResult::Replace(nv));
344 }
345 match &path[i] {
346 PathStep::Field(name) => {
347 let existing = v.get_field(name);
348 let child = apply_patch_step(existing, path, i+1, val_expr, env)?;
349 let mut m = v.into_map().unwrap_or_default();
350 match child {
351 PatchResult::Delete => { m.shift_remove(name.as_str()); }
352 PatchResult::Replace(nv) => { m.insert(Arc::from(name.as_str()), nv); }
353 }
354 Ok(PatchResult::Replace(Val::obj(m)))
355 }
356 PathStep::Index(idx) => {
357 let existing = v.get_index(*idx);
358 let child = apply_patch_step(existing, path, i+1, val_expr, env)?;
359 let mut a = v.into_vec().unwrap_or_default();
360 let resolved = resolve_idx(*idx, a.len() as i64);
361 match child {
362 PatchResult::Delete => {
363 if resolved < a.len() { a.remove(resolved); }
364 }
365 PatchResult::Replace(nv) => {
366 if resolved < a.len() { a[resolved] = nv; }
367 }
368 }
369 Ok(PatchResult::Replace(Val::arr(a)))
370 }
371 PathStep::Wildcard => {
372 let arr = v.into_vec().ok_or_else(|| EvalError("patch [*]: expected array".into()))?;
373 let mut out = Vec::with_capacity(arr.len());
374 for item in arr {
375 match apply_patch_step(item, path, i+1, val_expr, env)? {
376 PatchResult::Delete => {}
377 PatchResult::Replace(nv) => out.push(nv),
378 }
379 }
380 Ok(PatchResult::Replace(Val::arr(out)))
381 }
382 PathStep::WildcardFilter(pred) => {
383 let arr = v.into_vec().ok_or_else(|| EvalError("patch [* if]: expected array".into()))?;
384 let mut out = Vec::with_capacity(arr.len());
385 for item in arr {
386 let include = is_truthy(&eval(pred, &env.with_current(item.clone()))?);
387 if include {
388 match apply_patch_step(item, path, i+1, val_expr, env)? {
389 PatchResult::Delete => {}
390 PatchResult::Replace(nv) => out.push(nv),
391 }
392 } else {
393 out.push(item);
394 }
395 }
396 Ok(PatchResult::Replace(Val::arr(out)))
397 }
398 PathStep::Descendant(_) =>
399 err!("descendant paths (..) in patch are not yet supported"),
400 }
401}
402
403fn cast_val(v: &Val, ty: super::ast::CastType) -> Result<Val, EvalError> {
408 use super::ast::CastType;
409 match ty {
410 CastType::Str => Ok(Val::Str(Arc::from(match v {
411 Val::Null => "null".to_string(),
412 Val::Bool(b) => b.to_string(),
413 Val::Int(n) => n.to_string(),
414 Val::Float(f) => f.to_string(),
415 Val::Str(s) => s.to_string(),
416 other => super::eval::util::val_to_string(other),
417 }.as_str()))),
418 CastType::Bool => Ok(Val::Bool(match v {
419 Val::Null => false,
420 Val::Bool(b) => *b,
421 Val::Int(n) => *n != 0,
422 Val::Float(f) => *f != 0.0,
423 Val::Str(s) => !s.is_empty(),
424 Val::Arr(a) => !a.is_empty(),
425 Val::Obj(o) => !o.is_empty(),
426 })),
427 CastType::Number | CastType::Float => match v {
428 Val::Int(n) => Ok(Val::Float(*n as f64)),
429 Val::Float(_) => Ok(v.clone()),
430 Val::Str(s) => s.parse::<f64>().map(Val::Float)
431 .map_err(|e| EvalError(format!("as float: {}", e))),
432 Val::Bool(b) => Ok(Val::Float(if *b { 1.0 } else { 0.0 })),
433 Val::Null => Ok(Val::Float(0.0)),
434 _ => err!("as float: cannot convert"),
435 },
436 CastType::Int => match v {
437 Val::Int(_) => Ok(v.clone()),
438 Val::Float(f) => Ok(Val::Int(*f as i64)),
439 Val::Str(s) => s.parse::<i64>().map(Val::Int)
440 .or_else(|_| s.parse::<f64>().map(|f| Val::Int(f as i64)))
441 .map_err(|e| EvalError(format!("as int: {}", e))),
442 Val::Bool(b) => Ok(Val::Int(if *b { 1 } else { 0 })),
443 Val::Null => Ok(Val::Int(0)),
444 _ => err!("as int: cannot convert"),
445 },
446 CastType::Array => match v {
447 Val::Arr(_) => Ok(v.clone()),
448 Val::Null => Ok(Val::arr(Vec::new())),
449 other => Ok(Val::arr(vec![other.clone()])),
450 },
451 CastType::Object => match v {
452 Val::Obj(_) => Ok(v.clone()),
453 _ => err!("as object: cannot convert non-object"),
454 },
455 CastType::Null => Ok(Val::Null),
456 }
457}
458
459fn eval_pipeline(base: &Expr, steps: &[PipeStep], env: &Env) -> Result<Val, EvalError> {
462 let mut current = eval(base, env)?;
463 let mut env = env.clone();
464 for step in steps {
465 match step {
466 PipeStep::Forward(rhs) => current = eval_pipe(current, rhs, &env)?,
467 PipeStep::Bind(target) => env = apply_bind(target, ¤t, env)?,
468 }
469 }
470 Ok(current)
471}
472
473fn apply_bind(target: &BindTarget, val: &Val, env: Env) -> Result<Env, EvalError> {
474 match target {
475 BindTarget::Name(name) => Ok(env.with_var(name, val.clone())),
476 BindTarget::Obj { fields, rest } => {
477 let obj = val.as_object()
478 .ok_or_else(|| EvalError("bind destructure: expected object".into()))?;
479 let mut e = env;
480 for f in fields {
481 e = e.with_var(f, obj.get(f.as_str()).cloned().unwrap_or(Val::Null));
482 }
483 if let Some(rest_name) = rest {
484 let mut remainder: IndexMap<Arc<str>, Val> = IndexMap::new();
485 for (k, v) in obj {
486 if !fields.iter().any(|f| f.as_str() == k.as_ref()) {
487 remainder.insert(k.clone(), v.clone());
488 }
489 }
490 e = e.with_var(rest_name, Val::obj(remainder));
491 }
492 Ok(e)
493 }
494 BindTarget::Arr(names) => {
495 let arr = val.as_array()
496 .ok_or_else(|| EvalError("bind destructure: expected array".into()))?;
497 let mut e = env;
498 for (i, name) in names.iter().enumerate() {
499 e = e.with_var(name, arr.get(i).cloned().unwrap_or(Val::Null));
500 }
501 Ok(e)
502 }
503 }
504}
505
506fn eval_pipe(left: Val, rhs: &Expr, env: &Env) -> Result<Val, EvalError> {
507 match rhs {
508 Expr::Ident(name) => {
509 if env.has_var(name) {
510 eval(rhs, &env.with_current(left))
511 } else {
512 dispatch_method(left, name, &[], env)
513 }
514 }
515 Expr::Chain(base, steps) => {
516 if let Expr::Ident(name) = base.as_ref() {
517 if !env.has_var(name) {
518 let mut v = dispatch_method(left, name, &[], env)?;
519 for step in steps { v = eval_step(v, step, env)?; }
520 return Ok(v);
521 }
522 }
523 eval(rhs, &env.with_current(left))
524 }
525 _ => eval(rhs, &env.with_current(left)),
526 }
527}
528
529fn eval_step(val: Val, step: &Step, env: &Env) -> Result<Val, EvalError> {
532 match step {
533 Step::Field(name) => Ok(val.get_field(name)),
534 Step::OptField(name) => {
535 if val.is_null() { Ok(Val::Null) } else { Ok(val.get_field(name)) }
536 }
537 Step::Descendant(name) => {
538 let mut found = Vec::new();
539 collect_desc(&val, name, &mut found);
540 Ok(Val::arr(found))
541 }
542 Step::DescendAll => {
543 let mut found = Vec::new();
544 collect_all(&val, &mut found);
545 Ok(Val::arr(found))
546 }
547 Step::InlineFilter(pred) => {
548 let items = match val {
549 Val::Arr(a) => Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone()),
550 other => vec![other],
551 };
552 let mut out = Vec::new();
553 for item in items {
554 let ie = env.with_current(item.clone());
555 if is_truthy(&eval(pred, &ie)?) { out.push(item); }
556 }
557 Ok(Val::arr(out))
558 }
559 Step::Quantifier(kind) => {
560 use super::ast::QuantifierKind;
561 match kind {
562 QuantifierKind::First => {
563 Ok(match val {
564 Val::Arr(a) => a.first().cloned().unwrap_or(Val::Null),
565 other => other,
566 })
567 }
568 QuantifierKind::One => {
569 match val {
570 Val::Arr(a) if a.len() == 1 => Ok(a[0].clone()),
571 Val::Arr(a) => err!("quantifier !: expected exactly one element, got {}", a.len()),
572 other => Ok(other),
573 }
574 }
575 }
576 }
577 Step::Index(i) => Ok(val.get_index(*i)),
578 Step::DynIndex(expr) => {
579 let key = eval(expr, env)?;
580 match key {
581 Val::Int(i) => Ok(val.get_index(i)),
582 Val::Str(s) => Ok(val.get_field(s.as_ref())),
583 _ => err!("dynamic index must be a number or string"),
584 }
585 }
586 Step::Slice(from, to) => {
587 if let Val::Arr(a) = val {
588 let len = a.len() as i64;
589 let s = resolve_idx(from.unwrap_or(0), len);
590 let e = resolve_idx(to.unwrap_or(len), len);
591 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
592 let s = s.min(items.len());
593 let e = e.min(items.len());
594 Ok(Val::arr(items[s..e].to_vec()))
595 } else { Ok(Val::Null) }
596 }
597 Step::Method(name, args) => dispatch_method(val, name, args, env),
598 Step::OptMethod(name, args) => {
599 if val.is_null() { Ok(Val::Null) } else { dispatch_method(val, name, args, env) }
600 }
601 }
602}
603
604fn resolve_idx(i: i64, len: i64) -> usize {
605 (if i < 0 { (len + i).max(0) } else { i }) as usize
606}
607
608fn collect_desc(v: &Val, name: &str, out: &mut Vec<Val>) {
609 match v {
610 Val::Obj(m) => {
611 if let Some(v) = m.get(name) { out.push(v.clone()); }
612 for v in m.values() { collect_desc(v, name, out); }
613 }
614 Val::Arr(a) => { for item in a.as_ref() { collect_desc(item, name, out); } }
615 _ => {}
616 }
617}
618
619fn collect_all(v: &Val, out: &mut Vec<Val>) {
620 match v {
621 Val::Obj(m) => {
622 out.push(v.clone());
623 for child in m.values() { collect_all(child, out); }
624 }
625 Val::Arr(a) => {
626 for item in a.as_ref() { collect_all(item, out); }
627 }
628 other => out.push(other.clone()),
629 }
630}
631
632pub(super) fn dispatch_method(recv: Val, name: &str, args: &[Arg], env: &Env) -> Result<Val, EvalError> {
635 if let Some(f) = builtins::global().get(name) {
636 return f(recv, args, env);
637 }
638 if !env.registry.is_empty() {
639 if let Some(method) = env.registry.get(name) {
640 let evaluated: Result<Vec<Val>, EvalError> =
641 args.iter().map(|a| eval_pos(a, env)).collect();
642 return method.call(recv, &evaluated?);
643 }
644 }
645 err!("unknown method '{}'", name)
646}
647
648fn eval_object(fields: &[ObjField], env: &Env) -> Result<Val, EvalError> {
651 let mut map: IndexMap<Arc<str>, Val> = IndexMap::new();
652 for field in fields {
653 match field {
654 ObjField::Short(name) => {
655 let v = if let Some(v) = env.get_var(name) { v.clone() }
656 else { env.current.get_field(name) };
657 if !v.is_null() { map.insert(Arc::from(name.as_str()), v); }
658 }
659 ObjField::Kv { key, val, optional, cond } => {
660 if let Some(c) = cond {
661 if !is_truthy(&eval(c, env)?) { continue; }
662 }
663 let v = eval(val, env)?;
664 if *optional && v.is_null() { continue; }
665 map.insert(Arc::from(key.as_str()), v);
666 }
667 ObjField::Dynamic { key, val } => {
668 let k: Arc<str> = Arc::from(val_to_key(&eval(key, env)?).as_str());
669 map.insert(k, eval(val, env)?);
670 }
671 ObjField::Spread(expr) => {
672 if let Val::Obj(other) = eval(expr, env)? {
673 let entries = Arc::try_unwrap(other).unwrap_or_else(|m| (*m).clone());
674 for (k, v) in entries { map.insert(k, v); }
675 }
676 }
677 ObjField::SpreadDeep(expr) => {
678 if let Val::Obj(other) = eval(expr, env)? {
679 let base = std::mem::take(&mut map);
680 let merged = deep_merge_concat(Val::obj(base), Val::Obj(other));
681 if let Val::Obj(m) = merged {
682 map = Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone());
683 }
684 }
685 }
686 }
687 }
688 Ok(Val::obj(map))
689}
690
691fn eval_fstring(parts: &[FStringPart], env: &Env) -> Result<Val, EvalError> {
694 let mut out = String::new();
695 for part in parts {
696 match part {
697 FStringPart::Lit(s) => out.push_str(s),
698 FStringPart::Interp { expr, fmt } => {
699 let val = eval(expr, env)?;
700 let s = match fmt {
701 None => val_to_string(&val),
702 Some(FmtSpec::Spec(spec)) => apply_fmt_spec(&val, spec),
703 Some(FmtSpec::Pipe(method)) => {
704 val_to_string(&dispatch_method(val, method, &[], env)?)
705 }
706 };
707 out.push_str(&s);
708 }
709 }
710 }
711 Ok(Val::Str(Arc::from(out.as_str())))
712}
713
714fn apply_fmt_spec(val: &Val, spec: &str) -> String {
715 if let Some(rest) = spec.strip_suffix('f') {
716 if let Some(prec_str) = rest.strip_prefix('.') {
717 if let Ok(prec) = prec_str.parse::<usize>() {
718 if let Some(f) = val.as_f64() { return format!("{:.prec$}", f); }
719 }
720 }
721 }
722 if spec == "d" {
723 if let Some(i) = val.as_i64() { return format!("{}", i); }
724 }
725 let s = val_to_string(val);
726 if let Some(w) = spec.strip_prefix('>').and_then(|s| s.parse::<usize>().ok()) { return format!("{:>w$}", s); }
727 if let Some(w) = spec.strip_prefix('<').and_then(|s| s.parse::<usize>().ok()) { return format!("{:<w$}", s); }
728 if let Some(w) = spec.strip_prefix('^').and_then(|s| s.parse::<usize>().ok()) { return format!("{:^w$}", s); }
729 if let Some(w) = spec.strip_prefix('0').and_then(|s| s.parse::<usize>().ok()) {
730 if let Some(i) = val.as_i64() { return format!("{:0>w$}", i); }
731 }
732 s
733}
734
735fn eval_binop(l: &Expr, op: BinOp, r: &Expr, env: &Env) -> Result<Val, EvalError> {
738 match op {
739 BinOp::And => {
740 let lv = eval(l, env)?;
741 if !is_truthy(&lv) { return Ok(Val::Bool(false)); }
742 Ok(Val::Bool(is_truthy(&eval(r, env)?)))
743 }
744 BinOp::Or => {
745 let lv = eval(l, env)?;
746 if is_truthy(&lv) { return Ok(lv); }
747 eval(r, env)
748 }
749 _ => {
750 let lv = eval(l, env)?;
751 let rv = eval(r, env)?;
752 match op {
753 BinOp::Add => add_vals(lv, rv),
754 BinOp::Sub => num_op(lv, rv, |a, b| a - b, |a, b| a - b),
755 BinOp::Mul => num_op(lv, rv, |a, b| a * b, |a, b| a * b),
756 BinOp::Div => {
757 let b = rv.as_f64().unwrap_or(0.0);
758 if b == 0.0 { return err!("division by zero"); }
759 Ok(Val::Float(lv.as_f64().unwrap_or(0.0) / b))
760 }
761 BinOp::Mod => num_op(lv, rv, |a, b| a % b, |a, b| a % b),
762 BinOp::Eq => Ok(Val::Bool(vals_eq(&lv, &rv))),
763 BinOp::Neq => Ok(Val::Bool(!vals_eq(&lv, &rv))),
764 BinOp::Lt => Ok(Val::Bool(cmp_vals(&lv, &rv) == std::cmp::Ordering::Less)),
765 BinOp::Lte => Ok(Val::Bool(cmp_vals(&lv, &rv) != std::cmp::Ordering::Greater)),
766 BinOp::Gt => Ok(Val::Bool(cmp_vals(&lv, &rv) == std::cmp::Ordering::Greater)),
767 BinOp::Gte => Ok(Val::Bool(cmp_vals(&lv, &rv) != std::cmp::Ordering::Less)),
768 BinOp::Fuzzy => {
769 let ls = match &lv { Val::Str(s) => s.to_lowercase(), _ => val_to_string(&lv).to_lowercase() };
770 let rs = match &rv { Val::Str(s) => s.to_lowercase(), _ => val_to_string(&rv).to_lowercase() };
771 Ok(Val::Bool(ls.contains(&rs) || rs.contains(&ls)))
772 }
773 BinOp::And | BinOp::Or => unreachable!(),
774 }
775 }
776 }
777}
778
779fn eval_global(name: &str, args: &[Arg], env: &Env) -> Result<Val, EvalError> {
782 match name {
783 "coalesce" => {
784 for arg in args {
785 let v = eval_pos(arg, env)?;
786 if !v.is_null() { return Ok(v); }
787 }
788 Ok(Val::Null)
789 }
790 "chain" | "join" => {
791 let mut out = Vec::new();
792 for arg in args {
793 match eval_pos(arg, env)? {
794 Val::Arr(a) => {
795 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
796 out.extend(items);
797 }
798 v => out.push(v),
799 }
800 }
801 Ok(Val::arr(out))
802 }
803 "zip" => func_arrays::global_zip(args, env),
804 "zip_longest" => func_arrays::global_zip_longest(args, env),
805 "product" => func_arrays::global_product(args, env),
806 other => {
807 if let Some(first) = args.first() {
808 let recv = eval_pos(first, env)?;
809 dispatch_method(recv, other, args.get(1..).unwrap_or(&[]), env)
810 } else {
811 dispatch_method(env.current.clone(), other, &[], env)
812 }
813 }
814 }
815}
816
817pub(super) fn apply_item(item: Val, arg: &Arg, env: &Env) -> Result<Val, EvalError> {
820 match arg {
821 Arg::Pos(expr) | Arg::Named(_, expr) => apply_expr_item(item, expr, env),
822 }
823}
824
825pub(super) fn apply_item2(a: Val, b: Val, arg: &Arg, env: &Env) -> Result<Val, EvalError> {
826 match arg {
827 Arg::Pos(Expr::Lambda { params, body }) | Arg::Named(_, Expr::Lambda { params, body }) => {
828 let inner = match params.as_slice() {
829 [] => env.with_current(b),
830 [p] => env.with_var(p, b),
831 [p1, p2, ..] => env.with_vars2(p1, a, p2, b),
832 };
833 eval(body, &inner)
834 }
835 _ => apply_item(b, arg, env),
836 }
837}
838
839fn apply_expr_item(item: Val, expr: &Expr, env: &Env) -> Result<Val, EvalError> {
840 match expr {
841 Expr::Lambda { params, body } => {
842 let inner = if params.is_empty() {
843 env.with_current(item)
844 } else {
845 let mut e = env.with_var(¶ms[0], item.clone());
846 e.current = item;
847 e
848 };
849 eval(body, &inner)
850 }
851 _ => eval(expr, &env.with_current(item)),
852 }
853}
854
855pub(super) fn eval_pos(arg: &Arg, env: &Env) -> Result<Val, EvalError> {
856 match arg { Arg::Pos(e) | Arg::Named(_, e) => eval(e, env) }
857}
858
859pub(super) fn first_i64_arg(args: &[Arg], env: &Env) -> Result<i64, EvalError> {
860 args.first()
861 .map(|a| eval_pos(a, env)?.as_i64().ok_or_else(|| EvalError("expected integer arg".into())))
862 .transpose()
863 .map(|v| v.unwrap_or(1))
864}
865
866pub(super) fn str_arg(args: &[Arg], idx: usize, env: &Env) -> Result<String, EvalError> {
867 args.get(idx)
868 .map(|a| eval_pos(a, env))
869 .transpose()?
870 .map(|v| val_to_string(&v))
871 .ok_or_else(|| EvalError(format!("missing string arg at position {}", idx)))
872}
873
874fn eval_iter(iter: &Expr, env: &Env) -> Result<Vec<Val>, EvalError> {
877 match eval(iter, env)? {
878 Val::Arr(a) => Ok(Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone())),
879 Val::Obj(m) => {
880 let entries = Arc::try_unwrap(m).unwrap_or_else(|m| (*m).clone());
881 Ok(entries.into_iter().map(|(k, v)| {
882 let mut o: IndexMap<Arc<str>, Val> = IndexMap::new();
883 o.insert(Arc::from("key"), Val::Str(k));
884 o.insert(Arc::from("value"), v);
885 Val::obj(o)
886 }).collect())
887 }
888 other => Ok(vec![other]),
889 }
890}
891
892fn bind_vars(env: &Env, vars: &[String], item: Val) -> Env {
893 match vars {
894 [] => env.with_current(item),
895 [v] => { let mut e = env.with_var(v, item.clone()); e.current = item; e }
896 [v1, v2, ..] => {
897 let idx = item.get("index").cloned().unwrap_or(Val::Null);
898 let val = item.get("value").cloned().unwrap_or_else(|| item.clone());
899 let mut e = env.with_vars2(v1, idx, v2, val.clone());
900 e.current = val;
901 e
902 }
903 }
904}