use crate::position::PositionInLanguageTerm;
use crate::rule::RewriteRule;
use crate::term::syntax::{
LanguageTerm, LanguageTermNode, RewritableLanguageOperatorSymbol, TermFactory,
};
pub trait AssociativityChecker<LOS: RewritableLanguageOperatorSymbol> {
fn is_binary_associative(&self, op: &LOS) -> bool;
}
fn transformation_flush_to_the_right<LOS: RewritableLanguageOperatorSymbol>(
checker: &dyn AssociativityChecker<LOS>,
term: &LanguageTerm<LOS>,
factory: &mut TermFactory<LOS>,
) -> Option<LanguageTerm<LOS>> {
let op = &term.operator;
if !checker.is_binary_associative(op) {
return None;
}
let t1 = term.sub_terms.first().unwrap();
if &t1.operator != op {
return None;
}
let t2 = &term.sub_terms[1];
let t11 = &t1.sub_terms[0];
let t12 = &t1.sub_terms[1];
let inner = LanguageTermNode::build(op.clone(), vec![t12.clone(), t2.clone()], factory);
Some(LanguageTermNode::build(
op.clone(),
vec![t11.clone(), inner],
factory,
))
}
fn transformation_flush_to_the_left<LOS: RewritableLanguageOperatorSymbol>(
checker: &dyn AssociativityChecker<LOS>,
term: &LanguageTerm<LOS>,
factory: &mut TermFactory<LOS>,
) -> Option<LanguageTerm<LOS>> {
let op = &term.operator;
if !checker.is_binary_associative(op) {
return None;
}
let t2 = &term.sub_terms[1];
if &t2.operator != op {
return None;
}
let t1 = &term.sub_terms[0];
let t21 = &t2.sub_terms[0];
let t22 = &t2.sub_terms[1];
let inner = LanguageTermNode::build(op.clone(), vec![t1.clone(), t21.clone()], factory);
Some(LanguageTermNode::build(
op.clone(),
vec![inner, t22.clone()],
factory,
))
}
pub struct FlushRightRule<LOS: RewritableLanguageOperatorSymbol> {
desc: String,
checker: Box<dyn AssociativityChecker<LOS>>,
}
impl<LOS: RewritableLanguageOperatorSymbol> FlushRightRule<LOS> {
pub fn new(desc: impl Into<String>, checker: impl AssociativityChecker<LOS> + 'static) -> Self {
Self {
desc: desc.into(),
checker: Box::new(checker),
}
}
}
impl<LOS: RewritableLanguageOperatorSymbol> RewriteRule<LOS> for FlushRightRule<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>> {
transformation_flush_to_the_right(self.checker.as_ref(), term, factory)
}
}
pub struct FlushLeftRule<LOS: RewritableLanguageOperatorSymbol> {
desc: String,
checker: Box<dyn AssociativityChecker<LOS>>,
}
impl<LOS: RewritableLanguageOperatorSymbol> FlushLeftRule<LOS> {
pub fn new(desc: impl Into<String>, checker: impl AssociativityChecker<LOS> + 'static) -> Self {
Self {
desc: desc.into(),
checker: Box::new(checker),
}
}
}
impl<LOS: RewritableLanguageOperatorSymbol> RewriteRule<LOS> for FlushLeftRule<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>> {
transformation_flush_to_the_left(self.checker.as_ref(), term, factory)
}
}