Franck Pommereau

added files also

...@@ -4,5 +4,7 @@ doc/api/* ...@@ -4,5 +4,7 @@ doc/api/*
4 dist/* 4 dist/*
5 dput.sh 5 dput.sh
6 *.pyc 6 *.pyc
7 +*~
8 +.gone
7 ,* 9 ,*
8 *.class 10 *.class
......
1 +from snakes.lang.ctlstar.parser import parse
2 +from snakes.lang.ctlstar import asdl as ast
3 +from snakes.lang import getvars, unparse
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 Binder (ast.NodeTransformer) :
23 + def __init__ (self, bind) :
24 + ast.NodeTransformer.__init__(self)
25 + self.bind = [bind]
26 + def visit (self, node) :
27 + return ast.NodeTransformer.visit(self, astcopy(node))
28 + def visit_ListComp (self, node) :
29 + """
30 + >>> tree = ast.parse('x+y+[x+y+z for x, y in l]')
31 + >>> unparse(Binder({'x':ast.Name('hello')}).visit(tree))
32 + '((hello + y) + [((x + y) + z) for (x, y) in l])'
33 + >>> unparse(Binder({'y':ast.Name('hello')}).visit(tree))
34 + '((x + hello) + [((x + y) + z) for (x, y) in l])'
35 + >>> unparse(Binder({'z':ast.Name('hello')}).visit(tree))
36 + '((x + y) + [((x + y) + hello) for (x, y) in l])'
37 + """
38 + bind = self.bind[-1].copy()
39 + for comp in node.generators :
40 + for name in getvars(comp.target) :
41 + if name in bind :
42 + del bind[name]
43 + self.bind.append(bind)
44 + node.elt = self.visit(node.elt)
45 + self.bind.pop(-1)
46 + return node
47 + def visit_Name (self, node) :
48 + if node.id in self.bind[-1] :
49 + return astcopy(self.bind[-1][node.id])
50 + else :
51 + return astcopy(node)
52 +
53 +def bind (node, ctx) :
54 + return Binder(ctx).visit(node)
55 +
56 +class Builder (object) :
57 + def __init__ (self, spec) :
58 + self.spec = spec
59 + self.decl = {}
60 + for node in spec.atoms + spec.properties :
61 + if node.name in self.decl :
62 + raise SpecError(node, "%r already declare line %s"
63 + % (name.name, self.decl[name.name].lineno))
64 + self.decl[node.name] = node
65 + self.main = spec.main
66 + def build (self, node) :
67 + node = astcopy(node)
68 + return self._build(node, {})
69 + def _build (self, node, ctx) :
70 + if isinstance(node, ast.atom) :
71 + try :
72 + builder = getattr(self, "_build_%s" % node.__class__.__name__)
73 + except AttributeError :
74 + node.atomic = True
75 + else :
76 + node = builder(node, ctx)
77 + node.atomic = True
78 + elif isinstance(node, ast.CtlBinary) :
79 + node.left = self._build(node.left, ctx)
80 + node.right = self._build(node.right, ctx)
81 + node.atomic = (isinstance(node.op, (ast.boolop, ast.Imply,
82 + ast.Iff))
83 + and node.left.atomic
84 + and node.right.atomic)
85 + elif isinstance(node, ast.CtlUnary) :
86 + node.child = self._build(node.child, ctx)
87 + node.atomic = (isinstance(node.op, ast.Not)
88 + and node.child.atomic)
89 + else :
90 + assert False, "how did we get there?"
91 + return node
92 + def _build_place (self, param, ctx) :
93 + if isinstance(param, ast.Parameter) :
94 + if param.name not in ctx :
95 + raise SpecError(param, "place %r should be instantiated"
96 + % param.name)
97 + return ctx[param.name]
98 + else :
99 + return param
100 + def _build_InPlace (self, node, ctx) :
101 + node.data = [bind(child, ctx) for child in node.data]
102 + node.place = self._build_place(node.place, ctx)
103 + return node
104 + def _build_NotInPlace (self, node, ctx) :
105 + return self._build_InPlace(node, ctx)
106 + def _build_EmptyPlace (self, node, ctx) :
107 + node.place = self._build_place(node.place, ctx)
108 + return node
109 + def _build_MarkedPlace (self, node, ctx) :
110 + return self._build_EmptyPlace(node, ctx)
111 + # skip Deadlock and Boolean: nothing to do
112 + def _build_Quantifier (self, node, ctx) :
113 + node.place = self._build_place(node.place, ctx)
114 + ctx = ctx.copy()
115 + for name in node.vars :
116 + ctx[name] = ast.Token(name, node.place.place)
117 + node.child = self._build(node.child, ctx)
118 + return node
119 + def _build_Instance (self, node, ctx) :
120 + if node.name not in self.decl :
121 + raise SpecError(node, "undeclared object %r" % node.name)
122 + ctx = ctx.copy()
123 + decl = self.decl[node.name]
124 + for arg in decl.args :
125 + ctx[arg.name] = arg
126 + if isinstance(decl, ast.Property) :
127 + return self._build_Instance_Property(node, decl, ctx)
128 + else :
129 + return self._build_Instance_Atom(node, decl, ctx)
130 + def _build_Instance_Property (self, node, prop, ctx) :
131 + bound = set(a.name for a in prop.args)
132 + args = dict((a.arg, a.annotation) for a in node.args)
133 + for param in prop.params :
134 + if param.name in bound :
135 + raise SpecError(node, "argument %r already bound"
136 + % param.name)
137 + elif param.name in args :
138 + arg = args.pop(param.name)
139 + bound.add(param.name)
140 + else :
141 + raise SpecError(node, "missing argument %r" % param.name)
142 + if param.type == "place" :
143 + if not isinstance(arg, ast.Place) :
144 + raise SpecError(node, "expected place for %r"
145 + % param.name)
146 + arg.name = param.name
147 + ctx[param.name] = arg
148 + if args :
149 + raise SpecError(node, "too many arguments (%s)"
150 + % ", ".join(repr(a) for a in args))
151 + return self._build(astcopy(prop.body), ctx)
152 + def _build_Instance_Atom (self, node, atom, ctx) :
153 + bound = set(a.name for a in atom.args)
154 + args = dict((a.arg, a.annotation) for a in node.args)
155 + new = astcopy(atom)
156 + for param in atom.params :
157 + if param.name in bound :
158 + raise SpecError(node, "argument %r already bound"
159 + % param.name)
160 + elif param.name in args :
161 + arg = args.pop(param.name)
162 + bound.add(param.name)
163 + else :
164 + raise SpecError(node, "missing argument %r" % param.name)
165 + if param.type == "place" :
166 + if not isinstance(arg, ast.Place) :
167 + raise SpecError(node, "expected place for %r"
168 + % param.name)
169 + arg.name = param.name
170 + else :
171 + arg = ast.Argument(name=param.name,
172 + value=arg,
173 + type=param.type)
174 + new.args.append(arg)
175 + if args :
176 + raise SpecError(node, "too many arguments (%s)"
177 + % ", ".join(repr(a) for a in args))
178 + del new.params[:]
179 + return new
180 +
181 +def build (spec, main=None) :
182 + b = Builder(spec)
183 + if main is None :
184 + return b.build(spec.main)
185 + else :
186 + return b.build(main)