Franck Pommereau

working ABCD simulator

......@@ -396,7 +396,7 @@ class Net2HTML (object) :
pos = pos[((20, srow, scol), "instance", TreeInfo(t, name))]
prefix = sum(len(p) for p in path) + len(path)
srow, scol, _, _ = node.label("srcloc")
pos[((weight, srow, scol), kind, node.name[prefix:])] = tid
pos[((weight, srow, scol), kind, (node, node.name[prefix:]))] = tid
def _tree (self, tree, indent="") :
yield indent + "<ul>"
for (_, kind, data), child in sorted(tree.items()) :
......@@ -406,14 +406,19 @@ class Net2HTML (object) :
yield item
yield indent + "</li>"
else :
node, name = data
if kind == "buffer" :
content = ("<span class='kw'>buffer</span> "
"<span class='buffer'>%s</span></li>" % data)
"<span class='name'>%s</span> = "
"<span class='content'>%s</span>"
% (name, node.tokens))
yield indent + "<li>%s%s</span></li>" % (child, content)
elif kind == "action" :
content = data
content = name
yield (indent + "<li>%s%s</span><ul class='modes'>"
+ "</ul></li>") % (child, content)
else :
raise ValueError("unexpected data %r" % kind)
yield indent + "<li>%s%s</span></li>" % (child, content)
yield indent + "</ul>"
def html (self) :
return template_tree % {"tree" : "\n".join(self._tree(self.tree))}
......
/* ABCD source code */
#model .abcd {
border: solid 1px #DDD;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #F4F4F4;
overflow: auto;
float: left;
}
#model .abcd .comment {
color: #888;
}
#model .abcd .ident {
color: #808;
}
#model .abcd .string {
color: #088;
}
#model .abcd .kw {
color: #800;
font-weight: bold;
}
#model .abcd .flow {
color: #800;
font-weight: bold;
}
#model .abcd .buffer .decl {
color: #080;
font-weight: bold;
}
#model .abcd .net .decl {
color: #008;
font-weight: bold;
}
#model .abcd .instance .name {
color: #008;
}
#model .abcd .action .delim {
font-weight: bold;
}
#model .abcd .action .name {
color: #080;
}
#model .abcd .active {
background-color: #B6F8AE;
}
#model .abcd .highlight {
background-color: yellow;
}
/* Objects tree */
#model .tree {
border: solid 1px #DDD;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #F4F4F4;
overflow: auto;
font-family: monospace;
float: left;
}
#model .tree .buffer .kw {
color: #800;
font-weight: bold;
}
#model .tree .buffer .name {
color: #080;
font-weight: bold;
}
#model .tree .ident {
color: #808;
}
#model .tree .instance .name {
color: #008;
}
#model .tree .action .delim {
font-weight: bold;
}
#model .tree .action .name {
color: #080;
}
#model .tree .string {
color: #088;
}
#model .tree .modes li {
margin: 12px 0px;
}
#model .tree .modes a {
background-color: #B6F8AE;
border: solid 1px #AAA;
border-radius: 5px;
padding: 5px 10px;
text-decoration: none;
color: #333;
}
#model .tree .modes a:hover {
color: #A33;
background-color: #F8B6AE;
}
#model .tree .active {
background-color: #B6F8AE;
}
#model .tree .highlight {
background-color: yellow;
}
/* Petri net picture */
#model .petrinet {
border: solid 1px #DDD;
border-radius: 5px;
padding: 5px 10px;
margin: 5px;
background-color: #FFF;
overflow: auto;
clear: both;
display: none;
}
<h1><tt>%(filename)s</tt></h1>
%(abcd)s
%(tree)s
%(net)s
var nodeColor;
function abcdon () {
obj = $(this);
if (obj.attr("class") == "node") {
node = obj.children().children().first();
nodeColor = node.attr("fill");
node.attr("fill", "yellow");
} else {
obj.addClass("highlight");
}
$(obj.attr("data-abcd")).addClass("highlight");
};
function abcdoff () {
obj = $(this);
if (obj.attr("class") == "node") {
node = obj.children().children().first();
node.attr("fill", nodeColor);
} else {
obj.removeClass("highlight");
}
$(obj.attr("data-abcd")).removeClass("highlight");
};
function treeon () {
obj = $(this);
if (obj.attr("class") != "node") {
obj.addClass("highlight");
}
$(obj.attr("data-tree")).addClass("highlight");
};
function treeoff () {
obj = $(this);
if (obj.attr("class") != "node") {
obj.removeClass("highlight");
}
$(obj.attr("data-tree")).removeClass("highlight");
};
function neton () {
obj = $(this);
$(obj.attr("data-net")).each(function () {
node = $(this).children().children().first();
nodeColor = node.attr("fill");
node.attr("fill", "yellow");
});
obj.addClass("highlight");
};
function netoff () {
obj = $(this);
$(obj.attr("data-net")).each(function () {
node = $(this).children().children().first();
node.attr("fill", nodeColor);
});
obj.removeClass("highlight");
};
$(document).ready(function() {
$("#model [data-abcd]").hover(abcdon, abcdoff);
$("#model [data-tree]").hover(treeon, treeoff);
$("#model [data-net]").hover(neton, netoff);
$(".tree .instance, .tree .action").each(function () {
obj = $(this);
obj.html($(obj.attr("data-abcd")).html());
});
});
from snakes.utils.simul import *
import snakes.utils.abcd.html as html
class Simulator (BaseHTTPSimulator) :
def __init__ (self, abcd, node, net, gv) :
BaseHTTPSimulator.__init__(self, net)
self.abcd = abcd
self.node = node
self.net = net
self.gv = gv
a2html = html.ABCD2HTML(node)
n2html = html.Net2HTML(net, gv, a2html)
self.info = {"filename" : node.st.filename,
"abcd" : a2html.html(),
"tree" : n2html.html(),
"net" : n2html.svg()}
self.tree = {}
for node in net.node() :
nid = gv.nodemap[node.name]
if nid in n2html.n2t :
self.tree[node.name] = "#" + n2html.n2t[nid]
self.places = [place.name for place in net.place()
if place.name in self.tree]
self.abcd = {}
self.transid = []
for trans in net.transition() :
nid = gv.nodemap[trans.name]
self.transid.append(self.tree[trans.name])
if nid in n2html.n2a :
self.abcd[trans.name] = ", ".join("#" + i for i in
n2html.n2a[nid])
def getstate (self, state) :
marking = self.states[state]
# TODO: build HTML for places and modes, linked to the model
places = {}
modes = {}
modes = dict((t, []) for t in self.transid)
for i, (trans, mode) in enumerate(marking.modes) :
modes[self.tree[trans.name]].append({"state" : state,
"mode" : i,
"html" : str(mode)})
return {"id" : state,
"states" : places,
"modes" : modes}
"states" :
[{"do" : "dropclass",
"select" : "#model .active",
"class" : "active"}]
+ [{"do" : "addclass",
"select" : self.abcd[trans.name],
"class" : "active"} for trans, mode in marking.modes]
+ [{"do" : "addclass",
"select" : self.tree[trans.name],
"class" : "active"} for trans, mode in marking.modes]
+ [{"do" : "settext",
"select" : "%s .content" % self.tree[place],
"text" : "{}"} for place in self.places
if place not in marking]
+ [{"do" : "settext",
"select" : "%s .content" % self.tree[place],
"text" : str(marking[place])} for place in marking
if place in self.tree],
"modes" : [{"select" : "%s + .modes" % trans,
"items" : items}
for trans, items in modes.items()],
}
def init_model (self) :
# TODO: build HTML for the model
return "<h1><tt>%s</tt></h1>" % self.node.st.filename
return self.res["model.html"] % self.info
def init_ui (self) :
return BaseHTTPSimulator.init_ui(self)[:-1]
def init_help (self) :
help = BaseHTTPSimulator.init_help(self)
help.update({"#model .abcd" : "ABCD source code",
"#model .tree" : "hierarchy of ABCD objects",
"#model .net" : "Petri nets semantics"})
"#model .petrinet" : "Petri nets semantics"})
return help
......
......@@ -73,17 +73,18 @@ class WatchDog (multiprocessing.Process) :
shutdown.set()
class BaseHTTPSimulator (Node) :
def __init__ (self, net, port=8000, resources=[]) :
def __init__ (self, net, port=8000, respatt=[], resdict={}) :
self.res = {}
for cls in reversed(inspect.getmro(self.__class__)[:-2]) :
path = os.path.dirname(inspect.getsourcefile(cls))
for pattern in resources + ["resources/*.js",
"resources/*.css",
"resources/*.html",
"resources/alive.txt"] :
for pattern in respatt + ["resources/*.js",
"resources/*.css",
"resources/*.html",
"resources/alive.txt"] :
for res in glob.glob(os.path.join(path, pattern)) :
with open(res) as infile :
self.res[os.path.basename(res)] = infile.read()
self.res.update(resdict)
Node.__init__(self, r=ResourceNode(self.res))
# create HTTP server
self.port = port
......@@ -129,9 +130,11 @@ class BaseHTTPSimulator (Node) :
H.span(marking(place.name), class_="token"))
for place in sorted(self.states.net.place(),
key=operator.attrgetter("name"))]
modes = ["%s : %s" % (H.span(trans.name, class_="trans"),
H.span(binding, class_="binding"))
for trans, binding in marking.modes]
modes = [{"state" : state,
"mode" : i,
"html" : "%s : %s" % (H.span(trans.name, class_="trans"),
H.span(binding, class_="binding"))}
for i, (trans, binding) in enumerate(marking.modes)]
return {"id" : state,
"states" : [{"do" : "sethtml",
"select" : "#net",
......
......@@ -66,10 +66,15 @@ class Factory (object) :
H = Factory()
def utf8 (text) :
return text.encode("utf-8")
class JSONEncoder(JSON.JSONEncoder):
def default(self, obj):
if isinstance(obj, Tag):
return str(obj)
return utf8(str(obj))
elif isinstance(obj, (unicode, str)) :
return utf8(obj)
else :
return JSON.JSONEncoder.default(self, obj)
......
import sys, os.path, httplib, cgi, urlparse, functools, mimetypes
import os, signal, traceback, random, base64, inspect
import BaseHTTPServer
from snakes.utils.simul.html import json
from snakes.utils.simul.html import json, utf8
##
##
......@@ -25,8 +25,8 @@ class HTTPError (Exception) :
##
encoders = {"application/json" : json,
"text/plain" : str,
"text/html" : str,
"text/plain" : utf8,
"text/html" : utf8,
}
def http (content_type=None, **types) :
......
<html>
<head>
<!-- global information -->
<script type="text/javascript">
var server = {key : "%(key)s",
url : "%(url)s",
host : "%(host)s",
port : "%(port)s"};
</script>
<!-- simulator -->
<link type="text/css" href="r/simulator.css" rel="stylesheet"/>
<script type="text/javascript" src="r/jquery.min.js"></script>
<script type="text/javascript" src="r/jquery.periodic.js"></script>
<script type="text/javascript" src="r/simulator.js"></script>
<link type="text/css" href="r/simulator.css" rel="stylesheet"/>
<!-- user definable elements -->
<link type="text/css" href="r/model.css" rel="stylesheet"/>
<script type="text/javascript" src="r/model.js"></script>
<link type="text/css" href="r/trace.css" rel="stylesheet"/>
<script type="text/javascript" src="r/trace.js"></script>
<link type="text/css" href="r/about.css" rel="stylesheet"/>
<script type="text/javascript" src="r/about.js"></script>
</head>
<body>
<!-- control bar -->
<div id="alive">
<!-- buttons -->
<ul class="ui">
<li><a id="ui-reset" href="#">Reset simulation</a></li>
<li><a id="ui-quit" href="#">Stop server</a></li>
<li><a id="ui-help" href="#">Help</a></li>
<li><a id="ui-about" href="#">About</a></li>
</ul>
<!-- server pings -->
<span class="ping">Starting...</span>
</div>
<!-- model to be simulated -->
<div id="model">%(model)s</div>
<!-- exploration trace -->
<div id="trace"></div>
<!-- information about the simulator -->
<div id="about">%(about)s</div>
</body>
</html>
......
......@@ -33,10 +33,17 @@ var update = {
$.each(action.items, function (num, item) {
ul.append("<li>" + item + "</li>");
});
}
},
dropclass : function (action) {
$(action.select).removeClass(action.class);
},
addclass : function (action) {
$(action.select).addClass(action.class);
},
}
function setstate (state) {
$("#trace").append("<div class='state'>" + state.id + "</div>");
$.each(state.states, function (num, item) {
update[item.do](item);
});
......@@ -44,16 +51,16 @@ function setstate (state) {
ul = $(action.select);
ul.html("");
$.each(action.items, function (pos, item) {
ul.append("<li><a href='#' data-mode='" + state.id + ":"
+ pos + "''>" + item + "</a></li>");
ul.append("<li><a href='#'>" + item.html + "</a></li>");
a = ul.children().last().children().first();
a.attr({"data-state" : item.state, "data-mode" : item.mode});
a.click(function () {
next = $(this).attr("data-mode").split(":");
text = $(this).text();
$("#trace").append("<div class='trace'><div class='state'>"
+ state.id + "</div><div class='mode'>"
+ text + "</div></div>");
$.get("succ", {state: next[0], mode: next[1]},
state = $(this).attr("data-state");
mode = $(this).attr("data-mode");
content = $(this).html();
$("#trace").append("<div class='mode'>" + content + "</div></div>");
$.get("succ", {state: state, mode: mode},
function (newstate) {
setstate(newstate);
});
......@@ -126,4 +133,4 @@ $(document).ready(function() {
/* setup initial state */
setstate(init.state);
});
});
\ No newline at end of file
});
......