blob: dd75c227ee5588a205d9ff55e1e2dcecd0b13385 [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001"Usage: unparse.py <path to source file>"
2import sys
3
4class Unparser:
5 """Methods in this class recursively traverse an AST and
6 output source code for the abstract syntax; original formatting
7 is disregarged. """
8
9 def __init__(self, tree, file = sys.stdout):
10 """Unparser(tree, file=sys.stdout) -> None.
11 Print the source for tree to file."""
12 self.f = file
13 self._indent = 0
14 self.dispatch(tree)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +000015 print >>self.f,""
Tim Peters400cbc32006-02-28 18:44:41 +000016 self.f.flush()
17
18 def fill(self, text = ""):
19 "Indent a piece of text, according to the current indentation level"
20 self.f.write("\n"+" "*self._indent + text)
21
22 def write(self, text):
23 "Append a piece of text to the current line."
24 self.f.write(text)
25
26 def enter(self):
27 "Print ':', and increase the indentation."
28 self.write(":")
29 self._indent += 1
30
31 def leave(self):
32 "Decrease the indentation level."
33 self._indent -= 1
34
35 def dispatch(self, tree):
36 "Dispatcher function, dispatching tree type T to method _T."
37 if isinstance(tree, list):
38 for t in tree:
39 self.dispatch(t)
40 return
41 meth = getattr(self, "_"+tree.__class__.__name__)
42 meth(tree)
43
44
45 ############### Unparsing methods ######################
46 # There should be one method per concrete grammar type #
47 # Constructors should be grouped by sum type. Ideally, #
48 # this would follow the order in the grammar, but #
49 # currently doesn't. #
50 ########################################################
51
52 def _Module(self, tree):
53 for stmt in tree.body:
54 self.dispatch(stmt)
55
56 # stmt
57 def _Expr(self, tree):
58 self.fill()
59 self.dispatch(tree.value)
60
61 def _Import(self, t):
62 self.fill("import ")
63 first = True
64 for a in t.names:
65 if first:
66 first = False
67 else:
68 self.write(", ")
69 self.write(a.name)
70 if a.asname:
71 self.write(" as "+a.asname)
72
73 def _Assign(self, t):
74 self.fill()
75 for target in t.targets:
76 self.dispatch(target)
77 self.write(" = ")
78 self.dispatch(t.value)
79
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +000080 def _AugAssign(self, t):
81 self.fill()
82 self.dispatch(t.target)
83 self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
84 self.dispatch(t.value)
85
86 def _Return(self, t):
87 self.fill("return ")
88 if t.value:
89 self.dispatch(t.value)
90
91 def _Print(self, t):
92 self.fill("print ")
93 do_comma = False
94 if t.dest:
95 self.write(">>")
96 self.dispatch(t.dest)
97 do_comma = True
98 for e in t.values:
99 if do_comma:self.write(", ")
100 else:do_comma=True
101 self.dispatch(e)
102 if not t.nl:
103 self.write(",")
104
Tim Peters400cbc32006-02-28 18:44:41 +0000105 def _ClassDef(self, t):
106 self.write("\n")
107 self.fill("class "+t.name)
108 if t.bases:
109 self.write("(")
110 for a in t.bases:
111 self.dispatch(a)
112 self.write(", ")
113 self.write(")")
114 self.enter()
115 self.dispatch(t.body)
116 self.leave()
117
118 def _FunctionDef(self, t):
119 self.write("\n")
120 self.fill("def "+t.name + "(")
121 self.dispatch(t.args)
122 self.enter()
123 self.dispatch(t.body)
124 self.leave()
125
126 def _If(self, t):
127 self.fill("if ")
128 self.dispatch(t.test)
129 self.enter()
130 # XXX elif?
131 self.dispatch(t.body)
132 self.leave()
133 if t.orelse:
134 self.fill("else")
135 self.enter()
136 self.dispatch(t.orelse)
137 self.leave()
138
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000139 def _For(self, t):
140 self.fill("for ")
141 self.dispatch(t.target)
142 self.write(" in ")
143 self.dispatch(t.iter)
144 self.enter()
145 self.dispatch(t.body)
146 self.leave()
147 if t.orelse:
148 self.fill("else")
149 self.enter()
150 self.dispatch(t.orelse)
151 self.leave
152
Tim Peters400cbc32006-02-28 18:44:41 +0000153 # expr
154 def _Str(self, tree):
155 self.write(repr(tree.s))
156
157 def _Name(self, t):
158 self.write(t.id)
159
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000160 def _Num(self, t):
161 self.write(repr(t.n))
162
Tim Peters400cbc32006-02-28 18:44:41 +0000163 def _List(self, t):
164 self.write("[")
165 for e in t.elts:
166 self.dispatch(e)
167 self.write(", ")
168 self.write("]")
169
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000170 def _Dict(self, t):
171 self.write("{")
172 for k,v in zip(t.keys, t.values):
173 self.dispatch(k)
174 self.write(" : ")
175 self.dispatch(v)
176 self.write(", ")
177 self.write("}")
178
179 def _Tuple(self, t):
180 if not t.elts:
181 self.write("()")
182 return
183 self.write("(")
184 for e in t.elts:
185 self.dispatch(e)
186 self.write(", ")
187 self.write(")")
188
Tim Peters400cbc32006-02-28 18:44:41 +0000189 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
190 def _UnaryOp(self, t):
191 self.write(self.unop[t.op.__class__.__name__])
192 self.write("(")
193 self.dispatch(t.operand)
194 self.write(")")
195
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000196 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
197 "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
198 "FloorDiv":"//"}
199 def _BinOp(self, t):
200 self.write("(")
201 self.dispatch(t.left)
202 self.write(")" + self.binop[t.op.__class__.__name__] + "(")
203 self.dispatch(t.right)
204 self.write(")")
205
206 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
207 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
208 def _Compare(self, t):
209 self.write("(")
210 self.dispatch(t.left)
211 for o, e in zip(t.ops, t.comparators):
212 self.write(") " +self.cmpops[o.__class__.__name__] + " (")
213 self.dispatch(e)
214 self.write(")")
215
216 def _Attribute(self,t):
217 self.dispatch(t.value)
218 self.write(".")
219 self.write(t.attr)
220
221 def _Call(self, t):
222 self.dispatch(t.func)
223 self.write("(")
224 comma = False
225 for e in t.args:
226 if comma: self.write(", ")
227 else: comma = True
228 self.dispatch(e)
229 for e in t.keywords:
230 if comma: self.write(", ")
231 else: comma = True
232 self.dispatch(e)
233 if t.starargs:
234 if comma: self.write(", ")
235 else: comma = True
236 self.write("*")
237 self.dispatch(t.stararg)
238 if t.kwargs:
239 if comma: self.write(", ")
240 else: comma = True
241 self.write("**")
242 self.dispatch(t.stararg)
243 self.write(")")
244
245 def _Subscript(self, t):
246 self.dispatch(t.value)
247 self.write("[")
248 self.dispatch(t.slice)
249 self.write("]")
250
251 # slice
252 def _Index(self, t):
253 self.dispatch(t.value)
254
255 def _Slice(self, t):
256 if t.lower:
257 self.dispatch(t.lower)
258 self.write(":")
259 if t.upper:
260 self.dispatch(t.upper)
261 if t.step:
262 self.write(":")
263 self.dispatch(t.step)
264
Tim Peters400cbc32006-02-28 18:44:41 +0000265 # others
266 def _arguments(self, t):
267 first = True
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000268 nonDef = len(t.args)-len(t.defaults)
269 for a in t.args[0:nonDef]:
Tim Peters400cbc32006-02-28 18:44:41 +0000270 if first:first = False
271 else: self.write(", ")
272 self.dispatch(a)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000273 for a,d in zip(t.args[nonDef:], t.defaults):
274 if first:first = False
275 else: self.write(", ")
276 self.dispatch(a),
277 self.write("=")
278 self.dispatch(d)
Tim Peters400cbc32006-02-28 18:44:41 +0000279 if t.vararg:
280 if first:first = False
281 else: self.write(", ")
282 self.write("*"+t.vararg)
283 if t.kwarg:
284 if first:first = False
285 else: self.write(", ")
286 self.write("**"+self.kwarg)
287 self.write(")")
288
289def roundtrip(filename):
290 source = open(filename).read()
291 tree = compile(source, filename, "exec", 0x400)
292 Unparser(tree)
293
294if __name__=='__main__':
295 roundtrip(sys.argv[1])