blob: b02ef75db5b01e6047d9bdd85eb5af1362b5ee7b [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
Collin Winter6f2df4d2007-07-17 20:59:35 +00004import io
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005import os
Tim Peters400cbc32006-02-28 18:44:41 +00006
Guido van Rossumd8faa362007-04-27 19:54:29 +00007def interleave(inter, f, seq):
8 """Call f on each item in seq, calling inter() in between.
9 """
10 seq = iter(seq)
11 try:
Collin Winter6f2df4d2007-07-17 20:59:35 +000012 f(next(seq))
Guido van Rossumd8faa362007-04-27 19:54:29 +000013 except StopIteration:
14 pass
15 else:
16 for x in seq:
17 inter()
18 f(x)
19
Tim Peters400cbc32006-02-28 18:44:41 +000020class Unparser:
21 """Methods in this class recursively traverse an AST and
22 output source code for the abstract syntax; original formatting
23 is disregarged. """
24
25 def __init__(self, tree, file = sys.stdout):
26 """Unparser(tree, file=sys.stdout) -> None.
27 Print the source for tree to file."""
28 self.f = file
29 self._indent = 0
30 self.dispatch(tree)
Collin Winter6f2df4d2007-07-17 20:59:35 +000031 print("", file=self.f)
Tim Peters400cbc32006-02-28 18:44:41 +000032 self.f.flush()
33
34 def fill(self, text = ""):
35 "Indent a piece of text, according to the current indentation level"
36 self.f.write("\n"+" "*self._indent + text)
37
38 def write(self, text):
39 "Append a piece of text to the current line."
40 self.f.write(text)
41
42 def enter(self):
43 "Print ':', and increase the indentation."
44 self.write(":")
45 self._indent += 1
46
47 def leave(self):
48 "Decrease the indentation level."
49 self._indent -= 1
50
51 def dispatch(self, tree):
52 "Dispatcher function, dispatching tree type T to method _T."
53 if isinstance(tree, list):
54 for t in tree:
55 self.dispatch(t)
56 return
57 meth = getattr(self, "_"+tree.__class__.__name__)
58 meth(tree)
59
60
61 ############### Unparsing methods ######################
62 # There should be one method per concrete grammar type #
63 # Constructors should be grouped by sum type. Ideally, #
64 # this would follow the order in the grammar, but #
65 # currently doesn't. #
66 ########################################################
67
68 def _Module(self, tree):
69 for stmt in tree.body:
70 self.dispatch(stmt)
71
72 # stmt
73 def _Expr(self, tree):
74 self.fill()
75 self.dispatch(tree.value)
76
77 def _Import(self, t):
78 self.fill("import ")
Guido van Rossumd8faa362007-04-27 19:54:29 +000079 interleave(lambda: self.write(", "), self.dispatch, t.names)
Tim Peters400cbc32006-02-28 18:44:41 +000080
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000081 def _ImportFrom(self, t):
82 self.fill("from ")
83 self.write(t.module)
84 self.write(" import ")
Guido van Rossumd8faa362007-04-27 19:54:29 +000085 interleave(lambda: self.write(", "), self.dispatch, t.names)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000086 # 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):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000102 self.fill("return")
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000103 if t.value:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000104 self.write(" ")
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000105 self.dispatch(t.value)
106
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000107 def _Pass(self, t):
108 self.fill("pass")
109
110 def _Break(self, t):
111 self.fill("break")
112
113 def _Continue(self, t):
114 self.fill("continue")
115
116 def _Delete(self, t):
117 self.fill("del ")
Mark Dickinsonae100052010-06-28 19:44:20 +0000118 interleave(lambda: self.write(", "), self.dispatch, t.targets)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000119
120 def _Assert(self, t):
121 self.fill("assert ")
122 self.dispatch(t.test)
123 if t.msg:
124 self.write(", ")
125 self.dispatch(t.msg)
126
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000127 def _Print(self, t):
128 self.fill("print ")
129 do_comma = False
130 if t.dest:
131 self.write(">>")
132 self.dispatch(t.dest)
133 do_comma = True
134 for e in t.values:
135 if do_comma:self.write(", ")
136 else:do_comma=True
137 self.dispatch(e)
138 if not t.nl:
139 self.write(",")
140
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000141 def _Global(self, t):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000142 self.fill("global ")
143 interleave(lambda: self.write(", "), self.write, t.names)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000144
145 def _Yield(self, t):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000146 self.write("(")
147 self.write("yield")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000148 if t.value:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000149 self.write(" ")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000150 self.dispatch(t.value)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000151 self.write(")")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000152
153 def _Raise(self, t):
154 self.fill('raise ')
155 if t.type:
156 self.dispatch(t.type)
157 if t.inst:
158 self.write(", ")
159 self.dispatch(t.inst)
160 if t.tback:
161 self.write(", ")
162 self.dispatch(t.tback)
163
164 def _TryExcept(self, t):
165 self.fill("try")
166 self.enter()
167 self.dispatch(t.body)
168 self.leave()
169
170 for ex in t.handlers:
171 self.dispatch(ex)
172 if t.orelse:
173 self.fill("else")
174 self.enter()
175 self.dispatch(t.orelse)
176 self.leave()
177
178 def _TryFinally(self, t):
179 self.fill("try")
180 self.enter()
181 self.dispatch(t.body)
182 self.leave()
183
184 self.fill("finally")
185 self.enter()
186 self.dispatch(t.finalbody)
187 self.leave()
188
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000189 def _ExceptHandler(self, t):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000190 self.fill("except")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000191 if t.type:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000192 self.write(" ")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000193 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")
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000216 for deco in t.decorator_list:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000217 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)
Mark Dickinsonae100052010-06-28 19:44:20 +0000238 self.leave()
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000239
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)
Mark Dickinsonae100052010-06-28 19:44:20 +0000263 self.leave()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000264
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):
Mark Dickinsonae100052010-06-28 19:44:20 +0000288 # There are no negative numeric literals in Python; however,
289 # some optimizations produce a negative Num in the AST. Add
290 # parentheses to avoid turning (-1)**2 into -1**2.
291 strnum = repr(t.n)
292 if strnum.startswith("-"):
293 self.write("(")
294 self.write(strnum)
295 self.write(")")
296 else:
297 self.write(repr(t.n))
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000298
Tim Peters400cbc32006-02-28 18:44:41 +0000299 def _List(self, t):
300 self.write("[")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301 interleave(lambda: self.write(", "), self.dispatch, t.elts)
Tim Peters400cbc32006-02-28 18:44:41 +0000302 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):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000328 self.write("(")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000329 self.dispatch(t.body)
330 self.write(" if ")
331 self.dispatch(t.test)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000332 self.write(" else ")
333 self.dispatch(t.orelse)
334 self.write(")")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000335
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000336 def _Dict(self, t):
337 self.write("{")
Collin Winter6f2df4d2007-07-17 20:59:35 +0000338 def writem(xxx_todo_changeme):
339 (k, v) = xxx_todo_changeme
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000340 self.dispatch(k)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000341 self.write(": ")
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000342 self.dispatch(v)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000343 interleave(lambda: self.write(", "), writem, zip(t.keys, t.values))
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000344 self.write("}")
345
346 def _Tuple(self, t):
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000347 self.write("(")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000348 if len(t.elts) == 1:
349 (elt,) = t.elts
350 self.dispatch(elt)
351 self.write(",")
352 else:
353 interleave(lambda: self.write(", "), self.dispatch, t.elts)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000354 self.write(")")
355
Tim Peters400cbc32006-02-28 18:44:41 +0000356 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
357 def _UnaryOp(self, t):
Tim Peters400cbc32006-02-28 18:44:41 +0000358 self.write("(")
Mark Dickinsonae100052010-06-28 19:44:20 +0000359 self.write(self.unop[t.op.__class__.__name__])
360 self.write(" ")
Tim Peters400cbc32006-02-28 18:44:41 +0000361 self.dispatch(t.operand)
362 self.write(")")
363
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000364 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
Mark Dickinsonae100052010-06-28 19:44:20 +0000365 "LShift":"<<", "RShift":">>", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000366 "FloorDiv":"//", "Pow": "**"}
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000367 def _BinOp(self, t):
368 self.write("(")
369 self.dispatch(t.left)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000370 self.write(" " + self.binop[t.op.__class__.__name__] + " ")
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000371 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):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000380 self.write(" " + self.cmpops[o.__class__.__name__] + " ")
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000381 self.dispatch(e)
382 self.write(")")
383
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000384 boolops = {_ast.And: 'and', _ast.Or: 'or'}
385 def _BoolOp(self, t):
386 self.write("(")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000387 s = " %s " % self.boolops[t.op.__class__]
388 interleave(lambda: self.write(s), self.dispatch, t.values)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000389 self.write(")")
390
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000391 def _Attribute(self,t):
392 self.dispatch(t.value)
393 self.write(".")
394 self.write(t.attr)
395
396 def _Call(self, t):
397 self.dispatch(t.func)
398 self.write("(")
399 comma = False
400 for e in t.args:
401 if comma: self.write(", ")
402 else: comma = True
403 self.dispatch(e)
404 for e in t.keywords:
405 if comma: self.write(", ")
406 else: comma = True
407 self.dispatch(e)
408 if t.starargs:
409 if comma: self.write(", ")
410 else: comma = True
411 self.write("*")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000412 self.dispatch(t.starargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000413 if t.kwargs:
414 if comma: self.write(", ")
415 else: comma = True
416 self.write("**")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000417 self.dispatch(t.kwargs)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000418 self.write(")")
419
420 def _Subscript(self, t):
421 self.dispatch(t.value)
422 self.write("[")
423 self.dispatch(t.slice)
424 self.write("]")
425
426 # slice
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000427 def _Ellipsis(self, t):
428 self.write("...")
429
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000430 def _Index(self, t):
431 self.dispatch(t.value)
432
433 def _Slice(self, t):
434 if t.lower:
435 self.dispatch(t.lower)
436 self.write(":")
437 if t.upper:
438 self.dispatch(t.upper)
439 if t.step:
440 self.write(":")
441 self.dispatch(t.step)
442
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000443 def _ExtSlice(self, t):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000444 interleave(lambda: self.write(', '), self.dispatch, t.dims)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000445
Tim Peters400cbc32006-02-28 18:44:41 +0000446 # others
447 def _arguments(self, t):
448 first = True
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000449 nonDef = len(t.args)-len(t.defaults)
450 for a in t.args[0:nonDef]:
Tim Peters400cbc32006-02-28 18:44:41 +0000451 if first:first = False
452 else: self.write(", ")
453 self.dispatch(a)
Martin v. Löwis87a8b4f2006-02-28 21:41:30 +0000454 for a,d in zip(t.args[nonDef:], t.defaults):
455 if first:first = False
456 else: self.write(", ")
457 self.dispatch(a),
458 self.write("=")
459 self.dispatch(d)
Tim Peters400cbc32006-02-28 18:44:41 +0000460 if t.vararg:
461 if first:first = False
462 else: self.write(", ")
463 self.write("*"+t.vararg)
464 if t.kwarg:
465 if first:first = False
466 else: self.write(", ")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000467 self.write("**"+t.kwarg)
Tim Peters400cbc32006-02-28 18:44:41 +0000468
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469 def _keyword(self, t):
470 self.write(t.arg)
471 self.write("=")
472 self.dispatch(t.value)
473
474 def _Lambda(self, t):
475 self.write("lambda ")
476 self.dispatch(t.args)
477 self.write(": ")
478 self.dispatch(t.body)
479
Guido van Rossumd8faa362007-04-27 19:54:29 +0000480 def _alias(self, t):
481 self.write(t.name)
482 if t.asname:
483 self.write(" as "+t.asname)
484
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000485def roundtrip(filename, output=sys.stdout):
Tim Peters400cbc32006-02-28 18:44:41 +0000486 source = open(filename).read()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000487 tree = compile(source, filename, "exec", _ast.PyCF_ONLY_AST)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000488 Unparser(tree, output)
489
490
491
492def testdir(a):
493 try:
494 names = [n for n in os.listdir(a) if n.endswith('.py')]
495 except OSError:
Collin Winter6f2df4d2007-07-17 20:59:35 +0000496 print("Directory not readable: %s" % a, file=sys.stderr)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000497 else:
498 for n in names:
499 fullname = os.path.join(a, n)
500 if os.path.isfile(fullname):
Collin Winter6f2df4d2007-07-17 20:59:35 +0000501 output = io.StringIO()
502 print('Testing %s' % fullname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000503 try:
504 roundtrip(fullname, output)
Guido van Rossumb940e112007-01-10 16:19:56 +0000505 except Exception as e:
Collin Winter6f2df4d2007-07-17 20:59:35 +0000506 print(' Failed to compile, exception is %s' % repr(e))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000507 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 Peters400cbc32006-02-28 18:44:41 +0000517
518if __name__=='__main__':
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000519 main(sys.argv[1:])