use std::borrow::Borrow;
use std::{collections::BTreeSet, sync::Arc};
use cedar_policy_core::ast::Expr;
use super::concretizer::{ConcretizeError, Env};
use super::enforcer::footprints;
use super::env::{SymEntities, SymEntityData, SymEnv};
use super::factory;
use super::function::{Udf, UnaryFunction};
use super::interpretation::Interpretation;
use super::op::Uuf;
use super::term::{Term, TermPrim};
use super::term_type::TermType;
use super::type_abbrevs::EntityUID;
impl UnaryFunction {
fn uuf(&self) -> Option<&Uuf> {
match self {
UnaryFunction::Uuf(u) => Some(u),
UnaryFunction::Udf(_) => None,
}
}
}
impl SymEntityData {
fn uuf_ancestors(&self) -> impl Iterator<Item = &Uuf> {
self.ancestors.values().filter_map(|f| f.uuf())
}
}
impl SymEntities {
fn uuf_ancestors(&self) -> BTreeSet<&Uuf> {
self.values()
.flat_map(|edata| edata.uuf_ancestors())
.collect()
}
}
impl Uuf {
fn repair_as_counterexample(
&self,
footprints: &BTreeSet<EntityUID>,
interp: &Interpretation<'_>,
) -> Udf {
let udf = interp.interpret_fun(self);
let entry = |udf: &Udf, uid| -> Option<(Term, Term)> {
let t = Term::Prim(TermPrim::Entity(uid));
if t.type_of() == udf.arg {
Some((
t.clone(),
factory::app(UnaryFunction::Udf(Arc::new(udf.clone())), t),
))
} else {
None
}
};
let new_table = footprints
.iter()
.filter_map(|uid| entry(&udf, uid.clone()))
.collect();
Udf {
table: Arc::new(new_table),
default: match &udf.out {
TermType::Set { ty } => factory::set_of([], (**ty).clone()),
_ => udf.default,
},
..udf
}
}
}
impl Interpretation<'_> {
pub fn repair_as_counterexample<T: Borrow<Term>>(
&self,
footprint: impl IntoIterator<Item = T>,
) -> Self {
let mut footprint_uids = BTreeSet::new();
for term in footprint {
term.borrow()
.interpret(self)
.get_all_entity_uids(&mut footprint_uids);
}
let footprint_ancestors = self
.env
.entities
.uuf_ancestors()
.into_iter()
.map(|f| (f, f.repair_as_counterexample(&footprint_uids, self)));
let mut funs = self.funs.clone();
for (uuf, udf) in footprint_ancestors {
funs.insert(uuf.clone(), udf);
}
Self {
vars: self.vars.clone(),
funs,
env: self.env,
}
}
}
impl SymEnv {
pub fn extract<E: Borrow<Expr>>(
&self,
exprs: impl IntoIterator<Item = E>,
interp: &Interpretation<'_>,
) -> Result<Env, ConcretizeError> {
let exprs = exprs.into_iter().collect::<Vec<_>>();
let interp =
interp.repair_as_counterexample(footprints(exprs.iter().map(Borrow::borrow), self));
self.interpret(&interp).concretize(exprs)
}
}