use alloc::vec;
use crate::ast::manager::AstManager;
use crate::ast::node::{DeclInfo, FuncDeclFlags};
use crate::ast::{AstId, BASIC_FAMILY_ID, DeclKind, SortSize};
use crate::util::symbol::Symbol;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(i32)]
pub enum BasicSortKind {
Bool = 0,
Proof = 1,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(i32)]
pub enum BasicOp {
True = 0,
False = 1,
Eq = 2,
Distinct = 3,
Ite = 4,
And = 5,
Or = 6,
Xor = 7,
Not = 8,
Implies = 9,
Oeq = 10,
}
impl BasicOp {
#[inline]
const fn kind(self) -> DeclKind {
self as DeclKind
}
}
impl AstManager {
pub fn mk_bool_sort(&mut self) -> AstId {
self.mk_sort(
Symbol::new("Bool"),
DeclInfo::new(
BASIC_FAMILY_ID,
BasicSortKind::Bool as DeclKind,
alloc::vec::Vec::new(),
),
SortSize::finite(2),
)
}
fn mk_basic_app(
&mut self,
name: &str,
op: BasicOp,
domain: &[AstId],
range: AstId,
flags: FuncDeclFlags,
args: &[AstId],
) -> AstId {
let info = DeclInfo::new(BASIC_FAMILY_ID, op.kind(), alloc::vec::Vec::new());
let decl = self.mk_func_decl_full(Symbol::new(name), domain, range, info, flags);
self.mk_app(decl, args)
}
pub fn mk_true(&mut self) -> AstId {
let b = self.mk_bool_sort();
self.mk_basic_app("true", BasicOp::True, &[], b, FuncDeclFlags::default(), &[])
}
pub fn mk_false(&mut self) -> AstId {
let b = self.mk_bool_sort();
self.mk_basic_app(
"false",
BasicOp::False,
&[],
b,
FuncDeclFlags::default(),
&[],
)
}
pub fn mk_not(&mut self, a: AstId) -> AstId {
let b = self.mk_bool_sort();
self.mk_basic_app("not", BasicOp::Not, &[b], b, FuncDeclFlags::default(), &[a])
}
pub fn mk_and(&mut self, args: &[AstId]) -> AstId {
assert!(args.len() >= 2, "mk_and needs at least two arguments");
let b = self.mk_bool_sort();
let domain = vec![b; args.len()];
self.mk_basic_app("and", BasicOp::And, &domain, b, and_or_flags(), args)
}
pub fn mk_or(&mut self, args: &[AstId]) -> AstId {
assert!(args.len() >= 2, "mk_or needs at least two arguments");
let b = self.mk_bool_sort();
let domain = vec![b; args.len()];
self.mk_basic_app("or", BasicOp::Or, &domain, b, and_or_flags(), args)
}
pub fn mk_xor(&mut self, a: AstId, b_arg: AstId) -> AstId {
let b = self.mk_bool_sort();
let flags = FuncDeclFlags {
left_assoc: true,
right_assoc: true,
commutative: true,
..FuncDeclFlags::default()
};
self.mk_basic_app("xor", BasicOp::Xor, &[b, b], b, flags, &[a, b_arg])
}
pub fn mk_implies(&mut self, a: AstId, b_arg: AstId) -> AstId {
let b = self.mk_bool_sort();
let flags = FuncDeclFlags {
right_assoc: true,
..FuncDeclFlags::default()
};
self.mk_basic_app("=>", BasicOp::Implies, &[b, b], b, flags, &[a, b_arg])
}
pub fn mk_eq(&mut self, l: AstId, r: AstId) -> AstId {
let sort = self.get_sort(l);
let b = self.mk_bool_sort();
let flags = FuncDeclFlags {
commutative: true,
chainable: true,
..FuncDeclFlags::default()
};
self.mk_basic_app("=", BasicOp::Eq, &[sort, sort], b, flags, &[l, r])
}
pub fn mk_distinct(&mut self, args: &[AstId]) -> AstId {
assert!(args.len() >= 2, "mk_distinct needs at least two arguments");
let sort = self.get_sort(args[0]);
let b = self.mk_bool_sort();
let domain = vec![sort; args.len()];
let flags = FuncDeclFlags {
pairwise: true,
..FuncDeclFlags::default()
};
self.mk_basic_app("distinct", BasicOp::Distinct, &domain, b, flags, args)
}
pub fn mk_ite(&mut self, c: AstId, t: AstId, e: AstId) -> AstId {
let sort = self.get_sort(t);
let b = self.mk_bool_sort();
self.mk_basic_app(
"if",
BasicOp::Ite,
&[b, sort, sort],
sort,
FuncDeclFlags::default(),
&[c, t, e],
)
}
pub fn mk_bool_const(&mut self, name: &str) -> AstId {
let b = self.mk_bool_sort();
let decl = self.mk_func_decl(Symbol::new(name), &[], b);
self.mk_const(decl)
}
pub fn is_bool_sort(&self, sort_id: AstId) -> bool {
self.sort(sort_id).is_some_and(|s| {
s.info.family_id == BASIC_FAMILY_ID
&& s.info.decl_kind == BasicSortKind::Bool as DeclKind
})
}
pub fn is_bool(&self, expr: AstId) -> bool {
self.is_bool_sort(self.get_sort(expr))
}
}
fn and_or_flags() -> FuncDeclFlags {
FuncDeclFlags {
left_assoc: true,
right_assoc: true,
flat_associative: true,
commutative: true,
idempotent: true,
..FuncDeclFlags::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::AstKind;
#[test]
fn bool_sort_is_unique_and_finite() {
let mut m = AstManager::new();
let b1 = m.mk_bool_sort();
let b2 = m.mk_bool_sort();
assert_eq!(b1, b2);
assert_eq!(m.sort(b1).unwrap().num_elements, SortSize::finite(2));
assert_eq!(m.sort(b1).unwrap().info.family_id, BASIC_FAMILY_ID);
}
#[test]
fn build_a_propositional_formula() {
let mut m = AstManager::new();
let p = m.mk_bool_const("p");
let q = m.mk_bool_const("q");
let notq = m.mk_not(q);
let or = m.mk_or(&[p, notq]);
let eq = m.mk_eq(p, q);
let f = m.mk_and(&[or, eq]);
assert_eq!(m.kind(f), AstKind::App);
assert_eq!(m.get_sort(f), m.mk_bool_sort());
let and_decl = m.app_decl(f);
let fd = m.func_decl(and_decl).unwrap();
assert_eq!(fd.info.family_id, BASIC_FAMILY_ID);
assert_eq!(fd.info.decl_kind, BasicOp::And as DeclKind);
assert!(fd.flags.commutative && fd.flags.flat_associative);
}
#[test]
fn structural_sharing_holds_for_formulas() {
let mut m = AstManager::new();
let p = m.mk_bool_const("p");
let q = m.mk_bool_const("q");
let a1 = m.mk_and(&[p, q]);
let a2 = m.mk_and(&[p, q]);
assert_eq!(a1, a2);
let a3 = m.mk_and(&[q, p]);
assert_ne!(a1, a3);
}
#[test]
fn ite_and_eq_take_argument_sorts() {
let mut m = AstManager::new();
let a = m.mk_uninterpreted_sort(Symbol::new("A"));
let xd = m.mk_func_decl(Symbol::new("x"), &[], a);
let yd = m.mk_func_decl(Symbol::new("y"), &[], a);
let x = m.mk_const(xd);
let y = m.mk_const(yd);
let c = m.mk_bool_const("c");
let ite = m.mk_ite(c, x, y);
assert_eq!(m.get_sort(ite), a);
let eq = m.mk_eq(x, y);
assert_eq!(m.get_sort(eq), m.mk_bool_sort());
let eq_decl = m.app_decl(eq);
assert_eq!(m.func_decl(eq_decl).unwrap().domain[0], a);
}
}