1use std::collections::HashMap;
4use std::sync::Arc;
5
6use crate::array::{Array, Data};
7use crate::error::{Error, ErrorKind, Result, Span};
8use crate::fmt::{format_array, FmtOpts};
9use crate::frontend::Rules;
10use crate::fuse::FusedKernel;
11use crate::verb::{arrays_match, Agreement, Ctx, Env, EvalCfg, Verb};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub enum Scope {
17 Local,
20 Global,
22 LocalDefault,
25}
26
27#[derive(Clone, Debug)]
28pub enum Expr {
29 Const(Array, Span),
30 Param(usize, Span),
32 Name(String, Span),
34 Assign { name: String, value: Box<Expr>, scope: Scope, span: Span },
37 AmendIndex {
41 name: String,
42 slots: Vec<Option<Expr>>,
43 value: Box<Expr>,
44 origin: i64,
45 scope: Scope,
46 span: Span,
47 },
48 Control(Box<Control>, Span),
53 Monad { verb: Verb, y: Box<Expr>, span: Span },
54 Dyad { verb: Verb, x: Box<Expr>, y: Box<Expr>, span: Span },
55 PrintPass { value: Box<Expr>, bare: bool, span: Span },
59 Input { eval: bool, span: Span },
63 Fused { kernel: FusedKernel, inputs: Vec<Expr>, orig: Box<Expr>, span: Span },
67 Elided { orig: Vec<Expr>, span: Span },
72 VerbDef { name: String, verb: Verb, span: Span },
77 ModDef { name: String, spelling: String, conjunction: bool, span: Span },
82}
83
84#[derive(Clone, Debug)]
87pub enum Control {
88 If { arms: Vec<Branch>, otherwise: Option<Vec<Expr>> },
91 While { test: Vec<Expr>, body: Vec<Expr>, body_first: bool, until: bool },
94 For { name: Option<String>, source: Box<Expr>, body: Vec<Expr> },
97 Select { subject: Box<Expr>, cases: Vec<Branch> },
100 Try { body: Vec<Expr>, catch: Vec<Expr> },
103 Return,
105 Break,
107 Branch(Box<Expr>),
111 Continue,
113}
114
115#[derive(Clone, Debug)]
118pub struct Branch {
119 pub test: Option<Vec<Expr>>,
120 pub body: Vec<Expr>,
121 pub fall_through: bool,
123}
124
125pub const NILADIC: &str = "(no argument)";
129
130#[derive(Debug)]
133pub struct ExplicitDef {
134 pub name: String,
136 pub left: Option<String>,
139 pub right: String,
140 pub dyad_only: bool,
145 pub result: Option<String>,
148 pub locals: Vec<String>,
150 pub body: Vec<Expr>,
151 pub empty: Option<Array>,
153 pub labels: Vec<(String, usize)>,
157 pub pure: bool,
159}
160
161impl Expr {
162 pub(crate) fn depth(&self) -> usize {
166 let mut deepest = 0usize;
167 let mut stack: Vec<(&Expr, usize)> = vec![(self, 1)];
168 while let Some((e, d)) = stack.pop() {
169 deepest = deepest.max(d);
170 let kids: Vec<&Expr> = match e {
171 Expr::Const(..)
172 | Expr::Param(..)
173 | Expr::Name(..)
174 | Expr::Control(..)
175 | Expr::VerbDef { .. }
176 | Expr::Input { .. }
177 | Expr::ModDef { .. } => Vec::new(),
178 Expr::Assign { value, .. } | Expr::PrintPass { value, .. } => vec![value],
179 Expr::AmendIndex { slots, value, .. } => {
180 slots.iter().flatten().chain(std::iter::once(&**value)).collect()
181 }
182 Expr::Monad { y, .. } => vec![y],
183 Expr::Dyad { x, y, .. } => vec![x, y],
184 Expr::Fused { inputs, orig, .. } => {
185 inputs.iter().chain(std::iter::once(&**orig)).collect()
186 }
187 Expr::Elided { orig, .. } => orig.iter().collect(),
188 };
189 stack.extend(kids.into_iter().map(|c| (c, d + 1)));
190 }
191 deepest
192 }
193
194 pub fn span(&self) -> Span {
195 match self {
196 Expr::Const(_, s) | Expr::Param(_, s) | Expr::Name(_, s) => *s,
197 Expr::Control(_, s) => *s,
198 Expr::AmendIndex { span, .. } | Expr::Input { span, .. } => *span,
199 Expr::Assign { span, .. }
200 | Expr::Monad { span, .. }
201 | Expr::Dyad { span, .. }
202 | Expr::PrintPass { span, .. }
203 | Expr::Fused { span, .. }
204 | Expr::Elided { span, .. }
205 | Expr::VerbDef { span, .. }
206 | Expr::ModDef { span, .. } => *span,
207 }
208 }
209
210 pub fn set_span(&mut self, to: Span) {
214 match self {
215 Expr::Const(_, s) | Expr::Param(_, s) | Expr::Name(_, s) => *s = to,
216 Expr::Control(_, s) => *s = to,
217 Expr::AmendIndex { span, .. } | Expr::Input { span, .. } => *span = to,
218 Expr::Assign { span, .. }
219 | Expr::Monad { span, .. }
220 | Expr::Dyad { span, .. }
221 | Expr::PrintPass { span, .. }
222 | Expr::Fused { span, .. }
223 | Expr::Elided { span, .. }
224 | Expr::VerbDef { span, .. }
225 | Expr::ModDef { span, .. } => *span = to,
226 }
227 }
228
229 fn is_silent(&self) -> bool {
233 matches!(
234 self,
235 Expr::Assign { .. }
236 | Expr::AmendIndex { .. }
237 | Expr::PrintPass { .. }
238 | Expr::Elided { .. }
239 | Expr::VerbDef { .. }
240 | Expr::ModDef { .. }
241 )
242 }
243}
244
245#[derive(Clone, Debug)]
246pub struct ParamSpec {
247 pub name: String,
248}
249
250#[derive(Clone, Debug)]
252pub struct Program {
253 pub stmts: Vec<Expr>,
254 pub params: Vec<ParamSpec>,
255 pub display_src: String,
258 pub agreement: Agreement,
259 pub fmt: FmtOpts,
260 pub rules: Rules,
262}
263
264#[derive(Clone, Debug)]
266pub(crate) struct Note {
267 pub shape: Vec<usize>,
268 pub dtype: crate::dtype::DType,
269 pub layout: crate::array::Layout,
272 pub kernel_ran: Option<bool>,
275 pub decline: Option<crate::fuse::Decline>,
276 pub placement: crate::device::Placement,
279}
280
281pub(crate) type Trace = HashMap<usize, Note>;
285
286pub(crate) fn key(e: &Expr) -> usize {
287 std::ptr::from_ref(e) as usize
288}
289
290impl Program {
291 pub fn run(&self, args: &[Array], out: &mut dyn FnMut(&str)) -> Result<Option<Array>> {
298 self.exec(args, out, None, &mut None, None)
299 }
300
301 pub fn run_io(
305 &self,
306 args: &[Array],
307 out: &mut dyn FnMut(&str),
308 inp: &mut dyn FnMut() -> Option<String>,
309 ) -> Result<Option<Array>> {
310 self.exec(args, out, Some(inp), &mut None, None)
311 }
312
313 pub fn run_on_io(
315 &self,
316 device: &crate::device::Device,
317 args: &[Array],
318 out: &mut dyn FnMut(&str),
319 inp: &mut dyn FnMut() -> Option<String>,
320 ) -> Result<Option<Array>> {
321 self.exec(args, out, Some(inp), &mut None, Some(device))
322 }
323
324 pub fn run_on(
330 &self,
331 device: &crate::device::Device,
332 args: &[Array],
333 out: &mut dyn FnMut(&str),
334 ) -> Result<Option<Array>> {
335 self.exec(args, out, None, &mut None, Some(device))
336 }
337
338 pub(crate) fn trace(
342 &self,
343 args: &[Array],
344 out: &mut dyn FnMut(&str),
345 device: Option<&crate::device::Device>,
346 ) -> (Result<Option<Array>>, Trace) {
347 let mut rec = Some(Trace::new());
348 let r = self.exec(args, out, None, &mut rec, device);
349 (r, rec.expect("the recorder stays in place"))
350 }
351
352 fn exec(
353 &self,
354 args: &[Array],
355 out: &mut dyn FnMut(&str),
356 inp: crate::verb::InputFn<'_>,
357 rec: &mut Option<Trace>,
358 device: Option<&crate::device::Device>,
359 ) -> Result<Option<Array>> {
360 if args.len() != self.params.len() {
361 let names: Vec<&str> = self.params.iter().map(|p| p.name.as_str()).collect();
362 let wanted = if names.is_empty() {
363 "no arguments".to_string()
364 } else {
365 format!("one value for each of {}", names.join(", "))
366 };
367 return Err(Error::new(
368 ErrorKind::Value,
369 format!("this program takes {wanted}, and was given {}", args.len()),
370 None,
371 ));
372 }
373 let cfg = EvalCfg {
374 agreement: self.agreement,
375 fmt: self.fmt,
376 tol: self.rules.tol(),
377 rules: self.rules,
378 };
379 let mut env = Env::new(args.to_vec());
380 let mut inp = inp;
381 let inp = crate::verb::reborrow_input(&mut inp);
382 let mut ctx = Ctx { cfg, out, inp, env: &mut env, device };
383 let mut last = None;
384 for stmt in &self.stmts {
385 let (v, flow) = eval_stmt(stmt, &mut ctx, rec)?;
388 if flow != Flow::Normal {
389 return Err(Error::internal("a control signal escaped to the top level"));
390 }
391 last = if stmt.is_silent() { None } else { v };
392 }
393 Ok(last)
394 }
395
396 pub fn render_error(&self, e: &Error) -> String {
397 e.render(&self.display_src)
398 }
399
400 pub fn explain(&self, args: Option<&[Array]>) -> String {
410 crate::explain::explain(self, args, None)
411 }
412
413 pub fn explain_on(
417 &self,
418 device: &crate::device::Device,
419 args: Option<&[Array]>,
420 ) -> String {
421 crate::explain::explain(self, args, Some(device))
422 }
423}
424
425#[derive(Clone, Copy, Debug, PartialEq, Eq)]
427pub(crate) enum Flow {
428 Normal,
429 Return,
430 Break,
431 Continue,
432 Goto(usize),
434}
435
436pub(crate) fn run_block(
440 stmts: &[Expr],
441 last: Option<Array>,
442 ctx: &mut Ctx<'_>,
443 rec: &mut Option<Trace>,
444) -> Result<(Option<Array>, Flow)> {
445 let mut last = last;
446 for stmt in stmts {
447 let (v, flow) = eval_stmt(stmt, ctx, rec)?;
448 if let Some(v) = v {
451 last = Some(v);
452 }
453 if flow != Flow::Normal {
454 return Ok((last, flow));
455 }
456 }
457 Ok((last, Flow::Normal))
458}
459
460fn eval_stmt(
463 e: &Expr,
464 ctx: &mut Ctx<'_>,
465 rec: &mut Option<Trace>,
466) -> Result<(Option<Array>, Flow)> {
467 let Expr::Control(c, span) = e else {
468 return Ok((Some(eval(e, ctx, rec)?), Flow::Normal));
469 };
470 let (v, flow) = eval_control(c, *span, ctx, rec)?;
471 let v = match (v, flow) {
476 (Some(v), _) => Some(v),
477 (None, Flow::Normal) => ctx.env.current_def().and_then(|d| d.empty.clone()),
478 (None, _) => None,
479 };
480 if let (Some(t), Some(v)) = (rec.as_mut(), v.as_ref()) {
481 t.insert(
482 key(e),
483 Note {
484 shape: v.shape.clone(),
485 dtype: v.dtype(),
486 layout: v.layout(),
487 kernel_ran: None,
488 decline: None,
489 placement: crate::device::Placement::Default,
490 },
491 );
492 }
493 Ok((v, flow))
494}
495
496pub(crate) fn empty_result() -> Array {
498 Array::new(vec![0, 0], Data::I64(Vec::new().into()))
499}
500
501fn is_true(a: &Array, span: Span) -> Result<bool> {
504 if a.count() == 0 {
505 return Ok(true);
506 }
507 match &a.data {
508 Data::I64(v) => Ok(v.as_slice()[0] != 0),
509 Data::F64(v) => Ok(v.as_slice()[0] != 0.0),
510 Data::Bool(v) => Ok(v.as_slice()[0] != 0),
511 Data::Char(v) => Ok(v.as_slice()[0] as u32 != 0),
512 Data::Complex(v) => Ok(v.as_slice()[0] != crate::complex::ZERO),
513 Data::Ext(v) => Ok(v.as_slice()[0] != crate::exact::Ext::default()),
514 Data::Rat(v) => Ok(!v.as_slice()[0].is_zero()),
515 Data::Box(_) => Err(Error::domain("a condition must be numeric, not boxed", span)),
516 Data::Symbol(_) => {
517 Err(Error::domain("a condition must be numeric, not a symbol", span))
518 }
519 }
520}
521
522fn eval_control(
523 c: &Control,
524 span: Span,
525 ctx: &mut Ctx<'_>,
526 rec: &mut Option<Trace>,
527) -> Result<(Option<Array>, Flow)> {
528 match c {
529 Control::Return => Ok((None, Flow::Return)),
530 Control::Branch(target) => {
533 let to = eval(target, ctx, rec)?;
534 if to.count() == 0 {
535 return Ok((None, Flow::Normal));
536 }
537 let line = to
538 .to_i64_vec()
539 .and_then(|v| v.first().copied())
540 .ok_or_else(|| Error::domain("a branch target is a line number", span))?;
541 let lines = ctx.env.current_def().map_or(0, |d| d.body.len() as i64);
542 if line >= 1 && line <= lines {
543 return Ok((None, Flow::Goto(line as usize - 1)));
544 }
545 Ok((None, Flow::Return))
546 }
547 Control::Break => Ok((None, Flow::Break)),
548 Control::Continue => Ok((None, Flow::Continue)),
549 Control::If { arms, otherwise } => {
550 for arm in arms {
551 let test = arm.test.as_deref().unwrap_or(&[]);
552 let (t, flow) = run_block(test, None, ctx, rec)?;
553 if flow != Flow::Normal {
554 return Ok((t, flow));
555 }
556 let taken = match &t {
557 Some(v) => is_true(v, span)?,
558 None => true,
559 };
560 if taken {
561 return run_block(&arm.body, None, ctx, rec);
562 }
563 }
564 match otherwise {
565 Some(body) => run_block(body, None, ctx, rec),
566 None => Ok((None, Flow::Normal)),
567 }
568 }
569 Control::While { test, body, body_first, until } => {
570 let mut last = None;
571 let mut first = *body_first;
572 loop {
573 if !first {
574 let (t, flow) = run_block(test, None, ctx, rec)?;
575 if flow != Flow::Normal {
576 return Ok((t, flow));
577 }
578 let mut go = match &t {
579 Some(v) => is_true(v, span)?,
580 None => false,
581 };
582 if *until {
583 go = !go;
584 }
585 if !go {
586 return Ok((last, Flow::Normal));
587 }
588 }
589 first = false;
590 let (v, flow) = run_block(body, last, ctx, rec)?;
591 last = v;
592 match flow {
593 Flow::Normal | Flow::Continue => {}
594 Flow::Break => return Ok((last, Flow::Normal)),
595 other => return Ok((last, other)),
598 }
599 }
600 }
601 Control::For { name, source, body } => {
602 let src = eval(source, ctx, rec)?;
603 let n = if src.rank() == 0 { 1 } else { src.shape[0] };
604 let mut last = None;
605 for i in 0..n {
606 if let Some(name) = name {
607 let item = if src.rank() == 0 { src.clone() } else { src.item(i) };
608 ctx.env.assign(name.clone(), item, Scope::Local);
609 ctx.env.assign(
610 format!("{name}_index"),
611 Array::scalar_i64(i as i64),
612 Scope::Local,
613 );
614 }
615 let (v, flow) = run_block(body, last, ctx, rec)?;
616 last = v;
617 match flow {
618 Flow::Normal | Flow::Continue => {}
619 Flow::Break => return Ok((last, Flow::Normal)),
620 other => return Ok((last, other)),
623 }
624 }
625 Ok((last, Flow::Normal))
626 }
627 Control::Select { subject, cases } => {
628 let subject = eval(subject, ctx, rec)?;
629 let tol = ctx.cfg.tol;
630 let mut running = false;
631 let mut last = None;
632 for case in cases {
633 if !running {
634 match &case.test {
635 None => running = true,
636 Some(test) => {
637 let (t, flow) = run_block(test, None, ctx, rec)?;
638 if flow != Flow::Normal {
639 return Ok((t, flow));
640 }
641 running = t.is_some_and(|v| arrays_match(&subject, &v, tol));
644 }
645 }
646 }
647 if running {
648 let (v, flow) = run_block(&case.body, last, ctx, rec)?;
649 last = v;
650 if flow != Flow::Normal {
651 return Ok((last, flow));
652 }
653 if !case.fall_through {
654 return Ok((last, Flow::Normal));
655 }
656 running = true;
658 }
659 }
660 Ok((last, Flow::Normal))
661 }
662 Control::Try { body, catch } => {
663 match run_block(body, None, ctx, rec) {
667 Ok(r) => Ok(r),
668 Err(e) if matches!(e.kind, ErrorKind::NotYet | ErrorKind::Internal) => Err(e),
669 Err(_) => run_block(catch, None, ctx, rec),
670 }
671 }
672 }
673}
674
675pub(crate) fn call_explicit(
677 def: &Arc<ExplicitDef>,
678 x: Option<&Array>,
679 y: &Array,
680 ctx: &mut Ctx<'_>,
681 span: Span,
682) -> Result<Array> {
683 if x.is_some() && def.left.is_none() {
684 return Err(Error::new(
685 ErrorKind::Domain,
686 format!("{} has no dyadic definition", def.name),
687 Some(span),
688 ));
689 }
690 if x.is_none() && def.dyad_only {
691 return Err(Error::new(
692 ErrorKind::Domain,
693 format!(
694 "{} has no monadic definition: it names {}",
695 def.name,
696 def.left.as_deref().unwrap_or("a left argument")
697 ),
698 Some(span),
699 ));
700 }
701 let mut frame: HashMap<String, Array> = HashMap::new();
702 frame.insert(def.right.clone(), y.clone());
703 if let (Some(name), Some(v)) = (&def.left, x) {
704 frame.insert(name.clone(), v.clone());
705 }
706 for (label, at) in &def.labels {
708 frame.insert(label.clone(), Array::scalar_i64(*at as i64 + 1));
709 }
710 ctx.env.enter(frame, Arc::clone(def), span)?;
711 let mut rec = None;
712 let out = run_body(&def.body, ctx, &mut rec);
713 let frame = ctx.env.leave();
714 let value = out?;
715 if let Some(name) = &def.result {
718 return frame.get(name).cloned().ok_or_else(|| {
719 Error::new(
720 ErrorKind::Value,
721 format!("{} did not set its result {name}", def.name),
722 Some(span),
723 )
724 });
725 }
726 match value {
727 Some(v) => Ok(v),
728 None => def.empty.clone().ok_or_else(|| {
729 Error::new(
730 ErrorKind::Value,
731 format!("{} produced no result", def.name),
732 Some(span),
733 )
734 }),
735 }
736}
737
738const BRANCH_LIMIT: usize = 1 << 22;
741
742fn run_body(
745 stmts: &[Expr],
746 ctx: &mut Ctx<'_>,
747 rec: &mut Option<Trace>,
748) -> Result<Option<Array>> {
749 let mut last = None;
750 let mut at = 0usize;
751 let mut steps = 0usize;
752 while at < stmts.len() {
753 steps += 1;
754 if steps > BRANCH_LIMIT {
755 return Err(Error::new(
756 ErrorKind::Domain,
757 format!("a definition branched more than {BRANCH_LIMIT} times"),
758 Some(stmts[at].span()),
759 )
760 .note("a loop written with → needs a branch that leaves it"));
761 }
762 let (v, flow) = eval_stmt(&stmts[at], ctx, rec)?;
763 if let Some(v) = v {
764 last = Some(v);
765 }
766 match flow {
767 Flow::Normal => at += 1,
768 Flow::Goto(to) => at = to,
769 _ => break,
770 }
771 }
772 Ok(last)
773}
774
775pub(crate) fn fold_const(e: &Expr, cfg: EvalCfg) -> Option<Array> {
780 fn closed(e: &Expr) -> bool {
781 match e {
782 Expr::Const(..) => true,
783 Expr::Monad { verb, y, .. } => verb.is_pure() && closed(y),
784 Expr::Dyad { verb, x, y, .. } => verb.is_pure() && closed(x) && closed(y),
785 _ => false,
786 }
787 }
788 if !closed(e) {
789 return None;
790 }
791 cfg.pure(|ctx| eval(e, ctx, &mut None).ok())
792}
793
794fn eval(e: &Expr, ctx: &mut Ctx<'_>, rec: &mut Option<Trace>) -> Result<Array> {
795 let _depth = crate::verb::Nesting::enter(e.span())?;
798 let v = eval_node(e, ctx, rec)?;
799 if let Some(t) = rec.as_mut() {
800 let (kernel_ran, decline, placement) = t.get(&key(e)).map_or(
802 (None, None, crate::device::Placement::Default),
803 |n| (n.kernel_ran, n.decline, n.placement.clone()),
804 );
805 t.insert(
806 key(e),
807 Note {
808 shape: v.shape.clone(),
809 dtype: v.dtype(),
810 layout: v.layout(),
811 kernel_ran,
812 decline,
813 placement,
814 },
815 );
816 }
817 Ok(v)
818}
819
820fn eval_node(e: &Expr, ctx: &mut Ctx<'_>, rec: &mut Option<Trace>) -> Result<Array> {
821 match e {
822 Expr::Const(a, _) => Ok(a.clone()),
823 Expr::Param(i, _) => ctx.env.arg(*i),
824 Expr::Name(n, span) => ctx.env.get(n).ok_or_else(|| {
825 Error::new(ErrorKind::Value, format!("undefined name: {n}"), Some(*span))
826 }),
827 Expr::Assign { name, value, scope, .. } => {
828 let v = eval(value, ctx, rec)?;
829 ctx.env.assign(name.clone(), v.clone(), *scope);
830 Ok(v)
831 }
832 Expr::AmendIndex { name, slots, value, origin, scope, span } => {
833 let base = ctx.env.get(name).ok_or_else(|| {
834 Error::new(ErrorKind::Value, format!("undefined name: {name}"), Some(*span))
835 })?;
836 let v = eval(value, ctx, rec)?;
838 let mut idx = Vec::with_capacity(slots.len());
839 for slot in slots {
840 idx.push(match slot {
841 Some(e) => Some(eval(e, ctx, rec)?),
842 None => None,
843 });
844 }
845 let out = crate::verb::amend_at(&base, &idx, &v, *origin, *span)?;
846 ctx.env.assign(name.clone(), out.clone(), *scope);
847 Ok(out)
848 }
849 Expr::Control(..) => {
852 Err(Error::internal("a control sentence appeared in expression position"))
853 }
854 Expr::Monad { verb, y, span } => {
855 let vy = eval(y, ctx, rec)?;
856 verb.monad(&vy, ctx, *span)
857 }
858 Expr::Dyad { verb, x, y, span } => {
859 let vy = eval(y, ctx, rec)?;
862 let vx = eval(x, ctx, rec)?;
863 verb.dyad(&vx, &vy, ctx, *span)
864 }
865 Expr::PrintPass { value, bare, .. } => {
866 let v = eval(value, ctx, rec)?;
867 let text = format_array(&v, &ctx.cfg.fmt);
868 (ctx.out)(&text);
869 if !bare {
872 (ctx.out)("\n");
873 }
874 Ok(v)
875 }
876 Expr::Input { eval: run_it, span } => {
879 let line = ctx.read_line(*span)?;
880 if !run_it {
881 return Ok(Array::from_chars(line.chars().collect()));
882 }
883 crate::verb::execute_source(&line, true, ctx, *span)
884 }
885 Expr::Fused { kernel, inputs, orig, .. } => {
886 let mut vals = Vec::with_capacity(inputs.len());
887 for e in inputs {
888 vals.push(eval(e, ctx, rec)?);
889 }
890 let (ran, placement) = crate::fuse::eval_on(ctx.device, kernel, &vals);
891 if let Some(t) = rec.as_mut() {
892 let decline =
893 if ran.is_none() { crate::fuse::decline_reason(kernel, &vals) } else { None };
894 t.insert(
897 key(e),
898 Note {
899 shape: Vec::new(),
900 dtype: crate::dtype::DType::I64,
901 layout: crate::array::Layout::RowMajor,
902 kernel_ran: Some(ran.is_some()),
903 decline,
904 placement,
905 },
906 );
907 }
908 match ran {
909 Some(a) => Ok(a),
910 None => {
914 let tree = crate::fuse::fallback_tree(kernel, orig, &vals);
915 let v = eval(&tree, ctx, &mut None)?;
918 Ok(crate::fuse::fallback_finish(kernel, v))
919 }
920 }
921 }
922 Expr::VerbDef { name, verb, .. } => {
925 ctx.env.define(name.clone(), verb.clone());
926 Ok(Array::scalar_i64(0))
927 }
928 Expr::Elided { .. } | Expr::ModDef { .. } => Ok(Array::scalar_i64(0)),
932 }
933}