1#![doc = concat!("```ignore\n", include_str!("./Core.smt2"), "```")]
2
3use smtlib_lowlevel::{
4 ast::{self, Term},
5 Storage,
6};
7
8use crate::{
9 impl_op,
10 sorts::Sort,
11 terms::{app, qual_ident, Const, Dynamic, IntoWithStorage, STerm, Sorted, StaticSorted},
12};
13
14#[derive(Clone, Copy)]
18pub struct Bool<'st>(STerm<'st>);
19
20impl<'st> Bool<'st> {
21 pub fn new(st: &'st Storage, value: bool) -> Bool<'st> {
23 value.into_with_storage(st)
24 }
25}
26
27impl std::fmt::Debug for Bool<'_> {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 self.0.fmt(f)
30 }
31}
32
33impl<'st> From<Const<'st, Bool<'st>>> for Bool<'st> {
34 fn from(c: Const<'st, Bool<'st>>) -> Self {
35 c.1
36 }
37}
38impl<'st> IntoWithStorage<'st, Bool<'st>> for Const<'st, Bool<'st>> {
39 fn into_with_storage(self, _st: &'st Storage) -> Bool<'st> {
40 self.1
41 }
42}
43impl std::fmt::Display for Bool<'_> {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 self.term().fmt(f)
46 }
47}
48impl<'st> From<Bool<'st>> for Dynamic<'st> {
49 fn from(b: Bool<'st>) -> Self {
50 b.into_dynamic()
51 }
52}
53impl<'st> IntoWithStorage<'st, Bool<'st>> for bool {
54 fn into_with_storage(self, st: &'st Storage) -> Bool<'st> {
55 let s = match self {
56 true => "true",
57 false => "false",
58 };
59
60 STerm::new(st, Term::Identifier(qual_ident(s, None))).into()
61 }
62}
63impl<'st> From<Bool<'st>> for STerm<'st> {
64 fn from(b: Bool<'st>) -> Self {
65 b.0
66 }
67}
68impl<'st> From<STerm<'st>> for Bool<'st> {
69 fn from(t: STerm<'st>) -> Self {
70 Bool(t)
71 }
72}
73impl<'st> From<(STerm<'st>, Sort<'st>)> for Bool<'st> {
74 fn from((t, _): (STerm<'st>, Sort<'st>)) -> Self {
75 t.into()
76 }
77}
78impl<'st> StaticSorted<'st> for Bool<'st> {
79 type Inner = Self;
80 const AST_SORT: ast::Sort<'static> = ast::Sort::new_simple("Bool");
81 fn static_st(&self) -> &'st Storage {
82 self.sterm().st()
83 }
84}
85impl<'st> Bool<'st> {
86 pub fn sort() -> Sort<'st> {
88 Self::AST_SORT.into()
89 }
90 fn binop(self, op: &'st str, other: Bool<'st>) -> Self {
91 app(self.st(), op, (self.term(), other.term())).into()
92 }
93 pub fn implies(self, other: Bool<'st>) -> Bool<'st> {
99 self.binop("=>", other)
100 }
101 pub fn ite<T: Sorted<'st> + From<(STerm<'st>, Sort<'st>)>>(self, then: T, otherwise: T) -> T {
109 let sort = then.sort();
110 let term = app(
111 self.st(),
112 "ite",
113 (self.term(), then.term(), otherwise.term()),
114 );
115 let dyn_term = Dynamic::from_term_sort(term, sort);
116 T::from_dynamic(dyn_term)
117 }
118}
119
120impl_op!(Bool<'st>, bool, BitAnd, bitand, "and", BitAndAssign, bitand_assign, &);
121impl_op!(Bool<'st>, bool, BitOr, bitor, "or", BitOrAssign, bitor_assign, |);
122impl_op!(Bool<'st>, bool, BitXor, bitxor, "xor", BitXorAssign, bitxor_assign, ^);
123
124impl<'st> std::ops::Not for Bool<'st> {
125 type Output = Bool<'st>;
126
127 fn not(self) -> Self::Output {
128 app(self.st(), "not", self.term()).into()
129 }
130}
131
132pub fn and<'st, const N: usize>(st: &'st Storage, terms: [Bool<'st>; N]) -> Bool<'st> {
136 app(st, "and", terms.map(Sorted::term)).into()
137}
138pub fn or<'st, const N: usize>(st: &'st Storage, terms: [Bool<'st>; N]) -> Bool<'st> {
142 app(st, "or", terms.map(Sorted::term)).into()
143}
144pub fn xor<'st, const N: usize>(st: &'st Storage, terms: [Bool<'st>; N]) -> Bool<'st> {
146 app(st, "xor", terms.map(Sorted::term)).into()
147}
148
149pub fn equal<'st, T, const N: usize>(st: &'st Storage, terms: [T; N]) -> Bool<'st>
152where
153 T: Into<STerm<'st>>,
154{
155 app(st, "=", terms.map(Into::into).map(STerm::term)).into()
156}
157pub fn distinct<'st, T, const N: usize>(st: &'st Storage, terms: [T; N]) -> Bool<'st>
160where
161 T: Into<STerm<'st>>,
162{
163 app(st, "distinct", terms.map(Into::into).map(STerm::term)).into()
164}