1use std::sync::Arc;
2
3use crate::{
4 Symbol,
5 env::Cx,
6 error::{Error, Result},
7 eval::{Demand, LazyThunkObject, PreparedArgs, ThunkObject},
8 expr::Expr,
9 object::RawArgs,
10 value::Value,
11};
12
13use super::protocol::Phase;
14
15pub trait EvalPolicy: Send + Sync {
25 fn name(&self) -> &'static str;
27 fn allow_macro_expansion(&self, _phase: Phase) -> bool {
31 false
32 }
33 fn prepare_call_args(
38 &self,
39 cx: &mut Cx,
40 raw: RawArgs,
41 demands: &[Demand],
42 ) -> Result<PreparedArgs>;
43 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value>;
45 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value>;
47 fn resolve_unbound_symbol(&self, cx: &mut Cx, symbol: Symbol) -> Result<Value> {
52 cx.factory().symbol(symbol)
53 }
54 fn resolve_unbound_call(
59 &self,
60 cx: &mut Cx,
61 operator: Symbol,
62 args: Vec<Expr>,
63 ) -> Result<Value> {
64 cx.factory().expr(Expr::Call {
65 operator: Box::new(Expr::Symbol(operator)),
66 args,
67 })
68 }
69}
70
71pub type EvalPolicyRef = Arc<dyn EvalPolicy>;
73
74pub struct NoopEvalPolicy;
80
81impl EvalPolicy for NoopEvalPolicy {
82 fn name(&self) -> &'static str {
83 "noop"
84 }
85
86 fn prepare_call_args(
87 &self,
88 cx: &mut Cx,
89 raw: RawArgs,
90 _demands: &[Demand],
91 ) -> Result<PreparedArgs> {
92 let values = raw
93 .into_exprs()
94 .into_iter()
95 .map(|expr| cx.factory().expr(expr))
96 .collect::<Result<Vec<_>>>()?;
97 Ok(PreparedArgs::new(values))
98 }
99
100 fn force(&self, _cx: &mut Cx, value: Value, _demand: Demand) -> Result<Value> {
101 Ok(value)
102 }
103
104 fn eval_expr(&self, _cx: &mut Cx, _expr: Expr) -> Result<Value> {
105 Err(Error::Eval(
106 "noop eval policy cannot evaluate expressions".to_owned(),
107 ))
108 }
109}
110
111pub struct EagerPolicy;
113
114impl EvalPolicy for EagerPolicy {
115 fn name(&self) -> &'static str {
116 "eager"
117 }
118
119 fn allow_macro_expansion(&self, phase: Phase) -> bool {
120 matches!(
121 phase,
122 Phase::Read | Phase::Expand | Phase::Compile | Phase::Eval
123 )
124 }
125
126 fn prepare_call_args(
127 &self,
128 cx: &mut Cx,
129 raw: RawArgs,
130 _demands: &[Demand],
131 ) -> Result<PreparedArgs> {
132 let values = raw
133 .into_exprs()
134 .into_iter()
135 .map(|expr| cx.eval_expr(expr))
136 .collect::<Result<Vec<_>>>()?;
137 Ok(PreparedArgs::new(values))
138 }
139
140 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
141 crate::eval::force_default(cx, value, demand)
142 }
143
144 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
145 crate::eval::eval_expr_default(cx, expr)
146 }
147}
148
149pub struct LazyPolicy;
154
155impl EvalPolicy for LazyPolicy {
156 fn name(&self) -> &'static str {
157 "lazy"
158 }
159
160 fn allow_macro_expansion(&self, phase: Phase) -> bool {
161 matches!(
162 phase,
163 Phase::Read | Phase::Expand | Phase::Compile | Phase::Eval
164 )
165 }
166
167 fn prepare_call_args(
168 &self,
169 cx: &mut Cx,
170 raw: RawArgs,
171 _demands: &[Demand],
172 ) -> Result<PreparedArgs> {
173 lazy_args(cx, raw)
174 }
175
176 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
177 crate::eval::force_default(cx, value, demand)
178 }
179
180 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
181 crate::eval::eval_expr_default(cx, expr)
182 }
183}
184
185pub struct NeedPolicy;
190
191impl EvalPolicy for NeedPolicy {
192 fn name(&self) -> &'static str {
193 "lazy-by-need"
194 }
195
196 fn allow_macro_expansion(&self, phase: Phase) -> bool {
197 matches!(
198 phase,
199 Phase::Read | Phase::Expand | Phase::Compile | Phase::Eval
200 )
201 }
202
203 fn prepare_call_args(
204 &self,
205 cx: &mut Cx,
206 raw: RawArgs,
207 _demands: &[Demand],
208 ) -> Result<PreparedArgs> {
209 need_args(cx, raw)
210 }
211
212 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
213 crate::eval::force_default(cx, value, demand)
214 }
215
216 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
217 crate::eval::eval_expr_default(cx, expr)
218 }
219}
220
221pub struct StrictByShapePolicy;
226
227impl EvalPolicy for StrictByShapePolicy {
228 fn name(&self) -> &'static str {
229 "strict-by-shape"
230 }
231
232 fn allow_macro_expansion(&self, phase: Phase) -> bool {
233 matches!(
234 phase,
235 Phase::Read | Phase::Expand | Phase::Compile | Phase::Eval
236 )
237 }
238
239 fn prepare_call_args(
240 &self,
241 cx: &mut Cx,
242 raw: RawArgs,
243 demands: &[Demand],
244 ) -> Result<PreparedArgs> {
245 let env = cx.env().clone();
246 let values = raw
247 .into_exprs()
248 .into_iter()
249 .enumerate()
250 .map(|(index, expr)| {
251 let demand = demands.get(index).copied().unwrap_or(Demand::Value);
252 match demand {
253 Demand::Never | Demand::Expr => Ok(Value::from_arc(Arc::new(
254 LazyThunkObject::new(expr, env.clone()),
255 ))),
256 Demand::Value | Demand::Bool | Demand::Class(_) | Demand::Shape(_) => {
257 cx.eval_expr(expr)
258 }
259 }
260 })
261 .collect::<Result<Vec<_>>>()?;
262 Ok(PreparedArgs::new(values))
263 }
264
265 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
266 crate::eval::force_default(cx, value, demand)
267 }
268
269 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
270 crate::eval::eval_expr_default(cx, expr)
271 }
272}
273
274pub struct HybridPolicy;
279
280impl EvalPolicy for HybridPolicy {
281 fn name(&self) -> &'static str {
282 "hybrid"
283 }
284
285 fn allow_macro_expansion(&self, phase: Phase) -> bool {
286 matches!(
287 phase,
288 Phase::Read | Phase::Expand | Phase::Compile | Phase::Eval
289 )
290 }
291
292 fn prepare_call_args(
293 &self,
294 cx: &mut Cx,
295 raw: RawArgs,
296 demands: &[Demand],
297 ) -> Result<PreparedArgs> {
298 let values = raw
299 .into_exprs()
300 .into_iter()
301 .enumerate()
302 .map(|(index, expr)| {
303 let demand = demands.get(index).copied().unwrap_or(Demand::Value);
304 match demand {
305 Demand::Never | Demand::Expr => cx.factory().expr(expr),
306 Demand::Value | Demand::Bool | Demand::Class(_) | Demand::Shape(_) => {
307 cx.eval_expr(expr)
308 }
309 }
310 })
311 .collect::<Result<Vec<_>>>()?;
312 Ok(PreparedArgs::new(values))
313 }
314
315 fn force(&self, cx: &mut Cx, value: Value, demand: Demand) -> Result<Value> {
316 crate::eval::force_default(cx, value, demand)
317 }
318
319 fn eval_expr(&self, cx: &mut Cx, expr: Expr) -> Result<Value> {
320 crate::eval::eval_expr_default(cx, expr)
321 }
322}
323
324fn lazy_args(cx: &mut Cx, raw: RawArgs) -> Result<PreparedArgs> {
325 let env = cx.env().clone();
326 let values = raw
327 .into_exprs()
328 .into_iter()
329 .map(|expr| {
330 Ok(Value::from_arc(Arc::new(LazyThunkObject::new(
331 expr,
332 env.clone(),
333 ))))
334 })
335 .collect::<Result<Vec<_>>>()?;
336 Ok(PreparedArgs::new(values))
337}
338
339fn need_args(cx: &mut Cx, raw: RawArgs) -> Result<PreparedArgs> {
340 let env = cx.env().clone();
341 let values = raw
342 .into_exprs()
343 .into_iter()
344 .map(|expr| {
345 Ok(Value::from_arc(Arc::new(ThunkObject::new(
346 expr,
347 env.clone(),
348 ))))
349 })
350 .collect::<Result<Vec<_>>>()?;
351 Ok(PreparedArgs::new(values))
352}