use crate::computation::{
arithmetic_operation, comparison_operation, convert_unit, UnitResolutionContext,
};
use crate::evaluation::OperationResult;
use crate::planning::semantics::{DataPath, Expression, ExpressionKind, LiteralValue, ValueKind};
use crate::planning::ExecutionPlan;
use std::collections::HashMap;
pub(crate) fn try_resolve_value(
expr: &Expression,
known_values: &HashMap<DataPath, LiteralValue>,
plan: &ExecutionPlan,
) -> Option<LiteralValue> {
let unit_index = plan.expression_unit_index();
match &expr.kind {
ExpressionKind::Literal(literal) => Some(*literal.clone()),
ExpressionKind::DataPath(data_path) => known_values.get(data_path).cloned(),
ExpressionKind::Comparison(left_expr, op, right_expr) => {
let left_value = try_resolve_value(left_expr, known_values, plan)?;
let right_value = try_resolve_value(right_expr, known_values, plan)?;
match comparison_operation(
&left_value,
op,
&right_value,
UnitResolutionContext::WithIndex(unit_index),
) {
OperationResult::Value(result) => Some(result),
OperationResult::Veto(_) => None,
}
}
ExpressionKind::Arithmetic(left_expr, op, right_expr) => {
let left_value = try_resolve_value(left_expr, known_values, plan)?;
let right_value = try_resolve_value(right_expr, known_values, plan)?;
match arithmetic_operation(
&left_value,
op,
&right_value,
unit_index,
&plan.signature_index,
) {
OperationResult::Value(result) => Some(result),
OperationResult::Veto(_) => None,
}
}
ExpressionKind::UnitConversion(inner_expr, target) => {
let inner_value = try_resolve_value(inner_expr, known_values, plan)?;
match convert_unit(&inner_value, target) {
OperationResult::Value(result) => Some(result),
OperationResult::Veto(_) => None,
}
}
ExpressionKind::RulePath(_)
| ExpressionKind::Veto(_)
| ExpressionKind::Now
| ExpressionKind::DateRelative(_, _)
| ExpressionKind::DateCalendar(_, _, _)
| ExpressionKind::PastFutureRange(_, _)
| ExpressionKind::RangeLiteral(_, _)
| ExpressionKind::RangeContainment(_, _)
| ExpressionKind::MathematicalComputation(_, _)
| ExpressionKind::ResultIsVeto(_)
| ExpressionKind::LogicalAnd(_, _)
| ExpressionKind::LogicalOr(_, _)
| ExpressionKind::LogicalNegation(_, _)
| ExpressionKind::Piecewise(_) => None,
}
}
pub(crate) fn try_evaluate_condition(
expr: &Expression,
known_values: &HashMap<DataPath, LiteralValue>,
plan: &ExecutionPlan,
) -> Option<bool> {
match &expr.kind {
ExpressionKind::LogicalAnd(left_expr, right_expr) => {
let left_result = try_evaluate_condition(left_expr, known_values, plan);
let right_result = try_evaluate_condition(right_expr, known_values, plan);
match (left_result, right_result) {
(Some(false), _) | (_, Some(false)) => Some(false),
(Some(true), Some(true)) => Some(true),
_ => None,
}
}
ExpressionKind::LogicalOr(left_expr, right_expr) => {
let left_result = try_evaluate_condition(left_expr, known_values, plan);
let right_result = try_evaluate_condition(right_expr, known_values, plan);
match (left_result, right_result) {
(Some(true), _) | (_, Some(true)) => Some(true),
(Some(false), Some(false)) => Some(false),
_ => None,
}
}
ExpressionKind::LogicalNegation(inner_expr, _negation_type) => {
try_evaluate_condition(inner_expr, known_values, plan).map(|b| !b)
}
_ => {
let value = try_resolve_value(expr, known_values, plan)?;
match value.value {
ValueKind::Boolean(boolean) => Some(boolean),
_ => None,
}
}
}
}