#![forbid(unsafe_code)]
use log::info;
use merc_data::DataApplication;
use merc_data::DataExpression;
use merc_data::DataExpressionRef;
use merc_utilities::debug_trace;
use crate::AnnouncementInnermost;
use crate::MatchAnnouncement;
use crate::RewriteEngine;
use crate::RewriteSpecification;
use crate::RewritingStatistics;
use crate::set_automaton::SetAutomaton;
use crate::utilities::DataPositionIndexed;
pub struct NaiveRewriter {
apma: SetAutomaton<AnnouncementInnermost>,
}
impl RewriteEngine for NaiveRewriter {
fn rewrite(&mut self, t: &DataExpression) -> DataExpression {
let mut stats = RewritingStatistics::default();
let result = NaiveRewriter::rewrite_aux(&self.apma, t.copy(), &mut stats);
info!(
"{} rewrites, {} single steps and {} symbol comparisons",
stats.recursions, stats.rewrite_steps, stats.symbol_comparisons
);
result
}
}
impl NaiveRewriter {
pub fn new(spec: &RewriteSpecification) -> NaiveRewriter {
NaiveRewriter {
apma: SetAutomaton::new(spec, AnnouncementInnermost::new, false),
}
}
fn rewrite_aux(
automaton: &SetAutomaton<AnnouncementInnermost>,
t: DataExpressionRef<'_>,
stats: &mut RewritingStatistics,
) -> DataExpression {
let symbol = t.data_function_symbol();
let mut arguments = vec![];
for t in t.data_arguments() {
arguments.push(NaiveRewriter::rewrite_aux(automaton, t, stats));
}
let nf: DataExpression = if arguments.is_empty() {
symbol.protect().into()
} else {
DataApplication::with_args(&symbol, &arguments).into()
};
match NaiveRewriter::find_match(automaton, &nf, stats) {
None => nf,
Some((_announcement, ema)) => {
let result = ema.rhs_stack.evaluate(&nf);
debug_trace!("rewrote {} to {} using rule {}", nf, result, _announcement.rule);
NaiveRewriter::rewrite_aux(automaton, result.copy(), stats)
}
}
}
fn find_match<'a>(
automaton: &'a SetAutomaton<AnnouncementInnermost>,
t: &DataExpression,
stats: &mut RewritingStatistics,
) -> Option<(&'a MatchAnnouncement, &'a AnnouncementInnermost)> {
let mut state_index = 0;
loop {
let state = &automaton.states()[state_index];
let u = t.get_data_position(state.label());
let symbol = u.data_function_symbol();
if let Some(transition) = automaton.transitions().get(&(state_index, symbol.operation_id())) {
for (announcement, ema) in &transition.announcements {
let mut conditions_hold = true;
if !ema.conditions.is_empty() {
conditions_hold = NaiveRewriter::check_conditions(automaton, &t.copy(), ema, stats);
}
'ec_check: for ec in &ema.equivalence_classes {
if ec.positions.len() > 1 {
let mut iter_pos = ec.positions.iter();
let first_pos = iter_pos.next().unwrap();
let first_term = t.get_data_position(first_pos);
for other_pos in iter_pos {
let other_term = t.get_data_position(other_pos);
if first_term != other_term {
conditions_hold = false;
break 'ec_check;
}
}
}
}
if conditions_hold {
return Some((announcement, ema));
}
}
if transition.destinations.is_empty() {
return None;
}
state_index = transition.destinations.first().unwrap().1;
} else {
return None;
}
}
}
fn check_conditions(
automaton: &SetAutomaton<AnnouncementInnermost>,
t: &DataExpressionRef<'_>,
ema: &AnnouncementInnermost,
stats: &mut RewritingStatistics,
) -> bool {
for c in &ema.conditions {
let rhs = c.lhs_term_stack.evaluate(t);
let lhs = c.rhs_term_stack.evaluate(t);
let rhs_normal = NaiveRewriter::rewrite_aux(automaton, rhs.copy(), stats);
let lhs_normal = NaiveRewriter::rewrite_aux(automaton, lhs.copy(), stats);
let holds = (lhs_normal == rhs_normal && c.equality) || (lhs_normal != rhs_normal && !c.equality);
if !holds {
return false;
}
}
true
}
}