1use std::fmt;
14
15use crate::{
16 BinOp, BinRel, ConstDecl, Constant, Constraint, DataCtor, DataDecl, Expr, FixpointFmt, FunDef,
17 Identifier, KVarDecl, Sort, SortCtor, Task, ThyFunc, Types, constraint::Pred,
18};
19
20struct HornClause<'a, T: Types> {
22 vars: Vec<(&'a T::Var, &'a Sort<T>)>,
24 guards: Vec<&'a Pred<T>>,
26 head: &'a Pred<T>,
28}
29
30fn flatten_constraint<'a, T: Types>(
32 constraint: &'a Constraint<T>,
33 vars: &mut Vec<(&'a T::Var, &'a Sort<T>)>,
34 guards: &mut Vec<&'a Pred<T>>,
35 clauses: &mut Vec<HornClause<'a, T>>,
36) {
37 match constraint {
38 Constraint::ForAll(bind, body) => {
39 vars.push((&bind.name, &bind.sort));
40 let guard_len = guards.len();
41 guards.extend(bind.preds.iter().filter(|a| a.is_trivially_true()));
42 flatten_constraint(body, vars, guards, clauses);
43 guards.truncate(guard_len);
44 vars.pop();
45 }
46 Constraint::Conj(cstrs) => {
47 for cstr in cstrs {
48 flatten_constraint(cstr, vars, guards, clauses);
49 }
50 }
51 Constraint::Pred(head, _tag) => {
52 if head.is_trivially_true() {
53 return;
54 }
55 clauses.push(HornClause { vars: vars.clone(), guards: guards.clone(), head });
56 }
57 }
58}
59
60pub fn fmt_smt_horn<T: Types>(task: &Task<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 writeln!(f, "(set-logic HORN)")?;
66 writeln!(f)?;
67
68 for line in &task.comments {
70 writeln!(f, ";; {line}")?;
71 }
72 if !task.comments.is_empty() {
73 writeln!(f)?;
74 }
75
76 for data_decl in &task.data_decls {
78 fmt_data_decl_smt(data_decl, f)?;
79 }
80
81 for cinfo in &task.constants {
83 fmt_const_decl(cinfo, f)?;
84 }
85
86 for fun_decl in &task.define_funs {
88 fmt_fun_def(fun_decl, f)?;
89 }
90
91 for kvar in &task.kvars {
93 fmt_kvar_as_fun(kvar, f)?;
94 }
95
96 writeln!(f)?;
97
98 let mut clauses = Vec::new();
100 let mut vars = Vec::new();
101 let mut guards = Vec::new();
102 flatten_constraint(&task.constraint, &mut vars, &mut guards, &mut clauses);
103
104 for clause in &clauses {
106 fmt_assert(clause, f)?;
107 }
108
109 writeln!(f)?;
110 writeln!(f, "(check-sat)")
111}
112
113fn fmt_kvar_as_fun<T: Types>(kvar: &KVarDecl<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(f, "(declare-fun {} (", kvar.kvid.display())?;
115 for (i, sort) in kvar.sorts.iter().enumerate() {
116 if i > 0 {
117 write!(f, " ")?;
118 }
119 fmt_sort_smt(sort, f)?;
120 }
121 writeln!(f, ") Bool)")
122}
123
124fn fmt_assert<T: Types>(clause: &HornClause<'_, T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "(assert ")?;
126
127 if !clause.vars.is_empty() {
129 write!(f, "(forall (")?;
130 for (var, sort) in &clause.vars {
131 write!(f, "({} ", var.display())?;
132 fmt_sort_smt(sort, f)?;
133 write!(f, ")")?;
134 }
135 write!(f, ") ")?;
136 }
137
138 match &clause.head {
139 Pred::KVar(k, args) => {
140 write!(f, "(=> ")?;
142 fmt_guard_conjunction(&clause.guards, f)?;
143 write!(f, " ({}", k.display())?;
144 for arg in args {
145 write!(f, " ")?;
146 fmt_expr_smt(arg, f)?;
147 }
148 write!(f, "))")?;
149 }
150 Pred::Expr(e) => {
151 write!(f, "(=> ")?;
153 let guard_count = clause.guards.len() + 1;
154 if guard_count == 1 && clause.guards.is_empty() {
155 write!(f, "(not ")?;
156 fmt_expr_smt(e, f)?;
157 write!(f, ")")?;
158 } else {
159 write!(f, "(and")?;
160 for guard in &clause.guards {
161 write!(f, " ")?;
162 fmt_guard(guard, f)?;
163 }
164 write!(f, " (not ")?;
165 fmt_expr_smt(e, f)?;
166 write!(f, "))")?;
167 }
168 write!(f, " false)")?;
169 }
170 }
171
172 if !clause.vars.is_empty() {
174 write!(f, ")")?;
175 }
176
177 writeln!(f, ")")
178}
179
180fn fmt_guard_conjunction<T: Types>(guards: &[&Pred<T>], f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 if guards.is_empty() {
182 write!(f, "true")
183 } else if guards.len() == 1 {
184 fmt_guard(guards[0], f)
185 } else {
186 write!(f, "(and")?;
187 for guard in guards {
188 write!(f, " ")?;
189 fmt_guard(guard, f)?;
190 }
191 write!(f, ")")
192 }
193}
194
195fn fmt_guard<T: Types>(guard: &Pred<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 match guard {
197 Pred::KVar(k, args) => {
198 write!(f, "({}", k.display())?;
199 for arg in args {
200 write!(f, " ")?;
201 fmt_expr_smt(arg, f)?;
202 }
203 write!(f, ")")
204 }
205 Pred::Expr(e) => fmt_expr_smt(e, f),
206 }
207}
208
209pub struct SmtFormatter<'a, T: Types>(pub &'a Task<T>);
210
211impl<T: Types> fmt::Display for SmtFormatter<'_, T> {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 fmt_smt_horn(self.0, f)
214 }
215}
216
217fn fmt_sort_smt<T: Types>(sort: &Sort<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 match sort {
221 Sort::Int => write!(f, "Int"),
222 Sort::Bool => write!(f, "Bool"),
223 Sort::Real => write!(f, "Real"),
224 Sort::Str => write!(f, "String"),
225 Sort::BitVec(size) => {
226 write!(f, "(_ BitVec ")?;
227 fmt_sort_smt(size, f)?;
228 write!(f, ")")
229 }
230 Sort::BvSize(size) => write!(f, "{size}"),
231 Sort::Var(i) => write!(f, "T{i}"),
232 Sort::Func(fsort) => {
233 let [input, output] = &**fsort;
235 write!(f, "(Array ")?;
236 fmt_sort_smt(input, f)?;
237 write!(f, " ")?;
238 fmt_sort_smt(output, f)?;
239 write!(f, ")")
240 }
241 Sort::Abs(_, sort) => fmt_sort_smt(sort, f),
242 Sort::App(ctor, args) => {
243 if args.is_empty() {
244 fmt_sort_ctor_smt(ctor, f)
245 } else {
246 write!(f, "(")?;
247 fmt_sort_ctor_smt(ctor, f)?;
248 for arg in args {
249 write!(f, " ")?;
250 fmt_sort_smt(arg, f)?;
251 }
252 write!(f, ")")
253 }
254 }
255 }
256}
257
258fn fmt_sort_ctor_smt<T: Types>(ctor: &SortCtor<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 match ctor {
260 SortCtor::Set => write!(f, "Set"),
261 SortCtor::Map => write!(f, "Map"),
262 SortCtor::Data(name) => write!(f, "{}", name.display()),
263 }
264}
265
266fn fmt_expr_smt<T: Types>(expr: &Expr<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 match expr {
270 Expr::Constant(c) => fmt_constant_smt(c, f),
271 Expr::Var(x) => write!(f, "{}", x.display()),
272 Expr::App(func, _sort_args, args, _out_sort) => {
273 write!(f, "(")?;
274 fmt_expr_smt(func, f)?;
275 for arg in args {
276 write!(f, " ")?;
277 fmt_expr_smt(arg, f)?;
278 }
279 write!(f, ")")
280 }
281 Expr::Neg(e) => {
282 write!(f, "(- ")?;
283 fmt_expr_smt(e, f)?;
284 write!(f, ")")
285 }
286 Expr::BinaryOp(op, exprs) => {
287 let [e1, e2] = &**exprs;
288 write!(f, "({} ", fmt_binop_smt(*op))?;
289 fmt_expr_smt(e1, f)?;
290 write!(f, " ")?;
291 fmt_expr_smt(e2, f)?;
292 write!(f, ")")
293 }
294 Expr::IfThenElse(exprs) => {
295 let [p, e1, e2] = &**exprs;
296 write!(f, "(ite ")?;
297 fmt_expr_smt(p, f)?;
298 write!(f, " ")?;
299 fmt_expr_smt(e1, f)?;
300 write!(f, " ")?;
301 fmt_expr_smt(e2, f)?;
302 write!(f, ")")
303 }
304 Expr::And(exprs) => {
305 if exprs.is_empty() {
306 write!(f, "true")
307 } else {
308 write!(f, "(and")?;
309 for e in exprs {
310 write!(f, " ")?;
311 fmt_expr_smt(e, f)?;
312 }
313 write!(f, ")")
314 }
315 }
316 Expr::Or(exprs) => {
317 if exprs.is_empty() {
318 write!(f, "false")
319 } else {
320 write!(f, "(or")?;
321 for e in exprs {
322 write!(f, " ")?;
323 fmt_expr_smt(e, f)?;
324 }
325 write!(f, ")")
326 }
327 }
328 Expr::Not(e) => {
329 write!(f, "(not ")?;
330 fmt_expr_smt(e, f)?;
331 write!(f, ")")
332 }
333 Expr::Imp(exprs) => {
334 let [e1, e2] = &**exprs;
335 write!(f, "(=> ")?;
336 fmt_expr_smt(e1, f)?;
337 write!(f, " ")?;
338 fmt_expr_smt(e2, f)?;
339 write!(f, ")")
340 }
341 Expr::Iff(exprs) => {
342 let [e1, e2] = &**exprs;
343 write!(f, "(= ")?;
344 fmt_expr_smt(e1, f)?;
345 write!(f, " ")?;
346 fmt_expr_smt(e2, f)?;
347 write!(f, ")")
348 }
349 Expr::Atom(rel, exprs) => {
350 let [e1, e2] = &**exprs;
351 fmt_binrel_smt(*rel, e1, e2, f)
352 }
353 Expr::Let(name, exprs) => {
354 let [e1, e2] = &**exprs;
355 write!(f, "(let (({} ", name.display())?;
356 fmt_expr_smt(e1, f)?;
357 write!(f, ")) ")?;
358 fmt_expr_smt(e2, f)?;
359 write!(f, ")")
360 }
361 Expr::ThyFunc(thy_func) => fmt_thy_func_smt(thy_func, f),
362 Expr::IsCtor(ctor, e) => {
363 write!(f, "((_ is {}) ", ctor.display())?;
364 fmt_expr_smt(e, f)?;
365 write!(f, ")")
366 }
367 Expr::Quantifier(..) => {
368 panic!("Quantifiers are not supported in SMT/Horn format");
369 }
370 Expr::WKVar(..) => {
372 panic!("Weak KVars not supported in SMT/Horn format")
375 }
376 }
377}
378
379fn fmt_constant_smt<T: Types>(c: &Constant<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 match c {
381 Constant::Numeral(n) => write!(f, "{n}"),
382 Constant::Real(n) => write!(f, "{}", n.display()),
383 Constant::Boolean(b) => write!(f, "{b}"),
384 Constant::String(s) => write!(f, "\"{}\"", s.display()),
385 Constant::BitVec(val, size) => write!(f, "(_ bv{val} {size})"),
386 }
387}
388
389fn fmt_binop_smt(op: BinOp) -> &'static str {
390 match op {
391 BinOp::Add => "+",
392 BinOp::Sub => "-",
393 BinOp::Mul => "*",
394 BinOp::Div => "div",
395 BinOp::Mod => "mod",
396 }
397}
398
399fn fmt_binrel_smt<T: Types>(
400 rel: BinRel,
401 e1: &Expr<T>,
402 e2: &Expr<T>,
403 f: &mut fmt::Formatter<'_>,
404) -> fmt::Result {
405 match rel {
406 BinRel::Ne => {
407 write!(f, "(not (= ")?;
408 fmt_expr_smt(e1, f)?;
409 write!(f, " ")?;
410 fmt_expr_smt(e2, f)?;
411 write!(f, "))")
412 }
413 _ => {
414 let op = match rel {
415 BinRel::Eq => "=",
416 BinRel::Gt => ">",
417 BinRel::Ge => ">=",
418 BinRel::Lt => "<",
419 BinRel::Le => "<=",
420 BinRel::Ne => unreachable!(),
421 };
422 write!(f, "({op} ")?;
423 fmt_expr_smt(e1, f)?;
424 write!(f, " ")?;
425 fmt_expr_smt(e2, f)?;
426 write!(f, ")")
427 }
428 }
429}
430
431fn fmt_thy_func_smt(thy_func: &ThyFunc, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match thy_func {
433 ThyFunc::StrLen => write!(f, "str.len"),
434 ThyFunc::StrConcat => write!(f, "str.++"),
435 ThyFunc::StrPrefixOf => write!(f, "str.prefixof"),
436 ThyFunc::StrSuffixOf => write!(f, "str.suffixof"),
437 ThyFunc::StrContains => write!(f, "str.contains"),
438 ThyFunc::BvZeroExtend(size) => write!(f, "(_ zero_extend {size})"),
439 ThyFunc::BvSignExtend(size) => write!(f, "(_ sign_extend {size})"),
440 ThyFunc::IntToBv8 => write!(f, "(_ int2bv 8)"),
441 ThyFunc::Bv8ToInt => write!(f, "bv2int"),
442 ThyFunc::IntToBv32 => write!(f, "(_ int2bv 32)"),
443 ThyFunc::Bv32ToInt => write!(f, "bv2int"),
444 ThyFunc::IntToBv64 => write!(f, "(_ int2bv 64)"),
445 ThyFunc::Bv64ToInt => write!(f, "bv2int"),
446 ThyFunc::BvUle => write!(f, "bvule"),
447 ThyFunc::BvSle => write!(f, "bvsle"),
448 ThyFunc::BvUge => write!(f, "bvuge"),
449 ThyFunc::BvSge => write!(f, "bvsge"),
450 ThyFunc::BvUdiv => write!(f, "bvudiv"),
451 ThyFunc::BvSdiv => write!(f, "bvsdiv"),
452 ThyFunc::BvSrem => write!(f, "bvsrem"),
453 ThyFunc::BvUrem => write!(f, "bvurem"),
454 ThyFunc::BvLshr => write!(f, "bvlshr"),
455 ThyFunc::BvAshr => write!(f, "bvashr"),
456 ThyFunc::BvAnd => write!(f, "bvand"),
457 ThyFunc::BvOr => write!(f, "bvor"),
458 ThyFunc::BvXor => write!(f, "bvxor"),
459 ThyFunc::BvNot => write!(f, "bvnot"),
460 ThyFunc::BvAdd => write!(f, "bvadd"),
461 ThyFunc::BvNeg => write!(f, "bvneg"),
462 ThyFunc::BvSub => write!(f, "bvsub"),
463 ThyFunc::BvMul => write!(f, "bvmul"),
464 ThyFunc::BvShl => write!(f, "bvshl"),
465 ThyFunc::BvUgt => write!(f, "bvugt"),
466 ThyFunc::BvSgt => write!(f, "bvsgt"),
467 ThyFunc::BvUlt => write!(f, "bvult"),
468 ThyFunc::BvSlt => write!(f, "bvslt"),
469 ThyFunc::SetEmpty => write!(f, "as emptyset"),
470 ThyFunc::SetSng => write!(f, "singleton"),
471 ThyFunc::SetCup => write!(f, "union"),
472 ThyFunc::SetCap => write!(f, "intersection"),
473 ThyFunc::SetDif => write!(f, "setminus"),
474 ThyFunc::SetMem => write!(f, "member"),
475 ThyFunc::SetSub => write!(f, "subset"),
476 ThyFunc::MapDefault => write!(f, "const"),
477 ThyFunc::MapSelect => write!(f, "select"),
478 ThyFunc::MapStore => write!(f, "store"),
479 }
480}
481
482fn fmt_data_decl_smt<T: Types>(decl: &DataDecl<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 if decl.ctors.is_empty() {
486 write!(f, "(declare-sort {} {})", decl.name.display(), decl.vars)?;
487 writeln!(f)
488 } else {
489 write!(f, "(declare-datatypes (")?;
490 write!(f, "({} {})", decl.name.display(), decl.vars)?;
491 write!(f, ") ((")?;
492 for (i, ctor) in decl.ctors.iter().enumerate() {
493 if i > 0 {
494 write!(f, " ")?;
495 }
496 fmt_data_ctor_smt(ctor, f)?;
497 }
498 writeln!(f, ")))")
499 }
500}
501
502fn fmt_data_ctor_smt<T: Types>(ctor: &DataCtor<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
503 write!(f, "({}", ctor.name.display())?;
504 for field in &ctor.fields {
505 write!(f, " ({} ", field.name.display())?;
506 fmt_sort_smt(&field.sort, f)?;
507 write!(f, ")")?;
508 }
509 write!(f, ")")
510}
511
512fn fmt_const_decl<T: Types>(decl: &ConstDecl<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
513 write!(f, "(declare-const {} ", decl.name.display())?;
514 fmt_sort_smt(&decl.sort, f)?;
515 writeln!(f, ")")
516}
517
518fn fmt_fun_def<T: Types>(fun: &FunDef<T>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519 if let Some(body) = &fun.body {
520 write!(f, "(define-fun {} (", fun.name.display())?;
521 for (i, (name, sort)) in body.args.iter().zip(&fun.sort.inputs).enumerate() {
522 if i > 0 {
523 write!(f, " ")?;
524 }
525 write!(f, "({} ", name.display())?;
526 fmt_sort_smt(sort, f)?;
527 write!(f, ")")?;
528 }
529 write!(f, ") ")?;
530 fmt_sort_smt(&fun.sort.output, f)?;
531 write!(f, " ")?;
532 fmt_expr_smt(&body.expr, f)?;
533 writeln!(f, ")")
534 } else {
535 write!(f, "(declare-fun {} (", fun.name.display())?;
536 for (i, sort) in fun.sort.inputs.iter().enumerate() {
537 if i > 0 {
538 write!(f, " ")?;
539 }
540 fmt_sort_smt(sort, f)?;
541 }
542 write!(f, ") ")?;
543 fmt_sort_smt(&fun.sort.output, f)?;
544 writeln!(f, ")")
545 }
546}