customize38.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. # Copyright (c) 2019-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 3.8 version-specific semantic actions here.
  16. """
  17. ########################
  18. # Python 3.8+ changes
  19. #######################
  20. from decompyle3.semantics.consts import PRECEDENCE, TABLE_DIRECT
  21. from decompyle3.semantics.customize37 import FSTRING_CONVERSION_MAP
  22. from decompyle3.semantics.helper import escape_string, strip_quotes
  23. def customize_for_version38(self, version):
  24. # FIXME: pytest doesn't add proper keys in testing. Reinstate
  25. # after we have fixed pytest. for lhs in 'for forelsestmt
  26. # forelselaststmt ' 'forelselaststmtc tryfinally38'.split(): del
  27. # TABLE_DIRECT[lhs]
  28. TABLE_DIRECT.update(
  29. {
  30. "async_for_stmt38": (
  31. "%|async for %c in %c:\n%+%c%-",
  32. (2, "store"),
  33. (0, "expr"),
  34. (3, "for_block"),
  35. ),
  36. "async_forelse_stmt38": (
  37. "%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
  38. (2, "store"),
  39. (0, "expr"),
  40. (3, "for_block"),
  41. (6, "else_suite"),
  42. ),
  43. "async_with_stmt38": (
  44. "%|async with %c:\n%+%c%-",
  45. (0, "expr"),
  46. (7, ("c_stmts_opt", "c_stmts", "pass")),
  47. ),
  48. "async_with_as_stmt38": (
  49. "%|async with %c as %p:\n%+%|%c%-",
  50. (0, "expr"),
  51. (6, "store", PRECEDENCE["unpack"] - 1),
  52. (7, "suite_stmts"),
  53. ),
  54. "break_except": ("%|break\n",),
  55. "c_forelsestmt38": (
  56. "%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
  57. (2, "store"),
  58. (0, "expr"),
  59. (3, "for_block"),
  60. -1,
  61. ),
  62. "c_tryfinallystmt38": (
  63. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  64. (1, "c_suite_stmts_opt"),
  65. (-2, "c_suite_stmts_opt"),
  66. ),
  67. "c_tryfinallybstmt38": (
  68. "%|try:\n%+%c\n%|break\n%-%|finally:\n%+%c%-\n\n",
  69. (1, "c_suite_stmts_opt"),
  70. (-2, "c_suite_stmts_opt"),
  71. ),
  72. # Python 3.8 reverses the order of keys and items
  73. # from all prior versions of Python.
  74. "dict_comp_body": (
  75. "%c: %c",
  76. (0, "expr"),
  77. (1, "expr"),
  78. ),
  79. "except_handler38": ("%c", (2, "except_stmts")),
  80. "except_handler38a": ("%c", (-2, "stmts")),
  81. "except_handler38c": (
  82. "%c%+%c%-",
  83. (1, "except_cond1"),
  84. (2, "except_stmts"),
  85. ),
  86. "except_handler_as": (
  87. "%c%+\n%+%c%-",
  88. (1, "except_cond2"),
  89. (2, "tryfinallystmt"),
  90. ),
  91. "except_ret38a": ("return %c", (4, "expr")),
  92. # Note: there is a suite_stmts_opt which seems
  93. # to be bookkeeping which is not expressed in source code
  94. "except_ret38": ("%|return %c\n", (1, "expr")),
  95. "except_ret38b": ("%+\n%c%|return %c%-\n", (1, "_stmts"), (2, "expr")),
  96. "except_ret38c": ("%+\n%c%|return %c%-\n", (1, "_stmts"), (2, "expr")),
  97. "except_ret38d": (
  98. "%+\n%c%|return %c%-\n",
  99. (0, "suite_stmts_opt"),
  100. (1, "expr"),
  101. ),
  102. "except_return38": ("%c", (-1, "return")),
  103. "except_return_value38": ("%|return %c\n", (-1, "return")),
  104. "except_with_break": (
  105. "%|except:\n%+%c\n%c\n%-",
  106. (3, "c_stmts"),
  107. (4, "break_except"),
  108. ),
  109. "except_with_break2": ("%|except:\n%+%c\n%-", (3, "break_except")),
  110. "for38": (
  111. "%|for %c in %c:\n%+%c%-\n\n",
  112. (2, "store"),
  113. (0, "expr"),
  114. (3, "for_block"),
  115. ),
  116. "forelsestmt38": (
  117. "%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
  118. (2, "store"),
  119. (0, "expr"),
  120. (3, "for_block"),
  121. -2, # -1 when _come_froms is removed
  122. ),
  123. "forelselaststmt38": (
  124. "%|for %c in %c:\n%+%c%-%|else:\n%+%c%-",
  125. (2, "store"),
  126. (0, "expr"),
  127. (3, "for_block"),
  128. -2,
  129. ),
  130. "forelselaststmtc38": (
  131. "%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
  132. (2, "store"),
  133. (0, "expr"),
  134. (3, "for_block"),
  135. -2,
  136. ),
  137. "if_or_not_stmt": (
  138. "%|if %c:\n%+%c%-",
  139. (0, "testfalse"),
  140. (1, ("ifstmts_jump", "stmts")),
  141. ),
  142. "ifpoplaststmtc": ("%|if %c:\n%+%c%-", (0, "testexpr"), (2, "c_stmts")),
  143. "if_exp_compare38": (
  144. "%p if %c else %c",
  145. (2, "expr", PRECEDENCE["if_exp"] - 1),
  146. (0, ("expr", "bool_op", "or_in_ifexp")),
  147. -2,
  148. ),
  149. "list_if_not38": (" if not %c", (2, "expr", PRECEDENCE["unary_not"])),
  150. "named_expr": ( # AKA "walrus operator"
  151. "%c := %p",
  152. (2, "store"),
  153. (0, "expr", PRECEDENCE["named_expr"] - 1),
  154. ),
  155. "or_in_ifexp": (
  156. "%c or %c",
  157. (0, ("or_in_ifexp", "expr_pjit")),
  158. (-1, "expr"),
  159. ),
  160. "or_not": (
  161. "%c or not %c",
  162. (0, ("or_in_ifexp", "expr_pjit")),
  163. (-1, "expr"),
  164. ),
  165. "pop_return": ("%|return %c\n", (1, "return_expr")),
  166. "popb_return": ("%|return %c\n", (0, "return_expr")),
  167. "pop_ex_return": ("%|return %c\n", (0, "return_expr")),
  168. "pop_ex_return2": ("%|return %c\n", (1, "expr")),
  169. "pop3_except_return38": ("%|except:\n%+%c%-", (-1, "return")),
  170. "pop3_rot4_except_return38": (
  171. "%|except:\n%+%c%|return %c%-",
  172. (3, "except_stmts_opt"),
  173. (4, "return_expr"),
  174. ),
  175. "except_cond_pop3_rot4_except_return38": (
  176. "%c%+%c%|return %c%-",
  177. (0, "except_cond1"),
  178. (1, "except_stmts_opt"),
  179. (2, "return_expr"),
  180. ),
  181. "except_with_return38": (
  182. "%|except:\n%+%c\n%c%-",
  183. -2,
  184. (-1, "pop_ex_return2"),
  185. ),
  186. "except_return_value2": (
  187. "%c\n",
  188. (-1, "return"),
  189. ),
  190. "set_for": (
  191. " for %c in %c",
  192. (2, "store"),
  193. (0, "expr_or_arg"),
  194. ),
  195. "whilestmt38": (
  196. "%|while %c:\n%+%c%-\n\n",
  197. (1, ("bool_op", "testexpr", "testexprc")),
  198. (2, ("c_stmts", "pass")),
  199. ),
  200. "whileTruestmt38": (
  201. "%|while True:\n%+%c%-\n\n",
  202. (
  203. 1,
  204. ("c_stmts", "pass"),
  205. ),
  206. ),
  207. "try_elsestmtl38": (
  208. "%|try:\n%+%c%-%c%|else:\n%+%c%-",
  209. (1, "suite_stmts_opt"),
  210. (3, "except_handler38"),
  211. (5, "else_suitec"),
  212. ),
  213. "try_except38": (
  214. "%|try:\n%+%c\n%-%|except:\n%+%c%-\n\n",
  215. (2, ("suite_stmts_opt", "suite_stmts")),
  216. (3, ("except_handler38a", "except_handler38b", "except_handler38c")),
  217. ),
  218. "try_except38r": (
  219. "%|try:\n%+%c\n%-%|except:\n%+%c%-\n\n",
  220. (1, "return_except"),
  221. (2, "except_handler38b"),
  222. ),
  223. "try_except38r2": (
  224. "%|try:\n%+%c\n%-%|except:\n%+%c%c%-\n\n",
  225. (1, "suite_stmts_opt"),
  226. (8, "cond_except_stmts_opt"),
  227. (10, "return"),
  228. ),
  229. "try_except38r4": (
  230. "%|try:\n%+%c\n%-%c%+%c%-\n\n",
  231. (1, "returns_in_except"),
  232. (3, "except_cond1"),
  233. (4, "return"),
  234. ),
  235. "try_except38r5": (
  236. "%|try:\n%+%c\n%-%c%c%-\n\n",
  237. (1, "returns_in_except"),
  238. (3, ("except_cond1", "except_cond2")),
  239. (4, ("except_ret38b", "except_ret38d", "except_suite")),
  240. ),
  241. "try_except38r6": (
  242. "%|try:\n%+%c\n%-\n%|except:\n%c\n\n",
  243. (1, "returns_in_except2"),
  244. (6, "except_ret38d"),
  245. ),
  246. "try_except38r7": (
  247. "%|try:\n%+%c\n%-\n%|except:\n%+%|return %c%-\n\n",
  248. (1, "suite_stmts_opt"),
  249. (8, "return_expr"),
  250. ),
  251. "try_except_as": (
  252. "%|try:\n%+%c%-\n%|%-%c\n\n",
  253. (
  254. -4,
  255. ("suite_stmts", "_stmts"),
  256. ), # Go from the end because of POP_BLOCK variation
  257. (-3, "except_handler_as"),
  258. ),
  259. "try_except_ret38": (
  260. "%|try:\n%+%c%-\n%|except:\n%+%|%c%-\n\n",
  261. (1, "returns"),
  262. (2, "except_ret38a"),
  263. ),
  264. "try_except_ret38a": (
  265. "%|try:\n%+%c%-%c\n\n",
  266. (1, "returns"),
  267. (2, "except_handler38c"),
  268. ),
  269. "tryfinally38rstmt": (
  270. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  271. (0, "sf_pb_call_returns"),
  272. (-1, ("ss_end_finally", "suite_stmts", "_stmts")),
  273. ),
  274. "tryfinally38_return": (
  275. "%|try:\n%+%c%-%c%c\n\n",
  276. (1, "suite_stmts_opt"),
  277. (5, "except_cond2"),
  278. (6, "except_ret38c"),
  279. ),
  280. "tryfinally38a_return": (
  281. "%|try:\n%+%c%c%-%|finally:\n%+%c%-\n\n",
  282. (2, "suite_stmts_opt"),
  283. (3, "except_return38"),
  284. (8, "return"),
  285. ),
  286. "tryfinally38rstmt2": (
  287. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  288. (4, "returns"),
  289. -2,
  290. "ss_end_finally",
  291. ),
  292. "tryfinally38rstmt3": (
  293. "%|try:\n%+%|return %c%-\n%|finally:\n%+%c%-\n\n",
  294. (1, "expr"),
  295. (-1, "ss_end_finally"),
  296. ),
  297. "tryfinally38rstmt4": (
  298. "%|try:\n%+%c%-\n%|finally:\n%+%c%-\n\n",
  299. (1, "suite_stmts_opt"),
  300. (5, "suite_stmts_return"),
  301. ),
  302. "tryfinally38rstmt5": (
  303. "%|try:\n%+%c%-\n%|finally:\n%+%|return %c%-\n\n",
  304. (1, "try_except38r7"),
  305. (2, "expr"),
  306. ),
  307. "tryfinally38stmt": (
  308. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  309. (1, "suite_stmts_opt"),
  310. (6, "suite_stmts_opt"),
  311. ),
  312. "tryfinally38astmt": (
  313. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  314. (2, "suite_stmts_opt"),
  315. (8, "suite_stmts_opt"),
  316. ),
  317. "with_as_pass": (
  318. "%|with %c as %c:\n%+%c%-",
  319. (0, "expr"),
  320. (2, "store"),
  321. (3, "pass"),
  322. ),
  323. }
  324. )
  325. def except_return_value(node):
  326. if node[0] == "POP_BLOCK":
  327. self.default(node[1])
  328. else:
  329. self.template_engine(("%|return %c\n", (0, "expr")), node)
  330. self.prune()
  331. self.n_except_return_value = except_return_value
  332. # FIXME: now that we've split out cond_except_stmt,
  333. # we should be able to get this working as a pure transformation rule,
  334. # so no procedure is needed here.
  335. def try_except38r3(node):
  336. self.template_engine(("%|try:\n%+%c\n%-", (1, "suite_stmts_opt")), node)
  337. cond_except_stmts_opt = node[5]
  338. assert cond_except_stmts_opt == "cond_except_stmts_opt"
  339. for child in cond_except_stmts_opt:
  340. if child == "cond_except_stmt":
  341. if child[0] == "except_cond1":
  342. self.template_engine(
  343. ("%c\n", (0, "except_cond1"), (1, "expr")), child
  344. )
  345. self.template_engine(("%+%c%-\n", (1, "except_stmts")), child)
  346. pass
  347. pass
  348. self.template_engine(("%+%c%-\n", (7, "return")), node)
  349. self.prune()
  350. self.n_try_except38r3 = try_except38r3
  351. def n_list_afor(node):
  352. if len(node) == 2:
  353. # list_afor ::= get_iter list_afor
  354. self.comprehension_walk_newer(node, 0)
  355. else:
  356. list_iter_index = 2 if node[2] == "list_iter" else 3
  357. self.template_engine(
  358. (
  359. " async for %[1]{%c} in %c%[1]{%c}",
  360. (1, "store"),
  361. (0, "get_aiter"),
  362. (list_iter_index, "list_iter"),
  363. ),
  364. node,
  365. )
  366. self.prune()
  367. self.n_list_afor = n_list_afor
  368. def n_set_afor(node):
  369. if len(node) == 2:
  370. self.template_engine(
  371. (" async for %[1]{%c} in %c", (1, "store"), (0, "get_aiter")), node
  372. )
  373. else:
  374. self.template_engine(
  375. " async for %[1]{%c} in %c%c",
  376. (1, "store"),
  377. (0, "get_aiter"),
  378. (2, "set_iter"),
  379. )
  380. self.prune()
  381. self.n_set_afor = n_set_afor
  382. def n_formatted_value_debug(node):
  383. p = self.prec
  384. self.prec = 100
  385. formatted_value = node[1]
  386. value_equal = node[0].attr
  387. assert formatted_value.kind.startswith("formatted_value")
  388. old_in_format_string = self.in_format_string
  389. self.in_format_string = formatted_value.kind
  390. format_value_attr = node[-1]
  391. post_str = ""
  392. if node[-1] == "BUILD_STRING_3":
  393. post_load_str = node[-2]
  394. post_str = self.traverse(post_load_str, indent="")
  395. post_str = strip_quotes(post_str)
  396. if format_value_attr == "FORMAT_VALUE_ATTR":
  397. attr = format_value_attr.attr
  398. if attr & 4:
  399. fmt = strip_quotes(self.traverse(node[3], indent=""))
  400. attr_flags = attr & 3
  401. if attr_flags:
  402. conversion = "%s:%s" % (
  403. FSTRING_CONVERSION_MAP.get(attr_flags, ""),
  404. fmt,
  405. )
  406. else:
  407. conversion = ":%s" % fmt
  408. else:
  409. conversion = FSTRING_CONVERSION_MAP.get(attr, "")
  410. f_str = "f%s" % escape_string(
  411. "{%s%s}%s" % (value_equal, conversion, post_str)
  412. )
  413. else:
  414. f_conversion = self.traverse(formatted_value, indent="")
  415. # Remove leaving "f" and quotes
  416. conversion = strip_quotes(f_conversion[1:])
  417. f_str = "f%s" % escape_string(f"{value_equal}{conversion}" + post_str)
  418. self.write(f_str)
  419. self.in_format_string = old_in_format_string
  420. self.prec = p
  421. self.prune()
  422. self.n_formatted_value_debug = n_formatted_value_debug
  423. def n_suite_stmts_return(node):
  424. if len(node) > 1:
  425. assert len(node) == 2
  426. self.template_engine(
  427. ("%c\n%|return %c", (0, ("_stmts", "suite_stmts")), (1, "expr")), node
  428. )
  429. else:
  430. self.template_engine(("%|return %c", (0, "expr")), node)
  431. self.prune()
  432. self.n_suite_stmts_return = n_suite_stmts_return