1use crate::ir::{VerifyExpr, VerifyOp, VerifyType, BitVecOp};
6use std::collections::HashSet;
7
8pub fn to_smtlib2(expr: &VerifyExpr, declarations: &[(&str, VerifyType)]) -> String {
10 let mut output = String::new();
11 output.push_str("(set-logic ALL)\n");
12
13 for (name, ty) in declarations {
15 let sort = type_to_smtlib(ty);
16 output.push_str(&format!("(declare-fun {} () {})\n", name, sort));
17 }
18
19 let mut vars = HashSet::new();
21 crate::equivalence::collect_vars_pub(expr, &mut vars);
22 let declared: HashSet<String> = declarations.iter().map(|(n, _)| n.to_string()).collect();
23 for var in &vars {
24 if !declared.contains(var) {
25 output.push_str(&format!("(declare-fun {} () Int)\n", var));
26 }
27 }
28
29 output.push_str(&format!("(assert {})\n", expr_to_smtlib(expr)));
30 output.push_str("(check-sat)\n");
31 output.push_str("(get-model)\n");
32 output
33}
34
35pub fn equivalence_to_smtlib2(a: &VerifyExpr, b: &VerifyExpr) -> String {
37 let mut output = String::new();
38 output.push_str("(set-logic ALL)\n");
39
40 let mut vars = HashSet::new();
41 crate::equivalence::collect_vars_pub(a, &mut vars);
42 crate::equivalence::collect_vars_pub(b, &mut vars);
43 for var in &vars {
44 output.push_str(&format!("(declare-fun {} () Int)\n", var));
45 }
46
47 let a_smt = expr_to_smtlib(a);
48 let b_smt = expr_to_smtlib(b);
49 output.push_str(&format!("(assert (not (= {} {})))\n", a_smt, b_smt));
50 output.push_str("(check-sat)\n");
51 output
52}
53
54fn type_to_smtlib(ty: &VerifyType) -> String {
55 match ty {
56 VerifyType::Int => "Int".into(),
57 VerifyType::Bool => "Bool".into(),
58 VerifyType::Object => "Int".into(),
59 VerifyType::Real => "Real".into(),
60 VerifyType::BitVector(w) => format!("(_ BitVec {})", w),
61 VerifyType::Array(idx, elem) => {
62 format!("(Array {} {})", type_to_smtlib(idx), type_to_smtlib(elem))
63 }
64 }
65}
66
67fn expr_to_smtlib(expr: &VerifyExpr) -> String {
68 match expr {
69 VerifyExpr::Bool(true) => "true".into(),
70 VerifyExpr::Bool(false) => "false".into(),
71 VerifyExpr::Int(n) => {
72 if *n < 0 { format!("(- {})", -n) } else { n.to_string() }
73 }
74 VerifyExpr::Var(name) => name.clone(),
75 VerifyExpr::Binary { op, left, right } => {
76 let l = expr_to_smtlib(left);
77 let r = expr_to_smtlib(right);
78 let op_str = match op {
79 VerifyOp::Add => "+",
80 VerifyOp::Sub => "-",
81 VerifyOp::Mul => "*",
82 VerifyOp::Div => "div",
83 VerifyOp::FloorDiv => return format!("(to_int (/ (to_real {}) (to_real {})))", l, r),
85 VerifyOp::Eq => "=",
86 VerifyOp::Neq => return format!("(not (= {} {}))", l, r),
87 VerifyOp::Gt => ">",
88 VerifyOp::Lt => "<",
89 VerifyOp::Gte => ">=",
90 VerifyOp::Lte => "<=",
91 VerifyOp::And => "and",
92 VerifyOp::Or => "or",
93 VerifyOp::Implies => "=>",
94 };
95 format!("({} {} {})", op_str, l, r)
96 }
97 VerifyExpr::Not(inner) => format!("(not {})", expr_to_smtlib(inner)),
98 VerifyExpr::Iff(l, r) => format!("(= {} {})", expr_to_smtlib(l), expr_to_smtlib(r)),
99 VerifyExpr::ForAll { vars, body } => {
100 let bindings: Vec<String> = vars.iter()
101 .map(|(n, t)| format!("({} {})", n, type_to_smtlib(t)))
102 .collect();
103 format!("(forall ({}) {})", bindings.join(" "), expr_to_smtlib(body))
104 }
105 VerifyExpr::Exists { vars, body } => {
106 let bindings: Vec<String> = vars.iter()
107 .map(|(n, t)| format!("({} {})", n, type_to_smtlib(t)))
108 .collect();
109 format!("(exists ({}) {})", bindings.join(" "), expr_to_smtlib(body))
110 }
111 VerifyExpr::Apply { name, args } | VerifyExpr::ApplyInt { name, args } => {
112 let arg_strs: Vec<String> = args.iter().map(expr_to_smtlib).collect();
113 if arg_strs.is_empty() {
114 name.clone()
115 } else {
116 format!("({} {})", name, arg_strs.join(" "))
117 }
118 }
119 VerifyExpr::BitVecConst { width, value } => {
120 format!("#x{:0>width$X}", value, width = ((*width + 3) / 4) as usize)
121 }
122 VerifyExpr::BitVecBinary { op, left, right } => {
123 let l = expr_to_smtlib(left);
124 let r = expr_to_smtlib(right);
125 let op_str = match op {
126 BitVecOp::And => "bvand",
127 BitVecOp::Or => "bvor",
128 BitVecOp::Xor => "bvxor",
129 BitVecOp::Not => return format!("(bvnot {})", l),
130 BitVecOp::Shl => "bvshl",
131 BitVecOp::Shr => "bvlshr",
132 BitVecOp::AShr => "bvashr",
133 BitVecOp::Add => "bvadd",
134 BitVecOp::Sub => "bvsub",
135 BitVecOp::Mul => "bvmul",
136 BitVecOp::SDiv => "bvsdiv",
137 BitVecOp::SRem => "bvsrem",
138 BitVecOp::ULt => "bvult",
139 BitVecOp::SLt => "bvslt",
140 BitVecOp::ULe => "bvule",
141 BitVecOp::SLe => "bvsle",
142 BitVecOp::Eq => return format!("(= {} {})", l, r),
143 };
144 format!("({} {} {})", op_str, l, r)
145 }
146 VerifyExpr::BitVecExtract { high, low, operand } => {
147 format!("((_ extract {} {}) {})", high, low, expr_to_smtlib(operand))
148 }
149 VerifyExpr::BitVecConcat(l, r) => {
150 format!("(concat {} {})", expr_to_smtlib(l), expr_to_smtlib(r))
151 }
152 VerifyExpr::Select { array, index } => {
153 format!("(select {} {})", expr_to_smtlib(array), expr_to_smtlib(index))
154 }
155 VerifyExpr::Store { array, index, value } => {
156 format!("(store {} {} {})", expr_to_smtlib(array), expr_to_smtlib(index), expr_to_smtlib(value))
157 }
158 VerifyExpr::AtState { expr, .. } => expr_to_smtlib(expr),
159 VerifyExpr::Transition { from, to } => {
160 format!("(and {} {})", expr_to_smtlib(from), expr_to_smtlib(to))
161 }
162 }
163}