use super::super::expr_facts::{fold_associative_duplicate_and, fold_associative_duplicate_or};
use crate::hir::common::{HirExpr, HirLogicalExpr};
pub(super) fn logical_and(lhs: HirExpr, rhs: HirExpr) -> HirExpr {
if lhs == rhs {
lhs
} else {
HirExpr::LogicalAnd(Box::new(HirLogicalExpr { lhs, rhs }))
}
}
pub(super) fn logical_or(lhs: HirExpr, rhs: HirExpr) -> HirExpr {
if lhs == rhs {
lhs
} else {
HirExpr::LogicalOr(Box::new(HirLogicalExpr { lhs, rhs }))
}
}
pub(super) fn simplify_lua_logical_shape(expr: &HirExpr) -> Option<HirExpr> {
match expr {
HirExpr::LogicalAnd(logical) => simplify_logical_and(&logical.lhs, &logical.rhs),
HirExpr::LogicalOr(logical) => simplify_logical_or(&logical.lhs, &logical.rhs),
_ => None,
}
}
pub(super) fn simplify_condition_truthiness_shape(expr: &HirExpr) -> Option<HirExpr> {
match expr {
HirExpr::LogicalAnd(logical) => simplify_condition_logical_and(&logical.lhs, &logical.rhs),
HirExpr::LogicalOr(logical) => simplify_condition_logical_or(&logical.lhs, &logical.rhs),
_ => None,
}
}
fn simplify_logical_and(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
if lhs == rhs {
return Some(lhs.clone());
}
if let Some(replacement) = fold_associative_duplicate_and(lhs, rhs) {
return Some(replacement);
}
match rhs {
HirExpr::LogicalOr(inner) if lhs == &inner.lhs => Some(lhs.clone()),
_ => match lhs {
HirExpr::LogicalOr(inner) if rhs == &inner.lhs || rhs == &inner.rhs => {
Some(rhs.clone())
}
_ => None,
},
}
}
fn simplify_logical_or(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
if lhs == rhs {
return Some(lhs.clone());
}
if let Some(replacement) = fold_associative_duplicate_or(lhs, rhs) {
return Some(replacement);
}
if let Some(replacement) = factor_shared_and_guards(lhs, rhs) {
return Some(replacement);
}
if let Some(replacement) = pull_shared_or_tail(lhs, rhs) {
return Some(replacement);
}
match rhs {
HirExpr::LogicalAnd(inner) if lhs == &inner.lhs => Some(lhs.clone()),
_ => match lhs {
HirExpr::LogicalAnd(inner) if rhs == &inner.lhs || rhs == &inner.rhs => {
Some(rhs.clone())
}
_ => None,
},
}
}
fn factor_shared_and_guards(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
factor_shared_and_guards_one_side(lhs, rhs)
.or_else(|| factor_shared_and_guards_one_side(rhs, lhs))
}
fn factor_shared_and_guards_one_side(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
let HirExpr::LogicalAnd(lhs_and) = lhs else {
return None;
};
let HirExpr::LogicalAnd(rhs_and) = rhs else {
return None;
};
if lhs_and.lhs == rhs_and.lhs {
return Some(logical_and(
lhs_and.lhs.clone(),
logical_or(lhs_and.rhs.clone(), rhs_and.rhs.clone()),
));
}
if lhs_and.rhs == rhs_and.rhs {
return Some(logical_and(
logical_or(lhs_and.lhs.clone(), rhs_and.lhs.clone()),
lhs_and.rhs.clone(),
));
}
None
}
fn pull_shared_or_tail(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
pull_shared_or_tail_one_side(lhs, rhs).or_else(|| pull_shared_or_tail_one_side(rhs, lhs))
}
fn pull_shared_or_tail_one_side(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
let HirExpr::LogicalAnd(lhs_and) = lhs else {
return None;
};
let HirExpr::LogicalOr(inner_or) = &lhs_and.rhs else {
return None;
};
if rhs != &inner_or.rhs {
return None;
}
Some(logical_or(
logical_and(lhs_and.lhs.clone(), inner_or.lhs.clone()),
rhs.clone(),
))
}
fn simplify_condition_logical_and(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
if matches!(rhs, HirExpr::Boolean(true)) {
return Some(lhs.clone());
}
if matches!(rhs, HirExpr::Boolean(false)) {
return Some(HirExpr::Boolean(false));
}
if matches!(lhs, HirExpr::Boolean(true)) {
return Some(rhs.clone());
}
if matches!(lhs, HirExpr::Boolean(false)) {
return Some(HirExpr::Boolean(false));
}
None
}
fn simplify_condition_logical_or(lhs: &HirExpr, rhs: &HirExpr) -> Option<HirExpr> {
if matches!(rhs, HirExpr::Boolean(false)) {
return Some(lhs.clone());
}
if matches!(rhs, HirExpr::Boolean(true)) {
return Some(HirExpr::Boolean(true));
}
if matches!(lhs, HirExpr::Boolean(false)) {
return Some(rhs.clone());
}
if matches!(lhs, HirExpr::Boolean(true)) {
return Some(HirExpr::Boolean(true));
}
None
}