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}