main.py
6.87 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
import sys, optparse, os.path, webbrowser
import pdb, traceback
import snakes.plugins
from snakes.utils.andy import CompilationError, DeclarationError
from snakes.utils.andy.simul import Simulator, AndySimulator
from snakes.utils.andy.andy import andy2snakes
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("andy: %s\n" % message.strip())
sys.stdout.flush()
def err (message) :
sys.stderr.write("andy: %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="andy",
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("--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")
def getopts (args) :
global options, andy, tmp
(options, args) = opt.parse_args(args)
plugins = []
for p in options.plugins :
plugins.extend(t.strip() for t in p.split(","))
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.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)
andy = args[0]
if options.pnml == andy :
err("input file also used as output (--pnml)")
opt.print_help()
die(ERR_ARG)
for engine in gv_engines :
if getattr(options, "gv%s" % engine) == andy :
err("input file also used as output (--%s)" % engine)
opt.print_help()
die(ERR_ARG)
##
## drawing nets
##
def draw (net, target, engine="dot") :
try :
return net.draw(target, engine=engine)
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 (entities, potential, obligatory, filename='<string>') :
global options, snk
getopts(["--simul", filename])
snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk")
net = andy2snakes(snk, entities, potential, obligatory)
net.label(srcfile=filename, snakes=snk)
return AndySimulator(net)
##
## main
##
def main (args=sys.argv[1:]) :
global options, snk
# get options
try:
getopts(args)
except SystemExit :
raise
except :
die(ERR_OPT, str(sys.exc_info()[1]))
# read andy spec
try:
env = {}
execfile(andy, env)
del env['__builtins__']
except:
die(ERR_IO, "could not read input file %r" % andy)
# compile to net
dirname = os.path.dirname(andy)
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]))
try:
net = andy2snakes(snk, env['entities'], env['potential'],
env['obligatory'])
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)
trace, lineno = [], None
if options.simul :
try :
simul = Simulator(net, 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()