blob: 1c6e9330d4dbb6d27ce15afe7ed18c1d0d5c6cb3 [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001"Usage: unparse.py <path to source file>"
2import sys
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00003import _ast
4import cStringIO
5import os
Tim Peters400cbc32006-02-28 18:44:41 +00006
7class Unparser:
8 """Methods in this class recursively traverse an AST and
9 output source code for the abstract syntax; original formatting
10 is disregarged. """
11
12 def __init__(self, tree, file = sys.stdout):
13 """Unparser(tree, file=sys.stdout) -> None.
14 Print the source for tree to file."""
15 self.f = file
16 self._indent = 0
17 self.dispatch(tree)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +000018 print >>self.f,""
Tim Peters400cbc32006-02-28 18:44:41 +000019 self.f.flush()
20
21 def fill(self, text = ""):
22 "Indent a piece of text, according to the current indentation level"
23 self.f.write("\n"+" "*self._indent + text)
24
25 def write(self, text):
26 "Append a piece of text to the current line."
27 self.f.write(text)
28
29 def enter(self):
30 "Print ':', and increase the indentation."
31 self.write(":")
32 self._indent += 1
33
34 def leave(self):
35 "Decrease the indentation level."
36 self._indent -= 1
37
38 def dispatch(self, tree):
39 "Dispatcher function, dispatching tree type T to method _T."
40 if isinstance(tree, list):
41 for t in tree:
42 self.dispatch(t)
43 return
44 meth = getattr(self, "_"+tree.__class__.__name__)
45 meth(tree)
46
47
48 ############### Unparsing methods ######################
49 # There should be one method per concrete grammar type #
50 # Constructors should be grouped by sum type. Ideally, #
51 # this would follow the order in the grammar, but #
52 # currently doesn't. #
53 ########################################################
54
55 def _Module(self, tree):
56 for stmt in tree.body:
57 self.dispatch(stmt)
58
59 # stmt
60 def _Expr(self, tree):
61 self.fill()
62 self.dispatch(tree.value)
63
64 def _Import(self, t):
65 self.fill("import ")
66 first = True
67 for a in t.names:
68 if first:
69 first = False
70 else:
71 self.write(", ")
72 self.write(a.name)
73 if a.asname:
74 self.write(" as "+a.asname)
75
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000076 def _ImportFrom(self, t):
77 self.fill("from ")
78 self.write(t.module)
79 self.write(" import ")
80 for i, a in enumerate(t.names):
81 if i == 0:
82 self.write(", ")
83 self.write(a.name)
84 if a.asname:
85 self.write(" as "+a.asname)
86 # XXX(jpe) what is level for?
87
Tim Peters400cbc32006-02-28 18:44:41 +000088 def _Assign(self, t):
89 self.fill()
90 for target in t.targets:
91 self.dispatch(target)
92 self.write(" = ")
93 self.dispatch(t.value)
94
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +000095 def _AugAssign(self, t):
96 self.fill()
97 self.dispatch(t.target)
98 self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
99 self.dispatch(t.value)
100
101 def _Return(self, t):
102 self.fill("return ")
103 if t.value:
104 self.dispatch(t.value)
105
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000106 def _Pass(self, t):
107 self.fill("pass")
108
109 def _Break(self, t):
110 self.fill("break")
111
112 def _Continue(self, t):
113 self.fill("continue")
114
115 def _Delete(self, t):
116 self.fill("del ")
117 self.dispatch(t.targets)
118
119 def _Assert(self, t):
120 self.fill("assert ")
121 self.dispatch(t.test)
122 if t.msg:
123 self.write(", ")
124 self.dispatch(t.msg)
125
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000126 def _Print(self, t):
127 self.fill("print ")
128 do_comma = False
129 if t.dest:
130 self.write(">>")
131 self.dispatch(t.dest)
132 do_comma = True
133 for e in t.values:
134 if do_comma:self.write(", ")
135 else:do_comma=True
136 self.dispatch(e)
137 if not t.nl:
138 self.write(",")
139
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000140 def _Global(self, t):
141 self.fill("global")
142 for i, n in enumerate(t.names):
143 if i != 0:
144 self.write(",")
145 self.write(" " + n)
146
147 def _Yield(self, t):
148 self.fill("yield")
149 if t.value:
150 self.write(" (")
151 self.dispatch(t.value)
152 self.write(")")
153
154 def _Raise(self, t):
155 self.fill('raise ')
156 if t.type:
157 self.dispatch(t.type)
158 if t.inst:
159 self.write(", ")
160 self.dispatch(t.inst)
161 if t.tback:
162 self.write(", ")
163 self.dispatch(t.tback)
164
165 def _TryExcept(self, t):
166 self.fill("try")
167 self.enter()
168 self.dispatch(t.body)
169 self.leave()
170
171 for ex in t.handlers:
172 self.dispatch(ex)
173 if t.orelse:
174 self.fill("else")
175 self.enter()
176 self.dispatch(t.orelse)
177 self.leave()
178
179 def _TryFinally(self, t):
180 self.fill("try")
181 self.enter()
182 self.dispatch(t.body)
183 self.leave()
184
185 self.fill("finally")
186 self.enter()
187 self.dispatch(t.finalbody)
188 self.leave()
189
190 def _excepthandler(self, t):
191 self.fill("except ")
192 if t.type:
193 self.dispatch(t.type)
194 if t.name:
195 self.write(", ")
196 self.dispatch(t.name)
197 self.enter()
198 self.dispatch(t.body)
199 self.leave()
200
Tim Peters400cbc32006-02-28 18:44:41 +0000201 def _ClassDef(self, t):
202 self.write("\n")
203 self.fill("class "+t.name)
204 if t.bases:
205 self.write("(")
206 for a in t.bases:
207 self.dispatch(a)
208 self.write(", ")
209 self.write(")")
210 self.enter()
211 self.dispatch(t.body)
212 self.leave()
213
214 def _FunctionDef(self, t):
215 self.write("\n")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000216 for deco in t.decorators:
217 self.fill("@")
218 self.dispatch(deco)
Tim Peters400cbc32006-02-28 18:44:41 +0000219 self.fill("def "+t.name + "(")
220 self.dispatch(t.args)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000221 self.write(")")
Tim Peters400cbc32006-02-28 18:44:41 +0000222 self.enter()
223 self.dispatch(t.body)
224 self.leave()
225
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000226 def _For(self, t):
227 self.fill("for ")
228 self.dispatch(t.target)
229 self.write(" in ")
230 self.dispatch(t.iter)
231 self.enter()
232 self.dispatch(t.body)
233 self.leave()
234 if t.orelse:
235 self.fill("else")
236 self.enter()
237 self.dispatch(t.orelse)
238 self.leave
239
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000240 def _If(self, t):
241 self.fill("if ")
242 self.dispatch(t.test)
243 self.enter()
244 # XXX elif?
245 self.dispatch(t.body)
246 self.leave()
247 if t.orelse:
248 self.fill("else")
249 self.enter()
250 self.dispatch(t.orelse)
251 self.leave()
252
253 def _While(self, t):
254 self.fill("while ")
255 self.dispatch(t.test)
256 self.enter()
257 self.dispatch(t.body)
258 self.leave()
259 if t.orelse:
260 self.fill("else")
261 self.enter()
262 self.dispatch(t.orelse)
263 self.leave
264
265 def _With(self, t):
266 self.fill("with ")
267 self.dispatch(t.context_expr)
268 if t.optional_vars:
269 self.write(" as ")
270 self.dispatch(t.optional_vars)
271 self.enter()
272 self.dispatch(t.body)
273 self.leave()
274
Tim Peters400cbc32006-02-28 18:44:41 +0000275 # expr
276 def _Str(self, tree):
277 self.write(repr(tree.s))
278
279 def _Name(self, t):
280 self.write(t.id)
281
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000282 def _Repr(self, t):
283 self.write("`")
284 self.dispatch(t.value)
285 self.write("`")
286
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000287 def _Num(self, t):
288 self.write(repr(t.n))
289
Tim Peters400cbc32006-02-28 18:44:41 +0000290 def _List(self, t):
291 self.write("[")
292 for e in t.elts:
293 self.dispatch(e)
294 self.write(", ")
295 self.write("]")
296
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000297 def _ListComp(self, t):
298 self.write("[")
299 self.dispatch(t.elt)
300 for gen in t.generators:
301 self.dispatch(gen)
302 self.write("]")
303
304 def _GeneratorExp(self, t):
305 self.write("(")
306 self.dispatch(t.elt)
307 for gen in t.generators:
308 self.dispatch(gen)
309 self.write(")")
310
311 def _comprehension(self, t):
312 self.write(" for ")
313 self.dispatch(t.target)
314 self.write(" in ")
315 self.dispatch(t.iter)
316 for if_clause in t.ifs:
317 self.write(" if ")
318 self.dispatch(if_clause)
319
320 def _IfExp(self, t):
321 self.dispatch(t.body)
322 self.write(" if ")
323 self.dispatch(t.test)
324 if t.orelse:
325 self.write(" else ")
326 self.dispatch(t.orelse)
327
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000328 def _Dict(self, t):
329 self.write("{")
330 for k,v in zip(t.keys, t.values):
331 self.dispatch(k)
332 self.write(" : ")
333 self.dispatch(v)
334 self.write(", ")
335 self.write("}")
336
337 def _Tuple(self, t):
338 if not t.elts:
339 self.write("()")
340 return
341 self.write("(")
342 for e in t.elts:
343 self.dispatch(e)
344 self.write(", ")
345 self.write(")")
346
Tim Peters400cbc32006-02-28 18:44:41 +0000347 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
348 def _UnaryOp(self, t):
349 self.write(self.unop[t.op.__class__.__name__])
350 self.write("(")
351 self.dispatch(t.operand)
352 self.write(")")
353
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000354 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000355 "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
356 "FloorDiv":"//", "Pow": "**"}
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000357 def _BinOp(self, t):
358 self.write("(")
359 self.dispatch(t.left)
360 self.write(")" + self.binop[t.op.__class__.__name__] + "(")
361 self.dispatch(t.right)
362 self.write(")")
363
364 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
365 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
366 def _Compare(self, t):
367 self.write("(")
368 self.dispatch(t.left)
369 for o, e in zip(t.ops, t.comparators):
370 self.write(") " +self.cmpops[o.__class__.__name__] + " (")
371 self.dispatch(e)
372 self.write(")")
373
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000374 boolops = {_ast.And: 'and', _ast.Or: 'or'}
375 def _BoolOp(self, t):
376 self.write("(")
377 self.dispatch(t.values[0])
378 for v in t.values[1:]:
379 self.write(" %s " % self.boolops[t.op.__class__])
380 self.dispatch(v)
381 self.write(")")
382
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000383 def _Attribute(self,t):
384 self.dispatch(t.value)
385 self.write(".")
386 self.write(t.attr)
387
388 def _Call(self, t):
389 self.dispatch(t.func)
390 self.write("(")
391 comma = False
392 for e in t.args:
393 if comma: self.write(", ")
394 else: comma = True
395 self.dispatch(e)
396 for e in t.keywords:
397 if comma: self.write(", ")
398 else: comma = True
399 self.dispatch(e)
400 if t.starargs:
401 if comma: self.write(", ")
402 else: comma = True
403 self.write("*")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000404 self.dispatch(t.starargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000405 if t.kwargs:
406 if comma: self.write(", ")
407 else: comma = True
408 self.write("**")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000409 self.dispatch(t.kwargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000410 self.write(")")
411
412 def _Subscript(self, t):
413 self.dispatch(t.value)
414 self.write("[")
415 self.dispatch(t.slice)
416 self.write("]")
417
418 # slice
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000419 def _Ellipsis(self, t):
420 self.write("...")
421
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000422 def _Index(self, t):
423 self.dispatch(t.value)
424
425 def _Slice(self, t):
426 if t.lower:
427 self.dispatch(t.lower)
428 self.write(":")
429 if t.upper:
430 self.dispatch(t.upper)
431 if t.step:
432 self.write(":")
433 self.dispatch(t.step)
434
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000435 def _ExtSlice(self, t):
436 for i, d in enumerate(t.dims):
437 if i != 0:
438 self.write(': ')
439 self.dispatch(d)
440
Tim Peters400cbc32006-02-28 18:44:41 +0000441 # others
442 def _arguments(self, t):
443 first = True
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000444 nonDef = len(t.args)-len(t.defaults)
445 for a in t.args[0:nonDef]:
Tim Peters400cbc32006-02-28 18:44:41 +0000446 if first:first = False
447 else: self.write(", ")
448 self.dispatch(a)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000449 for a,d in zip(t.args[nonDef:], t.defaults):
450 if first:first = False
451 else: self.write(", ")
452 self.dispatch(a),
453 self.write("=")
454 self.dispatch(d)
Tim Peters400cbc32006-02-28 18:44:41 +0000455 if t.vararg:
456 if first:first = False
457 else: self.write(", ")
458 self.write("*"+t.vararg)
459 if t.kwarg:
460 if first:first = False
461 else: self.write(", ")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000462 self.write("**"+t.kwarg)
Tim Peters400cbc32006-02-28 18:44:41 +0000463
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000464 def _keyword(self, t):
465 self.write(t.arg)
466 self.write("=")
467 self.dispatch(t.value)
468
469 def _Lambda(self, t):
470 self.write("lambda ")
471 self.dispatch(t.args)
472 self.write(": ")
473 self.dispatch(t.body)
474
475def roundtrip(filename, output=sys.stdout):
Tim Peters400cbc32006-02-28 18:44:41 +0000476 source = open(filename).read()
477 tree = compile(source, filename, "exec", 0x400)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000478 Unparser(tree, output)
479
480
481
482def testdir(a):
483 try:
484 names = [n for n in os.listdir(a) if n.endswith('.py')]
485 except OSError:
486 print >> sys.stderr, "Directory not readable: %s" % a
487 else:
488 for n in names:
489 fullname = os.path.join(a, n)
490 if os.path.isfile(fullname):
491 output = cStringIO.StringIO()
492 print 'Testing %s' % fullname
493 try:
494 roundtrip(fullname, output)
Guido van Rossumb940e112007-01-10 16:19:56 +0000495 except Exception as e:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000496 print ' Failed to compile, exception is %s' % repr(e)
497 elif os.path.isdir(fullname):
498 testdir(fullname)
499
500def main(args):
501 if args[0] == '--testdir':
502 for a in args[1:]:
503 testdir(a)
504 else:
505 for a in args:
506 roundtrip(a)
Tim Peters400cbc32006-02-28 18:44:41 +0000507
508if __name__=='__main__':
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000509 main(sys.argv[1:])