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>, span: Span },
57 Fused { kernel: FusedKernel, inputs: Vec<Expr>, orig: Box<Expr>, span: Span },
61 Elided { orig: Vec<Expr>, span: Span },
66 VerbDef { name: String, verb: Verb, span: Span },
71}
72
73#[derive(Clone, Debug)]
76pub enum Control {
77 If { arms: Vec<Branch>, otherwise: Option<Vec<Expr>> },
80 While { test: Vec<Expr>, body: Vec<Expr>, body_first: bool, until: bool },
83 For { name: Option<String>, source: Box<Expr>, body: Vec<Expr> },
86 Select { subject: Box<Expr>, cases: Vec<Branch> },
89 Try { body: Vec<Expr>, catch: Vec<Expr> },
92 Return,
94 Break,
96 Branch(Box<Expr>),
100 Continue,
102}
103
104#[derive(Clone, Debug)]
107pub struct Branch {
108 pub test: Option<Vec<Expr>>,
109 pub body: Vec<Expr>,
110 pub fall_through: bool,
112}
113
114pub const NILADIC: &str = "(no argument)";
118
119#[derive(Debug)]
122pub struct ExplicitDef {
123 pub name: String,
125 pub left: Option<String>,
128 pub right: String,
129 pub dyad_only: bool,
134 pub result: Option<String>,
137 pub locals: Vec<String>,
139 pub body: Vec<Expr>,
140 pub empty: Option<Array>,
142 pub labels: Vec<(String, usize)>,
146 pub pure: bool,
148}
149
150impl Expr {
151 pub(crate) fn depth(&self) -> usize {
155 let mut deepest = 0usize;
156 let mut stack: Vec<(&Expr, usize)> = vec![(self, 1)];
157 while let Some((e, d)) = stack.pop() {
158 deepest = deepest.max(d);
159 let kids: Vec<&Expr> = match e {
160 Expr::Const(..)
161 | Expr::Param(..)
162 | Expr::Name(..)
163 | Expr::Control(..)
164 | Expr::VerbDef { .. } => Vec::new(),
165 Expr::Assign { value, .. } | Expr::PrintPass { value, .. } => vec![value],
166 Expr::AmendIndex { slots, value, .. } => {
167 slots.iter().flatten().chain(std::iter::once(&**value)).collect()
168 }
169 Expr::Monad { y, .. } => vec![y],
170 Expr::Dyad { x, y, .. } => vec![x, y],
171 Expr::Fused { inputs, orig, .. } => {
172 inputs.iter().chain(std::iter::once(&**orig)).collect()
173 }
174 Expr::Elided { orig, .. } => orig.iter().collect(),
175 };
176 stack.extend(kids.into_iter().map(|c| (c, d + 1)));
177 }
178 deepest
179 }
180
181 pub fn span(&self) -> Span {
182 match self {
183 Expr::Const(_, s) | Expr::Param(_, s) | Expr::Name(_, s) => *s,
184 Expr::Control(_, s) => *s,
185 Expr::AmendIndex { span, .. } => *span,
186 Expr::Assign { span, .. }
187 | Expr::Monad { span, .. }
188 | Expr::Dyad { span, .. }
189 | Expr::PrintPass { span, .. }
190 | Expr::Fused { span, .. }
191 | Expr::Elided { span, .. }
192 | Expr::VerbDef { span, .. } => *span,
193 }
194 }
195
196 pub fn set_span(&mut self, to: Span) {
200 match self {
201 Expr::Const(_, s) | Expr::Param(_, s) | Expr::Name(_, s) => *s = to,
202 Expr::Control(_, s) => *s = to,
203 Expr::AmendIndex { span, .. } => *span = to,
204 Expr::Assign { span, .. }
205 | Expr::Monad { span, .. }
206 | Expr::Dyad { span, .. }
207 | Expr::PrintPass { span, .. }
208 | Expr::Fused { span, .. }
209 | Expr::Elided { span, .. }
210 | Expr::VerbDef { span, .. } => *span = to,
211 }
212 }
213
214 fn is_silent(&self) -> bool {
218 matches!(
219 self,
220 Expr::Assign { .. }
221 | Expr::AmendIndex { .. }
222 | Expr::PrintPass { .. }
223 | Expr::Elided { .. }
224 | Expr::VerbDef { .. }
225 )
226 }
227}
228
229#[derive(Clone, Debug)]
230pub struct ParamSpec {
231 pub name: String,
232}
233
234#[derive(Clone, Debug)]
236pub struct Program {
237 pub stmts: Vec<Expr>,
238 pub params: Vec<ParamSpec>,
239 pub display_src: String,
242 pub agreement: Agreement,
243 pub fmt: FmtOpts,
244 pub rules: Rules,
246}
247
248#[derive(Clone, Debug)]
250pub(crate) struct Note {
251 pub shape: Vec<usize>,
252 pub dtype: crate::dtype::DType,
253 pub kernel_ran: Option<bool>,
256 pub decline: Option<crate::fuse::Decline>,
257 pub placement: crate::device::Placement,
260}
261
262pub(crate) type Trace = HashMap<usize, Note>;
266
267pub(crate) fn key(e: &Expr) -> usize {
268 std::ptr::from_ref(e) as usize
269}
270
271impl Program {
272 pub fn run(&self, args: &[Array], out: &mut dyn FnMut(&str)) -> Result<Option<Array>> {
275 self.exec(args, out, &mut None, None)
276 }
277
278 pub fn run_on(
284 &self,
285 device: &crate::device::Device,
286 args: &[Array],
287 out: &mut dyn FnMut(&str),
288 ) -> Result<Option<Array>> {
289 self.exec(args, out, &mut None, Some(device))
290 }
291
292 pub(crate) fn trace(
296 &self,
297 args: &[Array],
298 out: &mut dyn FnMut(&str),
299 device: Option<&crate::device::Device>,
300 ) -> (Result<Option<Array>>, Trace) {
301 let mut rec = Some(Trace::new());
302 let r = self.exec(args, out, &mut rec, device);
303 (r, rec.expect("the recorder stays in place"))
304 }
305
306 fn exec(
307 &self,
308 args: &[Array],
309 out: &mut dyn FnMut(&str),
310 rec: &mut Option<Trace>,
311 device: Option<&crate::device::Device>,
312 ) -> Result<Option<Array>> {
313 if args.len() != self.params.len() {
314 let names: Vec<&str> = self.params.iter().map(|p| p.name.as_str()).collect();
315 let wanted = if names.is_empty() {
316 "no arguments".to_string()
317 } else {
318 format!("one value for each of {}", names.join(", "))
319 };
320 return Err(Error::new(
321 ErrorKind::Value,
322 format!("this program takes {wanted}, and was given {}", args.len()),
323 None,
324 ));
325 }
326 let cfg = EvalCfg {
327 agreement: self.agreement,
328 fmt: self.fmt,
329 tol: self.rules.tol(),
330 rules: self.rules,
331 };
332 let mut env = Env::new(args.to_vec());
333 let mut ctx = Ctx { cfg, out, env: &mut env, device };
334 let mut last = None;
335 for stmt in &self.stmts {
336 let (v, flow) = eval_stmt(stmt, &mut ctx, rec)?;
339 if flow != Flow::Normal {
340 return Err(Error::internal("a control signal escaped to the top level"));
341 }
342 last = if stmt.is_silent() { None } else { v };
343 }
344 Ok(last)
345 }
346
347 pub fn render_error(&self, e: &Error) -> String {
348 e.render(&self.display_src)
349 }
350
351 pub fn explain(&self, args: Option<&[Array]>) -> String {
361 crate::explain::explain(self, args, None)
362 }
363
364 pub fn explain_on(
368 &self,
369 device: &crate::device::Device,
370 args: Option<&[Array]>,
371 ) -> String {
372 crate::explain::explain(self, args, Some(device))
373 }
374}
375
376#[derive(Clone, Copy, Debug, PartialEq, Eq)]
378pub(crate) enum Flow {
379 Normal,
380 Return,
381 Break,
382 Continue,
383 Goto(usize),
385}
386
387pub(crate) fn run_block(
391 stmts: &[Expr],
392 last: Option<Array>,
393 ctx: &mut Ctx<'_>,
394 rec: &mut Option<Trace>,
395) -> Result<(Option<Array>, Flow)> {
396 let mut last = last;
397 for stmt in stmts {
398 let (v, flow) = eval_stmt(stmt, ctx, rec)?;
399 if let Some(v) = v {
402 last = Some(v);
403 }
404 if flow != Flow::Normal {
405 return Ok((last, flow));
406 }
407 }
408 Ok((last, Flow::Normal))
409}
410
411fn eval_stmt(
414 e: &Expr,
415 ctx: &mut Ctx<'_>,
416 rec: &mut Option<Trace>,
417) -> Result<(Option<Array>, Flow)> {
418 let Expr::Control(c, span) = e else {
419 return Ok((Some(eval(e, ctx, rec)?), Flow::Normal));
420 };
421 let (v, flow) = eval_control(c, *span, ctx, rec)?;
422 let v = match (v, flow) {
427 (Some(v), _) => Some(v),
428 (None, Flow::Normal) => ctx.env.current_def().and_then(|d| d.empty.clone()),
429 (None, _) => None,
430 };
431 if let (Some(t), Some(v)) = (rec.as_mut(), v.as_ref()) {
432 t.insert(
433 key(e),
434 Note {
435 shape: v.shape.clone(),
436 dtype: v.dtype(),
437 kernel_ran: None,
438 decline: None,
439 placement: crate::device::Placement::Default,
440 },
441 );
442 }
443 Ok((v, flow))
444}
445
446pub(crate) fn empty_result() -> Array {
448 Array::new(vec![0, 0], Data::I64(Vec::new().into()))
449}
450
451fn is_true(a: &Array, span: Span) -> Result<bool> {
454 if a.count() == 0 {
455 return Ok(true);
456 }
457 match &a.data {
458 Data::I64(v) => Ok(v.as_slice()[0] != 0),
459 Data::F64(v) => Ok(v.as_slice()[0] != 0.0),
460 Data::Bool(v) => Ok(v.as_slice()[0] != 0),
461 Data::Char(v) => Ok(v.as_slice()[0] as u32 != 0),
462 Data::Complex(v) => Ok(v.as_slice()[0] != crate::complex::ZERO),
463 Data::Ext(v) => Ok(v.as_slice()[0] != crate::exact::Ext::default()),
464 Data::Rat(v) => Ok(!v.as_slice()[0].is_zero()),
465 Data::Box(_) => Err(Error::domain("a condition must be numeric, not boxed", span)),
466 }
467}
468
469fn eval_control(
470 c: &Control,
471 span: Span,
472 ctx: &mut Ctx<'_>,
473 rec: &mut Option<Trace>,
474) -> Result<(Option<Array>, Flow)> {
475 match c {
476 Control::Return => Ok((None, Flow::Return)),
477 Control::Branch(target) => {
480 let to = eval(target, ctx, rec)?;
481 if to.count() == 0 {
482 return Ok((None, Flow::Normal));
483 }
484 let line = to
485 .to_i64_vec()
486 .and_then(|v| v.first().copied())
487 .ok_or_else(|| Error::domain("a branch target is a line number", span))?;
488 let lines = ctx.env.current_def().map_or(0, |d| d.body.len() as i64);
489 if line >= 1 && line <= lines {
490 return Ok((None, Flow::Goto(line as usize - 1)));
491 }
492 Ok((None, Flow::Return))
493 }
494 Control::Break => Ok((None, Flow::Break)),
495 Control::Continue => Ok((None, Flow::Continue)),
496 Control::If { arms, otherwise } => {
497 for arm in arms {
498 let test = arm.test.as_deref().unwrap_or(&[]);
499 let (t, flow) = run_block(test, None, ctx, rec)?;
500 if flow != Flow::Normal {
501 return Ok((t, flow));
502 }
503 let taken = match &t {
504 Some(v) => is_true(v, span)?,
505 None => true,
506 };
507 if taken {
508 return run_block(&arm.body, None, ctx, rec);
509 }
510 }
511 match otherwise {
512 Some(body) => run_block(body, None, ctx, rec),
513 None => Ok((None, Flow::Normal)),
514 }
515 }
516 Control::While { test, body, body_first, until } => {
517 let mut last = None;
518 let mut first = *body_first;
519 loop {
520 if !first {
521 let (t, flow) = run_block(test, None, ctx, rec)?;
522 if flow != Flow::Normal {
523 return Ok((t, flow));
524 }
525 let mut go = match &t {
526 Some(v) => is_true(v, span)?,
527 None => false,
528 };
529 if *until {
530 go = !go;
531 }
532 if !go {
533 return Ok((last, Flow::Normal));
534 }
535 }
536 first = false;
537 let (v, flow) = run_block(body, last, ctx, rec)?;
538 last = v;
539 match flow {
540 Flow::Normal | Flow::Continue => {}
541 Flow::Break => return Ok((last, Flow::Normal)),
542 other => return Ok((last, other)),
545 }
546 }
547 }
548 Control::For { name, source, body } => {
549 let src = eval(source, ctx, rec)?;
550 let n = if src.rank() == 0 { 1 } else { src.shape[0] };
551 let mut last = None;
552 for i in 0..n {
553 if let Some(name) = name {
554 let item = if src.rank() == 0 { src.clone() } else { src.item(i) };
555 ctx.env.assign(name.clone(), item, Scope::Local);
556 ctx.env.assign(
557 format!("{name}_index"),
558 Array::scalar_i64(i as i64),
559 Scope::Local,
560 );
561 }
562 let (v, flow) = run_block(body, last, ctx, rec)?;
563 last = v;
564 match flow {
565 Flow::Normal | Flow::Continue => {}
566 Flow::Break => return Ok((last, Flow::Normal)),
567 other => return Ok((last, other)),
570 }
571 }
572 Ok((last, Flow::Normal))
573 }
574 Control::Select { subject, cases } => {
575 let subject = eval(subject, ctx, rec)?;
576 let tol = ctx.cfg.tol;
577 let mut running = false;
578 let mut last = None;
579 for case in cases {
580 if !running {
581 match &case.test {
582 None => running = true,
583 Some(test) => {
584 let (t, flow) = run_block(test, None, ctx, rec)?;
585 if flow != Flow::Normal {
586 return Ok((t, flow));
587 }
588 running = t.is_some_and(|v| arrays_match(&subject, &v, tol));
591 }
592 }
593 }
594 if running {
595 let (v, flow) = run_block(&case.body, last, ctx, rec)?;
596 last = v;
597 if flow != Flow::Normal {
598 return Ok((last, flow));
599 }
600 if !case.fall_through {
601 return Ok((last, Flow::Normal));
602 }
603 running = true;
605 }
606 }
607 Ok((last, Flow::Normal))
608 }
609 Control::Try { body, catch } => {
610 match run_block(body, None, ctx, rec) {
614 Ok(r) => Ok(r),
615 Err(e) if matches!(e.kind, ErrorKind::NotYet | ErrorKind::Internal) => Err(e),
616 Err(_) => run_block(catch, None, ctx, rec),
617 }
618 }
619 }
620}
621
622pub(crate) fn call_explicit(
624 def: &Arc<ExplicitDef>,
625 x: Option<&Array>,
626 y: &Array,
627 ctx: &mut Ctx<'_>,
628 span: Span,
629) -> Result<Array> {
630 if x.is_some() && def.left.is_none() {
631 return Err(Error::new(
632 ErrorKind::Domain,
633 format!("{} has no dyadic definition", def.name),
634 Some(span),
635 ));
636 }
637 if x.is_none() && def.dyad_only {
638 return Err(Error::new(
639 ErrorKind::Domain,
640 format!(
641 "{} has no monadic definition: it names {}",
642 def.name,
643 def.left.as_deref().unwrap_or("a left argument")
644 ),
645 Some(span),
646 ));
647 }
648 let mut frame: HashMap<String, Array> = HashMap::new();
649 frame.insert(def.right.clone(), y.clone());
650 if let (Some(name), Some(v)) = (&def.left, x) {
651 frame.insert(name.clone(), v.clone());
652 }
653 for (label, at) in &def.labels {
655 frame.insert(label.clone(), Array::scalar_i64(*at as i64 + 1));
656 }
657 ctx.env.enter(frame, Arc::clone(def), span)?;
658 let mut rec = None;
659 let out = run_body(&def.body, ctx, &mut rec);
660 let frame = ctx.env.leave();
661 let value = out?;
662 if let Some(name) = &def.result {
665 return frame.get(name).cloned().ok_or_else(|| {
666 Error::new(
667 ErrorKind::Value,
668 format!("{} did not set its result {name}", def.name),
669 Some(span),
670 )
671 });
672 }
673 match value {
674 Some(v) => Ok(v),
675 None => def.empty.clone().ok_or_else(|| {
676 Error::new(
677 ErrorKind::Value,
678 format!("{} produced no result", def.name),
679 Some(span),
680 )
681 }),
682 }
683}
684
685const BRANCH_LIMIT: usize = 1 << 22;
688
689fn run_body(
692 stmts: &[Expr],
693 ctx: &mut Ctx<'_>,
694 rec: &mut Option<Trace>,
695) -> Result<Option<Array>> {
696 let mut last = None;
697 let mut at = 0usize;
698 let mut steps = 0usize;
699 while at < stmts.len() {
700 steps += 1;
701 if steps > BRANCH_LIMIT {
702 return Err(Error::new(
703 ErrorKind::Domain,
704 format!("a definition branched more than {BRANCH_LIMIT} times"),
705 Some(stmts[at].span()),
706 )
707 .note("a loop written with → needs a branch that leaves it"));
708 }
709 let (v, flow) = eval_stmt(&stmts[at], ctx, rec)?;
710 if let Some(v) = v {
711 last = Some(v);
712 }
713 match flow {
714 Flow::Normal => at += 1,
715 Flow::Goto(to) => at = to,
716 _ => break,
717 }
718 }
719 Ok(last)
720}
721
722pub(crate) fn fold_const(e: &Expr, cfg: EvalCfg) -> Option<Array> {
727 fn closed(e: &Expr) -> bool {
728 match e {
729 Expr::Const(..) => true,
730 Expr::Monad { verb, y, .. } => verb.is_pure() && closed(y),
731 Expr::Dyad { verb, x, y, .. } => verb.is_pure() && closed(x) && closed(y),
732 _ => false,
733 }
734 }
735 if !closed(e) {
736 return None;
737 }
738 cfg.pure(|ctx| eval(e, ctx, &mut None).ok())
739}
740
741fn eval(e: &Expr, ctx: &mut Ctx<'_>, rec: &mut Option<Trace>) -> Result<Array> {
742 let _depth = crate::verb::Nesting::enter(e.span())?;
745 let v = eval_node(e, ctx, rec)?;
746 if let Some(t) = rec.as_mut() {
747 let (kernel_ran, decline, placement) = t.get(&key(e)).map_or(
749 (None, None, crate::device::Placement::Default),
750 |n| (n.kernel_ran, n.decline, n.placement.clone()),
751 );
752 t.insert(
753 key(e),
754 Note { shape: v.shape.clone(), dtype: v.dtype(), kernel_ran, decline, placement },
755 );
756 }
757 Ok(v)
758}
759
760fn eval_node(e: &Expr, ctx: &mut Ctx<'_>, rec: &mut Option<Trace>) -> Result<Array> {
761 match e {
762 Expr::Const(a, _) => Ok(a.clone()),
763 Expr::Param(i, _) => ctx.env.arg(*i),
764 Expr::Name(n, span) => ctx.env.get(n).ok_or_else(|| {
765 Error::new(ErrorKind::Value, format!("undefined name: {n}"), Some(*span))
766 }),
767 Expr::Assign { name, value, scope, .. } => {
768 let v = eval(value, ctx, rec)?;
769 ctx.env.assign(name.clone(), v.clone(), *scope);
770 Ok(v)
771 }
772 Expr::AmendIndex { name, slots, value, origin, scope, span } => {
773 let base = ctx.env.get(name).ok_or_else(|| {
774 Error::new(ErrorKind::Value, format!("undefined name: {name}"), Some(*span))
775 })?;
776 let v = eval(value, ctx, rec)?;
778 let mut idx = Vec::with_capacity(slots.len());
779 for slot in slots {
780 idx.push(match slot {
781 Some(e) => Some(eval(e, ctx, rec)?),
782 None => None,
783 });
784 }
785 let out = crate::verb::amend_at(&base, &idx, &v, *origin, *span)?;
786 ctx.env.assign(name.clone(), out.clone(), *scope);
787 Ok(out)
788 }
789 Expr::Control(..) => {
792 Err(Error::internal("a control sentence appeared in expression position"))
793 }
794 Expr::Monad { verb, y, span } => {
795 let vy = eval(y, ctx, rec)?;
796 verb.monad(&vy, ctx, *span)
797 }
798 Expr::Dyad { verb, x, y, span } => {
799 let vy = eval(y, ctx, rec)?;
802 let vx = eval(x, ctx, rec)?;
803 verb.dyad(&vx, &vy, ctx, *span)
804 }
805 Expr::PrintPass { value, .. } => {
806 let v = eval(value, ctx, rec)?;
807 let text = format_array(&v, &ctx.cfg.fmt);
808 (ctx.out)(&text);
809 (ctx.out)("\n");
810 Ok(v)
811 }
812 Expr::Fused { kernel, inputs, orig, .. } => {
813 let mut vals = Vec::with_capacity(inputs.len());
814 for e in inputs {
815 vals.push(eval(e, ctx, rec)?);
816 }
817 let (ran, placement) = crate::fuse::eval_on(ctx.device, kernel, &vals);
818 if let Some(t) = rec.as_mut() {
819 let decline =
820 if ran.is_none() { crate::fuse::decline_reason(kernel, &vals) } else { None };
821 t.insert(
824 key(e),
825 Note {
826 shape: Vec::new(),
827 dtype: crate::dtype::DType::I64,
828 kernel_ran: Some(ran.is_some()),
829 decline,
830 placement,
831 },
832 );
833 }
834 match ran {
835 Some(a) => Ok(a),
836 None => {
840 let tree = crate::fuse::fallback_tree(kernel, orig, &vals);
841 let v = eval(&tree, ctx, &mut None)?;
844 Ok(crate::fuse::fallback_finish(kernel, v))
845 }
846 }
847 }
848 Expr::VerbDef { name, verb, .. } => {
851 ctx.env.define(name.clone(), verb.clone());
852 Ok(Array::scalar_i64(0))
853 }
854 Expr::Elided { .. } => Ok(Array::scalar_i64(0)),
857 }
858}