1
+ # Copyright ${current_year} Budapest University of Technology and Economics
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ #
16
+ # Licensed under the Apache License, Version 2.0 (the "License");
17
+ # you may not use this file except in compliance with the License.
18
+ # You may obtain a copy of the License at
19
+ #
20
+ # http://www.apache.org/licenses/LICENSE-2.0
21
+ #
22
+ # Unless required by applicable law or agreed to in writing, software
23
+ # distributed under the License is distributed on an "AS IS" BASIS,
24
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
+ # See the License for the specific language governing permissions and
26
+ # limitations under the License.
27
+ #
28
+
1
29
import z3
2
30
import textwrap
3
31
7
35
class RecursiveException (Exception ):
8
36
pass
9
37
38
+
10
39
# As long as the CHC is nonrecursive or linear, this can be used
11
40
class LinearCHC2C (BaseCHC2C ):
12
41
@@ -17,7 +46,11 @@ def __init__(self):
17
46
self .current_rule = None
18
47
19
48
def propagate_callgraph (self , func ):
20
- name = self .current_rule .name () if not isinstance (self .current_rule , str ) else self .current_rule
49
+ name = (
50
+ self .current_rule .name ()
51
+ if not isinstance (self .current_rule , str )
52
+ else self .current_rule
53
+ )
21
54
if name not in self .callgraph :
22
55
self .callgraph [name ] = set ()
23
56
self .callgraph [name ].add (func .name ())
@@ -45,7 +78,14 @@ def expr_to_c(self, expr, bound_vars):
45
78
self .propagate_callgraph (func )
46
79
self .create_uf_vars (expr )
47
80
if expr .num_args () > 0 :
48
- return '(' + ' && ' .join (f"{ self .var_lookup [func ][i ][0 ]} == { self .expr_to_c (expr .arg (i ), bound_vars )} " for i in range (expr .num_args ())) + ')'
81
+ return (
82
+ "("
83
+ + " && " .join (
84
+ f"{ self .var_lookup [func ][i ][0 ]} == { self .expr_to_c (expr .arg (i ), bound_vars )} "
85
+ for i in range (expr .num_args ())
86
+ )
87
+ + ")"
88
+ )
49
89
else :
50
90
return self .var_lookup [func ][0 ][0 ]
51
91
else :
@@ -55,9 +95,14 @@ def create_uf_vars(self, expr):
55
95
func = expr .decl ()
56
96
if func not in self .var_lookup :
57
97
if expr .num_args () > 0 :
58
- self .var_lookup [func ] = [(f"{ self .sanitize_identifier (str (func ))} _{ i } " , expr .arg (i ).sort ()) for i in range (expr .num_args ())]
98
+ self .var_lookup [func ] = [
99
+ (f"{ self .sanitize_identifier (str (func ))} _{ i } " , expr .arg (i ).sort ())
100
+ for i in range (expr .num_args ())
101
+ ]
59
102
else :
60
- self .var_lookup [func ] = [(self .sanitize_identifier (str (func )), z3 .BoolSort ())]
103
+ self .var_lookup [func ] = [
104
+ (self .sanitize_identifier (str (func )), z3 .BoolSort ())
105
+ ]
61
106
62
107
def chc_to_c_program (self , smtlib_file_content , filename ):
63
108
# Parse the CHCs using Z3
@@ -70,7 +115,13 @@ def chc_to_c_program(self, smtlib_file_content, filename):
70
115
# Check if this is a forall with an implication
71
116
if z3 .is_quantifier (rule ) and rule .is_forall ():
72
117
# Extract variables and body
73
- bound_vars = [(rule .var_name (rule .num_vars () - i - 1 ), rule .var_sort (rule .num_vars () - i - 1 )) for i in range (rule .num_vars ())]
118
+ bound_vars = [
119
+ (
120
+ rule .var_name (rule .num_vars () - i - 1 ),
121
+ rule .var_sort (rule .num_vars () - i - 1 ),
122
+ )
123
+ for i in range (rule .num_vars ())
124
+ ]
74
125
body = rule .body ()
75
126
76
127
if z3 .is_implies (body ):
@@ -85,27 +136,41 @@ def chc_to_c_program(self, smtlib_file_content, filename):
85
136
86
137
self .check_nonrecursive ()
87
138
88
- c_program = textwrap .dedent (f"""
139
+ c_program = textwrap .dedent (
140
+ f"""
89
141
extern int __VERIFIER_nondet_int();
90
142
extern _Bool __VERIFIER_nondet__Bool();
91
143
extern void abort(void);
92
144
extern void __assert_fail(const char *, const char *, unsigned int, const char *);
93
145
void reach_error() {{ __assert_fail("0", "{ filename } ", 0, "reach_error"); }}
94
- """ )
146
+ """
147
+ )
95
148
c_program += "// function declarations\n "
96
- c_program += "\n " .join ([f"void { func_name } ();" for func_name in function_names ]) + "\n \n "
149
+ c_program += (
150
+ "\n " .join ([f"void { func_name } ();" for func_name in function_names ]) + "\n \n "
151
+ )
97
152
c_program += "// global variables\n "
98
153
for vars in self .var_lookup .values ():
99
- c_program += "\n " .join ([f"{ self .smt_sort_to_c (v [1 ])} { v [0 ]} ;" for v in vars ]) + "\n \n "
154
+ c_program += (
155
+ "\n " .join ([f"{ self .smt_sort_to_c (v [1 ])} { v [0 ]} ;" for v in vars ])
156
+ + "\n \n "
157
+ )
100
158
c_program += "// rules\n "
101
159
c_program += "\n " .join (functions ) + "\n \n "
102
160
c_program += "// main function\n "
103
161
c_program += "int main() {\n int i = __VERIFIER_nondet_int();\n switch(i) {\n "
104
- c_program += "\n " .join ([f" case { i } : { func } (); break;" for i , func in enumerate (function_names )]) + "\n "
162
+ c_program += (
163
+ "\n " .join (
164
+ [
165
+ f" case { i } : { func } (); break;"
166
+ for i , func in enumerate (function_names )
167
+ ]
168
+ )
169
+ + "\n "
170
+ )
105
171
c_program += " default: abort(); break;\n }\n }"
106
172
return c_program
107
173
108
-
109
174
def create_function (self , body , bound_vars , func_name , rule ):
110
175
condition = body .arg (0 ) # Left-hand side of the implication
111
176
conclusion = body .arg (1 ) # Right-hand side of the implication
@@ -119,7 +184,16 @@ def create_function(self, body, bound_vars, func_name, rule):
119
184
# Generate function body
120
185
func_body += f"void { func_name } () {{\n "
121
186
# Declare the parameters as unbound variables
122
- func_body += " " + "\n " .join (map (lambda v : f"{ self .smt_sort_to_c (v [1 ])} { v [0 ]} = __VERIFIER_nondet_{ self .smt_sort_to_c (v [1 ])} ();" , [x for x in bound_vars if x [0 ] != "CHC_COMP_UNUSED" ])) + "\n "
187
+ func_body += (
188
+ " "
189
+ + "\n " .join (
190
+ map (
191
+ lambda v : f"{ self .smt_sort_to_c (v [1 ])} { v [0 ]} = __VERIFIER_nondet_{ self .smt_sort_to_c (v [1 ])} ();" ,
192
+ [x for x in bound_vars if x [0 ] != "CHC_COMP_UNUSED" ],
193
+ )
194
+ )
195
+ + "\n "
196
+ )
123
197
# Convert the left-hand side of the implication to C (condition)
124
198
condition_str = self .expr_to_c (condition , bound_vars )
125
199
func_body += f" if ({ condition_str } ) {{\n "
0 commit comments