Example #1
0
 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()
Example #2
0
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)
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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
Example #10
0
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({})
Example #11
0
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
Example #12
0
 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()
Example #13
0
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)
Example #14
0
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)