1use std::sync::LazyLock;
2
3use derive_where::derive_where;
4
5use crate::{DefaultTypes, Types};
6
7pub(crate) static DEFAULT_QUALIFIERS: LazyLock<[Qualifier<DefaultTypes>; 13]> =
8 LazyLock::new(|| {
9 let eqtrue = Qualifier {
14 args: vec![("v", Sort::Bool)],
15 body: Expr::Var("v"),
16 name: String::from("EqTrue"),
17 };
18 let eqfalse = Qualifier {
20 args: vec![("v", Sort::Bool)],
21 body: Expr::Neg(Box::new(Expr::Var("v"))),
22 name: String::from("EqFalse"),
23 };
24 let eqzero = Qualifier {
26 args: vec![("v", Sort::Int)],
27 body: Expr::Atom(BinRel::Eq, Box::new([Expr::Var("v"), Expr::int(0)])),
28 name: String::from("EqZero"),
29 };
30
31 let gtzero = Qualifier {
33 args: vec![("v", Sort::Int)],
34 body: Expr::Atom(BinRel::Gt, Box::new([Expr::Var("v"), Expr::int(0)])),
35 name: String::from("GtZero"),
36 };
37
38 let gezero = Qualifier {
40 args: vec![("v", Sort::Int)],
41 body: Expr::Atom(BinRel::Ge, Box::new([Expr::Var("v"), Expr::int(0)])),
42 name: String::from("GeZero"),
43 };
44
45 let ltzero = Qualifier {
47 args: vec![("v", Sort::Int)],
48 body: Expr::Atom(BinRel::Lt, Box::new([Expr::Var("v"), Expr::int(0)])),
49 name: String::from("LtZero"),
50 };
51
52 let lezero = Qualifier {
54 args: vec![("v", Sort::Int)],
55 body: Expr::Atom(BinRel::Le, Box::new([Expr::Var("v"), Expr::int(0)])),
56 name: String::from("LeZero"),
57 };
58
59 let eq = Qualifier {
65 args: vec![("a", Sort::Int), ("b", Sort::Int)],
66 body: Expr::Atom(BinRel::Eq, Box::new([Expr::Var("a"), Expr::Var("b")])),
67 name: String::from("Eq"),
68 };
69
70 let gt = Qualifier {
72 args: vec![("a", Sort::Int), ("b", Sort::Int)],
73 body: Expr::Atom(BinRel::Gt, Box::new([Expr::Var("a"), Expr::Var("b")])),
74 name: String::from("Gt"),
75 };
76
77 let ge = Qualifier {
79 args: vec![("a", Sort::Int), ("b", Sort::Int)],
80 body: Expr::Atom(BinRel::Ge, Box::new([Expr::Var("a"), Expr::Var("b")])),
81 name: String::from("Ge"),
82 };
83
84 let lt = Qualifier {
86 args: vec![("a", Sort::Int), ("b", Sort::Int)],
87 body: Expr::Atom(BinRel::Lt, Box::new([Expr::Var("a"), Expr::Var("b")])),
88 name: String::from("Lt"),
89 };
90
91 let le = Qualifier {
93 args: vec![("a", Sort::Int), ("b", Sort::Int)],
94 body: Expr::Atom(BinRel::Le, Box::new([Expr::Var("a"), Expr::Var("b")])),
95 name: String::from("Le"),
96 };
97
98 let le1 = Qualifier {
100 args: vec![("a", Sort::Int), ("b", Sort::Int)],
101 body: Expr::Atom(
102 BinRel::Le,
103 Box::new([
104 Expr::Var("a"),
105 Expr::BinaryOp(BinOp::Sub, Box::new([Expr::Var("b"), Expr::int(1)])),
106 ]),
107 ),
108 name: String::from("Le1"),
109 };
110
111 [eqtrue, eqfalse, eqzero, gtzero, gezero, ltzero, lezero, eq, gt, ge, lt, le, le1]
112 });
113
114#[derive_where(Hash)]
115pub struct Bind<T: Types> {
116 pub name: T::Var,
117 pub sort: Sort<T>,
118 pub pred: Pred<T>,
119}
120
121#[derive_where(Hash)]
122pub enum Constraint<T: Types> {
123 Pred(Pred<T>, #[derive_where(skip)] Option<T::Tag>),
124 Conj(Vec<Self>),
125 ForAll(Bind<T>, Box<Self>),
126}
127
128impl<T: Types> Constraint<T> {
129 pub const TRUE: Self = Self::Pred(Pred::TRUE, None);
130
131 pub fn foralls(bindings: Vec<Bind<T>>, c: Self) -> Self {
132 bindings
133 .into_iter()
134 .rev()
135 .fold(c, |c, bind| Constraint::ForAll(bind, Box::new(c)))
136 }
137
138 pub fn conj(mut cstrs: Vec<Self>) -> Self {
139 if cstrs.len() == 1 { cstrs.remove(0) } else { Self::Conj(cstrs) }
140 }
141
142 pub fn is_concrete(&self) -> bool {
145 match self {
146 Constraint::Conj(cs) => cs.iter().any(Constraint::is_concrete),
147 Constraint::ForAll(_, c) => c.is_concrete(),
148 Constraint::Pred(p, _) => p.is_concrete() && !p.is_trivially_true(),
149 }
150 }
151}
152
153#[derive_where(Hash)]
154pub struct DataDecl<T: Types> {
155 pub name: T::Sort,
156 pub vars: usize,
157 pub ctors: Vec<DataCtor<T>>,
158}
159
160#[derive_where(Hash)]
161pub struct DataCtor<T: Types> {
162 pub name: T::Var,
163 pub fields: Vec<DataField<T>>,
164}
165
166#[derive_where(Hash)]
167pub struct DataField<T: Types> {
168 pub name: T::Var,
169 pub sort: Sort<T>,
170}
171
172#[derive_where(Hash, Clone)]
173pub enum Sort<T: Types> {
174 Int,
175 Bool,
176 Real,
177 Str,
178 BitVec(Box<Sort<T>>),
179 BvSize(u32),
180 Var(usize),
181 Func(Box<[Self; 2]>),
182 Abs(usize, Box<Self>),
183 App(SortCtor<T>, Vec<Self>),
184}
185
186impl<T: Types> Sort<T> {
187 pub fn mk_func<I>(params: usize, inputs: I, output: Sort<T>) -> Sort<T>
188 where
189 I: IntoIterator<Item = Sort<T>>,
190 I::IntoIter: DoubleEndedIterator,
191 {
192 let sort = inputs
193 .into_iter()
194 .rev()
195 .fold(output, |output, input| Sort::Func(Box::new([input, output])));
196
197 (0..params)
198 .rev()
199 .fold(sort, |sort, i| Sort::Abs(i, Box::new(sort)))
200 }
201
202 pub(crate) fn peel_out_abs(&self) -> (usize, &Sort<T>) {
203 let mut n = 0;
204 let mut curr = self;
205 while let Sort::Abs(i, sort) = curr {
206 assert_eq!(*i, n);
207 n += 1;
208 curr = sort;
209 }
210 (n, curr)
211 }
212}
213
214#[derive_where(Hash, Clone)]
215pub enum SortCtor<T: Types> {
216 Set,
217 Map,
218 Data(T::Sort),
219}
220
221#[derive_where(Hash)]
222pub enum Pred<T: Types> {
223 And(Vec<Self>),
224 KVar(T::KVar, Vec<T::Var>),
225 Expr(Expr<T>),
226}
227
228impl<T: Types> Pred<T> {
229 pub const TRUE: Self = Pred::Expr(Expr::Constant(Constant::Boolean(true)));
230
231 pub fn and(mut preds: Vec<Self>) -> Self {
232 if preds.len() == 1 { preds.remove(0) } else { Self::And(preds) }
233 }
234
235 pub fn is_trivially_true(&self) -> bool {
236 match self {
237 Pred::Expr(Expr::Constant(Constant::Boolean(true))) => true,
238 Pred::And(ps) => ps.is_empty(),
239 _ => false,
240 }
241 }
242
243 pub fn is_concrete(&self) -> bool {
244 match self {
245 Pred::And(ps) => ps.iter().any(Pred::is_concrete),
246 Pred::KVar(_, _) => false,
247 Pred::Expr(_) => true,
248 }
249 }
250}
251
252#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)]
253pub enum BinRel {
254 Eq,
255 Ne,
256 Gt,
257 Ge,
258 Lt,
259 Le,
260}
261
262impl BinRel {
263 pub const INEQUALITIES: [BinRel; 4] = [BinRel::Gt, BinRel::Ge, BinRel::Lt, BinRel::Le];
264}
265
266#[derive_where(Hash)]
267pub enum Expr<T: Types> {
268 Constant(Constant<T>),
269 Var(T::Var),
270 App(Box<Self>, Vec<Self>),
271 Neg(Box<Self>),
272 BinaryOp(BinOp, Box<[Self; 2]>),
273 IfThenElse(Box<[Self; 3]>),
274 And(Vec<Self>),
275 Or(Vec<Self>),
276 Not(Box<Self>),
277 Imp(Box<[Self; 2]>),
278 Iff(Box<[Self; 2]>),
279 Atom(BinRel, Box<[Self; 2]>),
280 Let(T::Var, Box<[Self; 2]>),
281}
282
283impl<T: Types> From<Constant<T>> for Expr<T> {
284 fn from(v: Constant<T>) -> Self {
285 Self::Constant(v)
286 }
287}
288
289impl<T: Types> Expr<T> {
290 pub const fn int(val: u128) -> Expr<T> {
291 Expr::Constant(Constant::Numeral(val))
292 }
293
294 pub fn eq(self, other: Self) -> Self {
295 Expr::Atom(BinRel::Eq, Box::new([self, other]))
296 }
297
298 pub fn and(mut exprs: Vec<Self>) -> Self {
299 if exprs.len() == 1 { exprs.remove(0) } else { Self::And(exprs) }
300 }
301}
302
303#[derive_where(Hash)]
304pub enum Constant<T: Types> {
305 Numeral(u128),
306 Decimal(T::Decimal),
307 Boolean(bool),
308 String(T::String),
309 BitVec(u128, u32),
310}
311
312#[derive_where(Hash)]
313pub struct Qualifier<T: Types> {
314 pub name: String,
315 pub args: Vec<(T::Var, Sort<T>)>,
316 pub body: Expr<T>,
317}
318
319#[derive(Clone, Copy, PartialEq, Eq, Hash)]
320pub enum BinOp {
321 Add,
322 Sub,
323 Mul,
324 Div,
325 Mod,
326}