Revision 995bfad5
Added by Guillaume Davy over 9 years ago
tests/gen_contracts.py | ||
---|---|---|
1 |
import sys |
|
2 |
import os |
|
3 |
import re |
|
4 |
import tempfile |
|
5 |
import subprocess |
|
6 |
import shutil |
|
7 |
|
|
8 |
import xml.etree.ElementTree as ET |
|
9 |
|
|
10 |
re_property_old = re.compile('--%[ ]*PROPERTY([^;]*);') |
|
11 |
re_property = re.compile('--![ ]*PROPERTY[ ]*:([^;]*);') |
|
12 |
re_node = re.compile('.*node.*') |
|
13 |
re_ensures = re.compile('.*ensures.*') |
|
14 |
re_k = re.compile('--![ ]*k[ ]*:([^;]*);') |
|
15 |
|
|
16 |
def findInLines(lines, regex): |
|
17 |
res = [] |
|
18 |
for i in range(len(lines)): |
|
19 |
m = regex.search(lines[i]) |
|
20 |
if m: |
|
21 |
res.append((i, m.groups()[0] if len(m.groups()) > 0 else None)) |
|
22 |
return res |
|
23 |
|
|
24 |
def modProperties(lines, temp): |
|
25 |
properties_old = findInLines(lines, re_property_old) |
|
26 |
|
|
27 |
if not properties_old: |
|
28 |
return (None, "NO_OLD", None) |
|
29 |
|
|
30 |
for (i, data) in properties_old: |
|
31 |
lines[i] = "--!PROPERTY:{};\n".format(data) |
|
32 |
return (lines, "OK", None) |
|
33 |
|
|
34 |
def addEnsures(lines, temp): |
|
35 |
nodes = findInLines(lines, re_node) |
|
36 |
ensures = findInLines(lines, re_ensures) |
|
37 |
properties = findInLines(lines, re_property) |
|
38 |
if not nodes: |
|
39 |
return (None, "NONODE", None) |
|
40 |
if ensures: |
|
41 |
return (None, "ALREADY", None) |
|
42 |
if not properties: |
|
43 |
return (None, "NOPR", None) |
|
44 |
if len(properties) > 1: |
|
45 |
return (None, "TOOMUCHPR", None) |
|
46 |
for (i, data) in properties: |
|
47 |
bestd = len(lines) |
|
48 |
best = -1 |
|
49 |
for (j, _) in nodes: |
|
50 |
if i - j < bestd: |
|
51 |
bestd = i - j |
|
52 |
best = j |
|
53 |
lines.insert(best, "--@ensures " + data + ";\n") |
|
54 |
return (lines, "OK", None) |
|
55 |
|
|
56 |
TIMEOUT=1 |
|
57 |
MAX=10 |
|
58 |
def addK(lines, temp): |
|
59 |
properties = findInLines(lines, re_property) |
|
60 |
k = findInLines(lines, re_k) |
|
61 |
if k: |
|
62 |
return (None, "ALREADY", None) |
|
63 |
if not properties: |
|
64 |
return (None, "NOPR", None) |
|
65 |
if len(properties) > 1: |
|
66 |
return (None, "TOOMUCHPR", None) |
|
67 |
top = temp + "/no_k.lus" |
|
68 |
f = open(top, 'w') |
|
69 |
f.write("".join(lines)) |
|
70 |
f.close() |
|
71 |
p = subprocess.Popen(["timeout", "40", "pkind", top, "-timeout", str(TIMEOUT), "-k_incremental", str(MAX)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
72 |
(stdout, stderr) = p.communicate() |
|
73 |
try: |
|
74 |
root = ET.fromstring(stdout) |
|
75 |
except ET.ParseError: |
|
76 |
return (None, "TIMEOUT", None) |
|
77 |
k = root.find(".//K") |
|
78 |
if k is None: |
|
79 |
return (None, "ERR", None) |
|
80 |
try: |
|
81 |
k = int(k.text) |
|
82 |
except ValueError: |
|
83 |
return (None, "NOTPROVED", None) |
|
84 |
lines.insert(properties[0][0], "--!k:{};\n".format(k)) |
|
85 |
return (lines, "OK("+"k=" + str(k)+")", None) |
|
86 |
|
|
87 |
def compileLustre(lines, temp): |
|
88 |
top = temp + "/top.lus" |
|
89 |
f = open(top, 'w') |
|
90 |
f.write("".join(lines)) |
|
91 |
f.close() |
|
92 |
p = subprocess.Popen(["lustrec", "-d", temp ,"-acsl-proof", top], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
93 |
(stdout, stderr) = p.communicate() |
|
94 |
res = p.wait() |
|
95 |
if res != 0: |
|
96 |
return (None, "ERR_"+str(res), stdout+"\n-------\n"+stderr) |
|
97 |
return (lines, "OK", None) |
|
98 |
|
|
99 |
|
|
100 |
|
|
101 |
def framac(lines, temp): |
|
102 |
FRAMAC=["frama-c", "-wp", "-wp-prover", "CVC4,alt-ergo,z3,coq", temp+"/top.c", "-wp-par", "2", "-wp-rte", "-wp-model", "ref", """-wp-tactic="Require Why3. intros. hnf. repeat split;try why3 \"CVC3\" timelimit 10;try why3 \"Z3\" timelimit 10;why3 \"CVC4\" timelimit 10""", "-wp-script", temp+"/top.coq" "-wp-no-let"] |
|
103 |
p = subprocess.Popen(FRAMAC, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
104 |
(stdout, stderr) = p.communicate() |
|
105 |
res = p.wait() |
|
106 |
if res != 0: |
|
107 |
return (None, "ERR_"+str(res), temp+"\n"+stdout+"\n-------\n"+stderr) |
|
108 |
return (lines, "OK", stdout) |
|
109 |
|
|
110 |
|
|
111 |
def parseFile(inp, out, todo): |
|
112 |
lines = inp.readlines() |
|
113 |
|
|
114 |
temp = tempfile.mkdtemp(prefix="contracts_") |
|
115 |
res = "" |
|
116 |
dats = [] |
|
117 |
for f in todo: |
|
118 |
x = [[]] |
|
119 |
(newlines, r, data) = f(lines[:], temp) |
|
120 |
res += "{:10} ".format(r[:10]) |
|
121 |
if newlines: |
|
122 |
lines = newlines |
|
123 |
if data: |
|
124 |
dats.append(data) |
|
125 |
out.write("".join(lines)) |
|
126 |
shutil.rmtree(temp) |
|
127 |
|
|
128 |
return (res, dats) |
|
129 |
|
|
130 |
TODO=[modProperties, addEnsures, addK, compileLustre] |
|
131 |
|
|
132 |
LENGTH=50 |
|
133 |
|
|
134 |
target="./generated/" |
|
135 |
|
|
136 |
#if os.path.exists(target): |
|
137 |
# shutil.rmtree(target) |
|
138 |
|
|
139 |
orig = "/home/davyg/good" |
|
140 |
for root, dirs, files in os.walk(orig): |
|
141 |
short = root[len(orig):] |
|
142 |
os.mkdir(target+"/"+short) |
|
143 |
for x in files: |
|
144 |
if not x.endswith(".lus"): |
|
145 |
continue |
|
146 |
inp = open(root+"/"+x, "r") |
|
147 |
out = open(target+"/"+short+"/"+x, "w") |
|
148 |
(res, dats) = parseFile(inp, out, TODO) |
|
149 |
inp.close() |
|
150 |
out.close() |
|
151 |
print(("Process {0:"+str(LENGTH)+"} : {1}").format(("./"+short+"/"+x)[:LENGTH], res)) |
|
152 |
if dats: |
|
153 |
print("\n/////////////////////\n".join(dats)) |
|
154 |
sys.stdout.flush() |
Also available in: Unified diff
Add the script used to add k annotation to tests.