helix/dna/ops/
eval.rs

1//! Evaluator for the Calculator DSL
2//!
3//! This module executes the AST against a mutable environment.
4
5use std::collections::HashMap;
6
7use anyhow::{anyhow, Result};
8
9use crate::ops::math::{Expr, Assign};
10
11/// Environment mapping variable names to integer values.
12pub type Env = HashMap<String, i64>;
13
14/// Recursively evaluate an expression inside `env`.
15pub fn eval_expr(expr: &Expr, env: &mut Env) -> Result<i64> {
16    match expr {
17        Expr::Number(n) => Ok(*n),
18
19        Expr::Var(name) => env
20            .get(name)
21            .cloned()
22            .ok_or_else(|| anyhow!("variable `{}` not defined", name)),
23
24        Expr::Mul(l, r) => Ok(eval_expr(l, env)? * eval_expr(r, env)?),
25
26        Expr::Add(l, r) => Ok(eval_expr(l, env)? + eval_expr(r, env)?),
27
28        Expr::Sub(l, r) => Ok(eval_expr(l, env)? - eval_expr(r, env)?),
29
30        Expr::Ref { var, modifier } => {
31            let val = env
32                .get(var)
33                .cloned()
34                .ok_or_else(|| anyhow!("variable `{}` not defined", var))?;
35            // For this demo we interpret `#n` as **modulo**.
36            // Change the implementation to whatever you need (e.g. scaling).
37            match modifier {
38                Some(mod_val) => Ok(val % mod_val),
39                None => Ok(val),
40            }
41        }
42    }
43}
44
45/// Execute a list of assignments. The environment is mutated in‑place and
46/// also returned for convenience.
47pub fn run_program(assignments: &[Assign]) -> Result<Env> {
48    let mut env = Env::new();
49
50    for assign in assignments {
51        let value = eval_expr(&assign.value, &mut env)?;
52        env.insert(assign.name.clone(), value);
53    }
54
55    Ok(env)
56}