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