customize37.py 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  1. # Copyright (c) 2019-2023 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.7 version-specific semantic actions here.
  16. """
  17. import re
  18. from spark_parser.ast import GenericASTTraversalPruningException
  19. from xdis import co_flags_is_async, iscode
  20. from decompyle3.parsers.treenode import SyntaxTree
  21. from decompyle3.scanners.tok import Token
  22. from decompyle3.semantics.consts import (
  23. INDENT_PER_LEVEL,
  24. PRECEDENCE,
  25. TABLE_DIRECT,
  26. TABLE_R,
  27. )
  28. from decompyle3.semantics.helper import escape_string, flatten_list, strip_quotes
  29. def escape_format(s):
  30. return s.replace("\r", "\\r").replace("\n", "\\n").replace("'''", '"""')
  31. EMPTY_DICT = SyntaxTree(
  32. "dict", [Token("BUILD_MAP_0", attr=0, pattr="", offset=0, has_arg=True)]
  33. )
  34. # FIXME: Get this from a newer xdis!
  35. FSTRING_CONVERSION_MAP = {1: "!s", 2: "!r", 3: "!a", "X": ":X"}
  36. #######################
  37. def customize_for_version37(self, version):
  38. ########################
  39. # Python 3.7+ changes
  40. #######################
  41. # fmt: off
  42. PRECEDENCE["attribute37"] = 2
  43. PRECEDENCE["call_ex"] = 1
  44. PRECEDENCE["call_ex_kw"] = 1
  45. PRECEDENCE["call_ex_kw2"] = 1
  46. PRECEDENCE["call_ex_kw3"] = 1
  47. PRECEDENCE["call_ex_kw4"] = 1
  48. PRECEDENCE["call_kw"] = 0
  49. PRECEDENCE["call_kw36"] = 1
  50. # f"...". This has to be below "named_expr" to make f'{(x := 10)}'
  51. # preserve parenthesis
  52. PRECEDENCE["formatted_value1"] = 38
  53. PRECEDENCE["formatted_value2"] = 38 # See above
  54. PRECEDENCE["if_exp_37a"] = 28
  55. PRECEDENCE["if_exp_37b"] = 28
  56. PRECEDENCE["dict_unpack"] = 0 # **{...}
  57. # fmt: on
  58. TABLE_DIRECT.update(
  59. {
  60. "and_parts": (
  61. "%P and %p",
  62. (0, -1, "and ", PRECEDENCE["and"]),
  63. (1, "expr_pjif", PRECEDENCE["and"]),
  64. ),
  65. "and_or_expr": (
  66. "%c and %c or %c",
  67. (0, "and_parts"),
  68. (1, "expr"),
  69. (2, "jitop_come_from_expr"),
  70. ),
  71. "or_and": (
  72. "%c or (%c and %c)",
  73. (0, "expr_jitop"),
  74. (1, "expr"),
  75. (4, "expr"),
  76. ),
  77. "or_and1": (
  78. "%p or %p",
  79. (0, "or_parts", PRECEDENCE["or"]),
  80. (1, "and_parts", PRECEDENCE["or"]),
  81. ),
  82. "and_or": (
  83. "%c and (%c or %c)",
  84. (0, "expr_jifop"),
  85. (1, "expr"),
  86. (4, "expr"),
  87. ),
  88. "and_not": ("%c and not %c", (0, "expr_pjif"), (1, "expr_pjit")),
  89. "and_cond": (
  90. "%c and %c",
  91. (0, ("and_parts", "testfalse")),
  92. (1, ("expr_pjif", "expr")),
  93. ),
  94. "ann_assign": (
  95. "%|%[2]{attr}: %c\n",
  96. 0,
  97. ),
  98. "ann_assign_init": (
  99. "%|%[2]{attr}: %c = %c\n",
  100. 0,
  101. 1,
  102. ),
  103. "async_for_stmt": (
  104. "%|async for %c in %c:\n%+%c%-\n\n",
  105. (8, "store"),
  106. (1, "expr"),
  107. (-9, "for_block"),
  108. ),
  109. "async_for_stmt2": (
  110. "%|async for %c in %c:\n%+%c%-\n\n",
  111. (10, "store"),
  112. (1, "expr"),
  113. (-3, "for_block"),
  114. ),
  115. "async_for_stmt36": (
  116. "%|async for %c in %c:\n%+%c%-\n\n",
  117. (9, "store"),
  118. (1, "expr"),
  119. (18, "for_block"),
  120. ),
  121. "async_for_stmt37": (
  122. "%|async for %c in %c:\n%+%c%-\n\n",
  123. (8, "store"),
  124. (1, "expr"),
  125. (17, "for_block"),
  126. ),
  127. "async_with_stmt": ("%|async with %c:\n%+%c%-", (0, "expr"), 3),
  128. "async_with_as_stmt": (
  129. "%|async with %c as %p:\n%+%c%-",
  130. (0, "expr"),
  131. (2, "store", PRECEDENCE["unpack"] - 1),
  132. 3,
  133. ),
  134. "async_forelse_stmt": (
  135. "%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
  136. (8, "store"),
  137. (1, "expr"),
  138. (-10, "for_block"),
  139. (-2, "else_suite"),
  140. ),
  141. "attribute37": ("%c.%[1]{pattr}", (0, "expr")),
  142. "attributes37": (
  143. "%[0]{pattr} import %c",
  144. (0, "IMPORT_NAME_ATTR"),
  145. (1, "IMPORT_FROM"),
  146. ),
  147. # nested await expressions like:
  148. # return await (await bar())
  149. # need parenthesis.
  150. # Note there are async dictionary expressions are like await expr's
  151. # the below is just the default fersion
  152. "await_expr": ("await %p", (0, PRECEDENCE["await_expr"] - 1)),
  153. "await_stmt": ("%|%c\n", 0),
  154. "c_async_with_stmt": ("%|async with %c:\n%+%c%-", (0, "expr"), 3),
  155. "call_ex": ("%c(%p)", (0, "expr"), (1, 100)),
  156. "compare_chained_middlea_37": (
  157. "%p %p",
  158. (0, PRECEDENCE["compare"] - 1),
  159. (1, PRECEDENCE["compare"] - 1),
  160. ),
  161. "c_compare_chained_middlea_37": (
  162. "%p %p",
  163. (0, PRECEDENCE["compare"] - 1),
  164. (1, PRECEDENCE["compare"] - 1),
  165. ),
  166. "compare_chained_middle_false_37": (
  167. "%p%p",
  168. (0, "chained_parts", PRECEDENCE["compare"] - 1),
  169. (1, PRECEDENCE["compare"] - 1),
  170. ),
  171. "compare_chained_right_false_37": (
  172. (0, "chained_part", PRECEDENCE["compare"] - 1),
  173. (1, PRECEDENCE["compare"] - 1),
  174. ),
  175. "compare_chained_middleb_false_37": (
  176. "%p %p",
  177. (0, PRECEDENCE["compare"] - 1),
  178. (1, PRECEDENCE["compare"] - 1),
  179. ),
  180. "chained_part": (
  181. ' %[3]{pattr.replace("-", " ")} %p',
  182. (0, "expr", PRECEDENCE["compare"] - 1),
  183. ),
  184. "compare_chained_and": (
  185. "%c%c and %c",
  186. (0, "expr"),
  187. (1, "chained_parts"),
  188. -2, # Is often a transformed negated_testtrue
  189. ),
  190. "compare_chained_middlec_37": (
  191. "%p %p",
  192. (0, PRECEDENCE["compare"] - 1),
  193. (1, PRECEDENCE["compare"] - 1),
  194. ),
  195. "compare_chained_righta_37": (
  196. '%[1]{pattr.replace("-", " ")} %p',
  197. (0, PRECEDENCE["compare"] - 1),
  198. ),
  199. "c_compare_chained_righta_37": (
  200. '%[1]{pattr.replace("-", " ")} %p',
  201. (0, PRECEDENCE["compare"] - 1),
  202. ),
  203. "c_try_except36": ("%|try:\n%+%c%-%c\n\n", 1, 2),
  204. "compare_chained_rightb_false_37": (
  205. '%[1]{pattr.replace("-", " ")} %p',
  206. (0, PRECEDENCE["compare"] - 1),
  207. ),
  208. "c_compare_chained_rightb_false_37": (
  209. ' %[1]{pattr.replace("-", " ")} %p',
  210. (0, PRECEDENCE["compare"] - 1),
  211. ),
  212. "compare_chained_righta_false_37": (
  213. '%[1]{pattr.replace("-", " ")} %p',
  214. (0, PRECEDENCE["compare"] - 1),
  215. ),
  216. "c_compare_chained_righta_false_37": (
  217. ' %[1]{pattr.replace("-", " ")} %p',
  218. (0, PRECEDENCE["compare"] - 1),
  219. ),
  220. "compare_chained_rightc_37": (
  221. "%p %p",
  222. (0, PRECEDENCE["compare"] - 1),
  223. (1, PRECEDENCE["compare"] - 1),
  224. ),
  225. "c_try_except": ("%|try:\n%+%c%-%c\n\n", 1, (3, "c_except_handler")),
  226. "if_exp_compare": (
  227. "%p if %c else %c",
  228. (1, "expr", PRECEDENCE["if_exp"] - 1),
  229. (0, ("expr", "bool_op")),
  230. -2, # Must be from end since beginnings might not match
  231. ),
  232. "dict_unpack": ("{**%C}", (0, -1, ", **")),
  233. "except_return": ("%|except:\n%+%c%-", 3),
  234. "if_exp_37a": (
  235. "%p if %p else %p",
  236. (1, "expr", PRECEDENCE["if_exp"] - 1),
  237. (0, PRECEDENCE["if_exp"] - 1),
  238. (4, "expr", PRECEDENCE["if_exp"] - 1),
  239. ),
  240. "if_exp_37b": (
  241. "%p if %p else %p",
  242. (1, "expr_pjif", PRECEDENCE["if_exp"] - 1),
  243. (0, "expr_pjif", PRECEDENCE["if_exp"] - 1),
  244. (3, "expr", PRECEDENCE["if_exp"] - 1),
  245. ),
  246. "if_not_stmtc": (
  247. "%|if not %c:\n%+%c%-",
  248. (0, "testexprc"),
  249. (1, "ifstmts_jumpc"),
  250. ),
  251. "ifstmt_bool": (
  252. "%|if %c:\n%+%c%-",
  253. (0, ("or_and_not", "or_and1")),
  254. (1, "stmts"),
  255. ),
  256. "ifstmtc": (
  257. "%|if %c:\n%+%c%-",
  258. (0, ("testexpr", "testexprc")),
  259. (1, "ifstmts_jumpc"),
  260. ),
  261. "if_and_elsestmtc": (
  262. "%|if %c and %c:\n%+%c%-%|else:\n%+%c%-",
  263. (0, "expr_pjif"),
  264. (1, "expr_pjif"),
  265. (2, "c_stmts"),
  266. (-2, "else_suitec"),
  267. ),
  268. "if_and_stmt": (
  269. "%|if %c and %c:\n%+%c%-",
  270. (0, "expr_pjif"),
  271. (1, "expr"),
  272. (3, "stmts"),
  273. ),
  274. "if_or_stmt": (
  275. "%|if %c or %c:\n%+%c%-",
  276. (0, "expr"),
  277. (2, "expr"),
  278. (5, "stmts"),
  279. ),
  280. "if_or_elsestmt": (
  281. "%|if %c or %c:\n%+%c%-%|else:\n%+%c%-",
  282. (0, "expr"),
  283. (3, "expr"),
  284. (6, "stmts"),
  285. (-2, "else_suite"),
  286. ),
  287. "if_or_not_elsestmt": (
  288. "%|if %c or not %c:\n%+%c%-%|else:\n%+%c%-",
  289. (0, "expr"),
  290. (3, "expr"),
  291. (6, "stmts"),
  292. (-2, "else_suite"),
  293. ),
  294. "import_from37": ("%|from %[2]{pattr} import %c\n", (3, "importlist37")),
  295. "import_from_as37": (
  296. "%|from %c as %c\n",
  297. (2, "import_from_attr37"),
  298. (3, "store"),
  299. ),
  300. "import_one": (
  301. "%c",
  302. (0, "importlists"),
  303. ),
  304. "importattr37": ("%c", (0, "IMPORT_NAME_ATTR")),
  305. "import_from_attr37": (
  306. "%c import %c",
  307. (0, "IMPORT_NAME_ATTR"),
  308. (1, "IMPORT_FROM"),
  309. ),
  310. "list_afor": (
  311. " async for %[1]{%c} in %c%[1]{%c}",
  312. (1, "store"),
  313. (0, "get_aiter"),
  314. (3, "list_iter"),
  315. ),
  316. "list_if37": (" if %p%c", (0, 27), 1),
  317. "list_if37_not": (" if not %p%c", (0, 27), 1),
  318. # This is eliminated in the transform phase, but
  319. # we have it here to be logically complete and more robust
  320. # if something goes wrong.
  321. "negated_testtrue": (
  322. "not %c",
  323. (0, "testtrue"),
  324. ),
  325. "not_and_not": (
  326. "%c and not %c",
  327. (0, "not"),
  328. (1, "expr_pjif"),
  329. ),
  330. "nor_cond": (
  331. "%c or %c",
  332. (0, ("or_parts", "and")),
  333. (1, "expr_pjif"),
  334. ),
  335. "or_and_not": (
  336. "%c or %c",
  337. (0, "expr_pjit"),
  338. (1, "and_not"),
  339. ),
  340. "or_cond": (
  341. "%c or %c",
  342. (0, ("or_parts", "and", "not_and_not")),
  343. (1, "expr_pjif"),
  344. ),
  345. "or_cond1": (
  346. "%c or %c",
  347. (0, ("or_parts", "and")),
  348. (-2, "expr_pjif"),
  349. ),
  350. "and_or_cond": (
  351. "%c and %c or %c",
  352. (0, ("and_parts", "or_parts")),
  353. (1, "expr"),
  354. (4, "expr_pjif"),
  355. ),
  356. "not": (
  357. "not %p",
  358. (0, "expr_pjit", PRECEDENCE["not"]),
  359. ),
  360. "not_or": (
  361. "not %p or %c",
  362. (0, "and_parts", PRECEDENCE["and"] - 1),
  363. (1, "expr_pjif"),
  364. ),
  365. "nand": (
  366. "not (%c and %c)",
  367. (0, "and_parts"),
  368. (1, ("expr", "expr_pjit")),
  369. ),
  370. "c_nand": (
  371. "not (%c and %c)",
  372. (0, "and_parts"),
  373. (1, "expr_pjitt"),
  374. ),
  375. "or_parts": (
  376. "%P or %p",
  377. (0, -1, " or ", PRECEDENCE["or"]),
  378. (1, ("expr_pjif", "expr_pjit"), PRECEDENCE["or"]),
  379. ),
  380. "store_async_iter_end": ("%c", (0, "store")),
  381. "testfalsec": (
  382. "not %c",
  383. (
  384. 0,
  385. (
  386. "expr",
  387. "c_compare_chained37_false",
  388. "c_compare_chained_middleb_false_37",
  389. "c_nand",
  390. ),
  391. ),
  392. ),
  393. "try_except36": ("%|try:\n%+%c%-%c\n\n", 1, -2),
  394. "tryfinally36": ("%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", (1, "returns"), 3),
  395. "tryfinally_return_stmt1": (
  396. "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
  397. (1, "suite_stmts_opt"),
  398. (-1, "returns"),
  399. ),
  400. "tryfinally_return_stmt2": (
  401. "%|try:\n%+%c%-%|finally:\n%+%|return %c%-\n\n",
  402. (1, "suite_stmts_opt"),
  403. 3,
  404. ),
  405. "unpack_list": ("*%c", (0, "list")),
  406. "yield_from": ("yield from %c", (0, "expr")),
  407. }
  408. )
  409. TABLE_R.update(
  410. {
  411. "CALL_FUNCTION_EX": ("%c(*%P)", 0, (1, 2, ", ", 100)),
  412. # Not quite right
  413. "CALL_FUNCTION_EX_KW": ("%c(**%C)", 0, (2, 3, ",")),
  414. }
  415. )
  416. def call36_tuple(node):
  417. """
  418. A tuple used in a call, these are like normal tuples but they
  419. don't have the enclosing parenthesis.
  420. """
  421. assert node == "tuple"
  422. # Note: don't iterate over last element which is a
  423. # BUILD_TUPLE...
  424. flat_elems = flatten_list(node[:-1])
  425. self.indent_more(INDENT_PER_LEVEL)
  426. sep = ""
  427. for elem in flat_elems:
  428. if elem in ("ROT_THREE", "EXTENDED_ARG"):
  429. continue
  430. assert elem == "expr"
  431. line_number = self.line_number
  432. value = self.traverse(elem)
  433. if line_number != self.line_number:
  434. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  435. self.write(sep, value)
  436. sep = ", "
  437. self.indent_less(INDENT_PER_LEVEL)
  438. return len(flat_elems)
  439. self.call36_tuple = call36_tuple
  440. def call36_dict(node):
  441. """
  442. A dict used in a call_ex_kw2, which are a dictionary items expressed
  443. in a call. This should format to:
  444. a=1, b=2
  445. In other words, no braces, no quotes around keys and ":" becomes
  446. "=".
  447. We will source-code use line breaks to guide us when to break.
  448. """
  449. p = self.prec
  450. self.prec = 100
  451. self.indent_more(INDENT_PER_LEVEL)
  452. sep = INDENT_PER_LEVEL[:-1]
  453. line_number = self.line_number
  454. if node[0].kind.startswith("kvlist"):
  455. # Python 3.5+ style key/value list in dict
  456. kv_node = node[0]
  457. ll = list(kv_node)
  458. i = 0
  459. length = len(ll)
  460. # FIXME: Parser-speed improved grammars will have BUILD_MAP
  461. # at the end. So in the future when everything is
  462. # complete, we can do an "assert" instead of "if".
  463. if kv_node[-1].kind.startswith("BUILD_MAP"):
  464. length -= 1
  465. # Respect line breaks from source
  466. while i < length:
  467. self.write(sep)
  468. name = self.traverse(ll[i], indent="")
  469. # Strip off beginning and trailing quotes in name
  470. name = name[1:-1]
  471. if i > 0:
  472. line_number = self.indent_if_source_nl(
  473. line_number, self.indent + INDENT_PER_LEVEL[:-1]
  474. )
  475. line_number = self.line_number
  476. self.write(name, "=")
  477. value = self.traverse(
  478. ll[i + 1], indent=self.indent + (len(name) + 2) * " "
  479. )
  480. self.write(value)
  481. sep = ", "
  482. if line_number != self.line_number:
  483. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  484. line_number = self.line_number
  485. i += 2
  486. pass
  487. elif node[-1].kind.startswith("BUILD_CONST_KEY_MAP"):
  488. keys_node = node[-2]
  489. keys = keys_node.attr
  490. # from trepan.api import debug; debug()
  491. assert keys_node == "LOAD_CONST" and isinstance(keys, tuple)
  492. for i in range(node[-1].attr):
  493. self.write(sep)
  494. self.write(keys[i], "=")
  495. value = self.traverse(node[i], indent="")
  496. self.write(value)
  497. sep = ", "
  498. if line_number != self.line_number:
  499. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  500. line_number = self.line_number
  501. pass
  502. pass
  503. else:
  504. self.write("**")
  505. try:
  506. if node == EMPTY_DICT:
  507. self.write("{}")
  508. else:
  509. self.default(node)
  510. except GenericASTTraversalPruningException:
  511. pass
  512. self.prec = p
  513. self.indent_less(INDENT_PER_LEVEL)
  514. return
  515. self.call36_dict = call36_dict
  516. def gen_function_parens_adjust(mapping_key, node):
  517. """If we can avoid the outer parenthesis
  518. of a generator function, set the node key to
  519. 'call_generator' and the caller will do the default
  520. action on that. Otherwise we do nothing.
  521. """
  522. if mapping_key.kind != "CALL_FUNCTION_1":
  523. return
  524. args_node = node[-2]
  525. if args_node == "pos_arg":
  526. assert args_node[0] == "expr"
  527. n = args_node[0][0]
  528. if n == "generator_exp":
  529. node.kind = "call_generator"
  530. pass
  531. return
  532. # FIXME: Can we to compress this into a single template?
  533. def n_and_parts(node):
  534. if len(node) == 1:
  535. self.template_engine(("%c", (0, "expr_pjif")), node)
  536. self.prune()
  537. else:
  538. self.default(node)
  539. pass
  540. return
  541. self.n_and_parts = n_and_parts
  542. def n_await_expr(node):
  543. dict_comp_async = node[0][0]
  544. if dict_comp_async == "dict_comp_async":
  545. compile_mode = self.compile_mode
  546. self.compile_mode = "dictcomp"
  547. try:
  548. self.n_set_comp(dict_comp_async)
  549. except GenericASTTraversalPruningException:
  550. pass
  551. self.compile_mode = compile_mode
  552. else:
  553. self.default(node)
  554. self.prune()
  555. return
  556. self.n_await_expr = n_await_expr
  557. # FIXME: we should be able to compress this into a single template
  558. def n_or_parts(node):
  559. if len(node) == 1:
  560. self.template_engine(("%c", (0, "expr_pjit", "expr_pjif")), node)
  561. self.prune()
  562. else:
  563. self.default(node)
  564. pass
  565. return
  566. self.n_or_parts = n_or_parts
  567. self.n_and_parts = n_and_parts
  568. def n_assert_invert(node):
  569. testtrue = node[0]
  570. assert testtrue == "testtrue"
  571. testtrue.kind = "assert"
  572. self.default(testtrue)
  573. self.n_assert_invert = n_assert_invert
  574. def n_async_call(node):
  575. self.f.write("async ")
  576. node.kind = "call"
  577. p = self.prec
  578. self.prec = 80
  579. self.template_engine(("%c(%P)", 0, (1, -4, ", ", 100)), node)
  580. self.prec = p
  581. node.kind = "async_call"
  582. self.prune()
  583. self.n_async_call = n_async_call
  584. def n_attribute37(node):
  585. expr = node[0]
  586. assert expr == "expr"
  587. if expr[0] == "LOAD_CONST":
  588. # FIXME: I didn't record which constants parenthesis is
  589. # necessary. However, I suspect that we could further
  590. # refine this by looking at operator precedence and
  591. # eval'ing the constant value (pattr) and comparing with
  592. # the type of the constant.
  593. node.kind = "attribute_w_parens"
  594. self.default(node)
  595. self.n_attribute37 = n_attribute37
  596. def n_build_list_unpack(node):
  597. """
  598. prettyprint a list or tuple
  599. """
  600. p = self.prec
  601. self.prec = 100
  602. lastnode = node.pop()
  603. lastnodetype = lastnode.kind
  604. # If this build list is inside a CALL_FUNCTION_VAR,
  605. # then the first * has already been printed.
  606. # Until I have a better way to check for CALL_FUNCTION_VAR,
  607. # will assume that if the text ends in *.
  608. last_was_star = self.f.getvalue().endswith("*")
  609. if lastnodetype.startswith("BUILD_LIST"):
  610. self.write("[")
  611. endchar = "]"
  612. else:
  613. endchar = ""
  614. flat_elems = flatten_list(node)
  615. self.indent_more(INDENT_PER_LEVEL)
  616. sep = ""
  617. for elem in flat_elems:
  618. if elem in ("ROT_THREE", "EXTENDED_ARG"):
  619. continue
  620. assert elem == "expr"
  621. line_number = self.line_number
  622. use_star = True
  623. value = self.traverse(elem)
  624. if value.startswith("("):
  625. assert value.endswith(")")
  626. use_star = False
  627. value = value[1:-1].rstrip(
  628. " "
  629. ) # Remove starting '(' and trailing ')' and additional spaces
  630. if value == "":
  631. pass
  632. else:
  633. if value.endswith(","): # if args has only one item
  634. value = value[:-1]
  635. if line_number != self.line_number:
  636. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  637. else:
  638. if sep != "":
  639. sep += " "
  640. if not last_was_star and use_star:
  641. sep += "*"
  642. pass
  643. else:
  644. last_was_star = False
  645. self.write(sep, value)
  646. sep = ","
  647. self.write(endchar)
  648. self.indent_less(INDENT_PER_LEVEL)
  649. self.prec = p
  650. self.prune()
  651. return
  652. self.n_build_list_unpack = n_build_list_unpack
  653. def n_c_with(node):
  654. if len(node) == 1 and node[0] == "with":
  655. node = node[0]
  656. else:
  657. node.kind = "with"
  658. self.default(node)
  659. self.n_c_with = n_c_with
  660. def n_c_except_suite(node):
  661. node_len = len(node)
  662. if node_len == 1 and node[0] in ("except_suite", "c_returns"):
  663. node = node[0]
  664. self.default(node)
  665. elif node[1] in ("c_suite_stmts", "c_except_suite"):
  666. node = node[1][0]
  667. template = ("%+%c%-", 0)
  668. self.template_engine(template, node)
  669. self.prune()
  670. self.n_c_except_suite = n_c_except_suite
  671. self.n_c_with = n_c_with
  672. def n_call(node):
  673. p = self.prec
  674. self.prec = 100
  675. mapping = self._get_mapping(node)
  676. table = mapping[0]
  677. key = node
  678. for i in mapping[1:]:
  679. key = key[i]
  680. pass
  681. opname = key.kind
  682. if opname.startswith("CALL_FUNCTION_VAR_KW"):
  683. # Python 3.5 changes the stack position of
  684. # *args: kwargs come after *args whereas
  685. # in earlier Pythons, *args is at the end
  686. # which simplifies things from our
  687. # perspective. Python 3.6+ replaces
  688. # CALL_FUNCTION_VAR_KW with
  689. # CALL_FUNCTION_EX We will just swap the
  690. # order to make it look like earlier
  691. # Python 3.
  692. entry = table[key.kind]
  693. kwarg_pos = entry[2][1]
  694. args_pos = kwarg_pos - 1
  695. # Put last node[args_pos] after subsequent kwargs
  696. while node[kwarg_pos] == "kwarg" and kwarg_pos < len(node):
  697. # swap node[args_pos] with node[kwargs_pos]
  698. node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
  699. args_pos = kwarg_pos
  700. kwarg_pos += 1
  701. elif opname.startswith("CALL_FUNCTION_VAR"):
  702. # CALL_FUNCTION_VAR's top element of the stack contains
  703. # the variable argument list, then comes
  704. # annotation args, then keyword args.
  705. # In the most least-top-most stack entry, but position 1
  706. # in node order, the positional args.
  707. argc = node[-1].attr
  708. nargs = argc & 0xFF
  709. kwargs = (argc >> 8) & 0xFF
  710. # FIXME: handle annotation args
  711. if nargs > 0:
  712. template = ("%c(%P, ", 0, (1, nargs + 1, ", ", 100))
  713. else:
  714. template = ("%c(", 0)
  715. self.template_engine(template, node)
  716. args_node = node[-2]
  717. if args_node in ("pos_arg", "expr"):
  718. args_node = args_node[0]
  719. if args_node == "build_list_unpack":
  720. template = ("*%P)", (0, len(args_node) - 1, ", *", 100))
  721. self.template_engine(template, args_node)
  722. else:
  723. if len(node) - nargs > 3:
  724. template = (
  725. "*%c, %P)",
  726. nargs + 1,
  727. (nargs + kwargs + 1, -1, ", ", 100),
  728. )
  729. else:
  730. template = ("*%c)", nargs + 1)
  731. self.template_engine(template, node)
  732. self.prec = p
  733. self.prune()
  734. elif (
  735. opname.startswith("CALL_FUNCTION_1")
  736. and opname == "CALL_FUNCTION_1"
  737. or not re.match(r"\d", opname[-1])
  738. ):
  739. template = "(%c)(%p)" if node[0][0] == "lambda_body" else "%c(%p)"
  740. self.template_engine(
  741. (template, (0, "expr"), (1, PRECEDENCE["yield"] - 1)), node
  742. )
  743. self.prec = p
  744. self.prune()
  745. else:
  746. gen_function_parens_adjust(key, node)
  747. self.prec = p
  748. self.default(node)
  749. self.n_call = n_call
  750. def n_classdef36(node):
  751. # class definition ('class X(A,B,C):')
  752. cclass = self.currentclass
  753. # Pick out various needed bits of information
  754. # * class_name - the name of the class
  755. # * subclass_info - the parameters to the class e.g.
  756. # class Foo(bar, baz)
  757. # ----------
  758. # * subclass_code - the code for the subclass body
  759. subclass_info = None
  760. if node == "classdefdeco2":
  761. if isinstance(node[1][1].attr, str):
  762. class_name = node[1][1].attr
  763. if self.is_pypy and class_name.find("<locals>") > 0:
  764. class_name = class_name.split(".")[-1]
  765. else:
  766. class_name = node[1][2].attr
  767. build_class = node
  768. else:
  769. build_class = node[0]
  770. if build_class == "build_class_kw":
  771. mkfunc = build_class[1]
  772. assert mkfunc == "mkfunc"
  773. subclass_info = build_class
  774. if hasattr(mkfunc[0], "attr") and iscode(mkfunc[0].attr):
  775. subclass_code = mkfunc[0].attr
  776. else:
  777. assert mkfunc[0] == "load_closure"
  778. subclass_code = mkfunc[1].attr
  779. assert iscode(subclass_code)
  780. if build_class[1][0] == "load_closure":
  781. code_node = build_class[1][1]
  782. else:
  783. code_node = build_class[1][0]
  784. class_name = code_node.attr.co_name
  785. assert "mkfunc" == build_class[1]
  786. mkfunc = build_class[1]
  787. if mkfunc[0] in ("kwargs", "no_kwargs"):
  788. for n in mkfunc:
  789. if hasattr(n, "attr") and iscode(n.attr):
  790. subclass_code = n.attr
  791. break
  792. pass
  793. if node == "classdefdeco2":
  794. subclass_info = node
  795. else:
  796. subclass_info = node[0]
  797. elif build_class[1][0] == "load_closure":
  798. # Python 3 with closures not functions
  799. load_closure = build_class[1]
  800. subclass_code = None
  801. for i in range(-4, -1):
  802. if load_closure[i] == "LOAD_CODE":
  803. subclass_code = load_closure[i].attr
  804. break
  805. if subclass_code is None:
  806. raise RuntimeError(
  807. "Internal Error n_classdef: cannot find " "class body"
  808. )
  809. if hasattr(build_class[3], "__len__"):
  810. if not subclass_info:
  811. subclass_info = build_class[3]
  812. elif hasattr(build_class[2], "__len__"):
  813. subclass_info = build_class[2]
  814. else:
  815. raise RuntimeError(
  816. "Internal Error n_classdef: cannot " "superclass name"
  817. )
  818. elif node == "classdefdeco2":
  819. subclass_info = node
  820. subclass_code = build_class[1][0].attr
  821. elif not subclass_info:
  822. if mkfunc[0] in ("no_kwargs", "kwargs"):
  823. subclass_code = mkfunc[1].attr
  824. else:
  825. subclass_code = mkfunc[0].attr
  826. if node == "classdefdeco2":
  827. subclass_info = node
  828. else:
  829. subclass_info = node[0]
  830. if node == "classdefdeco2":
  831. self.write("\n")
  832. else:
  833. self.write("\n\n")
  834. self.currentclass = str(class_name)
  835. self.write(self.indent, "class ", self.currentclass)
  836. self.print_super_classes3(subclass_info)
  837. self.println(":")
  838. # class body
  839. self.indent_more()
  840. self.build_class(subclass_code)
  841. self.indent_less()
  842. self.currentclass = cclass
  843. if len(self.param_stack) > 1:
  844. self.write("\n\n")
  845. else:
  846. self.write("\n\n\n")
  847. self.prune()
  848. self.n_classdef36 = n_classdef36
  849. def n_compare_chained(node):
  850. if node[0] in (
  851. "c_compare_chained37",
  852. "c_compare_chained37_false",
  853. "compare_chained37",
  854. "compare_chained37_false",
  855. ):
  856. self.default(node[0])
  857. else:
  858. self.default(node)
  859. self.n_compare_chained = self.n_c_compare_chained = n_compare_chained
  860. def n_importlist37(node):
  861. if len(node) == 1:
  862. self.default(node)
  863. return
  864. n = len(node) - 1
  865. i = -1
  866. for i in range(n, -1, -1):
  867. if node[i] != "ROT_TWO":
  868. break
  869. self.template_engine(("%C", (0, i + 1, ", ")), node)
  870. self.prune()
  871. return
  872. self.n_importlist37 = n_importlist37
  873. def n_call_kw36(node):
  874. self.template_engine(("%p(", (0, 100)), node)
  875. keys = node[-2].attr
  876. num_kwargs = len(keys)
  877. num_posargs = len(node) - (num_kwargs + 2)
  878. n = len(node)
  879. assert n >= len(keys) + 1, "not enough parameters keyword-tuple values"
  880. sep = ""
  881. line_number = self.line_number
  882. for i in range(1, num_posargs):
  883. self.write(sep)
  884. self.preorder(node[i])
  885. if line_number != self.line_number:
  886. sep = ",\n" + self.indent + " "
  887. else:
  888. sep = ", "
  889. line_number = self.line_number
  890. i = num_posargs
  891. j = 0
  892. # FIXME: adjust output for line breaks?
  893. while i < n - 2:
  894. self.write(sep)
  895. self.write(keys[j] + "=")
  896. self.preorder(node[i])
  897. if line_number != self.line_number:
  898. sep = ",\n" + self.indent + " "
  899. else:
  900. sep = ", "
  901. i += 1
  902. j += 1
  903. self.write(")")
  904. self.prune()
  905. return
  906. self.n_call_kw36 = n_call_kw36
  907. def is_async_fn(node):
  908. code_node = node[0][0]
  909. for n in node[0]:
  910. if hasattr(n, "attr") and iscode(n.attr):
  911. code_node = n
  912. break
  913. pass
  914. pass
  915. is_code = hasattr(code_node, "attr") and iscode(code_node.attr)
  916. return is_code and co_flags_is_async(code_node.attr.co_flags)
  917. def n_function_def(node):
  918. if is_async_fn(node):
  919. self.template_engine(("\n\n%|async def %c\n", -2), node)
  920. else:
  921. self.default(node)
  922. self.prune()
  923. self.n_function_def = n_function_def
  924. def n_import_from(node):
  925. relative_path_index = 0
  926. if node[relative_path_index].attr > 0:
  927. node[2].pattr = ("." * node[relative_path_index].attr) + node[2].pattr
  928. if isinstance(node[1].attr, tuple):
  929. imports = node[1].attr
  930. for pattr in imports:
  931. node[1].pattr = pattr
  932. self.default(node)
  933. return
  934. self.default(node)
  935. self.n_import_from = n_import_from
  936. self.n_import_from_star = n_import_from
  937. def n_mkfuncdeco0(node):
  938. if is_async_fn(node):
  939. self.template_engine(("%|async def %c\n", 0), node)
  940. else:
  941. self.default(node)
  942. self.prune()
  943. self.n_mkfuncdeco0 = n_mkfuncdeco0
  944. def n_unmapexpr(node):
  945. last_n = node[0][-1]
  946. for n in node[0]:
  947. self.preorder(n)
  948. if n != last_n:
  949. self.f.write(", **")
  950. pass
  951. pass
  952. self.prune()
  953. pass
  954. self.n_unmapexpr = n_unmapexpr
  955. # FIXME: start here
  956. def n_list_unpack(node):
  957. """
  958. prettyprint an unpacked list or tuple
  959. """
  960. p = self.prec
  961. self.prec = 100
  962. lastnode = node.pop()
  963. lastnodetype = lastnode.kind
  964. # If this build list is inside a CALL_FUNCTION_VAR,
  965. # then the first * has already been printed.
  966. # Until I have a better way to check for CALL_FUNCTION_VAR,
  967. # will assume that if the text ends in *.
  968. last_was_star = self.f.getvalue().endswith("*")
  969. if lastnodetype.startswith("BUILD_LIST"):
  970. self.write("[")
  971. endchar = "]"
  972. elif lastnodetype.startswith("BUILD_TUPLE"):
  973. # Tuples can appear places that can NOT
  974. # have parenthesis around them, like array
  975. # subscripts. We check for that by seeing
  976. # if a tuple item is some sort of slice.
  977. no_parens = False
  978. for n in node:
  979. if n == "expr" and n[0].kind.startswith("slice"):
  980. no_parens = True
  981. break
  982. pass
  983. if no_parens:
  984. endchar = ""
  985. else:
  986. self.write("(")
  987. endchar = ")"
  988. pass
  989. elif lastnodetype.startswith("BUILD_SET"):
  990. self.write("{")
  991. endchar = "}"
  992. elif lastnodetype.startswith("BUILD_MAP_UNPACK"):
  993. self.write("{*")
  994. endchar = "}"
  995. elif lastnodetype.startswith("ROT_TWO"):
  996. self.write("(")
  997. endchar = ")"
  998. else:
  999. raise TypeError(
  1000. "Internal Error: n_build_list expects list, tuple, set, or unpack"
  1001. )
  1002. flat_elems = flatten_list(node)
  1003. self.indent_more(INDENT_PER_LEVEL)
  1004. sep = ""
  1005. for elem in flat_elems:
  1006. if elem in ("ROT_THREE", "EXTENDED_ARG"):
  1007. continue
  1008. assert elem == "expr"
  1009. line_number = self.line_number
  1010. value = self.traverse(elem)
  1011. if elem[0] == "tuple":
  1012. assert value[0] == "("
  1013. assert value[-1] == ")"
  1014. value = value[1:-1]
  1015. if value[-1] == ",":
  1016. # singleton tuple
  1017. value = value[:-1]
  1018. else:
  1019. value = "*" + value
  1020. if line_number != self.line_number:
  1021. sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
  1022. else:
  1023. if sep != "":
  1024. sep += " "
  1025. if not last_was_star:
  1026. pass
  1027. else:
  1028. last_was_star = False
  1029. self.write(sep, value)
  1030. sep = ","
  1031. if lastnode.attr == 1 and lastnodetype.startswith("BUILD_TUPLE"):
  1032. self.write(",")
  1033. self.write(endchar)
  1034. self.indent_less(INDENT_PER_LEVEL)
  1035. self.prec = p
  1036. self.prune()
  1037. return
  1038. self.n_tuple_unpack = n_list_unpack
  1039. def n_build_unpack_tuple_with_call(node):
  1040. n = node[0]
  1041. if n == "expr":
  1042. n = n[0]
  1043. if n == "tuple":
  1044. self.call36_tuple(n)
  1045. first = 1
  1046. sep = ", *"
  1047. elif n in ("LOAD_CONST", "LOAD_STR"):
  1048. value = self.format_pos_args(n)
  1049. self.f.write(value)
  1050. first = 1
  1051. sep = ", *"
  1052. else:
  1053. first = 0
  1054. sep = "*"
  1055. buwc = node[-1]
  1056. assert buwc.kind.startswith("BUILD_TUPLE_UNPACK_WITH_CALL")
  1057. for n in node[first:-1]:
  1058. self.f.write(sep)
  1059. self.preorder(n)
  1060. sep = ", *"
  1061. pass
  1062. self.prune()
  1063. return
  1064. self.n_build_tuple_unpack_with_call = n_build_unpack_tuple_with_call
  1065. def n_build_unpack_map_with_call(node):
  1066. n = node[0]
  1067. if n == "expr":
  1068. n = n[0]
  1069. if n == "dict":
  1070. self.call36_dict(n)
  1071. first = 1
  1072. sep = ", **"
  1073. else:
  1074. first = 0
  1075. sep = "**"
  1076. for n in node[first:-1]:
  1077. self.f.write(sep)
  1078. self.preorder(n)
  1079. sep = ", **"
  1080. pass
  1081. self.prune()
  1082. return
  1083. self.n_build_map_unpack_with_call = n_build_unpack_map_with_call
  1084. def n_call_ex_kw(node):
  1085. """Handle CALL_FUNCTION_EX 1 (have KW) but with
  1086. BUILD_MAP_UNPACK_WITH_CALL"""
  1087. expr = node[1]
  1088. assert expr == "expr"
  1089. value = self.format_pos_args(expr)
  1090. if value == "":
  1091. fmt = "%c(%p)"
  1092. else:
  1093. fmt = "%c" + ("(%s, " % value).replace("%", "%%") + "%p)"
  1094. self.template_engine(
  1095. (fmt, (0, "expr"), (2, "build_map_unpack_with_call", 100)), node
  1096. )
  1097. self.prune()
  1098. self.n_call_ex_kw = n_call_ex_kw
  1099. def n_call_ex_kw2(node):
  1100. """Handle CALL_FUNCTION_EX 2 (have KW) but with
  1101. BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
  1102. assert node[1] == "build_tuple_unpack_with_call"
  1103. value = self.format_pos_args(node[1])
  1104. if value == "":
  1105. fmt = "%c(%p)"
  1106. else:
  1107. fmt = "%c" + ("(%s, " % value).replace("%", "%%") + "%p)"
  1108. self.template_engine(
  1109. (fmt, (0, "expr"), (2, "build_map_unpack_with_call", 100)), node
  1110. )
  1111. self.prune()
  1112. self.n_call_ex_kw2 = n_call_ex_kw2
  1113. def call_ex_kw3(node):
  1114. """Handle CALL_FUNCTION_EX 1 (have KW) but without
  1115. BUILD_MAP_UNPACK_WITH_CALL"""
  1116. self.preorder(node[0])
  1117. self.write("(")
  1118. value = self.format_pos_args(node[1][0])
  1119. if value == "":
  1120. pass
  1121. else:
  1122. self.write(value)
  1123. self.write(", ")
  1124. self.write("*")
  1125. self.preorder(node[1][1])
  1126. self.write(", ")
  1127. kwargs = node[2]
  1128. if kwargs == "expr":
  1129. kwargs = kwargs[0]
  1130. if kwargs == "expr" and kwargs[0] != "dict":
  1131. self.call36_dict(kwargs)
  1132. else:
  1133. self.write("**")
  1134. self.preorder(kwargs)
  1135. self.write(")")
  1136. self.prune()
  1137. self.n_call_ex_kw3 = call_ex_kw3
  1138. def call_ex_kw4(node):
  1139. """Handle CALL_FUNCTION_EX {1 or 2} but without
  1140. BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
  1141. self.preorder(node[0])
  1142. self.write("(")
  1143. args = node[1][0]
  1144. if args == "tuple":
  1145. if self.call36_tuple(args) > 0:
  1146. self.write(", ")
  1147. pass
  1148. pass
  1149. else:
  1150. self.write("*")
  1151. self.preorder(args)
  1152. self.write(", ")
  1153. pass
  1154. kwargs = node[2]
  1155. if kwargs == "expr":
  1156. kwargs = kwargs[0]
  1157. call_function_ex = node[-1]
  1158. assert call_function_ex == "CALL_FUNCTION_EX_KW" or (
  1159. self.version >= 3.6 and call_function_ex == "CALL_FUNCTION_EX"
  1160. )
  1161. # FIXME: decide if the below test be on kwargs == 'dict'
  1162. if (
  1163. call_function_ex.attr & 1
  1164. and (not isinstance(kwargs, Token) and kwargs != "attribute")
  1165. and kwargs != "call_kw36"
  1166. and not kwargs[0].kind.startswith("kvlist")
  1167. ):
  1168. self.call36_dict(kwargs)
  1169. else:
  1170. self.write("**")
  1171. self.preorder(kwargs)
  1172. self.write(")")
  1173. self.prune()
  1174. self.n_call_ex_kw4 = call_ex_kw4
  1175. # NOTE! This is different from decompyle3's version
  1176. # Reconcile?
  1177. def format_pos_args(node):
  1178. """
  1179. Positional args should format to:
  1180. (*(2, ), ...) -> (2, ...)
  1181. We remove starting and trailing parenthesis and ', ' if
  1182. tuple has only one element.
  1183. """
  1184. value = self.traverse(node, indent="")
  1185. if value.startswith("("):
  1186. assert value.endswith(")")
  1187. value = value[1:-1].rstrip(
  1188. " "
  1189. ) # Remove starting '(' and trailing ')' and additional spaces
  1190. if value == "":
  1191. pass # args is empty
  1192. else:
  1193. if value.endswith(","): # if args has only one item
  1194. value = value[:-1]
  1195. return value
  1196. self.format_pos_args = format_pos_args
  1197. def n_except_suite_finalize(node):
  1198. if node[1] == "returns" and self.hide_internal:
  1199. # Process node[1] only.
  1200. # The code after "returns", e.g. node[3], is dead code.
  1201. # Adding it is wrong as it dedents and another
  1202. # exception handler "except_stmt" afterwards.
  1203. # Note it is also possible that the grammar is wrong here.
  1204. # and this should not be "except_stmt".
  1205. self.indent_more()
  1206. self.preorder(node[1])
  1207. self.indent_less()
  1208. else:
  1209. self.default(node)
  1210. self.prune()
  1211. self.n_except_suite_finalize = n_except_suite_finalize
  1212. def n_formatted_value(node):
  1213. if node[0] in ("LOAD_STR", "LOAD_CONST"):
  1214. value = node[0].attr
  1215. if isinstance(value, tuple):
  1216. self.write(node[0].attr)
  1217. else:
  1218. self.write(escape_string(node[0].attr))
  1219. self.prune()
  1220. else:
  1221. self.default(node)
  1222. self.n_formatted_value = n_formatted_value
  1223. def n_formatted_value_attr(node):
  1224. f_conversion(node)
  1225. fmt_node = node.data[3]
  1226. if fmt_node == "expr" and fmt_node[0] == "LOAD_STR":
  1227. node.string = escape_format(fmt_node[0].attr)
  1228. else:
  1229. node.string = fmt_node
  1230. self.default(node)
  1231. self.n_formatted_value_attr = n_formatted_value_attr
  1232. def f_conversion(node):
  1233. fmt_node = node.data[1]
  1234. if fmt_node == "expr" and fmt_node[0] == "LOAD_STR":
  1235. data = fmt_node[0].attr
  1236. else:
  1237. data = fmt_node.attr
  1238. node.conversion = FSTRING_CONVERSION_MAP.get(data, "")
  1239. return node.conversion
  1240. def n_formatted_value1(node):
  1241. expr = node[0]
  1242. assert expr == "expr"
  1243. conversion = f_conversion(node)
  1244. if self.in_format_string and self.in_format_string != "formatted_value1":
  1245. value = self.traverse(expr, indent="")
  1246. if value[0] == "{":
  1247. # If we have a set or dictionary comprehension, then we need to add a space
  1248. # so as not to confuse the format string with {{.
  1249. fmt = "{ %s%s }"
  1250. else:
  1251. fmt = "{%s%s}"
  1252. es = escape_string(fmt % (value, conversion))
  1253. f_str = "%s" % es
  1254. else:
  1255. old_in_format_string = self.in_format_string
  1256. self.in_format_string = "formatted_value1"
  1257. value = self.traverse(expr, indent="")
  1258. self.in_format_string = old_in_format_string
  1259. es = escape_string("{%s%s}" % (value, conversion))
  1260. f_str = "f%s" % es
  1261. self.write(f_str)
  1262. self.prune()
  1263. self.n_formatted_value1 = n_formatted_value1
  1264. def n_formatted_value2(node):
  1265. p = self.prec
  1266. self.prec = 100
  1267. expr = node[0]
  1268. assert expr == "expr"
  1269. old_in_format_string = self.in_format_string
  1270. self.in_format_string = "formatted_value2"
  1271. value = self.traverse(expr, indent="")
  1272. format_value_attr = node[-1]
  1273. assert format_value_attr == "FORMAT_VALUE_ATTR"
  1274. attr = format_value_attr.attr
  1275. if attr & 4:
  1276. assert node[1] == "expr"
  1277. fmt = strip_quotes(self.traverse(node[1], indent=""))
  1278. attr_flags = attr & 3
  1279. if attr_flags:
  1280. conversion = "%s:%s" % (FSTRING_CONVERSION_MAP.get(attr_flags, ""), fmt)
  1281. else:
  1282. conversion = ":%s" % fmt
  1283. else:
  1284. conversion = FSTRING_CONVERSION_MAP.get(attr, "")
  1285. self.in_format_string = old_in_format_string
  1286. f_str = "f%s" % escape_string("{%s%s}" % (value, conversion))
  1287. self.write(f_str)
  1288. self.prec = p
  1289. self.prune()
  1290. self.n_formatted_value2 = n_formatted_value2
  1291. def n_joined_str(node):
  1292. p = self.prec
  1293. self.prec = 100
  1294. old_in_format_string = self.in_format_string
  1295. self.in_format_string = "joined_str"
  1296. result = ""
  1297. for expr in node[:-1]:
  1298. assert expr == "expr"
  1299. value = self.traverse(expr, indent="")
  1300. if expr[0].kind.startswith("formatted_value"):
  1301. # remove leading 'f'
  1302. if value.startswith("f"):
  1303. value = value[1:]
  1304. pass
  1305. else:
  1306. # {{ and }} in Python source-code format strings mean
  1307. # { and } respectively. But only when *not* part of a
  1308. # formatted value. However, in the LOAD_STR
  1309. # bytecode, the escaping of the braces has been
  1310. # removed. So we need to put back the braces escaping in
  1311. # reconstructing the source.
  1312. assert expr[0] == "LOAD_STR"
  1313. value = value.replace("{", "{{").replace("}", "}}")
  1314. # Remove leading quotes
  1315. result += strip_quotes(value)
  1316. pass
  1317. self.in_format_string = old_in_format_string
  1318. if self.in_format_string:
  1319. self.write(result)
  1320. else:
  1321. self.write("f%s" % escape_string(result))
  1322. self.prec = p
  1323. self.prune()
  1324. self.n_joined_str = n_joined_str
  1325. def return_closure(node):
  1326. # Nothing should be output here
  1327. self.prune()
  1328. return
  1329. self.n_return_closure = return_closure
  1330. # def kwargs_only_36(node):
  1331. # keys = node[-1].attr
  1332. # num_kwargs = len(keys)
  1333. # values = node[:num_kwargs]
  1334. # for i, (key, value) in enumerate(zip(keys, values)):
  1335. # self.write(key + '=')
  1336. # self.preorder(value)
  1337. # if i < num_kwargs:
  1338. # self.write(',')
  1339. # self.prune()
  1340. # return
  1341. # self.n_kwargs_only_36 = kwargs_only_36
  1342. def n_starred(node):
  1343. node_len = len(node)
  1344. assert node_len > 0
  1345. pos_args = node[0]
  1346. if pos_args == "expr":
  1347. pos_args = pos_args[0]
  1348. if pos_args == "tuple":
  1349. build_tuple = pos_args[0]
  1350. if build_tuple.kind.startswith("BUILD_TUPLE"):
  1351. tuple_len = 0
  1352. else:
  1353. tuple_len = len(node) - 1
  1354. star_start = 1
  1355. template = "%C", (0, -1, ", ")
  1356. self.template_engine(template, pos_args)
  1357. if tuple_len == 0:
  1358. self.write("*()")
  1359. # That's it
  1360. self.prune()
  1361. self.write(", ")
  1362. else:
  1363. star_start = 0
  1364. if node_len > 1:
  1365. template = ("*%C", (star_start, -1, ", *"))
  1366. else:
  1367. template = ("*%c", (star_start, "expr"))
  1368. self.template_engine(template, node)
  1369. self.prune()
  1370. self.n_starred = n_starred
  1371. def n_set_afor(node):
  1372. if len(node) == 2:
  1373. self.template_engine(
  1374. (" async for %[1]{%c} in %c", (1, "store"), (0, "get_aiter")), node
  1375. )
  1376. else:
  1377. self.template_engine(
  1378. " async for %[1]{%c} in %c%c",
  1379. (1, "store"),
  1380. (0, "get_aiter"),
  1381. (2, "set_iter"),
  1382. )
  1383. self.prune()
  1384. self.n_set_afor = n_set_afor
  1385. # FIXME: The following adjusts I guess a bug in the parser.
  1386. # It might be as simple as renaming grammar symbol "testtrue" to "testtrue_or_false"
  1387. # and then keeping this as is with the name change.
  1388. # Fixing in the parsing by inspection is harder than doing it here.
  1389. def n_testtrue(node):
  1390. compare_chained37 = node[0]
  1391. if (
  1392. compare_chained37 == "compare_chained37"
  1393. and compare_chained37[1] == "compare_chained_middleb_37"
  1394. ):
  1395. compare_chained_middleb_37 = compare_chained37[1]
  1396. if (
  1397. len(compare_chained_middleb_37) > 2
  1398. and compare_chained_middleb_37[-2] == "JUMP_FORWARD"
  1399. ):
  1400. node.kind = "testfalse"
  1401. pass
  1402. pass
  1403. self.default(node)
  1404. return
  1405. self.n_testtrue = n_testtrue