Franck Pommereau

working ABCD simulator

...@@ -396,7 +396,7 @@ class Net2HTML (object) : ...@@ -396,7 +396,7 @@ class Net2HTML (object) :
396 pos = pos[((20, srow, scol), "instance", TreeInfo(t, name))] 396 pos = pos[((20, srow, scol), "instance", TreeInfo(t, name))]
397 prefix = sum(len(p) for p in path) + len(path) 397 prefix = sum(len(p) for p in path) + len(path)
398 srow, scol, _, _ = node.label("srcloc") 398 srow, scol, _, _ = node.label("srcloc")
399 - pos[((weight, srow, scol), kind, node.name[prefix:])] = tid 399 + pos[((weight, srow, scol), kind, (node, node.name[prefix:]))] = tid
400 def _tree (self, tree, indent="") : 400 def _tree (self, tree, indent="") :
401 yield indent + "<ul>" 401 yield indent + "<ul>"
402 for (_, kind, data), child in sorted(tree.items()) : 402 for (_, kind, data), child in sorted(tree.items()) :
...@@ -406,14 +406,19 @@ class Net2HTML (object) : ...@@ -406,14 +406,19 @@ class Net2HTML (object) :
406 yield item 406 yield item
407 yield indent + "</li>" 407 yield indent + "</li>"
408 else : 408 else :
409 + node, name = data
409 if kind == "buffer" : 410 if kind == "buffer" :
410 content = ("<span class='kw'>buffer</span> " 411 content = ("<span class='kw'>buffer</span> "
411 - "<span class='buffer'>%s</span></li>" % data) 412 + "<span class='name'>%s</span> = "
413 + "<span class='content'>%s</span>"
414 + % (name, node.tokens))
415 + yield indent + "<li>%s%s</span></li>" % (child, content)
412 elif kind == "action" : 416 elif kind == "action" :
413 - content = data 417 + content = name
418 + yield (indent + "<li>%s%s</span><ul class='modes'>"
419 + + "</ul></li>") % (child, content)
414 else : 420 else :
415 raise ValueError("unexpected data %r" % kind) 421 raise ValueError("unexpected data %r" % kind)
416 - yield indent + "<li>%s%s</span></li>" % (child, content)
417 yield indent + "</ul>" 422 yield indent + "</ul>"
418 def html (self) : 423 def html (self) :
419 return template_tree % {"tree" : "\n".join(self._tree(self.tree))} 424 return template_tree % {"tree" : "\n".join(self._tree(self.tree))}
......
1 +/* ABCD source code */
2 +
3 +#model .abcd {
4 + border: solid 1px #DDD;
5 + border-radius: 5px;
6 + padding: 5px 10px;
7 + margin: 5px;
8 + background-color: #F4F4F4;
9 + overflow: auto;
10 + float: left;
11 +}
12 +
13 +#model .abcd .comment {
14 + color: #888;
15 +}
16 +
17 +#model .abcd .ident {
18 + color: #808;
19 +}
20 +
21 +#model .abcd .string {
22 + color: #088;
23 +}
24 +
25 +#model .abcd .kw {
26 + color: #800;
27 + font-weight: bold;
28 +}
29 +
30 +#model .abcd .flow {
31 + color: #800;
32 + font-weight: bold;
33 +}
34 +
35 +#model .abcd .buffer .decl {
36 + color: #080;
37 + font-weight: bold;
38 +}
39 +
40 +#model .abcd .net .decl {
41 + color: #008;
42 + font-weight: bold;
43 +}
44 +
45 +#model .abcd .instance .name {
46 + color: #008;
47 +}
48 +
49 +#model .abcd .action .delim {
50 + font-weight: bold;
51 +}
52 +
53 +#model .abcd .action .name {
54 + color: #080;
55 +}
56 +
57 +#model .abcd .active {
58 + background-color: #B6F8AE;
59 +}
60 +
61 +#model .abcd .highlight {
62 + background-color: yellow;
63 +}
64 +
65 +/* Objects tree */
66 +
67 +#model .tree {
68 + border: solid 1px #DDD;
69 + border-radius: 5px;
70 + padding: 5px 10px;
71 + margin: 5px;
72 + background-color: #F4F4F4;
73 + overflow: auto;
74 + font-family: monospace;
75 + float: left;
76 +}
77 +
78 +#model .tree .buffer .kw {
79 + color: #800;
80 + font-weight: bold;
81 +}
82 +
83 +#model .tree .buffer .name {
84 + color: #080;
85 + font-weight: bold;
86 +}
87 +
88 +#model .tree .ident {
89 + color: #808;
90 +}
91 +
92 +#model .tree .instance .name {
93 + color: #008;
94 +}
95 +
96 +#model .tree .action .delim {
97 + font-weight: bold;
98 +}
99 +
100 +#model .tree .action .name {
101 + color: #080;
102 +}
103 +
104 +#model .tree .string {
105 + color: #088;
106 +}
107 +
108 +#model .tree .modes li {
109 + margin: 12px 0px;
110 +}
111 +
112 +#model .tree .modes a {
113 + background-color: #B6F8AE;
114 + border: solid 1px #AAA;
115 + border-radius: 5px;
116 + padding: 5px 10px;
117 + text-decoration: none;
118 + color: #333;
119 +}
120 +
121 +#model .tree .modes a:hover {
122 + color: #A33;
123 + background-color: #F8B6AE;
124 +}
125 +
126 +#model .tree .active {
127 + background-color: #B6F8AE;
128 +}
129 +
130 +#model .tree .highlight {
131 + background-color: yellow;
132 +}
133 +
134 +/* Petri net picture */
135 +
136 +#model .petrinet {
137 + border: solid 1px #DDD;
138 + border-radius: 5px;
139 + padding: 5px 10px;
140 + margin: 5px;
141 + background-color: #FFF;
142 + overflow: auto;
143 + clear: both;
144 + display: none;
145 +}
146 +
1 +<h1><tt>%(filename)s</tt></h1>
2 +%(abcd)s
3 +%(tree)s
4 +%(net)s
1 +var nodeColor;
2 +
3 +function abcdon () {
4 + obj = $(this);
5 + if (obj.attr("class") == "node") {
6 + node = obj.children().children().first();
7 + nodeColor = node.attr("fill");
8 + node.attr("fill", "yellow");
9 + } else {
10 + obj.addClass("highlight");
11 + }
12 + $(obj.attr("data-abcd")).addClass("highlight");
13 +};
14 +
15 +function abcdoff () {
16 + obj = $(this);
17 + if (obj.attr("class") == "node") {
18 + node = obj.children().children().first();
19 + node.attr("fill", nodeColor);
20 + } else {
21 + obj.removeClass("highlight");
22 + }
23 + $(obj.attr("data-abcd")).removeClass("highlight");
24 +};
25 +
26 +function treeon () {
27 + obj = $(this);
28 + if (obj.attr("class") != "node") {
29 + obj.addClass("highlight");
30 + }
31 + $(obj.attr("data-tree")).addClass("highlight");
32 +};
33 +
34 +function treeoff () {
35 + obj = $(this);
36 + if (obj.attr("class") != "node") {
37 + obj.removeClass("highlight");
38 + }
39 + $(obj.attr("data-tree")).removeClass("highlight");
40 +};
41 +
42 +function neton () {
43 + obj = $(this);
44 + $(obj.attr("data-net")).each(function () {
45 + node = $(this).children().children().first();
46 + nodeColor = node.attr("fill");
47 + node.attr("fill", "yellow");
48 + });
49 + obj.addClass("highlight");
50 +};
51 +
52 +function netoff () {
53 + obj = $(this);
54 + $(obj.attr("data-net")).each(function () {
55 + node = $(this).children().children().first();
56 + node.attr("fill", nodeColor);
57 + });
58 + obj.removeClass("highlight");
59 +};
60 +
61 +$(document).ready(function() {
62 + $("#model [data-abcd]").hover(abcdon, abcdoff);
63 + $("#model [data-tree]").hover(treeon, treeoff);
64 + $("#model [data-net]").hover(neton, netoff);
65 + $(".tree .instance, .tree .action").each(function () {
66 + obj = $(this);
67 + obj.html($(obj.attr("data-abcd")).html());
68 + });
69 +});
1 from snakes.utils.simul import * 1 from snakes.utils.simul import *
2 +import snakes.utils.abcd.html as html
2 3
3 class Simulator (BaseHTTPSimulator) : 4 class Simulator (BaseHTTPSimulator) :
4 def __init__ (self, abcd, node, net, gv) : 5 def __init__ (self, abcd, node, net, gv) :
5 BaseHTTPSimulator.__init__(self, net) 6 BaseHTTPSimulator.__init__(self, net)
6 - self.abcd = abcd 7 + a2html = html.ABCD2HTML(node)
7 - self.node = node 8 + n2html = html.Net2HTML(net, gv, a2html)
8 - self.net = net 9 + self.info = {"filename" : node.st.filename,
9 - self.gv = gv 10 + "abcd" : a2html.html(),
11 + "tree" : n2html.html(),
12 + "net" : n2html.svg()}
13 + self.tree = {}
14 + for node in net.node() :
15 + nid = gv.nodemap[node.name]
16 + if nid in n2html.n2t :
17 + self.tree[node.name] = "#" + n2html.n2t[nid]
18 + self.places = [place.name for place in net.place()
19 + if place.name in self.tree]
20 + self.abcd = {}
21 + self.transid = []
22 + for trans in net.transition() :
23 + nid = gv.nodemap[trans.name]
24 + self.transid.append(self.tree[trans.name])
25 + if nid in n2html.n2a :
26 + self.abcd[trans.name] = ", ".join("#" + i for i in
27 + n2html.n2a[nid])
10 def getstate (self, state) : 28 def getstate (self, state) :
11 marking = self.states[state] 29 marking = self.states[state]
12 - # TODO: build HTML for places and modes, linked to the model 30 + modes = dict((t, []) for t in self.transid)
13 - places = {} 31 + for i, (trans, mode) in enumerate(marking.modes) :
14 - modes = {} 32 + modes[self.tree[trans.name]].append({"state" : state,
33 + "mode" : i,
34 + "html" : str(mode)})
15 return {"id" : state, 35 return {"id" : state,
16 - "states" : places, 36 + "states" :
17 - "modes" : modes} 37 + [{"do" : "dropclass",
38 + "select" : "#model .active",
39 + "class" : "active"}]
40 + + [{"do" : "addclass",
41 + "select" : self.abcd[trans.name],
42 + "class" : "active"} for trans, mode in marking.modes]
43 + + [{"do" : "addclass",
44 + "select" : self.tree[trans.name],
45 + "class" : "active"} for trans, mode in marking.modes]
46 + + [{"do" : "settext",
47 + "select" : "%s .content" % self.tree[place],
48 + "text" : "{}"} for place in self.places
49 + if place not in marking]
50 + + [{"do" : "settext",
51 + "select" : "%s .content" % self.tree[place],
52 + "text" : str(marking[place])} for place in marking
53 + if place in self.tree],
54 + "modes" : [{"select" : "%s + .modes" % trans,
55 + "items" : items}
56 + for trans, items in modes.items()],
57 + }
18 def init_model (self) : 58 def init_model (self) :
19 - # TODO: build HTML for the model 59 + return self.res["model.html"] % self.info
20 - return "<h1><tt>%s</tt></h1>" % self.node.st.filename
21 def init_ui (self) : 60 def init_ui (self) :
22 return BaseHTTPSimulator.init_ui(self)[:-1] 61 return BaseHTTPSimulator.init_ui(self)[:-1]
23 def init_help (self) : 62 def init_help (self) :
24 help = BaseHTTPSimulator.init_help(self) 63 help = BaseHTTPSimulator.init_help(self)
25 help.update({"#model .abcd" : "ABCD source code", 64 help.update({"#model .abcd" : "ABCD source code",
26 "#model .tree" : "hierarchy of ABCD objects", 65 "#model .tree" : "hierarchy of ABCD objects",
27 - "#model .net" : "Petri nets semantics"}) 66 + "#model .petrinet" : "Petri nets semantics"})
28 return help 67 return help
29 68
......
...@@ -73,17 +73,18 @@ class WatchDog (multiprocessing.Process) : ...@@ -73,17 +73,18 @@ class WatchDog (multiprocessing.Process) :
73 shutdown.set() 73 shutdown.set()
74 74
75 class BaseHTTPSimulator (Node) : 75 class BaseHTTPSimulator (Node) :
76 - def __init__ (self, net, port=8000, resources=[]) : 76 + def __init__ (self, net, port=8000, respatt=[], resdict={}) :
77 self.res = {} 77 self.res = {}
78 for cls in reversed(inspect.getmro(self.__class__)[:-2]) : 78 for cls in reversed(inspect.getmro(self.__class__)[:-2]) :
79 path = os.path.dirname(inspect.getsourcefile(cls)) 79 path = os.path.dirname(inspect.getsourcefile(cls))
80 - for pattern in resources + ["resources/*.js", 80 + for pattern in respatt + ["resources/*.js",
81 - "resources/*.css", 81 + "resources/*.css",
82 - "resources/*.html", 82 + "resources/*.html",
83 - "resources/alive.txt"] : 83 + "resources/alive.txt"] :
84 for res in glob.glob(os.path.join(path, pattern)) : 84 for res in glob.glob(os.path.join(path, pattern)) :
85 with open(res) as infile : 85 with open(res) as infile :
86 self.res[os.path.basename(res)] = infile.read() 86 self.res[os.path.basename(res)] = infile.read()
87 + self.res.update(resdict)
87 Node.__init__(self, r=ResourceNode(self.res)) 88 Node.__init__(self, r=ResourceNode(self.res))
88 # create HTTP server 89 # create HTTP server
89 self.port = port 90 self.port = port
...@@ -129,9 +130,11 @@ class BaseHTTPSimulator (Node) : ...@@ -129,9 +130,11 @@ class BaseHTTPSimulator (Node) :
129 H.span(marking(place.name), class_="token")) 130 H.span(marking(place.name), class_="token"))
130 for place in sorted(self.states.net.place(), 131 for place in sorted(self.states.net.place(),
131 key=operator.attrgetter("name"))] 132 key=operator.attrgetter("name"))]
132 - modes = ["%s : %s" % (H.span(trans.name, class_="trans"), 133 + modes = [{"state" : state,
133 - H.span(binding, class_="binding")) 134 + "mode" : i,
134 - for trans, binding in marking.modes] 135 + "html" : "%s : %s" % (H.span(trans.name, class_="trans"),
136 + H.span(binding, class_="binding"))}
137 + for i, (trans, binding) in enumerate(marking.modes)]
135 return {"id" : state, 138 return {"id" : state,
136 "states" : [{"do" : "sethtml", 139 "states" : [{"do" : "sethtml",
137 "select" : "#net", 140 "select" : "#net",
......
...@@ -66,10 +66,15 @@ class Factory (object) : ...@@ -66,10 +66,15 @@ class Factory (object) :
66 66
67 H = Factory() 67 H = Factory()
68 68
69 +def utf8 (text) :
70 + return text.encode("utf-8")
71 +
69 class JSONEncoder(JSON.JSONEncoder): 72 class JSONEncoder(JSON.JSONEncoder):
70 def default(self, obj): 73 def default(self, obj):
71 if isinstance(obj, Tag): 74 if isinstance(obj, Tag):
72 - return str(obj) 75 + return utf8(str(obj))
76 + elif isinstance(obj, (unicode, str)) :
77 + return utf8(obj)
73 else : 78 else :
74 return JSON.JSONEncoder.default(self, obj) 79 return JSON.JSONEncoder.default(self, obj)
75 80
......
1 import sys, os.path, httplib, cgi, urlparse, functools, mimetypes 1 import sys, os.path, httplib, cgi, urlparse, functools, mimetypes
2 import os, signal, traceback, random, base64, inspect 2 import os, signal, traceback, random, base64, inspect
3 import BaseHTTPServer 3 import BaseHTTPServer
4 -from snakes.utils.simul.html import json 4 +from snakes.utils.simul.html import json, utf8
5 5
6 ## 6 ##
7 ## 7 ##
...@@ -25,8 +25,8 @@ class HTTPError (Exception) : ...@@ -25,8 +25,8 @@ class HTTPError (Exception) :
25 ## 25 ##
26 26
27 encoders = {"application/json" : json, 27 encoders = {"application/json" : json,
28 - "text/plain" : str, 28 + "text/plain" : utf8,
29 - "text/html" : str, 29 + "text/html" : utf8,
30 } 30 }
31 31
32 def http (content_type=None, **types) : 32 def http (content_type=None, **types) :
......
1 <html> 1 <html>
2 <head> 2 <head>
3 + <!-- global information -->
3 <script type="text/javascript"> 4 <script type="text/javascript">
4 var server = {key : "%(key)s", 5 var server = {key : "%(key)s",
5 url : "%(url)s", 6 url : "%(url)s",
6 host : "%(host)s", 7 host : "%(host)s",
7 port : "%(port)s"}; 8 port : "%(port)s"};
8 </script> 9 </script>
10 + <!-- simulator -->
11 + <link type="text/css" href="r/simulator.css" rel="stylesheet"/>
9 <script type="text/javascript" src="r/jquery.min.js"></script> 12 <script type="text/javascript" src="r/jquery.min.js"></script>
10 <script type="text/javascript" src="r/jquery.periodic.js"></script> 13 <script type="text/javascript" src="r/jquery.periodic.js"></script>
11 <script type="text/javascript" src="r/simulator.js"></script> 14 <script type="text/javascript" src="r/simulator.js"></script>
12 - <link type="text/css" href="r/simulator.css" rel="stylesheet"/> 15 + <!-- user definable elements -->
13 <link type="text/css" href="r/model.css" rel="stylesheet"/> 16 <link type="text/css" href="r/model.css" rel="stylesheet"/>
17 + <script type="text/javascript" src="r/model.js"></script>
14 <link type="text/css" href="r/trace.css" rel="stylesheet"/> 18 <link type="text/css" href="r/trace.css" rel="stylesheet"/>
19 + <script type="text/javascript" src="r/trace.js"></script>
15 <link type="text/css" href="r/about.css" rel="stylesheet"/> 20 <link type="text/css" href="r/about.css" rel="stylesheet"/>
21 + <script type="text/javascript" src="r/about.js"></script>
16 </head> 22 </head>
17 <body> 23 <body>
24 + <!-- control bar -->
18 <div id="alive"> 25 <div id="alive">
26 + <!-- buttons -->
19 <ul class="ui"> 27 <ul class="ui">
20 <li><a id="ui-reset" href="#">Reset simulation</a></li> 28 <li><a id="ui-reset" href="#">Reset simulation</a></li>
21 <li><a id="ui-quit" href="#">Stop server</a></li> 29 <li><a id="ui-quit" href="#">Stop server</a></li>
22 <li><a id="ui-help" href="#">Help</a></li> 30 <li><a id="ui-help" href="#">Help</a></li>
23 <li><a id="ui-about" href="#">About</a></li> 31 <li><a id="ui-about" href="#">About</a></li>
24 </ul> 32 </ul>
33 + <!-- server pings -->
25 <span class="ping">Starting...</span> 34 <span class="ping">Starting...</span>
26 </div> 35 </div>
36 + <!-- model to be simulated -->
27 <div id="model">%(model)s</div> 37 <div id="model">%(model)s</div>
38 + <!-- exploration trace -->
28 <div id="trace"></div> 39 <div id="trace"></div>
40 + <!-- information about the simulator -->
29 <div id="about">%(about)s</div> 41 <div id="about">%(about)s</div>
30 </body> 42 </body>
31 </html> 43 </html>
......
...@@ -33,10 +33,17 @@ var update = { ...@@ -33,10 +33,17 @@ var update = {
33 $.each(action.items, function (num, item) { 33 $.each(action.items, function (num, item) {
34 ul.append("<li>" + item + "</li>"); 34 ul.append("<li>" + item + "</li>");
35 }); 35 });
36 - } 36 + },
37 + dropclass : function (action) {
38 + $(action.select).removeClass(action.class);
39 + },
40 + addclass : function (action) {
41 + $(action.select).addClass(action.class);
42 + },
37 } 43 }
38 44
39 function setstate (state) { 45 function setstate (state) {
46 + $("#trace").append("<div class='state'>" + state.id + "</div>");
40 $.each(state.states, function (num, item) { 47 $.each(state.states, function (num, item) {
41 update[item.do](item); 48 update[item.do](item);
42 }); 49 });
...@@ -44,16 +51,16 @@ function setstate (state) { ...@@ -44,16 +51,16 @@ function setstate (state) {
44 ul = $(action.select); 51 ul = $(action.select);
45 ul.html(""); 52 ul.html("");
46 $.each(action.items, function (pos, item) { 53 $.each(action.items, function (pos, item) {
47 - ul.append("<li><a href='#' data-mode='" + state.id + ":" 54 + ul.append("<li><a href='#'>" + item.html + "</a></li>");
48 - + pos + "''>" + item + "</a></li>"); 55 +
49 a = ul.children().last().children().first(); 56 a = ul.children().last().children().first();
57 + a.attr({"data-state" : item.state, "data-mode" : item.mode});
50 a.click(function () { 58 a.click(function () {
51 - next = $(this).attr("data-mode").split(":"); 59 + state = $(this).attr("data-state");
52 - text = $(this).text(); 60 + mode = $(this).attr("data-mode");
53 - $("#trace").append("<div class='trace'><div class='state'>" 61 + content = $(this).html();
54 - + state.id + "</div><div class='mode'>" 62 + $("#trace").append("<div class='mode'>" + content + "</div></div>");
55 - + text + "</div></div>"); 63 + $.get("succ", {state: state, mode: mode},
56 - $.get("succ", {state: next[0], mode: next[1]},
57 function (newstate) { 64 function (newstate) {
58 setstate(newstate); 65 setstate(newstate);
59 }); 66 });
...@@ -126,4 +133,4 @@ $(document).ready(function() { ...@@ -126,4 +133,4 @@ $(document).ready(function() {
126 /* setup initial state */ 133 /* setup initial state */
127 setstate(init.state); 134 setstate(init.state);
128 }); 135 });
129 -});
...\ No newline at end of file ...\ No newline at end of file
136 +});
......