Skip to main content

sim_expr_tree_calc/
policy.rs

1use sim_kernel::{
2    Cx, Demand, Error as KernelError, EvalPolicy, Expr, Phase, PreparedArgs, Symbol, Value,
3    object::RawArgs,
4};
5
6pub const EXPR_TREE_REF: &str = "expr-tree/ref";
7
8pub struct ExprTreeRefPolicy<P> {
9    inner: P,
10}
11
12impl<P> ExprTreeRefPolicy<P> {
13    pub fn new(inner: P) -> Self {
14        Self { inner }
15    }
16
17    pub fn inner(&self) -> &P {
18        &self.inner
19    }
20}
21
22impl<P: EvalPolicy> EvalPolicy for ExprTreeRefPolicy<P> {
23    fn name(&self) -> &'static str {
24        "expr-tree-ref"
25    }
26
27    fn allow_macro_expansion(&self, phase: Phase) -> bool {
28        self.inner.allow_macro_expansion(phase)
29    }
30
31    fn prepare_call_args(
32        &self,
33        cx: &mut Cx,
34        raw: RawArgs,
35        demands: &[Demand],
36    ) -> sim_kernel::Result<PreparedArgs> {
37        self.inner.prepare_call_args(cx, raw, demands)
38    }
39
40    fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> sim_kernel::Result<Value> {
41        self.inner.force(cx, value, demand)
42    }
43
44    fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> sim_kernel::Result<Value> {
45        self.inner.eval_expr(cx, expr)
46    }
47
48    fn resolve_unbound_symbol(&self, cx: &mut Cx, symbol: Symbol) -> sim_kernel::Result<Value> {
49        cx.factory().string(format!("expr-tree/ref:{symbol}"))
50    }
51
52    fn resolve_unbound_call(
53        &self,
54        cx: &mut Cx,
55        operator: Symbol,
56        args: Vec<Expr>,
57    ) -> sim_kernel::Result<Value> {
58        if operator.to_string() == EXPR_TREE_REF {
59            let Some(reference) = args.first() else {
60                return Err(KernelError::Eval(
61                    "expr-tree/ref requires a reference".to_owned(),
62                ));
63            };
64            return cx
65                .factory()
66                .string(format!("expr-tree/ref:{}", expr_text(reference)));
67        }
68        self.inner.resolve_unbound_call(cx, operator, args)
69    }
70}
71
72fn expr_text(expr: &Expr) -> String {
73    match expr {
74        Expr::String(value) => value.clone(),
75        Expr::Symbol(symbol) => symbol.to_string(),
76        other => format!("{other:?}"),
77    }
78}