compose_eval/expression/
control_flow.rs1use crate::expression::bindings::destructure_pattern;
2use crate::vm::{FlowEvent, Tracked};
3use crate::{Eval, Evaluated, Machine};
4use compose_library::diag::{At, SourceResult};
5use compose_library::{BindingKind, IterValue, Value, ValueIterator, Visibility};
6use compose_syntax::ast;
7use compose_syntax::ast::AstNode;
8
9impl Eval for ast::Conditional<'_> {
10 fn eval(self, vm: &mut Machine) -> SourceResult<Evaluated> {
11 if eval_condition(self.condition(), vm)? {
12 return self.consequent().eval(vm);
13 }
14
15 for alternate in self.cond_alternates() {
16 if eval_condition(alternate.condition(), vm)? {
17 return alternate.consequent().eval(vm);
18 }
19 }
20
21 if let Some(cond_else) = self.cond_else() {
22 return cond_else.consequent().eval(vm);
23 }
24
25 Ok(Evaluated::unit())
26 }
27}
28
29impl Eval for ast::WhileLoop<'_> {
30 fn eval(self, vm: &mut Machine) -> SourceResult<Evaluated> {
31 let mut output = Value::unit();
32 let flow = vm.flow.take();
33 while eval_condition(self.condition(), vm)? {
34 output = self.body().eval(vm)?.value;
35
36 match &vm.flow {
37 None => {}
38 Some(FlowEvent::Break(_, value)) => {
39 if let Some(value) = value {
40 output = value.clone();
41 }
42 vm.flow = None;
43 break;
44 }
45 Some(FlowEvent::Continue(_)) => vm.flow = None,
46 Some(FlowEvent::Return(..)) => break,
47 }
48 }
49
50 if let Some(flow) = flow {
51 vm.flow = Some(flow);
52 }
53
54 Ok(Evaluated::mutable(output))
55 }
56}
57
58impl Eval for ast::ForLoop<'_> {
59 fn eval(self, vm: &mut Machine) -> SourceResult<Evaluated> {
61 let root_guard = vm.temp_root_guard();
62 let mut output = Value::unit();
63 let pattern = self.binding();
64 let iterable_expr = self.iterable();
65 let iterator = {
66 let value = iterable_expr
67 .eval(root_guard.vm)?
68 .track_tmp_root(root_guard.vm);
69 IterValue::try_from_value(value.value, value.mutable, root_guard.vm)
70 .at(iterable_expr.span())?
71 .track_tmp_root(root_guard.vm)
72 };
73
74 let body = self.body();
75
76 let flow = root_guard.vm.flow.take();
77
78 while let Some(v) = iterator.next(root_guard.vm)? {
79 root_guard.vm.in_scope(|vm| {
80 destructure_pattern(
81 vm,
82 pattern,
83 v,
84 BindingKind::Immutable { first_assign: None },
85 Visibility::Private,
86 )?;
87
88 output = body.eval(vm)?.value;
89
90 SourceResult::Ok(())
91 })?;
92
93 match &root_guard.vm.flow {
94 None => {}
95 Some(FlowEvent::Break(_, value)) => {
96 if let Some(value) = value {
97 output = value.clone();
98 }
99 root_guard.vm.flow = None;
100 break;
101 }
102 Some(FlowEvent::Continue(_)) => root_guard.vm.flow = None,
103 Some(FlowEvent::Return(..)) => break,
104 }
105 }
106
107 if let Some(flow) = flow {
108 root_guard.vm.flow = Some(flow);
109 }
110
111 Ok(Evaluated::mutable(output))
112 }
113}
114
115#[inline]
117fn eval_condition(cond: ast::Condition<'_>, vm: &mut Machine) -> SourceResult<bool> {
118 let cond_expr = cond.expr();
119 let cond_value = cond_expr.eval(vm)?;
120 cond_value.value.cast::<bool>().at(cond_expr.span())
121}