1use super::{operation, Evaluator, NameSpace};
2use crate::ir::{Expr, Program};
3use crate::{MiniError, MiniResult, Printer};
4
5#[derive(Clone, Debug, PartialEq, Eq)]
6enum Var {
7 Thunk(Expr),
8 Cached(i32),
9}
10
11impl Var {
12 fn get(self, ns: &mut NameSpace<Self>, funcs: &[Expr]) -> MiniResult<i32> {
13 Ok(match self {
14 Self::Thunk(e) => eval_expr(e, ns, funcs)?,
15 Self::Cached(i) => i,
16 })
17 }
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct LazyEval;
23
24impl Evaluator for LazyEval {
25 type Err = MiniError;
26 fn evaluate<P: Printer>(&self, ir: Program, printer: &mut P) -> MiniResult<()> {
27 let Program {
28 funcs,
29 vars,
30 prints,
31 } = ir;
32
33 let mut ns = NameSpace::new();
34 for var in vars {
35 ns.register(Var::Thunk(var));
36 }
37
38 for print in prints {
39 printer
40 .print(eval_expr(print, &mut ns, &funcs)?)
41 .map_err(MiniError::from_error)?;
42 }
43 Ok(())
44 }
45}
46
47fn funccall(
48 func: Expr,
49 args: Vec<Expr>,
50 ns: &mut NameSpace<Var>,
51 funcs: &[Expr],
52) -> MiniResult<i32> {
53 let depth = ns.chunk();
54 for arg in args {
55 ns.register(Var::Thunk(arg));
56 }
57 let res = eval_expr(func.circulate(depth), ns, funcs)?;
58 ns.back();
59 Ok(res)
60}
61
62fn eval_expr(expr: Expr, ns: &mut NameSpace<Var>, funcs: &[Expr]) -> MiniResult<i32> {
63 Ok(match expr {
64 Expr::Value(v) => v,
65 Expr::Variable(depth, id) => {
66 let var = ns.borrow(depth, id)?;
67 let val = var.get(ns, funcs)?;
68 ns.ret(depth, id, Var::Cached(val))?;
69 val
70 }
71 Expr::Operation(op, lhs, rhs) => {
72 operation(op, eval_expr(*lhs, ns, funcs)?, eval_expr(*rhs, ns, funcs)?)?
73 }
74 Expr::FuncCall(f, a) => funccall(funcs[f].clone(), a, ns, funcs)?,
75 Expr::If(c, t, f) => {
76 if eval_expr(*c, ns, funcs)? != 0 {
77 eval_expr(*t, ns, funcs)?
78 } else {
79 eval_expr(*f, ns, funcs)?
80 }
81 }
82 })
83}