1use gitql_ast::expression::ArithmeticExpr;
2use gitql_ast::expression::ArrayExpr;
3use gitql_ast::expression::AssignmentExpr;
4use gitql_ast::expression::BenchmarkCallExpr;
5use gitql_ast::expression::BetweenExpr;
6use gitql_ast::expression::BetweenKind;
7use gitql_ast::expression::BitwiseExpr;
8use gitql_ast::expression::BooleanExpr;
9use gitql_ast::expression::CallExpr;
10use gitql_ast::expression::CaseExpr;
11use gitql_ast::expression::CastExpr;
12use gitql_ast::expression::ColumnExpr;
13use gitql_ast::expression::ComparisonExpr;
14use gitql_ast::expression::ContainedByExpr;
15use gitql_ast::expression::ContainsExpr;
16use gitql_ast::expression::Expr;
17use gitql_ast::expression::ExprKind::*;
18use gitql_ast::expression::GlobExpr;
19use gitql_ast::expression::GlobalVariableExpr;
20use gitql_ast::expression::GroupComparisonExpr;
21use gitql_ast::expression::InExpr;
22use gitql_ast::expression::IndexExpr;
23use gitql_ast::expression::IntervalExpr;
24use gitql_ast::expression::IsNullExpr;
25use gitql_ast::expression::LikeExpr;
26use gitql_ast::expression::LogicalExpr;
27use gitql_ast::expression::MemberAccessExpr;
28use gitql_ast::expression::Number;
29use gitql_ast::expression::NumberExpr;
30use gitql_ast::expression::RegexExpr;
31use gitql_ast::expression::RowExpr;
32use gitql_ast::expression::SliceExpr;
33use gitql_ast::expression::StringExpr;
34use gitql_ast::expression::SymbolExpr;
35use gitql_ast::expression::UnaryExpr;
36use gitql_ast::operator::ArithmeticOperator;
37use gitql_ast::operator::BinaryBitwiseOperator;
38use gitql_ast::operator::BinaryLogicalOperator;
39use gitql_ast::operator::ComparisonOperator;
40use gitql_ast::operator::PrefixUnaryOperator;
41use gitql_core::environment::Environment;
42use gitql_core::values::array::ArrayValue;
43use gitql_core::values::boolean::BoolValue;
44use gitql_core::values::composite::CompositeValue;
45use gitql_core::values::float::FloatValue;
46use gitql_core::values::integer::IntValue;
47use gitql_core::values::interval::IntervalValue;
48use gitql_core::values::null::NullValue;
49use gitql_core::values::row::RowValue;
50use gitql_core::values::text::TextValue;
51use gitql_core::values::Value;
52
53use std::cmp::Ordering;
54use std::string::String;
55
56#[allow(clippy::borrowed_box)]
57pub fn evaluate_expression(
58 env: &mut Environment,
59 expression: &Box<dyn Expr>,
60 titles: &[String],
61 object: &Vec<Box<dyn Value>>,
62) -> Result<Box<dyn Value>, String> {
63 match expression.kind() {
64 Assignment => {
65 let expr = expression
66 .as_any()
67 .downcast_ref::<AssignmentExpr>()
68 .unwrap();
69 evaluate_assignment(env, expr, titles, object)
70 }
71 String => {
72 let expr = expression.as_any().downcast_ref::<StringExpr>().unwrap();
73 evaluate_string(expr)
74 }
75 Symbol => {
76 let expr = expression.as_any().downcast_ref::<SymbolExpr>().unwrap();
77 evaluate_symbol(expr, titles, object)
78 }
79 Array => {
80 let expr = expression.as_any().downcast_ref::<ArrayExpr>().unwrap();
81 evaluate_array(env, expr, titles, object)
82 }
83 GlobalVariable => {
84 let expr = expression
85 .as_any()
86 .downcast_ref::<GlobalVariableExpr>()
87 .unwrap();
88 evaluate_global_variable(env, expr)
89 }
90 Number => {
91 let expr = expression.as_any().downcast_ref::<NumberExpr>().unwrap();
92 evaluate_number(expr)
93 }
94 Boolean => {
95 let expr = expression.as_any().downcast_ref::<BooleanExpr>().unwrap();
96 evaluate_boolean(expr)
97 }
98 Interval => {
99 let expr = expression.as_any().downcast_ref::<IntervalExpr>().unwrap();
100 evaluate_interval(expr)
101 }
102 PrefixUnary => {
103 let expr = expression.as_any().downcast_ref::<UnaryExpr>().unwrap();
104 evaluate_prefix_unary(env, expr, titles, object)
105 }
106 Index => {
107 let expr = expression.as_any().downcast_ref::<IndexExpr>().unwrap();
108 evaluate_collection_index(env, expr, titles, object)
109 }
110 Slice => {
111 let expr = expression.as_any().downcast_ref::<SliceExpr>().unwrap();
112 evaluate_collection_slice(env, expr, titles, object)
113 }
114 Arithmetic => {
115 let expr = expression
116 .as_any()
117 .downcast_ref::<ArithmeticExpr>()
118 .unwrap();
119 evaluate_arithmetic(env, expr, titles, object)
120 }
121 Comparison => {
122 let expr = expression
123 .as_any()
124 .downcast_ref::<ComparisonExpr>()
125 .unwrap();
126 evaluate_comparison(env, expr, titles, object)
127 }
128 GroupComparison => {
129 let expr = expression
130 .as_any()
131 .downcast_ref::<GroupComparisonExpr>()
132 .unwrap();
133 evaluate_group_comparison(env, expr, titles, object)
134 }
135 Contains => {
136 let expr = expression.as_any().downcast_ref::<ContainsExpr>().unwrap();
137 evaluate_contains(env, expr, titles, object)
138 }
139 ContainedBy => {
140 let expr = expression
141 .as_any()
142 .downcast_ref::<ContainedByExpr>()
143 .unwrap();
144 evaluate_contained_by(env, expr, titles, object)
145 }
146 Like => {
147 let expr = expression.as_any().downcast_ref::<LikeExpr>().unwrap();
148 evaluate_like(env, expr, titles, object)
149 }
150 Regex => {
151 let expr = expression.as_any().downcast_ref::<RegexExpr>().unwrap();
152 evaluate_regex(env, expr, titles, object)
153 }
154 Glob => {
155 let expr = expression.as_any().downcast_ref::<GlobExpr>().unwrap();
156 evaluate_glob(env, expr, titles, object)
157 }
158 Logical => {
159 let expr = expression.as_any().downcast_ref::<LogicalExpr>().unwrap();
160 evaluate_logical(env, expr, titles, object)
161 }
162 Bitwise => {
163 let expr = expression.as_any().downcast_ref::<BitwiseExpr>().unwrap();
164 evaluate_bitwise(env, expr, titles, object)
165 }
166 Call => {
167 let expr = expression.as_any().downcast_ref::<CallExpr>().unwrap();
168 evaluate_call(env, expr, titles, object)
169 }
170 BenchmarkCall => {
171 let expr = expression
172 .as_any()
173 .downcast_ref::<BenchmarkCallExpr>()
174 .unwrap();
175 evaluate_benchmark_call(env, expr, titles, object)
176 }
177 Between => {
178 let expr = expression.as_any().downcast_ref::<BetweenExpr>().unwrap();
179 evaluate_between(env, expr, titles, object)
180 }
181 Case => {
182 let expr = expression.as_any().downcast_ref::<CaseExpr>().unwrap();
183 evaluate_case(env, expr, titles, object)
184 }
185 In => {
186 let expr = expression.as_any().downcast_ref::<InExpr>().unwrap();
187 evaluate_in(env, expr, titles, object)
188 }
189 IsNull => {
190 let expr = expression.as_any().downcast_ref::<IsNullExpr>().unwrap();
191 evaluate_is_null(env, expr, titles, object)
192 }
193 Cast => {
194 let expr = expression.as_any().downcast_ref::<CastExpr>().unwrap();
195 evaluate_cast(env, expr, titles, object)
196 }
197 Column => {
198 let expr = expression.as_any().downcast_ref::<ColumnExpr>().unwrap();
199 evaluate_column(env, expr, titles, object)
200 }
201 Row => {
202 let expr = expression.as_any().downcast_ref::<RowExpr>().unwrap();
203 evaluate_row(env, expr, titles, object)
204 }
205 MemberAccess => {
206 let expr = expression
207 .as_any()
208 .downcast_ref::<MemberAccessExpr>()
209 .unwrap();
210 evaluate_member_access(env, expr, titles, object)
211 }
212 Null => Ok(Box::new(NullValue)),
213 }
214}
215
216fn evaluate_assignment(
217 env: &mut Environment,
218 expr: &AssignmentExpr,
219 titles: &[String],
220 object: &Vec<Box<dyn Value>>,
221) -> Result<Box<dyn Value>, String> {
222 let value = evaluate_expression(env, &expr.value, titles, object)?;
223 env.globals.insert(expr.symbol.to_string(), value.clone());
224 Ok(value)
225}
226
227fn evaluate_string(expr: &StringExpr) -> Result<Box<dyn Value>, String> {
228 Ok(Box::new(TextValue::new(expr.value.to_owned())))
229}
230
231fn evaluate_symbol(
232 expr: &SymbolExpr,
233 titles: &[String],
234 object: &[Box<dyn Value>],
235) -> Result<Box<dyn Value>, String> {
236 for (index, title) in titles.iter().enumerate() {
237 if expr.value.eq(title) {
238 return Ok(object[index].clone());
239 }
240 }
241 Err(format!("Invalid column name `{}`", &expr.value))
242}
243
244fn evaluate_array(
245 env: &mut Environment,
246 expr: &ArrayExpr,
247 titles: &[String],
248 object: &Vec<Box<dyn Value>>,
249) -> Result<Box<dyn Value>, String> {
250 let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(expr.values.len());
251 for value in &expr.values {
252 values.push(evaluate_expression(env, value, titles, object)?);
253 }
254 Ok(Box::new(ArrayValue::new(values, expr.element_type.clone())))
255}
256
257fn evaluate_global_variable(
258 env: &mut Environment,
259 expr: &GlobalVariableExpr,
260) -> Result<Box<dyn Value>, String> {
261 let name = &expr.name;
262 if env.globals.contains_key(name) {
263 return Ok(env.globals[name].clone());
264 }
265
266 Err(format!(
267 "The value of `{name}` may be not exists or calculated yet",
268 ))
269}
270
271fn evaluate_number(expr: &NumberExpr) -> Result<Box<dyn Value>, String> {
272 Ok(match expr.value {
273 Number::Int(integer) => Box::new(IntValue::new(integer)),
274 Number::Float(float) => Box::new(FloatValue::new(float)),
275 })
276}
277
278fn evaluate_boolean(expr: &BooleanExpr) -> Result<Box<dyn Value>, String> {
279 Ok(Box::new(BoolValue::new(expr.is_true)))
280}
281
282fn evaluate_interval(expr: &IntervalExpr) -> Result<Box<dyn Value>, String> {
283 Ok(Box::new(IntervalValue::new(expr.interval.clone())))
284}
285
286fn evaluate_collection_index(
287 env: &mut Environment,
288 expr: &IndexExpr,
289 titles: &[String],
290 object: &Vec<Box<dyn Value>>,
291) -> Result<Box<dyn Value>, String> {
292 let array = evaluate_expression(env, &expr.collection, titles, object)?;
293 let index = evaluate_expression(env, &expr.index, titles, object)?;
294 array.index_op(&index)
295}
296
297fn evaluate_collection_slice(
298 env: &mut Environment,
299 expr: &SliceExpr,
300 titles: &[String],
301 object: &Vec<Box<dyn Value>>,
302) -> Result<Box<dyn Value>, String> {
303 let array = evaluate_expression(env, &expr.collection, titles, object)?;
304
305 let start = if let Some(start_expr) = &expr.start {
306 Some(evaluate_expression(env, start_expr, titles, object)?)
307 } else {
308 None
309 };
310
311 let end = if let Some(end_expr) = &expr.end {
312 Some(evaluate_expression(env, end_expr, titles, object)?)
313 } else {
314 None
315 };
316
317 array.slice_op(&start, &end)
318}
319
320fn evaluate_prefix_unary(
321 env: &mut Environment,
322 expr: &UnaryExpr,
323 titles: &[String],
324 object: &Vec<Box<dyn Value>>,
325) -> Result<Box<dyn Value>, String> {
326 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
327 match expr.operator {
328 PrefixUnaryOperator::Plus => rhs.plus_op(),
329 PrefixUnaryOperator::Minus => rhs.neg_op(),
330 PrefixUnaryOperator::Bang => rhs.bang_op(),
331 PrefixUnaryOperator::Not => rhs.not_op(),
332 }
333}
334
335fn evaluate_arithmetic(
336 env: &mut Environment,
337 expr: &ArithmeticExpr,
338 titles: &[String],
339 object: &Vec<Box<dyn Value>>,
340) -> Result<Box<dyn Value>, String> {
341 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
342 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
343 match expr.operator {
344 ArithmeticOperator::Plus => lhs.add_op(&rhs),
345 ArithmeticOperator::Minus => lhs.sub_op(&rhs),
346 ArithmeticOperator::Star => lhs.mul_op(&rhs),
347 ArithmeticOperator::Slash => lhs.div_op(&rhs),
348 ArithmeticOperator::Modulus => lhs.rem_op(&rhs),
349 ArithmeticOperator::Exponentiation => lhs.caret_op(&rhs),
350 }
351}
352
353fn evaluate_comparison(
354 env: &mut Environment,
355 expr: &ComparisonExpr,
356 titles: &[String],
357 object: &Vec<Box<dyn Value>>,
358) -> Result<Box<dyn Value>, String> {
359 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
360 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
361 match expr.operator {
362 ComparisonOperator::Greater => lhs.gt_op(&rhs),
363 ComparisonOperator::GreaterEqual => lhs.gte_op(&rhs),
364 ComparisonOperator::Less => lhs.lt_op(&rhs),
365 ComparisonOperator::LessEqual => lhs.lte_op(&rhs),
366 ComparisonOperator::Equal => lhs.eq_op(&rhs),
367 ComparisonOperator::NotEqual => lhs.bang_eq_op(&rhs),
368 ComparisonOperator::NullSafeEqual => lhs.null_safe_eq_op(&rhs),
369 }
370}
371
372fn evaluate_group_comparison(
373 env: &mut Environment,
374 expr: &GroupComparisonExpr,
375 titles: &[String],
376 object: &Vec<Box<dyn Value>>,
377) -> Result<Box<dyn Value>, String> {
378 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
379 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
380 match expr.comparison_operator {
381 ComparisonOperator::Greater => lhs.group_gt_op(&rhs, &expr.group_operator),
382 ComparisonOperator::GreaterEqual => lhs.group_gte_op(&rhs, &expr.group_operator),
383 ComparisonOperator::Less => lhs.group_lt_op(&rhs, &expr.group_operator),
384 ComparisonOperator::LessEqual => lhs.group_lte_op(&rhs, &expr.group_operator),
385 ComparisonOperator::Equal => lhs.group_eq_op(&rhs, &expr.group_operator),
386 ComparisonOperator::NotEqual => lhs.group_bang_eq_op(&rhs, &expr.group_operator),
387 ComparisonOperator::NullSafeEqual => lhs.group_null_safe_eq_op(&rhs, &expr.group_operator),
388 }
389}
390
391fn evaluate_contains(
392 env: &mut Environment,
393 expr: &ContainsExpr,
394 titles: &[String],
395 object: &Vec<Box<dyn Value>>,
396) -> Result<Box<dyn Value>, String> {
397 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
398 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
399 lhs.contains_op(&rhs)
400}
401
402fn evaluate_contained_by(
403 env: &mut Environment,
404 expr: &ContainedByExpr,
405 titles: &[String],
406 object: &Vec<Box<dyn Value>>,
407) -> Result<Box<dyn Value>, String> {
408 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
409 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
410 rhs.contains_op(&lhs)
411}
412
413fn evaluate_like(
414 env: &mut Environment,
415 expr: &LikeExpr,
416 titles: &[String],
417 object: &Vec<Box<dyn Value>>,
418) -> Result<Box<dyn Value>, String> {
419 let input = evaluate_expression(env, &expr.input, titles, object)?;
420 let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
421 input.like_op(&pattern)
422}
423
424fn evaluate_regex(
425 env: &mut Environment,
426 expr: &RegexExpr,
427 titles: &[String],
428 object: &Vec<Box<dyn Value>>,
429) -> Result<Box<dyn Value>, String> {
430 let input = evaluate_expression(env, &expr.input, titles, object)?;
431 let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
432 input.regexp_op(&pattern)
433}
434
435fn evaluate_glob(
436 env: &mut Environment,
437 expr: &GlobExpr,
438 titles: &[String],
439 object: &Vec<Box<dyn Value>>,
440) -> Result<Box<dyn Value>, String> {
441 let input = evaluate_expression(env, &expr.input, titles, object)?;
442 let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
443 input.glob_op(&pattern)
444}
445
446fn evaluate_logical(
447 env: &mut Environment,
448 expr: &LogicalExpr,
449 titles: &[String],
450 object: &Vec<Box<dyn Value>>,
451) -> Result<Box<dyn Value>, String> {
452 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
453 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
454 match expr.operator {
455 BinaryLogicalOperator::And => lhs.logical_and_op(&rhs),
456 BinaryLogicalOperator::Or => lhs.logical_or_op(&rhs),
457 BinaryLogicalOperator::Xor => lhs.logical_xor_op(&rhs),
458 }
459}
460
461fn evaluate_bitwise(
462 env: &mut Environment,
463 expr: &BitwiseExpr,
464 titles: &[String],
465 object: &Vec<Box<dyn Value>>,
466) -> Result<Box<dyn Value>, String> {
467 let lhs = evaluate_expression(env, &expr.left, titles, object)?;
468 let rhs = evaluate_expression(env, &expr.right, titles, object)?;
469 match expr.operator {
470 BinaryBitwiseOperator::Or => lhs.or_op(&rhs),
471 BinaryBitwiseOperator::And => lhs.and_op(&rhs),
472 BinaryBitwiseOperator::Xor => lhs.xor_op(&rhs),
473 BinaryBitwiseOperator::RightShift => lhs.shr_op(&rhs),
474 BinaryBitwiseOperator::LeftShift => lhs.shl_op(&rhs),
475 }
476}
477
478fn evaluate_call(
479 env: &mut Environment,
480 expr: &CallExpr,
481 titles: &[String],
482 object: &Vec<Box<dyn Value>>,
483) -> Result<Box<dyn Value>, String> {
484 let function_name = expr.function_name.as_str();
485 let mut arguments = Vec::with_capacity(expr.arguments.len());
486 for arg in expr.arguments.iter() {
487 arguments.push(evaluate_expression(env, arg, titles, object)?);
488 }
489 let function = env.std_function(function_name).unwrap();
490 Ok(function(&arguments))
491}
492
493fn evaluate_benchmark_call(
494 env: &mut Environment,
495 expr: &BenchmarkCallExpr,
496 titles: &[String],
497 object: &Vec<Box<dyn Value>>,
498) -> Result<Box<dyn Value>, String> {
499 let number_of_execution = evaluate_expression(env, &expr.count, titles, object)?;
500 if let Some(number) = number_of_execution.as_any().downcast_ref::<IntValue>() {
501 for _ in 0..number.value {
502 evaluate_expression(env, &expr.expression, titles, object)?;
503 }
504 }
505 Ok(Box::new(IntValue::new_zero()))
506}
507
508fn evaluate_between(
509 env: &mut Environment,
510 expr: &BetweenExpr,
511 titles: &[String],
512 object: &Vec<Box<dyn Value>>,
513) -> Result<Box<dyn Value>, String> {
514 let value = evaluate_expression(env, &expr.value, titles, object)?;
515 let range_start = evaluate_expression(env, &expr.range_start, titles, object)?;
516 let range_end = evaluate_expression(env, &expr.range_end, titles, object)?;
517 let comparing_result = match expr.kind {
518 BetweenKind::Symmetric => {
519 let (start, end) = if let Some(order) = range_start.compare(&range_end) {
520 if Ordering::is_gt(order) {
521 (range_end, range_start)
522 } else {
523 (range_start, range_end)
524 }
525 } else {
526 (range_start, range_end)
527 };
528 value.compare(&start).unwrap().is_ge() && value.compare(&end).unwrap().is_le()
529 }
530 BetweenKind::Asymmetric => {
531 value.compare(&range_start).unwrap().is_ge()
532 && value.compare(&range_end).unwrap().is_le()
533 }
534 };
535 Ok(Box::new(BoolValue::new(comparing_result)))
536}
537
538fn evaluate_case(
539 env: &mut Environment,
540 expr: &CaseExpr,
541 titles: &[String],
542 object: &Vec<Box<dyn Value>>,
543) -> Result<Box<dyn Value>, String> {
544 let conditions = &expr.conditions;
545 let values = &expr.values;
546
547 for i in 0..conditions.len() {
548 let condition = evaluate_expression(env, &conditions[i], titles, object)?;
549 if let Some(bool_value) = condition.as_any().downcast_ref::<BoolValue>() {
550 if bool_value.value {
551 return evaluate_expression(env, &values[i], titles, object);
552 }
553 }
554 }
555
556 match &expr.default_value {
557 Some(default_value) => evaluate_expression(env, default_value, titles, object),
558 _ => Err("Invalid case statement".to_owned()),
559 }
560}
561
562fn evaluate_in(
563 env: &mut Environment,
564 expr: &InExpr,
565 titles: &[String],
566 object: &Vec<Box<dyn Value>>,
567) -> Result<Box<dyn Value>, String> {
568 let argument = evaluate_expression(env, &expr.argument, titles, object)?;
569 for value_expr in &expr.values {
570 let value = evaluate_expression(env, value_expr, titles, object)?;
571 if argument.equals(&value) {
572 return Ok(Box::new(BoolValue::new(!expr.has_not_keyword)));
573 }
574 }
575 Ok(Box::new(BoolValue::new(expr.has_not_keyword)))
576}
577
578fn evaluate_is_null(
579 env: &mut Environment,
580 expr: &IsNullExpr,
581 titles: &[String],
582 object: &Vec<Box<dyn Value>>,
583) -> Result<Box<dyn Value>, String> {
584 let argument = evaluate_expression(env, &expr.argument, titles, object)?;
585 let is_null = argument.as_any().downcast_ref::<NullValue>().is_some();
586 let result = if expr.has_not { !is_null } else { is_null };
587 Ok(Box::new(BoolValue::new(result)))
588}
589
590fn evaluate_cast(
591 env: &mut Environment,
592 expr: &CastExpr,
593 titles: &[String],
594 object: &Vec<Box<dyn Value>>,
595) -> Result<Box<dyn Value>, String> {
596 let value = evaluate_expression(env, &expr.value, titles, object)?;
597 value.cast_op(&expr.result_type)
598}
599
600fn evaluate_column(
601 env: &mut Environment,
602 expr: &ColumnExpr,
603 titles: &[String],
604 object: &Vec<Box<dyn Value>>,
605) -> Result<Box<dyn Value>, String> {
606 let value = evaluate_expression(env, &expr.expr, titles, object)?;
607 Ok(value)
608}
609
610fn evaluate_row(
611 env: &mut Environment,
612 expr: &RowExpr,
613 titles: &[String],
614 object: &Vec<Box<dyn Value>>,
615) -> Result<Box<dyn Value>, String> {
616 let mut values = Vec::with_capacity(expr.exprs.len());
617 for column in expr.exprs.iter() {
618 values.push(evaluate_expression(env, column, titles, object)?);
619 }
620 Ok(Box::new(RowValue::new(values, expr.row_type.to_owned())))
621}
622
623fn evaluate_member_access(
624 env: &mut Environment,
625 expr: &MemberAccessExpr,
626 titles: &[String],
627 object: &Vec<Box<dyn Value>>,
628) -> Result<Box<dyn Value>, String> {
629 let value = evaluate_expression(env, &expr.composite, titles, object)?;
630 if let Some(composite_value) = value.as_any().downcast_ref::<CompositeValue>() {
631 let member_name = &expr.member_name;
632 return Ok(composite_value.members.get(member_name).unwrap().clone());
633 }
634 Err("Invalid value for Member access expression".to_owned())
635}