mini_lang/eval/
lazy.rs

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/// The lazy evaluator
21#[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}