#![forbid(unsafe_code)]
use merc_aterm::ATerm;
use merc_aterm::ATermRef;
use merc_aterm::Protected;
use merc_aterm::Term;
use merc_aterm::ThreadTermPool;
pub type SubstitutionBuilder = Protected<Vec<ATermRef<'static>>>;
pub fn substitute<'a, 'b>(tp: &ThreadTermPool, t: &'b impl Term<'a, 'b>, new_subterm: ATerm, p: &[usize]) -> ATerm {
let mut args = Protected::new(vec![]);
substitute_rec(tp, t, new_subterm, p, &mut args, 0)
}
pub fn substitute_with<'a, 'b>(
builder: &mut SubstitutionBuilder,
tp: &ThreadTermPool,
t: &'b impl Term<'a, 'b>,
new_subterm: ATerm,
p: &[usize],
) -> ATerm {
substitute_rec(tp, t, new_subterm, p, builder, 0)
}
fn substitute_rec<'a, 'b>(
tp: &ThreadTermPool,
t: &'b impl Term<'a, 'b>,
new_subterm: ATerm,
p: &[usize],
args: &mut SubstitutionBuilder,
depth: usize,
) -> ATerm {
if p.len() == depth {
new_subterm
} else {
let new_child_index = p[depth] - 1;
let new_child = substitute_rec(tp, &t.arg(new_child_index), new_subterm, p, args, depth + 1);
let mut write_args = args.write();
for (index, arg) in t.arguments().enumerate() {
if index == new_child_index {
let t = write_args.protect(&new_child);
write_args.push(t);
} else {
let t = write_args.protect(&arg);
write_args.push(t);
}
}
let result = tp.create_term(&t.get_head_symbol(), &write_args);
drop(write_args);
args.write().clear();
result.protect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use merc_aterm::THREAD_TERM_POOL;
use crate::utilities::ExplicitPosition;
use crate::utilities::PositionIndexed;
#[test]
fn test_substitute() {
let t = ATerm::from_string("s(s(a))").unwrap();
let t0 = ATerm::from_string("0").unwrap();
let result = THREAD_TERM_POOL.with_borrow(|tp| substitute(tp, &t, t0.clone(), &vec![1, 1]));
assert_eq!(t0, result.get_position(&ExplicitPosition::new(&vec![1, 1])).protect());
}
}