1use crate::errors::{GentError, GentResult};
6use crate::interpreter::types::{EnumConstructor, EnumValue};
7use crate::interpreter::{Environment, Value};
8use crate::parser::ast::{BinaryOp, Expression, StringPart, UnaryOp};
9use std::collections::HashMap;
10
11pub fn evaluate_expr(expr: &Expression, env: &Environment) -> GentResult<Value> {
13 match expr {
14 Expression::String(parts, _span) => {
16 let mut result = String::new();
18 for part in parts {
19 match part {
20 StringPart::Literal(s) => result.push_str(s),
21 StringPart::Expr(expr) => {
22 let value = evaluate_expr(expr, env)?;
23 result.push_str(&value.to_string());
24 }
25 }
26 }
27 Ok(Value::String(result))
28 }
29 Expression::Number(n, _) => Ok(Value::Number(*n)),
30 Expression::Boolean(b, _) => Ok(Value::Boolean(*b)),
31 Expression::Null(_) => Ok(Value::Null),
32
33 Expression::Identifier(name, span) => {
35 env.get(name)
36 .cloned()
37 .ok_or_else(|| GentError::UndefinedVariable {
38 name: name.clone(),
39 span: span.clone(),
40 })
41 }
42
43 Expression::Array(elements, _) => {
45 let mut values = Vec::new();
46 for elem in elements {
47 values.push(evaluate_expr(elem, env)?);
48 }
49 Ok(Value::Array(values))
50 }
51
52 Expression::Object(fields, _) => {
54 let mut map = HashMap::new();
55 for (key, value_expr) in fields {
56 let value = evaluate_expr(value_expr, env)?;
57 map.insert(key.clone(), value);
58 }
59 Ok(Value::Object(map))
60 }
61
62 Expression::Binary(op, left, right, span) => {
64 let left_val = evaluate_expr(left, env)?;
65 let right_val = evaluate_expr(right, env)?;
66 evaluate_binary_op(op, left_val, right_val, span)
67 }
68
69 Expression::Unary(op, operand, span) => {
71 let val = evaluate_expr(operand, env)?;
72 evaluate_unary_op(op, val, span)
73 }
74
75 Expression::Member(object_expr, property, span) => {
77 if let Expression::Identifier(name, _) = object_expr.as_ref() {
79 if let Some(enum_def) = env.get_enum(name) {
80 let variant = enum_def.variants.iter().find(|v| v.name == *property);
82 if let Some(v) = variant {
83 if v.fields.is_empty() {
84 return Ok(Value::Enum(EnumValue {
86 enum_name: name.clone(),
87 variant: property.clone(),
88 data: vec![],
89 }));
90 } else {
91 return Ok(Value::EnumConstructor(EnumConstructor {
93 enum_name: name.clone(),
94 variant: property.clone(),
95 expected_fields: v.fields.len(),
96 }));
97 }
98 } else {
99 return Err(GentError::TypeError {
100 expected: format!("valid variant of enum '{}'", name),
101 got: property.clone(),
102 span: span.clone(),
103 });
104 }
105 }
106 }
107
108 let object = evaluate_expr(object_expr, env)?;
110 match object {
111 Value::Object(map) => {
112 map.get(property)
113 .cloned()
114 .ok_or_else(|| GentError::UndefinedProperty {
115 property: property.clone(),
116 type_name: "Object".to_string(),
117 span: span.clone(),
118 })
119 }
120 _ => Err(GentError::UndefinedProperty {
121 property: property.clone(),
122 type_name: object.type_name().to_string(),
123 span: span.clone(),
124 }),
125 }
126 }
127
128 Expression::Index(target_expr, index_expr, span) => {
130 let target = evaluate_expr(target_expr, env)?;
131 let index = evaluate_expr(index_expr, env)?;
132
133 match target {
134 Value::Array(ref items) => {
135 if let Value::Number(n) = index {
137 let idx = n as i64;
138 if idx < 0 || idx >= items.len() as i64 {
139 return Err(GentError::IndexOutOfBounds {
140 index: idx,
141 length: items.len(),
142 span: span.clone(),
143 });
144 }
145 Ok(items[idx as usize].clone())
146 } else {
147 Err(GentError::NotIndexable {
148 type_name: format!("Array with {} index", index.type_name()),
149 span: span.clone(),
150 })
151 }
152 }
153 Value::Object(ref map) => {
154 if let Value::String(key) = index {
156 map.get(&key)
157 .cloned()
158 .ok_or_else(|| GentError::UndefinedProperty {
159 property: key.clone(),
160 type_name: "Object".to_string(),
161 span: span.clone(),
162 })
163 } else {
164 Err(GentError::NotIndexable {
165 type_name: format!("Object with {} index", index.type_name()),
166 span: span.clone(),
167 })
168 }
169 }
170 _ => Err(GentError::NotIndexable {
171 type_name: target.type_name().to_string(),
172 span: span.clone(),
173 }),
174 }
175 }
176
177 Expression::Call(_, _, span) => Err(GentError::TypeError {
179 expected: "synchronous expression".to_string(),
180 got: "function call (requires async context)".to_string(),
181 span: span.clone(),
182 }),
183
184 Expression::Range(start, end, span) => {
186 let start_val = evaluate_expr(start, env)?;
187 let end_val = evaluate_expr(end, env)?;
188
189 match (start_val, end_val) {
190 (Value::Number(s), Value::Number(e)) => {
191 let range: Vec<Value> = (s as i64..e as i64)
192 .map(|n| Value::Number(n as f64))
193 .collect();
194 Ok(Value::Array(range))
195 }
196 _ => Err(GentError::TypeError {
197 expected: "Number".to_string(),
198 got: "non-number".to_string(),
199 span: span.clone(),
200 }),
201 }
202 }
203
204 Expression::Lambda(lambda) => {
206 Ok(Value::Lambda(crate::interpreter::types::LambdaValue {
207 params: lambda.params.clone(),
208 body: lambda.body.clone(),
209 }))
210 }
211
212 Expression::Match(match_expr) => Err(GentError::TypeError {
214 expected: "synchronous expression".to_string(),
215 got: "match expression (requires async context)".to_string(),
216 span: match_expr.span.clone(),
217 }),
218 }
219}
220
221fn evaluate_binary_op(
223 op: &BinaryOp,
224 left: Value,
225 right: Value,
226 span: &crate::Span,
227) -> GentResult<Value> {
228 match op {
229 BinaryOp::Add => {
231 match (&left, &right) {
232 (Value::String(s1), Value::String(s2)) => {
234 Ok(Value::String(format!("{}{}", s1, s2)))
235 }
236 (Value::Number(n1), Value::Number(n2)) => Ok(Value::Number(n1 + n2)),
238 (Value::String(s), other) => Ok(Value::String(format!("{}{}", s, other))),
240 (other, Value::String(s)) => Ok(Value::String(format!("{}{}", other, s))),
241 _ => Err(GentError::InvalidOperands {
242 op: "+".to_string(),
243 left: left.type_name().to_string(),
244 right: right.type_name().to_string(),
245 span: span.clone(),
246 }),
247 }
248 }
249 BinaryOp::Sub => binary_arithmetic_op(left, right, span, "-", |a, b| a - b),
250 BinaryOp::Mul => binary_arithmetic_op(left, right, span, "*", |a, b| a * b),
251 BinaryOp::Div => {
252 if let (Value::Number(a), Value::Number(b)) = (&left, &right) {
253 if *b == 0.0 {
254 return Err(GentError::DivisionByZero { span: span.clone() });
255 }
256 Ok(Value::Number(a / b))
257 } else {
258 Err(GentError::InvalidOperands {
259 op: "/".to_string(),
260 left: left.type_name().to_string(),
261 right: right.type_name().to_string(),
262 span: span.clone(),
263 })
264 }
265 }
266 BinaryOp::Mod => {
267 if let (Value::Number(a), Value::Number(b)) = (&left, &right) {
268 if *b == 0.0 {
269 return Err(GentError::DivisionByZero { span: span.clone() });
270 }
271 Ok(Value::Number(a % b))
272 } else {
273 Err(GentError::InvalidOperands {
274 op: "%".to_string(),
275 left: left.type_name().to_string(),
276 right: right.type_name().to_string(),
277 span: span.clone(),
278 })
279 }
280 }
281
282 BinaryOp::Eq => Ok(Value::Boolean(values_equal(&left, &right))),
284 BinaryOp::Ne => Ok(Value::Boolean(!values_equal(&left, &right))),
285 BinaryOp::Lt => binary_comparison_op(left, right, span, "<", |a, b| a < b),
286 BinaryOp::Le => binary_comparison_op(left, right, span, "<=", |a, b| a <= b),
287 BinaryOp::Gt => binary_comparison_op(left, right, span, ">", |a, b| a > b),
288 BinaryOp::Ge => binary_comparison_op(left, right, span, ">=", |a, b| a >= b),
289
290 BinaryOp::And => Ok(Value::Boolean(left.is_truthy() && right.is_truthy())),
292 BinaryOp::Or => Ok(Value::Boolean(left.is_truthy() || right.is_truthy())),
293 }
294}
295
296fn binary_arithmetic_op<F>(
298 left: Value,
299 right: Value,
300 span: &crate::Span,
301 op_str: &str,
302 op: F,
303) -> GentResult<Value>
304where
305 F: FnOnce(f64, f64) -> f64,
306{
307 if let (Value::Number(a), Value::Number(b)) = (&left, &right) {
308 Ok(Value::Number(op(*a, *b)))
309 } else {
310 Err(GentError::InvalidOperands {
311 op: op_str.to_string(),
312 left: left.type_name().to_string(),
313 right: right.type_name().to_string(),
314 span: span.clone(),
315 })
316 }
317}
318
319fn binary_comparison_op<F>(
321 left: Value,
322 right: Value,
323 span: &crate::Span,
324 op_str: &str,
325 op: F,
326) -> GentResult<Value>
327where
328 F: FnOnce(f64, f64) -> bool,
329{
330 if let (Value::Number(a), Value::Number(b)) = (&left, &right) {
331 Ok(Value::Boolean(op(*a, *b)))
332 } else {
333 Err(GentError::InvalidOperands {
334 op: op_str.to_string(),
335 left: left.type_name().to_string(),
336 right: right.type_name().to_string(),
337 span: span.clone(),
338 })
339 }
340}
341
342fn values_equal(left: &Value, right: &Value) -> bool {
344 match (left, right) {
345 (Value::String(a), Value::String(b)) => a == b,
346 (Value::Number(a), Value::Number(b)) => a == b,
347 (Value::Boolean(a), Value::Boolean(b)) => a == b,
348 (Value::Null, Value::Null) => true,
349 (Value::Array(a), Value::Array(b)) => {
350 if a.len() != b.len() {
351 return false;
352 }
353 a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
354 }
355 (Value::Object(a), Value::Object(b)) => {
356 if a.len() != b.len() {
357 return false;
358 }
359 a.iter()
360 .all(|(k, v)| b.get(k).is_some_and(|v2| values_equal(v, v2)))
361 }
362 _ => false, }
364}
365
366fn evaluate_unary_op(op: &UnaryOp, operand: Value, span: &crate::Span) -> GentResult<Value> {
368 match op {
369 UnaryOp::Not => Ok(Value::Boolean(!operand.is_truthy())),
370 UnaryOp::Neg => {
371 if let Value::Number(n) = operand {
372 Ok(Value::Number(-n))
373 } else {
374 Err(GentError::InvalidOperands {
375 op: "-".to_string(),
376 left: operand.type_name().to_string(),
377 right: "".to_string(),
378 span: span.clone(),
379 })
380 }
381 }
382 }
383}