blob: 510cdb07ba11affb5ff66c8321ce32dba431a464 [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
126 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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +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(")")
163
164 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)
174
175 def _TryExcept(self, t):
176 self.fill("try")
177 self.enter()
178 self.dispatch(t.body)
179 self.leave()
180
181 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()
210
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")
226 self.fill("def "+t.name + "(")
227 self.dispatch(t.args)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000228 self.write(")")
Tim Peters400cbc32006-02-28 18:44:41 +0000229 self.enter()
230 self.dispatch(t.body)
231 self.leave()
232
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000233 def _For(self, t):
234 self.fill("for ")
235 self.dispatch(t.target)
236 self.write(" in ")
237 self.dispatch(t.iter)
238 self.enter()
239 self.dispatch(t.body)
240 self.leave()
241 if t.orelse:
242 self.fill("else")
243 self.enter()
244 self.dispatch(t.orelse)
245 self.leave
246
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000247 def _If(self, t):
248 self.fill("if ")
249 self.dispatch(t.test)
250 self.enter()
251 # XXX elif?
252 self.dispatch(t.body)
253 self.leave()
254 if t.orelse:
255 self.fill("else")
256 self.enter()
257 self.dispatch(t.orelse)
258 self.leave()
259
260 def _While(self, t):
261 self.fill("while ")
262 self.dispatch(t.test)
263 self.enter()
264 self.dispatch(t.body)
265 self.leave()
266 if t.orelse:
267 self.fill("else")
268 self.enter()
269 self.dispatch(t.orelse)
270 self.leave
271
272 def _With(self, t):
273 self.fill("with ")
274 self.dispatch(t.context_expr)
275 if t.optional_vars:
276 self.write(" as ")
277 self.dispatch(t.optional_vars)
278 self.enter()
279 self.dispatch(t.body)
280 self.leave()
281
Tim Peters400cbc32006-02-28 18:44:41 +0000282 # expr
283 def _Str(self, tree):
284 self.write(repr(tree.s))
285
286 def _Name(self, t):
287 self.write(t.id)
288
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000289 def _Repr(self, t):
290 self.write("`")
291 self.dispatch(t.value)
292 self.write("`")
293
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000294 def _Num(self, t):
295 self.write(repr(t.n))
296
Tim Peters400cbc32006-02-28 18:44:41 +0000297 def _List(self, t):
298 self.write("[")
299 for e in t.elts:
300 self.dispatch(e)
301 self.write(", ")
302 self.write("]")
303
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000304 def _ListComp(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 _GeneratorExp(self, t):
312 self.write("(")
313 self.dispatch(t.elt)
314 for gen in t.generators:
315 self.dispatch(gen)
316 self.write(")")
317
318 def _comprehension(self, t):
319 self.write(" for ")
320 self.dispatch(t.target)
321 self.write(" in ")
322 self.dispatch(t.iter)
323 for if_clause in t.ifs:
324 self.write(" if ")
325 self.dispatch(if_clause)
326
327 def _IfExp(self, t):
328 self.dispatch(t.body)
329 self.write(" if ")
330 self.dispatch(t.test)
331 if t.orelse:
332 self.write(" else ")
333 self.dispatch(t.orelse)
334
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000335 def _Dict(self, t):
336 self.write("{")
337 for k,v in zip(t.keys, t.values):
338 self.dispatch(k)
339 self.write(" : ")
340 self.dispatch(v)
341 self.write(", ")
342 self.write("}")
343
344 def _Tuple(self, t):
345 if not t.elts:
346 self.write("()")
347 return
348 self.write("(")
349 for e in t.elts:
350 self.dispatch(e)
351 self.write(", ")
352 self.write(")")
353
Tim Peters400cbc32006-02-28 18:44:41 +0000354 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
355 def _UnaryOp(self, t):
356 self.write(self.unop[t.op.__class__.__name__])
357 self.write("(")
358 self.dispatch(t.operand)
359 self.write(")")
360
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000361 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000362 "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
363 "FloorDiv":"//", "Pow": "**"}
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000364 def _BinOp(self, t):
365 self.write("(")
366 self.dispatch(t.left)
367 self.write(")" + self.binop[t.op.__class__.__name__] + "(")
368 self.dispatch(t.right)
369 self.write(")")
370
371 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
372 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
373 def _Compare(self, t):
374 self.write("(")
375 self.dispatch(t.left)
376 for o, e in zip(t.ops, t.comparators):
377 self.write(") " +self.cmpops[o.__class__.__name__] + " (")
378 self.dispatch(e)
379 self.write(")")
380
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000381 boolops = {_ast.And: 'and', _ast.Or: 'or'}
382 def _BoolOp(self, t):
383 self.write("(")
384 self.dispatch(t.values[0])
385 for v in t.values[1:]:
386 self.write(" %s " % self.boolops[t.op.__class__])
387 self.dispatch(v)
388 self.write(")")
389
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000390 def _Attribute(self,t):
391 self.dispatch(t.value)
392 self.write(".")
393 self.write(t.attr)
394
395 def _Call(self, t):
396 self.dispatch(t.func)
397 self.write("(")
398 comma = False
399 for e in t.args:
400 if comma: self.write(", ")
401 else: comma = True
402 self.dispatch(e)
403 for e in t.keywords:
404 if comma: self.write(", ")
405 else: comma = True
406 self.dispatch(e)
407 if t.starargs:
408 if comma: self.write(", ")
409 else: comma = True
410 self.write("*")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000411 self.dispatch(t.starargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000412 if t.kwargs:
413 if comma: self.write(", ")
414 else: comma = True
415 self.write("**")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000416 self.dispatch(t.kwargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000417 self.write(")")
418
419 def _Subscript(self, t):
420 self.dispatch(t.value)
421 self.write("[")
422 self.dispatch(t.slice)
423 self.write("]")
424
425 # slice
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000426 def _Ellipsis(self, t):
427 self.write("...")
428
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000429 def _Index(self, t):
430 self.dispatch(t.value)
431
432 def _Slice(self, t):
433 if t.lower:
434 self.dispatch(t.lower)
435 self.write(":")
436 if t.upper:
437 self.dispatch(t.upper)
438 if t.step:
439 self.write(":")
440 self.dispatch(t.step)
441
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000442 def _ExtSlice(self, t):
443 for i, d in enumerate(t.dims):
444 if i != 0:
445 self.write(': ')
446 self.dispatch(d)
447
Tim Peters400cbc32006-02-28 18:44:41 +0000448 # others
449 def _arguments(self, t):
450 first = True
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000451 nonDef = len(t.args)-len(t.defaults)
452 for a in t.args[0:nonDef]:
Tim Peters400cbc32006-02-28 18:44:41 +0000453 if first:first = False
454 else: self.write(", ")
455 self.dispatch(a)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000456 for a,d in zip(t.args[nonDef:], t.defaults):
457 if first:first = False
458 else: self.write(", ")
459 self.dispatch(a),
460 self.write("=")
461 self.dispatch(d)
Tim Peters400cbc32006-02-28 18:44:41 +0000462 if t.vararg:
463 if first:first = False
464 else: self.write(", ")
465 self.write("*"+t.vararg)
466 if t.kwarg:
467 if first:first = False
468 else: self.write(", ")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469 self.write("**"+t.kwarg)
Tim Peters400cbc32006-02-28 18:44:41 +0000470
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000471 def _keyword(self, t):
472 self.write(t.arg)
473 self.write("=")
474 self.dispatch(t.value)
475
476 def _Lambda(self, t):
477 self.write("lambda ")
478 self.dispatch(t.args)
479 self.write(": ")
480 self.dispatch(t.body)
481
482def roundtrip(filename, output=sys.stdout):
Tim Peters400cbc32006-02-28 18:44:41 +0000483 source = open(filename).read()
484 tree = compile(source, filename, "exec", 0x400)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000485 Unparser(tree, output)
486
487
488
489def testdir(a):
490 try:
491 names = [n for n in os.listdir(a) if n.endswith('.py')]
492 except OSError:
493 print >> sys.stderr, "Directory not readable: %s" % a
494 else:
495 for n in names:
496 fullname = os.path.join(a, n)
497 if os.path.isfile(fullname):
498 output = cStringIO.StringIO()
499 print 'Testing %s' % fullname
500 try:
501 roundtrip(fullname, output)
502 except Exception, e:
503 print ' Failed to compile, exception is %s' % repr(e)
504 elif os.path.isdir(fullname):
505 testdir(fullname)
506
507def main(args):
508 if args[0] == '--testdir':
509 for a in args[1:]:
510 testdir(a)
511 else:
512 for a in args:
513 roundtrip(a)
Tim Peters400cbc32006-02-28 18:44:41 +0000514
515if __name__=='__main__':
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000516 main(sys.argv[1:])