parse30.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. # Copyright (c) 2016-2017, 2022-2024 Rocky Bernstein
  2. """
  3. spark grammar differences over Python 3.1 for Python 3.0.
  4. """
  5. from __future__ import print_function
  6. from uncompyle6.parser import PythonParserSingle
  7. from uncompyle6.parsers.parse31 import Python31Parser
  8. class Python30Parser(Python31Parser):
  9. def p_30(self, args):
  10. """
  11. pt_bp ::= POP_TOP POP_BLOCK
  12. assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
  13. COME_FROM POP_TOP
  14. assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1
  15. RAISE_VARARGS_1 come_froms
  16. call_stmt ::= expr _come_froms POP_TOP
  17. return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM POP_TOP
  18. compare_chained_right ::= expr COMPARE_OP RETURN_END_IF_LAMBDA
  19. # FIXME: combine with parse3.2
  20. whileTruestmt ::= SETUP_LOOP l_stmts_opt
  21. jb_or_c COME_FROM_LOOP
  22. whileTruestmt ::= SETUP_LOOP returns
  23. COME_FROM_LOOP
  24. # In many ways Python 3.0 code generation is more like Python 2.6 than
  25. # it is 2.7 or 3.1. So we have a number of 2.6ish (and before) rules below
  26. # Specifically POP_TOP is more prevalant since there is no POP_JUMP_IF_...
  27. # instructions.
  28. _ifstmts_jump ::= c_stmts JUMP_FORWARD _come_froms POP_TOP COME_FROM
  29. _ifstmts_jump ::= c_stmts COME_FROM POP_TOP
  30. # Used to keep index order the same in semantic actions
  31. jb_pop_top ::= JUMP_BACK _come_froms POP_TOP
  32. while1stmt ::= SETUP_LOOP l_stmts COME_FROM_LOOP
  33. whileelsestmt ::= SETUP_LOOP testexpr l_stmts
  34. jb_pop_top POP_BLOCK
  35. else_suitel COME_FROM_LOOP
  36. # while1elsestmt ::= SETUP_LOOP l_stmts
  37. # jb_pop_top POP_BLOCK
  38. # else_suitel COME_FROM_LOOP
  39. else_suitel ::= l_stmts COME_FROM_LOOP JUMP_BACK
  40. jump_absolute_else ::= COME_FROM JUMP_ABSOLUTE COME_FROM POP_TOP
  41. jump_cf_pop ::= _come_froms _jump _come_froms POP_TOP
  42. ifelsestmt ::= testexpr c_stmts_opt jump_cf_pop else_suite COME_FROM
  43. ifelsestmtl ::= testexpr c_stmts_opt jump_cf_pop else_suitel
  44. ifelsestmtc ::= testexpr c_stmts_opt jump_absolute_else else_suitec
  45. ifelsestmtc ::= testexpr c_stmts_opt jump_cf_pop else_suitec
  46. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE COME_FROM
  47. iflaststmtl ::= testexpr c_stmts_opt jb_pop_top
  48. iflaststmtl ::= testexpr c_stmts_opt come_froms JUMP_BACK COME_FROM POP_TOP
  49. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE COME_FROM POP_TOP
  50. with_as ::= expr setupwithas store suite_stmts_opt
  51. POP_BLOCK LOAD_CONST COME_FROM_FINALLY
  52. LOAD_FAST DELETE_FAST WITH_CLEANUP END_FINALLY
  53. setupwithas ::= DUP_TOP LOAD_ATTR STORE_FAST LOAD_ATTR CALL_FUNCTION_0 setup_finally
  54. setup_finally ::= STORE_FAST SETUP_FINALLY LOAD_FAST DELETE_FAST
  55. # Need to keep LOAD_FAST as index 1
  56. set_comp_header ::= BUILD_SET_0 DUP_TOP STORE_FAST
  57. set_comp_func ::= set_comp_header
  58. LOAD_ARG FOR_ITER store comp_iter
  59. JUMP_BACK ending_return
  60. list_comp_header ::= BUILD_LIST_0 DUP_TOP STORE_FAST
  61. list_comp ::= list_comp_header
  62. LOAD_FAST FOR_ITER store comp_iter
  63. JUMP_BACK
  64. list_comp ::= list_comp_header
  65. LOAD_FAST FOR_ITER store comp_iter
  66. JUMP_BACK _come_froms POP_TOP JUMP_BACK
  67. list_for ::= DUP_TOP STORE_FAST
  68. expr_or_arg
  69. FOR_ITER
  70. store list_iter jb_or_c
  71. set_comp ::= set_comp_header
  72. LOAD_FAST FOR_ITER store comp_iter
  73. JUMP_BACK
  74. dict_comp_header ::= BUILD_MAP_0 DUP_TOP STORE_FAST
  75. dict_comp ::= dict_comp_header
  76. LOAD_FAST FOR_ITER store dict_comp_iter
  77. JUMP_BACK
  78. dict_comp ::= dict_comp_header
  79. LOAD_FAST FOR_ITER store dict_comp_iter
  80. JUMP_BACK _come_froms POP_TOP JUMP_BACK
  81. dict_comp_func ::= BUILD_MAP_0
  82. DUP_TOP STORE_FAST
  83. LOAD_ARG FOR_ITER store
  84. dict_comp_iter JUMP_BACK ending_return
  85. stmt ::= try_except30
  86. try_except30 ::= SETUP_EXCEPT suite_stmts_opt
  87. _come_froms pt_bp
  88. except_handler opt_come_from_except
  89. # From Python 2.6
  90. lc_body ::= LOAD_FAST expr LIST_APPEND
  91. lc_body ::= LOAD_NAME expr LIST_APPEND
  92. list_if ::= expr jmp_false_then list_iter
  93. list_if_not ::= expr jmp_true list_iter JUMP_BACK come_froms POP_TOP
  94. list_iter ::= list_if JUMP_BACK
  95. list_iter ::= list_if JUMP_BACK _come_froms POP_TOP
  96. #############
  97. dict_comp_iter ::= expr expr ROT_TWO expr STORE_SUBSCR
  98. # JUMP_IF_TRUE POP_TOP as a replacement
  99. comp_if ::= expr jmp_false comp_iter
  100. comp_if ::= expr jmp_false comp_iter JUMP_BACK COME_FROM POP_TOP
  101. comp_if_not ::= expr jmp_true comp_iter JUMP_BACK COME_FROM POP_TOP
  102. comp_iter ::= expr expr SET_ADD
  103. comp_iter ::= expr expr LIST_APPEND
  104. jump_forward_else ::= JUMP_FORWARD COME_FROM POP_TOP
  105. jump_absolute_else ::= JUMP_ABSOLUTE COME_FROM POP_TOP
  106. except_suite ::= c_stmts POP_EXCEPT jump_except POP_TOP
  107. except_suite_finalize ::= SETUP_FINALLY c_stmts_opt except_var_finalize END_FINALLY
  108. _jump COME_FROM POP_TOP
  109. except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts END_FINALLY
  110. _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP
  111. _ifstmts_jump ::= c_stmts_opt come_froms POP_TOP JUMP_FORWARD _come_froms
  112. jump_except ::= _jump COME_FROM POP_TOP
  113. expr_jt ::= expr jmp_true
  114. or ::= expr jmp_false expr jmp_true expr
  115. or ::= expr_jt expr
  116. import_from ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist _come_froms POP_TOP
  117. ################################################################################
  118. # In many ways 3.0 is like 2.6. One similarity is there is no JUMP_IF_TRUE and
  119. # JUMP_IF_FALSE
  120. # The below rules in fact are the same or similar.
  121. jmp_true ::= JUMP_IF_TRUE POP_TOP
  122. jmp_true_then ::= JUMP_IF_TRUE _come_froms POP_TOP
  123. jmp_false ::= JUMP_IF_FALSE _come_froms POP_TOP
  124. jmp_false_then ::= JUMP_IF_FALSE POP_TOP
  125. # We don't have hacky THEN detection, so we do it
  126. # in the grammar below which is also somewhat hacky.
  127. stmt ::= ifstmt30
  128. stmt ::= ifnotstmt30
  129. ifstmt30 ::= testfalse_then _ifstmts_jump30
  130. ifnotstmt30 ::= testtrue_then _ifstmts_jump30
  131. testfalse_then ::= expr jmp_false_then
  132. testtrue_then ::= expr jmp_true_then
  133. call_stmt ::= expr COME_FROM
  134. _ifstmts_jump30 ::= c_stmts POP_TOP
  135. gen_comp_body ::= expr YIELD_VALUE COME_FROM POP_TOP
  136. except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
  137. COME_FROM POP_TOP END_FINALLY
  138. or ::= expr jmp_true_then expr come_from_opt
  139. ret_or ::= expr jmp_true_then expr come_from_opt
  140. ret_and ::= expr jump_false expr come_from_opt
  141. ################################################################################
  142. for_block ::= l_stmts_opt _come_froms POP_TOP JUMP_BACK
  143. except_handler ::= JUMP_FORWARD COME_FROM_EXCEPT except_stmts
  144. POP_TOP END_FINALLY come_froms
  145. except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
  146. POP_TOP END_FINALLY
  147. return_if_stmt ::= return_expr RETURN_END_IF come_froms POP_TOP
  148. return_if_stmt ::= return_expr RETURN_VALUE come_froms POP_TOP
  149. and ::= expr jmp_false_then expr come_from_opt
  150. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt come_from_opt
  151. JUMP_BACK _come_froms POP_TOP POP_BLOCK COME_FROM_LOOP
  152. whilestmt ::= SETUP_LOOP testexpr returns
  153. POP_TOP POP_BLOCK COME_FROM_LOOP
  154. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt come_from_opt
  155. come_froms POP_TOP POP_BLOCK COME_FROM_LOOP
  156. # A "compare_chained" is two comparisons like x <= y <= z
  157. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  158. jmp_false compared_chained_middle _come_froms
  159. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  160. jmp_false compare_chained_right _come_froms
  161. compare_chained_right ::= expr COMPARE_OP RETURN_END_IF
  162. """
  163. def remove_rules_30(self):
  164. self.remove_rules(
  165. """
  166. # The were found using grammar coverage
  167. while1stmt ::= SETUP_LOOP l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
  168. whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM_LOOP
  169. whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
  170. else_suitel COME_FROM_LOOP
  171. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
  172. COME_FROM_LOOP
  173. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK JUMP_BACK
  174. COME_FROM_LOOP
  175. whilestmt ::= SETUP_LOOP testexpr returns POP_TOP POP_BLOCK COME_FROM_LOOP
  176. with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST
  177. COME_FROM_WITH WITH_CLEANUP END_FINALLY
  178. with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
  179. COME_FROM_WITH WITH_CLEANUP END_FINALLY
  180. # lc_body ::= LOAD_FAST expr LIST_APPEND
  181. # lc_body ::= LOAD_NAME expr LIST_APPEND
  182. # lc_body ::= expr LIST_APPEND
  183. # list_comp ::= BUILD_LIST_0 list_iter
  184. list_for ::= expr FOR_ITER store list_iter jb_or_c
  185. # list_if ::= expr jmp_false list_iter
  186. # list_if ::= expr jmp_false_then list_iter
  187. # list_if_not ::= expr jmp_true list_iter
  188. # list_iter ::= list_if JUMP_BACK
  189. # list_iter ::= list_if JUMP_BACK _come_froms POP_TOP
  190. # list_iter ::= list_if_not
  191. # load_closure ::= BUILD_TUPLE_0
  192. # load_genexpr ::= BUILD_TUPLE_1 LOAD_GENEXPR LOAD_STR
  193. ##########################################################################################
  194. iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK COME_FROM_LOOP
  195. ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel
  196. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
  197. _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_froms
  198. jump_forward_else ::= JUMP_FORWARD ELSE
  199. jump_absolute_else ::= JUMP_ABSOLUTE ELSE
  200. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt COME_FROM JUMP_BACK POP_BLOCK
  201. COME_FROM_LOOP
  202. whilestmt ::= SETUP_LOOP testexpr returns
  203. POP_BLOCK COME_FROM_LOOP
  204. assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
  205. return_if_lambda ::= RETURN_END_IF_LAMBDA
  206. except_suite ::= c_stmts POP_EXCEPT jump_except
  207. whileelsestmt ::= SETUP_LOOP testexpr l_stmts JUMP_BACK POP_BLOCK
  208. else_suitel COME_FROM_LOOP
  209. ################################################################
  210. # No JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP,
  211. # POP_JUMP_IF_FALSE, or POP_JUMP_IF_TRUE
  212. jmp_false ::= POP_JUMP_IF_FALSE
  213. jmp_true ::= JUMP_IF_TRUE_OR_POP POP_TOP
  214. jmp_true ::= POP_JUMP_IF_TRUE
  215. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  216. JUMP_IF_FALSE_OR_POP compared_chained_middle
  217. COME_FROM
  218. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  219. JUMP_IF_FALSE_OR_POP compare_chained_right COME_FROM
  220. ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
  221. ret_and ::= expr JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
  222. if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF
  223. COME_FROM return_expr_or_cond
  224. return_expr_or_cond ::= if_exp_ret
  225. or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
  226. and ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
  227. and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
  228. """
  229. )
  230. def customize_grammar_rules(self, tokens, customize):
  231. super(Python30Parser, self).customize_grammar_rules(tokens, customize)
  232. self.remove_rules_30()
  233. self.check_reduce["iflaststmtl"] = "AST"
  234. self.check_reduce["ifstmt"] = "AST"
  235. self.check_reduce["ifelsestmtc"] = "AST"
  236. self.check_reduce["ifelsestmt"] = "AST"
  237. # self.check_reduce["and"] = "stmt"
  238. return
  239. def reduce_is_invalid(self, rule, ast, tokens, first, last):
  240. invalid = super(Python30Parser, self).reduce_is_invalid(
  241. rule, ast, tokens, first, last
  242. )
  243. if invalid:
  244. return invalid
  245. lhs = rule[0]
  246. if (
  247. lhs in ("iflaststmtl", "ifstmt", "ifelsestmt", "ifelsestmtc")
  248. and ast[0] == "testexpr"
  249. ):
  250. testexpr = ast[0]
  251. if testexpr[0] == "testfalse":
  252. testfalse = testexpr[0]
  253. if lhs == "ifelsestmtc" and ast[2] == "jump_absolute_else":
  254. jump_absolute_else = ast[2]
  255. come_from = jump_absolute_else[2]
  256. return (
  257. come_from == "COME_FROM"
  258. and come_from.attr < tokens[first].offset
  259. )
  260. pass
  261. elif lhs in ("ifelsestmt", "ifelsestmtc") and ast[2] == "jump_cf_pop":
  262. jump_cf_pop = ast[2]
  263. come_froms = jump_cf_pop[0]
  264. for come_from in come_froms:
  265. if come_from.attr < tokens[first].offset:
  266. return True
  267. come_froms = jump_cf_pop[2]
  268. if come_froms == "COME_FROM":
  269. if come_froms.attr < tokens[first].offset:
  270. return True
  271. pass
  272. elif come_froms == "_come_froms":
  273. for come_from in come_froms:
  274. if come_from.attr < tokens[first].offset:
  275. return True
  276. return False
  277. elif testfalse[1] == "jmp_false":
  278. jmp_false = testfalse[1]
  279. if last == len(tokens):
  280. last -= 1
  281. while isinstance(tokens[first].offset, str) and first < last:
  282. first += 1
  283. if first == last:
  284. return True
  285. while first < last and isinstance(tokens[last].offset, str):
  286. last -= 1
  287. if rule[0] == "iflaststmtl":
  288. return not (jmp_false[0].attr <= tokens[last].offset)
  289. else:
  290. jmp_false_target = jmp_false[0].attr
  291. if tokens[first].offset > jmp_false_target:
  292. return True
  293. return (jmp_false_target > tokens[last].offset) and tokens[
  294. last
  295. ] != "JUMP_FORWARD"
  296. pass
  297. pass
  298. pass
  299. # elif lhs == "and":
  300. # return tokens[last+1] == "JUMP_FORWARD"
  301. pass
  302. class Python30ParserSingle(Python30Parser, PythonParserSingle):
  303. pass
  304. if __name__ == "__main__":
  305. # Check grammar
  306. p = Python30Parser()
  307. p.remove_rules_30()
  308. p.check_grammar()
  309. from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
  310. if PYTHON_VERSION_TRIPLE[:2] == (3, 0):
  311. lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets()
  312. from uncompyle6.scanner import get_scanner
  313. s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
  314. opcode_set = set(s.opc.opname).union(
  315. set(
  316. """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
  317. LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
  318. LAMBDA_MARKER RETURN_LAST
  319. """.split()
  320. )
  321. )
  322. ## FIXME: try this
  323. remain_tokens = set(tokens) - opcode_set
  324. import re
  325. remain_tokens = set([re.sub(r"_\d+$", "", t) for t in remain_tokens])
  326. remain_tokens = set([re.sub("_CONT$", "", t) for t in remain_tokens])
  327. remain_tokens = set(remain_tokens) - opcode_set
  328. print(remain_tokens)
  329. import sys
  330. if len(sys.argv) > 1:
  331. from spark_parser.spark import rule2str
  332. for rule in sorted(p.rule2name.items()):
  333. print(rule2str(rule[0]))