customize.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. # Copyright (c) 2018-2019, 2021-2022 2024 by Rocky Bernstein
  2. #
  3. # This program is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. """Isolate Python version-specific semantic actions here.
  16. """
  17. from uncompyle6.parsers.treenode import SyntaxTree
  18. from uncompyle6.scanners.tok import Token
  19. from uncompyle6.semantics.consts import (
  20. INDENT_PER_LEVEL,
  21. NO_PARENTHESIS_EVER,
  22. PRECEDENCE,
  23. TABLE_DIRECT,
  24. TABLE_R,
  25. )
  26. from uncompyle6.semantics.helper import flatten_list
  27. def customize_for_version(self, is_pypy, version):
  28. if is_pypy:
  29. ########################
  30. # PyPy changes
  31. #######################
  32. # fmt: off
  33. self.TABLE_DIRECT.update({
  34. "assert": ("%|assert %c\n", 0),
  35. # This can happen as a result of an if transformation
  36. "assert2": ("%|assert %c, %c\n", 0, 3),
  37. "assert_pypy": ( "%|assert %c\n" , (1, "assert_expr") ),
  38. # This is as a result of an if transformation
  39. 'assert0_pypy': ( "%|assert %c\n" , 0),
  40. 'assert_not_pypy': ( "%|assert not %c\n" , (1, "assert_exp") ),
  41. "assert2_not_pypy": (
  42. "%|assert not %c, %c\n",
  43. (1, "assert_exp"),
  44. (4, "expr"),
  45. ),
  46. "try_except_pypy": ( "%|try:\n%+%c%-%c\n\n", 1, 2 ),
  47. "tryfinallystmt_pypy": ( "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", 1, 3 ),
  48. "assign3_pypy": ( "%|%c, %c, %c = %c, %c, %c\n", 5, 4, 3, 0, 1, 2 ),
  49. "assign2_pypy": ( "%|%c, %c = %c, %c\n", 3, 2, 0, 1),
  50. })
  51. # fmt: on
  52. if version[:2] >= (3, 7):
  53. def n_call_kw_pypy37(node):
  54. self.template_engine(("%p(", (0, NO_PARENTHESIS_EVER)), node)
  55. assert node[-1] == "CALL_METHOD_KW"
  56. arg_count = node[-1].attr
  57. kw_names = node[-2]
  58. assert kw_names == "pypy_kw_keys"
  59. kwargs_names = kw_names[0].attr
  60. kwarg_count = len(kwargs_names)
  61. pos_argc = arg_count - kwarg_count
  62. flat_elems = flatten_list(node[1:-2])
  63. n = len(flat_elems)
  64. assert n == arg_count, "n: %s, arg_count: %s\n%s" % (
  65. n,
  66. arg_count,
  67. node,
  68. )
  69. sep = ""
  70. for i in range(pos_argc):
  71. elem = flat_elems[i]
  72. line_number = self.line_number
  73. value = self.traverse(elem)
  74. if line_number != self.line_number:
  75. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  76. pass
  77. self.write(f"{sep}{value}")
  78. sep = ", "
  79. assert n >= len(kwargs_names)
  80. j = pos_argc
  81. for i in range(kwarg_count):
  82. elem = flat_elems[j]
  83. j += 1
  84. assert elem == "expr"
  85. line_number = self.line_number
  86. value = self.traverse(elem)
  87. if line_number != self.line_number:
  88. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  89. pass
  90. self.write(f"{sep}{kwargs_names[i]}={value}")
  91. sep = ", "
  92. pass
  93. self.write(")")
  94. self.prune()
  95. self.n_call_kw_pypy37 = n_call_kw_pypy37
  96. else:
  97. ########################
  98. # Without PyPy
  99. #######################
  100. self.TABLE_DIRECT.update(
  101. {
  102. # "assert" and "assert_expr" are added via transform rules.
  103. "assert": ("%|assert %c\n", 0),
  104. "assert2": ("%|assert %c, %c\n", 0, 3),
  105. # Created only via transformation
  106. "assertnot": ("%|assert not %p\n", (0, PRECEDENCE["unary_not"])),
  107. "assert2not": (
  108. "%|assert not %p, %c\n",
  109. (0, PRECEDENCE["unary_not"]),
  110. 3,
  111. ),
  112. "assign2": ("%|%c, %c = %c, %c\n", 3, 4, 0, 1),
  113. "assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2),
  114. "try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3),
  115. }
  116. )
  117. if version >= (3, 0):
  118. if version >= (3, 2):
  119. self.TABLE_DIRECT.update(
  120. {"del_deref_stmt": ("%|del %c\n", 0), "DELETE_DEREF": ("%{pattr}", 0)}
  121. )
  122. from uncompyle6.semantics.customize3 import customize_for_version3
  123. customize_for_version3(self, version)
  124. else: # < 3.0
  125. self.TABLE_DIRECT.update(
  126. {"except_cond3": ("%|except %c, %c:\n", (1, "expr"), (-2, "store"))}
  127. )
  128. if version <= (2, 6):
  129. self.TABLE_DIRECT["testtrue_then"] = self.TABLE_DIRECT["testtrue"]
  130. if (2, 4) <= version <= (2, 6):
  131. self.TABLE_DIRECT.update({"comp_for": (" for %c in %c", 3, 1)})
  132. else:
  133. self.TABLE_DIRECT.update({"comp_for": (" for %c in %c%c", 2, 0, 3)})
  134. if version >= (2, 5):
  135. from uncompyle6.semantics.customize25 import customize_for_version25
  136. customize_for_version25(self, version)
  137. if version >= (2, 6):
  138. from uncompyle6.semantics.customize26_27 import (
  139. customize_for_version26_27,
  140. )
  141. customize_for_version26_27(self, version)
  142. pass
  143. else: # < 2.5
  144. global NAME_MODULE
  145. NAME_MODULE = SyntaxTree(
  146. "stmt",
  147. [
  148. SyntaxTree(
  149. "assign",
  150. [
  151. SyntaxTree(
  152. "expr",
  153. [
  154. Token(
  155. "LOAD_GLOBAL",
  156. pattr="__name__",
  157. offset=0,
  158. has_arg=True,
  159. )
  160. ],
  161. ),
  162. SyntaxTree(
  163. "store",
  164. [
  165. Token(
  166. "STORE_NAME",
  167. pattr="__module__",
  168. offset=3,
  169. has_arg=True,
  170. )
  171. ],
  172. ),
  173. ],
  174. )
  175. ],
  176. )
  177. self.TABLE_DIRECT.update(
  178. {
  179. "importmultiple": ("%|import %c%c\n", 2, 3),
  180. "import_cont": (", %c", 2),
  181. "tryfinallystmt": (
  182. "%|try:\n%+%c%-%|finally:\n%+%c%-",
  183. (1, "suite_stmts_opt"),
  184. (5, "suite_stmts_opt"),
  185. ),
  186. }
  187. )
  188. if version == (2, 4):
  189. def n_iftrue_stmt24(node):
  190. self.template_engine(("%c", 0), node)
  191. self.default(node)
  192. self.prune()
  193. self.n_iftrue_stmt24 = n_iftrue_stmt24
  194. elif version < (1, 4):
  195. from uncompyle6.semantics.customize14 import customize_for_version14
  196. customize_for_version14(self, version)
  197. def n_call(node):
  198. expr = node[0]
  199. assert expr == "expr"
  200. params = node[1]
  201. if params == "tuple":
  202. self.template_engine(("%p(", (0, NO_PARENTHESIS_EVER)), expr)
  203. sep = ""
  204. for param in params[:-1]:
  205. self.write(sep)
  206. self.preorder(param)
  207. sep = ", "
  208. self.write(")")
  209. else:
  210. self.template_engine(
  211. (
  212. "%p(%P)",
  213. (0, "expr", 100),
  214. (1, -1, ", ", NO_PARENTHESIS_EVER),
  215. ),
  216. node,
  217. )
  218. self.prune()
  219. self.n_call = n_call
  220. else: # 1.0 <= version <= 2.3:
  221. self.TABLE_DIRECT.update({"if1_stmt": ("%|if 1\n%+%c%-", 5)})
  222. if version <= (2, 1):
  223. self.TABLE_DIRECT.update(
  224. {
  225. "importmultiple": ("%c", 2),
  226. # FIXME: not quite right. We have indiividual imports
  227. # when there is in fact one: "import a, b, ..."
  228. "imports_cont": ("%C%,", (1, 100, "\n")),
  229. }
  230. )
  231. pass
  232. pass
  233. pass # < 2.5
  234. # < 3.0 continues
  235. self.TABLE_R.update(
  236. {
  237. "STORE_SLICE+0": ("%c[:]", 0),
  238. "STORE_SLICE+1": ("%c[%p:]", 0, (1, -1)),
  239. "STORE_SLICE+2": ("%c[:%p]", 0, (1, -1)),
  240. "STORE_SLICE+3": ("%c[%p:%p]", 0, (1, -1), (2, -1)),
  241. "DELETE_SLICE+0": ("%|del %c[:]\n", 0),
  242. "DELETE_SLICE+1": ("%|del %c[%c:]\n", 0, 1),
  243. "DELETE_SLICE+2": ("%|del %c[:%c]\n", 0, 1),
  244. "DELETE_SLICE+3": ("%|del %c[%c:%c]\n", 0, 1, 2),
  245. }
  246. )
  247. self.TABLE_DIRECT.update({"raise_stmt2": ("%|raise %c, %c\n", 0, 1)})
  248. # exec as a built-in statement is only in Python 2.x
  249. def n_exec_stmt(node):
  250. """
  251. exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT
  252. exec_stmt ::= expr exprlist EXEC_STMT
  253. """
  254. self.write(self.indent, "exec ")
  255. self.preorder(node[0])
  256. if not node[1][0].isNone():
  257. sep = " in "
  258. for subnode in node[1]:
  259. self.write(sep)
  260. sep = ", "
  261. self.preorder(subnode)
  262. self.println()
  263. self.prune() # stop recursing
  264. self.n_exec_smt = n_exec_stmt
  265. pass # < 3.0
  266. return