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::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}