1use std::{cell::RefCell, ops::Deref, rc::Rc};
5
6use rimu_ast::{Block, Expression, SpannedBlock, SpannedExpression};
7use rimu_meta::{Span, Spanned};
8use rimu_value::{
9 convert_value_object_to_serde_value_object, Environment, Function, FunctionBody, SpannedValue,
10 Value, ValueList, ValueObject,
11};
12
13use crate::{common, expression::evaluate as evaluate_expression, EvalError, Result};
14
15pub fn evaluate(expression: &SpannedBlock, env: Rc<RefCell<Environment>>) -> Result<SpannedValue> {
16 Evaluator::new(env).block(expression)
17}
18
19struct Evaluator {
22 env: Rc<RefCell<Environment>>,
23}
24
25impl Evaluator {
26 fn new(env: Rc<RefCell<Environment>>) -> Self {
27 Self { env }
28 }
29
30 fn block(&self, block: &SpannedBlock) -> Result<SpannedValue> {
31 let span = block.span();
32 match block.inner() {
33 Block::Expression(expr) => self.expression(span, expr),
34 Block::Object(object) => self.object(span, object),
35 Block::List(list) => self.list(span, list),
36 Block::Function { args, body } => self.function(span, args, body),
37 Block::Call { function, args } => self.call(span, function, args),
38 Block::If {
39 condition,
40 consequent,
41 alternative,
42 } => self.if_(
43 span,
44 condition,
45 consequent.as_ref().map(|c| c.deref()),
46 alternative.as_ref().map(|a| a.deref()),
47 ),
48 Block::Let { variables, body } => self.let_(span, variables, body.deref()),
49 }
50 }
51
52 fn expression(&self, span: Span, expr: &Expression) -> Result<SpannedValue> {
53 evaluate_expression(&Spanned::new(expr.clone(), span), self.env.clone())
54 }
55
56 fn object(
57 &self,
58 span: Span,
59 entries: &[(Spanned<String>, SpannedBlock)],
60 ) -> Result<SpannedValue> {
61 let mut object = ValueObject::new();
62 for (key, value) in entries.iter() {
63 let key = key.clone().into_inner();
64 let value = self.block(value)?;
65 if value.inner() == &Value::Null {
66 continue;
67 };
68 object.insert(key, value);
69 }
70 let value = Value::Object(object);
71 Ok(Spanned::new(value, span))
72 }
73
74 fn list(&self, span: Span, items: &[SpannedBlock]) -> Result<SpannedValue> {
75 let mut list = ValueList::with_capacity(items.len());
76 for item in items.iter() {
77 let item = self.block(item)?;
78 if item.inner() == &Value::Null {
79 continue;
80 };
81 list.push(item);
82 }
83 let value = Value::List(list);
84 Ok(Spanned::new(value, span))
85 }
86
87 fn function(
88 &self,
89 span: Span,
90 args: &[Spanned<String>],
91 body: &SpannedBlock,
92 ) -> Result<SpannedValue> {
93 let args: Vec<String> = args.iter().map(|a| a.inner()).cloned().collect();
94 let body = FunctionBody::Block(body.clone());
95 let env = self.env.clone();
96 let value = Value::Function(Function { args, body, env });
97 Ok(Spanned::new(value, span))
98 }
99
100 fn call(
101 &self,
102 span: Span,
103 function: &SpannedExpression,
104 args: &SpannedBlock,
105 ) -> Result<SpannedValue> {
106 let Value::Function(function) =
107 evaluate_expression(function, self.env.clone())?.into_inner()
108 else {
109 return Err(EvalError::CallNonFunction {
110 span: function.span(),
111 expr: function.clone().into_inner(),
112 });
113 };
114
115 let arg = self.block(args)?;
116
117 let args = match arg.inner() {
118 Value::List(list) => list.clone(),
119 _ => vec![arg],
120 };
121
122 common::call(span, function, &args)
123 }
124
125 fn if_(
126 &self,
127 span: Span,
128 condition: &SpannedBlock,
129 consequent: Option<&SpannedBlock>,
130 alternative: Option<&SpannedBlock>,
131 ) -> Result<SpannedValue> {
132 let condition = self.block(condition)?.into_inner();
133
134 let value = if Into::<bool>::into(condition) {
135 if let Some(consequent) = &consequent {
136 self.block(consequent)?.into_inner()
137 } else {
138 Value::Null
139 }
140 } else {
141 #[allow(clippy::collapsible_else_if)]
142 if let Some(alternative) = &alternative {
143 self.block(alternative)?.into_inner()
144 } else {
145 Value::Null
146 }
147 };
148
149 Ok(Spanned::new(value, span))
150 }
151
152 fn let_(
153 &self,
154 span: Span,
155 entries: &[(Spanned<String>, SpannedBlock)],
156 body: &SpannedBlock,
157 ) -> Result<SpannedValue> {
158 let mut variables = ValueObject::new();
159 for (key, value) in entries.iter() {
160 let key = key.clone().into_inner();
161 let value = self.block(value)?;
162 if value.inner() == &Value::Null {
163 continue;
164 };
165 variables.insert(key, value);
166 }
167
168 let parent_env = self.env.clone();
169 let variables = convert_value_object_to_serde_value_object(variables);
170 let let_env = Environment::from_object(&variables, Some(parent_env)).map_err(|error| {
171 EvalError::Environment {
172 span: span.clone(),
173 source: error,
174 }
175 })?;
176 let let_env = Rc::new(RefCell::new(let_env));
177
178 let value = evaluate(body, let_env)?.into_inner();
179
180 Ok(Spanned::new(value, span))
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use std::cell::RefCell;
187 use std::rc::Rc;
188
189 use indexmap::IndexMap;
190
191 use indexmap::indexmap;
192 use pretty_assertions::assert_eq;
193 use rimu_ast::SpannedBlock;
194 use rimu_meta::SourceId;
195 use rimu_parse::parse_block;
196 use rimu_value::SerdeValue;
197 use rimu_value::{Environment, Value};
198 use rust_decimal_macros::dec;
199
200 use super::{evaluate, EvalError};
201
202 fn test_block(
203 expr: SpannedBlock,
204 env_object: Option<IndexMap<String, SerdeValue>>,
205 ) -> Result<Value, EvalError> {
206 let mut env = Environment::new();
207 if let Some(env_object) = env_object {
208 for (key, value) in env_object.into_iter() {
209 env.insert(key, value);
210 }
211 }
212 let env = Rc::new(RefCell::new(env));
213
214 let value = evaluate(&expr, env)?.into_inner();
215 Ok(value)
216 }
217
218 fn test_code(
219 code: &str,
220 env_object: Option<IndexMap<String, SerdeValue>>,
221 ) -> Result<SerdeValue, EvalError> {
222 let (Some(expr), errors) = parse_block(code, SourceId::empty()) else {
223 panic!()
224 };
225 assert_eq!(errors.len(), 0);
226 Ok(test_block(expr, env_object)?.into())
227 }
228
229 #[test]
230 fn op_if() {
231 let code = "
232zero:
233 if ten > five
234 then five
235 else ten
236";
237
238 let env = indexmap! {
239 "five".into() => SerdeValue::Number(dec!(5).into()),
240 "ten".into() => SerdeValue::Number(dec!(10).into()),
241 };
242 let actual = test_code(code, Some(env));
243
244 let expected = Ok(SerdeValue::Object(indexmap! {
245 "zero".into() => SerdeValue::Number(dec!(5).into())
246 }));
247
248 assert_eq!(expected, actual);
249 }
250
251 #[test]
252 fn op_let() {
253 let code = "
254zero:
255 let
256 one: ten
257 two: 2
258 in
259 three: one + two
260";
261
262 let env = indexmap! {
263 "ten".into() => SerdeValue::Number(dec!(10).into()),
264 };
265 let actual = test_code(code, Some(env));
266
267 let expected = Ok(SerdeValue::Object(indexmap! {
268 "zero".into() => SerdeValue::Object(indexmap! {
269 "three".into() => SerdeValue::Number(dec!(12).into())
270 })
271 }));
272
273 assert_eq!(expected, actual);
274 }
275}