Lines
87.5 %
Functions
28.47 %
//! Default implementations of some Repr trait methods using functors;
//! These methods are used by the register_repr! macro
use super::errors::ReprUpError;
use super::types::{LookupFn, ReprDomainLevel, ReprInstantiateResult};
use super::util::try_up_via;
use crate::ast::{
DeclarationKind, DeclarationPtr, DomainPtr, Expression, Literal, Name, SymbolTable,
eval_constant,
};
use crate::representation::ReprInstantiateError;
use anyhow::anyhow;
use funcmap::{FuncMap, TryFuncMap};
/// Returns the number of values in a representation-variable domain.
/// Domains whose size is unknown or does not fit in `usize` rank as least compact.
pub fn domain_size(domain: &DomainPtr) -> usize {
domain
.length()
.ok()
.and_then(|size| usize::try_from(size).ok())
.unwrap_or(usize::MAX)
}
/// Implement [ReprDeclLevel::lookup_via] as a functor `S<DeclarationPtr> -> S<Literal>`.
pub fn lookup_via_default_impl<DeclL, A>(
decl_level: &DeclL,
lookup: &LookupFn<'_>,
) -> Result<A, ReprUpError>
where
DeclL: Clone + TryFuncMap<DeclarationPtr, Literal, Output = A>,
{
decl_level
.clone()
.try_func_map(|decl: DeclarationPtr| try_up_via(decl, lookup))
/// Implement [ReprDeclLevel::to_domain_level] as a functor `S<DeclarationPtr> -> S<DomainPtr>`.
pub fn to_domain_level_default_impl<DomL, DecL>(decl_level: DecL) -> DomL
DecL: FuncMap<DeclarationPtr, DomainPtr, Output = DomL>,
let field_dom = |decl: DeclarationPtr| decl.domain().expect("variable must have a domain");
decl_level.func_map(field_dom)
/// Implement [ReprDomainLevel::instantiate] as a functor `S<DomainPtr> -> S<DeclarationPtr>`.
/// Needs the following additional arguments:
/// - `structural` - function which takes `&S<DeclarationPtr>` and generates its structural constraints
pub fn instantiate_default_impl<DomL, DecL, A, SF>(
dom_level: DomL,
decl: DeclarationPtr,
structural: SF,
) -> ReprInstantiateResult<DecL>
DomL: ReprDomainLevel<Assignment = A, DeclLevel = DecL>
+ FuncMap<DomainPtr, DeclarationPtr, Output = DecL>,
A: FuncMap<Literal, DeclarationPtr, Output = DecL>,
SF: Fn(&DecL) -> Vec<Expression>,
let src_name = decl.name();
let repr_name = <DomL as ReprDomainLevel>::RULE.id();
let mut symtab = SymbolTable::new();
let mut counter = 1;
let element_domains = decl.as_find().and_then(|var| var.element_domains.clone());
match &decl.kind() as &DeclarationKind {
DeclarationKind::Find(_) | DeclarationKind::FindAuxiliary(_) => {
let declare_field_var = |dom: DomainPtr| {
let dom = element_domains
.as_ref()
.and_then(|domains| domains.get(counter - 1))
.cloned()
.unwrap_or(dom);
let name = Name::repr(src_name.clone(), repr_name, &counter.to_string());
let mut field_decl = if decl.is_find_auxiliary() {
DeclarationPtr::new_find_auxiliary(name, dom)
} else {
DeclarationPtr::new_find(name, dom)
*(field_decl.source_mut()) = Some(decl.clone());
symtab
.insert(field_decl.clone())
.expect("declaration already exists");
counter += 1;
field_decl
let decl_level = dom_level.func_map(declare_field_var);
let constraints = structural(&decl_level);
Ok((decl_level, symtab, constraints))
DeclarationKind::ValueLetting(expr, _) | DeclarationKind::TemporaryValueLetting(expr) => {
let declare_field_value_letting = |lit: Literal| {
let mut field_decl = DeclarationPtr::new_value_letting(name, lit.into());
let val = eval_constant(expr).ok_or(ReprInstantiateError::Other(anyhow!(
"expression {expr} is not constant"
)))?;
let val_down = dom_level.down(val).unwrap();
let decl_level = val_down.func_map(declare_field_value_letting);
// no constraints for value letting reprs
let constraints = vec![];
_ => Err(ReprInstantiateError::BadKind(
decl.clone(),
String::from("expected a variable or value letting"),
)),