use crate::position::PositionInLanguageTerm;
use crate::rule::RewriteRule;
use crate::rules::util::lpo::is_greater_as_per_lexicographic_path_ordering;
use crate::term::syntax::{
LanguageTerm, LanguageTermNode, RewritableLanguageOperatorSymbol, TermFactory,
};
pub trait CommutativeCheckerAndOrderer<LOS: RewritableLanguageOperatorSymbol> {
fn is_a_binary_commutative_operator(&self, op: &LOS) -> bool;
fn may_commute_under(
&self,
parent_op: &LOS,
left_sub_term: &LanguageTerm<LOS>,
right_sub_term: &LanguageTerm<LOS>,
) -> bool;
fn compare_operators(&self, op1: &LOS, op2: &LOS) -> std::cmp::Ordering;
}
pub struct CommuteReorderRule<LOS: RewritableLanguageOperatorSymbol> {
desc: String,
checker: Box<dyn CommutativeCheckerAndOrderer<LOS>>,
}
impl<LOS: RewritableLanguageOperatorSymbol> CommuteReorderRule<LOS> {
pub fn new(
desc: impl Into<String>,
checker: impl CommutativeCheckerAndOrderer<LOS> + 'static,
) -> Self {
Self {
desc: desc.into(),
checker: Box::new(checker),
}
}
}
impl<LOS: RewritableLanguageOperatorSymbol> RewriteRule<LOS> for CommuteReorderRule<LOS> {
fn get_desc(&self) -> String {
self.desc.clone()
}
fn try_apply(
&self,
term: &LanguageTerm<LOS>,
_ctx: &LanguageTerm<LOS>,
_pos: &PositionInLanguageTerm,
factory: &mut TermFactory<LOS>,
) -> Option<LanguageTerm<LOS>> {
let op = &term.operator;
if !self.checker.is_a_binary_commutative_operator(op) {
return None;
}
let left = &term.sub_terms[0];
let right = &term.sub_terms[1];
if self.checker.may_commute_under(op, left, right)
&& is_greater_as_per_lexicographic_path_ordering::<LOS>(left, right, &|x, y| {
self.checker.compare_operators(x, y)
})
{
Some(LanguageTermNode::build(
op.clone(),
vec![right.clone(), left.clone()],
factory,
))
} else {
None
}
}
}