gencomp.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. # Copyright (c) 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. """
  16. Generators and comprehension functions
  17. """
  18. from typing import Optional
  19. from spark_parser.ast import GenericASTTraversalPruningException
  20. from xdis import iscode
  21. from decompyle3.parsers.main import get_python_parser
  22. from decompyle3.scanner import Code
  23. from decompyle3.scanners.tok import Token
  24. from decompyle3.semantics.consts import PRECEDENCE
  25. from decompyle3.semantics.helper import is_lambda_mode
  26. class ComprehensionMixin:
  27. """
  28. These functions hand nonterminal common actions that occur
  29. when encountering a generator or some sort of comprehension.
  30. What is common about these is that often the nonterminal has
  31. a code object whose decompilation needs to be melded into the resulting
  32. Python source code. In source code, the implicit function calls
  33. are not seen.
  34. """
  35. def closure_walk(self, node, collection_index: int):
  36. """Dictionary and Set comprehensions using closures."""
  37. p: int = self.prec
  38. code_index = 0 if node[0] == "load_genexpr" else 1
  39. tree = self.get_comprehension_function(node, code_index=code_index)
  40. if tree.kind in ("stmts", "lambda_start"):
  41. tree = tree[0]
  42. # Remove single reductions as in ("stmts", "sstmt"):
  43. # FIXME: when parse_tree -> ast_transform is done we should
  44. # not need this.
  45. while len(tree) == 1 or tree.kind in ("return_expr_lambda",):
  46. tree = tree[0]
  47. if tree == "genexpr_func_async":
  48. store = tree[2]
  49. iter_index = 3
  50. collection_index = 3
  51. elif tree in ("genexpr_func", "dict_comp_func", "set_comp_func"):
  52. store = tree[3]
  53. iter_index = 4
  54. elif tree == "set_comp":
  55. tree = tree[1][0]
  56. assert tree == "set_for", tree.kind
  57. store = tree[2]
  58. iter_index = 3
  59. else:
  60. store = tree[4]
  61. iter_index = 5
  62. if node[collection_index] == "get_iter":
  63. expr = node[collection_index][0]
  64. assert expr == "expr", expr.kind
  65. collection = expr
  66. else:
  67. collection = node[collection_index]
  68. n = tree[iter_index]
  69. if_condition = None
  70. write_if = False
  71. assert n in ("comp_iter", "set_iter")
  72. # Find inner-most body node.
  73. while n == "comp_iter":
  74. n = n[0] # recurse one step
  75. if n in ("list_for", "comp_for"):
  76. store = n[2]
  77. n = n[3]
  78. elif n[0].kind == "c_compare":
  79. if_condition = n
  80. n = n[-1]
  81. elif n in (
  82. "comp_if",
  83. "comp_if_not",
  84. "list_if",
  85. "list_if_and_or",
  86. "list_if_not",
  87. "list_if_or_not",
  88. ):
  89. # FIXME: most of the grammar start with expr_...
  90. # Some of the older ones can be: expr <jump> <iter>
  91. # This may disappear though.
  92. if n[0].kind == "expr":
  93. if_condition = n
  94. n = n[-1]
  95. elif n[0].kind in ("expr_pjif", "expr_pjiff"):
  96. if_condition = n
  97. n = n[-1]
  98. assert n == "comp_iter"
  99. elif n[0].kind in ("or_jump_if_false_cf", "or_jump_if_false_loop_cf"):
  100. if_condition = n[1]
  101. n = n[1]
  102. else:
  103. if len(n) == 2:
  104. if_condition = n[0]
  105. n = n[1]
  106. else:
  107. if_condition = n[1]
  108. n = n[2]
  109. pass
  110. pass
  111. assert n in ("comp_body", "set_iter"), n.kind
  112. self.preorder(n[0])
  113. if node == "generator_exp_async":
  114. self.write(" async")
  115. self.write(" for ")
  116. self.preorder(store)
  117. self.write(" in ")
  118. self.preorder(collection)
  119. if if_condition:
  120. if write_if:
  121. self.write(" if ")
  122. self.preorder(if_condition)
  123. self.prec = p
  124. def comprehension_walk(
  125. self,
  126. node,
  127. iter_index: Optional[int],
  128. ):
  129. p: int = self.prec
  130. self.prec = PRECEDENCE["lambda_body"] - 1
  131. # FIXME: clean this up
  132. if node == "dict_comp":
  133. cn = node[1]
  134. elif node in ("generator_exp", "generator_exp_async"):
  135. if node[0] == "load_genexpr":
  136. load_genexpr = node[0]
  137. elif node[1] == "load_genexpr":
  138. load_genexpr = node[1]
  139. cn = load_genexpr[0]
  140. else:
  141. if len(node[1]) > 1 and hasattr(node[1][1], "attr"):
  142. # Python 3.3+ does this
  143. cn = node[1][1]
  144. else:
  145. assert False, "Can't find code for comprehension"
  146. assert iscode(cn.attr)
  147. code = Code(cn.attr, self.scanner, self.currentclass, self.debug_opts["asm"])
  148. # FIXME: is there a way we can avoid this?
  149. # The problem is that in filter in top-level list comprehensions we can
  150. # encounter comprehensions of other kinds, and lambdas
  151. if is_lambda_mode(self.compile_mode):
  152. p_save = self.p
  153. self.p = get_python_parser(
  154. self.version,
  155. compile_mode="exec",
  156. is_pypy=self.is_pypy,
  157. )
  158. tree = self.build_ast(code._tokens, code._customize, code)
  159. self.p = p_save
  160. else:
  161. tree = self.build_ast(code._tokens, code._customize, code)
  162. self.customize(code._customize)
  163. # Remove single reductions as in ("stmts", "sstmt"):
  164. while len(tree) == 1:
  165. tree = tree[0]
  166. if tree == "stmts":
  167. # FIXME: rest is a return None?
  168. # Verify this
  169. # rest = tree[1:]
  170. tree = tree[0]
  171. elif tree == "lambda_start":
  172. assert len(tree) <= 3
  173. tree = tree[-2]
  174. if tree == "return_expr_lambda":
  175. tree = tree[1]
  176. pass
  177. if tree in ("genexpr_func_async", "genexpr_func"):
  178. for n in tree:
  179. if n.kind == "comp_iter":
  180. break
  181. pass
  182. else:
  183. n = tree[iter_index]
  184. assert n == "comp_iter", n
  185. if_condition = None
  186. write_if = False
  187. # Find the comprehension body. It is the inner-most
  188. # node that is not list_.. .
  189. while n == "comp_iter": # list_iter
  190. n = n[0] # recurse one step
  191. if n == "comp_for":
  192. if n[0] == "SETUP_LOOP":
  193. n = n[4]
  194. else:
  195. n = n[3]
  196. elif n == "comp_if":
  197. n = n[1]
  198. elif n in (
  199. "comp_if_not",
  200. "comp_if_not_and",
  201. "comp_if_not_or",
  202. "comp_if_or",
  203. ):
  204. if_condition = n
  205. write_if = True
  206. n = n[-1]
  207. assert n == "comp_iter"
  208. assert n == "comp_body", n.kind
  209. self.preorder(n[0])
  210. if node == "generator_exp_async":
  211. self.write(" async")
  212. iter_var_index = 2
  213. else:
  214. iter_var_index = iter_index
  215. if tree[iter_var_index] != "store":
  216. iter_var_index = iter_index - 1
  217. self.write(" for ")
  218. self.preorder(tree[iter_var_index])
  219. self.write(" in ")
  220. if node[2] == "expr":
  221. iter_expr = node[2]
  222. elif node[3] == "get_aiter":
  223. iter_expr = node[3]
  224. else:
  225. iter_expr = node[-3]
  226. assert iter_expr in ("expr", "get_aiter"), iter_expr
  227. self.preorder(iter_expr)
  228. if if_condition and not tree[iter_index][0].kind.startswith("comp_if"):
  229. if write_if:
  230. self.write(" if ")
  231. self.preorder(if_condition)
  232. self.prec = p
  233. def comprehension_walk_newer(
  234. self,
  235. node,
  236. iter_index: Optional[int],
  237. code_index: int = -5,
  238. collection_node=None,
  239. ):
  240. """Non-closure-based comprehensions.
  241. Note: there are also other comprehensions.
  242. """
  243. # FIXME: DRY with listcomp_closure3
  244. p = self.prec
  245. self.prec = PRECEDENCE["lambda_body"] - 1
  246. # FIXME? Nonterminals in grammar maybe should be split out better?
  247. # Maybe test on self.compile_mode?
  248. if (
  249. isinstance(node[0], Token)
  250. and node[0].kind.startswith("LOAD")
  251. and iscode(node[0].attr)
  252. ):
  253. if node[3] == "get_aiter":
  254. compile_mode = self.compile_mode
  255. self.compile_mode = "genexpr"
  256. is_lambda = self.is_lambda
  257. self.is_lambda = True
  258. try:
  259. tree = self.get_comprehension_function(node, code_index)
  260. except GenericASTTraversalPruningException:
  261. pass
  262. self.compile_mode = compile_mode
  263. self.is_lambda = is_lambda
  264. else:
  265. tree = self.get_comprehension_function(node, code_index)
  266. elif (
  267. len(node) > 2
  268. and isinstance(node[2], Token)
  269. and node[2].kind.startswith("LOAD")
  270. and iscode(node[2].attr)
  271. ):
  272. tree = self.get_comprehension_function(node, 2)
  273. else:
  274. tree = node
  275. # Pick out important parts of the comprehension:
  276. # * the variable we iterate over: "store"
  277. # * the results we accumulate: "n"
  278. store = None
  279. if tree.kind == "genexpr_func_async":
  280. genexpr_func_async = tree
  281. elif tree.kind == "set_iter":
  282. # Not sure if this is correct
  283. node = tree = tree[0]
  284. elif tree.kind != "genexpr_func":
  285. # Not sure if this is still correct
  286. genexpr_func_async = tree[1]
  287. collection_node_index = None
  288. if node == "list_comp_async":
  289. # We have two different kinds of grammar rules:
  290. # list_comp_async ::= LOAD_LISTCOMP LOAD_STR MAKE_FUNCTION_0 expr ...
  291. # and:
  292. # list_comp_async ::= BUILD_LIST_0 LOAD_ARG list_afor2
  293. if tree[0] == "expr" and tree[0][0] == "list_comp_async":
  294. tree = tree[0][0]
  295. # PyPy 3.8 has LOAD_ARG
  296. if tree[0] in ("BUILD_LIST_0", "LOAD_ARG"):
  297. list_afor2 = tree[2]
  298. assert list_afor2 == "list_afor2"
  299. store = list_afor2[1]
  300. assert store == "store"
  301. n = list_afor2[3] if list_afor2[3] == "list_iter" else list_afor2[2]
  302. collection_node_index = 1
  303. else:
  304. # ???
  305. pass
  306. elif node.kind in ("dict_comp_async", "set_comp_async"):
  307. # We have two different kinds of grammar rules:
  308. # dict_comp_async ::= LOAD_DICTCOMP LOAD_STR MAKE_FUNCTION_0 expr ...
  309. # set_comp_async ::= LOAD_SETCOMP LOAD_STR MAKE_FUNCTION_0 expr ...
  310. # and:
  311. # dict_comp_async ::= BUILD_MAP_0 LOAD_ARG genexpr_func_async
  312. # set_comp_async ::= BUILD_SET_0 LOAG_ARG genexpr_func_async
  313. if tree[0] == "expr":
  314. tree = tree[0]
  315. if tree[0].kind in ("BUILD_MAP_0", "BUILD_SET_0"):
  316. genexpr_func_async = tree[1]
  317. if genexpr_func_async == "genexpr_func_async":
  318. store = genexpr_func_async[2]
  319. assert store.kind.startswith("store")
  320. n = genexpr_func_async[3]
  321. else:
  322. set_afor2 = genexpr_func_async
  323. assert set_afor2 == "set_afor2"
  324. n = set_afor2[1]
  325. store = n[1]
  326. collection_node = node[3]
  327. else:
  328. # ???
  329. pass
  330. elif node == "list_afor":
  331. collection_node = node[0]
  332. list_afor2 = node[1]
  333. assert list_afor2 == "list_afor2"
  334. store = list_afor2[1]
  335. assert store == "store"
  336. n = list_afor2[2]
  337. elif node == "set_afor2":
  338. collection_node = node[0]
  339. set_iter_async = node[1]
  340. assert set_iter_async == "set_iter_async"
  341. store = set_iter_async[1]
  342. assert store == "store"
  343. n = set_iter_async[2]
  344. elif node == "list_comp" and tree[0] == "expr":
  345. tree = tree[0][0]
  346. n = tree[iter_index]
  347. elif node == "set_comp" and tree[1] == "set_iter":
  348. n = tree[1]
  349. else:
  350. for k in tree:
  351. if k.kind in ("comp_iter", "list_iter", "set_iter", "lc_body"):
  352. n = k
  353. break
  354. pass
  355. else:
  356. n = tree[iter_index]
  357. if tree in (
  358. "dict_comp_func",
  359. "genexpr_func",
  360. "genexpr_func_async",
  361. "generator_exp",
  362. "list_comp",
  363. "set_comp",
  364. "set_comp_func",
  365. "set_comp_func_header",
  366. ):
  367. # Find location of store
  368. for k in tree:
  369. if k.kind in ("comp_iter", "list_iter", "set_iter", "await_expr"):
  370. n = k
  371. elif k == "store":
  372. store = k
  373. break
  374. pass
  375. pass
  376. elif tree.kind in ("list_comp_async", "dict_comp_async", "set_afor2"):
  377. # Handled this condition above.
  378. pass
  379. else:
  380. # FIXME: we get this when we parse lambda's explicitly.
  381. # And here we've already printed/handled the list comprehension
  382. # this iteration is duplicate in seeing the list-comprehension code
  383. # item again. Is this a larger duplicate parsing problem?
  384. # Not sure what the best this thing to do is.
  385. # try:
  386. # n
  387. # except:
  388. # from trepan.api import debug; debug()
  389. if n.kind in ("RETURN_VALUE_LAMBDA", "return_expr_lambda"):
  390. self.prune()
  391. assert n.kind in ("list_iter", "comp_iter", "set_iter", "set_iter_async"), n
  392. # FIXME: I'm not totally sure this is right.
  393. # Find the list comprehension body. It is the inner-most
  394. # node that is not list_.. .
  395. if_nodes = []
  396. if_node_parent = None
  397. comp_for = None
  398. comp_store = None
  399. if n == "comp_iter":
  400. comp_for = n
  401. if not store:
  402. comp_store = tree[3]
  403. # Iterate to find the inner-most comprehension body.
  404. # We'll come back to the list iteration below.
  405. while n in (
  406. "comp_iter",
  407. "list_afor",
  408. "list_afor2",
  409. "list_iter",
  410. "set_afor",
  411. "set_afor2",
  412. "set_iter",
  413. "set_iter_async",
  414. ):
  415. # iterate one nesting deeper
  416. if n in ("list_afor", "set_afor"):
  417. n = n[1]
  418. elif n in ("list_afor2", "set_afor2", "set_iter_async"):
  419. if n[1] == "store":
  420. store = n[1]
  421. n = n[3] if n[3] in ("list_iter", "set_iter") else n[2]
  422. else:
  423. n = n[0]
  424. if n in ("comp_for", "list_for", "set_for"):
  425. collection_node = n
  426. if n[2] == "store" and not store:
  427. store = n[2]
  428. if not comp_store:
  429. comp_store = store
  430. n = n[3]
  431. assert n.kind in ("comp_iter", "list_iter", "set_iter")
  432. elif n in ("list_if_chained",):
  433. # list_if_chained ::= list_if_compare ... list_iter
  434. if_nodes.append(n[0])
  435. assert n[0] == "list_if_compare"
  436. n = n[-1]
  437. assert n == "list_iter"
  438. elif n in (
  439. "comp_if_not_and",
  440. "comp_if_or",
  441. "comp_if_or2",
  442. "comp_if_or_not",
  443. "comp_if_not_or",
  444. ):
  445. if_nodes.append(n[0])
  446. n = n[-1]
  447. assert n == "comp_iter"
  448. elif n in (
  449. "list_if",
  450. "list_if_not",
  451. "list_if37",
  452. "list_if37_not",
  453. "comp_if",
  454. "comp_if_not",
  455. ):
  456. if n in ("list_if37", "list_if37_not", "comp_if"):
  457. if n in ("comp_if", "list_if37", "list_if"):
  458. if_nodes.append(n[0])
  459. n = n[1]
  460. else:
  461. if n in ("comp_if_not",):
  462. if_nodes.append(n)
  463. else:
  464. if_node_parent = n
  465. if_nodes.append(n[0])
  466. if n[1] == "store":
  467. store = n[1]
  468. n = n[-2] if n[-1] == "come_from_opt" else n[-1]
  469. pass
  470. elif n.kind == "list_if_and_or":
  471. if_nodes.append(n[-1][0])
  472. n = n[-1]
  473. assert n == "list_iter"
  474. pass
  475. # Python 2.7+ starts including set_comp_body
  476. # Python 3.5+ starts including set_comp_func
  477. assert store, "Couldn't find store in list/set comprehension"
  478. # A problem created with later Python code generation is that there
  479. # is a lambda set up with a dummy argument name that is then called
  480. # So we can't just translate that as is but need to replace the
  481. # dummy name. Below we are picking out the variable name as seen
  482. # in the code. And trying to generate code for the other parts
  483. # that don't have the dummy argument name in it.
  484. # Another approach might be to be able to pass in the source name
  485. # for the dummy argument.
  486. if node not in ("list_afor", "set_afor"):
  487. # FIXME decompile_cfg doesn't have to do this. Find out why.
  488. self.preorder(n if n.kind in ("await_expr", "LOAD_ARG") else n[0])
  489. if node.kind in (
  490. "dict_comp_async",
  491. "genexpr_func_async",
  492. "list_afor",
  493. "list_comp_async",
  494. "set_afor2",
  495. "set_comp_async",
  496. ):
  497. self.write(" async")
  498. # For listcomp, setcomp, etc., the collection is .0 and that's the best we
  499. # can do. So don't try to find the collection node.
  500. if not self.compile_mode.endswith("comp"):
  501. collection_node_index = None
  502. if collection_node_index is None:
  503. for i, child in enumerate(node):
  504. if child.kind in (
  505. "expr",
  506. "expr_get_aiter",
  507. "get_aiter",
  508. "get_iter",
  509. ):
  510. collection_node_index = i
  511. break
  512. assert collection_node_index is not None
  513. elif len(node) >= 3 and node[3] == "expr":
  514. collection_node_index = 3
  515. collection_node = node[3]
  516. assert collection_node == "expr"
  517. elif node == "comp_body":
  518. collection_node = node
  519. elif node.kind == "genexpr_func":
  520. collection_node_index = 0
  521. elif collection_node is None:
  522. collection_node_index = -3
  523. self.write(" for ")
  524. if comp_store:
  525. self.preorder(comp_store)
  526. # We have already added the comp_store contribution,
  527. # don't attempt to decompile it again
  528. comp_store = None
  529. else:
  530. self.preorder(store)
  531. self.write(" in ")
  532. if node == "list_afor":
  533. list_afor2 = node[1]
  534. assert list_afor2 == "list_afor2"
  535. list_iter = list_afor2[2]
  536. assert list_iter == "list_iter"
  537. self.preorder(collection_node)
  538. elif node == "set_comp_async":
  539. self.preorder(collection_node)
  540. elif node == "list_comp_async":
  541. self.preorder(node[collection_node_index])
  542. elif is_lambda_mode(self.compile_mode) and collection_node_index is None:
  543. if node in ("list_comp_async",):
  544. self.preorder(node[1])
  545. elif collection_node is None:
  546. assert node[3] in ("get_aiter", "get_iter"), node[3].kind
  547. self.preorder(node[3])
  548. else:
  549. self.preorder(collection_node)
  550. else:
  551. if not collection_node:
  552. if node[3] == "set_iter":
  553. self.preorder(tree[0])
  554. collection_node = node[collection_node_index]
  555. self.preorder(collection_node)
  556. # Here is where we handle nested list iterations which
  557. # includes their corresponding "if" conditions.
  558. if tree in ("list_comp", "set_comp") and not self.is_pypy:
  559. list_iter = tree[1]
  560. assert list_iter in ("list_iter", "set_iter")
  561. list_for = list_iter[0]
  562. if list_for in ("list_for", "set_for"):
  563. # In the grammar we have:
  564. # list_for ::= _ for_iter store list_iter ...
  565. # or
  566. # set_for ::= _ set_iter store set_iter ...
  567. list_iter_inner = list_for[3]
  568. assert list_iter_inner in ("list_iter", "set_iter")
  569. # If we have set_comp_body, we've done this above.
  570. if not (
  571. list_iter_inner == "set_iter"
  572. and list_iter_inner[0] == "set_comp_body"
  573. ):
  574. self.preorder(list_iter_inner)
  575. if if_node_parent == list_iter_inner[0]:
  576. self.prec = p
  577. return
  578. comp_store = None
  579. pass
  580. elif tree == "set_comp_func":
  581. # Handle nested comp_for iterations.
  582. comp_iter = tree[4]
  583. assert comp_iter in ("comp_iter", "await_expr")
  584. while comp_iter == "comp_iter":
  585. comp_for = comp_iter[0]
  586. if comp_for != "comp_for":
  587. break
  588. self.preorder(comp_iter)
  589. if len(comp_for) < 4:
  590. break
  591. comp_iter = comp_for[3]
  592. assert comp_store is None
  593. if comp_store:
  594. self.preorder(comp_store)
  595. for if_node in if_nodes:
  596. if if_node != "comp_if_or":
  597. self.write(" if ")
  598. if if_node in (
  599. "c_compare_chained37_false",
  600. "comp_if_not_and",
  601. "comp_if_not_or",
  602. "comp_if_or",
  603. "comp_if_or2",
  604. "comp_if_or_not",
  605. ):
  606. self.preorder(if_node)
  607. else:
  608. # FIXME: go over these to add more of this in the template,
  609. # not here.
  610. if if_node in (
  611. "comp_if_not",
  612. "list_if37_not",
  613. "list_if_not",
  614. "list_if_or_not",
  615. ):
  616. self.write("not ")
  617. pass
  618. self.prec = PRECEDENCE["lambda_body"] - 1
  619. self.preorder(if_node[0])
  620. pass
  621. self.prec = p
  622. def get_comprehension_function(self, node, code_index: int):
  623. """
  624. Build the body of a comprehension function and then
  625. find the comprehension node buried in the tree which may
  626. be surrounded with start-like symbols or dominiators,.
  627. """
  628. self.prec = PRECEDENCE["lambda_body"] - 1
  629. code_node = node[code_index]
  630. if code_node == "load_genexpr":
  631. code_node = code_node[0]
  632. code_obj = code_node.attr
  633. assert iscode(code_obj), code_node
  634. code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
  635. # FIXME: is there a way we can avoid this?
  636. # The problem is that in filter in top-level list comprehensions we can
  637. # encounter comprehensions of other kinds, and lambdas
  638. if is_lambda_mode(self.compile_mode):
  639. p_save = self.p
  640. self.p = get_python_parser(
  641. self.version,
  642. compile_mode="exec",
  643. is_pypy=self.is_pypy,
  644. )
  645. tree = self.build_ast(
  646. code._tokens, code._customize, code, is_lambda=self.is_lambda
  647. )
  648. self.p = p_save
  649. else:
  650. tree = self.build_ast(
  651. code._tokens, code._customize, code, is_lambda=self.is_lambda
  652. )
  653. self.customize(code._customize)
  654. # skip over: sstmt, stmt, return, return_expr
  655. # and other singleton derivations
  656. if tree == "lambda_start":
  657. tree = tree[0]
  658. while len(tree) == 1 or (
  659. tree in ("stmt", "sstmt", "return", "return_expr", "return_expr_lambda")
  660. ):
  661. self.prec = 100
  662. tree = tree[0]
  663. return tree