1 "Usage: unparse.py <path to source file>"
7 def interleave(inter
, f
, seq
):
8 """Call f on each item in seq, calling inter() in between.
21 """Methods in this class recursively traverse an AST and
22 output source code for the abstract syntax; original formatting
25 def __init__(self
, tree
, file = sys
.stdout
):
26 """Unparser(tree, file=sys.stdout) -> None.
27 Print the source for tree to file."""
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
)
38 def write(self
, text
):
39 "Append a piece of text to the current line."
43 "Print ':', and increase the indentation."
48 "Decrease the indentation level."
51 def dispatch(self
, tree
):
52 "Dispatcher function, dispatching tree type T to method _T."
53 if isinstance(tree
, list):
57 meth
= getattr(self
, "_"+tree
.__class
__.__name
__)
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 ########################################################
68 def _Module(self
, tree
):
69 for stmt
in tree
.body
:
73 def _Expr(self
, tree
):
75 self
.dispatch(tree
.value
)
79 interleave(lambda: self
.write(", "), self
.dispatch
, t
.names
)
81 def _ImportFrom(self
, t
):
84 self
.write(" import ")
85 interleave(lambda: self
.write(", "), self
.dispatch
, t
.names
)
86 # XXX(jpe) what is level for?
90 for target
in t
.targets
:
93 self
.dispatch(t
.value
)
95 def _AugAssign(self
, t
):
97 self
.dispatch(t
.target
)
98 self
.write(" "+self
.binop
[t
.op
.__class
__.__name
__]+"= ")
99 self
.dispatch(t
.value
)
101 def _Return(self
, t
):
105 self
.dispatch(t
.value
)
113 def _Continue(self
, t
):
114 self
.fill("continue")
116 def _Delete(self
, t
):
118 self
.dispatch(t
.targets
)
120 def _Assert(self
, t
):
122 self
.dispatch(t
.test
)
129 self
.dispatch(t
.body
)
132 self
.dispatch(t
.globals)
135 self
.dispatch(t
.locals)
142 self
.dispatch(t
.dest
)
145 if do_comma
:self
.write(", ")
151 def _Global(self
, t
):
153 interleave(lambda: self
.write(", "), self
.write
, t
.names
)
160 self
.dispatch(t
.value
)
166 self
.dispatch(t
.type)
169 self
.dispatch(t
.inst
)
172 self
.dispatch(t
.tback
)
174 def _TryExcept(self
, t
):
177 self
.dispatch(t
.body
)
180 for ex
in t
.handlers
:
185 self
.dispatch(t
.orelse
)
188 def _TryFinally(self
, t
):
191 self
.dispatch(t
.body
)
196 self
.dispatch(t
.finalbody
)
199 def _ExceptHandler(self
, t
):
203 self
.dispatch(t
.type)
206 self
.dispatch(t
.name
)
208 self
.dispatch(t
.body
)
211 def _ClassDef(self
, t
):
213 self
.fill("class "+t
.name
)
221 self
.dispatch(t
.body
)
224 def _FunctionDef(self
, t
):
226 for deco
in t
.decorator_list
:
229 self
.fill("def "+t
.name
+ "(")
230 self
.dispatch(t
.args
)
233 self
.dispatch(t
.body
)
238 self
.dispatch(t
.target
)
240 self
.dispatch(t
.iter)
242 self
.dispatch(t
.body
)
247 self
.dispatch(t
.orelse
)
252 self
.dispatch(t
.test
)
255 self
.dispatch(t
.body
)
260 self
.dispatch(t
.orelse
)
265 self
.dispatch(t
.test
)
267 self
.dispatch(t
.body
)
272 self
.dispatch(t
.orelse
)
277 self
.dispatch(t
.context_expr
)
280 self
.dispatch(t
.optional_vars
)
282 self
.dispatch(t
.body
)
286 def _Str(self
, tree
):
287 self
.write(repr(tree
.s
))
294 self
.dispatch(t
.value
)
298 self
.write(repr(t
.n
))
302 interleave(lambda: self
.write(", "), self
.dispatch
, t
.elts
)
305 def _ListComp(self
, t
):
308 for gen
in t
.generators
:
312 def _GeneratorExp(self
, t
):
315 for gen
in t
.generators
:
319 def _comprehension(self
, t
):
321 self
.dispatch(t
.target
)
323 self
.dispatch(t
.iter)
324 for if_clause
in t
.ifs
:
326 self
.dispatch(if_clause
)
330 self
.dispatch(t
.body
)
332 self
.dispatch(t
.test
)
334 self
.dispatch(t
.orelse
)
343 interleave(lambda: self
.write(", "), writem
, zip(t
.keys
, t
.values
))
353 interleave(lambda: self
.write(", "), self
.dispatch
, t
.elts
)
356 unop
= {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
357 def _UnaryOp(self
, t
):
358 self
.write(self
.unop
[t
.op
.__class
__.__name
__])
360 self
.dispatch(t
.operand
)
363 binop
= { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
364 "LShift":">>", "RShift":"<<", "BitOr":"|", "BitXor":"^", "BitAnd":"&",
365 "FloorDiv":"//", "Pow": "**"}
368 self
.dispatch(t
.left
)
369 self
.write(" " + self
.binop
[t
.op
.__class
__.__name
__] + " ")
370 self
.dispatch(t
.right
)
373 cmpops
= {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=",
374 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"}
375 def _Compare(self
, t
):
377 self
.dispatch(t
.left
)
378 for o
, e
in zip(t
.ops
, t
.comparators
):
379 self
.write(" " + self
.cmpops
[o
.__class
__.__name
__] + " ")
383 boolops
= {_ast
.And
: 'and', _ast
.Or
: 'or'}
384 def _BoolOp(self
, t
):
386 s
= " %s " % self
.boolops
[t
.op
.__class
__]
387 interleave(lambda: self
.write(s
), self
.dispatch
, t
.values
)
390 def _Attribute(self
,t
):
391 self
.dispatch(t
.value
)
396 self
.dispatch(t
.func
)
400 if comma
: self
.write(", ")
404 if comma
: self
.write(", ")
408 if comma
: self
.write(", ")
411 self
.dispatch(t
.starargs
)
413 if comma
: self
.write(", ")
416 self
.dispatch(t
.kwargs
)
419 def _Subscript(self
, t
):
420 self
.dispatch(t
.value
)
422 self
.dispatch(t
.slice)
426 def _Ellipsis(self
, t
):
430 self
.dispatch(t
.value
)
434 self
.dispatch(t
.lower
)
437 self
.dispatch(t
.upper
)
440 self
.dispatch(t
.step
)
442 def _ExtSlice(self
, t
):
443 interleave(lambda: self
.write(', '), self
.dispatch
, t
.dims
)
446 def _arguments(self
, t
):
448 nonDef
= len(t
.args
)-len(t
.defaults
)
449 for a
in t
.args
[0:nonDef
]:
450 if first
:first
= False
451 else: self
.write(", ")
453 for a
,d
in zip(t
.args
[nonDef
:], t
.defaults
):
454 if first
:first
= False
455 else: self
.write(", ")
460 if first
:first
= False
461 else: self
.write(", ")
462 self
.write("*"+t
.vararg
)
464 if first
:first
= False
465 else: self
.write(", ")
466 self
.write("**"+t
.kwarg
)
468 def _keyword(self
, t
):
471 self
.dispatch(t
.value
)
473 def _Lambda(self
, t
):
474 self
.write("lambda ")
475 self
.dispatch(t
.args
)
477 self
.dispatch(t
.body
)
482 self
.write(" as "+t
.asname
)
484 def roundtrip(filename
, output
=sys
.stdout
):
485 source
= open(filename
).read()
486 tree
= compile(source
, filename
, "exec", _ast
.PyCF_ONLY_AST
)
487 Unparser(tree
, output
)
493 names
= [n
for n
in os
.listdir(a
) if n
.endswith('.py')]
495 print >> sys
.stderr
, "Directory not readable: %s" % a
498 fullname
= os
.path
.join(a
, n
)
499 if os
.path
.isfile(fullname
):
500 output
= cStringIO
.StringIO()
501 print 'Testing %s' % fullname
503 roundtrip(fullname
, output
)
505 print ' Failed to compile, exception is %s' % repr(e
)
506 elif os
.path
.isdir(fullname
):
510 if args
[0] == '--testdir':
517 if __name__
=='__main__':