gitql_engine/
engine_evaluator.rs

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::Negative => rhs.neg_op(),
329        PrefixUnaryOperator::Bang => rhs.bang_op(),
330        PrefixUnaryOperator::Not => rhs.not_op(),
331    }
332}
333
334fn evaluate_arithmetic(
335    env: &mut Environment,
336    expr: &ArithmeticExpr,
337    titles: &[String],
338    object: &Vec<Box<dyn Value>>,
339) -> Result<Box<dyn Value>, String> {
340    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
341    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
342    match expr.operator {
343        ArithmeticOperator::Plus => lhs.add_op(&rhs),
344        ArithmeticOperator::Minus => lhs.sub_op(&rhs),
345        ArithmeticOperator::Star => lhs.mul_op(&rhs),
346        ArithmeticOperator::Slash => lhs.div_op(&rhs),
347        ArithmeticOperator::Modulus => lhs.rem_op(&rhs),
348        ArithmeticOperator::Exponentiation => lhs.caret_op(&rhs),
349    }
350}
351
352fn evaluate_comparison(
353    env: &mut Environment,
354    expr: &ComparisonExpr,
355    titles: &[String],
356    object: &Vec<Box<dyn Value>>,
357) -> Result<Box<dyn Value>, String> {
358    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
359    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
360    match expr.operator {
361        ComparisonOperator::Greater => lhs.gt_op(&rhs),
362        ComparisonOperator::GreaterEqual => lhs.gte_op(&rhs),
363        ComparisonOperator::Less => lhs.lt_op(&rhs),
364        ComparisonOperator::LessEqual => lhs.lte_op(&rhs),
365        ComparisonOperator::Equal => lhs.eq_op(&rhs),
366        ComparisonOperator::NotEqual => lhs.bang_eq_op(&rhs),
367        ComparisonOperator::NullSafeEqual => lhs.null_safe_eq_op(&rhs),
368    }
369}
370
371fn evaluate_group_comparison(
372    env: &mut Environment,
373    expr: &GroupComparisonExpr,
374    titles: &[String],
375    object: &Vec<Box<dyn Value>>,
376) -> Result<Box<dyn Value>, String> {
377    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
378    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
379    match expr.comparison_operator {
380        ComparisonOperator::Greater => lhs.group_gt_op(&rhs, &expr.group_operator),
381        ComparisonOperator::GreaterEqual => lhs.group_gte_op(&rhs, &expr.group_operator),
382        ComparisonOperator::Less => lhs.group_lt_op(&rhs, &expr.group_operator),
383        ComparisonOperator::LessEqual => lhs.group_lte_op(&rhs, &expr.group_operator),
384        ComparisonOperator::Equal => lhs.group_eq_op(&rhs, &expr.group_operator),
385        ComparisonOperator::NotEqual => lhs.group_bang_eq_op(&rhs, &expr.group_operator),
386        ComparisonOperator::NullSafeEqual => lhs.group_null_safe_eq_op(&rhs, &expr.group_operator),
387    }
388}
389
390fn evaluate_contains(
391    env: &mut Environment,
392    expr: &ContainsExpr,
393    titles: &[String],
394    object: &Vec<Box<dyn Value>>,
395) -> Result<Box<dyn Value>, String> {
396    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
397    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
398    lhs.contains_op(&rhs)
399}
400
401fn evaluate_contained_by(
402    env: &mut Environment,
403    expr: &ContainedByExpr,
404    titles: &[String],
405    object: &Vec<Box<dyn Value>>,
406) -> Result<Box<dyn Value>, String> {
407    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
408    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
409    rhs.contains_op(&lhs)
410}
411
412fn evaluate_like(
413    env: &mut Environment,
414    expr: &LikeExpr,
415    titles: &[String],
416    object: &Vec<Box<dyn Value>>,
417) -> Result<Box<dyn Value>, String> {
418    let input = evaluate_expression(env, &expr.input, titles, object)?;
419    let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
420    input.like_op(&pattern)
421}
422
423fn evaluate_regex(
424    env: &mut Environment,
425    expr: &RegexExpr,
426    titles: &[String],
427    object: &Vec<Box<dyn Value>>,
428) -> Result<Box<dyn Value>, String> {
429    let input = evaluate_expression(env, &expr.input, titles, object)?;
430    let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
431    input.regexp_op(&pattern)
432}
433
434fn evaluate_glob(
435    env: &mut Environment,
436    expr: &GlobExpr,
437    titles: &[String],
438    object: &Vec<Box<dyn Value>>,
439) -> Result<Box<dyn Value>, String> {
440    let input = evaluate_expression(env, &expr.input, titles, object)?;
441    let pattern = evaluate_expression(env, &expr.pattern, titles, object)?;
442    input.glob_op(&pattern)
443}
444
445fn evaluate_logical(
446    env: &mut Environment,
447    expr: &LogicalExpr,
448    titles: &[String],
449    object: &Vec<Box<dyn Value>>,
450) -> Result<Box<dyn Value>, String> {
451    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
452    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
453    match expr.operator {
454        BinaryLogicalOperator::And => lhs.logical_and_op(&rhs),
455        BinaryLogicalOperator::Or => lhs.logical_or_op(&rhs),
456        BinaryLogicalOperator::Xor => lhs.logical_xor_op(&rhs),
457    }
458}
459
460fn evaluate_bitwise(
461    env: &mut Environment,
462    expr: &BitwiseExpr,
463    titles: &[String],
464    object: &Vec<Box<dyn Value>>,
465) -> Result<Box<dyn Value>, String> {
466    let lhs = evaluate_expression(env, &expr.left, titles, object)?;
467    let rhs = evaluate_expression(env, &expr.right, titles, object)?;
468    match expr.operator {
469        BinaryBitwiseOperator::Or => lhs.or_op(&rhs),
470        BinaryBitwiseOperator::And => lhs.and_op(&rhs),
471        BinaryBitwiseOperator::Xor => lhs.xor_op(&rhs),
472        BinaryBitwiseOperator::RightShift => lhs.shr_op(&rhs),
473        BinaryBitwiseOperator::LeftShift => lhs.shl_op(&rhs),
474    }
475}
476
477fn evaluate_call(
478    env: &mut Environment,
479    expr: &CallExpr,
480    titles: &[String],
481    object: &Vec<Box<dyn Value>>,
482) -> Result<Box<dyn Value>, String> {
483    let function_name = expr.function_name.as_str();
484    let mut arguments = Vec::with_capacity(expr.arguments.len());
485    for arg in expr.arguments.iter() {
486        arguments.push(evaluate_expression(env, arg, titles, object)?);
487    }
488    let function = env.std_function(function_name).unwrap();
489    Ok(function(&arguments))
490}
491
492fn evaluate_benchmark_call(
493    env: &mut Environment,
494    expr: &BenchmarkCallExpr,
495    titles: &[String],
496    object: &Vec<Box<dyn Value>>,
497) -> Result<Box<dyn Value>, String> {
498    let number_of_execution = evaluate_expression(env, &expr.count, titles, object)?;
499    if let Some(number) = number_of_execution.as_any().downcast_ref::<IntValue>() {
500        for _ in 0..number.value {
501            evaluate_expression(env, &expr.expression, titles, object)?;
502        }
503    }
504    Ok(Box::new(IntValue::new_zero()))
505}
506
507fn evaluate_between(
508    env: &mut Environment,
509    expr: &BetweenExpr,
510    titles: &[String],
511    object: &Vec<Box<dyn Value>>,
512) -> Result<Box<dyn Value>, String> {
513    let value = evaluate_expression(env, &expr.value, titles, object)?;
514    let range_start = evaluate_expression(env, &expr.range_start, titles, object)?;
515    let range_end = evaluate_expression(env, &expr.range_end, titles, object)?;
516    let comparing_result = match expr.kind {
517        BetweenKind::Symmetric => {
518            let (start, end) = if let Some(order) = range_start.compare(&range_end) {
519                if Ordering::is_gt(order) {
520                    (range_end, range_start)
521                } else {
522                    (range_start, range_end)
523                }
524            } else {
525                (range_start, range_end)
526            };
527            value.compare(&start).unwrap().is_ge() && value.compare(&end).unwrap().is_le()
528        }
529        BetweenKind::Asymmetric => {
530            value.compare(&range_start).unwrap().is_ge()
531                && value.compare(&range_end).unwrap().is_le()
532        }
533    };
534    Ok(Box::new(BoolValue::new(comparing_result)))
535}
536
537fn evaluate_case(
538    env: &mut Environment,
539    expr: &CaseExpr,
540    titles: &[String],
541    object: &Vec<Box<dyn Value>>,
542) -> Result<Box<dyn Value>, String> {
543    let conditions = &expr.conditions;
544    let values = &expr.values;
545
546    for i in 0..conditions.len() {
547        let condition = evaluate_expression(env, &conditions[i], titles, object)?;
548        if let Some(bool_value) = condition.as_any().downcast_ref::<BoolValue>() {
549            if bool_value.value {
550                return evaluate_expression(env, &values[i], titles, object);
551            }
552        }
553    }
554
555    match &expr.default_value {
556        Some(default_value) => evaluate_expression(env, default_value, titles, object),
557        _ => Err("Invalid case statement".to_owned()),
558    }
559}
560
561fn evaluate_in(
562    env: &mut Environment,
563    expr: &InExpr,
564    titles: &[String],
565    object: &Vec<Box<dyn Value>>,
566) -> Result<Box<dyn Value>, String> {
567    let argument = evaluate_expression(env, &expr.argument, titles, object)?;
568    for value_expr in &expr.values {
569        let value = evaluate_expression(env, value_expr, titles, object)?;
570        if argument.equals(&value) {
571            return Ok(Box::new(BoolValue::new(!expr.has_not_keyword)));
572        }
573    }
574    Ok(Box::new(BoolValue::new(expr.has_not_keyword)))
575}
576
577fn evaluate_is_null(
578    env: &mut Environment,
579    expr: &IsNullExpr,
580    titles: &[String],
581    object: &Vec<Box<dyn Value>>,
582) -> Result<Box<dyn Value>, String> {
583    let argument = evaluate_expression(env, &expr.argument, titles, object)?;
584    let is_null = argument.as_any().downcast_ref::<NullValue>().is_some();
585    let result = if expr.has_not { !is_null } else { is_null };
586    Ok(Box::new(BoolValue::new(result)))
587}
588
589fn evaluate_cast(
590    env: &mut Environment,
591    expr: &CastExpr,
592    titles: &[String],
593    object: &Vec<Box<dyn Value>>,
594) -> Result<Box<dyn Value>, String> {
595    let value = evaluate_expression(env, &expr.value, titles, object)?;
596    value.cast_op(&expr.result_type)
597}
598
599fn evaluate_column(
600    env: &mut Environment,
601    expr: &ColumnExpr,
602    titles: &[String],
603    object: &Vec<Box<dyn Value>>,
604) -> Result<Box<dyn Value>, String> {
605    let value = evaluate_expression(env, &expr.expr, titles, object)?;
606    Ok(value)
607}
608
609fn evaluate_row(
610    env: &mut Environment,
611    expr: &RowExpr,
612    titles: &[String],
613    object: &Vec<Box<dyn Value>>,
614) -> Result<Box<dyn Value>, String> {
615    let mut values = Vec::with_capacity(expr.exprs.len());
616    for column in expr.exprs.iter() {
617        values.push(evaluate_expression(env, column, titles, object)?);
618    }
619    Ok(Box::new(RowValue::new(values, expr.row_type.to_owned())))
620}
621
622fn evaluate_member_access(
623    env: &mut Environment,
624    expr: &MemberAccessExpr,
625    titles: &[String],
626    object: &Vec<Box<dyn Value>>,
627) -> Result<Box<dyn Value>, String> {
628    let value = evaluate_expression(env, &expr.composite, titles, object)?;
629    if let Some(composite_value) = value.as_any().downcast_ref::<CompositeValue>() {
630        let member_name = &expr.member_name;
631        return Ok(composite_value.members.get(member_name).unwrap().clone());
632    }
633    Err("Invalid value for Member access expression".to_owned())
634}