/Demo/parser/unparse.py

http://unladen-swallow.googlecode.com/ · Python · 518 lines · 429 code · 70 blank · 19 comment · 81 complexity · 1931bab04f70736294ae846c3265878c MD5 · raw file

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