def __init__(self, snk, path=[], up=None): self.snk = snk self.path = path self.up = up self.env = { "True": Decl(None, kind=Decl.CONST, value=True), "False": Decl(None, kind=Decl.CONST, value=False), "None": Decl(None, kind=Decl.CONST, value=None), "dot": Decl(None, kind=Decl.CONST, value=self.snk.dot), "BlackToken": Decl(None, kind=Decl.TYPE, type=self.snk.Instance(self.snk.BlackToken)) } self.stack = [] if up: self.globals = up.globals else: self.globals = snk.Evaluator(dot=self.snk.dot, BlackToken=self.snk.BlackToken) self.instances = MultiSet()
def fire(n, state, tname, s): set_state(n, state) waiting = state.waiting.copy() process = state.process.copy() t = n.transition(tname) if t.enabled(s): token = token_in_process(s) wt = wait_time(n, token, tname) if wt == 0: # fire immediately prev_tokens = {} for p in t.output(): prev_tokens.update({p[0].name: p[0].tokens.copy()}) t.fire(s) # <--- transition fires for p in t.output(): received = p[0].tokens - prev_tokens[p[0].name] if p[0].tokens - prev_tokens[p[0].name] != {}: # this is a process place, init process # TO DO: enable multiple tokens in output places token = received.items()[0] wt = wait_time(n, token, p[0].name) p[0].remove(received.items()[0]) p[0].wait = wt p[0].add('processing') process.update( {p[0].name: { 'wait': p[0].wait, 'token': token }}) else: #start wait time and reserve tokens t.wait = wt removeTokens = {} reserveTokens = {} for item in s.items(): for inputPlace in t.input(): if item[1] in inputPlace[0]: removeTokens.update( {inputPlace[0].name: MultiSet([item[1]])}) for outputPlace in t.output(): reserveTokens.update( {outputPlace[0].name: MultiSet(['reserved'])}) remove = Marking(removeTokens) reserve = Marking(reserveTokens) waiting.update({ t.name: { 'wait': t.wait, 'removed': remove, 'reserved': reserve, 's': s } }) n.set_marking(state.marking - remove + reserve) return NetState(n.get_marking(), waiting, process)
def filterByValue(m, v): """ Given a MultiSets `m` of key-value pairs (e.g., {('t0', 'p1') * 2, ('t0', 'p2')}) and a value `v` (e.g., 'p1'), it returns a multiset containing the pairs with the given value `v`. e.g., filterByValue({('t0', 'p1'), ('t0', 'p2')}, 'p1') = {('t0', 'p1') * 2}""" result = MultiSet([]) for pair in m: if pair[1] == v: result.add([pair]) return result
def filterByKey(m, k): """ Given a MultiSets `m` of key-value pairs (e.g., {('t1', 'p1') * 2, ('t0', 'p2')}) and a key `k` (e.g., 't0'), it returns a multiset containing the pairs with the given key `k`. e.g., filterByKey({('t0', 'p1'), ('t0', 'p2')}, 't0') = {('t0', 'p2')}""" result = MultiSet([]) for pair in m: if pair[0] == k: result.add([pair]) return result
def keys(m, v): """ Given a MultiSet `m` of key-value pairs (e.g., {('t0', 'p1'), ('t0', 'p2')}) and a value `v` (e.g., 'p1'), it returns a multiset containing the keys associated with the value `v`. e.g., pre_pl({('t0', 'p1'), ('t0', 'p2')}, 'p1') = {'t0'}""" result = MultiSet([]) for pair in m: if pair[1] == v: result.add(pair[0]) return result
def values(m, k): """ Given a MultiSet `m` of key-value pairs (e.g., {('t0', 'p1'), ('t0', 'p2')}) and an key `k` (e.g., 't0'), it returns a multiset containing the values associated with the key `k`. e.g., pre_tr({('t0', 'p1'), ('t0', 'p2')}, 't0') = {'p1', 'p2'}""" result = MultiSet([]) for pair in m: if pair[0] == k: result.add(pair[1]) return result
def projection(m1, m2): """ Given two MultiSets `m1`, `m2` (e.g., {'p0', 'p1'}, {'p0' * 2}), it returns a projection of `m1` containing only the elements appearing in `m2`. e.g., projection({'p0', 'p1'}, {'p0' * 2}) = {'p0'}""" #print('projection( ' + str(m1) + ', ' + str(m2) + ' )') result = MultiSet([]) for e in m1: if m2(e) > 0: result.add([e]) #print(' result = ' + str(result)) return result
def value(m, key): """ Given a MultiSet `m` of (key, value) pairs (e.g., {('t0', 'p0'), ('t0', 'p1')}), it returns a MultiSet of the values associated with the given `key`. e.g., value({('t0', 'p0') * 2, ('t0', 'p1')}, 't0') = {'p0' * 2, 'p1'}""" #print('value( ' + str(m) + ', ' + str(key) + ' )') result = MultiSet([]) for pair in m: if pair[0] == key: result = result + MultiSet([pair[1]]) #print(' result = ' + str(result)) return result
def intersection(m1, m2): """ Given two MultiSets `m1`, `m2` (e.g., {'p0' * 2, 'p1', 'p2'}, {'p0', 'p2'}), it returns the intersection. e.g., intersection({'p0' *2, 'p1', 'p2'}, {'p0', 'p2'}) = {'p0', 'p2'}""" result = MultiSet([]) for e in set(m1): n1 = m1(e) n2 = m2(e) if n1 > 0 and n2 > 0: mult = n1 if n2 < n1: mult = n2 result.add([e] * mult) return result
def reserveTokens(n, t, s): #returns markings needed to reserve and remove tokens if t.activated(s): removeTokens = {} reserveTokens = {} for item in s.items(): for inputPlace in t.input(): if item[1] in inputPlace[0]: removeTokens.update( {inputPlace[0].name: MultiSet([item[1]])}) for outputPlace in t.output(): reserveTokens.update({outputPlace[0].name: MultiSet(['reserved'])}) return Marking(removeTokens), Marking(reserveTokens) else: return Marking({}), Marking({})
def full_marking(s): m = s.marking r = Marking({}) w = [] for key in s.waiting.keys(): for place in s.waiting[key]['removed'].keys(): m = m + Marking( {place + str('_r'): s.waiting[key]['removed'][place]}) for key in s.process.keys(): w.append({key + '_r': MultiSet(s.process[key]['token'])}) for i in w: r = r + Marking(i) return m + r
def __init__ (self, snk, path=[], up=None) : self.snk = snk self.path = path self.up = up self.env = {"True": Decl(None, kind=Decl.CONST, value=True), "False": Decl(None, kind=Decl.CONST, value=False), "None": Decl(None, kind=Decl.CONST, value=None), "dot": Decl(None, kind=Decl.CONST, value=self.snk.dot), "BlackToken": Decl(None, kind=Decl.TYPE, type=self.snk.Instance(self.snk.BlackToken))} self.stack = [] if up : self.globals = up.globals else : self.globals = snk.Evaluator(dot=self.snk.dot, BlackToken=self.snk.BlackToken) self.instances = MultiSet()
class Builder (object) : def __init__ (self, snk, path=[], up=None) : self.snk = snk self.path = path self.up = up self.env = {"True": Decl(None, kind=Decl.CONST, value=True), "False": Decl(None, kind=Decl.CONST, value=False), "None": Decl(None, kind=Decl.CONST, value=None), "dot": Decl(None, kind=Decl.CONST, value=self.snk.dot), "BlackToken": Decl(None, kind=Decl.TYPE, type=self.snk.Instance(self.snk.BlackToken))} self.stack = [] if up : self.globals = up.globals else : self.globals = snk.Evaluator(dot=self.snk.dot, BlackToken=self.snk.BlackToken) self.instances = MultiSet() # utilities def _raise (self, error, message) : """raise an exception with appropriate location """ if self.stack : pos = "[%s:%s]: " % (self.stack[-1].lineno, self.stack[-1].col_offset) else : pos = "" raise error(pos+message) def _eval (self, expr, *largs, **kwargs) : env = self.globals.copy() if isinstance(expr, ast.AST) : expr = unparse(expr) return env(expr, dict(*largs, **kwargs)) # declarations management def __setitem__ (self, name, value) : if name in self.env : self._raise(DeclarationError, "duplicated declaration of %r" % name) self.env[name] = value def __getitem__ (self, name) : if name in self.env : return self.env[name] elif self.up is None : self._raise(DeclarationError, "%r not declared" % name) else : return self.up[name] def __contains__ (self, name) : if name in self.env : return True elif self.up is None : return False else : return name in self.up def goto (self, name) : if name in self.env : return self elif self.up is None : self._raise(DeclarationError, "%r not declared" % name) else : return self.up.goto(name) def get_buffer (self, name) : if name not in self : self._raise(DeclarationError, "buffer %r not declared" % name) decl = self[name] if decl.kind != Decl.BUFFER : self._raise(DeclarationError, "%r declared as %s but used as buffer" % (name, decl.kind)) elif decl.capacity is not None : pass #self._raise(NotImplementedError, "capacities not (yet) supported") return decl def get_net (self, name) : if name not in self : self._raise(DeclarationError, "net %r not declared" % name) decl = self[name] if decl.kind != Decl.NET : self._raise(DeclarationError, "%r declared as %s but used as net" % (name, decl.kind)) return decl def get_task (self, name) : if name not in self : self._raise(DeclarationError, "task %r not declared" % name) decl = self[name] if decl.kind != Decl.TASK : self._raise(DeclarationError, "%r declared as %s but used as task" % (name, decl.kind)) return decl # main compiler entry point def build (self, node, prefix="", fallback=None) : self.stack.append(node) if prefix : prefix += "_" method = "build_" + prefix + node.__class__.__name__ visitor = getattr(self, method, fallback or self.build_fail) try : return visitor(node) finally : self.stack.pop(-1) def build_fail (self, node) : self._raise(CompilationError, "do not know how to compile %s" % node.__class__.__name__) def build_arc (self, node) : return self.build(node, "arc", self.build_arc_expr) # specification def build_AbcdSpec (self, node) : for decl in node.context : self.build(decl) tasks = [self._build_TaskNet(decl.node) for name, decl in self.env.items() if decl.kind == Decl.TASK and decl.used] net = reduce(operator.or_, tasks, self.build(node.body)) # set local buffers marking, and hide them for name, decl in ((n, d) for n, d in self.env.items() if d.kind == Decl.BUFFER) : status = self.snk.buffer(name) for place in net.status(status) : place = net.place(place) try : place.reset(decl.marking) except ValueError as err : self._raise(CompilationError, "invalid initial marking (%s)" % err) if decl.capacity is None : cap = None else : #cap = [c.n if c else None for c in decl.capacity] # TODO: accept more than integers as capacities cap = [] for c in decl.capacity : if c is None : cap.append(None) else : try : cap.append(self._eval(c)) except : err = sys.exc_info()[1] self._raise(CompilationError, "could not evaluate %r, %s" % (unparse(c), err)) place.label(path=self.path, capacity=cap) # TODO: check capacity net.hide(status) if self.up is None : # set entry marking for place in net.status(self.snk.entry) : net.place(place).reset(self.snk.dot) # rename nodes self._rename_nodes(net) # copy global declarations net.globals.update(self.globals) # add info about source file net.label(srcfile=str(node.st.text.filename)) # add assertions net.label(asserts=node.asserts) return net def _build_TaskNet (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") def _rename_nodes (self, net) : # generate unique names total = collections.defaultdict(int) count = collections.defaultdict(int) def ren (node) : if net.has_transition(node.name) : status = node.label("srctext") else : if node.status == self.snk.entry : status = "e" elif node.status == self.snk.internal : status = "i" elif node.status == self.snk.exit : status = "x" else : status = node.label("buffer") name = ".".join(node.label("path") + [status]) if total[name] > 1 : count[name] += 1 name = "%s#%s" % (name, count[name]) return name # count occurrences of each name base _total = collections.defaultdict(int) for node in net.node() : _total[ren(node)] += 1 total = _total # rename nodes using a depth-first traversal done = set(net.status(self.snk.entry)) todo = [net.node(n) for n in done] while todo : node = todo.pop(-1) new = ren(node) if new != node.name : net.rename_node(node.name, new) done.add(new) for n in net.post(new) - done : todo.append(net.node(n)) done.add(n) # rename isolated nodes for letter, method in (("p", net.place), ("t", net.transition)) : for node in method() : if node.name not in done : net.rename_node(node.name, ren(node)) # declarations def build_AbcdTypedef (self, node) : """ >>> import snakes.nets >>> b = Builder(snakes.nets) >>> b.build(ast.AbcdTypedef(name='number', type=ast.UnionType(types=[ast.NamedType(name='int'), ast.NamedType(name='float')]))) >>> b.env['number'].type (Instance(int) | Instance(float)) >>> b.build(ast.ImportFrom(module='inspect', names=[ast.alias(name='isbuiltin')])) >>> b.build(ast.AbcdTypedef(name='builtin', type=ast.NamedType(name='isbuiltin'))) >>> b.env['builtin'].type TypeCheck(inspect.isbuiltin) """ self[node.name] = Decl(node, type=self.build(node.type)) def build_AbcdBuffer (self, node) : self[node.name] = Decl(node, type=self.build(node.type), capacity=node.capacity, marking=self._eval(node.content)) def build_AbcdSymbol (self, node) : for name in node.symbols : value = self.snk.Symbol(name, False) self[name] = Decl(node, value=value) self.globals[name] = value def build_AbcdConst (self, node) : value = self._eval(node.value) self[node.name] = Decl(node, value=value) self.globals[node.name] = value def build_AbcdNet (self, node) : self[node.name] = Decl(node, getargs=GetInstanceArgs(node)) def build_AbcdTask (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") self[node.name] = Decl(node, used=False) def build_Import (self, node) : for alias in node.names : self[alias.asname or alias.name] = Decl(node) self.globals.declare(unparse(node)) def build_ImportFrom (self, node) : self.build_Import(node) # processes def build_AbcdAction (self, node) : if node.guard is True : return self._build_True(node) elif node.guard is False : return self._build_False(node) else : return self._build_action(node) def _build_True (self, node) : net = self.snk.PetriNet("true") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) t = self.snk.Transition("t") t.label(srctext=node.st.source(), srcloc=(node.st.srow, node.st.scol, node.st.erow, node.st.ecol), path=self.path) net.add_transition(t) net.add_input("e", "t", self.snk.Value(self.snk.dot)) net.add_output("x", "t", self.snk.Value(self.snk.dot)) return net def _build_False (self, node) : net = self.snk.PetriNet("false") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) return net def _build_action (self, node) : net = self.snk.PetriNet("flow") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) t = self.snk.Transition("t", self.snk.Expression(unparse(node.guard)), status=self.snk.tick("action")) t.label(srctext=node.st.source(), srcloc=(node.st.srow, node.st.scol, node.st.erow, node.st.ecol), path=self.path) net.add_transition(t) net.add_input("e", "t", self.snk.Value(self.snk.dot)) net.add_output("x", "t", self.snk.Value(self.snk.dot)) net = reduce(operator.or_, [self.build(a) for a in node.accesses], net) net.hide(self.snk.tick("action")) return net def build_AbcdFlowOp (self, node) : return self.build(node.op)(self.build(node.left), self.build(node.right)) def _get_instance_arg (self, arg) : if arg.__class__.__name__ == "Name" and arg.id in self : return self[arg.id] else : try : self._eval(arg) except : self._raise(CompilationError, "could not evaluate argument %r" % arg.st.source()) return arg def build_AbcdInstance (self, node) : if node.net not in self : self._raise(DeclarationError, "%r not declared" % node.net) elif node.starargs : self._raise(CompilationError, "* argument not allowed here") elif node.kwargs : self._raise(CompilationError, "** argument not allowed here") decl = self[node.net] if decl.kind != Decl.NET : self._raise(DeclarationError, "%r declared as %s but used as net" % (name, decl.kind)) # unpack args posargs, kwargs = [], {} for arg in node.args : posargs.append(self._get_instance_arg(arg)) for kw in node.keywords : kwargs[kw.arg] = self._get_instance_arg(kw.value) # bind args try : args, buffers, nets, tasks = decl.getargs(*posargs, **kwargs) except TypeError : c, v, t = sys.exc_info() self._raise(CompilationError, str(v)) for d, kind in ((buffers, Decl.BUFFER), (nets, Decl.NET), (tasks, Decl.TASK)) : for k, v in d.items() : if v.kind != kind : self._raise(DeclarationError, "%r declared as %s but used as %s" % (k, v.kind, kind)) d[k] = v.node.name # build sub-net binder = transform.ArgsBinder(args, buffers, nets, tasks) spec = binder.visit(decl.node.body) if node.asname : name = str(node.asname) else : name = node.st.source() if name in self.instances : name = "%s#%s" % (name, self.instances(name)) self.instances.add(name) path = self.path + [name] builder = self.__class__(self.snk, path, self) net = builder.build(spec) src = (node.st.source(), node.st.srow, node.st.scol, node.st.erow, node.st.ecol) for trans in net.transition() : try : lbl = trans.label("instances") trans.label(instances=[src] + lbl) except KeyError : trans.label(instances=[src]) for place in net.place() : if place.status == self.snk.Status(None) : try : lbl = place.label("instances") place.label(instances=[src] + lbl) except KeyError : place.label(instances=[src]) return net # control flow operations def build_Sequence (self, node) : return self.snk.PetriNet.__and__ def build_Choice (self, node) : return self.snk.PetriNet.__add__ def build_Parallel (self, node) : return self.snk.PetriNet.__or__ def build_Loop (self, node) : return self.snk.PetriNet.__mul__ # accesses : def build_SimpleAccess (self, node) : decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition(self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(str(node.buffer), [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) self.build(node.arc)(net, node.buffer, "t", self.build_arc(node.tokens)) return net def build_FlushAccess (self, node) : decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition(self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(str(node.buffer), [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) net.add_input(node.buffer, "t", self.snk.Flush(node.target)) return net def build_SwapAccess (self, node) : decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition(self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(node.buffer, [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) net.add_input(node.buffer, "t", self.build_arc(node.target)) net.add_output(node.buffer, "t", self.build_arc(node.tokens)) return net def build_Spawn (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") def build_Wait (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") def build_Suspend (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") def build_Resume (self, node) : self._raise(NotImplementedError, "tasks not (yet) supported") # arc labels def build_arc_Name (self, node) : if node.id in self : decl = self[node.id] if decl.kind in (Decl.CONST, Decl.SYMBOL) : return self.snk.Value(decl.value) return self.snk.Variable(node.id) def build_arc_Num (self, node) : return self.snk.Value(node.n) def build_arc_Str (self, node) : return self.snk.Value(node.s) def build_arc_Tuple (self, node) : return self.snk.Tuple([self.build_arc(elt) for elt in node.elts]) def build_arc_expr (self, node) : return self.snk.Expression(unparse(node)) # arcs def build_Produce (self, node) : def arc (net, place, trans, label) : net.add_output(place, trans, label) return arc def build_Test (self, node) : def arc (net, place, trans, label) : net.add_input(place, trans, self.snk.Test(label)) return arc def build_Consume (self, node) : def arc (net, place, trans, label) : net.add_input(place, trans, label) return arc def build_Fill (self, node) : def arc (net, place, trans, label) : net.add_output(place, trans, self.snk.Flush(str(label))) return arc # types def build_UnionType (self, node) : return reduce(operator.or_, (self.build(child) for child in node.types)) def build_IntersectionType (self, node) : return reduce(operator.and_, (self.build(child) for child in node.types)) def build_CrossType (self, node) : return self.snk.CrossProduct(*(self.build(child) for child in node.types)) def build_ListType (self, node) : return self.snk.List(self.build(node.items)) def build_TupleType (self, node) : return self.snk.Collection(self.snk.Instance(tuple), (self.build(node.items))) def build_SetType (self, node) : return self.snk.Set(self.build(node.items)) def build_DictType (self, node) : return self.snk.Mapping(keys=self.build(node.keys), items=self.build(node.items), _dict=self.snk.Instance(self.snk.hdict)) def build_EnumType (self, node) : return self.snk.OneOf(*(self._eval(child) for child in node.items)) def build_NamedType (self, node) : name = node.name if name in self and self[name].kind == Decl.TYPE : return self[name].type elif name in self.globals : obj = self.globals[name] if inspect.isclass(obj) : return self.snk.Instance(obj) elif inspect.isroutine(obj) : return self.snk.TypeCheck(obj) elif hasattr(sys.modules["__builtin__"], name) : obj = getattr(sys.modules["__builtin__"], name) if inspect.isclass(obj) : return self.snk.Instance(obj) elif inspect.isroutine(obj) : return self.snk.TypeCheck(obj) self._raise(CompilationError, "invalid type %r" % name)
class Builder(object): def __init__(self, snk, path=[], up=None): self.snk = snk self.path = path self.up = up self.env = { "True": Decl(None, kind=Decl.CONST, value=True), "False": Decl(None, kind=Decl.CONST, value=False), "None": Decl(None, kind=Decl.CONST, value=None), "dot": Decl(None, kind=Decl.CONST, value=self.snk.dot), "BlackToken": Decl(None, kind=Decl.TYPE, type=self.snk.Instance(self.snk.BlackToken)) } self.stack = [] if up: self.globals = up.globals else: self.globals = snk.Evaluator(dot=self.snk.dot, BlackToken=self.snk.BlackToken) self.instances = MultiSet() # utilities def _raise(self, error, message): """raise an exception with appropriate location """ if self.stack: try: pos = "[%s:%s]: " % (self.stack[-1].lineno, self.stack[-1].col_offset) except: pos = "" else: pos = "" raise error(pos + message) def _eval(self, expr, *largs, **kwargs): env = self.globals.copy() if isinstance(expr, ast.AST): expr = unparse(expr) return env(expr, dict(*largs, **kwargs)) # declarations management def __setitem__(self, name, value): if name in self.env: self._raise(DeclarationError, "duplicated declaration of %r" % name) self.env[name] = value def __getitem__(self, name): if name in self.env: return self.env[name] elif self.up is None: self._raise(DeclarationError, "%r not declared" % name) else: return self.up[name] def __contains__(self, name): if name in self.env: return True elif self.up is None: return False else: return name in self.up def goto(self, name): if name in self.env: return self elif self.up is None: self._raise(DeclarationError, "%r not declared" % name) else: return self.up.goto(name) def get_buffer(self, name): if name not in self: self._raise(DeclarationError, "buffer %r not declared" % name) decl = self[name] if decl.kind != Decl.BUFFER: self._raise( DeclarationError, "%r declared as %s but used as buffer" % (name, decl.kind)) elif decl.capacity is not None: pass #self._raise(NotImplementedError, "capacities not (yet) supported") return decl def get_net(self, name): if name not in self: self._raise(DeclarationError, "net %r not declared" % name) decl = self[name] if decl.kind != Decl.NET: self._raise( DeclarationError, "%r declared as %s but used as net" % (name, decl.kind)) return decl def get_task(self, name): if name not in self: self._raise(DeclarationError, "task %r not declared" % name) decl = self[name] if decl.kind != Decl.TASK: self._raise( DeclarationError, "%r declared as %s but used as task" % (name, decl.kind)) return decl # main compiler entry point def build(self, node, prefix="", fallback=None): self.stack.append(node) if prefix: prefix += "_" method = "build_" + prefix + node.__class__.__name__ visitor = getattr(self, method, fallback or self.build_fail) try: return visitor(node) finally: self.stack.pop(-1) def build_fail(self, node): self._raise(CompilationError, "do not know how to compile %s" % node.__class__.__name__) def build_arc(self, node): return self.build(node, "arc", self.build_arc_expr) # specification def build_AbcdSpec(self, node): for decl in node.context: self.build(decl) tasks = [ self._build_TaskNet(decl.node) for name, decl in self.env.items() if decl.kind == Decl.TASK and decl.used ] net = reduce(operator.or_, tasks, self.build(node.body)) # set local buffers marking, and hide them for name, decl in ((n, d) for n, d in self.env.items() if d.kind == Decl.BUFFER): status = self.snk.buffer(name) for place in net.status(status): place = net.place(place) try: place.reset(decl.marking) except ValueError as err: self._raise(CompilationError, "invalid initial marking (%s)" % err) if decl.capacity is None: cap = None else: #cap = [c.n if c else None for c in decl.capacity] # TODO: accept more than integers as capacities cap = [] for c in decl.capacity: if c is None: cap.append(None) else: try: cap.append(self._eval(c)) except: err = sys.exc_info()[1] self._raise( CompilationError, "could not evaluate %r, %s" % (unparse(c), err)) place.label(path=self.path, capacity=cap) # TODO: check capacity net.hide(status) if self.up is None: # set entry marking for place in net.status(self.snk.entry): net.place(place).reset(self.snk.dot) # rename nodes self._rename_nodes(net) # copy global declarations net.globals.update(self.globals) # add info about source file net.label(srcfile=str(node.st.text.filename)) # add assertions net.label(asserts=node.asserts) return net def _build_TaskNet(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") def _rename_nodes(self, net): # generate unique names total = collections.defaultdict(int) count = collections.defaultdict(int) def ren(node): if net.has_transition(node.name): status = node.label("srctext") else: if node.status == self.snk.entry: status = "e" elif node.status == self.snk.internal: status = "i" elif node.status == self.snk.exit: status = "x" else: status = node.label("buffer") name = ".".join(node.label("path") + [status]) if total[name] > 1: count[name] += 1 name = "%s#%s" % (name, count[name]) return name # count occurrences of each name base _total = collections.defaultdict(int) for node in net.node(): _total[ren(node)] += 1 total = _total # rename nodes using a depth-first traversal done = set(net.status(self.snk.entry)) todo = [net.node(n) for n in done] while todo: node = todo.pop(-1) new = ren(node) if new != node.name: net.rename_node(node.name, new) done.add(new) for n in net.post(new) - done: todo.append(net.node(n)) done.add(n) # rename isolated nodes for letter, method in (("p", net.place), ("t", net.transition)): for node in method(): if node.name not in done: net.rename_node(node.name, ren(node)) # declarations def build_AbcdTypedef(self, node): """ >>> import snakes.nets >>> b = Builder(snakes.nets) >>> b.build(ast.AbcdTypedef(name='number', type=ast.UnionType(types=[ast.NamedType(name='int'), ast.NamedType(name='float')]))) >>> b.env['number'].type (Instance(int) | Instance(float)) >>> b.build(ast.ImportFrom(module='inspect', names=[ast.alias(name='isbuiltin')])) >>> b.build(ast.AbcdTypedef(name='builtin', type=ast.NamedType(name='isbuiltin'))) >>> b.env['builtin'].type TypeCheck(inspect.isbuiltin) """ self[node.name] = Decl(node, type=self.build(node.type)) def build_AbcdBuffer(self, node): self[node.name] = Decl(node, type=self.build(node.type), capacity=node.capacity, marking=self._eval(node.content)) def build_AbcdSymbol(self, node): for name in node.symbols: value = self.snk.Symbol(name, False) self[name] = Decl(node, value=value) self.globals[name] = value def build_AbcdConst(self, node): value = self._eval(node.value) self[node.name] = Decl(node, value=value) self.globals[node.name] = value def build_AbcdNet(self, node): self[node.name] = Decl(node, getargs=GetInstanceArgs(node)) def build_AbcdTask(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") self[node.name] = Decl(node, used=False) def build_Import(self, node): for alias in node.names: self[alias.asname or alias.name] = Decl(node) self.globals.declare(unparse(node)) def build_ImportFrom(self, node): self.build_Import(node) # processes def build_AbcdAction(self, node): if node.guard is True: return self._build_True(node) elif node.guard is False: return self._build_False(node) else: return self._build_action(node) def _build_True(self, node): net = self.snk.PetriNet("true") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) t = self.snk.Transition("t") t.label(srctext=node.st.source(), srcloc=(node.st.srow, node.st.scol, node.st.erow, node.st.ecol), path=self.path) net.add_transition(t) net.add_input("e", "t", self.snk.Value(self.snk.dot)) net.add_output("x", "t", self.snk.Value(self.snk.dot)) return net def _build_False(self, node): net = self.snk.PetriNet("false") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) return net def _build_action(self, node): net = self.snk.PetriNet("flow") e = self.snk.Place("e", [], self.snk.tBlackToken, status=self.snk.entry) e.label(path=self.path) net.add_place(e) x = self.snk.Place("x", [], self.snk.tBlackToken, status=self.snk.exit) x.label(path=self.path) net.add_place(x) t = self.snk.Transition("t", self.snk.Expression(unparse(node.guard)), status=self.snk.tick("action")) t.label(srctext=node.st.source(), srcloc=(node.st.srow, node.st.scol, node.st.erow, node.st.ecol), path=self.path) net.add_transition(t) net.add_input("e", "t", self.snk.Value(self.snk.dot)) net.add_output("x", "t", self.snk.Value(self.snk.dot)) net = reduce(operator.or_, [self.build(a) for a in node.accesses], net) net.hide(self.snk.tick("action")) return net def build_AbcdFlowOp(self, node): return self.build(node.op)(self.build(node.left), self.build(node.right)) def _get_instance_arg(self, arg): if arg.__class__.__name__ == "Name" and arg.id in self: return self[arg.id] else: try: self._eval(arg) except: self._raise(CompilationError, "could not evaluate argument %r" % arg.st.source()) return arg def build_AbcdInstance(self, node): if node.net not in self: self._raise(DeclarationError, "%r not declared" % node.net) elif node.starargs: self._raise(CompilationError, "* argument not allowed here") elif node.kwargs: self._raise(CompilationError, "** argument not allowed here") decl = self[node.net] if decl.kind != Decl.NET: self._raise( DeclarationError, "%r declared as %s but used as net" % (name, decl.kind)) # unpack args posargs, kwargs = [], {} for arg in node.args: posargs.append(self._get_instance_arg(arg)) for kw in node.keywords: kwargs[kw.arg] = self._get_instance_arg(kw.value) # bind args try: args, buffers, nets, tasks = decl.getargs(*posargs, **kwargs) except TypeError: c, v, t = sys.exc_info() self._raise(CompilationError, str(v)) for d, kind in ((buffers, Decl.BUFFER), (nets, Decl.NET), (tasks, Decl.TASK)): for k, v in d.items(): if v.kind != kind: self._raise( DeclarationError, "%r declared as %s but used as %s" % (k, v.kind, kind)) d[k] = v.node.name # build sub-net binder = transform.ArgsBinder(args, buffers, nets, tasks) spec = binder.visit(decl.node.body) if node.asname: name = str(node.asname) else: name = node.st.source() if name in self.instances: name = "%s#%s" % (name, self.instances(name)) self.instances.add(name) path = self.path + [name] builder = self.__class__(self.snk, path, self) net = builder.build(spec) src = (node.st.source(), node.st.srow, node.st.scol, node.st.erow, node.st.ecol) for trans in net.transition(): try: lbl = trans.label("instances") trans.label(instances=[src] + lbl) except KeyError: trans.label(instances=[src]) for place in net.place(): if place.status == self.snk.Status(None): try: lbl = place.label("instances") place.label(instances=[src] + lbl) except KeyError: place.label(instances=[src]) return net # control flow operations def build_Sequence(self, node): return self.snk.PetriNet.__and__ def build_Choice(self, node): return self.snk.PetriNet.__add__ def build_Parallel(self, node): return self.snk.PetriNet.__or__ def build_Loop(self, node): return self.snk.PetriNet.__mul__ # accesses : def build_SimpleAccess(self, node): decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition( self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(str(node.buffer), [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) self.build(node.arc)(net, node.buffer, "t", self.build_arc(node.tokens)) return net def build_FlushAccess(self, node): decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition( self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(str(node.buffer), [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) net.add_input(node.buffer, "t", self.snk.Flush(node.target)) return net def build_SwapAccess(self, node): decl = self.get_buffer(node.buffer) net = self.snk.PetriNet("access") net.add_transition( self.snk.Transition("t", status=self.snk.tick("action"))) b = self.snk.Place(node.buffer, [], decl.type, status=self.snk.buffer(node.buffer)) b.label(path=self.path, buffer=str(node.buffer), srctext=decl.node.st.source(), srcloc=(decl.node.st.srow, decl.node.st.scol, decl.node.st.erow, decl.node.st.ecol)) net.add_place(b) net.add_input(node.buffer, "t", self.build_arc(node.target)) net.add_output(node.buffer, "t", self.build_arc(node.tokens)) return net def build_Spawn(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") def build_Wait(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") def build_Suspend(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") def build_Resume(self, node): self._raise(NotImplementedError, "tasks not (yet) supported") # arc labels def build_arc_Name(self, node): if node.id in self: decl = self[node.id] if decl.kind in (Decl.CONST, Decl.SYMBOL): return self.snk.Value(decl.value) return self.snk.Variable(node.id) def build_arc_Num(self, node): return self.snk.Value(node.n) def build_arc_Str(self, node): return self.snk.Value(node.s) def build_arc_Tuple(self, node): return self.snk.Tuple([self.build_arc(elt) for elt in node.elts]) def build_arc_expr(self, node): return self.snk.Expression(unparse(node)) # arcs def build_Produce(self, node): def arc(net, place, trans, label): net.add_output(place, trans, label) return arc def build_Test(self, node): def arc(net, place, trans, label): net.add_input(place, trans, self.snk.Test(label)) return arc def build_Consume(self, node): def arc(net, place, trans, label): net.add_input(place, trans, label) return arc def build_Fill(self, node): def arc(net, place, trans, label): net.add_output(place, trans, self.snk.Flush(str(label))) return arc # types def build_UnionType(self, node): return reduce(operator.or_, (self.build(child) for child in node.types)) def build_IntersectionType(self, node): return reduce(operator.and_, (self.build(child) for child in node.types)) def build_CrossType(self, node): return self.snk.CrossProduct(*(self.build(child) for child in node.types)) def build_ListType(self, node): return self.snk.List(self.build(node.items)) def build_TupleType(self, node): return self.snk.Collection(self.snk.Instance(tuple), (self.build(node.items))) def build_SetType(self, node): return self.snk.Set(self.build(node.items)) def build_DictType(self, node): return self.snk.Mapping(keys=self.build(node.keys), items=self.build(node.items), _dict=self.snk.Instance(self.snk.hdict)) def build_EnumType(self, node): return self.snk.OneOf(*(self._eval(child) for child in node.items)) def build_NamedType(self, node): name = node.name if name in self and self[name].kind == Decl.TYPE: return self[name].type elif name in self.globals: obj = self.globals[name] if inspect.isclass(obj): return self.snk.Instance(obj) elif inspect.isroutine(obj): return self.snk.TypeCheck(obj) elif hasattr(sys.modules["__builtin__"], name): obj = getattr(sys.modules["__builtin__"], name) if inspect.isclass(obj): return self.snk.Instance(obj) elif inspect.isroutine(obj): return self.snk.TypeCheck(obj) self._raise(CompilationError, "invalid type %r" % name)