use std::borrow::Borrow;
use std::{collections::BTreeSet, sync::Arc};
use cedar_policy_core::ast::Expr;
use super::concretizer::{ConcretizeError, Env};
use super::enforcer::footprint;
use super::env::SymEnv;
use super::factory;
use super::function::{Udf, UnaryFunction};
use super::interpretation::Interpretation;
use super::op::Uuf;
use super::term::{Term, TermPrim};
use super::type_abbrevs::{EntityType, EntityUID};
impl Uuf {
fn repair_as_counterexample(
&self,
arg_ety: &EntityType,
footprints: &BTreeSet<EntityUID>,
interp: &Interpretation<'_>,
) -> Udf {
let udf = interp.interpret_fun(self);
let new_table = footprints
.iter()
.filter_map(|uid| {
if uid.type_name() == arg_ety {
let t = Term::Prim(TermPrim::Entity(uid.clone()));
Some((
t.clone(),
factory::app(UnaryFunction::Udf(Arc::new(udf.clone())), t),
))
} else {
None
}
})
.collect();
Udf {
table: Arc::new(new_table),
default: udf.default.clone(),
arg: udf.arg.clone(),
out: udf.out,
}
}
}
impl Interpretation<'_> {
pub fn repair_as_counterexample<'b>(&self, exprs: impl Iterator<Item = &'b Expr>) -> Self {
let mut footprint_uids = BTreeSet::new();
for term in exprs.flat_map(|e| footprint(e, self.env).collect::<Vec<_>>()) {
term.interpret(self)
.get_all_entity_uids(&mut footprint_uids);
}
let mut funs = self.funs.clone();
for (ety, ent_data) in self.env.entities.iter() {
for fun in ent_data.ancestors.values() {
if let UnaryFunction::Uuf(uuf) = fun {
funs.insert(
uuf.as_ref().clone(),
uuf.repair_as_counterexample(ety, &footprint_uids, self),
);
}
}
}
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(exprs.iter().map(Borrow::borrow));
self.interpret(&interp).concretize(exprs)
}
}