use convert_case::{Case::Snake, Casing as _};
use crate::algebra::signature::{FuncId, Signature, TypeId, TypeKind};
use crate::ast::Ast;
use crate::flat_eqlog::FlatRel;
pub(crate) struct RustGenCtx<'a> {
ast: &'a Ast,
signature: &'a Signature,
}
impl<'a> RustGenCtx<'a> {
pub(crate) fn new(ast: &'a Ast, signature: &'a Signature) -> Self {
Self { ast, signature }
}
pub(crate) fn ast(&self) -> &Ast {
self.ast
}
pub(crate) fn signature(&self) -> &Signature {
self.signature
}
pub(crate) fn type_name(&self, typ: TypeId) -> String {
match self.signature.type_(typ).kind {
TypeKind::Plain => self
.signature
.iter_type_decls()
.find_map(|(decl, typ0)| {
(typ0 == typ).then(|| self.ast.type_decl(decl).name.clone())
})
.expect("type id should have a type declaration"),
TypeKind::Enum => self
.signature
.iter_enum_decls()
.find_map(|(decl, typ0)| {
(typ0 == typ).then(|| self.ast.enum_decl(decl).name.clone())
})
.expect("enum type id should have an enum declaration"),
TypeKind::Model => self
.signature
.iter_model_decls()
.find_map(|(decl, ids)| {
(ids.type_ == typ).then(|| self.ast.model_decl(decl).name.clone())
})
.expect("model type id should have a model declaration"),
TypeKind::Mor(model_type) => format!("{}Mor", self.type_name(model_type)),
}
}
pub(crate) fn func_name(&self, func: FuncId) -> String {
if let Some((decl, _)) = self
.signature
.iter_func_decls()
.find(|(_, func0)| *func0 == func)
{
return self.ast.func_decl(decl).name.clone();
}
if let Some((decl, _)) = self
.signature
.iter_ctor_decls()
.find(|(_, func0)| *func0 == func)
{
return self.ast.ctor_decl(decl).name.clone();
}
if let Some((_decl, ids)) = self
.signature
.iter_model_decls()
.find(|(_, ids)| ids.dom == func || ids.cod == func)
{
let mor_name = self.type_name(ids.mor).to_case(Snake);
let suffix = if ids.dom == func { "dom" } else { "cod" };
return format!("{mor_name}_{suffix}");
}
if let Some((member_type, _)) = self
.signature
.iter_mor_app_funcs()
.find(|(_, func0)| *func0 == func)
{
return format!("{}_mor_app", self.type_name(member_type).to_case(Snake));
}
panic!("function id should be declared or generated by the signature pass")
}
pub(crate) fn rel_name(&self, rel: FlatRel) -> String {
match rel {
FlatRel::Pred(pred) => self
.signature
.iter_pred_decls()
.find_map(|(decl, pred0)| {
(pred0 == pred).then(|| self.ast.pred_decl(decl).name.clone())
})
.expect("predicate id should have a predicate declaration"),
FlatRel::Func(func) => self.func_name(func),
FlatRel::ModelMember(member_type) => {
let model_type = self
.signature
.type_(member_type)
.parents
.last()
.copied()
.expect("model member relation requires a member type");
let model_name = self.type_name(model_type).to_case(Snake);
let member_name = self.type_name(member_type).to_case(Snake);
format!("{model_name}_member_{member_name}")
}
}
}
pub(crate) fn function_can_be_made_defined(&self, func: FuncId) -> bool {
let codomain = self.signature.func(func).codomain;
matches!(
self.signature.type_(codomain).kind,
TypeKind::Plain | TypeKind::Model | TypeKind::Mor(_)
) || self
.signature
.iter_ctor_decls()
.any(|(_, func0)| func0 == func)
}
pub(crate) fn pred_like_rels(&self) -> impl Iterator<Item = FlatRel> + '_ {
self.signature.iter_preds().map(FlatRel::Pred).chain(
self.signature.iter_types().filter_map(|typ| {
(!self.signature.type_(typ).parents.is_empty()).then_some(FlatRel::ModelMember(typ))
}),
)
}
}