lambda_expr.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. # Copyright (c) 2017-2023 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. Python 3.7 lambda grammar for the spark Earley-algorithm parser.
  17. """
  18. from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
  19. from decompyle3.parsers.p37.lambda_custom import Python37LambdaCustom
  20. from decompyle3.parsers.parse_heads import PythonBaseParser, PythonParserLambda
  21. class Python37LambdaParser(Python37LambdaCustom, PythonParserLambda):
  22. def __init__(
  23. self,
  24. start_symbol: str = "lambda_start",
  25. debug_parser: dict = PARSER_DEFAULT_DEBUG,
  26. ):
  27. PythonParserLambda.__init__(
  28. self, debug_parser=debug_parser, start_symbol=start_symbol
  29. )
  30. PythonBaseParser.__init__(
  31. self, start_symbol=start_symbol, debug_parser=debug_parser
  32. )
  33. Python37LambdaCustom.__init__(self)
  34. def customize_grammar_rules(self, tokens, customize):
  35. self.customize_grammar_rules_lambda37(tokens, customize)
  36. ###################################################
  37. # Python 3.7 grammar rules for lambda expressions
  38. ###################################################
  39. pass
  40. def p_lambda(self, args):
  41. """
  42. lambda_start ::= return_expr_lambda LAMBDA_MARKER
  43. return_expr_lambda ::= expr RETURN_VALUE_LAMBDA
  44. return_expr_lambda ::= genexpr_func LOAD_CONST RETURN_VALUE_LAMBDA
  45. return_expr_lambda ::= if_exp_lambda
  46. return_expr_lambda ::= if_exp_lambda2
  47. return_expr_lambda ::= if_exp_not_lambda
  48. return_expr_lambda ::= if_exp_not_lambda2
  49. return_expr_lambda ::= if_exp_dead_code
  50. return_expr_lambda ::= dict_comp_func
  51. ## FIXME: add rules for these
  52. # return_expr_lambda ::= generator_exp
  53. # return_expr_lambda ::= list_comp_func
  54. return_expr_lambda ::= set_comp_func
  55. return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
  56. return_if_lambda ::= RETURN_END_IF_LAMBDA
  57. if_exp_lambda ::= expr_pjif expr return_if_lambda
  58. return_expr_lambda LAMBDA_MARKER
  59. if_exp_lambda2 ::= and_parts return_expr_lambda come_froms
  60. return_expr_lambda opt_lambda_marker
  61. if_exp_not_lambda ::= expr POP_JUMP_IF_TRUE expr return_if_lambda
  62. return_expr_lambda LAMBDA_MARKER
  63. if_exp_not_lambda2 ::= expr POP_JUMP_IF_TRUE expr
  64. RETURN_VALUE_LAMBDA COME_FROM return_expr_lambda
  65. if_exp_dead_code ::= return_expr_lambda return_expr_lambda
  66. opt_lambda_marker ::= LAMBDA_MARKER?
  67. """
  68. def p_and_or_not(self, args):
  69. """
  70. # Note: reduction-rule checks are needed for many of the below;
  71. # the rules in of themselves are not sufficient.
  72. # Nonterminals that end in "_cond" are used in "conditions":
  73. # used for testing in control structures where the test is important and
  74. # the value popped. Conditions also generally have non-local COME_FROMs
  75. # that often need to be checked in the control structure. This is for example
  76. # how we determine the difference between some "if not (not a or b) versus
  77. # "if a and b".
  78. # FIXME: this is some sort of bool_not or not_cond. Figure out how to have
  79. # it not appear in arbitrary expr's
  80. not ::= expr_pjit
  81. and_parts ::= expr_pjif+
  82. # Note: "and" like "nor" might not have a trailing "come_from".
  83. # "nand" and "or", in contrast, *must* have at least one "come_from".
  84. not_or ::= and_parts expr_pjif _come_froms
  85. and_cond ::= and_parts expr_pjif _come_froms
  86. and_cond ::= testfalse expr_pjif _come_froms
  87. and_not_cond ::= and_not
  88. # FIXME: Investigate - We don't do the below because these rules prevent the
  89. # "and_cond" from triggering.
  90. # and ::= and_parts expr
  91. # and ::= not expr
  92. nand ::= and_parts expr_pjit come_froms
  93. c_nand ::= and_parts expr_pjitt come_froms
  94. or_parts ::= expr_pjit+
  95. # Note: "nor" like "and" might not have a trailing "come_from".
  96. # "nand" and "or_cond", in contrast, *must* have at least one "come_from".
  97. or_cond ::= or_parts expr_pjif come_froms
  98. or_cond ::= not_and_not expr_pjif come_froms
  99. or_cond1 ::= and POP_JUMP_IF_TRUE come_froms expr_pjif come_from_opt
  100. nor_cond ::= or_parts expr_pjif
  101. # When we alternating and/or's such as:
  102. # a and (b or c) and d
  103. # instead of POP_JUMP_IF_TRUE, JUMP_IF_FALSE_OR_POP is sometimes be used
  104. # The semantic rules for "and" require expr-like things in positions 0 and 1,
  105. # thus the use of expr_jifop_cfs below.
  106. expr_jifop_cfs ::= expr JUMP_IF_FALSE_OR_POP _come_froms
  107. and ::= expr_jifop_cfs expr _come_froms
  108. or_and ::= expr_jitop expr come_from_opt JUMP_IF_FALSE_OR_POP expr
  109. _come_froms
  110. or_and1 ::= or_parts and_parts come_froms
  111. and_or ::= expr_jifop expr come_from_opt JUMP_IF_TRUE_OR_POP expr
  112. _come_froms
  113. ## A COME_FROM is dropped off because of JUMP-to-JUMP optimization
  114. # and ::= expr_pjif expr
  115. ## Note that "POP_JUMP_IF_FALSE" is what we check on in the "and" reduce rule.
  116. # and ::= expr_pjif expr COME_FROM
  117. jump_if_false_cf ::= POP_JUMP_IF_FALSE COME_FROM
  118. and_or_cond ::= and_parts expr POP_JUMP_IF_TRUE come_froms expr_pjif
  119. _come_froms
  120. # For "or", keep index 0 and 1 be the two expressions.
  121. or ::= or_parts expr
  122. or ::= expr_pjit expr COME_FROM
  123. or ::= expr_pjit expr jump_if_false_cf
  124. # Note: in the "or below", if "come_from_opt" becomes
  125. # _come_froms, then we will need to write a check to make sure
  126. # *all* of the COME_FROMs are associated with the
  127. # "or".
  128. #
  129. # Otherwise, in 3.8 we may turn:
  130. # i and j or k # i == i and (j or k)
  131. # erroneously into:
  132. # i and (j or k)
  133. or ::= expr_jitop expr come_from_opt
  134. or_expr ::= expr JUMP_IF_TRUE expr COME_FROM
  135. jitop_come_from_expr ::= JUMP_IF_TRUE_OR_POP _come_froms expr
  136. and_or_expr ::= and_parts expr jitop_come_from_expr COME_FROM
  137. """
  138. def p_come_froms(self, args):
  139. """
  140. # Zero or one COME_FROM
  141. # And/or expressions have this
  142. come_from_opt ::= COME_FROM?
  143. # One or more COME_FROMs - joins of tryelse's have this
  144. come_froms ::= COME_FROM+
  145. # Zero or more COME_FROMs - loops can have this
  146. _come_froms ::= COME_FROM*
  147. _come_froms ::= COME_FROM_LOOP
  148. """
  149. def p_jump(self, args):
  150. """
  151. jump ::= JUMP_FORWARD
  152. jump ::= JUMP_LOOP
  153. jump_or_break ::= jump
  154. jump_or_break ::= BREAK_LOOP
  155. # These are used to keep parse tree indices the same
  156. # in "if"/"else" like rules.
  157. jump_forward_else ::= JUMP_FORWARD _come_froms
  158. jump_forward_else ::= come_froms jump COME_FROM
  159. pjump_ift ::= POP_JUMP_IF_TRUE
  160. pjump_ift ::= POP_JUMP_IF_TRUE_LOOP
  161. pjump_iff ::= POP_JUMP_IF_FALSE
  162. pjump_iff ::= POP_JUMP_IF_FALSE_LOOP
  163. # pjump ::= pjump_iff
  164. # pjump ::= pjump_ift
  165. """
  166. def p_37chained(self, args):
  167. """
  168. # A compare_chained is two comparisons like x <= y <= z
  169. compare_chained ::= expr compare_chained_middle ROT_TWO POP_TOP _come_froms
  170. compare_chained ::= compare_chained37
  171. compare_chained ::= compare_chained37_false
  172. compare_chained_and ::= expr chained_parts
  173. compare_chained_righta_false_37
  174. come_froms
  175. POP_TOP JUMP_FORWARD COME_FROM
  176. negated_testtrue
  177. come_froms
  178. # We don't use testtrue directly because we need to tell the semantic
  179. # action to negate the testtrue
  180. negated_testtrue ::= testtrue
  181. c_compare_chained ::= c_compare_chained37_false
  182. compare_chained37 ::= expr chained_parts
  183. compare_chained37 ::= expr compare_chained_middlea_37
  184. compare_chained37 ::= expr compare_chained_middlec_37
  185. c_compare_chained37 ::= expr c_compare_chained_middlea_37
  186. # c_compare_chained37 ::= expr c_compare_chained_middlec_37
  187. compare_chained37_false ::= expr compare_chained_middle_false_37
  188. compare_chained37_false ::= expr compare_chained_middleb_false_37
  189. compare_chained37_false ::= expr compare_chained_right_false_37
  190. c_compare_chained37_false ::= expr c_compare_chained_right_false_37
  191. c_compare_chained37_false ::= expr c_compare_chained_middleb_false_37
  192. c_compare_chained37_false ::= compare_chained37_false
  193. compare_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  194. JUMP_IF_FALSE_OR_POP compare_chained_middle
  195. COME_FROM
  196. compare_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  197. JUMP_IF_FALSE_OR_POP compare_chained_right
  198. COME_FROM
  199. chained_parts ::= chained_part+
  200. chained_part ::= expr DUP_TOP ROT_THREE COMPARE_OP come_from_opt
  201. POP_JUMP_IF_FALSE
  202. chained_part ::= expr DUP_TOP ROT_THREE COMPARE_OP come_from_opt
  203. # c_chained_parts ::= c_chained_part+
  204. # c_chained_part ::= expr DUP_TOP ROT_THREE COMPARE_OP come_from_opt
  205. POP_JUMP_IF_FALSE_LOOP
  206. # c_chained_parts ::= chained_parts
  207. compare_chained_middlea_37 ::= chained_parts
  208. compare_chained_righta_37 COME_FROM
  209. POP_TOP come_from_opt
  210. c_compare_chained_middlea_37 ::= chained_parts
  211. c_compare_chained_righta_37 COME_FROM
  212. POP_TOP come_from_opt
  213. compare_chained_middleb_false_37 ::= chained_parts
  214. compare_chained_rightb_false_37
  215. POP_TOP jump _come_froms
  216. c_compare_chained_middleb_false_37 ::= chained_parts
  217. c_compare_chained_rightb_false_37 POP_TOP jump
  218. _come_froms
  219. c_compare_chained_middleb_false_37 ::= chained_parts
  220. compare_chained_rightb_false_37 POP_TOP jump
  221. _come_froms
  222. compare_chained_middlec_37 ::= chained_parts
  223. compare_chained_righta_37 POP_TOP
  224. compare_chained_middle_false_37 ::= chained_parts
  225. compare_chained_rightc_37 POP_TOP JUMP_FORWARD
  226. come_from_opt
  227. compare_chained_middle_false_37 ::= chained_parts
  228. compare_chained_rightb_false_37 POP_TOP jump
  229. COME_FROM
  230. compare_chained_right ::= expr COMPARE_OP JUMP_FORWARD
  231. compare_chained_right ::= expr COMPARE_OP RETURN_VALUE
  232. compare_chained_right ::= expr COMPARE_OP RETURN_VALUE_LAMBDA
  233. compare_chained_right_false_37 ::= chained_parts
  234. compare_chained_righta_false_37 POP_TOP
  235. JUMP_LOOP COME_FROM
  236. c_compare_chained_right_false_37 ::= chained_parts
  237. c_compare_chained_righta_false_37 POP_TOP
  238. JUMP_LOOP COME_FROM
  239. compare_chained_righta_37 ::= expr COMPARE_OP come_from_opt
  240. POP_JUMP_IF_TRUE JUMP_FORWARD
  241. c_compare_chained_righta_37 ::= expr COMPARE_OP come_from_opt
  242. POP_JUMP_IF_TRUE_LOOP JUMP_FORWARD
  243. compare_chained_righta_37 ::= expr COMPARE_OP come_from_opt
  244. POP_JUMP_IF_TRUE JUMP_LOOP
  245. compare_chained_righta_false_37 ::= expr COMPARE_OP come_from_opt
  246. POP_JUMP_IF_FALSE jf_cfs
  247. compare_chained_rightb_false_37 ::= expr COMPARE_OP come_from_opt
  248. POP_JUMP_IF_FALSE
  249. jump_or_break COME_FROM
  250. c_compare_chained_rightb_false_37 ::= expr COMPARE_OP come_from_opt
  251. POP_JUMP_IF_FALSE_LOOP jump_or_break
  252. COME_FROM
  253. c_compare_chained_righta_false_37 ::= expr COMPARE_OP come_from_opt
  254. POP_JUMP_IF_FALSE_LOOP jf_cfs
  255. c_compare_chained_righta_false_37 ::= expr COMPARE_OP come_from_opt
  256. POP_JUMP_IF_FALSE_LOOP
  257. c_compare_chained_rightb_false_37 ::= expr COMPARE_OP come_from_opt
  258. JUMP_FORWARD COME_FROM
  259. compare_chained_rightc_37 ::= chained_parts
  260. compare_chained_righta_false_37
  261. """
  262. def p_expr(self, args):
  263. """
  264. expr ::= LOAD_CODE
  265. expr ::= LOAD_CONST
  266. expr ::= LOAD_DEREF
  267. expr ::= LOAD_FAST
  268. expr ::= LOAD_GLOBAL
  269. expr ::= LOAD_NAME
  270. expr ::= LOAD_STR
  271. expr ::= and
  272. expr ::= and_or
  273. expr ::= and_or_expr
  274. expr ::= attribute37
  275. expr ::= bin_op
  276. expr ::= call
  277. expr ::= compare
  278. expr ::= genexpr_func
  279. expr ::= if_exp
  280. expr ::= if_exp_loop
  281. expr ::= list_comp
  282. expr ::= not
  283. expr ::= or
  284. expr ::= or_and
  285. expr ::= or_expr
  286. expr ::= set_comp
  287. expr ::= subscript
  288. expr ::= subscript2
  289. expr ::= unary_not
  290. expr ::= unary_op
  291. expr ::= yield
  292. # Python 3.3+ adds yield from.
  293. expr ::= yield_from
  294. yield_from ::= expr GET_YIELD_FROM_ITER LOAD_CONST YIELD_FROM
  295. attribute37 ::= expr LOAD_METHOD
  296. # bin_op (formerly "binary_expr") is the Python AST BinOp
  297. bin_op ::= expr expr binary_operator
  298. binary_operator ::= BINARY_ADD
  299. binary_operator ::= BINARY_AND
  300. binary_operator ::= BINARY_FLOOR_DIVIDE
  301. binary_operator ::= BINARY_LSHIFT
  302. binary_operator ::= BINARY_MATRIX_MULTIPLY
  303. binary_operator ::= BINARY_MODULO
  304. binary_operator ::= BINARY_MULTIPLY
  305. binary_operator ::= BINARY_OR
  306. binary_operator ::= BINARY_POWER
  307. binary_operator ::= BINARY_RSHIFT
  308. binary_operator ::= BINARY_SUBTRACT
  309. binary_operator ::= BINARY_TRUE_DIVIDE
  310. binary_operator ::= BINARY_XOR
  311. # FIXME: the below is to work around test_grammar expecting a "call" to be
  312. # on the LHS because it is also somewhere on in a rule.
  313. call ::= expr CALL_METHOD_0
  314. compare ::= compare_chained
  315. compare ::= compare_single
  316. compare_single ::= expr expr COMPARE_OP
  317. c_compare ::= c_compare_chained
  318. genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter
  319. _come_froms JUMP_LOOP _come_froms
  320. load_genexpr ::= LOAD_GENEXPR
  321. load_genexpr ::= BUILD_TUPLE_1 LOAD_GENEXPR LOAD_STR
  322. subscript ::= expr expr BINARY_SUBSCR
  323. subscript2 ::= expr expr DUP_TOP_TWO BINARY_SUBSCR
  324. # unary_op (formerly "unary_expr") is the Python AST UnaryOp
  325. unary_op ::= expr unary_operator
  326. unary_operator ::= UNARY_POSITIVE
  327. unary_operator ::= UNARY_NEGATIVE
  328. unary_operator ::= UNARY_INVERT
  329. unary_not ::= expr UNARY_NOT
  330. yield ::= expr YIELD_VALUE
  331. """
  332. def p_comprehension_list(self, args):
  333. """
  334. lc_body ::= expr LIST_APPEND
  335. list_comp ::= BUILD_LIST_0 list_iter
  336. list_iter ::= list_for
  337. list_iter ::= list_if
  338. list_iter ::= list_if_not
  339. list_iter ::= list_if_or_not
  340. list_iter ::= lc_body
  341. set_iter ::= set_for
  342. set_iter ::= list_if
  343. # set_iter ::= list_if_and_or
  344. # set_iter ::= list_if_chained
  345. set_iter ::= list_if_not
  346. set_iter ::= set_comp_body
  347. list_for ::= expr_or_arg
  348. for_iter
  349. store list_iter
  350. jb_or_c _come_froms
  351. set_for ::= expr_or_arg
  352. for_iter
  353. store set_iter
  354. jb_or_c _come_froms
  355. list_if_not_end ::= pjump_ift _come_froms
  356. list_if_not ::= expr list_if_not_end list_iter come_from_opt
  357. list_if ::= expr pjump_iff list_iter come_from_opt
  358. list_if ::= expr jump_if_false_cf list_iter
  359. list_if_or_not ::= expr_pjit expr_pjit COME_FROM list_iter
  360. list_if_end ::= pjump_iff _come_froms
  361. list_if ::= expr list_if_end list_iter come_from_opt
  362. jb_or_c ::= JUMP_LOOP
  363. jb_or_c ::= CONTINUE
  364. """
  365. def p_37conditionals(self, args):
  366. """
  367. expr ::= if_exp_compare
  368. bool_op ::= and_cond
  369. bool_op ::= and_not_cond
  370. bool_op ::= and POP_JUMP_IF_TRUE expr
  371. expr_pjif ::= expr POP_JUMP_IF_FALSE
  372. expr_pjit ::= expr POP_JUMP_IF_TRUE
  373. expr_pjitt ::= expr pjump_ift
  374. expr_jifop ::= expr JUMP_IF_FALSE_OR_POP
  375. expr_jitop ::= expr JUMP_IF_TRUE_OR_POP
  376. expr_pjiff ::= expr pjump_iff
  377. expr_pjift ::= expr pjump_ift
  378. if_exp ::= expr_pjif expr jump_forward_else expr come_froms
  379. if_exp_compare ::= expr expr jf_cfs expr COME_FROM
  380. if_exp_compare ::= bool_op expr jf_cfs expr COME_FROM
  381. if_exp_loop ::= expr_pjif
  382. expr
  383. POP_JUMP_IF_FALSE_LOOP
  384. JUMP_FORWARD
  385. come_froms
  386. expr
  387. jf_cfs ::= JUMP_FORWARD _come_froms
  388. list_iter ::= list_if37
  389. list_iter ::= list_if37_not
  390. list_if37 ::= c_compare_chained37_false list_iter
  391. list_if37_not ::= compare_chained37 list_iter
  392. # A reduction check distinguishes between "and" and "and_not"
  393. # based on whether the POP_IF_JUMP location matches the location of the
  394. # POP_JUMP_IF_FALSE.
  395. and_not ::= expr_pjif expr_pjit
  396. or_and_not ::= expr_pjit and_not COME_FROM
  397. not_and_not ::= not expr_pjif COME_FROM
  398. expr ::= if_exp_37a
  399. expr ::= if_exp_37b
  400. if_exp_37a ::= and_not expr JUMP_FORWARD come_froms expr COME_FROM
  401. if_exp_37b ::= expr_pjif expr_pjif jump_forward_else expr
  402. """
  403. def p_comprehension(self, args):
  404. """
  405. # Python3 scanner adds LOAD_LISTCOMP. Python3 does list comprehension like
  406. # other comprehensions (set, dictionary).
  407. comp_body ::= dict_comp_body
  408. comp_body ::= gen_comp_body
  409. # FIXME: decompile-cfg has this. We are missing a LHS rule?
  410. # comp_body ::= list_comp_body
  411. comp_body ::= set_comp_body
  412. # Our "continue" heuristic - in two successive JUMP_LOOPS, the first
  413. # one may be a continue - sometimes classifies a JUMP_LOOP
  414. # as a CONTINUE. The two are kind of the same in a comprehension.
  415. comp_for ::= expr get_for_iter store comp_iter
  416. CONTINUE
  417. _come_froms
  418. comp_for ::= expr get_for_iter store comp_iter
  419. JUMP_LOOP
  420. _come_froms
  421. get_for_iter ::= GET_ITER _come_froms FOR_ITER
  422. dict_comp_body ::= expr expr MAP_ADD
  423. set_comp_body ::= expr SET_ADD
  424. # See also common Python p_list_comprehension
  425. comp_if ::= expr_pjif comp_iter
  426. comp_if ::= expr_pjiff comp_iter
  427. comp_if ::= c_compare comp_iter
  428. comp_if ::= or_jump_if_false_cf comp_iter
  429. comp_if ::= or_jump_if_false_loop_cf comp_iter
  430. # We need to have a reduction rule to disambiguate
  431. # these "comp_if_not" and "comp_if". The difference is buried in the
  432. # sense of the jump in
  433. # comp_iter -> comp_if_or -> or_parts_false_loop
  434. # vs.:
  435. # comp_iter -> comp_if_or -> or_parts_true_loop
  436. #
  437. # If "true_loop then that goes with "comp_if_not"
  438. # if "false_loop" then that goes with comp_if"
  439. #
  440. # We might be able to do this in the grammar but it is a bit
  441. # too pervasive and involved.
  442. # We have a bunch of these comp_if_<logic expression>
  443. # because the logic operation bleeds into the
  444. # "if" of the comprehension. Note thet specific position of
  445. # POP_JUMP_IF_xxx_LOOP stays the same.
  446. comp_if_or ::= or_parts
  447. expr POP_JUMP_IF_FALSE_LOOP
  448. come_froms
  449. comp_iter
  450. # comp_if_or ::= or_parts_true_loop
  451. # expr POP_JUMP_IF_FALSE_LOOP
  452. # come_froms
  453. # comp_iter
  454. # comp_if_or ::= or_parts_false_loop
  455. # expr POP_JUMP_IF_FALSE_LOOP
  456. # come_froms
  457. # comp_iter
  458. # Here, the "or" is melded a little into the "comp_if" test
  459. comp_if_or2 ::= compare compare_chained37_false comp_iter
  460. comp_if_or_not ::= or_parts
  461. expr POP_JUMP_IF_TRUE_LOOP
  462. come_froms
  463. comp_iter
  464. ## FIXME: we add this, per comment above later.
  465. ## comp_if ::= expr pjump_ift comp_iter
  466. comp_if_not ::= expr pjump_ift comp_iter
  467. comp_if_not_and ::= expr_pjif
  468. expr POP_JUMP_IF_TRUE_LOOP
  469. come_froms
  470. comp_iter
  471. comp_if_not_or ::= expr_pjif
  472. expr POP_JUMP_IF_FALSE_LOOP
  473. come_from_opt
  474. comp_iter
  475. comp_iter ::= dict_comp_body
  476. comp_iter ::= comp_body
  477. comp_iter ::= comp_if
  478. comp_iter ::= comp_if_not
  479. comp_iter ::= comp_if_not_and
  480. comp_iter ::= comp_if_not_or
  481. comp_iter ::= comp_if_or
  482. comp_iter ::= comp_if_or_not
  483. comp_iter ::= comp_if_or2
  484. or_jump_if_false_cf ::= or POP_JUMP_IF_FALSE COME_FROM
  485. or_jump_if_false_loop_cf ::= or_loop POP_JUMP_IF_FALSE_LOOP COME_FROM
  486. or_loop ::= or
  487. or_loop ::= or_parts_loop expr
  488. or_parts_loop ::= expr_pjift+
  489. # Semantic rules require "comp_if" to have index 0 be some
  490. # sort of "expr" and index 1 to be some sort of "comp_iter"
  491. c_compare ::= compare
  492. expr_or_arg ::= LOAD_ARG
  493. expr_or_arg ::= expr
  494. ending_return ::= RETURN_VALUE RETURN_LAST
  495. ending_return ::= RETURN_VALUE_LAMBDA LAMBDA_MARKER
  496. for_iter ::= _come_froms FOR_ITER
  497. dict_comp_func ::= BUILD_MAP_0 LOAD_ARG for_iter store
  498. comp_iter JUMP_LOOP _come_froms
  499. ending_return
  500. set_comp_func ::= BUILD_SET_0
  501. expr_or_arg
  502. for_iter store comp_iter
  503. JUMP_LOOP
  504. _come_froms
  505. ending_return
  506. set_comp_func ::= BUILD_SET_0
  507. expr_or_arg
  508. for_iter store comp_iter
  509. COME_FROM
  510. JUMP_LOOP
  511. _come_froms
  512. ending_return
  513. await_expr ::= expr GET_AWAITABLE LOAD_CONST YIELD_FROM
  514. set_comp_func ::= BUILD_SET_0
  515. expr_or_arg
  516. for_iter store await_expr
  517. SET_ADD
  518. JUMP_LOOP
  519. _come_froms
  520. ending_return
  521. """
  522. def p_expr3(self, args):
  523. """
  524. expr ::= if_exp_not
  525. if_exp_not ::= expr POP_JUMP_IF_TRUE expr jump_forward_else expr COME_FROM
  526. # a JUMP_FORWARD to another JUMP_FORWARD can get turned into
  527. # a JUMP_ABSOLUTE with no COME_FROM
  528. if_exp ::= expr_pjif expr jump_forward_else expr
  529. # if_exp_true are are IfExp which always evaluate true, e.g.:
  530. # x = a if 1 else b
  531. # There is dead or non-optional remnants of the condition code though,
  532. # and we use that to match on to reconstruct the source more accurately
  533. expr ::= if_exp_true
  534. if_exp_true ::= expr JUMP_FORWARD expr COME_FROM
  535. """
  536. def p_set_comp(self, args):
  537. """
  538. comp_iter ::= comp_for
  539. gen_comp_body ::= expr YIELD_VALUE POP_TOP
  540. set_comp ::= BUILD_SET_0 set_iter
  541. """
  542. def p_store(self, args):
  543. """
  544. # Note. The below is right-recursive:
  545. designList ::= store store
  546. designList ::= store DUP_TOP designList
  547. ## Can we replace with left-recursive, and redo with:
  548. ##
  549. ## designList ::= designLists store store
  550. ## designLists ::= designLists store DUP_TOP
  551. ## designLists ::=
  552. ## Will need to redo semantic actiion
  553. store ::= STORE_FAST
  554. store ::= STORE_NAME
  555. store ::= STORE_GLOBAL
  556. store ::= STORE_DEREF
  557. store ::= expr STORE_ATTR
  558. store ::= store_subscript
  559. store_subscript ::= expr expr STORE_SUBSCR
  560. """
  561. if __name__ == "__main__":
  562. # Check grammar
  563. from decompyle3.parsers.dump import dump_and_check
  564. p = Python37LambdaParser()
  565. modified_tokens = set(
  566. """JUMP_LOOP CONTINUE RETURN_END_IF_LAMBDA COME_FROM
  567. LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
  568. LAMBDA_MARKER RETURN_VALUE_LAMBDA
  569. """.split()
  570. )
  571. dump_and_check(p, (3, 7), modified_tokens)