blob: f4dd90c95ee07a1971996d3413fc67cec0c543c7 [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001"Usage: unparse.py <path to source file>"
2import sys
Martin v. Löwis3fa6c092006-04-10 12:43:55 +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)
Tim Peters3daf3042006-04-10 20:28:40 +000075
Martin v. Löwis3fa6c092006-04-10 12:43:55 +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?
Tim Peters400cbc32006-02-28 18:44:41 +000087
88 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
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000106 def _Pass(self, t):
107 self.fill("pass")
Tim Peters3daf3042006-04-10 20:28:40 +0000108
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000109 def _Break(self, t):
110 self.fill("break")
111
112 def _Continue(self, t):
113 self.fill("continue")
Tim Peters3daf3042006-04-10 20:28:40 +0000114
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000115 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)
Tim Peters3daf3042006-04-10 20:28:40 +0000125
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000126 def _Exec(self, t):
127 self.fill("exec ")
128 self.dispatch(t.body)
129 if t.globals:
130 self.write(" in ")
131 self.dispatch(t.globals)
132 if t.locals:
133 self.write(", ")
134 self.dispatch(t.locals)
135
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000136 def _Print(self, t):
137 self.fill("print ")
138 do_comma = False
139 if t.dest:
140 self.write(">>")
141 self.dispatch(t.dest)
142 do_comma = True
143 for e in t.values:
144 if do_comma:self.write(", ")
145 else:do_comma=True
146 self.dispatch(e)
147 if not t.nl:
148 self.write(",")
149
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000150 def _Global(self, t):
151 self.fill("global")
152 for i, n in enumerate(t.names):
153 if i != 0:
154 self.write(",")
155 self.write(" " + n)
156
157 def _Yield(self, t):
158 self.fill("yield")
159 if t.value:
160 self.write(" (")
161 self.dispatch(t.value)
162 self.write(")")
Tim Peters3daf3042006-04-10 20:28:40 +0000163
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000164 def _Raise(self, t):
165 self.fill('raise ')
166 if t.type:
167 self.dispatch(t.type)
168 if t.inst:
169 self.write(", ")
170 self.dispatch(t.inst)
171 if t.tback:
172 self.write(", ")
173 self.dispatch(t.tback)
Tim Peters3daf3042006-04-10 20:28:40 +0000174
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000175 def _TryExcept(self, t):
176 self.fill("try")
177 self.enter()
178 self.dispatch(t.body)
179 self.leave()
Tim Peters3daf3042006-04-10 20:28:40 +0000180
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000181 for ex in t.handlers:
182 self.dispatch(ex)
183 if t.orelse:
184 self.fill("else")
185 self.enter()
186 self.dispatch(t.orelse)
187 self.leave()
188
189 def _TryFinally(self, t):
190 self.fill("try")
191 self.enter()
192 self.dispatch(t.body)
193 self.leave()
194
195 self.fill("finally")
196 self.enter()
197 self.dispatch(t.finalbody)
198 self.leave()
199
200 def _excepthandler(self, t):
201 self.fill("except ")
202 if t.type:
203 self.dispatch(t.type)
204 if t.name:
205 self.write(", ")
206 self.dispatch(t.name)
207 self.enter()
208 self.dispatch(t.body)
209 self.leave()
Tim Peters3daf3042006-04-10 20:28:40 +0000210
Tim Peters400cbc32006-02-28 18:44:41 +0000211 def _ClassDef(self, t):
212 self.write("\n")
213 self.fill("class "+t.name)
214 if t.bases:
215 self.write("(")
216 for a in t.bases:
217 self.dispatch(a)
218 self.write(", ")
219 self.write(")")
220 self.enter()
221 self.dispatch(t.body)
222 self.leave()
223
224 def _FunctionDef(self, t):
225 self.write("\n")
Georg Brandl27562782006-10-27 20:39:43 +0000226 for deco in t.decorators:
227 self.fill("@")
228 self.dispatch(deco)
Tim Peters400cbc32006-02-28 18:44:41 +0000229 self.fill("def "+t.name + "(")
230 self.dispatch(t.args)
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000231 self.write(")")
Tim Peters400cbc32006-02-28 18:44:41 +0000232 self.enter()
233 self.dispatch(t.body)
234 self.leave()
235
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000236 def _For(self, t):
237 self.fill("for ")
238 self.dispatch(t.target)
239 self.write(" in ")
240 self.dispatch(t.iter)
241 self.enter()
242 self.dispatch(t.body)
243 self.leave()
244 if t.orelse:
245 self.fill("else")
246 self.enter()
247 self.dispatch(t.orelse)
248 self.leave
249
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000250 def _If(self, t):
251 self.fill("if ")
252 self.dispatch(t.test)
253 self.enter()
254 # XXX elif?
255 self.dispatch(t.body)
256 self.leave()
257 if t.orelse:
258 self.fill("else")
259 self.enter()
260 self.dispatch(t.orelse)
261 self.leave()
262
263 def _While(self, t):
264 self.fill("while ")
265 self.dispatch(t.test)
266 self.enter()
267 self.dispatch(t.body)
268 self.leave()
269 if t.orelse:
270 self.fill("else")
271 self.enter()
272 self.dispatch(t.orelse)
273 self.leave
Tim Peters3daf3042006-04-10 20:28:40 +0000274
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000275 def _With(self, t):
276 self.fill("with ")
277 self.dispatch(t.context_expr)
278 if t.optional_vars:
279 self.write(" as ")
280 self.dispatch(t.optional_vars)
281 self.enter()
282 self.dispatch(t.body)
283 self.leave()
284
Tim Peters400cbc32006-02-28 18:44:41 +0000285 # expr
286 def _Str(self, tree):
287 self.write(repr(tree.s))
288
289 def _Name(self, t):
290 self.write(t.id)
291
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000292 def _Repr(self, t):
293 self.write("`")
294 self.dispatch(t.value)
295 self.write("`")
Tim Peters3daf3042006-04-10 20:28:40 +0000296
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000297 def _Num(self, t):
298 self.write(repr(t.n))
299
Tim Peters400cbc32006-02-28 18:44:41 +0000300 def _List(self, t):
301 self.write("[")
302 for e in t.elts:
303 self.dispatch(e)
304 self.write(", ")
305 self.write("]")
306
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000307 def _ListComp(self, t):
308 self.write("[")
309 self.dispatch(t.elt)
310 for gen in t.generators:
311 self.dispatch(gen)
312 self.write("]")
Tim Peters3daf3042006-04-10 20:28:40 +0000313
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000314 def _GeneratorExp(self, t):
315 self.write("(")
316 self.dispatch(t.elt)
317 for gen in t.generators:
318 self.dispatch(gen)
319 self.write(")")
Tim Peters3daf3042006-04-10 20:28:40 +0000320
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000321 def _comprehension(self, t):
322 self.write(" for ")
323 self.dispatch(t.target)
324 self.write(" in ")
325 self.dispatch(t.iter)
326 for if_clause in t.ifs:
327 self.write(" if ")
328 self.dispatch(if_clause)
329
330 def _IfExp(self, t):
331 self.dispatch(t.body)
332 self.write(" if ")
333 self.dispatch(t.test)
334 if t.orelse:
335 self.write(" else ")
336 self.dispatch(t.orelse)
Tim Peters3daf3042006-04-10 20:28:40 +0000337
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000338 def _Dict(self, t):
339 self.write("{")
340 for k,v in zip(t.keys, t.values):
341 self.dispatch(k)
342 self.write(" : ")
343 self.dispatch(v)
344 self.write(", ")
345 self.write("}")
346
347 def _Tuple(self, t):
348 if not t.elts:
349 self.write("()")
350 return
351 self.write("(")
352 for e in t.elts:
353 self.dispatch(e)
354 self.write(", ")
355 self.write(")")
356
Tim Peters400cbc32006-02-28 18:44:41 +0000357 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
358 def _UnaryOp(self, t):
359 self.write(self.unop[t.op.__class__.__name__])
360 self.write("(")
361 self.dispatch(t.operand)
362 self.write(")")
363
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000364 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000365 "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
366 "FloorDiv":"//", "Pow": "**"}
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000367 def _BinOp(self, t):
368 self.write("(")
369 self.dispatch(t.left)
370 self.write(")" + self.binop[t.op.__class__.__name__] + "(")
371 self.dispatch(t.right)
372 self.write(")")
373
374 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
375 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
376 def _Compare(self, t):
377 self.write("(")
378 self.dispatch(t.left)
379 for o, e in zip(t.ops, t.comparators):
380 self.write(") " +self.cmpops[o.__class__.__name__] + " (")
381 self.dispatch(e)
382 self.write(")")
383
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000384 boolops = {_ast.And: 'and', _ast.Or: 'or'}
385 def _BoolOp(self, t):
386 self.write("(")
387 self.dispatch(t.values[0])
388 for v in t.values[1:]:
389 self.write(" %s " % self.boolops[t.op.__class__])
390 self.dispatch(v)
391 self.write(")")
Tim Peters3daf3042006-04-10 20:28:40 +0000392
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000393 def _Attribute(self,t):
394 self.dispatch(t.value)
395 self.write(".")
396 self.write(t.attr)
397
398 def _Call(self, t):
399 self.dispatch(t.func)
400 self.write("(")
401 comma = False
402 for e in t.args:
403 if comma: self.write(", ")
404 else: comma = True
405 self.dispatch(e)
406 for e in t.keywords:
407 if comma: self.write(", ")
408 else: comma = True
409 self.dispatch(e)
410 if t.starargs:
411 if comma: self.write(", ")
412 else: comma = True
413 self.write("*")
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000414 self.dispatch(t.starargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000415 if t.kwargs:
416 if comma: self.write(", ")
417 else: comma = True
418 self.write("**")
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000419 self.dispatch(t.kwargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000420 self.write(")")
421
422 def _Subscript(self, t):
423 self.dispatch(t.value)
424 self.write("[")
425 self.dispatch(t.slice)
426 self.write("]")
427
428 # slice
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000429 def _Ellipsis(self, t):
430 self.write("...")
Tim Peters3daf3042006-04-10 20:28:40 +0000431
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000432 def _Index(self, t):
433 self.dispatch(t.value)
434
435 def _Slice(self, t):
436 if t.lower:
437 self.dispatch(t.lower)
438 self.write(":")
439 if t.upper:
440 self.dispatch(t.upper)
441 if t.step:
442 self.write(":")
443 self.dispatch(t.step)
444
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000445 def _ExtSlice(self, t):
446 for i, d in enumerate(t.dims):
447 if i != 0:
448 self.write(': ')
449 self.dispatch(d)
Tim Peters3daf3042006-04-10 20:28:40 +0000450
Tim Peters400cbc32006-02-28 18:44:41 +0000451 # others
452 def _arguments(self, t):
453 first = True
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000454 nonDef = len(t.args)-len(t.defaults)
455 for a in t.args[0:nonDef]:
Tim Peters400cbc32006-02-28 18:44:41 +0000456 if first:first = False
457 else: self.write(", ")
458 self.dispatch(a)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000459 for a,d in zip(t.args[nonDef:], t.defaults):
460 if first:first = False
461 else: self.write(", ")
462 self.dispatch(a),
463 self.write("=")
464 self.dispatch(d)
Tim Peters400cbc32006-02-28 18:44:41 +0000465 if t.vararg:
466 if first:first = False
467 else: self.write(", ")
468 self.write("*"+t.vararg)
469 if t.kwarg:
470 if first:first = False
471 else: self.write(", ")
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000472 self.write("**"+t.kwarg)
Tim Peters400cbc32006-02-28 18:44:41 +0000473
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000474 def _keyword(self, t):
475 self.write(t.arg)
476 self.write("=")
477 self.dispatch(t.value)
Tim Peters3daf3042006-04-10 20:28:40 +0000478
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000479 def _Lambda(self, t):
480 self.write("lambda ")
481 self.dispatch(t.args)
482 self.write(": ")
483 self.dispatch(t.body)
Tim Peters3daf3042006-04-10 20:28:40 +0000484
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000485def roundtrip(filename, output=sys.stdout):
Tim Peters400cbc32006-02-28 18:44:41 +0000486 source = open(filename).read()
487 tree = compile(source, filename, "exec", 0x400)
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000488 Unparser(tree, output)
Tim Peters400cbc32006-02-28 18:44:41 +0000489
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000490
491
492def testdir(a):
493 try:
494 names = [n for n in os.listdir(a) if n.endswith('.py')]
495 except OSError:
496 print >> sys.stderr, "Directory not readable: %s" % a
497 else:
498 for n in names:
499 fullname = os.path.join(a, n)
500 if os.path.isfile(fullname):
501 output = cStringIO.StringIO()
502 print 'Testing %s' % fullname
503 try:
504 roundtrip(fullname, output)
505 except Exception, e:
506 print ' Failed to compile, exception is %s' % repr(e)
507 elif os.path.isdir(fullname):
508 testdir(fullname)
509
510def main(args):
511 if args[0] == '--testdir':
512 for a in args[1:]:
513 testdir(a)
514 else:
515 for a in args:
516 roundtrip(a)
Tim Peters3daf3042006-04-10 20:28:40 +0000517
Tim Peters400cbc32006-02-28 18:44:41 +0000518if __name__=='__main__':
Martin v. Löwis3fa6c092006-04-10 12:43:55 +0000519 main(sys.argv[1:])