11//! Not a SAT solver, but a prover. There's a difference.
22
3- use std:: { fmt:: Display , time:: Duration } ;
3+ //use std::{fmt::Display, time::Duration};
4+
5+ use std:: { collections:: VecDeque , fmt:: Display , io:: Write , path:: Path , process:: Command , time:: Duration } ;
6+
7+ use tempfile:: NamedTempFile ;
48
59use z3:: {
610 ast:: { forall_const, Ast , Bool , Dynamic } ,
@@ -21,6 +25,68 @@ pub enum ProveResult<'ctx> {
2125 Unknown ( ReasonUnknown ) ,
2226}
2327
28+ /// Find the swine-z3 file located under the dir directory, and execute swine-z3 on the file located at file_path
29+ fn execute_swine ( dir : & Path , file_path : & Path ) {
30+ let swine = "swine-z3" ;
31+
32+ let find_output = Command :: new ( "find" )
33+ . arg ( dir)
34+ . arg ( "-name" )
35+ . arg ( swine)
36+ . output ( ) . unwrap ( ) ;
37+
38+ if find_output. status . success ( ) {
39+ let stdout = String :: from_utf8_lossy ( & find_output. stdout ) ;
40+
41+ for line in stdout. lines ( ) . rev ( ) {
42+ let path = Path :: new ( line) ;
43+
44+ if path. exists ( ) && path. is_file ( ) {
45+ let cmd_output = Command :: new ( path)
46+ . arg ( file_path)
47+ . output ( ) . unwrap ( ) ;
48+
49+ if cmd_output. status . success ( ) {
50+ println ! ( "{}" , String :: from_utf8_lossy( & cmd_output. stdout) ) ;
51+ break ;
52+ } else {
53+ eprintln ! ( "Failed to execute swine({}) command with status: {}" , line, cmd_output. status) ;
54+ }
55+ }
56+ }
57+ } else {
58+ eprintln ! ( "Find command execution failed" ) ;
59+ }
60+ }
61+
62+ fn remove_lines_for_swine ( input : & str ) -> String {
63+ let mut output = String :: new ( ) ;
64+ let mut tmp_buffer: VecDeque < char > = VecDeque :: new ( ) ;
65+ let mut input_buffer: VecDeque < char > = input. chars ( ) . collect ( ) ;
66+ let mut cnt = 0 ;
67+
68+ while let Some ( c) = input_buffer. pop_front ( ) {
69+ tmp_buffer. push_back ( c) ;
70+ match c {
71+ '(' => {
72+ cnt += 1 ;
73+ }
74+ ')' => {
75+ cnt -= 1 ;
76+ if cnt == 0 {
77+ let tmp: String = tmp_buffer. iter ( ) . collect ( ) ;
78+ if !tmp. contains ( "declare-fun exp" ) && !tmp. contains ( "forall" ) {
79+ output. push_str ( & tmp) ;
80+ }
81+ tmp_buffer. clear ( ) ;
82+ }
83+ }
84+ _ => { }
85+ }
86+ }
87+ output
88+ }
89+
2490impl Display for ProveResult < ' _ > {
2591 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
2692 match self {
@@ -94,6 +160,21 @@ impl<'ctx> Prover<'ctx> {
94160 if self . min_level_with_provables . is_none ( ) {
95161 return ProveResult :: Proof ;
96162 }
163+
164+ let mut smtlib = self . get_smtlib ( ) ;
165+
166+ smtlib. add_check_sat ( ) ;
167+
168+ let smtlib = smtlib. into_string ( ) ;
169+ let mut smt_file: NamedTempFile = NamedTempFile :: new ( ) . unwrap ( ) ;
170+
171+ smt_file. write_all ( remove_lines_for_swine ( & smtlib) . as_bytes ( ) ) . unwrap ( ) ;
172+
173+ let file_path = smt_file. path ( ) ;
174+ let start_dir = Path :: new ( "../" ) ;
175+
176+ execute_swine ( start_dir, file_path) ;
177+
97178 let res = if assumptions. is_empty ( ) {
98179 self . solver . check ( )
99180 } else {
0 commit comments