use crate::formally;
use dashmap::DashSet;
use formally::{
smt::*,
support::{Identifier, Nominal},
};
use std::{borrow::Borrow, cell::RefCell, collections::HashSet, fmt::Debug, sync::Arc};
pub trait TermPool {
fn shared(&self, kind: TermKind) -> Term;
fn shared_ref(&self, kind: &TermKind) -> Term;
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct Lookup<T>(T);
impl Borrow<TermKind> for Lookup<Arc<TermInner>> {
fn borrow(&self) -> &TermKind {
&self.0.kind
}
}
#[derive(Debug, Default)]
pub struct HashPool {
pool: RefCell<HashSet<Lookup<Arc<TermInner>>>>,
}
impl HashPool {
pub fn new() -> HashPool {
HashPool::default()
}
}
#[derive(Debug, Default)]
pub struct DashPool {
pool: DashSet<Lookup<Arc<TermInner>>>,
}
impl DashPool {
pub fn new() -> DashPool {
DashPool::default()
}
}
impl TermPool for DashPool {
fn shared(&self, kind: TermKind) -> Term {
if let Some(kind) = self.pool.get(&kind) {
Term(Nominal(kind.0.clone()))
} else {
let arc = Arc::new(TermInner::new(kind));
let term = Term(Nominal(arc.clone()));
self.pool.insert(Lookup(arc));
term
}
}
fn shared_ref(&self, kind: &TermKind) -> Term {
if let Some(kind) = self.pool.get(kind) {
Term(Nominal(kind.0.clone()))
} else {
let arc = Arc::new(TermInner::new(kind.clone()));
let term = Term(Nominal(arc.clone()));
self.pool.insert(Lookup(arc));
term
}
}
}
impl TermPool for HashPool {
fn shared(&self, kind: TermKind) -> Term {
if let Some(kind) = self.pool.borrow().get(&kind) {
Term(Nominal(kind.0.clone()))
} else {
let arc = Arc::new(TermInner::new(kind));
let term = Term(Nominal(arc.clone()));
self.pool.borrow_mut().insert(Lookup(arc));
term
}
}
fn shared_ref(&self, kind: &TermKind) -> Term {
if let Some(kind) = self.pool.borrow().get(kind) {
Term(Nominal(kind.0.clone()))
} else {
let arc = Arc::new(TermInner::new(kind.clone()));
let term = Term(Nominal(arc.clone()));
self.pool.borrow_mut().insert(Lookup(arc));
term
}
}
}
pub trait ToTerm: Debug {
fn into_term_in(self, pool: &dyn TermPool) -> Term;
fn to_term_in(&self, pool: &dyn TermPool) -> Term;
}
impl<T: ToTerm> ToTerm for &T {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
self.to_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
(*self).to_term_in(pool)
}
}
impl ToTerm for Term {
fn into_term_in(self, _pool: &dyn TermPool) -> Term {
self
}
fn to_term_in(&self, _pool: &dyn TermPool) -> Term {
self.clone()
}
}
impl ToTerm for TermKind {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
pool.shared(self)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
pool.shared_ref(self)
}
}
impl ToTerm for Constant {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Constant(self).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Constant(self.clone()).into_term_in(pool)
}
}
impl ToTerm for Atom {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(self).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(self.clone()).into_term_in(pool)
}
}
impl ToTerm for FunctionRef {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for BoundRef {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Function {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Variable {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Primitive {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for UserFunction {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Declared {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Defined {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self)).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone())).into_term_in(pool)
}
}
impl ToTerm for Identifier<'_> {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.into_owned())).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Atom(Atom::from(self.clone().into_owned())).into_term_in(pool)
}
}
impl ToTerm for Quantified {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Quantified(self).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Quantified(self.clone()).into_term_in(pool)
}
}
impl ToTerm for Let {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
TermKind::Let(self).into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
TermKind::Let(self.clone()).into_term_in(pool)
}
}
impl ToTerm for Sort {
fn into_term_in(self, pool: &dyn TermPool) -> Term {
let mut arguments = Vec::with_capacity(self.arguments.len());
for arg in &*self.arguments {
match arg {
SortArgument::Value(c) => arguments.push(
Constant::Integer {
value: c.clone(),
span: None,
}
.to_term_in(pool),
),
SortArgument::Sort(s) => arguments.push(s.to_term_in(pool)),
}
}
Atom {
head: FunctionRef::from(self.head.clone()),
arguments: Arc::from(arguments.into_boxed_slice()),
span: None,
}
.into_term_in(pool)
}
fn to_term_in(&self, pool: &dyn TermPool) -> Term {
self.clone().into_term_in(pool)
}
}