Showing
102 changed files
with
4479 additions
and
0 deletions
.hgignore
0 → 100644
BUGS
0 → 100644
1 | +abcd crash on [foo>>(s), foo<<(s+s)] | ||
2 | +[foo(x,y,z)] creates a multi-arc instead of a tuple | ||
3 | + | ||
4 | +abcd substitues for loops variables: | ||
5 | +net Foo (x) : | ||
6 | + buffer b : int = [x for x in range(4)] | ||
7 | + ^ ^ | ||
8 | + substituted (should not) | ||
9 | + | ||
10 | +errors during expressions evaluation are directly sent to user, should be wrapper to indicate this is a model error. And should be catched in abcd --simul/check |
MANIFEST.in
0 → 100644
Makefile
0 → 100644
1 | +all: | ||
2 | + @echo "Commands:" | ||
3 | + @echo " release prepare source for release" | ||
4 | + @echo " tgz build a source tarball" | ||
5 | + @echo " doc build API documentation" | ||
6 | + @echo " dput build and upload Ubuntu packages" | ||
7 | + @echo " clean delete some garbage files" | ||
8 | + @echo " test run tests through supported Python implementations" | ||
9 | + @echo " next-deb increments debian/VERSION" | ||
10 | + @echo " next-ppa increments debian/PPA" | ||
11 | + @echo " lang build generated files in snakes/lang" | ||
12 | + @echo " emacs compile Emacs files" | ||
13 | + | ||
14 | +committed: | ||
15 | + hg summary|grep -q '^commit: (clean)$$' | ||
16 | + | ||
17 | +next-deb: | ||
18 | + echo 1 > debian/PPA | ||
19 | + echo $$((1+$$(cat debian/VERSION))) > debian/VERSION | ||
20 | + | ||
21 | +emacs: | ||
22 | + emacs -batch -f batch-byte-compile utils/abcd-mode.el | ||
23 | + | ||
24 | +next-ppa: | ||
25 | + echo $$((1+$$(cat debian/PPA))) > debian/PPA | ||
26 | + | ||
27 | +release: committed test doc tgz | ||
28 | + hg tag version-$$(cat VERSION) | ||
29 | + echo 1 > debian/PPA | ||
30 | + echo 1 > debian/VERSION | ||
31 | + hg commit -m "version $$(cat VERSION)" | ||
32 | + hg push | ||
33 | + | ||
34 | +lang: | ||
35 | + python mklang.py | ||
36 | + | ||
37 | +tgz: committed | ||
38 | + hg archive snakes-$$(cat VERSION)-$$(cat debian/VERSION) | ||
39 | + cd snakes-$$(cat VERSION)-$$(cat debian/VERSION) && make doc | ||
40 | + tar cf snakes-$$(cat VERSION)-$$(cat debian/VERSION).tar snakes-$$(cat VERSION)-$$(cat debian/VERSION) | ||
41 | + rm -rf snakes-$$(cat VERSION)-$$(cat debian/VERSION) | ||
42 | + gzip -9 snakes-$$(cat VERSION)-$$(cat debian/VERSION).tar | ||
43 | + gpg --armor --sign --detach-sig snakes-$$(cat VERSION)-$$(cat debian/VERSION).tar.gz | ||
44 | + | ||
45 | +doc: snakes/*.py snakes/plugins/*.py snakes/utils/*.py snakes/lang/*.py | ||
46 | + make -C doc | ||
47 | + | ||
48 | +dput.sh: VERSION debian/* | ||
49 | + python mkdeb.py | ||
50 | + | ||
51 | +dput: committed dput.sh | ||
52 | + sh dput.sh | ||
53 | + | ||
54 | +clean: | ||
55 | + rm -f $$(find . -name ",*") | ||
56 | + rm -f $$(find . -name "*.pyc") | ||
57 | + rm -f $$(find . -name "*~") | ||
58 | + rm -f $$(find . -name "*.class") | ||
59 | + rm -rf $$(find . -type d -name __pycache__) | ||
60 | + | ||
61 | +test: | ||
62 | + python2.5 test.py | ||
63 | + python2.6 test.py | ||
64 | + python2.7 test.py | ||
65 | + python3 test.py | ||
66 | + unladen test.py | ||
67 | + pypy test.py | ||
68 | + spypy test.py | ||
69 | + stackless test.py | ||
70 | + jython test.py |
NEWS
0 → 100644
1 | + + emacs mode for ABCD | ||
2 | + ! fixex nodes merge in plugin labels | ||
3 | + ! fixed nets.MultiArc.flow (thanks to Jan Ciger's report) | ||
4 | + | ||
5 | +version 0.9.13 (Fri Jul 16 17:01:22 CEST 2010): | ||
6 | + + added inhibitor arcs | ||
7 | + + added Ubuntu Lucid (10.04) package | ||
8 | + ! fixed data.WordSet.fresh when base is used | ||
9 | + ! fixed reduce(xor, []) is some __hash__ methods | ||
10 | + + added PetriNet.layout method in snakes.plugins.gv | ||
11 | + | ||
12 | +version 0.9.12 (Thu Apr 1 19:42:33 CEST 2010): | ||
13 | + + removed PyGraphviz dependency (layout method supressed temporarily) | ||
14 | + + now compatible with PyPy (1.2), Unladen-Swallow and Jython (2.5.1) | ||
15 | + ! fixed snakes.plugins.clusters.rename_node | ||
16 | + ! fixed snakes.nets.Flush.flow | ||
17 | + ! fixed an uncaught exception in snakes.data.MultiSet.__eq__ | ||
18 | + and snakes.data.Symbol.__eq__ | ||
19 | + ! hopefully fixed LALR built in ABCD compiler | ||
20 | + ! fixed hash-related issues | ||
21 | + * moved PLY stuff to snakes.utils.abcd | ||
22 | + * snakes.compyler has been completely replaced (PLY dependency removed) | ||
23 | + | ||
24 | +version 0.9.11 (Thu Mar 25 19:32:31 CET 2010): | ||
25 | + ! fixed various doctests | ||
26 | + ! fixed issues with attributes locking | ||
27 | + ! fixed issues related to missing __hash__ methods | ||
28 | + ! fixed renaming a node to itself in ABCD | ||
29 | + + added snakes.nets.Evaluator.__contains__ | ||
30 | + + added base argument to snakes.data.WordSet | ||
31 | + + added option --symbols to ABCD compiler | ||
32 | + + added snakes.data.Symbol | ||
33 | + + added net instances naming in ABCD | ||
34 | + + added logo | ||
35 | + + added let function to update bindings from expressions | ||
36 | + + added snakes.data.Subtitution.__setitem__ | ||
37 | + | ||
38 | +version 0.9.10 (Fri Jun 19 13:32:45 CEST 2009): | ||
39 | + ! fixed inconstent hashing on clusters | ||
40 | + ! fixed mutability of hashed multisets | ||
41 | + ! fixed snakes.nets.Tuple.mode | ||
42 | + | ||
43 | +version 0.9.9 (Tue, 19 May 2009 15:00:00 +0100): | ||
44 | + + added mkdeb.py to build deb packages for multiple distributions | ||
45 | + + ported to Python 2.6 | ||
46 | + | ||
47 | +version 0.9.8 (lun, 23 mar 2009 17:30:34 (CET)): | ||
48 | + + added graph_attr option to snakes.plugins.gv.StateGraph | ||
49 | + * plugin gv now draws partially constructed marking graphs | ||
50 | + ! fixed expression compilation in present of net parameters in ABCD | ||
51 | + compiler | ||
52 | + ! fixed flush arcs binding | ||
53 | + * plugin lashdata has been removed because its too experimental | ||
54 | + * merged plugin decorators into a single one | ||
55 | + | ||
56 | +version 0.9.7 (Tue, 20 Jan 2009 13:04:15 +0100): | ||
57 | + ! fixed sharing of globals between net components | ||
58 | + ! fixed loading of PNML when some plugins fail to load | ||
59 | + + added cpp option to abcd | ||
60 | + + added some docstrings and doctests | ||
61 | + ! fixed sharing of globals between net components | ||
62 | + | ||
63 | +version 0.9.6 (Fri, 28 Nov 2008 15:22:27 +0100): | ||
64 | + + added doc for ABCD | ||
65 | + ! fixed False and True handling in ABCD compiler | ||
66 | + + added cross product types to ABCD | ||
67 | + | ||
68 | +version 0.9.5 (Wed, 19 Nov 2008 21:42:05 +0100): | ||
69 | + + added distutils setup.py | ||
70 | + * strip PNML data before decoding (work around invalid XML) | ||
71 | + ! fixed Multiset.__pnmlload__ on iterable values | ||
72 | + | ||
73 | +version 0.9.4 (mar, 28 oct 2008 12:28:02 (UTC+0100)): | ||
74 | + ! fixed nets.Value.__eq__, __ne__ and __hash__ | ||
75 | + ! fixed nets.Token.__repr__ | ||
76 | + + added Flush arcs | ||
77 | + ! fixed nets.Tuple.bind | ||
78 | + ! fixed PNML dump/load of subclasses | ||
79 | + ! fixed nets.PetriNet.merge_* in the presence of Tuple arcs | ||
80 | + ! fixed plugins.clusters.Cluster.path | ||
81 | + ! fixed plugins.status.PetriNet.__pnmlload__ | ||
82 | + ! fixed ABCD lexer | ||
83 | + + improved ABCD compiler with parametric nets, Python declarations | ||
84 | + ! fixed black token values in ABCD arcs and flush | ||
85 | + + ABCD compiler launches pdb.post_mortem when an error occurs in | ||
86 | + + added TCP mode to query plugin debug mode | ||
87 | + * removed dependency to epydoc in snakes.typing | ||
88 | + + updated PNML doc | ||
89 | + + added a producer/consumer ABCD example | ||
90 | + | ||
91 | +version 0.9.3 (lun, 29 sep 2008 08:04:55 (CEST)): | ||
92 | + ! fixed a bug in place pnml loading | ||
93 | + ! fixed wrong association of pnml tags to classes | ||
94 | + + improved query and associated programs, added documentation | ||
95 | + * improved loading of PNML files with plugins | ||
96 | + * PNML tag <snakes> can only occur once as a child of <pnml> | ||
97 | + + abcd compiler adds many structural information to PNML (including | ||
98 | + + test.py checks is snakes.version is correct AST if asked) | ||
99 | + + query plugins now has two verbosity levels | ||
100 | + + added snakes.compyler.Tree.__pnmldump__() | ||
101 | + | ||
102 | +version 0.9.2 | ||
103 | + + added query plugin and demon client/server programs | ||
104 | + ! various small bugs fixed | ||
105 | + + improved PNML serialisation of standard objects | ||
106 | + + snakes.plugins.load puts new module in caller's environment | ||
107 | + ! fixed snakes.pnml.Tree.update | ||
108 | + * Substitution.image() returns a set | ||
109 | + + added apix.py | ||
110 | + ! PNML export empty arcs fixed | ||
111 | + ! fixed broken abcd.py | ||
112 | + * updated abcd.py so it uses gv | ||
113 | + * improved clustering efficiency | ||
114 | + | ||
115 | +version 0.9.1 | ||
116 | + + added plugin gv to replace graphviz | ||
117 | + + added plugin clusters to manage clusters of nodes | ||
118 | + + updated plugins ops so it builds clusters | ||
119 | + * the plugin posops is deprecated since gv does the work much better | ||
120 | + | ||
121 | +version 0.9 | ||
122 | + * dropped compatibilty with Python 2.4 | ||
123 | + + finished pnml | ||
124 | + * the compyler module has been completely replaced | ||
125 | + | ||
126 | +Changes in 0.8.4 (06.09.2007 11:30:21): | ||
127 | + + updated the tutorial | ||
128 | + | ||
129 | +Changes in 0.8.3 (29.06.2007 11:57:39): | ||
130 | + + snakes.plugins.graphivz: added options to control the layout | ||
131 | + + snakes.plugins.graphviz: improved the rendering | ||
132 | + + updated the tutorial | ||
133 | + | ||
134 | +Changes in 0.8.2 (22.06.2007 13:09:02): | ||
135 | + + snakes.plugins.ops: added a name hiding operator (PetriNet.__div__) | ||
136 | + ! fixed several copy/clone problems | ||
137 | + | ||
138 | +Changes in 0.8.1 (20.06.2007 10:18:17): | ||
139 | + * updated tutorial | ||
140 | + + snakes.plugins.pos: the position of a node can be redefined when | ||
141 | + ! snakes.plugins.pos: accept float positions when loading from pnml | ||
142 | + | ||
143 | +Changes in 0.8 (19.06.2007 17:19:19): First public release. |
README
0 → 100644
1 | +SNAKES is the Net Algebra Kit for Editors and Simulators | ||
2 | +======================================================== | ||
3 | + | ||
4 | +//////////////////////////////////////////////////////////////// | ||
5 | +This file is formatted in order to be processed by AsciiDoc | ||
6 | +(http://www.methods.co.nz/asciidoc). It will be more comfortable | ||
7 | +to render it or to read the HTML version available at: | ||
8 | +http://www.univ-paris12.fr/pommereau/soft/snakes/index.html | ||
9 | +//////////////////////////////////////////////////////////////// | ||
10 | + | ||
11 | +SNAKES is a Python library that provides all then necessary to define | ||
12 | +and execute many sorts of Petri nets, in particular those of the PBC | ||
13 | +and M-nets family. Its main aim is to be a general Petri net library, | ||
14 | +being able to cope with most Petri nets models, and providing the | ||
15 | +researcher with a tool to quickly prototype its new ideas. SNAKES | ||
16 | +should be suitable to provide the data model for editors or | ||
17 | +simulators; actually, any editor that use SNAKES may also be a | ||
18 | +simulator as SNAKES can execute any net. | ||
19 | + | ||
20 | +A key feature of SNAKES is the ability to use arbitrary Python objects | ||
21 | +as tokens and arbitrary Python expressions in many points, for | ||
22 | +instance in transitions guards or arcs outgoing of transitions. This | ||
23 | +is what makes SNAKES that general. This relies on the capability of | ||
24 | +Python to run dynamically provided Python code (the $eval$ function). | ||
25 | +This feature may not be efficient enough for model-checking: speed is | ||
26 | +the price to pay for the wide generality. However, in the case of a | ||
27 | +new model, SNAKES may happen to be the only available tool. | ||
28 | + | ||
29 | +Another important feature of SNAKES is the plugin system that allows | ||
30 | +to extend the features and work with specialised classes of Petri | ||
31 | +nets. Currently, the following plugins are provided: | ||
32 | + | ||
33 | +pos:: adds to nodes the capability of holding their position. Nodes | ||
34 | +can be moved or shifted, Petri nets can be shifted globally and their | ||
35 | +bounding box can be computed. | ||
36 | + | ||
37 | +gv:: adds a method to draw a Petri net or a state graph using the tool | ||
38 | +http://www.graphviz.org[GraphViz] (through the Python binding | ||
39 | +http://networkx.lanl.gov/wiki/pygraphviz[PyGraphViz]). This module | ||
40 | +replaces the previous plugin called _graphviz_ and provides more | ||
41 | +flexibility and security, _graphviz_ is still provided but deprecated. | ||
42 | + | ||
43 | +status:: extends the Petri net model by adding status to the nodes. | ||
44 | +This is similar to what is used in the models of the PBC or Mnets | ||
45 | +family. Nodes can then merged automatically according to their status. | ||
46 | + | ||
47 | +ops:: this plugins defines control flow operations on Petri nets | ||
48 | +usually found in the PBC and Mnets family. Nets can be composed in | ||
49 | +parallel, sequence, choice and iteration. These operations rely on the | ||
50 | +places status. | ||
51 | + | ||
52 | +labels:: allows to add arbitrary labels to most objects (places, | ||
53 | +transitions, nets, ...) | ||
54 | + | ||
55 | +posops:: combines the features of pos and ops plugins: the control | ||
56 | +flow operations are modified in order to rearrange the nodes position | ||
57 | +in order to provide well shaped nets. This plugin is deprecated | ||
58 | +because the new _gv_ does the work much better. | ||
59 | + | ||
60 | +synchro:: it defines the label-based transition synchronisation | ||
61 | +defined in the Mnets model. | ||
62 | + | ||
63 | +// export:: allows to save Petri nets objects in the format of the tools | ||
64 | +// http://pep.sourceforge.net[PEP], http://helena.cnam.fr[Helena] and | ||
65 | +// http://maria[Maria]. http://pnml[PNML] is also supported as it is | ||
66 | +// built-in SNAKES. | ||
67 | + | ||
68 | +lashdata:: allows to define data that is not handled in the places of | ||
69 | +the Petri net but stored instead in the special structures handled by | ||
70 | +the http://www.montefiore.ulg.ac.be/~boigelot/research/lash/[library | ||
71 | +Lash]. This allows in particular to aggregate possibly infinite states | ||
72 | +into one meta-state. | ||
73 | + | ||
74 | +clusters:: this is an auxiliary plugin that allows to group nodes in a | ||
75 | +Petri net. This feature is used by _ops_ in order to record how a net | ||
76 | +is constructed, which is exploited by _gv_ in order to build a nice | ||
77 | +layout of composed nets. | ||
78 | + | ||
79 | + | ||
80 | +Getting SNAKES and installing it | ||
81 | +-------------------------------- | ||
82 | + | ||
83 | +Download http://www.univ-paris12.fr/lacl/pommereau/soft/snakes/snakes-{VERSION}.tar.gz[$snakes-{VERSION}.tar.gz$] | ||
84 | +({sys:../stat snakes-{VERSION}.tar.gz}) | ||
85 | + | ||
86 | +To install SNAKES, uncompress the archive and copy the directory | ||
87 | +snakes in a location where Python can find it (_i.e._, in a directory | ||
88 | +listed in your $PYTHONPATH$ environment variable). | ||
89 | + | ||
90 | +SNAKES should work with a Python version at least 2.5 but will _not_ | ||
91 | +work for an older version. Optionally, you may want to install | ||
92 | +additional software required by some plugins: | ||
93 | + | ||
94 | +gv:: depends on http://www.graphviz.org[GraphViz] and its Python | ||
95 | + binding http://networkx.lanl.gov/wiki/pygraphviz[PyGraphViz]. The | ||
96 | + plugin _graphviz_ depends on GraphViz only but is now deprecated. | ||
97 | + | ||
98 | +lashdata:: requires | ||
99 | + http://www.montefiore.ulg.ac.be/~boigelot/research/lash[Lash] and | ||
100 | + the | ||
101 | + http://www.univ-paris12.fr/lacl/pommereau/soft/index.html#PyLash[Python | ||
102 | + Lash binding]. | ||
103 | + | ||
104 | +[NOTE] | ||
105 | +===================== | ||
106 | +(C) 2007 Franck Pommereau <pommereau@univ-paris12.fr> | ||
107 | + | ||
108 | +This library is free software; you can redistribute it and/or modify | ||
109 | +it under the terms of the GNU Lesser General Public License as | ||
110 | +published by the Free Software Foundation; either version 2.1 of the | ||
111 | +License, or (at your option) any later version. | ||
112 | + | ||
113 | +This library is distributed in the hope that it will be useful, but | ||
114 | +WITHOUT ANY WARRANTY; without even the implied warranty of | ||
115 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
116 | +Lesser General Public License for more details. | ||
117 | + | ||
118 | +You should have received a copy of the GNU Lesser General Public | ||
119 | +License along with this library; if not, write to the Free Software | ||
120 | +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 | ||
121 | +USA | ||
122 | +===================== | ||
123 | + | ||
124 | + | ||
125 | +Contact | ||
126 | +------- | ||
127 | + | ||
128 | +Please feel free to send me comments, questions, bug reports or | ||
129 | +contributions by mailto:pommereau@univ-paris12.fr[email]. | ||
130 | + | ||
131 | +If you wish to be notified of the new releases of SNAKES, please | ||
132 | +register at the http://freshmeat.net/projects/snakes[FreshMeat page]. | ||
133 | + | ||
134 | +You may contribute to SNAKES by either send patches by email, or by | ||
135 | +using the https://launchpad.net/snakes[SNAKES Launchpad page]. | ||
136 | + | ||
137 | + | ||
138 | +Documentation | ||
139 | +------------- | ||
140 | + | ||
141 | +A good starting point may be the link:tutorial.html[tutorial]. Then, | ||
142 | +you may find the link:api/index.html[API reference manual] useful, it | ||
143 | +documents all the API and gives number of examples of how to use the | ||
144 | +various classes and functions. | ||
145 | + | ||
146 | +If you do not program Python, you can learn it in a few hours thanks | ||
147 | +to the very good http://docs.python.org/tut/tut.html[Python tutorial]. | ||
148 | + | ||
149 | +In order to know more about the PBC and M-nets family or the Petri net | ||
150 | +compositions defined in the plugins, you may read papers from | ||
151 | +http://www.univ-paris12.fr/lacl/pommereau/publis[my publications page] | ||
152 | +(in particular those with _calculus_ in the title). |
TODO
0 → 100644
bin/abcd
0 → 100755
bin/snkc
0 → 100755
1 | +#!/usr/bin/env python | ||
2 | +import socket, sys, readline | ||
3 | +from snakes.pnml import dumps, loads | ||
4 | +from snakes.plugins.query import Query | ||
5 | + | ||
6 | +env = {} | ||
7 | + | ||
8 | +def public (fun) : | ||
9 | + env[fun.__name__] = fun | ||
10 | + return fun | ||
11 | + | ||
12 | +@public | ||
13 | +def set (*larg, **karg) : | ||
14 | + """set(name, value) -> None | ||
15 | + assign value (object) to name (str) on the server""" | ||
16 | + return Query("set", *larg, **karg) | ||
17 | + | ||
18 | +@public | ||
19 | +def get (*larg, **karg) : | ||
20 | + """get(name) -> object | ||
21 | + return the last value assigned to name (str)""" | ||
22 | + return Query("get", *larg, **karg) | ||
23 | + | ||
24 | +@public | ||
25 | +def delete (*larg, **karg) : | ||
26 | + """delete(name) -> None | ||
27 | + discard name (str)""" | ||
28 | + return Query("del", *larg, **karg) | ||
29 | + | ||
30 | +@public | ||
31 | +def call (*larg, **karg) : | ||
32 | + """call(obj, ...) -> object | ||
33 | + call obj (str or result from another call) with the additional arguments | ||
34 | + return whatever the called object returns""" | ||
35 | + return Query("call", *larg, **karg) | ||
36 | + | ||
37 | +@public | ||
38 | +def help (command=None) : | ||
39 | + """help(command) -> None | ||
40 | + print help about command, if no command is given, list available commands""" | ||
41 | + if command is None: | ||
42 | + print "commands:", ", ".join(repr(cmd) for cmd in env | ||
43 | + if not cmd.startswith("_")) | ||
44 | + print " type 'help(cmd)' to ge help about a command" | ||
45 | + elif command in env : | ||
46 | + print env[command].__doc__ | ||
47 | + elif command.__name__ in env : | ||
48 | + print command.__doc__ | ||
49 | + else : | ||
50 | + print "unknown command %r" % command | ||
51 | + | ||
52 | +@public | ||
53 | +def quit () : | ||
54 | + """quit() -> None | ||
55 | + terminate the client""" | ||
56 | + print "bye" | ||
57 | + sys.exit(0) | ||
58 | + | ||
59 | +@public | ||
60 | +def load (path) : | ||
61 | + """net(path) -> object | ||
62 | + load a PNML file from path (str) and return the object is represents""" | ||
63 | + return loads(open(path).read()) | ||
64 | + | ||
65 | +@public | ||
66 | +def show (query) : | ||
67 | + """show(obj) -> None | ||
68 | + show the PNML representation of obj (object), for instance of a query""" | ||
69 | + print dumps(query) | ||
70 | + | ||
71 | +_verbose = False | ||
72 | + | ||
73 | +@public | ||
74 | +def verbose (state=None) : | ||
75 | + """verbose(state) -> None | ||
76 | + turn on (state=True), off (state=False) or toggle (state not | ||
77 | + given) the printing of queries before they are sent to the | ||
78 | + server""" | ||
79 | + global _verbose | ||
80 | + if state is None : | ||
81 | + _verbose = not _verbose | ||
82 | + else : | ||
83 | + _verbose = state | ||
84 | + if _verbose : | ||
85 | + print "dump of queries enabled" | ||
86 | + else : | ||
87 | + print "dump of queries disabled" | ||
88 | + | ||
89 | +try : | ||
90 | + if sys.argv[1] in ("-t", "--tcp") : | ||
91 | + proto = "TCP" | ||
92 | + del sys.argv[1] | ||
93 | + else : | ||
94 | + proto = "UDP" | ||
95 | + host, port = sys.argv[1:] | ||
96 | + port = int(port) | ||
97 | +except : | ||
98 | + print >>sys.stderr, "Usage: snkc [--tcp] HOST PORT" | ||
99 | + sys.exit(1) | ||
100 | + | ||
101 | +sock = None | ||
102 | + | ||
103 | +def sendto (data, address) : | ||
104 | + global sock | ||
105 | + if proto == "UDP" : | ||
106 | + if sock is None : | ||
107 | + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
108 | + sock.settimeout(2) | ||
109 | + sock.sendto(data, address) | ||
110 | + else : | ||
111 | + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
112 | + sock.settimeout(2) | ||
113 | + sock.connect(address) | ||
114 | + sock.send(data) | ||
115 | + | ||
116 | +def recvfrom (size) : | ||
117 | + global sock | ||
118 | + if proto == "UDP" : | ||
119 | + data, address = sock.recvfrom(size) | ||
120 | + else : | ||
121 | + parts = [] | ||
122 | + while True : | ||
123 | + parts.append(sock.recv(size)) | ||
124 | + if len(parts[-1]) < size : | ||
125 | + break | ||
126 | + address = sock.getpeername() | ||
127 | + sock.close() | ||
128 | + data = "".join(parts) | ||
129 | + return data, address | ||
130 | + | ||
131 | +while True : | ||
132 | + try : | ||
133 | + data = raw_input("? ") | ||
134 | + q = eval(data.strip(), env) | ||
135 | + except (EOFError, KeyboardInterrupt) : | ||
136 | + quit() | ||
137 | + except SystemExit : | ||
138 | + raise | ||
139 | + except Exception, e : | ||
140 | + print "query error:", e | ||
141 | + continue | ||
142 | + if q is not None : | ||
143 | + q = dumps(q) | ||
144 | + if _verbose : | ||
145 | + print "# query to %s:%u" % (host, port) | ||
146 | + print q | ||
147 | + sendto(q, (host, port)) | ||
148 | + try : | ||
149 | + data, address = recvfrom(2**20) | ||
150 | + if _verbose : | ||
151 | + print "# answer from %s:%u" % address | ||
152 | + print data.strip() | ||
153 | + except socket.timeout : | ||
154 | + print "# no answer received (timeout)" | ||
155 |
bin/snkd
0 → 100755
1 | +#!/usr/bin/env python | ||
2 | +import sys | ||
3 | +import snakes.plugins | ||
4 | +snakes.plugins.load("query", "snakes.nets", "nets") | ||
5 | + | ||
6 | +port = 1234 | ||
7 | +size = 2**20 | ||
8 | +verbose = 0 | ||
9 | +proto = "UDP" | ||
10 | + | ||
11 | +def help () : | ||
12 | + print "Usage: snkd [OPTION]" | ||
13 | + print "Options:" | ||
14 | + print " -p PORT, --port PORT listen on port number PORT" | ||
15 | + print " -t, --tcp use TCP instead of UDP" | ||
16 | + print " -s SIZE, --size SIZE set buffer size for inputs" | ||
17 | + print " -v, --verbose display information about queries" | ||
18 | + print " (use '-v' twice to dump queries/answers)" | ||
19 | + print " -h, --help print this help and exit" | ||
20 | + | ||
21 | +args = sys.argv[1:] | ||
22 | +try : | ||
23 | + while len(args) > 0 : | ||
24 | + arg = args.pop(0) | ||
25 | + if arg in ("-p", "--port") : | ||
26 | + port = int(args.pop(0)) | ||
27 | + elif arg in ("-v", "--verbose") : | ||
28 | + verbose += 1 | ||
29 | + elif arg in ("-t", "--tcp") : | ||
30 | + proto = "TCP" | ||
31 | + elif arg in ("-s", "--size") : | ||
32 | + size = int(args.pop(0)) | ||
33 | + elif arg in ("-h", "--help") : | ||
34 | + help() | ||
35 | + sys.exit(0) | ||
36 | + else : | ||
37 | + print >>sys.stderr("snkd: invalid command %r" % arg) | ||
38 | + sys.exit(1) | ||
39 | +except SystemExit : | ||
40 | + raise | ||
41 | +except : | ||
42 | + cls, val, tb = sys.exc_info() | ||
43 | + print >>sys.stderr, "snkd: %s, %s" % (cls.__name__, val) | ||
44 | + sys.exit(1) | ||
45 | + | ||
46 | +if verbose : | ||
47 | + print "# starting" | ||
48 | + print "# listen on: %s:%u" % (proto, port) | ||
49 | + print "# buffer size: %uMb" % (size/1024) | ||
50 | + print "# verbosity:", verbose | ||
51 | + | ||
52 | +try : | ||
53 | + if proto == "UDP" : | ||
54 | + nets.UDPServer(port, size=size, verbose=verbose).run() | ||
55 | + else : | ||
56 | + nets.TCPServer(port, size=size, verbose=verbose).run() | ||
57 | +except KeyboardInterrupt : | ||
58 | + print "# bye" | ||
59 | +except : | ||
60 | + cls, val, tb = sys.exc_info() | ||
61 | + if verbose > 1 : | ||
62 | + raise | ||
63 | + elif verbose : | ||
64 | + print "# fatal error" | ||
65 | + print >>sys.stderr, "snkd: %s, %s" % (cls.__name__, val) | ||
66 | + sys.exit(2) |
debian/DISTRIB
0 → 100644
debian/PPA
0 → 100644
1 | +5 |
debian/VERSION
0 → 100644
1 | +1 |
debian/changelog
0 → 100644
1 | +python-snakes (0.9.16-1) UNRELEASED; urgency=low | ||
2 | + | ||
3 | + * see NEWS | ||
4 | + | ||
5 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 07 Jun 2011 12:23:33 +0200 | ||
6 | + | ||
7 | +python-snakes (0.9.15-1) UNRELEASED; urgency=low | ||
8 | + | ||
9 | + * see NEWS | ||
10 | + | ||
11 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 10 May 2011 18:22:34 +0200 | ||
12 | + | ||
13 | +python-snakes (0.9.14-1) UNRELEASED; urgency=low | ||
14 | + | ||
15 | + * see NEWS | ||
16 | + | ||
17 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Mon, 11 Apr 2011 16:45:50 +0200 | ||
18 | + | ||
19 | +python-snakes (0.9.13-2) UNRELEASED; urgency=low | ||
20 | + | ||
21 | + * see NEWS | ||
22 | + | ||
23 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 23 Jul 2010 20:06:53 +0200 | ||
24 | + | ||
25 | +python-snakes (0.9.13-1) UNRELEASED; urgency=low | ||
26 | + | ||
27 | + * see NEWS | ||
28 | + | ||
29 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 16 Jul 2010 17:09:14 +0200 | ||
30 | + | ||
31 | +python-snakes (0.9.12-2) UNRELEASED; urgency=low | ||
32 | + | ||
33 | + * see NEWS | ||
34 | + | ||
35 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Sat, 03 Apr 2010 21:06:50 +0200 | ||
36 | + | ||
37 | +python-snakes (0.9.12-1) UNRELEASED; urgency=low | ||
38 | + | ||
39 | + * see NEWS | ||
40 | + | ||
41 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Thu, 01 Apr 2010 19:46:02 +0200 | ||
42 | + | ||
43 | +python-snakes (0.9.11-1) UNRELEASED; urgency=low | ||
44 | + | ||
45 | + * see NEWS | ||
46 | + | ||
47 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Thu, 25 Mar 2010 19:39:47 +0100 | ||
48 | + | ||
49 | +python-snakes (0.9.10-1) UNRELEASED; urgency=low | ||
50 | + | ||
51 | + * see NEWS | ||
52 | + | ||
53 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 19 Jun 2009 13:40:36 +0200 | ||
54 | + | ||
55 | +python-snakes (0.9.9-2) UNRELEASED; urgency=low | ||
56 | + | ||
57 | + * see NEWS | ||
58 | + | ||
59 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 19 May 2009 09:29:46 +0200 | ||
60 | + | ||
61 | +python-snakes (0.9.8-2) UNRELEASED; urgency=low | ||
62 | + | ||
63 | + * see NEWS | ||
64 | + | ||
65 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 14 Apr 2009 20:02:32 +0200 | ||
66 | + | ||
67 | +python-snakes (0.9.8-1) UNRELEASED; urgency=low | ||
68 | + | ||
69 | + * see NEWS | ||
70 | + | ||
71 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Mon, 23 Mar 2009 17:34:06 +0100 | ||
72 | + | ||
73 | +python-snakes (0.9.7-1) UNRELEASED; urgency=low | ||
74 | + | ||
75 | + * see NEWS | ||
76 | + | ||
77 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 20 Jan 2009 13:07:09 +0100 | ||
78 | + | ||
79 | +python-snakes (0.9.6-2) UNRELEASED; urgency=low | ||
80 | + | ||
81 | + * see NEWS | ||
82 | + | ||
83 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 02 Dec 2008 17:47:43 +0100 | ||
84 | + | ||
85 | +python-snakes (0.9.6-1) UNRELEASED; urgency=low | ||
86 | + | ||
87 | + * see NEWS | ||
88 | + | ||
89 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 28 Nov 2008 15:24:05 +0100 | ||
90 | + | ||
91 | +python-snakes (0.9.5-2) UNRELEASED; urgency=low | ||
92 | + | ||
93 | + * Fixed doc installation path | ||
94 | + | ||
95 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 21 Nov 2008 13:20:55 +0100 | ||
96 | + | ||
97 | +python-snakes (0.9.5-1) UNRELEASED; urgency=low | ||
98 | + | ||
99 | + * Trying to fix build on Launchpad | ||
100 | + | ||
101 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Fri, 21 Nov 2008 08:19:04 +0100 | ||
102 | + | ||
103 | +python-snakes (0.9.5) UNRELEASED; urgency=low | ||
104 | + | ||
105 | + * See NEWS | ||
106 | + | ||
107 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Wed, 19 Nov 2008 21:47:52 +0100 | ||
108 | + | ||
109 | +python-snakes (0.9.4) UNRELEASED; urgency=low | ||
110 | + | ||
111 | + * Initial release. (Closes: #XXXXXX) | ||
112 | + | ||
113 | + -- Franck Pommereau <pommereau@univ-paris12.fr> Tue, 18 Nov 2008 12:09:16 +0100 |
debian/compat
0 → 100644
1 | +6 |
debian/control
0 → 100644
1 | +Source: python-snakes | ||
2 | +Section: python | ||
3 | +Priority: extra | ||
4 | +Maintainer: Franck Pommereau <pommereau@univ-paris12.fr> | ||
5 | +Homepage: http://lacl.univ-paris12.fr/pommereau/soft/snakes | ||
6 | +Build-Depends: python (>=2.5), cdbs (>=0.4.49), debhelper (>= 5), python-central (>=0.5.6) | ||
7 | +XS-Python-Version: >=2.5 | ||
8 | +Standards-Version: 3.7.2 | ||
9 | + | ||
10 | +Package: python-snakes | ||
11 | +Architecture: all | ||
12 | +XB-Python-Version: ${python:Versions} | ||
13 | +Depends: python (>=2.5), python-central, graphviz, python-tk | ||
14 | +Description: SNAKES is the Net Algebra Kit for Editors and Simulators | ||
15 | + SNAKES is a general purpose Petri net Python library allowing to | ||
16 | + define and execute most classes of Petri nets. It features a plugin | ||
17 | + system to allow its extension. In particular, plugins are provided to | ||
18 | + implement the operations usually found in the PBC and M-nets family. |
debian/copyright
0 → 100644
1 | +This package was debianized by Franck Pommereau <pommereau@univ-paris12.fr> on | ||
2 | +DATE | ||
3 | + | ||
4 | +License: | ||
5 | + | ||
6 | + This package is free software; you can redistribute it and/or | ||
7 | + modify it under the terms of the GNU Lesser General Public License | ||
8 | + as published by the Free Software Foundation; either version 2 of | ||
9 | + the License, or (at your option) any later version. | ||
10 | + | ||
11 | + This package is distributed in the hope that it will be useful, but | ||
12 | + WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | + Lesser General Public License for more details. | ||
15 | + | ||
16 | + You should have received a copy of the GNU Lesser General Public | ||
17 | + License along with this package; if not, see | ||
18 | + `http://www.gnu.org/licenses/lgpl-3.0.txt'. | ||
19 | + | ||
20 | +On Debian systems, the complete text of the GNU General | ||
21 | +Public License can be found in `/usr/share/common-licenses/LGPL'. | ||
22 | + | ||
23 | +The Debian packaging is (C) 2008, Franck Pommereau | ||
24 | +<pommereau@univ-paris12.fr> and is licensed under the LGPL, see above. |
debian/rules
0 → 100755
doc/COPYING
0 → 100644
1 | + GNU LESSER GENERAL PUBLIC LICENSE | ||
2 | + Version 3, 29 June 2007 | ||
3 | + | ||
4 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
5 | + Everyone is permitted to copy and distribute verbatim copies | ||
6 | + of this license document, but changing it is not allowed. | ||
7 | + | ||
8 | + | ||
9 | + This version of the GNU Lesser General Public License incorporates | ||
10 | +the terms and conditions of version 3 of the GNU General Public | ||
11 | +License, supplemented by the additional permissions listed below. | ||
12 | + | ||
13 | + 0. Additional Definitions. | ||
14 | + | ||
15 | + As used herein, "this License" refers to version 3 of the GNU Lesser | ||
16 | +General Public License, and the "GNU GPL" refers to version 3 of the GNU | ||
17 | +General Public License. | ||
18 | + | ||
19 | + "The Library" refers to a covered work governed by this License, | ||
20 | +other than an Application or a Combined Work as defined below. | ||
21 | + | ||
22 | + An "Application" is any work that makes use of an interface provided | ||
23 | +by the Library, but which is not otherwise based on the Library. | ||
24 | +Defining a subclass of a class defined by the Library is deemed a mode | ||
25 | +of using an interface provided by the Library. | ||
26 | + | ||
27 | + A "Combined Work" is a work produced by combining or linking an | ||
28 | +Application with the Library. The particular version of the Library | ||
29 | +with which the Combined Work was made is also called the "Linked | ||
30 | +Version". | ||
31 | + | ||
32 | + The "Minimal Corresponding Source" for a Combined Work means the | ||
33 | +Corresponding Source for the Combined Work, excluding any source code | ||
34 | +for portions of the Combined Work that, considered in isolation, are | ||
35 | +based on the Application, and not on the Linked Version. | ||
36 | + | ||
37 | + The "Corresponding Application Code" for a Combined Work means the | ||
38 | +object code and/or source code for the Application, including any data | ||
39 | +and utility programs needed for reproducing the Combined Work from the | ||
40 | +Application, but excluding the System Libraries of the Combined Work. | ||
41 | + | ||
42 | + 1. Exception to Section 3 of the GNU GPL. | ||
43 | + | ||
44 | + You may convey a covered work under sections 3 and 4 of this License | ||
45 | +without being bound by section 3 of the GNU GPL. | ||
46 | + | ||
47 | + 2. Conveying Modified Versions. | ||
48 | + | ||
49 | + If you modify a copy of the Library, and, in your modifications, a | ||
50 | +facility refers to a function or data to be supplied by an Application | ||
51 | +that uses the facility (other than as an argument passed when the | ||
52 | +facility is invoked), then you may convey a copy of the modified | ||
53 | +version: | ||
54 | + | ||
55 | + a) under this License, provided that you make a good faith effort to | ||
56 | + ensure that, in the event an Application does not supply the | ||
57 | + function or data, the facility still operates, and performs | ||
58 | + whatever part of its purpose remains meaningful, or | ||
59 | + | ||
60 | + b) under the GNU GPL, with none of the additional permissions of | ||
61 | + this License applicable to that copy. | ||
62 | + | ||
63 | + 3. Object Code Incorporating Material from Library Header Files. | ||
64 | + | ||
65 | + The object code form of an Application may incorporate material from | ||
66 | +a header file that is part of the Library. You may convey such object | ||
67 | +code under terms of your choice, provided that, if the incorporated | ||
68 | +material is not limited to numerical parameters, data structure | ||
69 | +layouts and accessors, or small macros, inline functions and templates | ||
70 | +(ten or fewer lines in length), you do both of the following: | ||
71 | + | ||
72 | + a) Give prominent notice with each copy of the object code that the | ||
73 | + Library is used in it and that the Library and its use are | ||
74 | + covered by this License. | ||
75 | + | ||
76 | + b) Accompany the object code with a copy of the GNU GPL and this license | ||
77 | + document. | ||
78 | + | ||
79 | + 4. Combined Works. | ||
80 | + | ||
81 | + You may convey a Combined Work under terms of your choice that, | ||
82 | +taken together, effectively do not restrict modification of the | ||
83 | +portions of the Library contained in the Combined Work and reverse | ||
84 | +engineering for debugging such modifications, if you also do each of | ||
85 | +the following: | ||
86 | + | ||
87 | + a) Give prominent notice with each copy of the Combined Work that | ||
88 | + the Library is used in it and that the Library and its use are | ||
89 | + covered by this License. | ||
90 | + | ||
91 | + b) Accompany the Combined Work with a copy of the GNU GPL and this license | ||
92 | + document. | ||
93 | + | ||
94 | + c) For a Combined Work that displays copyright notices during | ||
95 | + execution, include the copyright notice for the Library among | ||
96 | + these notices, as well as a reference directing the user to the | ||
97 | + copies of the GNU GPL and this license document. | ||
98 | + | ||
99 | + d) Do one of the following: | ||
100 | + | ||
101 | + 0) Convey the Minimal Corresponding Source under the terms of this | ||
102 | + License, and the Corresponding Application Code in a form | ||
103 | + suitable for, and under terms that permit, the user to | ||
104 | + recombine or relink the Application with a modified version of | ||
105 | + the Linked Version to produce a modified Combined Work, in the | ||
106 | + manner specified by section 6 of the GNU GPL for conveying | ||
107 | + Corresponding Source. | ||
108 | + | ||
109 | + 1) Use a suitable shared library mechanism for linking with the | ||
110 | + Library. A suitable mechanism is one that (a) uses at run time | ||
111 | + a copy of the Library already present on the user's computer | ||
112 | + system, and (b) will operate properly with a modified version | ||
113 | + of the Library that is interface-compatible with the Linked | ||
114 | + Version. | ||
115 | + | ||
116 | + e) Provide Installation Information, but only if you would otherwise | ||
117 | + be required to provide such information under section 6 of the | ||
118 | + GNU GPL, and only to the extent that such information is | ||
119 | + necessary to install and execute a modified version of the | ||
120 | + Combined Work produced by recombining or relinking the | ||
121 | + Application with a modified version of the Linked Version. (If | ||
122 | + you use option 4d0, the Installation Information must accompany | ||
123 | + the Minimal Corresponding Source and Corresponding Application | ||
124 | + Code. If you use option 4d1, you must provide the Installation | ||
125 | + Information in the manner specified by section 6 of the GNU GPL | ||
126 | + for conveying Corresponding Source.) | ||
127 | + | ||
128 | + 5. Combined Libraries. | ||
129 | + | ||
130 | + You may place library facilities that are a work based on the | ||
131 | +Library side by side in a single library together with other library | ||
132 | +facilities that are not Applications and are not covered by this | ||
133 | +License, and convey such a combined library under terms of your | ||
134 | +choice, if you do both of the following: | ||
135 | + | ||
136 | + a) Accompany the combined library with a copy of the same work based | ||
137 | + on the Library, uncombined with any other library facilities, | ||
138 | + conveyed under the terms of this License. | ||
139 | + | ||
140 | + b) Give prominent notice with the combined library that part of it | ||
141 | + is a work based on the Library, and explaining where to find the | ||
142 | + accompanying uncombined form of the same work. | ||
143 | + | ||
144 | + 6. Revised Versions of the GNU Lesser General Public License. | ||
145 | + | ||
146 | + The Free Software Foundation may publish revised and/or new versions | ||
147 | +of the GNU Lesser General Public License from time to time. Such new | ||
148 | +versions will be similar in spirit to the present version, but may | ||
149 | +differ in detail to address new problems or concerns. | ||
150 | + | ||
151 | + Each version is given a distinguishing version number. If the | ||
152 | +Library as you received it specifies that a certain numbered version | ||
153 | +of the GNU Lesser General Public License "or any later version" | ||
154 | +applies to it, you have the option of following the terms and | ||
155 | +conditions either of that published version or of any later version | ||
156 | +published by the Free Software Foundation. If the Library as you | ||
157 | +received it does not specify a version number of the GNU Lesser | ||
158 | +General Public License, you may choose any version of the GNU Lesser | ||
159 | +General Public License ever published by the Free Software Foundation. | ||
160 | + | ||
161 | + If the Library as you received it specifies that a proxy can decide | ||
162 | +whether future versions of the GNU Lesser General Public License shall | ||
163 | +apply, that proxy's public statement of acceptance of any version is | ||
164 | +permanent authorization for you to choose that version for the | ||
165 | +Library. |
doc/Makefile
0 → 100644
1 | +all: | ||
2 | + rm -rf api | ||
3 | + epydoc --output api --no-frames --graph=all \ | ||
4 | + --name="SNAKES is the Net Algebra Kit for Editors and Simulators" \ | ||
5 | + --navlink='<img alt="SNAKES logo" src="snakes-logo.jpg" width="120" height="120"/>' \ | ||
6 | + --no-private ../snakes | ||
7 | + convert ../logo/snakes-logo.png -background white -scale 120x120 ./api/snakes-logo.jpg |
doc/abcd.txt
0 → 100644
This diff is collapsed. Click to expand it.
doc/examples/abcd/README
0 → 100644
doc/examples/abcd/ns/dolev_yao.py
0 → 100644
This diff is collapsed. Click to expand it.
doc/examples/abcd/ns/ns.abcd
0 → 100644
1 | +# communication network | ||
2 | +buffer nw : object = () | ||
3 | +# implementation of nonces and Dolev-Yao attacker | ||
4 | +from dolev_yao import * | ||
5 | + | ||
6 | +net Alice (this, who: buffer) : | ||
7 | + # protocol initiater | ||
8 | + buffer peer : int = () | ||
9 | + buffer peer_nonce : Nonce = () | ||
10 | + [who?(B), peer+(B), nw+("crypt", ("pub", B), this, Nonce(this))] | ||
11 | + ; [nw-("crypt", ("pub", this), Na, Nb), peer_nonce+(Nb) if Na == Nonce(this)] | ||
12 | + ; [peer?(B), peer_nonce?(Nb), nw+("crypt", ("pub", B), Nb)] | ||
13 | + | ||
14 | +net Bob (this) : | ||
15 | + # protocol responder | ||
16 | + buffer peer : int = () | ||
17 | + buffer peer_nonce : Nonce = () | ||
18 | + [nw-("crypt", ("pub", this), A, Na), peer+(A), peer_nonce+(Na)] | ||
19 | + ; [peer?(A), peer_nonce?(Na), nw+("crypt", ("pub", A), Na, Nonce(this))] | ||
20 | + ; [nw-("crypt", ("pub", this), Nb) if Nb == Nonce(this)] | ||
21 | + | ||
22 | +net Mallory (this, init) : | ||
23 | + # attacker | ||
24 | + buffer knowledge : object = (this, Nonce(this), ("priv", this)) + init | ||
25 | + # Dolev-Yao attacker, bound by protocol signature | ||
26 | + buffer spy : object = Spy(("crypt", ("pub", int), int, Nonce), | ||
27 | + ("crypt", ("pub", int), Nonce, Nonce), | ||
28 | + ("crypt", ("pub", int), Nonce)) | ||
29 | + # capture on message and learn from it | ||
30 | + ([spy?(s), nw-(m), knowledge>>(k), knowledge<<(s.learn(m, k))] | ||
31 | + # loose message or inject another one (may be the same) | ||
32 | + ; ([True] + [spy?(s), knowledge?(x), nw+(x) if s.message(x)])) | ||
33 | + * [False] | ||
34 | + | ||
35 | +# Alice will contact one of these agents | ||
36 | +buffer agents : int = 2, 3 | ||
37 | +# main processes, with friendly names | ||
38 | +alice::Alice(1, agents) | ||
39 | +| bob::Bob(2) | ||
40 | +| spy::Mallory(3, (1, ("pub", 1), 2, ("pub", 2))) |
doc/examples/abcd/ns/ns.py
0 → 100644
1 | +import snakes.plugins | ||
2 | +snakes.plugins.load("status", "snakes.nets", "nets") | ||
3 | +from nets import * | ||
4 | +from dolev_yao import Nonce | ||
5 | + | ||
6 | +ns = loads(",ns.pnml") | ||
7 | +states = StateGraph(ns) | ||
8 | + | ||
9 | +for s in states : | ||
10 | + m = states.net.get_marking() | ||
11 | + # skip non final markings | ||
12 | + if "bob.x" not in m or "alice.x" not in m : | ||
13 | + continue | ||
14 | + # get Alice's and Bob's peers ids | ||
15 | + bp = list(m["bob.peer"])[0] | ||
16 | + ap = list(m["alice.peer"])[0] | ||
17 | + # violation of mutual authentication | ||
18 | + if bp == 1 and ap != 2 : | ||
19 | + print(s, "A(1) <=> %s ; B(2) <=> %s" % (ap, bp)) | ||
20 | + print(m) | ||
21 | + | ||
22 | +print(len(states), "states") |
doc/examples/abcd/philo.abcd
0 → 100644
1 | +# get BlackToken | ||
2 | +#from snakes.nets import * | ||
3 | + | ||
4 | +buffer fork1 : BlackToken = dot | ||
5 | +buffer fork2 : BlackToken = dot | ||
6 | +buffer fork3 : BlackToken = dot | ||
7 | + | ||
8 | +# buffer parameters have to be declared as such | ||
9 | +net philo (left: buffer, right: buffer): | ||
10 | + buffer eating : BlackToken = () | ||
11 | + ([left-(dot), right-(dot), eating+(dot)] | ||
12 | + ; [left+(dot), right+(dot), eating-(dot)]) | ||
13 | + * [False] | ||
14 | + | ||
15 | +philo(fork1, fork2) | ||
16 | +| philo(fork2, fork3) | ||
17 | +| philo(fork3, fork1) |
doc/examples/abcd/prod-cons.abcd
0 → 100644
1 | +# shared buffer between producers and consumers | ||
2 | +buffer bag : int = () | ||
3 | + | ||
4 | +net prod () : | ||
5 | + # produces 10 tokens: 1..9 in bag | ||
6 | + buffer count : int = 0 | ||
7 | + [count-(x), count+(x+1), bag+(x) if x < 10] * [count-(x) if x == 10] | ||
8 | + | ||
9 | +net odd () : | ||
10 | + # consumes odd tokens in bag | ||
11 | + [bag-(x) if (x % 2) == 1] * [False] | ||
12 | + | ||
13 | +net even () : | ||
14 | + # consumes even tokens un bag | ||
15 | + [bag-(x) if (x % 2) == 0] * [False] | ||
16 | + | ||
17 | +# main process with one instance of each net | ||
18 | +odd() | even() | prod() |
doc/examples/abcd/railroad.abcd
0 → 100644
1 | +# symbols | ||
2 | +symbol RED, GREEN, UP, DOWN, OPEN, MOVING, CLOSED | ||
3 | +# states of the gate | ||
4 | +typedef gatestate : enum(OPEN, MOVING, CLOSED) | ||
5 | + | ||
6 | +# stores green light state | ||
7 | +buffer light : enum(RED, GREEN) = GREEN | ||
8 | +# commands send by the track to the gate | ||
9 | +buffer command : enum(UP, DOWN) = () | ||
10 | + | ||
11 | +net gate () : | ||
12 | + # a pair of gates | ||
13 | + buffer state : gatestate = OPEN | ||
14 | + ([command-(DOWN), state-(OPEN), state+(MOVING)] ; | ||
15 | + [state-(MOVING), state+(CLOSED), light-(RED), light+(GREEN)] ; | ||
16 | + [command-(UP), state-(CLOSED), state+(MOVING)] ; | ||
17 | + [state-(MOVING), state+(OPEN)]) | ||
18 | + * [False] | ||
19 | + | ||
20 | +net track () : | ||
21 | + # a track with trains passing on it | ||
22 | + buffer crossing : bool = False | ||
23 | + ([command+(DOWN), light-(GREEN), light+(RED)] ; | ||
24 | + [light?(GREEN), crossing-(False), crossing+(True)] ; | ||
25 | + [crossing-(True), crossing+(False), command+(UP)]) | ||
26 | + * [False] | ||
27 | + | ||
28 | +# main process | ||
29 | +gate() | track() |
doc/examples/abcd/railroad.py
0 → 100644
1 | +import sys | ||
2 | + | ||
3 | +import snakes.plugins | ||
4 | +snakes.plugins.load("gv", "snakes.nets", "snk") | ||
5 | +from snk import * | ||
6 | + | ||
7 | +n = loads(sys.argv[1]) | ||
8 | +g = StateGraph(n) | ||
9 | +for s in g : | ||
10 | + m = g.net.get_marking() | ||
11 | + # safety property: train present => gates closed | ||
12 | + if ("train().crossing" in m | ||
13 | + and True in m["train().crossing"] | ||
14 | + and "closed" not in m["gate().state"]) : | ||
15 | + print("%s %s" % (s, m)) | ||
16 | +print("checked %s states" % len(g)) | ||
17 | + | ||
18 | +g.draw(sys.argv[1].rsplit(".", 1)[0] + "-states.png") |
doc/queries.txt
0 → 100644
This diff is collapsed. Click to expand it.
doc/simple-coloured.pnml
0 → 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<pnml> | ||
3 | + <net id="mynet"> | ||
4 | + <place id="p2"> | ||
5 | + <type domain="universal"/> | ||
6 | + <initialMarking> | ||
7 | + <multiset/> | ||
8 | + </initialMarking> | ||
9 | + </place> | ||
10 | + <place id="p1"> | ||
11 | + <type domain="universal"/> | ||
12 | + <initialMarking> | ||
13 | + <multiset> | ||
14 | + <item> | ||
15 | + <value> | ||
16 | + <object type="int"> | ||
17 | + 1 | ||
18 | + </object> | ||
19 | + </value> | ||
20 | + <multiplicity> | ||
21 | + 1 | ||
22 | + </multiplicity> | ||
23 | + </item> | ||
24 | + <item> | ||
25 | + <value> | ||
26 | + <object type="int"> | ||
27 | + 2 | ||
28 | + </object> | ||
29 | + </value> | ||
30 | + <multiplicity> | ||
31 | + 1 | ||
32 | + </multiplicity> | ||
33 | + </item> | ||
34 | + </multiset> | ||
35 | + </initialMarking> | ||
36 | + </place> | ||
37 | + <transition id="t"/> | ||
38 | + <arc id="p1:t" source="p1" target="t"> | ||
39 | + <inscription> | ||
40 | + <variable> | ||
41 | + x | ||
42 | + </variable> | ||
43 | + </inscription> | ||
44 | + </arc> | ||
45 | + <arc id="t:p2" source="t" target="p2"> | ||
46 | + <inscription> | ||
47 | + <expression> | ||
48 | + x+1 | ||
49 | + </expression> | ||
50 | + </inscription> | ||
51 | + </arc> | ||
52 | + </net> | ||
53 | +</pnml> |
doc/simple-pt.pnml
0 → 100644
1 | +<?xml version="1.0" encoding="utf-8"?> | ||
2 | +<pnml> | ||
3 | + <net id="Simple P/T net"> | ||
4 | + <place id="p2"> | ||
5 | + <initialMarking> | ||
6 | + <text> | ||
7 | + 0 | ||
8 | + </text> | ||
9 | + </initialMarking> | ||
10 | + </place> | ||
11 | + <place id="p1"> | ||
12 | + <initialMarking> | ||
13 | + <text> | ||
14 | + 1 | ||
15 | + </text> | ||
16 | + </initialMarking> | ||
17 | + </place> | ||
18 | + <transition id="t2"/> | ||
19 | + <transition id="t1"/> | ||
20 | + <arc id="p2:t2" source="p2" target="t2"> | ||
21 | + <inscription> | ||
22 | + <text> | ||
23 | + 1 | ||
24 | + </text> | ||
25 | + </inscription> | ||
26 | + </arc> | ||
27 | + <arc id="t2:p1" source="t2" target="p1"> | ||
28 | + <inscription> | ||
29 | + <text> | ||
30 | + 1 | ||
31 | + </text> | ||
32 | + </inscription> | ||
33 | + </arc> | ||
34 | + <arc id="p1:t1" source="p1" target="t1"> | ||
35 | + <inscription> | ||
36 | + <text> | ||
37 | + 1 | ||
38 | + </text> | ||
39 | + </inscription> | ||
40 | + </arc> | ||
41 | + <arc id="t1:p2" source="t1" target="p2"> | ||
42 | + <inscription> | ||
43 | + <text> | ||
44 | + 1 | ||
45 | + </text> | ||
46 | + </inscription> | ||
47 | + </arc> | ||
48 | + </net> | ||
49 | +</pnml> |
doc/snakes-pnml.txt
0 → 100644
This diff is collapsed. Click to expand it.
doc/tutorial.png
0 → 100644
15.3 KB
doc/tutorial.txt
0 → 100644
This diff is collapsed. Click to expand it.
logo/snakes-logo.png
0 → 100644
23.3 KB
logo/snakes-logo.svg
0 → 100644
This diff is collapsed. Click to expand it.
mkdeb.py
0 → 100644
1 | +import os, os.path | ||
2 | + | ||
3 | +snakes_version = open("VERSION").readline().strip() | ||
4 | +package_version = open("debian/VERSION").readline().strip() | ||
5 | +ppa_version = open("debian/PPA").readline().strip() | ||
6 | +changelog_version = open("debian/changelog").readline().split()[1].strip("()") | ||
7 | +distribs = [l.strip().split()[0] for l in open("debian/DISTRIB")] | ||
8 | +base_dir = os.getcwd() | ||
9 | +base_dist_dir = "dist" | ||
10 | +dput_sh = open("dput.sh", "w") | ||
11 | + | ||
12 | +def system (command) : | ||
13 | + print("*** %s" % command) | ||
14 | + retcode = os.system(command) | ||
15 | + if retcode != 0 : | ||
16 | + print("*** error return status (%s)" % retcode) | ||
17 | + sys.exit(retcode) | ||
18 | + | ||
19 | +def chdir (path) : | ||
20 | + print("*** cd %s" % path) | ||
21 | + os.chdir(path) | ||
22 | + | ||
23 | +def changelog (path, dist) : | ||
24 | + full_version = "%s-%s~ppa%s~%s1" % (snakes_version, package_version, | ||
25 | + ppa_version, dist) | ||
26 | + chdir(path) | ||
27 | + system("debchange -b --newversion %s --distribution %s 'see NEWS'" | ||
28 | + % (full_version, dist)) | ||
29 | + chdir(base_dir) | ||
30 | + | ||
31 | +def build_package (dist_dir, dist) : | ||
32 | + full_version = "%s-%s~ppa%s~%s1" % (snakes_version, package_version, | ||
33 | + ppa_version, dist) | ||
34 | + deb_dir = os.path.join(dist_dir, "python-snakes_%s" % full_version) | ||
35 | + if not os.path.isdir(dist_dir) : | ||
36 | + print("*** make dir %r" % dist_dir) | ||
37 | + os.makedirs(dist_dir) | ||
38 | + if os.path.isdir(deb_dir) : | ||
39 | + system("rm -rf %s" % deb_dir) | ||
40 | + system("hg archive %s" % deb_dir) | ||
41 | + changelog(deb_dir, dist) | ||
42 | + system("sed -i -e 's/DATE/$(date -R)/' %s/debian/copyright" % deb_dir) | ||
43 | + system("sed -i -e 's/UNRELEASED/%s/' %s/debian/changelog" % (dist, deb_dir)) | ||
44 | + chdir(deb_dir) | ||
45 | + system("make doc") | ||
46 | + system("dpkg-buildpackage") | ||
47 | + system("dpkg-buildpackage -S -sa") | ||
48 | + chdir(base_dir) | ||
49 | + dput_sh.write("dput lp %s_source.changes\n" % deb_dir) | ||
50 | + | ||
51 | +main_version = "%s-%s" % (snakes_version, package_version) | ||
52 | +if main_version != changelog_version : | ||
53 | + system("debchange --newversion %s --distribution UNRELEASED 'see NEWS'" | ||
54 | + % main_version) | ||
55 | + system("hg commit -m 'updated debian/changelog' debian/changelog") | ||
56 | + | ||
57 | +for dist in distribs : | ||
58 | + build_package(base_dist_dir, dist) | ||
59 | +dput_sh.close() |
mklang.py
0 → 100644
1 | +import glob, os, os.path | ||
2 | + | ||
3 | +for src in glob.glob("snakes/lang/*/*.pgen") : | ||
4 | + tgt = os.path.join(os.path.dirname(src), "pgen.py") | ||
5 | + if not os.path.isfile(tgt) or os.path.getmtime(src) > os.path.getmtime(tgt) : | ||
6 | + print("python snakes/lang/pgen.py --output=%s %s" % (tgt, src)) | ||
7 | + os.system("python snakes/lang/pgen.py --output=%s %s" % (tgt, src)) | ||
8 | + | ||
9 | +for src in glob.glob("snakes/lang/*/*.asdl") : | ||
10 | + tgt = os.path.join(os.path.dirname(src), "asdl.py") | ||
11 | + if not os.path.isfile(tgt) or os.path.getmtime(src) > os.path.getmtime(tgt) : | ||
12 | + print("python snakes/lang/asdl.py --output=%s %s" % (tgt, src)) | ||
13 | + os.system("python snakes/lang/asdl.py --output=%s %s" % (tgt, src)) |
setup.py
0 → 100644
1 | +#!/usr/bin/env python | ||
2 | + | ||
3 | +import sys, os | ||
4 | +from distutils.core import setup | ||
5 | + | ||
6 | +def doc_files() : | ||
7 | + import os, os.path | ||
8 | + result = {} | ||
9 | + for root, dirs, files in os.walk("doc") : | ||
10 | + target_dir = os.path.join("share/doc/python-snakes", | ||
11 | + *root.split(os.sep)[1:]) | ||
12 | + for name in files : | ||
13 | + if target_dir not in result : | ||
14 | + result[target_dir] = [] | ||
15 | + result[target_dir].append(os.path.join(root, name)) | ||
16 | + return list(result.items()) | ||
17 | + | ||
18 | +if __name__ == "__main__" : | ||
19 | + print("Compiling Emacs files...") | ||
20 | + os.system("emacs -batch -f batch-byte-compile utils/abcd-mode.el") | ||
21 | + # | ||
22 | + setup(name="SNAKES", | ||
23 | + version=open("VERSION").read().strip(), | ||
24 | + description="SNAKES is the Net Algebra Kit for Editors and Simulators", | ||
25 | + long_description="""SNAKES is a general purpose Petri net Python | ||
26 | + library allowing to define and execute most classes of Petri | ||
27 | + nets. It features a plugin system to allow its extension. In | ||
28 | + particular, plugins are provided to implement the operations | ||
29 | + usually found in the PBC and M-nets family.""", | ||
30 | + author="Franck Pommereau", | ||
31 | + author_email="pommereau@univ-paris12.fr", | ||
32 | + maintainer="Franck Pommereau", | ||
33 | + maintainer_email="pommereau@univ-paris12.fr", | ||
34 | + url="http://lacl.univ-paris12.fr/pommereau/soft/snakes", | ||
35 | + scripts=["bin/abcd", | ||
36 | + "bin/snkc", | ||
37 | + "bin/snkd", | ||
38 | + ], | ||
39 | + packages=["snakes", | ||
40 | + "snakes.lang", | ||
41 | + "snakes.lang.pylib", | ||
42 | + "snakes.lang.python", | ||
43 | + "snakes.lang.abcd", | ||
44 | + "snakes.lang.ctlstar", | ||
45 | + "snakes.plugins", | ||
46 | + "snakes.utils", | ||
47 | + "snakes.utils.abcd", | ||
48 | + "snakes.utils.ctlstar", | ||
49 | + ], | ||
50 | + data_files=(doc_files() | ||
51 | + + [("share/emacs/site-lisp", ["utils/abcd-mode.el", | ||
52 | + "utils/abcd-mode.elc"])]), | ||
53 | + ) |
snakes/__init__.py
0 → 100644
1 | +"""SNAKES is the Net Algebra Kit for Editors and Simulators | ||
2 | + | ||
3 | +@author: Franck Pommereau | ||
4 | +@organization: University of Paris 12 | ||
5 | +@copyright: (C) 2005 Franck Pommereau | ||
6 | +@license: GNU Lesser General Public Licence (aka. GNU LGPL), | ||
7 | + see the file C{doc/COPYING} in the distribution or visit U{the GNU | ||
8 | + web site<http://www.gnu.org/licenses/licenses.html#LGPL>} | ||
9 | +@contact: pommereau@univ-paris12.fr | ||
10 | + | ||
11 | +SNAKES is a Python library allowing to model all sorts of Petri nets | ||
12 | +and to execute them. It is very general as most Petri nets annotations | ||
13 | +can be arbitrary Python expressions while most values can be arbitrary | ||
14 | +Python objects. | ||
15 | + | ||
16 | +SNAKES can be further extended with plugins, several ones being | ||
17 | +already provided, in particular two plugins implement the Petri nets | ||
18 | +compositions defined for the Petri Box Calculus and its successors. | ||
19 | +""" | ||
20 | + | ||
21 | +version = "0.9.16" | ||
22 | +defaultencoding = "utf-8" | ||
23 | + | ||
24 | +class SnakesError (Exception) : | ||
25 | + "An error in SNAKES" | ||
26 | + pass | ||
27 | + | ||
28 | +class ConstraintError (SnakesError) : | ||
29 | + "Violation of a constraint" | ||
30 | + pass | ||
31 | + | ||
32 | +class NodeError (SnakesError) : | ||
33 | + "Error related to a place or a transition" | ||
34 | + pass | ||
35 | + | ||
36 | +class DomainError (SnakesError) : | ||
37 | + "Function applied out of its domain" | ||
38 | + pass | ||
39 | + | ||
40 | +class ModeError (SnakesError) : | ||
41 | + "The modes of a transition cannot be found" | ||
42 | + pass | ||
43 | + | ||
44 | +class PluginError (SnakesError) : | ||
45 | + "Error when adding a plugin" | ||
46 | + pass | ||
47 | + | ||
48 | +class UnificationError (SnakesError) : | ||
49 | + "Error while unifying parameters" | ||
50 | + pass |
snakes/compat.py
0 → 100644
1 | +"""Python 2 and 3 compatibility layer | ||
2 | +""" | ||
3 | + | ||
4 | +import sys | ||
5 | + | ||
6 | +try : | ||
7 | + xrange | ||
8 | +except NameError : | ||
9 | + xrange = range | ||
10 | + | ||
11 | +try : | ||
12 | + reduce | ||
13 | +except NameError : | ||
14 | + from functools import reduce | ||
15 | + | ||
16 | +try : | ||
17 | + import StringIO as io | ||
18 | +except ImportError : | ||
19 | + import io | ||
20 | + | ||
21 | +try : | ||
22 | + next | ||
23 | +except NameError : | ||
24 | + def next (obj) : | ||
25 | + return obj.next() | ||
26 | + | ||
27 | +PY3 = sys.version > "3" |
snakes/data.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/hashables.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/__init__.py
0 → 100644
1 | +import sys | ||
2 | +if sys.version_info[:2] in ((2, 6), (2, 7)) : | ||
3 | + import ast | ||
4 | +elif sys.version_info[0] == 3 : | ||
5 | + import ast | ||
6 | +elif hasattr(sys, "pypy_version_info") : | ||
7 | + import astpypy as ast | ||
8 | +elif hasattr(sys, "JYTHON_JAR") : | ||
9 | + import astjy25 as ast | ||
10 | +elif sys.version_info[:2] == (2, 5) : | ||
11 | + import astpy25 as ast | ||
12 | +else : | ||
13 | + raise NotImplementedError("unsupported Python version") | ||
14 | + | ||
15 | +sys.modules["snkast"] = ast | ||
16 | + | ||
17 | +from . import unparse as _unparse | ||
18 | +from snakes.compat import * | ||
19 | + | ||
20 | +class Names (ast.NodeVisitor) : | ||
21 | + def __init__ (self) : | ||
22 | + ast.NodeVisitor.__init__(self) | ||
23 | + self.names = set() | ||
24 | + def visit_Name (self, node) : | ||
25 | + self.names.add(node.id) | ||
26 | + | ||
27 | +def getvars (expr) : | ||
28 | + """ | ||
29 | + >>> list(sorted(getvars('x+y<z'))) | ||
30 | + ['x', 'y', 'z'] | ||
31 | + >>> list(sorted(getvars('x+y<z+f(3,t)'))) | ||
32 | + ['f', 't', 'x', 'y', 'z'] | ||
33 | + """ | ||
34 | + names = Names() | ||
35 | + names.visit(ast.parse(expr)) | ||
36 | + return names.names - set(['None', 'True', 'False']) | ||
37 | + | ||
38 | +class Unparser(_unparse.Unparser) : | ||
39 | + boolops = {"And": 'and', "Or": 'or'} | ||
40 | + def _Interactive (self, tree) : | ||
41 | + for stmt in tree.body : | ||
42 | + self.dispatch(stmt) | ||
43 | + def _Expression (self, tree) : | ||
44 | + self.dispatch(tree.body) | ||
45 | + def _ClassDef(self, tree): | ||
46 | + self.write("\n") | ||
47 | + for deco in tree.decorator_list: | ||
48 | + self.fill("@") | ||
49 | + self.dispatch(deco) | ||
50 | + self.fill("class "+tree.name) | ||
51 | + if tree.bases: | ||
52 | + self.write("(") | ||
53 | + for a in tree.bases: | ||
54 | + self.dispatch(a) | ||
55 | + self.write(", ") | ||
56 | + self.write(")") | ||
57 | + self.enter() | ||
58 | + self.dispatch(tree.body) | ||
59 | + self.leave() | ||
60 | + | ||
61 | +def unparse (st) : | ||
62 | + output = io.StringIO() | ||
63 | + Unparser(st, output) | ||
64 | + return output.getvalue().strip() | ||
65 | + | ||
66 | +class Renamer (ast.NodeTransformer) : | ||
67 | + def __init__ (self, map_names) : | ||
68 | + ast.NodeTransformer.__init__(self) | ||
69 | + self.map = [map_names] | ||
70 | + def visit_ListComp (self, node) : | ||
71 | + bind = self.map[-1].copy() | ||
72 | + for comp in node.generators : | ||
73 | + for name in getvars(comp.target) : | ||
74 | + if name in bind : | ||
75 | + del bind[name] | ||
76 | + self.map.append(bind) | ||
77 | + node.elt = self.visit(node.elt) | ||
78 | + self.map.pop(-1) | ||
79 | + return node | ||
80 | + def visit_SetComp (self, node) : | ||
81 | + return self.visit_ListComp(node) | ||
82 | + def visit_DictComp (self, node) : | ||
83 | + bind = self.map[-1].copy() | ||
84 | + for comp in node.generators : | ||
85 | + for name in getvars(comp.target) : | ||
86 | + if name in bind : | ||
87 | + del bind[name] | ||
88 | + self.map.append(bind) | ||
89 | + node.key = self.visit(node.key) | ||
90 | + node.value = self.visit(node.value) | ||
91 | + self.map.pop(-1) | ||
92 | + return node | ||
93 | + def visit_Name (self, node) : | ||
94 | + return ast.copy_location(ast.Name(id=self.map[-1].get(node.id, | ||
95 | + node.id), | ||
96 | + ctx=ast.Load()), node) | ||
97 | + | ||
98 | +def rename (expr, map={}, **ren) : | ||
99 | + """ | ||
100 | + >>> rename('x+y<z', x='t') | ||
101 | + '((t + y) < z)' | ||
102 | + >>> rename('x+y<z+f(3,t)', f='g', t='z', z='t') | ||
103 | + '((x + y) < (t + g(3, z)))' | ||
104 | + >>> rename('[x+y for x in range(3)]', x='z') | ||
105 | + '[(x + y) for x in range(3)]' | ||
106 | + >>> rename('[x+y for x in range(3)]', y='z') | ||
107 | + '[(x + z) for x in range(3)]' | ||
108 | + """ | ||
109 | + map_names = dict(map) | ||
110 | + map_names.update(ren) | ||
111 | + transf = Renamer(map_names) | ||
112 | + return unparse(transf.visit(ast.parse(expr))) | ||
113 | + | ||
114 | +class Binder (Renamer) : | ||
115 | + def visit_Name (self, node) : | ||
116 | + if node.id in self.map[-1] : | ||
117 | + return self.map[-1][node.id] | ||
118 | + else : | ||
119 | + return node | ||
120 | + | ||
121 | +def bind (expr, map={}, **ren) : | ||
122 | + """ | ||
123 | + >>> bind('x+y<z', x=ast.Num(n=2)) | ||
124 | + '((2 + y) < z)' | ||
125 | + >>> bind('x+y<z', y=ast.Num(n=2)) | ||
126 | + '((x + 2) < z)' | ||
127 | + >>> bind('[x+y for x in range(3)]', x=ast.Num(n=2)) | ||
128 | + '[(x + y) for x in range(3)]' | ||
129 | + >>> bind('[x+y for x in range(3)]', y=ast.Num(n=2)) | ||
130 | + '[(x + 2) for x in range(3)]' | ||
131 | + """ | ||
132 | + map_names = dict(map) | ||
133 | + map_names.update(ren) | ||
134 | + transf = Binder(map_names) | ||
135 | + return unparse(transf.visit(ast.parse(expr))) | ||
136 | + | ||
137 | +if __name__ == "__main__" : | ||
138 | + import doctest | ||
139 | + doctest.testmod() |
snakes/lang/abcd/__init__.py
0 → 100644
File mode changed
snakes/lang/abcd/abcd.asdl
0 → 100644
1 | +module ABCD version "$Revision: 1 $" | ||
2 | +{ | ||
3 | + abcd = AbcdSpec(decl* context, process body, expr* asserts) | ||
4 | + | ||
5 | + decl = AbcdTypedef(identifier name, abcdtype type) | ||
6 | + | AbcdBuffer(identifier name, abcdtype type, | ||
7 | + Slice? capacity, expr content) | ||
8 | + | AbcdSymbol(identifier* symbols) | ||
9 | + | AbcdConst(identifier name, expr value) | ||
10 | + | AbcdNet(identifier name, arguments args, AbcdSpec body) | ||
11 | + | AbcdTask(identifier name, AbcdSpec body, | ||
12 | + abcdtype* input, ancdtype* output) | ||
13 | + | stmt -- this too much, but does not harm | ||
14 | + | ||
15 | + attributes (int lineno, int col_offset) | ||
16 | + | ||
17 | + process = AbcdAction(access* accesses, object guard) | ||
18 | + | AbcdFlowOp(process left, flowop op, process right) | ||
19 | + | AbcdInstance(identifier net, identifier? asname, expr* args, | ||
20 | + keyword* keywords, expr? starargs, expr? kwargs) | ||
21 | + | ||
22 | + attributes (int lineno, int col_offset) | ||
23 | + | ||
24 | + flowop = Sequence | Choice | Parallel | Loop | ||
25 | + | ||
26 | + access = SimpleAccess(identifier buffer, arc arc, expr tokens) | ||
27 | + | FlushAccess(identifier buffer, identifier target) | ||
28 | + | SwapAccess(identifier buffer, expr target, expr tokens) | ||
29 | + | Spawn(identifier net, expr pid, expr args) | ||
30 | + | Wait(identifier net, expr pid, expr args) | ||
31 | + | Suspend(identifier net, expr pid) | ||
32 | + | Resume(identifier net, expr pid) | ||
33 | + | ||
34 | + attributes (int lineno, int col_offset) | ||
35 | + | ||
36 | + arc = Produce | Test | Consume | Fill | ||
37 | + | ||
38 | + abcdtype = UnionType(abcdtype* types) | ||
39 | + | IntersectionType(abcdtype* types) | ||
40 | + | CrossType(abcdtype* types) | ||
41 | + | ListType(abcdtype items) | ||
42 | + | TupleType(abcdtype items) | ||
43 | + | SetType(abcdtype items) | ||
44 | + | DictType(abcdtype keys, abcdtype values) | ||
45 | + | EnumType(expr* items) | ||
46 | + | NamedType(identifier name) | ||
47 | + | ||
48 | + attributes (int lineno, int col_offset) | ||
49 | + | ||
50 | + -------------------------------------------------------------- | ||
51 | + -- the rest is copied from "snakes/lang/python/python.asdl" -- | ||
52 | + -------------------------------------------------------------- | ||
53 | + | ||
54 | + stmt = FunctionDef(identifier name, arguments args, | ||
55 | + stmt* body, expr* decorator_list, expr? returns) | ||
56 | + | ClassDef(identifier name, | ||
57 | + expr* bases, | ||
58 | + keyword* keywords, | ||
59 | + expr? starargs, | ||
60 | + expr? kwargs, | ||
61 | + stmt* body, | ||
62 | + expr *decorator_list) | ||
63 | + | Return(expr? value) | ||
64 | + | ||
65 | + | Delete(expr* targets) | ||
66 | + | Assign(expr* targets, expr value) | ||
67 | + | AugAssign(expr target, operator op, expr value) | ||
68 | + | ||
69 | + | For(expr target, expr iter, stmt* body, stmt* orelse) | ||
70 | + | While(expr test, stmt* body, stmt* orelse) | ||
71 | + | If(expr test, stmt* body, stmt* orelse) | ||
72 | + | With(expr context_expr, expr? optional_vars, stmt* body) | ||
73 | + | ||
74 | + | Raise(expr? exc, expr? cause) | ||
75 | + | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) | ||
76 | + | TryFinally(stmt* body, stmt* finalbody) | ||
77 | + | Assert(expr test, expr? msg) | ||
78 | + | ||
79 | + | Import(alias* names) | ||
80 | + | ImportFrom(identifier module, alias* names, int? level) | ||
81 | + | ||
82 | + | Exec(expr body, expr? globals, expr? locals) | ||
83 | + | ||
84 | + | Global(identifier* names) | ||
85 | + | Nonlocal(identifier* names) | ||
86 | + | Expr(expr value) | ||
87 | + | Pass | Break | Continue | ||
88 | + | ||
89 | + attributes (int lineno, int col_offset) | ||
90 | + | ||
91 | + expr = BoolOp(boolop op, expr* values) | ||
92 | + | BinOp(expr left, operator op, expr right) | ||
93 | + | UnaryOp(unaryop op, expr operand) | ||
94 | + | Lambda(arguments args, expr body) | ||
95 | + | IfExp(expr test, expr body, expr orelse) | ||
96 | + | Dict(expr* keys, expr* values) | ||
97 | + | Set(expr* elts) | ||
98 | + | ListComp(expr elt, comprehension* generators) | ||
99 | + | SetComp(expr elt, comprehension* generators) | ||
100 | + | DictComp(expr key, expr value, comprehension* generators) | ||
101 | + | GeneratorExp(expr elt, comprehension* generators) | ||
102 | + | Yield(expr? value) | ||
103 | + | Compare(expr left, cmpop* ops, expr* comparators) | ||
104 | + | Call(expr func, expr* args, keyword* keywords, | ||
105 | + expr? starargs, expr? kwargs) | ||
106 | + | Num(object n) | ||
107 | + | Str(string s) | ||
108 | + | Ellipsis | ||
109 | + | ||
110 | + | Attribute(expr value, identifier attr, expr_context ctx) | ||
111 | + | Subscript(expr value, slice slice, expr_context ctx) | ||
112 | + | Starred(expr value, expr_context ctx) | ||
113 | + | Name(identifier id, expr_context ctx) | ||
114 | + | List(expr* elts, expr_context ctx) | ||
115 | + | Tuple(expr* elts, expr_context ctx) | ||
116 | + | ||
117 | + attributes (int lineno, int col_offset) | ||
118 | + | ||
119 | + expr_context = Load | Store | Del | AugLoad | AugStore | Param | ||
120 | + | ||
121 | + slice = Slice(expr? lower, expr? upper, expr? step) | ||
122 | + | ExtSlice(slice* dims) | ||
123 | + | Index(expr value) | ||
124 | + | ||
125 | + boolop = And | Or | ||
126 | + | ||
127 | + operator = Add | Sub | Mult | Div | Mod | Pow | LShift | ||
128 | + | RShift | BitOr | BitXor | BitAnd | FloorDiv | ||
129 | + | ||
130 | + unaryop = Invert | Not | UAdd | USub | ||
131 | + | ||
132 | + cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn | ||
133 | + | ||
134 | + comprehension = (expr target, expr iter, expr* ifs) | ||
135 | + | ||
136 | + excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) | ||
137 | + attributes (int lineno, int col_offset) | ||
138 | + | ||
139 | + arguments = (arg* args, identifier? vararg, expr? varargannotation, | ||
140 | + arg* kwonlyargs, identifier? kwarg, | ||
141 | + expr? kwargannotation, expr* defaults, | ||
142 | + expr* kw_defaults) | ||
143 | + arg = (identifier arg, expr? annotation) | ||
144 | + | ||
145 | + keyword = (identifier arg, expr value) | ||
146 | + | ||
147 | + alias = (identifier name, identifier? asname) | ||
148 | +} |
snakes/lang/abcd/abcd.pgen
0 → 100644
1 | +# Grammar for ABCD | ||
2 | + | ||
3 | +# new tokens | ||
4 | +$QUESTION '?' | ||
5 | +$ELLIPSIS '...' | ||
6 | + | ||
7 | +file_input: abcd_main ENDMARKER | ||
8 | + | ||
9 | +abcd_main: (NEWLINE | abcd_global)* abcd_expr abcd_prop* | ||
10 | +abcd_global: import_stmt | abcd_symbol | abcd_typedef | abcd_const | abcd_decl | ||
11 | +abcd_spec: (NEWLINE | abcd_decl)* abcd_expr | ||
12 | +abcd_decl: abcd_net | abcd_task | abcd_buffer | ||
13 | + | ||
14 | +abcd_const: 'const' NAME '=' testlist | ||
15 | +abcd_symbol: 'symbol' abcd_namelist | ||
16 | +abcd_typedef: 'typedef' NAME ':' abcd_type | ||
17 | +abcd_net: 'net' NAME parameters ':' abcd_suite | ||
18 | +abcd_task: 'task' NAME typelist '-' '>' typelist ':' abcd_suite | ||
19 | +abcd_suite: abcd_expr | NEWLINE INDENT abcd_spec DEDENT | ||
20 | +abcd_buffer: [ decorators ] 'buffer' NAME ['[' test ']'] ':' abcd_type '=' testlist | ||
21 | + | ||
22 | +abcd_namelist: NAME (',' NAME)* | ||
23 | +typelist: '(' [abcd_type (',' abcd_type)*] ')' | ||
24 | + | ||
25 | +abcd_type: abcd_and_type ('|' abcd_and_type)* | ||
26 | +abcd_and_type: abcd_cross_type ('&' abcd_cross_type)* | ||
27 | +abcd_cross_type: abcd_base_type ('*' abcd_base_type)* | ||
28 | +abcd_base_type: (NAME ['(' abcd_type (',' abcd_type)* ')'] | ||
29 | + | 'enum' '(' test (',' test)* ')' | '(' abcd_type ')') | ||
30 | + | ||
31 | +abcd_expr: abcd_choice_expr ('|' abcd_choice_expr)* | ||
32 | +abcd_choice_expr: abcd_iter_expr ('+' abcd_iter_expr)* | ||
33 | +abcd_iter_expr: abcd_seq_expr ('*' abcd_seq_expr)* | ||
34 | +abcd_seq_expr: abcd_base_expr (';' abcd_base_expr)* | ||
35 | +abcd_base_expr: (abcd_action | '(' abcd_expr ')') (NEWLINE)* | ||
36 | +abcd_action: ('[' 'True' ']' | | ||
37 | + '[' 'False' ']' | | ||
38 | + '[' abcd_access_list ['if' test] ']' | | ||
39 | + abcd_instance) | ||
40 | +abcd_access_list: abcd_access (',' abcd_access)* | ||
41 | +abcd_access: (NAME '+' '(' testlist ')' | | ||
42 | + NAME '?' '(' testlist ')' | | ||
43 | + NAME '-' '(' testlist ')' | | ||
44 | + NAME '<>' '(' testlist '=' testlist ')' | | ||
45 | + NAME '>>' '(' NAME ')' | | ||
46 | + NAME '<<' '(' testlist_comp ')' | | ||
47 | + NAME '.' NAME '(' test (',' test)* ')') | ||
48 | +abcd_instance: [NAME ':' ':'] NAME '(' [arglist] ')' | ||
49 | + | ||
50 | +tfpdef: NAME [':' ('net' | 'buffer' | 'task')] | ||
51 | + | ||
52 | +abcd_prop: 'assert' test (NEWLINE)* | ||
53 | + | ||
54 | +# | ||
55 | +# the rest is from SNAKES/Python grammar | ||
56 | +# | ||
57 | + | ||
58 | +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE | ||
59 | +decorators: decorator+ | ||
60 | +decorated: decorators (classdef | funcdef) | ||
61 | +funcdef: 'def' NAME parameters ['-' '>' test] ':' suite | ||
62 | +parameters: '(' [typedargslist] ')' | ||
63 | +typedargslist: ((tfpdef ['=' test] ',')* | ||
64 | + ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | ||
65 | + | '**' tfpdef) | ||
66 | + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) | ||
67 | +varargslist: ((vfpdef ['=' test] ',')* | ||
68 | + ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | ||
69 | + | '**' vfpdef) | ||
70 | + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) | ||
71 | +vfpdef: NAME | ||
72 | + | ||
73 | +stmt: simple_stmt | compound_stmt | ||
74 | +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE | ||
75 | +small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | | ||
76 | + import_stmt | global_stmt | nonlocal_stmt | assert_stmt) | ||
77 | +expr_stmt: testlist (augassign (yield_expr|testlist) | | ||
78 | + ('=' (yield_expr|testlist))*) | ||
79 | +augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | | ||
80 | + '<<=' | '>>=' | '**=' | '//=') | ||
81 | +del_stmt: 'del' exprlist | ||
82 | +pass_stmt: 'pass' | ||
83 | +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt | ||
84 | +break_stmt: 'break' | ||
85 | +continue_stmt: 'continue' | ||
86 | +return_stmt: 'return' [testlist] | ||
87 | +yield_stmt: yield_expr | ||
88 | +raise_stmt: 'raise' [test ['from' test]] | ||
89 | +import_stmt: import_name | import_from | ||
90 | +import_name: 'import' dotted_as_names | ||
91 | +import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) | ||
92 | + 'import' ('*' | '(' import_as_names ')' | import_as_names)) | ||
93 | +import_as_name: NAME ['as' NAME] | ||
94 | +dotted_as_name: dotted_name ['as' NAME] | ||
95 | +import_as_names: import_as_name (',' import_as_name)* [','] | ||
96 | +dotted_as_names: dotted_as_name (',' dotted_as_name)* | ||
97 | +dotted_name: NAME ('.' NAME)* | ||
98 | +global_stmt: 'global' NAME (',' NAME)* | ||
99 | +nonlocal_stmt: 'nonlocal' NAME (',' NAME)* | ||
100 | +assert_stmt: 'assert' test [',' test] | ||
101 | + | ||
102 | +compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | ||
103 | + | funcdef | classdef | decorated) | ||
104 | +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] | ||
105 | +while_stmt: 'while' test ':' suite ['else' ':' suite] | ||
106 | +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] | ||
107 | +try_stmt: ('try' ':' suite | ||
108 | + ((except_clause ':' suite)+ | ||
109 | + ['else' ':' suite] | ||
110 | + ['finally' ':' suite] | | ||
111 | + 'finally' ':' suite)) | ||
112 | +with_stmt: 'with' test [ with_var ] ':' suite | ||
113 | +with_var: 'as' expr | ||
114 | +except_clause: 'except' [test ['as' NAME]] | ||
115 | +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT | ||
116 | + | ||
117 | +test: or_test ['if' or_test 'else' test] | lambdef | ||
118 | +test_nocond: or_test | lambdef_nocond | ||
119 | +lambdef: 'lambda' [varargslist] ':' test | ||
120 | +lambdef_nocond: 'lambda' [varargslist] ':' test_nocond | ||
121 | +or_test: and_test ('or' and_test)* | ||
122 | +and_test: not_test ('and' not_test)* | ||
123 | +not_test: 'not' not_test | comparison | ||
124 | +comparison: star_expr (comp_op star_expr)* | ||
125 | +comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'<>'|'in'|'not' 'in'|'is'|'is' 'not' | ||
126 | +star_expr: ['*'] expr | ||
127 | +expr: xor_expr ('|' xor_expr)* | ||
128 | +xor_expr: and_expr ('^' and_expr)* | ||
129 | +and_expr: shift_expr ('&' shift_expr)* | ||
130 | +shift_expr: arith_expr (('<<'|'>>') arith_expr)* | ||
131 | +arith_expr: term (('+'|'-') term)* | ||
132 | +term: factor (('*'|'/'|'%'|'//') factor)* | ||
133 | +factor: ('+'|'-'|'~') factor | power | ||
134 | +power: atom trailer* ['**' factor] | ||
135 | +atom: ('(' [yield_expr|testlist_comp] ')' | | ||
136 | + '[' [testlist_comp] ']' | | ||
137 | + '{' [dictorsetmaker] '}' | | ||
138 | + NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') | ||
139 | +testlist_comp: test ( comp_for | (',' test)* [','] ) | ||
140 | +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME | ||
141 | +subscriptlist: subscript (',' subscript)* [','] | ||
142 | +subscript: test | [test] ':' [test] [sliceop] | ||
143 | +sliceop: ':' [test] | ||
144 | +exprlist: star_expr (',' star_expr)* [','] | ||
145 | +testlist: test (',' test)* [','] | ||
146 | +dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | | ||
147 | + (test (comp_for | (',' test)* [','])) ) | ||
148 | + | ||
149 | +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite | ||
150 | + | ||
151 | +arglist: (argument ',')* (argument [','] | ||
152 | + |'*' test (',' argument)* [',' '**' test] | ||
153 | + |'**' test) | ||
154 | +argument: test [comp_for] | test '=' test | ||
155 | + | ||
156 | +comp_iter: comp_for | comp_if | ||
157 | +comp_for: 'for' exprlist 'in' or_test [comp_iter] | ||
158 | +comp_if: 'if' test_nocond [comp_iter] | ||
159 | + | ||
160 | +yield_expr: 'yield' [testlist] |
snakes/lang/abcd/asdl.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/abcd/parser.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/abcd/pgen.py
0 → 100644
This diff could not be displayed because it is too large.
snakes/lang/asdl.py
0 → 100644
1 | +import sys, datetime | ||
2 | +from snakes.lang.pylib import asdl | ||
3 | +from collections import defaultdict | ||
4 | +from functools import partial | ||
5 | + | ||
6 | +class memoize(object): | ||
7 | + def __init__(self, function): | ||
8 | + self.function = function | ||
9 | + self.memoized = {} | ||
10 | + | ||
11 | + def __call__(self, *args): | ||
12 | + try: | ||
13 | + return self.memoized[args] | ||
14 | + except KeyError: | ||
15 | + call = self.function(*args) | ||
16 | + self.memoized[args] = call | ||
17 | + return call | ||
18 | + | ||
19 | + def __get__(self, obj, objtype): | ||
20 | + """Support instance methods.""" | ||
21 | + return partial(self.__call__, obj) | ||
22 | + | ||
23 | +def component_has_cycle(node, graph, proceeding, visited): | ||
24 | + if node in visited: | ||
25 | + return False | ||
26 | + if node in proceeding: | ||
27 | + proceeding.append(node) # populate trace | ||
28 | + return True | ||
29 | + proceeding.append(node) | ||
30 | + if node in graph: | ||
31 | + for successor in graph[node]: | ||
32 | + if component_has_cycle(successor, graph, proceeding, visited): | ||
33 | + return True | ||
34 | + proceeding.remove(node) | ||
35 | + visited.add(node) | ||
36 | + return False | ||
37 | + | ||
38 | +def has_cycle(graph): | ||
39 | + visited = set() | ||
40 | + proceeding = list() | ||
41 | + todo = set(graph.keys()) | ||
42 | + | ||
43 | + while todo: | ||
44 | + node = todo.pop() | ||
45 | + if component_has_cycle(node, graph, proceeding, visited): | ||
46 | + i = proceeding.index(proceeding[-1]) | ||
47 | + return proceeding[i:] | ||
48 | + todo.difference_update(visited) | ||
49 | + return [] | ||
50 | + | ||
51 | +class CyclicDependencies(Exception): | ||
52 | + def __init__(self, seq): | ||
53 | + self.seq = seq | ||
54 | + | ||
55 | + def __str__(self): | ||
56 | + return "cyclic dependencies: {}".format(" -> ".join(self.seq)) | ||
57 | + | ||
58 | +def remove_duplicates(l): | ||
59 | + d = {} | ||
60 | + nl = [] | ||
61 | + for e in l: | ||
62 | + if not e in d: | ||
63 | + d[e] = 1 | ||
64 | + nl.append(e) | ||
65 | + return nl | ||
66 | + | ||
67 | +class CodeGen (asdl.VisitorBase) : | ||
68 | + | ||
69 | + def __init__(self, node): | ||
70 | + asdl.VisitorBase.__init__(self) | ||
71 | + | ||
72 | + self.starting_node = None | ||
73 | + self.current_node = None | ||
74 | + self.hierarchy = defaultdict(list) | ||
75 | + self.hierarchy['_AST'] = [] | ||
76 | + self.fields = defaultdict(list) | ||
77 | + self.attributes = defaultdict(list) | ||
78 | + self.code = defaultdict(list) | ||
79 | + | ||
80 | + self.visit(node) | ||
81 | + ret = has_cycle(self.hierarchy) | ||
82 | + if ret: | ||
83 | + raise CyclicDependencies(ret) | ||
84 | + self._gen_code(node) | ||
85 | + | ||
86 | + def visitModule(self, node): | ||
87 | + for name, child in node.types.items(): | ||
88 | + if not self.starting_node: | ||
89 | + self.starting_node = str(name) | ||
90 | + self.current_node = str(name) | ||
91 | + self.hierarchy[name] | ||
92 | + self.visit(child) | ||
93 | + | ||
94 | + def visitSum(self, node): | ||
95 | + if hasattr(node, "fields"): | ||
96 | + self.fields[self.current_node] = node.fields | ||
97 | + else: | ||
98 | + self.fields[self.current_node] = [] | ||
99 | + if hasattr(node, "attributes"): | ||
100 | + self.attributes[self.current_node] = node.attributes | ||
101 | + else: | ||
102 | + self.attributes[self.current_node] = [] | ||
103 | + | ||
104 | + for child in node.types: | ||
105 | + self.visit(child) | ||
106 | + | ||
107 | + def visitConstructor (self, node): | ||
108 | + if str(node.name) in self.fields: | ||
109 | + #print >> sys.stderr, "constructor '{!s}' appears twice !".format(node.name) | ||
110 | + #exit(0) | ||
111 | + return | ||
112 | + self.fields[str(node.name)].extend(node.fields) | ||
113 | + self.hierarchy[str(node.name)].append(self.current_node) | ||
114 | + | ||
115 | + def visitProduct(self, node): | ||
116 | + self.fields[self.current_node].extend(node.fields) | ||
117 | + | ||
118 | + @memoize | ||
119 | + def _get_fields(self, name): | ||
120 | + if self.fields.has_key(name): | ||
121 | + fields = map(lambda f : f.name, self.fields[name]) | ||
122 | + for parent in self.hierarchy[name]: | ||
123 | + fields.extend(self._get_fields(parent)) | ||
124 | + return fields | ||
125 | + else: | ||
126 | + return [] | ||
127 | + | ||
128 | + @memoize | ||
129 | + def _get_attributes(self, name): | ||
130 | + if name == '_AST': | ||
131 | + return [] | ||
132 | + attributes = map(lambda a : a.name, self.attributes[name]) | ||
133 | + for parent in self.hierarchy[name]: | ||
134 | + attributes.extend(self._get_attributes(parent)) | ||
135 | + return attributes | ||
136 | + | ||
137 | + def _gen_code(self, node): | ||
138 | + is_methods = [] | ||
139 | + for name in sorted(self.hierarchy): | ||
140 | + if name != '_AST': | ||
141 | + is_methods.extend(["", | ||
142 | + "def is{!s}(self):".format(name), | ||
143 | + ["return False"] | ||
144 | + ]) | ||
145 | + cls = ["class _AST (ast.AST):", | ||
146 | + ["_fields = ()", | ||
147 | + "_attributes = ()", | ||
148 | + "", | ||
149 | + "def __init__ (self, **ARGS):", | ||
150 | + ["ast.AST.__init__(self)", | ||
151 | + "for k, v in ARGS.items():", | ||
152 | + ["setattr(self, k, v)"] | ||
153 | + ] | ||
154 | + ] + is_methods | ||
155 | + ] | ||
156 | + self.code['_AST'] = cls | ||
157 | + | ||
158 | + for name, parents in self.hierarchy.iteritems(): | ||
159 | + if name == '_AST': | ||
160 | + continue | ||
161 | + if not parents: | ||
162 | + parents = ['_AST'] | ||
163 | + fields = self.fields[name] | ||
164 | + args = [] | ||
165 | + assign = [] | ||
166 | + body = [] | ||
167 | + _fields = remove_duplicates(self._get_fields(name)) | ||
168 | + _attributes = remove_duplicates(self._get_attributes(name)) | ||
169 | + | ||
170 | + body = [] | ||
171 | + cls = ["class {!s} ({!s}):".format(name, ", ".join(parents)), body] | ||
172 | + | ||
173 | + non_default_args = [] | ||
174 | + default_args = [] | ||
175 | + for f in fields: | ||
176 | + if f.name.value == 'ctx': | ||
177 | + f.opt = True | ||
178 | + | ||
179 | + if f.opt: | ||
180 | + default_args.append("{!s}=None".format(f.name)) | ||
181 | + assign.append("self.{0!s} = {0!s}".format(f.name)) | ||
182 | + elif f.seq: | ||
183 | + default_args.append("{!s}=[]".format(f.name)) | ||
184 | + assign.append("self.{0!s} = list({0!s})".format(f.name)) | ||
185 | + else: | ||
186 | + non_default_args.append("{!s}".format(f.name)) | ||
187 | + assign.append("self.{0!s} = {0!s}".format(f.name)) | ||
188 | + | ||
189 | + args = non_default_args + default_args | ||
190 | + | ||
191 | + body.append("_fields = {!r}".format( tuple(map(repr, _fields)))) | ||
192 | + body.append("_attributes = {!r}".format( tuple(map(repr, _attributes)))) | ||
193 | + body.append("") | ||
194 | + # ctor | ||
195 | + args_str = ", ".join(args) | ||
196 | + if args_str != "": | ||
197 | + args_str += ", " | ||
198 | + body.append("def __init__ (self, {!s} **ARGS):".format(args_str)) | ||
199 | + ctor_body = [] | ||
200 | + body.append(ctor_body) | ||
201 | + ctor_body.extend(map(lambda base : "{!s}.__init__(self, **ARGS)".format(base), parents)) | ||
202 | + ctor_body.extend(assign) | ||
203 | + | ||
204 | + body.extend(["", "def is{}(self):".format(name), ["return True"]]) | ||
205 | + | ||
206 | + self.code[name] = cls | ||
207 | + | ||
208 | + @memoize | ||
209 | + def _cost(self, name): | ||
210 | + # print "call cost {}".format(name) | ||
211 | + if name == '_AST': | ||
212 | + return 0 | ||
213 | + parents = self.hierarchy[name] | ||
214 | + return reduce(lambda acc, x: acc + self._cost(x), parents, 1) | ||
215 | + | ||
216 | + @property | ||
217 | + def python(self): | ||
218 | + | ||
219 | + classes = self.hierarchy.keys() | ||
220 | + classes.sort(lambda a, b: self._cost(a) - self._cost(b)) | ||
221 | + | ||
222 | + code = ["from snakes.lang import ast", | ||
223 | + "from ast import *", | ||
224 | + ""] | ||
225 | + | ||
226 | + for cls in classes: | ||
227 | + code.extend(self.code[cls]) | ||
228 | + code.append("") | ||
229 | + | ||
230 | + def python (code, indent) : | ||
231 | + for line in code : | ||
232 | + if isinstance(line, str) : | ||
233 | + yield (4*indent) * " " + line | ||
234 | + else : | ||
235 | + for sub in python(line, indent+1) : | ||
236 | + yield sub | ||
237 | + return "\n".join(python(code, 0)) | ||
238 | + | ||
239 | +def compile_asdl(infilename, outfilename): | ||
240 | + """ Helper function to compile asdl files. """ | ||
241 | + | ||
242 | + infile = open(infilename, 'r') | ||
243 | + outfile = open(outfilename, 'w') | ||
244 | + | ||
245 | + scanner = asdl.ASDLScanner() | ||
246 | + parser = asdl.ASDLParser() | ||
247 | + tokens = scanner.tokenize(infile.read()) | ||
248 | + node = parser.parse(tokens) | ||
249 | + | ||
250 | + outfile.write(("# this file has been automatically generated running:\n" | ||
251 | + "# %s\n# timestamp: %s\n\n") % (" ".join(sys.argv), | ||
252 | + datetime.datetime.now())) | ||
253 | + outfile.write(CodeGen(node).python) | ||
254 | + outfile.close() | ||
255 | + infile.close() | ||
256 | + | ||
257 | +if __name__ == "__main__": | ||
258 | + # a simple CLI | ||
259 | + import getopt | ||
260 | + outfile = sys.stdout | ||
261 | + try : | ||
262 | + opts, args = getopt.getopt(sys.argv[1:], "ho:", | ||
263 | + ["help", "output="]) | ||
264 | + if ("-h", "") in opts or ("--help", "") in opts : | ||
265 | + opts = [("-h", "")] | ||
266 | + args = [None] | ||
267 | + elif not args : | ||
268 | + raise getopt.GetoptError("no input file provided" | ||
269 | + " (try -h to get help)") | ||
270 | + elif len(args) > 1 : | ||
271 | + raise getopt.GetoptError("more than one input file provided") | ||
272 | + except getopt.GetoptError : | ||
273 | + sys.stderr.write("%s: %s\n" % (__file__, sys.exc_info()[1])) | ||
274 | + sys.exit(1) | ||
275 | + for (flag, arg) in opts : | ||
276 | + if flag in ("-h", "--help") : | ||
277 | + print("""usage: %s [OPTIONS] INFILE | ||
278 | + Options: | ||
279 | + -h, --help print this help and exit | ||
280 | + --output=OUTPUT set output file""" % __file__) | ||
281 | + sys.exit(0) | ||
282 | + elif flag in ("-o", "--output") : | ||
283 | + outfile = open(arg, "w") | ||
284 | + scanner = asdl.ASDLScanner() | ||
285 | + parser = asdl.ASDLParser() | ||
286 | + tokens = scanner.tokenize(open(args[0]).read()) | ||
287 | + node = parser.parse(tokens) | ||
288 | + outfile.write(("# this file has been automatically generated running:\n" | ||
289 | + "# %s\n# timestamp: %s\n\n") % (" ".join(sys.argv), | ||
290 | + datetime.datetime.now())) | ||
291 | + try: | ||
292 | + outfile.write(CodeGen(node).python) | ||
293 | + except CyclicDependencies as cycle: | ||
294 | + msg = "[E] {!s}".format(cycle) | ||
295 | + outfile.write(msg) | ||
296 | + if outfile != sys.stdout: | ||
297 | + print >> sys.stderr, msg | ||
298 | + outfile.close() |
snakes/lang/astjy25.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/astpy25.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/astpypy.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/ctlstar/__init__.py
0 → 100644
File mode changed
snakes/lang/ctlstar/asdl.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/ctlstar/ctlstar.asdl
0 → 100644
1 | +module CTLstar version "$Revision: 1 $" | ||
2 | +{ | ||
3 | + ctlstar = Spec(ctldecl* atoms, ctldecl* properties, form? main) | ||
4 | + attributes (int lineno, int col_offset) | ||
5 | + | ||
6 | + ctldecl = Atom(identifier name, ctlarg* args, ctlparams* params, | ||
7 | + stmt* body) | ||
8 | + | Property(identifier name, ctlargs* args, | ||
9 | + ctlparams* params, form body) | ||
10 | + attributes (int lineno, int col_offset) | ||
11 | + | ||
12 | + ctlarg = Place(identifier name, string place) | ||
13 | + | Token(identifier name, string place) | ||
14 | + | Argument(identifier name, expr value, identifier type) | ||
15 | + attributes (int lineno, int col_offset) | ||
16 | + | ||
17 | + ctlparam = Parameter(identifier name, identifier type) | ||
18 | + attributes (int lineno, int col_offset) | ||
19 | + | ||
20 | + form = atom | ||
21 | + | CtlUnary(ctlunary op, form child) | ||
22 | + | CtlBinary(ctlbinary op, form left, form right) | ||
23 | + attributes (int lineno, int col_offset) | ||
24 | + | ||
25 | + ctlunary = notop | All | Exists | Next | Future | Globally | ||
26 | + | ||
27 | + notop = Not | ||
28 | + | ||
29 | + ctlbinary = boolop | Imply | Iff | Until | WeakUntil | Release | ||
30 | + | ||
31 | + atom = InPlace(expr* data, ctlarg place) | ||
32 | + | NotInPlace(expr* data, ctlarg place) | ||
33 | + | EmptyPlace(ctlarg place) | ||
34 | + | MarkedPlace(ctlarg place) | ||
35 | + | Deadlock | ||
36 | + | Boolean(bool val) | ||
37 | + | Instance(identifier name, arg* args) | ||
38 | + | Quantifier(ctlunary op, | ||
39 | + identifier* vars, | ||
40 | + ctlarg place, | ||
41 | + form child, | ||
42 | + bool distinct) | ||
43 | + attributes (int lineno, int col_offset) | ||
44 | + | ||
45 | + -------------------------------------------------------------- | ||
46 | + -- the rest is copied from "snakes/lang/python/python.asdl" -- | ||
47 | + -------------------------------------------------------------- | ||
48 | + | ||
49 | + stmt = FunctionDef(identifier name, arguments args, | ||
50 | + stmt* body, expr* decorator_list, expr? returns) | ||
51 | + | ClassDef(identifier name, | ||
52 | + expr* bases, | ||
53 | + keyword* keywords, | ||
54 | + expr? starargs, | ||
55 | + expr? kwargs, | ||
56 | + stmt* body, | ||
57 | + expr *decorator_list) | ||
58 | + | Return(expr? value) | ||
59 | + | ||
60 | + | Delete(expr* targets) | ||
61 | + | Assign(expr* targets, expr value) | ||
62 | + | AugAssign(expr target, operator op, expr value) | ||
63 | + | ||
64 | + | For(expr target, expr iter, stmt* body, stmt* orelse) | ||
65 | + | While(expr test, stmt* body, stmt* orelse) | ||
66 | + | If(expr test, stmt* body, stmt* orelse) | ||
67 | + | With(expr context_expr, expr? optional_vars, stmt* body) | ||
68 | + | ||
69 | + | Raise(expr? exc, expr? cause) | ||
70 | + | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) | ||
71 | + | TryFinally(stmt* body, stmt* finalbody) | ||
72 | + | Assert(expr test, expr? msg) | ||
73 | + | ||
74 | + | Import(alias* names) | ||
75 | + | ImportFrom(identifier module, alias* names, int? level) | ||
76 | + | ||
77 | + | Exec(expr body, expr? globals, expr? locals) | ||
78 | + | ||
79 | + | Global(identifier* names) | ||
80 | + | Nonlocal(identifier* names) | ||
81 | + | Expr(expr value) | ||
82 | + | Pass | Break | Continue | ||
83 | + | ||
84 | + attributes (int lineno, int col_offset) | ||
85 | + | ||
86 | + expr = BoolOp(boolop op, expr* values) | ||
87 | + | BinOp(expr left, operator op, expr right) | ||
88 | + | UnaryOp(unaryop op, expr operand) | ||
89 | + | Lambda(arguments args, expr body) | ||
90 | + | IfExp(expr test, expr body, expr orelse) | ||
91 | + | Dict(expr* keys, expr* values) | ||
92 | + | Set(expr* elts) | ||
93 | + | ListComp(expr elt, comprehension* generators) | ||
94 | + | SetComp(expr elt, comprehension* generators) | ||
95 | + | DictComp(expr key, expr value, comprehension* generators) | ||
96 | + | GeneratorExp(expr elt, comprehension* generators) | ||
97 | + | Yield(expr? value) | ||
98 | + | Compare(expr left, cmpop* ops, expr* comparators) | ||
99 | + | Call(expr func, expr* args, keyword* keywords, | ||
100 | + expr? starargs, expr? kwargs) | ||
101 | + | Num(object n) | ||
102 | + | Str(string s) | ||
103 | + | Ellipsis | ||
104 | + | ||
105 | + | Attribute(expr value, identifier attr, expr_context ctx) | ||
106 | + | Subscript(expr value, slice slice, expr_context ctx) | ||
107 | + | Starred(expr value, expr_context ctx) | ||
108 | + | Name(identifier id, expr_context ctx) | ||
109 | + | List(expr* elts, expr_context ctx) | ||
110 | + | Tuple(expr* elts, expr_context ctx) | ||
111 | + | ||
112 | + attributes (int lineno, int col_offset) | ||
113 | + | ||
114 | + expr_context = Load | Store | Del | AugLoad | AugStore | Param | ||
115 | + | ||
116 | + slice = Slice(expr? lower, expr? upper, expr? step) | ||
117 | + | ExtSlice(slice* dims) | ||
118 | + | Index(expr value) | ||
119 | + | ||
120 | + boolop = And | Or | ||
121 | + | ||
122 | + operator = Add | Sub | Mult | Div | Mod | Pow | LShift | ||
123 | + | RShift | BitOr | BitXor | BitAnd | FloorDiv | ||
124 | + | ||
125 | + unaryop = Invert | notop | UAdd | USub | ||
126 | + | ||
127 | + cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn | ||
128 | + | ||
129 | + comprehension = (expr target, expr iter, expr* ifs) | ||
130 | + | ||
131 | + excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) | ||
132 | + attributes (int lineno, int col_offset) | ||
133 | + | ||
134 | + arguments = (arg* args, identifier? vararg, expr? varargannotation, | ||
135 | + arg* kwonlyargs, identifier? kwarg, | ||
136 | + expr? kwargannotation, expr* defaults, | ||
137 | + expr* kw_defaults) | ||
138 | + arg = (identifier arg, expr? annotation) | ||
139 | + | ||
140 | + keyword = (identifier arg, expr value) | ||
141 | + | ||
142 | + alias = (identifier name, identifier? asname) | ||
143 | +} |
snakes/lang/ctlstar/ctlstar.pgen
0 → 100644
1 | +# Grammar for (permissive) CTL* | ||
2 | + | ||
3 | +# new tokens | ||
4 | +$ELLIPSIS '...' | ||
5 | + | ||
6 | +file_input: (NEWLINE | ctl_atomdef | ctl_propdef)* [ ctl_formula ] NEWLINE* ENDMARKER | ||
7 | + | ||
8 | +ctl_atomdef: 'atom' NAME '(' [ctl_parameters] ')' ':' suite | ||
9 | +ctl_propdef: 'prop' NAME '(' [ctl_parameters] ')' ':' ctl_suite | ||
10 | +ctl_suite: ( ctl_formula NEWLINE | ||
11 | + | NEWLINE INDENT ctl_formula NEWLINE+ DEDENT ) | ||
12 | +ctl_parameters: (ctl_param ',')* ctl_param | ||
13 | +ctl_param: NAME ( '=' '@' STRING+ | ':' NAME ) | ||
14 | + | ||
15 | +ctl_formula: ctl_or_formula [ ctl_connector ctl_or_formula ] | ||
16 | +ctl_connector: ( '=' '>' | '<=' '>' ) | ||
17 | +ctl_or_formula: ctl_and_formula ('or' ctl_and_formula)* | ||
18 | +ctl_and_formula: ctl_not_formula ('and' ctl_not_formula)* | ||
19 | +ctl_not_formula: ('not' ctl_not_formula | ctl_binary_formula) | ||
20 | +ctl_binary_formula: ctl_unary_formula [ ctl_binary_op ctl_unary_formula ] | ||
21 | +ctl_unary_formula: [ ctl_unary_op ] (ctl_atom_formula | '(' ctl_formula ')') | ||
22 | +ctl_unary_op: ('A' | 'G' | 'F' | 'E' | 'X') | ||
23 | +ctl_binary_op: ('R' | 'U' | 'W') | ||
24 | +ctl_atom_formula: ( 'empty' '(' ctl_place ')' | ||
25 | + | 'marked' '(' ctl_place ')' | ||
26 | + | 'has' ['not'] '(' ctl_place ',' test (',' test)* ')' | ||
27 | + | 'deadlock' | 'True' | 'False' | ||
28 | + | NAME '(' ctl_arguments ')' | ||
29 | + | 'forall' [ 'distinct' ] NAME (',' NAME)* | ||
30 | + 'in' ctl_place '(' ctl_atom_formula ')' | ||
31 | + | 'exists' [ 'distinct' ] NAME (',' NAME)* | ||
32 | + 'in' ctl_place '(' ctl_atom_formula ')' ) | ||
33 | +ctl_arguments: (NAME '=' ctl_place_or_test ',')* NAME '=' ctl_place_or_test | ||
34 | +ctl_place: '@' STRING+ | NAME | ||
35 | +ctl_place_or_test: test | '@' STRING+ | ||
36 | + | ||
37 | +# | ||
38 | +# the rest is from SNAKES/Python grammar | ||
39 | +# | ||
40 | + | ||
41 | +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE | ||
42 | +decorators: decorator+ | ||
43 | +decorated: decorators (classdef | funcdef) | ||
44 | +funcdef: 'def' NAME parameters ['-' '>' test] ':' suite | ||
45 | +parameters: '(' [typedargslist] ')' | ||
46 | +typedargslist: ((tfpdef ['=' test] ',')* | ||
47 | + ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | ||
48 | + | '**' tfpdef) | ||
49 | + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) | ||
50 | +tfpdef: NAME [':' test] | ||
51 | +varargslist: ((vfpdef ['=' test] ',')* | ||
52 | + ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | ||
53 | + | '**' vfpdef) | ||
54 | + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) | ||
55 | +vfpdef: NAME | ||
56 | + | ||
57 | +stmt: simple_stmt | compound_stmt | ||
58 | +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE | ||
59 | +small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | | ||
60 | + import_stmt | global_stmt | nonlocal_stmt | assert_stmt) | ||
61 | +expr_stmt: testlist (augassign (yield_expr|testlist) | | ||
62 | + ('=' (yield_expr|testlist))*) | ||
63 | +augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | | ||
64 | + '<<=' | '>>=' | '**=' | '//=') | ||
65 | +del_stmt: 'del' exprlist | ||
66 | +pass_stmt: 'pass' | ||
67 | +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt | ||
68 | +break_stmt: 'break' | ||
69 | +continue_stmt: 'continue' | ||
70 | +return_stmt: 'return' [testlist] | ||
71 | +yield_stmt: yield_expr | ||
72 | +raise_stmt: 'raise' [test ['from' test]] | ||
73 | +import_stmt: import_name | import_from | ||
74 | +import_name: 'import' dotted_as_names | ||
75 | +import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) | ||
76 | + 'import' ('*' | '(' import_as_names ')' | import_as_names)) | ||
77 | +import_as_name: NAME ['as' NAME] | ||
78 | +dotted_as_name: dotted_name ['as' NAME] | ||
79 | +import_as_names: import_as_name (',' import_as_name)* [','] | ||
80 | +dotted_as_names: dotted_as_name (',' dotted_as_name)* | ||
81 | +dotted_name: NAME ('.' NAME)* | ||
82 | +global_stmt: 'global' NAME (',' NAME)* | ||
83 | +nonlocal_stmt: 'nonlocal' NAME (',' NAME)* | ||
84 | +assert_stmt: 'assert' test [',' test] | ||
85 | + | ||
86 | +compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | ||
87 | + | funcdef | classdef | decorated) | ||
88 | +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] | ||
89 | +while_stmt: 'while' test ':' suite ['else' ':' suite] | ||
90 | +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] | ||
91 | +try_stmt: ('try' ':' suite | ||
92 | + ((except_clause ':' suite)+ | ||
93 | + ['else' ':' suite] | ||
94 | + ['finally' ':' suite] | | ||
95 | + 'finally' ':' suite)) | ||
96 | +with_stmt: 'with' test [ with_var ] ':' suite | ||
97 | +with_var: 'as' expr | ||
98 | +except_clause: 'except' [test ['as' NAME]] | ||
99 | +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT | ||
100 | + | ||
101 | +test: or_test ['if' or_test 'else' test] | lambdef | ||
102 | +test_nocond: or_test | lambdef_nocond | ||
103 | +lambdef: 'lambda' [varargslist] ':' test | ||
104 | +lambdef_nocond: 'lambda' [varargslist] ':' test_nocond | ||
105 | +or_test: and_test ('or' and_test)* | ||
106 | +and_test: not_test ('and' not_test)* | ||
107 | +not_test: 'not' not_test | comparison | ||
108 | +comparison: star_expr (comp_op star_expr)* | ||
109 | +comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'<>'|'in'|'not' 'in'|'is'|'is' 'not' | ||
110 | +star_expr: ['*'] expr | ||
111 | +expr: xor_expr ('|' xor_expr)* | ||
112 | +xor_expr: and_expr ('^' and_expr)* | ||
113 | +and_expr: shift_expr ('&' shift_expr)* | ||
114 | +shift_expr: arith_expr (('<<'|'>>') arith_expr)* | ||
115 | +arith_expr: term (('+'|'-') term)* | ||
116 | +term: factor (('*'|'/'|'%'|'//') factor)* | ||
117 | +factor: ('+'|'-'|'~') factor | power | ||
118 | +power: atom trailer* ['**' factor] | ||
119 | +atom: ('(' [yield_expr|testlist_comp] ')' | | ||
120 | + '[' [testlist_comp] ']' | | ||
121 | + '{' [dictorsetmaker] '}' | | ||
122 | + NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') | ||
123 | +testlist_comp: test ( comp_for | (',' test)* [','] ) | ||
124 | +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME | ||
125 | +subscriptlist: subscript (',' subscript)* [','] | ||
126 | +subscript: test | [test] ':' [test] [sliceop] | ||
127 | +sliceop: ':' [test] | ||
128 | +exprlist: star_expr (',' star_expr)* [','] | ||
129 | +testlist: test (',' test)* [','] | ||
130 | +dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | | ||
131 | + (test (comp_for | (',' test)* [','])) ) | ||
132 | + | ||
133 | +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite | ||
134 | + | ||
135 | +arglist: (argument ',')* (argument [','] | ||
136 | + |'*' test (',' argument)* [',' '**' test] | ||
137 | + |'**' test) | ||
138 | +argument: test [comp_for] | test '=' test | ||
139 | + | ||
140 | +comp_iter: comp_for | comp_if | ||
141 | +comp_for: 'for' exprlist 'in' or_test [comp_iter] | ||
142 | +comp_if: 'if' test_nocond [comp_iter] | ||
143 | + | ||
144 | +yield_expr: 'yield' [testlist] |
snakes/lang/ctlstar/parser.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/ctlstar/pgen.py
0 → 100644
This diff could not be displayed because it is too large.
snakes/lang/pgen.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/pylib/__init__.py
0 → 100644
File mode changed
snakes/lang/pylib/asdl.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/pylib/spark.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/pylib/unparse.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/python/__init__.py
0 → 100644
File mode changed
snakes/lang/python/asdl.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/python/parser.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/lang/python/pgen.py
0 → 100644
This diff could not be displayed because it is too large.
snakes/lang/python/python.asdl
0 → 100644
1 | +module Python version "$Revision: SNAKES $" | ||
2 | +{ | ||
3 | + mod = Module(stmt* body) | ||
4 | + | Interactive(stmt* body) | ||
5 | + | Expression(expr body) | ||
6 | + | Suite(stmt* body) | ||
7 | + | ||
8 | + stmt = FunctionDef(identifier name, arguments args, | ||
9 | + stmt* body, expr* decorator_list, expr? returns) | ||
10 | + | ClassDef(identifier name, | ||
11 | + expr* bases, | ||
12 | + keyword* keywords, | ||
13 | + expr? starargs, | ||
14 | + expr? kwargs, | ||
15 | + stmt* body, | ||
16 | + expr *decorator_list) | ||
17 | + | Return(expr? value) | ||
18 | + | ||
19 | + | Delete(expr* targets) | ||
20 | + | Assign(expr* targets, expr value) | ||
21 | + | AugAssign(expr target, operator op, expr value) | ||
22 | + | ||
23 | + | For(expr target, expr iter, stmt* body, stmt* orelse) | ||
24 | + | While(expr test, stmt* body, stmt* orelse) | ||
25 | + | If(expr test, stmt* body, stmt* orelse) | ||
26 | + | With(expr context_expr, expr? optional_vars, stmt* body) | ||
27 | + | ||
28 | + | Raise(expr? exc, expr? cause) | ||
29 | + | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) | ||
30 | + | TryFinally(stmt* body, stmt* finalbody) | ||
31 | + | Assert(expr test, expr? msg) | ||
32 | + | ||
33 | + | Import(alias* names) | ||
34 | + | ImportFrom(identifier module, alias* names, int? level) | ||
35 | + | ||
36 | + | Exec(expr body, expr? globals, expr? locals) | ||
37 | + | ||
38 | + | Global(identifier* names) | ||
39 | + | Nonlocal(identifier* names) | ||
40 | + | Expr(expr value) | ||
41 | + | Pass | Break | Continue | ||
42 | + | ||
43 | + attributes (int lineno, int col_offset) | ||
44 | + | ||
45 | + expr = BoolOp(boolop op, expr* values) | ||
46 | + | BinOp(expr left, operator op, expr right) | ||
47 | + | UnaryOp(unaryop op, expr operand) | ||
48 | + | Lambda(arguments args, expr body) | ||
49 | + | IfExp(expr test, expr body, expr orelse) | ||
50 | + | Dict(expr* keys, expr* values) | ||
51 | + | Set(expr* elts) | ||
52 | + | ListComp(expr elt, comprehension* generators) | ||
53 | + | SetComp(expr elt, comprehension* generators) | ||
54 | + | DictComp(expr key, expr value, comprehension* generators) | ||
55 | + | GeneratorExp(expr elt, comprehension* generators) | ||
56 | + | Yield(expr? value) | ||
57 | + | Compare(expr left, cmpop* ops, expr* comparators) | ||
58 | + | Call(expr func, expr* args, keyword* keywords, | ||
59 | + expr? starargs, expr? kwargs) | ||
60 | + | Num(object n) | ||
61 | + | Str(string s) | ||
62 | + | Ellipsis | ||
63 | + | ||
64 | + | Attribute(expr value, identifier attr, expr_context ctx) | ||
65 | + | Subscript(expr value, slice slice, expr_context ctx) | ||
66 | + | Starred(expr value, expr_context ctx) | ||
67 | + | Name(identifier id, expr_context ctx) | ||
68 | + | List(expr* elts, expr_context ctx) | ||
69 | + | Tuple(expr* elts, expr_context ctx) | ||
70 | + | ||
71 | + attributes (int lineno, int col_offset) | ||
72 | + | ||
73 | + expr_context = Load | Store | Del | AugLoad | AugStore | Param | ||
74 | + | ||
75 | + slice = Slice(expr? lower, expr? upper, expr? step) | ||
76 | + | ExtSlice(slice* dims) | ||
77 | + | Index(expr value) | ||
78 | + | ||
79 | + boolop = And | Or | ||
80 | + | ||
81 | + operator = Add | Sub | Mult | Div | Mod | Pow | LShift | ||
82 | + | RShift | BitOr | BitXor | BitAnd | FloorDiv | ||
83 | + | ||
84 | + unaryop = Invert | Not | UAdd | USub | ||
85 | + | ||
86 | + cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn | ||
87 | + | ||
88 | + comprehension = (expr target, expr iter, expr* ifs) | ||
89 | + | ||
90 | + excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) | ||
91 | + attributes (int lineno, int col_offset) | ||
92 | + | ||
93 | + arguments = (arg* args, identifier? vararg, expr? varargannotation, | ||
94 | + arg* kwonlyargs, identifier? kwarg, | ||
95 | + expr? kwargannotation, expr* defaults, | ||
96 | + expr* kw_defaults) | ||
97 | + arg = (identifier arg, expr? annotation) | ||
98 | + | ||
99 | + keyword = (identifier arg, expr value) | ||
100 | + | ||
101 | + alias = (identifier name, identifier? asname) | ||
102 | +} |
snakes/lang/python/python.pgen
0 → 100644
1 | +# Grammar for Python in SNAKES | ||
2 | +# This is a mixture of the grammars from various Python versions | ||
3 | + | ||
4 | +$ELLIPSIS '...' | ||
5 | + | ||
6 | +file_input: (NEWLINE | stmt)* ENDMARKER | ||
7 | + | ||
8 | +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE | ||
9 | +decorators: decorator+ | ||
10 | +decorated: decorators (classdef | funcdef) | ||
11 | +funcdef: 'def' NAME parameters ['-' '>' test] ':' suite | ||
12 | +parameters: '(' [typedargslist] ')' | ||
13 | +typedargslist: ((tfpdef ['=' test] ',')* | ||
14 | + ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | ||
15 | + | '**' tfpdef) | ||
16 | + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) | ||
17 | +tfpdef: NAME [':' test] | ||
18 | +varargslist: ((vfpdef ['=' test] ',')* | ||
19 | + ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | ||
20 | + | '**' vfpdef) | ||
21 | + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) | ||
22 | +vfpdef: NAME | ||
23 | + | ||
24 | +stmt: simple_stmt | compound_stmt | ||
25 | +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE | ||
26 | +small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | | ||
27 | + import_stmt | global_stmt | nonlocal_stmt | assert_stmt) | ||
28 | +expr_stmt: testlist (augassign (yield_expr|testlist) | | ||
29 | + ('=' (yield_expr|testlist))*) | ||
30 | +augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | | ||
31 | + '<<=' | '>>=' | '**=' | '//=') | ||
32 | +del_stmt: 'del' exprlist | ||
33 | +pass_stmt: 'pass' | ||
34 | +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt | ||
35 | +break_stmt: 'break' | ||
36 | +continue_stmt: 'continue' | ||
37 | +return_stmt: 'return' [testlist] | ||
38 | +yield_stmt: yield_expr | ||
39 | +raise_stmt: 'raise' [test ['from' test]] | ||
40 | +import_stmt: import_name | import_from | ||
41 | +import_name: 'import' dotted_as_names | ||
42 | +import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) | ||
43 | + 'import' ('*' | '(' import_as_names ')' | import_as_names)) | ||
44 | +import_as_name: NAME ['as' NAME] | ||
45 | +dotted_as_name: dotted_name ['as' NAME] | ||
46 | +import_as_names: import_as_name (',' import_as_name)* [','] | ||
47 | +dotted_as_names: dotted_as_name (',' dotted_as_name)* | ||
48 | +dotted_name: NAME ('.' NAME)* | ||
49 | +global_stmt: 'global' NAME (',' NAME)* | ||
50 | +nonlocal_stmt: 'nonlocal' NAME (',' NAME)* | ||
51 | +assert_stmt: 'assert' test [',' test] | ||
52 | + | ||
53 | +compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | ||
54 | + | funcdef | classdef | decorated) | ||
55 | +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] | ||
56 | +while_stmt: 'while' test ':' suite ['else' ':' suite] | ||
57 | +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] | ||
58 | +try_stmt: ('try' ':' suite | ||
59 | + ((except_clause ':' suite)+ | ||
60 | + ['else' ':' suite] | ||
61 | + ['finally' ':' suite] | | ||
62 | + 'finally' ':' suite)) | ||
63 | +with_stmt: 'with' test [ with_var ] ':' suite | ||
64 | +with_var: 'as' expr | ||
65 | +except_clause: 'except' [test ['as' NAME]] | ||
66 | +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT | ||
67 | + | ||
68 | +test: or_test ['if' or_test 'else' test] | lambdef | ||
69 | +test_nocond: or_test | lambdef_nocond | ||
70 | +lambdef: 'lambda' [varargslist] ':' test | ||
71 | +lambdef_nocond: 'lambda' [varargslist] ':' test_nocond | ||
72 | +or_test: and_test ('or' and_test)* | ||
73 | +and_test: not_test ('and' not_test)* | ||
74 | +not_test: 'not' not_test | comparison | ||
75 | +comparison: star_expr (comp_op star_expr)* | ||
76 | +comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'<>'|'in'|'not' 'in'|'is'|'is' 'not' | ||
77 | +star_expr: ['*'] expr | ||
78 | +expr: xor_expr ('|' xor_expr)* | ||
79 | +xor_expr: and_expr ('^' and_expr)* | ||
80 | +and_expr: shift_expr ('&' shift_expr)* | ||
81 | +shift_expr: arith_expr (('<<'|'>>') arith_expr)* | ||
82 | +arith_expr: term (('+'|'-') term)* | ||
83 | +term: factor (('*'|'/'|'%'|'//') factor)* | ||
84 | +factor: ('+'|'-'|'~') factor | power | ||
85 | +power: atom trailer* ['**' factor] | ||
86 | +atom: ('(' [yield_expr|testlist_comp] ')' | | ||
87 | + '[' [testlist_comp] ']' | | ||
88 | + '{' [dictorsetmaker] '}' | | ||
89 | + NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') | ||
90 | +testlist_comp: test ( comp_for | (',' test)* [','] ) | ||
91 | +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME | ||
92 | +subscriptlist: subscript (',' subscript)* [','] | ||
93 | +subscript: test | [test] ':' [test] [sliceop] | ||
94 | +sliceop: ':' [test] | ||
95 | +exprlist: star_expr (',' star_expr)* [','] | ||
96 | +testlist: test (',' test)* [','] | ||
97 | +dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | | ||
98 | + (test (comp_for | (',' test)* [','])) ) | ||
99 | + | ||
100 | +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite | ||
101 | + | ||
102 | +arglist: (argument ',')* (argument [','] | ||
103 | + |'*' test (',' argument)* [',' '**' test] | ||
104 | + |'**' test) | ||
105 | +argument: test [comp_for] | test '=' test | ||
106 | + | ||
107 | +comp_iter: comp_for | comp_if | ||
108 | +comp_for: 'for' exprlist 'in' or_test [comp_iter] | ||
109 | +comp_if: 'if' test_nocond [comp_iter] | ||
110 | + | ||
111 | +yield_expr: 'yield' [testlist] |
snakes/lang/unparse.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/nets.py
0 → 100644
This diff could not be displayed because it is too large.
snakes/plugins/__init__.py
0 → 100644
1 | +"""A plugins system. | ||
2 | + | ||
3 | +The first example shows how to load a plugin: we load | ||
4 | +C{snakes.plugins.hello} and plug it into C{snakes.nets}, which results | ||
5 | +in a new module that actually C{snakes.nets} extended by | ||
6 | +C{snakes.plugins.hello}. | ||
7 | + | ||
8 | +>>> import snakes.plugins as plugins | ||
9 | +>>> hello_nets = plugins.load('hello', 'snakes.nets') | ||
10 | +>>> n = hello_nets.PetriNet('N') | ||
11 | +>>> n.hello() | ||
12 | +Hello from N | ||
13 | +>>> n = hello_nets.PetriNet('N', hello='Hi, this is %s!') | ||
14 | +>>> n.hello() | ||
15 | +Hi, this is N! | ||
16 | + | ||
17 | +The next example shows how to simulate the effect of C{import module}: | ||
18 | +we give to C{load} a thrid argument that is the name of the created | ||
19 | +module, from which it becomes possible to import names or C{*}. | ||
20 | + | ||
21 | +B{Warning:} this feature will not work C{load} is not called from the | ||
22 | +module where we then do the C{from ... import ...}. This is exactly | ||
23 | +the same when, from a module C{foo} that you load a module C{bar}: if | ||
24 | +C{bar} loads other modules they will not be imported in C{foo}. | ||
25 | + | ||
26 | +>>> plugins.load('hello', 'snakes.nets', 'another_version') | ||
27 | +<module ...> | ||
28 | +>>> from another_version import PetriNet | ||
29 | +>>> n = PetriNet('another net') | ||
30 | +>>> n.hello() | ||
31 | +Hello from another net | ||
32 | +>>> n = PetriNet('yet another net', hello='Hi, this is %s!') | ||
33 | +>>> n.hello() | ||
34 | +Hi, this is yet another net! | ||
35 | + | ||
36 | +How to define a plugin is explained in the example C{hello}. | ||
37 | +""" | ||
38 | + | ||
39 | +import imp, sys, inspect | ||
40 | +from functools import wraps | ||
41 | + | ||
42 | +def update (module, objects) : | ||
43 | + """Update a module content | ||
44 | + """ | ||
45 | + for obj in objects : | ||
46 | + if isinstance(obj, tuple) : | ||
47 | + try : | ||
48 | + n, o = obj | ||
49 | + except : | ||
50 | + raise ValueError("expected (name, object) and got '%r'" % obj) | ||
51 | + setattr(module, n, o) | ||
52 | + elif inspect.isclass(obj) or inspect.isfunction(obj) : | ||
53 | + setattr(module, obj.__name__, obj) | ||
54 | + else : | ||
55 | + raise ValueError("cannot plug '%r'" % obj) | ||
56 | + | ||
57 | +def build (name, module, *objects) : | ||
58 | + """Builds an extended module. | ||
59 | + | ||
60 | + The parameter C{module} is exactly that taken by the function | ||
61 | + C{extend} of a plugin. This list argument C{objects} holds all the | ||
62 | + objects, constructed in C{extend}, that are extensions of objects | ||
63 | + from C{module}. The resulting value should be returned by | ||
64 | + C{extend}. | ||
65 | + | ||
66 | + @param name: the name of the constructed module | ||
67 | + @type name: C{str} | ||
68 | + @param module: the extended module | ||
69 | + @type module: C{module} | ||
70 | + @param objects: the sub-objects | ||
71 | + @type objects: each is a class object | ||
72 | + @return: the new module | ||
73 | + @rtype: C{module} | ||
74 | + """ | ||
75 | + result = imp.new_module(name) | ||
76 | + result.__dict__.update(module.__dict__) | ||
77 | + update(result, objects) | ||
78 | + result.__plugins__ = (module.__dict__.get("__plugins__", | ||
79 | + (module.__name__,)) | ||
80 | + + (name,)) | ||
81 | + for obj in objects : | ||
82 | + if inspect.isclass(obj) : | ||
83 | + obj.__plugins__ = result.__plugins__ | ||
84 | + return result | ||
85 | + | ||
86 | +def load (plugins, base, name=None) : | ||
87 | + """Load plugins. | ||
88 | + | ||
89 | + C{plugins} can be a single plugin name or module or a list of such | ||
90 | + values. If C{name} is not C{None}, the extended module is loaded | ||
91 | + ad C{name} in C{sys.modules} as well as in the global environment | ||
92 | + from which C{load} was called. | ||
93 | + | ||
94 | + @param plugins: the module that implements the plugin, or its name, | ||
95 | + or a collection of such values | ||
96 | + @type plugins: C{str} or C{module}, or a C{list}/C{tuple}/... of | ||
97 | + such values | ||
98 | + @param base: the module being extended or its name | ||
99 | + @type base: C{str} or C{module} | ||
100 | + @param name: the name of the created module | ||
101 | + @type name: C{str} | ||
102 | + @return: the extended module | ||
103 | + @rtype: C{module} | ||
104 | + """ | ||
105 | + if type(base) is str : | ||
106 | + result = __import__(base, fromlist=["__name__"]) | ||
107 | + else : | ||
108 | + result = base | ||
109 | + if isinstance(plugins, str) : | ||
110 | + plugins = [plugins] | ||
111 | + else : | ||
112 | + try : | ||
113 | + plugins = list(plugins) | ||
114 | + except TypeError : | ||
115 | + plugins = [plugins] | ||
116 | + for i, p in enumerate(plugins) : | ||
117 | + if isinstance(p, str) and not p.startswith("snakes.plugins.") : | ||
118 | + plugins[i] = "snakes.plugins." + p | ||
119 | + for plug in plugins : | ||
120 | + if type(plug) is str : | ||
121 | + plug = __import__(plug, fromlist=["__name__"]) | ||
122 | + result = plug.extend(result) | ||
123 | + if name is not None : | ||
124 | + result.__name__ = name | ||
125 | + sys.modules[name] = result | ||
126 | + inspect.stack()[1][0].f_globals[name] = result | ||
127 | + return result | ||
128 | + | ||
129 | +def plugin (base, depends=[], conflicts=[]) : | ||
130 | + """Decorator for extension functions | ||
131 | + | ||
132 | + @param base: name of base module (usually 'snakes.nets') | ||
133 | + @type base: str | ||
134 | + @param depends: list of plugins on which this one depends | ||
135 | + @type depends: list of str | ||
136 | + @param conflicts: list of plugins with which this one conflicts | ||
137 | + @type conflicts: list of str | ||
138 | + @return: the appropriate decorator | ||
139 | + @rtype: function | ||
140 | + """ | ||
141 | + def wrapper (fun) : | ||
142 | + @wraps(fun) | ||
143 | + def extend (module) : | ||
144 | + try : | ||
145 | + loaded = set(module.__plugins__) | ||
146 | + except AttributeError : | ||
147 | + loaded = set() | ||
148 | + for name in depends : | ||
149 | + if name not in loaded : | ||
150 | + module = load(name, module) | ||
151 | + loaded.update(module.__plugins__) | ||
152 | + conf = set(conflicts) & loaded | ||
153 | + if len(conf) > 0 : | ||
154 | + raise ValueError("plugin conflict (%s)" % ", ".join(conf)) | ||
155 | + objects = fun(module) | ||
156 | + if type(objects) is not tuple : | ||
157 | + objects = (objects,) | ||
158 | + return build(fun.__module__, module, *objects) | ||
159 | + module = sys.modules[fun.__module__] | ||
160 | + module.__test__ = {"extend" : extend} | ||
161 | + objects = fun(__import__(base, fromlist=["__name__"])) | ||
162 | + if type(objects) is not tuple : | ||
163 | + objects = (objects,) | ||
164 | + update(module, objects) | ||
165 | + return extend | ||
166 | + return wrapper | ||
167 | + | ||
168 | +def new_instance (cls, obj) : | ||
169 | + """Create a copy of C{obj} which is an instance of C{cls} | ||
170 | + """ | ||
171 | + result = object.__new__(cls) | ||
172 | + result.__dict__.update(obj.__dict__) | ||
173 | + return result |
snakes/plugins/clusters.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/plugins/gv.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/plugins/hello.py
0 → 100644
1 | +"""An example plugin that allows instances class C{PetriNet} to say hello. | ||
2 | + | ||
3 | +A new method C{hello} is added. The constructor is added a keyword | ||
4 | +argument C{hello} that must be the C{str} to print when calling | ||
5 | +C{hello}, with one C{%s} that will be replaced by the name of the net | ||
6 | +when C{hello} is called. | ||
7 | + | ||
8 | +Defining a plugins need writing a module with a single function called | ||
9 | +C{extend} that takes a single argument that is the module to be | ||
10 | +extended. | ||
11 | + | ||
12 | +Inside the function, extensions of the classes in the module are | ||
13 | +defined as normal sub-classes. | ||
14 | + | ||
15 | +The function C{extend} should return the extended module created by | ||
16 | +C{snakes.plugins.build} that takes as arguments: the name of the | ||
17 | +extended module, the module taken as argument and the sub-classes | ||
18 | +defined (expected as a list argument C{*args} in no special order). | ||
19 | + | ||
20 | +If the plugin depends on other plugins, for instance C{foo} and | ||
21 | +C{bar}, the function C{extend} should be decorated by | ||
22 | +C{@depends('foo', 'bar')}. | ||
23 | + | ||
24 | +Read the source code of this module to have an example | ||
25 | +""" | ||
26 | + | ||
27 | +import snakes.plugins | ||
28 | + | ||
29 | +@snakes.plugins.plugin("snakes.nets") | ||
30 | +def extend (module) : | ||
31 | + """Extends C{module} | ||
32 | + """ | ||
33 | + class PetriNet (module.PetriNet) : | ||
34 | + """Extension of the class C{PetriNet} in C{module} | ||
35 | + """ | ||
36 | + def __init__ (self, name, **args) : | ||
37 | + """When extending an existing method, take care that you | ||
38 | + may be working on an already extended class, so you so not | ||
39 | + know how its arguments have been changed. So, always use | ||
40 | + those from the unextended class plus C{**args}, remove | ||
41 | + from it what your plugin needs and pass it to the method | ||
42 | + of the extended class if you need to call it. | ||
43 | + | ||
44 | + >>> PetriNet('N').hello() | ||
45 | + Hello from N | ||
46 | + >>> PetriNet('N', hello='Hi! This is %s...').hello() | ||
47 | + Hi! This is N... | ||
48 | + | ||
49 | + @param args: plugin options | ||
50 | + @keyword hello: the message to print, with C{%s} where the | ||
51 | + net name should appear. | ||
52 | + @type hello: C{str} | ||
53 | + """ | ||
54 | + self._hello = args.pop("hello", "Hello from %s") | ||
55 | + module.PetriNet.__init__(self, name, **args) | ||
56 | + def hello (self) : | ||
57 | + """A new method C{hello} | ||
58 | + | ||
59 | + >>> n = PetriNet('N') | ||
60 | + >>> n.hello() | ||
61 | + Hello from N | ||
62 | + """ | ||
63 | + print(self._hello % self.name) | ||
64 | + return PetriNet |
snakes/plugins/labels.py
0 → 100644
1 | +"""A plugin to add labels to nodes and nets. | ||
2 | + | ||
3 | +""" | ||
4 | + | ||
5 | +from snakes.plugins import plugin, new_instance | ||
6 | +from snakes.pnml import Tree | ||
7 | + | ||
8 | +@plugin("snakes.nets") | ||
9 | +def extend (module) : | ||
10 | + class Transition (module.Transition) : | ||
11 | + def label (self, *get, **set) : | ||
12 | + if not hasattr(self, "_labels") : | ||
13 | + self._labels = {} | ||
14 | + result = tuple(self._labels[g] for g in get) | ||
15 | + self._labels.update(set) | ||
16 | + if len(get) == 1 : | ||
17 | + return result[0] | ||
18 | + elif len(get) > 1 : | ||
19 | + return result | ||
20 | + elif len(set) == 0 : | ||
21 | + return self._labels.copy() | ||
22 | + def has_label (self, name, *names) : | ||
23 | + if len(names) == 0 : | ||
24 | + return name in self._labels | ||
25 | + else : | ||
26 | + return tuple(n in self._labels for n in (name,) + names) | ||
27 | + def copy (self, name=None, **options) : | ||
28 | + if not hasattr(self, "_labels") : | ||
29 | + self._labels = {} | ||
30 | + result = module.Transition.copy(self, name, **options) | ||
31 | + result._labels = self._labels.copy() | ||
32 | + return result | ||
33 | + def __pnmldump__ (self) : | ||
34 | + """ | ||
35 | + >>> t = Transition('t') | ||
36 | + >>> t.label(foo='bar', spam=42) | ||
37 | + >>> t.__pnmldump__() | ||
38 | + <?xml version="1.0" encoding="utf-8"?> | ||
39 | + <pnml> | ||
40 | + <transition id="t"> | ||
41 | + <label name="foo"> | ||
42 | + <object type="str"> | ||
43 | + bar | ||
44 | + </object> | ||
45 | + </label> | ||
46 | + <label name="spam"> | ||
47 | + <object type="int"> | ||
48 | + 42 | ||
49 | + </object> | ||
50 | + </label> | ||
51 | + </transition> | ||
52 | + </pnml> | ||
53 | + """ | ||
54 | + t = module.Transition.__pnmldump__(self) | ||
55 | + if hasattr(self, "_labels") : | ||
56 | + for key, val in self._labels.items() : | ||
57 | + t.add_child(Tree("label", None, | ||
58 | + Tree.from_obj(val), | ||
59 | + name=key)) | ||
60 | + return t | ||
61 | + @classmethod | ||
62 | + def __pnmlload__ (cls, tree) : | ||
63 | + """ | ||
64 | + >>> old = Transition('t') | ||
65 | + >>> old.label(foo='bar', spam=42) | ||
66 | + >>> p = old.__pnmldump__() | ||
67 | + >>> new = Transition.__pnmlload__(p) | ||
68 | + >>> new | ||
69 | + Transition('t', Expression('True')) | ||
70 | + >>> new.__class__ | ||
71 | + <class 'snakes.plugins.labels.Transition'> | ||
72 | + >>> new.label('foo', 'spam') | ||
73 | + ('bar', 42) | ||
74 | + """ | ||
75 | + t = new_instance(cls, module.Transition.__pnmlload__(tree)) | ||
76 | + t._labels = dict((lbl["name"], lbl.child().to_obj()) | ||
77 | + for lbl in tree.get_children("label")) | ||
78 | + return t | ||
79 | + class Place (module.Place) : | ||
80 | + def label (self, *get, **set) : | ||
81 | + if not hasattr(self, "_labels") : | ||
82 | + self._labels = {} | ||
83 | + result = tuple(self._labels[g] for g in get) | ||
84 | + self._labels.update(set) | ||
85 | + if len(get) == 1 : | ||
86 | + return result[0] | ||
87 | + elif len(get) > 1 : | ||
88 | + return result | ||
89 | + elif len(set) == 0 : | ||
90 | + return self._labels.copy() | ||
91 | + def has_label (self, name, *names) : | ||
92 | + if len(names) == 0 : | ||
93 | + return name in self._labels | ||
94 | + else : | ||
95 | + return tuple(n in self._labels for n in (name,) + names) | ||
96 | + def copy (self, name=None, **options) : | ||
97 | + if not hasattr(self, "_labels") : | ||
98 | + self._labels = {} | ||
99 | + result = module.Place.copy(self, name, **options) | ||
100 | + result._labels = self._labels.copy() | ||
101 | + return result | ||
102 | + def __pnmldump__ (self) : | ||
103 | + """ | ||
104 | + >>> p = Place('p') | ||
105 | + >>> p.label(foo='bar', spam=42) | ||
106 | + >>> p.__pnmldump__() | ||
107 | + <?xml version="1.0" encoding="utf-8"?> | ||
108 | + <pnml> | ||
109 | + <place id="p"> | ||
110 | + <type domain="universal"/> | ||
111 | + <initialMarking> | ||
112 | + <multiset/> | ||
113 | + </initialMarking> | ||
114 | + <label name="foo"> | ||
115 | + <object type="str"> | ||
116 | + bar | ||
117 | + </object> | ||
118 | + </label> | ||
119 | + <label name="spam"> | ||
120 | + <object type="int"> | ||
121 | + 42 | ||
122 | + </object> | ||
123 | + </label> | ||
124 | + </place> | ||
125 | + </pnml> | ||
126 | + """ | ||
127 | + t = module.Place.__pnmldump__(self) | ||
128 | + if hasattr(self, "_labels") : | ||
129 | + for key, val in self._labels.items() : | ||
130 | + t.add_child(Tree("label", None, | ||
131 | + Tree.from_obj(val), | ||
132 | + name=key)) | ||
133 | + return t | ||
134 | + @classmethod | ||
135 | + def __pnmlload__ (cls, tree) : | ||
136 | + """ | ||
137 | + >>> old = Place('p') | ||
138 | + >>> old.label(foo='bar', spam=42) | ||
139 | + >>> p = old.__pnmldump__() | ||
140 | + >>> new = Place.__pnmlload__(p) | ||
141 | + >>> new | ||
142 | + Place('p', MultiSet([]), tAll) | ||
143 | + >>> new.__class__ | ||
144 | + <class 'snakes.plugins.labels.Place'> | ||
145 | + >>> new.label('foo', 'spam') | ||
146 | + ('bar', 42) | ||
147 | + """ | ||
148 | + p = new_instance(cls, module.Place.__pnmlload__(tree)) | ||
149 | + p._labels = dict((lbl["name"], lbl.child().to_obj()) | ||
150 | + for lbl in tree.get_children("label")) | ||
151 | + return p | ||
152 | + class PetriNet (module.PetriNet) : | ||
153 | + def label (self, *get, **set) : | ||
154 | + if not hasattr(self, "_labels") : | ||
155 | + self._labels = {} | ||
156 | + result = tuple(self._labels[g] for g in get) | ||
157 | + self._labels.update(set) | ||
158 | + if len(get) == 1 : | ||
159 | + return result[0] | ||
160 | + elif len(get) > 1 : | ||
161 | + return result | ||
162 | + elif len(set) == 0 : | ||
163 | + return self._labels.copy() | ||
164 | + def has_label (self, name, *names) : | ||
165 | + if len(names) == 0 : | ||
166 | + return name in self._labels | ||
167 | + else : | ||
168 | + return tuple(n in self._labels for n in (name,) + names) | ||
169 | + def copy (self, name=None, **options) : | ||
170 | + if not hasattr(self, "_labels") : | ||
171 | + self._labels = {} | ||
172 | + result = module.PetriNet.copy(self, name, **options) | ||
173 | + result._labels = self._labels.copy() | ||
174 | + return result | ||
175 | + def __pnmldump__ (self) : | ||
176 | + """ | ||
177 | + >>> n = PetriNet('n') | ||
178 | + >>> n.label(foo='bar', spam=42) | ||
179 | + >>> n.__pnmldump__() | ||
180 | + <?xml version="1.0" encoding="utf-8"?> | ||
181 | + <pnml> | ||
182 | + <net id="n"> | ||
183 | + <label name="foo"> | ||
184 | + <object type="str"> | ||
185 | + bar | ||
186 | + </object> | ||
187 | + </label> | ||
188 | + <label name="spam"> | ||
189 | + <object type="int"> | ||
190 | + 42 | ||
191 | + </object> | ||
192 | + </label> | ||
193 | + </net> | ||
194 | + </pnml> | ||
195 | + """ | ||
196 | + t = module.PetriNet.__pnmldump__(self) | ||
197 | + if hasattr(self, "_labels") : | ||
198 | + for key, val in self._labels.items() : | ||
199 | + t.add_child(Tree("label", None, | ||
200 | + Tree.from_obj(val), | ||
201 | + name=key)) | ||
202 | + return t | ||
203 | + @classmethod | ||
204 | + def __pnmlload__ (cls, tree) : | ||
205 | + """ | ||
206 | + >>> old = PetriNet('n') | ||
207 | + >>> old.label(foo='bar', spam=42) | ||
208 | + >>> p = old.__pnmldump__() | ||
209 | + >>> new = PetriNet.__pnmlload__(p) | ||
210 | + >>> new | ||
211 | + PetriNet('n') | ||
212 | + >>> new.__class__ | ||
213 | + <class 'snakes.plugins.labels.PetriNet'> | ||
214 | + >>> new.label('foo', 'spam') | ||
215 | + ('bar', 42) | ||
216 | + """ | ||
217 | + n = new_instance(cls, module.PetriNet.__pnmlload__(tree)) | ||
218 | + n._labels = dict((lbl["name"], lbl.child().to_obj()) | ||
219 | + for lbl in tree.get_children("label")) | ||
220 | + return n | ||
221 | + def merge_places (self, target, sources, **options) : | ||
222 | + module.PetriNet.merge_places(self, target, sources, **options) | ||
223 | + new = self.place(target) | ||
224 | + for place in sources : | ||
225 | + new.label(**dict(self.place(place).label())) | ||
226 | + def merge_transitions (self, target, sources, **options) : | ||
227 | + module.PetriNet.merge_transitions(self, target, sources, **options) | ||
228 | + new = self.transition(target) | ||
229 | + for trans in sources : | ||
230 | + new.label(**dict(self.transition(trans).label())) | ||
231 | + return Transition, Place, PetriNet |
snakes/plugins/ops.py
0 → 100644
1 | +"""A plugin to compose nets. | ||
2 | + | ||
3 | +The compositions are based on place status and automatically merge | ||
4 | +some nodes (buffers and variables, tick transitions). | ||
5 | + | ||
6 | +>>> import snakes.plugins | ||
7 | +>>> snakes.plugins.load('ops', 'snakes.nets', 'nets') | ||
8 | +<module ...> | ||
9 | +>>> from nets import * | ||
10 | +>>> from snakes.plugins.status import entry, internal, exit, buffer | ||
11 | +>>> basic = PetriNet('basic') | ||
12 | +>>> basic.add_place(Place('e', status=entry)) | ||
13 | +>>> basic.add_place(Place('x', status=exit)) | ||
14 | +>>> basic.add_transition(Transition('t')) | ||
15 | +>>> basic.add_input('e', 't', Value(1)) | ||
16 | +>>> basic.add_output('x', 't', Value(2)) | ||
17 | +>>> basic.add_place(Place('b', [1], status=buffer('buf'))) | ||
18 | + | ||
19 | +>>> n = basic.copy() | ||
20 | +>>> n.hide(entry) | ||
21 | +>>> n.node('e').status | ||
22 | +Status(None) | ||
23 | +>>> n.hide(buffer('buf'), buffer(None)) | ||
24 | +>>> n.node('b').status | ||
25 | +Buffer('buffer') | ||
26 | + | ||
27 | +>>> n = basic / 'buf' | ||
28 | +>>> n.node('[b/buf]').status | ||
29 | +Buffer('buffer') | ||
30 | + | ||
31 | +>>> n = basic & basic | ||
32 | +>>> n.status(internal) | ||
33 | +('[x&e]',) | ||
34 | +>>> n.place('[x&e]').pre | ||
35 | +{'[t&]': Value(2)} | ||
36 | +>>> n.place('[x&e]').post | ||
37 | +{'[&t]': Value(1)} | ||
38 | +>>> n.status(buffer('buf')) | ||
39 | +('[b&b]',) | ||
40 | + | ||
41 | +>>> n = basic + basic | ||
42 | +>>> n.status(entry) | ||
43 | +('[e+e]',) | ||
44 | +>>> list(sorted(n.place('[e+e]').post.items())) | ||
45 | +[('[+t]', Value(1)), ('[t+]', Value(1))] | ||
46 | +>>> n.status(exit) | ||
47 | +('[x+x]',) | ||
48 | +>>> list(sorted(n.place('[x+x]').pre.items())) | ||
49 | +[('[+t]', Value(2)), ('[t+]', Value(2))] | ||
50 | + | ||
51 | +>>> n = basic * basic | ||
52 | +>>> n.status(entry) | ||
53 | +('[e,x*e]',) | ||
54 | +>>> n.place('[e,x*e]').post | ||
55 | +{'[t*]': Value(1), '[*t]': Value(1)} | ||
56 | +>>> n.place('[e,x*e]').pre | ||
57 | +{'[t*]': Value(2)} | ||
58 | + | ||
59 | +>>> n1 = basic.copy() | ||
60 | +>>> n1.declare('global x; x=1') | ||
61 | +>>> n2 = basic.copy() | ||
62 | +>>> n2.globals['y'] = 2 | ||
63 | +>>> n = n1 + n2 | ||
64 | +>>> n.globals['x'], n.globals['y'] | ||
65 | +(1, 2) | ||
66 | +>>> n._declare | ||
67 | +['global x; x=1'] | ||
68 | +""" | ||
69 | + | ||
70 | +import snakes.plugins | ||
71 | +from snakes.plugins.status import Status, entry, exit, internal | ||
72 | +from snakes.data import cross | ||
73 | +from snakes.plugins.clusters import Cluster | ||
74 | + | ||
75 | +def _glue (op, one, two) : | ||
76 | + result = one.__class__("(%s%s%s)" % (one.name, op, two.name)) | ||
77 | + def new (name) : | ||
78 | + return "[%s%s]" % (name, op) | ||
79 | + for net in (one, two) : | ||
80 | + result.clusters.add_child(Cluster()) | ||
81 | + result._declare = list(set(result._declare) | set(net._declare)) | ||
82 | + result.globals.update(net.globals) | ||
83 | + for place in net.place() : | ||
84 | + result.add_place(place.copy(new(place.name)), | ||
85 | + cluster=[-1]+net.clusters.get_path(place.name)) | ||
86 | + for trans in net.transition() : | ||
87 | + result.add_transition(trans.copy(new(trans.name)), | ||
88 | + cluster=[-1]+net.clusters.get_path(trans.name)) | ||
89 | + for place, label in trans.input() : | ||
90 | + result.add_input(new(place.name), | ||
91 | + new(trans.name), | ||
92 | + label.copy()) | ||
93 | + for place, label in trans.output() : | ||
94 | + result.add_output(new(place.name), | ||
95 | + new(trans.name), | ||
96 | + label.copy()) | ||
97 | + def new (name) : | ||
98 | + return "[%s%s]" % (op, name) | ||
99 | + for status in result.status : | ||
100 | + result.status.merge(status) | ||
101 | + new = result.status(status) | ||
102 | + if len(new) == 1 : | ||
103 | + name = "[%s%s%s]" % (",".join(sorted(one.status(status))), | ||
104 | + op, | ||
105 | + ",".join(sorted(two.status(status)))) | ||
106 | + if name != new[0] : | ||
107 | + result.rename_node(new[0], name) | ||
108 | + return result | ||
109 | + | ||
110 | +@snakes.plugins.plugin("snakes.nets", | ||
111 | + depends=["snakes.plugins.clusters", | ||
112 | + "snakes.plugins.status"]) | ||
113 | +def extend (module) : | ||
114 | + "Build the extended module" | ||
115 | + class PetriNet (module.PetriNet) : | ||
116 | + def __or__ (self, other) : | ||
117 | + "Parallel" | ||
118 | + return _glue("|", self, other) | ||
119 | + def __and__ (self, other) : | ||
120 | + "Sequence" | ||
121 | + result = _glue("&", self, other) | ||
122 | + remove = set() | ||
123 | + for x, e in cross((self.status(exit), other.status(entry))) : | ||
124 | + new = "[%s&%s]" % (x, e) | ||
125 | + new_x, new_e = "[%s&]" % x, "[&%s]" % e | ||
126 | + result.merge_places(new, (new_x, new_e), status=internal) | ||
127 | + remove.update((new_x, new_e)) | ||
128 | + for p in remove : | ||
129 | + result.remove_place(p) | ||
130 | + return result | ||
131 | + def __add__ (self, other) : | ||
132 | + "Choice" | ||
133 | + result = _glue("+", self, other) | ||
134 | + for status in (entry, exit) : | ||
135 | + remove = set() | ||
136 | + for l, r in cross((self.status(status), | ||
137 | + other.status(status))) : | ||
138 | + new = "[%s+%s]" % (l, r) | ||
139 | + new_l, new_r = "[%s+]" % l, "[+%s]" % r | ||
140 | + result.merge_places(new, (new_l, new_r), status=status) | ||
141 | + remove.update((new_l, new_r)) | ||
142 | + for p in remove : | ||
143 | + result.remove_place(p) | ||
144 | + return result | ||
145 | + def __mul__ (self, other) : | ||
146 | + "Iteration" | ||
147 | + result = _glue("*", self, other) | ||
148 | + remove = set() | ||
149 | + for e1, x1, e2 in cross((self.status(entry), | ||
150 | + self.status(exit), | ||
151 | + other.status(entry))) : | ||
152 | + new = "[%s,%s*%s]" % (e1, x1, e2) | ||
153 | + new_e1, new_x1 = "[%s*]" % e1, "[%s*]" % x1 | ||
154 | + new_e2 = "[*%s]" % e2 | ||
155 | + result.merge_places(new, (new_e1, new_x1, new_e2), | ||
156 | + status=entry) | ||
157 | + remove.update((new_e1, new_x1, new_e2)) | ||
158 | + for p in remove : | ||
159 | + result.remove_place(p) | ||
160 | + return result | ||
161 | + def hide (self, old, new=None) : | ||
162 | + if new is None : | ||
163 | + new = Status(None) | ||
164 | + for node in self.status(old) : | ||
165 | + self.set_status(node, new) | ||
166 | + def __div__ (self, name) : | ||
167 | + result = self.copy() | ||
168 | + for node in result.node() : | ||
169 | + result.rename_node(node.name, "[%s/%s]" % (node, name)) | ||
170 | + for status in result.status : | ||
171 | + if status._value == name : | ||
172 | + result.hide(status, status.__class__(status._name, None)) | ||
173 | + return result | ||
174 | + def __truediv__ (self, other) : | ||
175 | + return self.__div__(other) | ||
176 | + return PetriNet |
snakes/plugins/pos.py
0 → 100644
1 | +"""A plugin to add positions to the nodes. | ||
2 | + | ||
3 | + - C{Place} and C{Transition} constructors are added an optional | ||
4 | + argument C{pos=(x,y)} to set their position | ||
5 | + | ||
6 | + - C{Place} and C{Transition} are added an attribute C{pos} that is | ||
7 | + pair of numbers with attributes C{x} and C{y} and methods | ||
8 | + C{shift(dx, dy)} and C{moveto(x, y)} | ||
9 | + | ||
10 | + - Petri nets are added methods C{bbox()} that returns a pair of | ||
11 | + extrema C{((xmin, ymin), (xmax, ymax))}, a method C{shift(dx, dy)} | ||
12 | + that shift all the nodes, and a method C{transpose()} that rotates | ||
13 | + the net in such a way that the top-down direction becomes | ||
14 | + left-right | ||
15 | + | ||
16 | +>>> import snakes.plugins | ||
17 | +>>> snakes.plugins.load('pos', 'snakes.nets', 'nets') | ||
18 | +<module ...> | ||
19 | +>>> from nets import PetriNet, Place, Transition | ||
20 | +>>> n = PetriNet('N') | ||
21 | +>>> n.add_place(Place('p00')) | ||
22 | +>>> n.add_transition(Transition('t10', pos=(1, 0))) | ||
23 | +>>> n.add_place(Place('p11', pos=(1, 1))) | ||
24 | +>>> n.add_transition(Transition('t01', pos=(0, 1))) | ||
25 | +>>> n.node('t10').pos | ||
26 | +Position(1, 0) | ||
27 | +>>> n.node('t10').pos.x | ||
28 | +1 | ||
29 | +>>> n.node('t10').pos.y | ||
30 | +0 | ||
31 | +>>> n.node('t10').pos.y = 1 | ||
32 | +Traceback (most recent call last): | ||
33 | + ... | ||
34 | +AttributeError: readonly attribute | ||
35 | +>>> n.node('t10').pos() | ||
36 | +(1, 0) | ||
37 | +>>> n.bbox() | ||
38 | +((0, 0), (1, 1)) | ||
39 | +>>> n.shift(1, 2) | ||
40 | +>>> n.bbox() | ||
41 | +((1, 2), (2, 3)) | ||
42 | +>>> n.node('t01').copy().pos | ||
43 | +Position(1, 3) | ||
44 | +>>> n.transpose() | ||
45 | +>>> n.node('t01').pos | ||
46 | +Position(-3, 1) | ||
47 | +""" | ||
48 | + | ||
49 | +from snakes import SnakesError | ||
50 | +from snakes.compat import * | ||
51 | +from snakes.plugins import plugin, new_instance | ||
52 | +from snakes.pnml import Tree | ||
53 | + | ||
54 | +class Position (object) : | ||
55 | + "The position of a node" | ||
56 | + def __init__ (self, x, y) : | ||
57 | + self.__dict__["x"] = x | ||
58 | + self.__dict__["y"] = y | ||
59 | + def __str__ (self) : | ||
60 | + return "(%s, %s)" % (str(self.x), str(self.y)) | ||
61 | + def __repr__ (self) : | ||
62 | + return "Position(%s, %s)" % (str(self.x), str(self.y)) | ||
63 | + def __setattr__ (self, name, value) : | ||
64 | + if name in ("x", "y") : | ||
65 | + raise AttributeError("readonly attribute") | ||
66 | + else : | ||
67 | + self.__dict__[name] = value | ||
68 | + def moveto (self, x, y) : | ||
69 | + self.__init__(x, y) | ||
70 | + def shift (self, dx, dy) : | ||
71 | + self.__init__(self.x + dx, self.y + dy) | ||
72 | + def __getitem__ (self, rank) : | ||
73 | + if rank == 0 : | ||
74 | + return self.x | ||
75 | + elif rank == 1 : | ||
76 | + return self.y | ||
77 | + else : | ||
78 | + raise IndexError("Position index out of range") | ||
79 | + def __iter__ (self) : | ||
80 | + yield self.x | ||
81 | + yield self.y | ||
82 | + def __call__ (self) : | ||
83 | + return (self.x, self.y) | ||
84 | + | ||
85 | +@plugin("snakes.nets") | ||
86 | +def extend (module) : | ||
87 | + class Place (module.Place) : | ||
88 | + def __init__ (self, name, tokens=[], check=None, **args) : | ||
89 | + x, y = args.pop("pos", (0, 0)) | ||
90 | + self.pos = Position(x, y) | ||
91 | + module.Place.__init__(self, name, tokens, check, **args) | ||
92 | + def copy (self, name=None, **args) : | ||
93 | + x, y = args.pop("pos", self.pos()) | ||
94 | + result = module.Place.copy(self, name, **args) | ||
95 | + result.pos.moveto(x, y) | ||
96 | + return result | ||
97 | + def __pnmldump__ (self) : | ||
98 | + """ | ||
99 | + >>> p = Place('p', pos=(1, 2)) | ||
100 | + >>> p.__pnmldump__() | ||
101 | + <?xml version="1.0" encoding="utf-8"?> | ||
102 | + <pnml> | ||
103 | + <place id="p"> | ||
104 | + <type domain="universal"/> | ||
105 | + <initialMarking> | ||
106 | + <multiset/> | ||
107 | + </initialMarking> | ||
108 | + <graphics> | ||
109 | + <position x="1" y="2"/> | ||
110 | + </graphics> | ||
111 | + </place> | ||
112 | + </pnml> | ||
113 | + """ | ||
114 | + t = module.Place.__pnmldump__(self) | ||
115 | + try : | ||
116 | + gfx = t.child("graphics") | ||
117 | + except SnakesError : | ||
118 | + gfx = Tree("graphics", None) | ||
119 | + t.add_child(gfx) | ||
120 | + gfx.add_child(Tree("position", None, | ||
121 | + x=str(self.pos.x), | ||
122 | + y=str(self.pos.y))) | ||
123 | + return t | ||
124 | + @classmethod | ||
125 | + def __pnmlload__ (cls, tree) : | ||
126 | + """ | ||
127 | + >>> old = Place('p', pos=(1, 2)) | ||
128 | + >>> p = old.__pnmldump__() | ||
129 | + >>> new = Place.__pnmlload__(p) | ||
130 | + >>> new.pos | ||
131 | + Position(1, 2) | ||
132 | + >>> new | ||
133 | + Place('p', MultiSet([]), tAll) | ||
134 | + >>> new.__class__ | ||
135 | + <class 'snakes.plugins.pos.Place'> | ||
136 | + """ | ||
137 | + result = new_instance(cls, module.Place.__pnmlload__(tree)) | ||
138 | + try : | ||
139 | + p = tree.child("graphics").child("position") | ||
140 | + x, y = eval(p["x"]), eval(p["y"]) | ||
141 | + result.pos = Position(x, y) | ||
142 | + except SnakesError : | ||
143 | + result.pos = Position(0, 0) | ||
144 | + return result | ||
145 | + class Transition (module.Transition) : | ||
146 | + def __init__ (self, name, guard=None, **args) : | ||
147 | + x, y = args.pop("pos", (0, 0)) | ||
148 | + self.pos = Position(x, y) | ||
149 | + module.Transition.__init__(self, name, guard, **args) | ||
150 | + def copy (self, name=None, **args) : | ||
151 | + x, y = args.pop("pos", self.pos()) | ||
152 | + result = module.Transition.copy(self, name, **args) | ||
153 | + result.pos.moveto(x, y) | ||
154 | + return result | ||
155 | + def __pnmldump__ (self) : | ||
156 | + """ | ||
157 | + >>> t = Transition('t', pos=(2, 1)) | ||
158 | + >>> t.__pnmldump__() | ||
159 | + <?xml version="1.0" encoding="utf-8"?> | ||
160 | + <pnml> | ||
161 | + <transition id="t"> | ||
162 | + <graphics> | ||
163 | + <position x="2" y="1"/> | ||
164 | + </graphics> | ||
165 | + </transition> | ||
166 | + </pnml> | ||
167 | + """ | ||
168 | + t = module.Transition.__pnmldump__(self) | ||
169 | + t.add_child(Tree("graphics", None, | ||
170 | + Tree("position", None, | ||
171 | + x=str(self.pos.x), | ||
172 | + y=str(self.pos.y)))) | ||
173 | + return t | ||
174 | + @classmethod | ||
175 | + def __pnmlload__ (cls, tree) : | ||
176 | + """ | ||
177 | + >>> old = Transition('t', pos=(2, 1)) | ||
178 | + >>> p = old.__pnmldump__() | ||
179 | + >>> new = Transition.__pnmlload__(p) | ||
180 | + >>> new.pos | ||
181 | + Position(2, 1) | ||
182 | + >>> new | ||
183 | + Transition('t', Expression('True')) | ||
184 | + >>> new.__class__ | ||
185 | + <class 'snakes.plugins.pos.Transition'> | ||
186 | + """ | ||
187 | + result = new_instance(cls, module.Transition.__pnmlload__(tree)) | ||
188 | + try : | ||
189 | + p = tree.child("graphics").child("position") | ||
190 | + x, y = eval(p["x"]), eval(p["y"]) | ||
191 | + result.pos = Position(x, y) | ||
192 | + except SnakesError : | ||
193 | + result.pos = Position(0, 0) | ||
194 | + return result | ||
195 | + class PetriNet (module.PetriNet) : | ||
196 | + def add_place (self, place, **args) : | ||
197 | + if "pos" in args : | ||
198 | + x, y = args.pop("pos") | ||
199 | + place.pos.moveto(x, y) | ||
200 | + module.PetriNet.add_place(self, place, **args) | ||
201 | + def add_transition (self, trans, **args) : | ||
202 | + if "pos" in args : | ||
203 | + x, y = args.pop("pos") | ||
204 | + trans.pos.moveto(x, y) | ||
205 | + module.PetriNet.add_transition(self, trans, **args) | ||
206 | + def merge_places (self, target, sources, **args) : | ||
207 | + pos = args.pop("pos", None) | ||
208 | + module.PetriNet.merge_places(self, target, sources, **args) | ||
209 | + if pos is None : | ||
210 | + pos = reduce(complex.__add__, | ||
211 | + (complex(*self._place[name].pos()) | ||
212 | + for name in sources)) / len(sources) | ||
213 | + x, y = pos.real, pos.imag | ||
214 | + else : | ||
215 | + x, y = pos | ||
216 | + self._place[target].pos.moveto(x, y) | ||
217 | + def merge_transitions (self, target, sources, **args) : | ||
218 | + pos = args.pop("pos", None) | ||
219 | + module.PetriNet.merge_transitions(self, target, sources, **args) | ||
220 | + if pos is None : | ||
221 | + pos = reduce(complex.__add__, | ||
222 | + (complex(*self._trans[name].pos()) | ||
223 | + for name in sources)) / len(sources) | ||
224 | + x, y = pos.real, pos.imag | ||
225 | + else : | ||
226 | + x, y = pos | ||
227 | + self._trans[target].pos.moveto(x, y) | ||
228 | + def bbox (self) : | ||
229 | + if len(self._node) == 0 : | ||
230 | + return (0, 0), (0, 0) | ||
231 | + else : | ||
232 | + nodes = iter(self._node.values()) | ||
233 | + xmin, ymin = next(nodes).pos() | ||
234 | + xmax, ymax = xmin, ymin | ||
235 | + for n in nodes : | ||
236 | + x, y = n.pos() | ||
237 | + xmin = min(xmin, x) | ||
238 | + xmax = max(xmax, x) | ||
239 | + ymin = min(ymin, y) | ||
240 | + ymax = max(ymax, y) | ||
241 | + return (xmin, ymin), (xmax, ymax) | ||
242 | + def shift (self, dx, dy) : | ||
243 | + for node in self.node() : | ||
244 | + node.pos.shift(dx, dy) | ||
245 | + def transpose (self) : | ||
246 | + for node in self.node() : | ||
247 | + x, y = node.pos() | ||
248 | + node.pos.moveto(-y, x) | ||
249 | + return Place, Transition, PetriNet, Position |
snakes/plugins/query.py
0 → 100644
1 | +from snakes.plugins import plugin | ||
2 | +from snakes.pnml import Tree, loads, dumps | ||
3 | +import imp, sys, socket, traceback, operator | ||
4 | + | ||
5 | +class QueryError (Exception) : | ||
6 | + pass | ||
7 | + | ||
8 | +class Query (object) : | ||
9 | + def __init__ (self, name, *larg, **karg) : | ||
10 | + self._name = name | ||
11 | + self._larg = tuple(larg) | ||
12 | + self._karg = dict(karg) | ||
13 | + __pnmltag__ = "query" | ||
14 | + def __pnmldump__ (self) : | ||
15 | + """ | ||
16 | + >>> Query('set', 'x', 42).__pnmldump__() | ||
17 | + <?xml version="1.0" encoding="utf-8"?> | ||
18 | + <pnml> | ||
19 | + <query name="set"> | ||
20 | + <argument> | ||
21 | + <object type="str"> | ||
22 | + x | ||
23 | + </object> | ||
24 | + </argument> | ||
25 | + <argument> | ||
26 | + <object type="int"> | ||
27 | + 42 | ||
28 | + </object> | ||
29 | + </argument> | ||
30 | + </query> | ||
31 | + </pnml> | ||
32 | + >>> Query('test', x=1).__pnmldump__() | ||
33 | + <?xml version="1.0" encoding="utf-8"?> | ||
34 | + <pnml> | ||
35 | + <query name="test"> | ||
36 | + <keyword name="x"> | ||
37 | + <object type="int"> | ||
38 | + 1 | ||
39 | + </object> | ||
40 | + </keyword> | ||
41 | + </query> | ||
42 | + </pnml> | ||
43 | + >>> Query('test', 'x', 42, y=1).__pnmldump__() | ||
44 | + <?xml version="1.0" encoding="utf-8"?> | ||
45 | + <pnml> | ||
46 | + <query name="test"> | ||
47 | + <argument> | ||
48 | + <object type="str"> | ||
49 | + x | ||
50 | + </object> | ||
51 | + </argument> | ||
52 | + <argument> | ||
53 | + <object type="int"> | ||
54 | + 42 | ||
55 | + </object> | ||
56 | + </argument> | ||
57 | + <keyword name="y"> | ||
58 | + <object type="int"> | ||
59 | + 1 | ||
60 | + </object> | ||
61 | + </keyword> | ||
62 | + </query> | ||
63 | + </pnml> | ||
64 | + >>> Query('set', 'x', Query('call', 'x.upper')).__pnmldump__() | ||
65 | + <?xml version="1.0" encoding="utf-8"?> | ||
66 | + <pnml> | ||
67 | + <query name="set"> | ||
68 | + <argument> | ||
69 | + <object type="str"> | ||
70 | + x | ||
71 | + </object> | ||
72 | + </argument> | ||
73 | + <argument> | ||
74 | + <query name="call"> | ||
75 | + <argument> | ||
76 | + <object type="str"> | ||
77 | + x.upper | ||
78 | + </object> | ||
79 | + </argument> | ||
80 | + </query> | ||
81 | + </argument> | ||
82 | + </query> | ||
83 | + </pnml> | ||
84 | + """ | ||
85 | + children = [] | ||
86 | + for arg in self._larg : | ||
87 | + children.append(Tree("argument", None, | ||
88 | + Tree.from_obj(arg))) | ||
89 | + for name, value in self._karg.items() : | ||
90 | + children.append(Tree("keyword", None, | ||
91 | + Tree.from_obj(value), | ||
92 | + name=name)) | ||
93 | + return Tree(self.__pnmltag__, None, *children, **{"name": self._name}) | ||
94 | + @classmethod | ||
95 | + def __pnmlload__ (cls, tree) : | ||
96 | + """ | ||
97 | + >>> Tree._tag2obj = {'query': Query} | ||
98 | + >>> t = Query('test', 'x', 42, y=1).__pnmldump__() | ||
99 | + >>> q = Query.__pnmlload__(t) | ||
100 | + >>> q._name | ||
101 | + 'test' | ||
102 | + >>> q._larg | ||
103 | + ('x', 42) | ||
104 | + >>> q._karg | ||
105 | + {'y': 1} | ||
106 | + """ | ||
107 | + larg = (child.child().to_obj() | ||
108 | + for child in tree.get_children("argument")) | ||
109 | + karg = dict((child["name"], child.child().to_obj()) | ||
110 | + for child in tree.get_children("keyword")) | ||
111 | + return cls(tree["name"], *larg, **karg) | ||
112 | + def run (self, envt) : | ||
113 | + """ | ||
114 | + >>> import imp | ||
115 | + >>> env = imp.new_module('environment') | ||
116 | + >>> Query('set', 'x', 'hello').run(env) | ||
117 | + >>> env.x | ||
118 | + 'hello' | ||
119 | + >>> Query('set', 'x', Query('call', 'x.upper')).run(env) | ||
120 | + >>> env.x | ||
121 | + 'HELLO' | ||
122 | + >>> Query('test', 1, 2, 3).run(env) | ||
123 | + Traceback (most recent call last): | ||
124 | + ... | ||
125 | + QueryError: unknown query 'test' | ||
126 | + """ | ||
127 | + try : | ||
128 | + handler = getattr(self, "_run_%s" % self._name) | ||
129 | + except AttributeError : | ||
130 | + raise QueryError("unknown query %r" % self._name) | ||
131 | + self._envt = envt | ||
132 | + larg = tuple(a.run(envt) if isinstance(a, self.__class__) else a | ||
133 | + for a in self._larg) | ||
134 | + karg = dict((n, v.run(envt) if isinstance(v, self.__class__) else v) | ||
135 | + for n, v in self._karg.items()) | ||
136 | + try : | ||
137 | + return handler(*larg, **karg) | ||
138 | + except TypeError : | ||
139 | + cls, val, tb = sys.exc_info() | ||
140 | + try : | ||
141 | + fun, msg = str(val).strip().split("()", 1) | ||
142 | + except : | ||
143 | + raise val | ||
144 | + if fun.startswith("_run_") and hasattr(self, fun) : | ||
145 | + raise TypeError(fun[5:] + "()" + msg) | ||
146 | + raise val | ||
147 | + def _get_object (self, path) : | ||
148 | + obj = self._envt | ||
149 | + for n in path : | ||
150 | + obj = getattr(obj, n) | ||
151 | + return obj | ||
152 | + def _run_set (self, name, value) : | ||
153 | + """ | ||
154 | + >>> import imp | ||
155 | + >>> env = imp.new_module('environment') | ||
156 | + >>> Query('set', 'x', 1).run(env) | ||
157 | + >>> env.x | ||
158 | + 1 | ||
159 | + """ | ||
160 | + path = name.split(".") | ||
161 | + setattr(self._get_object(path[:-1]), path[-1], value) | ||
162 | + def _run_get (self, name) : | ||
163 | + """ | ||
164 | + >>> import imp | ||
165 | + >>> env = imp.new_module('environment') | ||
166 | + >>> env.x = 2 | ||
167 | + >>> Query('get', 'x').run(env) | ||
168 | + 2 | ||
169 | + """ | ||
170 | + path = name.split(".") | ||
171 | + return self._get_object(path) | ||
172 | + def _run_del (self, name) : | ||
173 | + """ | ||
174 | + >>> import imp | ||
175 | + >>> env = imp.new_module('environment') | ||
176 | + >>> env.x = 2 | ||
177 | + >>> Query('del', 'x').run(env) | ||
178 | + >>> env.x | ||
179 | + Traceback (most recent call last): | ||
180 | + ... | ||
181 | + AttributeError: 'module' object has no attribute 'x' | ||
182 | + """ | ||
183 | + path = name.split(".") | ||
184 | + delattr(self._get_object(path[:-1]), path[-1]) | ||
185 | + def _run_call (self, fun, *larg, **karg) : | ||
186 | + """ | ||
187 | + >>> import imp | ||
188 | + >>> env = imp.new_module('environment') | ||
189 | + >>> env.x = 'hello' | ||
190 | + >>> Query('call', 'x.center', 7).run(env) | ||
191 | + ' hello ' | ||
192 | + >>> env.__dict__.update(__builtins__) | ||
193 | + >>> Query('call', Query('call', 'getattr', | ||
194 | + ... Query('call', 'x.center', 7), | ||
195 | + ... 'upper')).run(env) | ||
196 | + ' HELLO ' | ||
197 | + """ | ||
198 | + if isinstance(fun, str) : | ||
199 | + fun = self._get_object(fun.split(".")) | ||
200 | + return fun(*larg, **karg) | ||
201 | + | ||
202 | +@plugin("snakes.nets") | ||
203 | +def extend (module) : | ||
204 | + class UDPServer (object) : | ||
205 | + def __init__ (self, port, size=2**20, verbose=0) : | ||
206 | + self._size = size | ||
207 | + self._verbose = verbose | ||
208 | + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
209 | + self._sock.bind(("", port)) | ||
210 | + self._env = imp.new_module("snk") | ||
211 | + self._env.__dict__.update(__builtins__) | ||
212 | + self._env.__dict__.update(operator.__dict__) | ||
213 | + self._env.__dict__.update(module.__dict__) | ||
214 | + def recvfrom (self) : | ||
215 | + return self._sock.recvfrom(self._size) | ||
216 | + def sendto (self, data, address) : | ||
217 | + self._sock.sendto(data.strip() + "\n", address) | ||
218 | + def run (self) : | ||
219 | + while True : | ||
220 | + data, address = self.recvfrom() | ||
221 | + data = data.strip() | ||
222 | + if self._verbose : | ||
223 | + print("# query from %s:%u" % address) | ||
224 | + try : | ||
225 | + if self._verbose > 1 : | ||
226 | + print(data) | ||
227 | + res = loads(data).run(self._env) | ||
228 | + if res is None : | ||
229 | + res = Tree("answer", None, status="ok") | ||
230 | + else : | ||
231 | + res = Tree("answer", None, Tree.from_obj(res), | ||
232 | + status="ok") | ||
233 | + except : | ||
234 | + cls, val, tb = sys.exc_info() | ||
235 | + res = Tree("answer", str(val).strip(), | ||
236 | + error=cls.__name__, status="error") | ||
237 | + if self._verbose > 1 : | ||
238 | + print("# error") | ||
239 | + for entry in traceback.format_exception(cls, val, tb) : | ||
240 | + for line in entry.splitlines() : | ||
241 | + print("## %s" % line) | ||
242 | + if self._verbose : | ||
243 | + if self._verbose > 1 : | ||
244 | + print("# answer") | ||
245 | + print(res.to_pnml()) | ||
246 | + elif res["status"] == "error" : | ||
247 | + print("# answer: %s: %s" % (res["error"], res.data)) | ||
248 | + else : | ||
249 | + print("# answer: %s" % res["status"]) | ||
250 | + self.sendto(res.to_pnml(), address) | ||
251 | + class TCPServer (UDPServer) : | ||
252 | + def __init__ (self, port, size=2**20, verbose=0) : | ||
253 | + self._size = size | ||
254 | + self._verbose = verbose | ||
255 | + self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
256 | + self._sock.bind(("", port)) | ||
257 | + self._sock.listen(1) | ||
258 | + self._env = imp.new_module("snk") | ||
259 | + self._env.__dict__.update(__builtins__) | ||
260 | + self._env.__dict__.update(operator.__dict__) | ||
261 | + self._env.__dict__.update(module.__dict__) | ||
262 | + self._connection = {} | ||
263 | + def recvfrom (self) : | ||
264 | + connection, address = self._sock.accept() | ||
265 | + self._connection[address] = connection | ||
266 | + parts = [] | ||
267 | + while True : | ||
268 | + parts.append(connection.recv(self._size)) | ||
269 | + if len(parts[-1]) < self._size : | ||
270 | + break | ||
271 | + return "".join(parts), address | ||
272 | + def sendto (self, data, address) : | ||
273 | + self._connection[address].send(data.rstrip() + "\n") | ||
274 | + self._connection[address].close() | ||
275 | + del self._connection[address] | ||
276 | + return Query, UDPServer, TCPServer |
snakes/plugins/status.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/plugins/synchro.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/pnml.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/typing.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/utils/__init__.py
0 → 100644
File mode changed
snakes/utils/abcd/__init__.py
0 → 100644
snakes/utils/abcd/build.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/utils/abcd/checker.py
0 → 100644
1 | +import heapq | ||
2 | +from snakes.nets import StateGraph | ||
3 | +import snakes.lang | ||
4 | +import snkast as ast | ||
5 | + | ||
6 | +class Checker (object) : | ||
7 | + def __init__ (self, net) : | ||
8 | + self.g = StateGraph(net) | ||
9 | + self.f = [self.build(f) for f in net.label("asserts")] | ||
10 | + def build (self, tree) : | ||
11 | + src = """ | ||
12 | +def check (_) : | ||
13 | + return %s | ||
14 | +""" % tree.st.source()[7:] | ||
15 | + ctx = dict(self.g.net.globals) | ||
16 | + ctx["bounded"] = self.bounded | ||
17 | + exec(src, ctx) | ||
18 | + fun = ctx["check"] | ||
19 | + fun.lineno = tree.lineno | ||
20 | + return fun | ||
21 | + def bounded (self, marking, max) : | ||
22 | + return all(len(marking(p)) == 1 for p in marking) | ||
23 | + def run (self) : | ||
24 | + for state in self.g : | ||
25 | + marking = self.g.net.get_marking() | ||
26 | + for place in marking : | ||
27 | + if max(marking(place).values()) > 1 : | ||
28 | + return None, self.trace(state) | ||
29 | + for check in self.f : | ||
30 | + try : | ||
31 | + if not check(marking) : | ||
32 | + return check.lineno, self.trace(state) | ||
33 | + except : | ||
34 | + pass | ||
35 | + return None, None | ||
36 | + def path (self, tgt, src=0) : | ||
37 | + q = [(0, src, ())] | ||
38 | + visited = set() | ||
39 | + while True : | ||
40 | + (c, v1, path) = heapq.heappop(q) | ||
41 | + if v1 not in visited : | ||
42 | + path = path + (v1,) | ||
43 | + if v1 == tgt : | ||
44 | + return path | ||
45 | + visited.add(v1) | ||
46 | + for v2 in self.g.successors(v1) : | ||
47 | + if v2 not in visited : | ||
48 | + heapq.heappush(q, (c+1, v2, path)) | ||
49 | + def trace (self, state) : | ||
50 | + path = self.path(state) | ||
51 | + return tuple(self.g.successors(i)[j] | ||
52 | + for i, j in zip(path[:-1], path[1:])) |
snakes/utils/abcd/main.py
0 → 100644
1 | +import sys, optparse, os.path | ||
2 | +import pdb, traceback | ||
3 | +import snakes.plugins | ||
4 | +from snakes.utils.abcd.build import Builder | ||
5 | +from snakes.lang.abcd.parser import parse | ||
6 | +from snakes.lang.pgen import ParseError | ||
7 | +from snakes.utils.abcd import CompilationError, DeclarationError | ||
8 | +from snakes.utils.abcd.simul import Simulator | ||
9 | +from snakes.utils.abcd.checker import Checker | ||
10 | + | ||
11 | +## | ||
12 | +## error messages | ||
13 | +## | ||
14 | + | ||
15 | +ERR_ARG = 1 | ||
16 | +ERR_OPT = 2 | ||
17 | +ERR_IO = 3 | ||
18 | +ERR_PARSE = 4 | ||
19 | +ERR_PLUGIN = 5 | ||
20 | +ERR_COMPILE = 6 | ||
21 | +ERR_OUTPUT = 7 | ||
22 | +ERR_BUG = 255 | ||
23 | + | ||
24 | +def err (message) : | ||
25 | + sys.stderr.write("abcd: %s\n" % message.strip()) | ||
26 | + | ||
27 | +def die (code, message=None) : | ||
28 | + if message : | ||
29 | + err(message) | ||
30 | + if options.debug : | ||
31 | + pdb.post_mortem(sys.exc_info()[2]) | ||
32 | + else : | ||
33 | + sys.exit(code) | ||
34 | + | ||
35 | +def bug () : | ||
36 | + sys.stderr.write(""" | ||
37 | + ******************************************************************** | ||
38 | + *** An unexpected error ocurred. Please report this bug to *** | ||
39 | + *** <franck.pommereau@gmail.com>, together with the execution *** | ||
40 | + *** trace below and, if possible, a stripped-down version of the *** | ||
41 | + *** ABCD source code that caused this bug. Thank you for your *** | ||
42 | + *** help in improving SNAKES! *** | ||
43 | + ******************************************************************** | ||
44 | + | ||
45 | +""") | ||
46 | + traceback.print_exc() | ||
47 | + if options.debug : | ||
48 | + pdb.post_mortem(sys.exc_info()[2]) | ||
49 | + else : | ||
50 | + sys.exit(ERR_BUG) | ||
51 | + | ||
52 | +## | ||
53 | +## options parsing | ||
54 | +## | ||
55 | + | ||
56 | +gv_engines = ("dot", "neato", "twopi", "circo", "fdp") | ||
57 | + | ||
58 | +opt = optparse.OptionParser(prog="abcd", | ||
59 | + usage="%prog [OPTION]... FILE") | ||
60 | +opt.add_option("-l", "--load", | ||
61 | + dest="plugins", action="append", default=[], | ||
62 | + help="load plugin (this option can be repeated)", | ||
63 | + metavar="PLUGIN") | ||
64 | +opt.add_option("-p", "--pnml", | ||
65 | + dest="pnml", action="store", default=None, | ||
66 | + help="save net as PNML", | ||
67 | + metavar="OUTFILE") | ||
68 | +for engine in gv_engines : | ||
69 | + opt.add_option("-" + engine[0], "--" + engine, | ||
70 | + dest="gv" + engine, action="store", default=None, | ||
71 | + help="draw net using '%s' (from GraphViz)" % engine, | ||
72 | + metavar="OUTFILE") | ||
73 | +opt.add_option("-a", "--all-names", | ||
74 | + dest="allnames", action="store_true", default=False, | ||
75 | + help="draw control-flow places names (default: hide)") | ||
76 | +opt.add_option("--debug", | ||
77 | + dest="debug", action="store_true", default=False, | ||
78 | + help="launch debugger on compiler error (default: no)") | ||
79 | +opt.add_option("-s", "--simul", | ||
80 | + dest="simul", action="store_true", default=False, | ||
81 | + help="launch interactive code simulator") | ||
82 | +opt.add_option("--check", | ||
83 | + dest="check", action="store_true", default=False, | ||
84 | + help="check assertions") | ||
85 | + | ||
86 | +def getopts (args) : | ||
87 | + global options, abcd | ||
88 | + (options, args) = opt.parse_args(args) | ||
89 | + plugins = [] | ||
90 | + for p in options.plugins : | ||
91 | + plugins.extend(t.strip() for t in p.split(",")) | ||
92 | + if "ops" not in options.plugins : | ||
93 | + plugins.append("ops") | ||
94 | + if "labels" not in plugins : | ||
95 | + plugins.append("labels") | ||
96 | + for engine in gv_engines : | ||
97 | + gvopt = getattr(options, "gv%s" % engine) | ||
98 | + if gvopt and "gv" not in plugins : | ||
99 | + plugins.append("gv") | ||
100 | + break | ||
101 | + options.plugins = plugins | ||
102 | + if len(args) < 1 : | ||
103 | + err("no input file provided") | ||
104 | + opt.print_help() | ||
105 | + die(ERR_ARG) | ||
106 | + elif len(args) > 1 : | ||
107 | + err("more than one input file provided") | ||
108 | + opt.print_help() | ||
109 | + die(ERR_ARG) | ||
110 | + abcd = args[0] | ||
111 | + if options.pnml == abcd : | ||
112 | + err("input file also used as output (--pnml)") | ||
113 | + opt.print_help() | ||
114 | + die(ERR_ARG) | ||
115 | + for engine in gv_engines : | ||
116 | + if getattr(options, "gv%s" % engine) == abcd : | ||
117 | + err("input file also used as output (--%s)" % engine) | ||
118 | + opt.print_help() | ||
119 | + die(ERR_ARG) | ||
120 | + | ||
121 | +## | ||
122 | +## drawing nets | ||
123 | +## | ||
124 | + | ||
125 | +def place_attr (place, attr) : | ||
126 | + # fix color | ||
127 | + if place.status == snk.entry : | ||
128 | + attr["fillcolor"] = "green" | ||
129 | + elif place.status == snk.internal : | ||
130 | + pass | ||
131 | + elif place.status == snk.exit : | ||
132 | + attr["fillcolor"] = "yellow" | ||
133 | + else : | ||
134 | + attr["fillcolor"] = "lightblue" | ||
135 | + # fix shape | ||
136 | + if (not options.allnames | ||
137 | + and place.status in (snk.entry, snk.internal, snk.exit)) : | ||
138 | + attr["shape"] = "circle" | ||
139 | + # render marking | ||
140 | + if place._check == snk.tBlackToken : | ||
141 | + count = len(place.tokens) | ||
142 | + if count == 0 : | ||
143 | + marking = " " | ||
144 | + elif count == 1 : | ||
145 | + marking = "@" | ||
146 | + else : | ||
147 | + marking = "%s@" % count | ||
148 | + else : | ||
149 | + marking = str(place.tokens) | ||
150 | + # node label | ||
151 | + if (options.allnames | ||
152 | + or place.status not in (snk.entry, snk.internal, snk.exit)) : | ||
153 | + attr["label"] = "%s\\n%s" % (place.name, marking) | ||
154 | + else : | ||
155 | + attr["label"] = "%s" % marking | ||
156 | + | ||
157 | +def trans_attr (trans, attr) : | ||
158 | + pass | ||
159 | + | ||
160 | +def arc_attr (label, attr) : | ||
161 | + if label == snk.Value(snk.dot) : | ||
162 | + del attr["label"] | ||
163 | + elif isinstance(label, snk.Test) : | ||
164 | + attr["arrowhead"] = "none" | ||
165 | + attr["label"] = " %s " % label._annotation | ||
166 | + elif isinstance(label, snk.Flush) : | ||
167 | + attr["arrowhead"] = "box" | ||
168 | + attr["label"] = " %s " % label._annotation | ||
169 | + | ||
170 | +def draw (net, engine, target) : | ||
171 | + try : | ||
172 | + net.draw(target, engine=engine, | ||
173 | + place_attr=place_attr, | ||
174 | + trans_attr=trans_attr, | ||
175 | + arc_attr=arc_attr) | ||
176 | + except : | ||
177 | + die(ERR_OUTPUT, str(sys.exc_info()[1])) | ||
178 | + | ||
179 | +## | ||
180 | +## save pnml | ||
181 | +## | ||
182 | + | ||
183 | +def save_pnml (net, target) : | ||
184 | + try : | ||
185 | + out = open(target, "w") | ||
186 | + out.write(snk.dumps(net)) | ||
187 | + out.close() | ||
188 | + except : | ||
189 | + die(ERR_OUTPUT, str(sys.exc_info()[1])) | ||
190 | + | ||
191 | +## | ||
192 | +## main | ||
193 | +## | ||
194 | + | ||
195 | +def main (args=sys.argv[1:], src=None) : | ||
196 | + global snk | ||
197 | + # get options | ||
198 | + try: | ||
199 | + if src is None : | ||
200 | + getopts(args) | ||
201 | + else : | ||
202 | + getopts(list(args) + ["<string>"]) | ||
203 | + except SystemExit : | ||
204 | + raise | ||
205 | + except : | ||
206 | + die(ERR_OPT, str(sys.exc_info()[1])) | ||
207 | + # read source | ||
208 | + if src is not None : | ||
209 | + source = src | ||
210 | + else : | ||
211 | + try : | ||
212 | + source = open(abcd).read() | ||
213 | + except : | ||
214 | + die(ERR_IO, "could not read input file %r" % abcd) | ||
215 | + # parse | ||
216 | + try : | ||
217 | + node = parse(source, filename=abcd) | ||
218 | + except ParseError : | ||
219 | + die(ERR_PARSE, str(sys.exc_info()[1])) | ||
220 | + except : | ||
221 | + bug() | ||
222 | + # compile | ||
223 | + dirname = os.path.dirname(abcd) | ||
224 | + if dirname and dirname not in sys.path : | ||
225 | + sys.path.append(dirname) | ||
226 | + elif "." not in sys.path : | ||
227 | + sys.path.append(".") | ||
228 | + try : | ||
229 | + snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk") | ||
230 | + except : | ||
231 | + die(ERR_PLUGIN, str(sys.exc_info()[1])) | ||
232 | + build = Builder(snk) | ||
233 | + try : | ||
234 | + net = build.build(node) | ||
235 | + net.label(srcfile=abcd) | ||
236 | + except (CompilationError, DeclarationError) : | ||
237 | + die(ERR_COMPILE, str(sys.exc_info()[1])) | ||
238 | + except : | ||
239 | + bug() | ||
240 | + # output | ||
241 | + if options.pnml : | ||
242 | + save_pnml(net, options.pnml) | ||
243 | + for engine in gv_engines : | ||
244 | + target = getattr(options, "gv%s" % engine) | ||
245 | + if target : | ||
246 | + draw(net, engine, target) | ||
247 | + trace, lineno = [], None | ||
248 | + if options.check : | ||
249 | + lineno, trace = Checker(net).run() | ||
250 | + if options.simul : | ||
251 | + Simulator(snk, source, net, trace, lineno).run() | ||
252 | + elif trace : | ||
253 | + if lineno is None : | ||
254 | + print("unsafe execution:") | ||
255 | + else : | ||
256 | + asserts = dict((a.lineno, a) for a in net.label("asserts")) | ||
257 | + print("line %s, %r failed:" | ||
258 | + % (lineno, asserts[lineno].st.source())) | ||
259 | + for trans, mode in trace : | ||
260 | + print(" %s %s" % (trans, mode)) | ||
261 | + return net | ||
262 | + | ||
263 | +if __name__ == "__main__" : | ||
264 | + main() |
snakes/utils/abcd/simul.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/utils/abcd/transform.py
0 → 100644
1 | +from snakes.lang.abcd.parser import ast | ||
2 | + | ||
3 | +class NodeCopier (ast.NodeTransformer) : | ||
4 | + def copy (self, node, **replace) : | ||
5 | + args = {} | ||
6 | + for name in node._fields + node._attributes : | ||
7 | + old = getattr(node, name, None) | ||
8 | + if name in replace : | ||
9 | + new = replace[name] | ||
10 | + elif isinstance(old, list): | ||
11 | + new = [] | ||
12 | + for val in old : | ||
13 | + if isinstance(val, ast.AST) : | ||
14 | + new.append(self.visit(val)) | ||
15 | + else : | ||
16 | + new.append(val) | ||
17 | + elif isinstance(old, ast.AST): | ||
18 | + new = self.visit(old) | ||
19 | + else : | ||
20 | + new = old | ||
21 | + args[name] = new | ||
22 | + if hasattr(node, "st") : | ||
23 | + args["st"] = node.st | ||
24 | + return node.__class__(**args) | ||
25 | + def generic_visit (self, node) : | ||
26 | + return self.copy(node) | ||
27 | + | ||
28 | +class ArgsBinder (NodeCopier) : | ||
29 | + def __init__ (self, args, buffers, nets, tasks) : | ||
30 | + NodeCopier.__init__(self) | ||
31 | + self.args = args | ||
32 | + self.buffers = buffers | ||
33 | + self.nets = nets | ||
34 | + self.tasks = tasks | ||
35 | + def visit_Name (self, node) : | ||
36 | + if node.id in self.args : | ||
37 | + return self.copy(self.args[node.id]) | ||
38 | + else : | ||
39 | + return self.copy(node) | ||
40 | + def visit_Instance (self, node) : | ||
41 | + if node.net in self.nets : | ||
42 | + return self.copy(node, net=self.nets[node.net]) | ||
43 | + else : | ||
44 | + return self.copy(node) | ||
45 | + def _visit_access (self, node) : | ||
46 | + if node.buffer in self.buffers : | ||
47 | + return self.copy(node, buffer=self.buffers[node.buffer]) | ||
48 | + else : | ||
49 | + return self.copy(node) | ||
50 | + def visit_SimpleAccess (self, node) : | ||
51 | + return self._visit_access(node) | ||
52 | + def visit_FlushAccess (self, node) : | ||
53 | + return self._visit_access(node) | ||
54 | + def visit_SwapAccess (self, node) : | ||
55 | + return self._visit_access(node) | ||
56 | + def _visit_task (self, node) : | ||
57 | + if node.net in self.tasks : | ||
58 | + return self.copy(node, net=self.tasks[node.net]) | ||
59 | + else : | ||
60 | + return self.copy(node) | ||
61 | + def visit_Spawn (self, node) : | ||
62 | + return self._visit_task(node) | ||
63 | + def visit_Wait (self, node) : | ||
64 | + return self._visit_task(node) | ||
65 | + def visit_Suspend (self, node) : | ||
66 | + return self._visit_task(node) | ||
67 | + def visit_Resume (self, node) : | ||
68 | + return self._visit_task(node) | ||
69 | + def visit_AbcdNet (self, node) : | ||
70 | + args = self.args.copy() | ||
71 | + buffers = self.buffers.copy() | ||
72 | + nets = self.nets.copy() | ||
73 | + tasks = self.tasks.copy() | ||
74 | + netargs = ([a.arg for a in node.args.args + node.args.kwonlyargs] | ||
75 | + + [node.args.vararg, node.args.kwarg]) | ||
76 | + copy = True | ||
77 | + for a in netargs : | ||
78 | + for d in (args, buffers, nets, tasks) : | ||
79 | + if a in d : | ||
80 | + del d[a] | ||
81 | + copy = False | ||
82 | + if copy : | ||
83 | + return self.copy(node) | ||
84 | + else : | ||
85 | + return self.__class__(args, buffers, nets, tasks).visit(node) | ||
86 | + | ||
87 | +if __name__ == "__main__" : | ||
88 | + import doctest | ||
89 | + doctest.testmod() |
snakes/utils/apidoc.py
0 → 100644
This diff is collapsed. Click to expand it.
snakes/utils/ctlstar/__init__.py
0 → 100644
File mode changed
snakes/utils/ctlstar/build.py
0 → 100644
1 | +from snakes.lang.ctlstar.parser import parse | ||
2 | +from snakes.lang.ctlstar import asdl as ast | ||
3 | +from snakes.lang import getvars, bind | ||
4 | +import _ast | ||
5 | + | ||
6 | +class SpecError (Exception) : | ||
7 | + def __init__ (self, node, reason) : | ||
8 | + Exception.__init__(self, "[line %s] %s" % (node.lineno, reason)) | ||
9 | + | ||
10 | +def astcopy (node) : | ||
11 | + if not isinstance(node, _ast.AST) : | ||
12 | + return node | ||
13 | + attr = {} | ||
14 | + for name in node._fields + node._attributes : | ||
15 | + value = getattr(node, name) | ||
16 | + if isinstance(value, list) : | ||
17 | + attr[name] = [astcopy(child) for child in value] | ||
18 | + else : | ||
19 | + attr[name] = astcopy(value) | ||
20 | + return node.__class__(**attr) | ||
21 | + | ||
22 | +class Builder (object) : | ||
23 | + def __init__ (self, spec) : | ||
24 | + self.spec = spec | ||
25 | + self.decl = {} | ||
26 | + for node in spec.atoms + spec.properties : | ||
27 | + if node.name in self.decl : | ||
28 | + raise SpecError(node, "%r already declare line %s" | ||
29 | + % (name.name, self.decl[name.name].lineno)) | ||
30 | + self.decl[node.name] = node | ||
31 | + self.main = spec.main | ||
32 | + def build (self, node) : | ||
33 | + node = astcopy(node) | ||
34 | + return self._build(node, {}) | ||
35 | + def _build (self, node, ctx) : | ||
36 | + if isinstance(node, ast.atom) : | ||
37 | + try : | ||
38 | + builder = getattr(self, "_build_%s" % node.__class__.__name__) | ||
39 | + except AttributeError : | ||
40 | + node.atomic = True | ||
41 | + else : | ||
42 | + node = builder(node, ctx) | ||
43 | + node.atomic = True | ||
44 | + elif isinstance(node, ast.CtlBinary) : | ||
45 | + node.left = self._build(node.left, ctx) | ||
46 | + node.right = self._build(node.right, ctx) | ||
47 | + node.atomic = (isinstance(node.op, (ast.boolop, ast.Imply, | ||
48 | + ast.Iff)) | ||
49 | + and node.left.atomic | ||
50 | + and node.right.atomic) | ||
51 | + elif isinstance(node, ast.CtlUnary) : | ||
52 | + node.child = self._build(node.child, ctx) | ||
53 | + node.atomic = (isinstance(node.op, ast.Not) | ||
54 | + and node.child.atomic) | ||
55 | + else : | ||
56 | + assert False, "how did we get there?" | ||
57 | + return node | ||
58 | + def _build_place (self, param, ctx) : | ||
59 | + if isinstance(param, ast.Parameter) : | ||
60 | + if param.name not in ctx : | ||
61 | + raise SpecError(param, "place %r should be instantiated" | ||
62 | + % param.name) | ||
63 | + return ctx[param.name] | ||
64 | + else : | ||
65 | + return param | ||
66 | + def _build_InPlace (self, node, ctx) : | ||
67 | + node.data = [bind(child, ctx) for child in node.data] | ||
68 | + node.place = self._build_place(node.place, ctx) | ||
69 | + return node | ||
70 | + def _build_NotInPlace (self, node, ctx) : | ||
71 | + return self._build_InPlace(node, ctx) | ||
72 | + def _build_EmptyPlace (self, node, ctx) : | ||
73 | + node.place = self._build_place(node.place, ctx) | ||
74 | + return node | ||
75 | + def _build_MarkedPlace (self, node, ctx) : | ||
76 | + return self._build_EmptyPlace(node, ctx) | ||
77 | + # skip Deadlock and Boolean: nothing to do | ||
78 | + def _build_Quantifier (self, node, ctx) : | ||
79 | + node.place = self._build_place(node.place, ctx) | ||
80 | + ctx = ctx.copy() | ||
81 | + for name in node.vars : | ||
82 | + ctx[name] = ast.Token(name, node.place.place) | ||
83 | + node.child = self._build(node.child, ctx) | ||
84 | + return node | ||
85 | + def _build_Instance (self, node, ctx) : | ||
86 | + if node.name not in self.decl : | ||
87 | + raise SpecError(node, "undeclared object %r" % node.name) | ||
88 | + ctx = ctx.copy() | ||
89 | + decl = self.decl[node.name] | ||
90 | + for arg in decl.args : | ||
91 | + ctx[arg.name] = arg | ||
92 | + if isinstance(decl, ast.Property) : | ||
93 | + return self._build_Instance_Property(node, decl, ctx) | ||
94 | + else : | ||
95 | + return self._build_Instance_Atom(node, decl, ctx) | ||
96 | + def _build_Instance_Property (self, node, prop, ctx) : | ||
97 | + bound = set(a.name for a in prop.args) | ||
98 | + args = dict((a.arg, a.annotation) for a in node.args) | ||
99 | + for param in prop.params : | ||
100 | + if param.name in bound : | ||
101 | + raise SpecError(node, "argument %r already bound" | ||
102 | + % param.name) | ||
103 | + elif param.name in args : | ||
104 | + arg = args.pop(param.name) | ||
105 | + bound.add(param.name) | ||
106 | + else : | ||
107 | + raise SpecError(node, "missing argument %r" % param.name) | ||
108 | + if param.type == "place" : | ||
109 | + if not isinstance(arg, ast.Place) : | ||
110 | + raise SpecError(node, "expected place for %r" | ||
111 | + % param.name) | ||
112 | + arg.name = param.name | ||
113 | + ctx[param.name] = arg | ||
114 | + if args : | ||
115 | + raise SpecError(node, "too many arguments (%s)" | ||
116 | + % ", ".join(repr(a) for a in args)) | ||
117 | + return self._build(astcopy(prop.body), ctx) | ||
118 | + def _build_Instance_Atom (self, node, atom, ctx) : | ||
119 | + bound = set(a.name for a in atom.args) | ||
120 | + args = dict((a.arg, a.annotation) for a in node.args) | ||
121 | + new = astcopy(atom) | ||
122 | + for param in atom.params : | ||
123 | + if param.name in bound : | ||
124 | + raise SpecError(node, "argument %r already bound" | ||
125 | + % param.name) | ||
126 | + elif param.name in args : | ||
127 | + arg = args.pop(param.name) | ||
128 | + bound.add(param.name) | ||
129 | + else : | ||
130 | + raise SpecError(node, "missing argument %r" % param.name) | ||
131 | + if param.type == "place" : | ||
132 | + if not isinstance(arg, ast.Place) : | ||
133 | + raise SpecError(node, "expected place for %r" | ||
134 | + % param.name) | ||
135 | + arg.name = param.name | ||
136 | + else : | ||
137 | + arg = ast.Argument(name=param.name, | ||
138 | + value=arg, | ||
139 | + type=param.type) | ||
140 | + new.args.append(arg) | ||
141 | + if args : | ||
142 | + raise SpecError(node, "too many arguments (%s)" | ||
143 | + % ", ".join(repr(a) for a in args)) | ||
144 | + del new.params[:] | ||
145 | + return new | ||
146 | + | ||
147 | +def build (spec, main=None) : | ||
148 | + b = Builder(spec) | ||
149 | + if main is None : | ||
150 | + return b.build(spec.main) | ||
151 | + else : | ||
152 | + return b.build(main) |
test-scripts/test-abcd.sh
0 → 100755
test.py
0 → 100644
1 | +import doctest, sys, os, glob | ||
2 | + | ||
3 | +retcode = 0 | ||
4 | + | ||
5 | +import snakes | ||
6 | +version = open("VERSION").read().strip() | ||
7 | +if snakes.version != version : | ||
8 | + print("Mismatched versions:") | ||
9 | + print(" snakes.version = %r" % snakes.version) | ||
10 | + print(" VERSION = %r" % version) | ||
11 | + sys.exit(1) | ||
12 | + | ||
13 | +def test (module) : | ||
14 | + print(" Testing '%s'" % module.__name__) | ||
15 | + f, t = doctest.testmod(module, #verbose=True, | ||
16 | + optionflags=doctest.NORMALIZE_WHITESPACE | ||
17 | + | doctest.REPORT_ONLY_FIRST_FAILURE | ||
18 | + | doctest.ELLIPSIS) | ||
19 | + return f | ||
20 | + | ||
21 | +modules = ["snakes", | ||
22 | + "snakes.hashables", | ||
23 | + "snakes.lang", | ||
24 | + "snakes.lang.python.parser", | ||
25 | + "snakes.lang.abcd.parser", | ||
26 | + "snakes.lang.ctlstar.parser", | ||
27 | + "snakes.data", | ||
28 | + "snakes.typing", | ||
29 | + "snakes.nets", | ||
30 | + "snakes.pnml", | ||
31 | + "snakes.plugins", | ||
32 | + "snakes.plugins.pos", | ||
33 | + "snakes.plugins.status", | ||
34 | + "snakes.plugins.ops", | ||
35 | + "snakes.plugins.synchro", | ||
36 | + "snakes.plugins.hello", | ||
37 | + "snakes.plugins.gv", | ||
38 | + "snakes.plugins.clusters", | ||
39 | + "snakes.plugins.labels", | ||
40 | + "snakes.utils.abcd.build", | ||
41 | + ] | ||
42 | + | ||
43 | +stop = False | ||
44 | +if len(sys.argv) > 1 : | ||
45 | + if sys.argv[1] == "--stop" : | ||
46 | + stop = True | ||
47 | + del sys.argv[1] | ||
48 | + | ||
49 | +doscripts = True | ||
50 | +if len(sys.argv) > 1 : | ||
51 | + modules = sys.argv[1:] | ||
52 | + doscripts = False | ||
53 | + | ||
54 | +for modname in modules : | ||
55 | + try : | ||
56 | + __import__(modname) | ||
57 | + retcode = max(retcode, test(sys.modules[modname])) | ||
58 | + if retcode and stop : | ||
59 | + break | ||
60 | + except : | ||
61 | + print(" Could not test %r:" % modname) | ||
62 | + c, e, t = sys.exc_info() | ||
63 | + print(" %s: %s" % (c.__name__, e)) | ||
64 | + | ||
65 | +if doscripts : | ||
66 | + for script in (glob.glob("test-scripts/test*.sh") | ||
67 | + + glob.glob("test-scripts/test*.py")) : | ||
68 | + print(" Running '%s'" % script) | ||
69 | + retcode = max(retcode, os.system(script)) | ||
70 | + if retcode and stop : | ||
71 | + break | ||
72 | + | ||
73 | +sys.exit(retcode) |
utils/abcd-mode.el
0 → 100644
utils/pgen2dot.py
0 → 100644
This diff is collapsed. Click to expand it.
utils/pgen2min.py
0 → 100644
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment