use alloc::vec::Vec;
use crate::ast::manager::AstManager;
use crate::ast::node::{AppData, AstNode, DeclInfo, FuncDeclData, SortData, VarData};
use crate::ast::parameter::Parameter;
use crate::ast::{AstId, FamilyId, NULL_FAMILY_ID};
impl AstManager {
pub fn translate(&self, id: AstId, dst: &mut AstManager) -> AstId {
let mut memo: Vec<(AstId, AstId)> = Vec::new();
self.translate_memo(id, dst, &mut memo)
}
fn translate_memo(
&self,
id: AstId,
dst: &mut AstManager,
memo: &mut Vec<(AstId, AstId)>,
) -> AstId {
if let Some(&(_, t)) = memo.iter().find(|&&(s, _)| s == id) {
return t;
}
let translated = match self.node(id).clone() {
AstNode::Sort(SortData {
name,
info,
num_elements,
}) => {
let info = self.translate_info(&info, dst, memo);
dst.mk_sort(name, info, num_elements)
}
AstNode::FuncDecl(FuncDeclData {
name,
info,
flags,
domain,
range,
}) => {
let info = self.translate_info(&info, dst, memo);
let domain: Vec<AstId> = domain
.iter()
.map(|&d| self.translate_memo(d, dst, memo))
.collect();
let range = self.translate_memo(range, dst, memo);
dst.mk_func_decl_full(name, &domain, range, info, flags)
}
AstNode::App(AppData { decl, args }) => {
let decl = self.translate_memo(decl, dst, memo);
let args: Vec<AstId> = args
.iter()
.map(|&a| self.translate_memo(a, dst, memo))
.collect();
dst.mk_app(decl, &args)
}
AstNode::Var(VarData { index, sort }) => {
let sort = self.translate_memo(sort, dst, memo);
dst.mk_var(index, sort)
}
AstNode::Quantifier(q) => {
let var_sorts: Vec<AstId> = q
.var_sorts
.iter()
.map(|&s| self.translate_memo(s, dst, memo))
.collect();
let body = self.translate_memo(q.body, dst, memo);
let patterns: Vec<AstId> = q
.patterns
.iter()
.map(|&p| self.translate_memo(p, dst, memo))
.collect();
dst.mk_quantifier(q.kind, &var_sorts, &q.var_names, body, &patterns, q.weight)
}
};
memo.push((id, translated));
translated
}
fn translate_info(
&self,
info: &DeclInfo,
dst: &mut AstManager,
memo: &mut Vec<(AstId, AstId)>,
) -> DeclInfo {
let family_id = self.translate_family(info.family_id, dst);
let parameters = info
.parameters
.iter()
.map(|p| match p {
Parameter::Ast(a) => Parameter::Ast(self.translate_memo(*a, dst, memo)),
other => other.clone(),
})
.collect();
DeclInfo {
family_id,
decl_kind: info.decl_kind,
parameters,
}
}
fn translate_family(&self, fid: FamilyId, dst: &mut AstManager) -> FamilyId {
if fid == NULL_FAMILY_ID {
return NULL_FAMILY_ID;
}
match self.family_name(fid) {
Some(name) => dst.mk_family_id(name),
None => NULL_FAMILY_ID,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::symbol::Symbol;
#[test]
fn round_trip_preserves_pp() {
let mut src = AstManager::new();
let p = src.mk_bool_const("p");
let q = src.mk_bool_const("q");
let a = src.mk_uninterpreted_sort(Symbol::new("A"));
let f = src.mk_func_decl(Symbol::new("f"), &[a], a);
let xd = src.mk_func_decl(Symbol::new("x"), &[], a);
let x = src.mk_const(xd);
let fx = src.mk_app(f, &[x]);
let nq = src.mk_not(q);
let or = src.mk_or(&[p, nq]);
let eq = src.mk_eq(p, q);
let body = src.mk_and(&[or, eq]);
for &term in &[p, q, fx, body] {
let mut dst = AstManager::new();
let t = src.translate(term, &mut dst);
assert_eq!(src.pp(term), dst.pp(t), "pp changed under translation");
let mut back = AstManager::new();
let t2 = dst.translate(t, &mut back);
assert_eq!(src.pp(term), back.pp(t2));
}
}
#[test]
fn translate_arith_remaps_family() {
let mut src = AstManager::new();
let x = src.mk_int_const("x");
let three = src.mk_int(3);
let sum = src.mk_add(&[x, three]);
let ten = src.mk_int(10);
let le = src.mk_le(sum, ten);
let mut dst = AstManager::new();
let t = src.translate(le, &mut dst);
assert_eq!(src.pp(le), dst.pp(t));
let twice = src.mk_add(&[x, x]);
let mut d2 = AstManager::new();
let tt = src.translate(twice, &mut d2);
let args = d2.app_args(tt).to_vec();
assert_eq!(args[0], args[1], "shared subterm not re-shared");
}
#[test]
fn translate_nested_sort_parameters() {
let mut src = AstManager::new();
let arr = src.mk_int_const("a"); let _ = arr;
let idx = src.mk_int(0);
let a = src.mk_int_const("arr_elem");
let _ = (idx, a);
let bv = src.mk_bv(5, 8);
let mut dst = AstManager::new();
let t = src.translate(bv, &mut dst);
assert_eq!(src.pp(bv), dst.pp(t));
}
#[test]
fn translate_quantifier() {
let mut src = AstManager::new();
let int = src.mk_int_sort();
let v0 = src.mk_var(0, int);
let zero = src.mk_int(0);
let body = src.mk_le(v0, zero);
let phi = src.mk_forall(&[int], body);
assert!(src.is_quantifier(phi));
let bool_sort = src.mk_bool_sort();
assert_eq!(src.get_sort(phi), bool_sort);
let mut dst = AstManager::new();
let t = src.translate(phi, &mut dst);
assert_eq!(src.pp(phi), dst.pp(t));
assert!(dst.is_quantifier(t));
assert!(src.num_subexprs(phi) >= 2);
}
}