#![forbid(unsafe_code)]
use std::fmt;
use merc_aterm::Protected;
use merc_aterm::Term;
use merc_aterm::ThreadTermPool;
use merc_data::DataExpression;
use merc_data::DataExpressionRef;
use crate::Rule;
use crate::matching::conditions::EMACondition;
use crate::matching::conditions::extend_conditions;
use crate::matching::nonlinear::EquivalenceClass;
use crate::matching::nonlinear::derive_equivalence_classes;
use crate::set_automaton::MatchAnnouncement;
use crate::set_automaton::SetAutomaton;
use super::DataPosition;
use super::DataPositionIndexed;
use super::DataSubstitutionBuilder;
use super::TermStack;
use super::create_var_map;
use super::data_substitute_with;
#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct AnnouncementSabre {
pub equivalence_classes: Vec<EquivalenceClass>,
pub conditions: Vec<EMACondition>,
pub rhs_term_stack: TermStack,
pub is_duplicating: bool,
}
impl AnnouncementSabre {
pub fn new(rule: &Rule) -> AnnouncementSabre {
let var_map = create_var_map(&rule.lhs);
let sctt_rhs = TermStack::from_term(&rule.rhs.copy(), &var_map);
let is_duplicating = sctt_rhs.contains_duplicate_var_references();
AnnouncementSabre {
conditions: extend_conditions(rule),
equivalence_classes: derive_equivalence_classes(rule),
rhs_term_stack: sctt_rhs,
is_duplicating,
}
}
}
#[derive(Debug)]
pub(crate) struct Configuration<'a> {
pub state: usize,
pub position: Option<&'a DataPosition>,
}
#[derive(Debug)]
pub(crate) struct SideInfo<'a> {
pub corresponding_configuration: usize,
pub info: SideInfoType<'a>,
}
pub(crate) enum SideInfoType<'a> {
SideBranch(&'a [(DataPosition, usize)]),
DelayedRewriteRule(&'a MatchAnnouncement, &'a AnnouncementSabre),
EquivalenceAndConditionCheck(&'a MatchAnnouncement, &'a AnnouncementSabre),
}
#[derive(Debug)]
pub(crate) struct ConfigurationStack<'a> {
pub stack: Vec<Configuration<'a>>,
pub terms: Protected<Vec<DataExpressionRef<'static>>>,
pub side_branch_stack: Vec<SideInfo<'a>>,
pub current_node: Option<usize>,
pub oldest_reliable_subterm: usize,
pub substitution_builder: DataSubstitutionBuilder,
}
impl<'a> ConfigurationStack<'a> {
pub fn new(state: usize, term: &DataExpression) -> ConfigurationStack<'a> {
let mut conf_list = ConfigurationStack {
stack: Vec::with_capacity(8),
side_branch_stack: vec![],
terms: Protected::new(vec![]),
current_node: Some(0),
oldest_reliable_subterm: 0,
substitution_builder: DataSubstitutionBuilder::default(),
};
conf_list.stack.push(Configuration { state, position: None });
let mut write_conf_list = conf_list.terms.write();
write_conf_list.push(term.copy());
drop(write_conf_list);
conf_list
}
pub(crate) fn get_unexplored_leaf(&self) -> Option<usize> {
self.current_node
}
pub(crate) fn get_prev_with_side_info(&self) -> Option<usize> {
self.side_branch_stack.last().map(|si| si.corresponding_configuration)
}
pub fn grow(&mut self, c: usize, tr_slice: &'a [(DataPosition, usize)]) {
let (pos, des) = tr_slice.first().unwrap();
let tr_slice: &[(DataPosition, usize)] = &(tr_slice)[1..];
if !tr_slice.is_empty() {
self.side_branch_stack.push(SideInfo {
corresponding_configuration: c,
info: SideInfoType::SideBranch(tr_slice),
})
}
let new_leaf = Configuration {
state: *des,
position: Some(pos),
};
self.stack.push(new_leaf);
let mut write_terms = self.terms.write();
let t = write_terms.protect(&write_terms[c].get_data_position(pos));
write_terms.push(t.into());
self.current_node = Some(c + 1);
}
pub fn prune(
&mut self,
tp: &ThreadTermPool,
automaton: &SetAutomaton<AnnouncementSabre>,
depth: usize,
new_subterm: DataExpression,
) {
self.current_node = Some(depth);
self.stack.truncate(depth + 1);
self.terms.write().truncate(depth + 1);
self.roll_back_side_info_stack(depth, true);
let mut write_terms = self.terms.write();
let subterm = write_terms.protect(&data_substitute_with(
&mut self.substitution_builder,
tp,
&write_terms[depth],
new_subterm,
automaton.states()[self.stack[depth].state].label(),
));
write_terms[depth] = subterm.into();
self.oldest_reliable_subterm = depth;
}
pub fn roll_back_side_info_stack(&mut self, end: usize, including: bool) {
loop {
match self.side_branch_stack.last() {
None => {
break;
}
Some(sbi) => {
if sbi.corresponding_configuration < end || (sbi.corresponding_configuration <= end && !including) {
break;
} else {
self.side_branch_stack.pop();
}
}
}
}
}
pub fn jump_back(&mut self, depth: usize, tp: &ThreadTermPool) {
self.integrate_updated_subterms(depth, tp, true);
self.current_node = Some(depth);
self.stack.truncate(depth + 1);
self.terms.write().truncate(depth + 1);
self.roll_back_side_info_stack(depth, false);
}
pub fn integrate_updated_subterms(&mut self, end: usize, tp: &ThreadTermPool, store_intermediate: bool) {
let mut up_to_date = self.oldest_reliable_subterm;
if up_to_date == 0 || end >= up_to_date {
return;
}
let mut write_terms = self.terms.write();
let mut subterm = write_terms.protect(&write_terms[up_to_date]);
while up_to_date > end {
subterm = match self.stack[up_to_date].position {
None => subterm,
Some(position) => {
let t = data_substitute_with(
&mut self.substitution_builder,
tp,
&write_terms[up_to_date - 1],
subterm.protect().into(),
position,
);
write_terms.protect(&t)
}
};
up_to_date -= 1;
if store_intermediate {
let subterm = write_terms.protect(&subterm);
write_terms[up_to_date] = subterm.into();
}
}
self.oldest_reliable_subterm = up_to_date;
let subterm = write_terms.protect(&subterm);
write_terms[up_to_date] = subterm.into();
}
pub fn compute_final_term(&mut self, tp: &ThreadTermPool) -> DataExpression {
self.jump_back(0, tp);
self.terms.read()[0].protect()
}
pub fn pop_side_branch_leaf(stack: &mut Vec<SideInfo<'a>>, leaf_index: usize) -> Option<SideInfoType<'a>> {
let should_pop = match stack.last() {
None => false,
Some(si) => si.corresponding_configuration == leaf_index,
};
if should_pop {
Some(stack.pop().unwrap().info)
} else {
None
}
}
}
impl fmt::Display for ConfigurationStack<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Current node: {:?}", self.current_node)?;
for (i, c) in self.stack.iter().enumerate() {
writeln!(f, "Configuration {i} ")?;
writeln!(f, " State: {:?}", c.state)?;
writeln!(
f,
" Position: {}",
match c.position {
Some(x) => x.to_string(),
None => "None".to_string(),
}
)?;
writeln!(f, " Subterm: {}", self.terms.read()[i])?;
for side_branch in &self.side_branch_stack {
if i == side_branch.corresponding_configuration {
writeln!(f, " Side branch: {:?} ", side_branch.info)?;
}
}
}
Ok(())
}
}
impl fmt::Debug for SideInfoType<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SideInfoType::SideBranch(tr_slice) => {
let mut first = true;
write!(f, "matching: ")?;
for (position, index) in tr_slice.iter() {
if !first {
write!(f, ", ")?;
}
write!(f, "{} {}", position, *index)?;
first = false;
}
}
SideInfoType::DelayedRewriteRule(announcement, _) => {
write!(f, "delayed rule: {announcement:?}")?;
}
SideInfoType::EquivalenceAndConditionCheck(announcement, _) => {
write!(f, "equivalence {announcement:?}")?;
}
}
Ok(())
}
}