main.py
9.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import sys, optparse, os.path, webbrowser
import pdb, traceback
import snakes.plugins
from snakes.utils.abcd.build import Builder
from snakes.lang.abcd.parser import parse
from snakes.lang.pgen import ParseError
from snakes.utils.abcd import CompilationError, DeclarationError
from snakes.utils.abcd.simul import Simulator, ABCDSimulator
from snakes.utils.abcd.checker import Checker
from snakes.utils.abcd.html import build as html
from snakes.utils.simul.html import json
##
## error messages
##
options = None
ERR_ARG = 1
ERR_OPT = 2
ERR_IO = 3
ERR_PARSE = 4
ERR_PLUGIN = 5
ERR_COMPILE = 6
ERR_OUTPUT = 7
ERR_BUG = 255
def log (message) :
sys.stdout.write("abcd: %s\n" % message.strip())
sys.stdout.flush()
def err (message) :
sys.stderr.write("abcd: %s\n" % message.strip())
sys.stderr.flush()
def die (code, message=None) :
global options
if message :
err(message)
if options.debug :
pdb.post_mortem(sys.exc_info()[2])
else :
sys.exit(code)
def bug () :
global options
sys.stderr.write("""
********************************************************************
*** An unexpected error ocurred. Please report this bug to ***
*** <franck.pommereau@gmail.com>, together with the execution ***
*** trace below and, if possible, a stripped-down version of the ***
*** ABCD source code that caused this bug. Thank you for your ***
*** help in improving SNAKES! ***
********************************************************************
""")
traceback.print_exc()
if options.debug :
pdb.post_mortem(sys.exc_info()[2])
else :
sys.exit(ERR_BUG)
##
## options parsing
##
gv_engines = ("dot", "neato", "twopi", "circo", "fdp")
opt = optparse.OptionParser(prog="abcd",
usage="%prog [OPTION]... FILE")
opt.add_option("-l", "--load",
dest="plugins", action="append", default=[],
help="load plugin (this option can be repeated)",
metavar="PLUGIN")
opt.add_option("-p", "--pnml",
dest="pnml", action="store", default=None,
help="save net as PNML",
metavar="OUTFILE")
for engine in gv_engines :
opt.add_option("-" + engine[0], "--" + engine,
dest="gv" + engine, action="store", default=None,
help="draw net using '%s' (from GraphViz)" % engine,
metavar="OUTFILE")
opt.add_option("-a", "--all-names",
dest="allnames", action="store_true", default=False,
help="draw control-flow places names (default: hide)")
opt.add_option("--debug",
dest="debug", action="store_true", default=False,
help="launch debugger on compiler error (default: no)")
opt.add_option("-s", "--simul",
dest="simul", action="store_true", default=False,
help="launch interactive code simulator")
opt.add_option("--headless",
dest="headless", action="store", default=None,
help="headless code simulator, with saved parameters",
metavar="JSONFILE")
opt.add_option("--port",
dest="port", action="store", default=8000, type=int,
help="port on which the simulator server runs",
metavar="PORT")
opt.add_option("-H", "--html",
dest="html", action="store", default=None,
help="save net as HTML",
metavar="OUTFILE")
opt.add_option("--check",
dest="check", action="store_true", default=False,
help="check assertions")
def getopts (args) :
global options, abcd, tmp
(options, args) = opt.parse_args(args)
plugins = []
for p in options.plugins :
plugins.extend(t.strip() for t in p.split(","))
if "ops" not in options.plugins :
plugins.append("ops")
if "labels" not in plugins :
plugins.append("labels")
for engine in gv_engines :
gvopt = getattr(options, "gv%s" % engine)
if gvopt and "gv" not in plugins :
plugins.append("gv")
break
if (options.html or options.simul) and "gv" not in plugins :
plugins.append("gv")
options.plugins = plugins
if len(args) < 1 :
err("no input file provided")
opt.print_help()
die(ERR_ARG)
elif len(args) > 1 :
err("more than one input file provided")
opt.print_help()
die(ERR_ARG)
abcd = args[0]
if options.pnml == abcd :
err("input file also used as output (--pnml)")
opt.print_help()
die(ERR_ARG)
if options.html == abcd :
err("input file also used as output (--html)")
opt.print_help()
die(ERR_ARG)
for engine in gv_engines :
if getattr(options, "gv%s" % engine) == abcd :
err("input file also used as output (--%s)" % engine)
opt.print_help()
die(ERR_ARG)
##
## drawing nets
##
def place_attr (place, attr) :
# fix color
if place.status == snk.entry :
attr["fillcolor"] = "green"
elif place.status == snk.internal :
pass
elif place.status == snk.exit :
attr["fillcolor"] = "orange"
else :
attr["fillcolor"] = "lightblue"
# fix shape
if (not options.allnames
and place.status in (snk.entry, snk.internal, snk.exit)) :
attr["shape"] = "circle"
# render marking
if place._check == snk.tBlackToken :
count = len(place.tokens)
if count == 0 :
marking = " "
elif count == 1 :
marking = "•"
else :
marking = "%s•" % count
else :
marking = str(place.tokens)
# node label
if (options.allnames
or place.status not in (snk.entry, snk.internal, snk.exit)) :
attr["label"] = "%s\\n%s" % (place.name, marking)
else :
attr["label"] = "%s" % marking
def trans_attr (trans, attr) :
pass
def arc_attr (label, attr) :
if label == snk.Value(snk.dot) :
del attr["label"]
elif isinstance(label, snk.Test) :
attr["arrowhead"] = "none"
attr["label"] = " %s " % label._annotation
elif isinstance(label, snk.Flush) :
attr["arrowhead"] = "box"
attr["label"] = " %s " % label._annotation
def draw (net, target, engine="dot") :
try :
return net.draw(target, engine=engine,
place_attr=place_attr,
trans_attr=trans_attr,
arc_attr=arc_attr)
except :
die(ERR_OUTPUT, str(sys.exc_info()[1]))
##
## save pnml
##
def save_pnml (net, target) :
try :
out = open(target, "w")
out.write(snk.dumps(net))
out.close()
except :
die(ERR_OUTPUT, str(sys.exc_info()[1]))
##
## simulator (not standalone)
##
def simulate (source, filename="<string>") :
global options, snk
getopts(["--simul", filename])
node = parse(source, filename=filename)
snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk")
build = Builder(snk)
net = build.build(node)
net.label(srcfile=filename, snakes=snk)
return ABCDSimulator(node, net, draw(net, None))
##
## main
##
def main (args=sys.argv[1:], src=None) :
global options, snk
# get options
try:
if src is None :
getopts(args)
else :
getopts(list(args) + ["<string>"])
except SystemExit :
raise
except :
die(ERR_OPT, str(sys.exc_info()[1]))
# read source
if src is not None :
source = src
else :
try :
source = open(abcd).read()
except :
die(ERR_IO, "could not read input file %r" % abcd)
# parse
try :
node = parse(source, filename=abcd)
except ParseError :
die(ERR_PARSE, str(sys.exc_info()[1]))
except :
bug()
# compile
dirname = os.path.dirname(abcd)
if dirname and dirname not in sys.path :
sys.path.append(dirname)
elif "." not in sys.path :
sys.path.append(".")
try :
snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk")
except :
die(ERR_PLUGIN, str(sys.exc_info()[1]))
build = Builder(snk)
try :
net = build.build(node)
net.label(srcfile=abcd, snakes=snk)
except (CompilationError, DeclarationError) :
die(ERR_COMPILE, str(sys.exc_info()[1]))
except :
bug()
# output
if options.pnml :
save_pnml(net, options.pnml)
for engine in gv_engines :
target = getattr(options, "gv%s" % engine)
if target :
draw(net, target, engine)
if options.html :
try :
html(abcd, node, net, draw(net, None), options.html)
except :
bug()
trace, lineno = [], None
if options.check :
lineno, trace = Checker(net).run()
if options.simul :
engine = "dot"
for eng in gv_engines :
if getattr(options, "gv%s" % eng) :
engine = eng
break
try :
simul = Simulator(node, net, draw(net, None, engine), options.port)
except :
bug()
simul.start()
if options.headless :
with open(options.headless, "w") as out :
out.write(json({"res" : "%sr" % simul.url,
"url" : simul.url,
"key" : simul.server.httpd.key,
"host" : "127.0.0.1",
"port" : simul.port}))
else :
webbrowser.open(simul.url)
simul.wait()
elif trace :
if lineno is None :
print("unsafe execution:")
else :
asserts = dict((a.lineno, a) for a in net.label("asserts"))
print("line %s, %r failed:"
% (lineno, asserts[lineno].st.source()))
for trans, mode in trace :
print(" %s %s" % (trans, mode))
return net
if __name__ == "__main__" :
main()