use crate::position::{PositionInLanguageTerm, PositionInRewriteProcess};
use crate::rule::RewriteRule;
use crate::term::syntax::{
LanguageTerm, LanguageTermNode, RewritableLanguageOperatorSymbol, TermFactory,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SiblingOrder {
Leftmost,
Rightmost,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DepthOrder {
Outermost,
Innermost,
}
pub enum RewriteProcess<LOS: RewritableLanguageOperatorSymbol> {
Rule(Box<dyn RewriteRule<LOS>>),
AnyChild(SiblingOrder, DepthOrder, Box<Self>),
Pipe(Box<Self>, Box<Self>),
Repeat(Box<Self>),
TryOnePath(Vec<Self>),
TryAllPaths(Vec<Self>),
}
pub(crate) fn run_to_completion<LOS: RewritableLanguageOperatorSymbol>(
this: &RewriteProcess<LOS>,
term: &LanguageTerm<LOS>,
context_term: &LanguageTerm<LOS>,
position: &PositionInLanguageTerm,
factory: &mut TermFactory<LOS>,
) -> Vec<LanguageTerm<LOS>> {
match this {
RewriteProcess::Rule(rule) => rule
.try_apply(term, context_term, position, factory)
.into_iter()
.collect(),
RewriteProcess::AnyChild(sibling_order, depth_order, process) => {
let indices: Vec<usize> = match sibling_order {
SiblingOrder::Leftmost => (0..term.sub_terms.len()).collect(),
SiblingOrder::Rightmost => (0..term.sub_terms.len()).rev().collect(),
};
for n in indices {
let child = &term.sub_terms[n];
let child_pos = position.get_position_of_nth_child(n);
let (first, second) = match depth_order {
DepthOrder::Outermost => (
run_to_completion(process, child, context_term, &child_pos, factory),
run_to_completion(this, child, context_term, &child_pos, factory),
),
DepthOrder::Innermost => (
run_to_completion(this, child, context_term, &child_pos, factory),
run_to_completion(process, child, context_term, &child_pos, factory),
),
};
if !first.is_empty() {
return first
.into_iter()
.map(|rw| rebuild_child(term, n, rw, factory))
.collect();
}
if !second.is_empty() {
return second
.into_iter()
.map(|rw| rebuild_child(term, n, rw, factory))
.collect();
}
}
vec![]
}
RewriteProcess::Pipe(a, b) => run_to_completion(a, term, context_term, position, factory)
.into_iter()
.flat_map(|ti| {
let new_ctx = replace_at_position(context_term, position, ti.clone(), factory);
run_to_completion(b, &ti, &new_ctx, position, factory)
})
.collect(),
RewriteProcess::Repeat(process) => {
let results = run_to_completion(process, term, context_term, position, factory);
if results.is_empty() {
vec![term.clone()]
} else {
results
.into_iter()
.flat_map(|ti| {
let new_ctx =
replace_at_position(context_term, position, ti.clone(), factory);
run_to_completion(this, &ti, &new_ctx, position, factory)
})
.collect()
}
}
RewriteProcess::TryOnePath(processes) => {
for process in processes {
let results = run_to_completion(process, term, context_term, position, factory);
if !results.is_empty() {
return results;
}
}
vec![]
}
RewriteProcess::TryAllPaths(processes) => processes
.iter()
.flat_map(|process| run_to_completion(process, term, context_term, position, factory))
.collect(),
}
}
#[allow(clippy::type_complexity)]
pub(crate) fn run_traced_step<LOS: RewritableLanguageOperatorSymbol>(
this: &RewriteProcess<LOS>,
term: &LanguageTerm<LOS>,
context_term: &LanguageTerm<LOS>,
term_position: &PositionInLanguageTerm,
strategy_position: &PositionInRewriteProcess,
factory: &mut TermFactory<LOS>,
) -> Vec<(
Vec<(PositionInRewriteProcess, PositionInLanguageTerm)>,
LanguageTerm<LOS>,
)> {
match this {
RewriteProcess::Rule(rule) => rule
.try_apply(term, context_term, term_position, factory)
.map(|result| {
(
vec![(strategy_position.clone(), term_position.clone())],
result,
)
})
.into_iter()
.collect(),
RewriteProcess::AnyChild(sibling_order, depth_order, process) => {
let inner_sp = strategy_position.get_position_of_nth_child(0);
let indices: Vec<usize> = match sibling_order {
SiblingOrder::Leftmost => (0..term.sub_terms.len()).collect(),
SiblingOrder::Rightmost => (0..term.sub_terms.len()).rev().collect(),
};
for n in indices {
let child = &term.sub_terms[n];
let child_tp = term_position.get_position_of_nth_child(n);
let (first, second) = match depth_order {
DepthOrder::Outermost => (
run_traced_step(
process,
child,
context_term,
&child_tp,
&inner_sp,
factory,
),
run_traced_step(
this,
child,
context_term,
&child_tp,
strategy_position,
factory,
),
),
DepthOrder::Innermost => (
run_traced_step(
this,
child,
context_term,
&child_tp,
strategy_position,
factory,
),
run_traced_step(
process,
child,
context_term,
&child_tp,
&inner_sp,
factory,
),
),
};
if !first.is_empty() {
return first
.into_iter()
.map(|(chain, rw)| (chain, rebuild_child(term, n, rw, factory)))
.collect();
}
if !second.is_empty() {
return second
.into_iter()
.map(|(chain, rw)| (chain, rebuild_child(term, n, rw, factory)))
.collect();
}
}
vec![]
}
RewriteProcess::Pipe(a, b) => {
let sp_a = strategy_position.get_position_of_nth_child(0);
let sp_b = strategy_position.get_position_of_nth_child(1);
run_traced_step(a, term, context_term, term_position, &sp_a, factory)
.into_iter()
.flat_map(|(chain_a, ti)| {
let new_ctx =
replace_at_position(context_term, term_position, ti.clone(), factory);
run_traced_step(b, &ti, &new_ctx, term_position, &sp_b, factory)
.into_iter()
.map(move |(chain_b, result)| {
let mut full_chain = chain_a.clone();
full_chain.extend(chain_b);
(full_chain, result)
})
})
.collect()
}
RewriteProcess::Repeat(process) => run_traced_step(
process,
term,
context_term,
term_position,
&strategy_position.get_position_of_nth_child(0),
factory,
),
RewriteProcess::TryOnePath(processes) => {
for (i, process) in processes.iter().enumerate() {
let sp_i = strategy_position.get_position_of_nth_child(i);
let results =
run_traced_step(process, term, context_term, term_position, &sp_i, factory);
if !results.is_empty() {
return results;
}
}
vec![]
}
RewriteProcess::TryAllPaths(processes) => processes
.iter()
.enumerate()
.flat_map(|(i, process)| {
let sp_i = strategy_position.get_position_of_nth_child(i);
run_traced_step(process, term, context_term, term_position, &sp_i, factory)
})
.collect(),
}
}
fn rebuild_child<LOS: RewritableLanguageOperatorSymbol>(
parent: &LanguageTerm<LOS>,
child_index: usize,
new_child: LanguageTerm<LOS>,
factory: &mut TermFactory<LOS>,
) -> LanguageTerm<LOS> {
let mut new_sub_terms = parent.sub_terms.clone();
new_sub_terms[child_index] = new_child;
LanguageTermNode::build(parent.operator.clone(), new_sub_terms, factory)
}
fn replace_at_position<LOS: RewritableLanguageOperatorSymbol>(
context: &LanguageTerm<LOS>,
position: &PositionInLanguageTerm,
replacement: LanguageTerm<LOS>,
factory: &mut TermFactory<LOS>,
) -> LanguageTerm<LOS> {
replace_rec(
context,
position.get_absolute_coordinates_from_root(),
replacement,
factory,
)
}
fn replace_rec<LOS: RewritableLanguageOperatorSymbol>(
term: &LanguageTerm<LOS>,
coords: &[usize],
replacement: LanguageTerm<LOS>,
factory: &mut TermFactory<LOS>,
) -> LanguageTerm<LOS> {
match coords.first() {
None => replacement,
Some(&n) => {
let new_child = replace_rec(&term.sub_terms[n], &coords[1..], replacement, factory);
rebuild_child(term, n, new_child, factory)
}
}
}