parse38.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. # Copyright (c) 2017-2020, 2022-2024 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. spark grammar differences over Python 3.7 for Python 3.8
  17. """
  18. from __future__ import print_function
  19. from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
  20. from uncompyle6.parser import PythonParserSingle, nop_func
  21. from uncompyle6.parsers.parse37 import Python37Parser
  22. from uncompyle6.parsers.reducecheck.pop_return import pop_return_check
  23. class Python38Parser(Python37Parser):
  24. def p_38_stmt(self, args):
  25. """
  26. stmt ::= async_for_stmt38
  27. stmt ::= async_forelse_stmt38
  28. stmt ::= call_stmt
  29. stmt ::= continue
  30. stmt ::= for38
  31. stmt ::= forelselaststmt38
  32. stmt ::= forelselaststmtl38
  33. stmt ::= forelsestmt38
  34. stmt ::= try_elsestmtl38
  35. stmt ::= try_except38
  36. stmt ::= try_except38r
  37. stmt ::= try_except38r2
  38. stmt ::= try_except38r3
  39. stmt ::= try_except38r4
  40. stmt ::= try_except_as
  41. stmt ::= try_except_ret38
  42. stmt ::= tryfinally38astmt
  43. stmt ::= tryfinally38rstmt
  44. stmt ::= tryfinally38rstmt2
  45. stmt ::= tryfinally38rstmt3
  46. stmt ::= tryfinally38stmt
  47. stmt ::= whileTruestmt38
  48. stmt ::= whilestmt38
  49. call_stmt ::= call
  50. break ::= POP_BLOCK BREAK_LOOP
  51. break ::= POP_BLOCK POP_TOP BREAK_LOOP
  52. break ::= POP_TOP BREAK_LOOP
  53. break ::= POP_EXCEPT BREAK_LOOP
  54. # The "continue" rule is a weird one. In 3.8, CONTINUE_LOOP was removed.
  55. # Inside an loop we can have this, which can only appear in side a try/except
  56. # And it can also appear at the end of the try except.
  57. continue ::= POP_EXCEPT JUMP_BACK
  58. # FIXME: this should be restricted to being inside a try block
  59. stmt ::= except_ret38
  60. stmt ::= except_ret38a
  61. # FIXME: this should be added only when seeing GET_AITER or YIELD_FROM
  62. async_for ::= GET_AITER _come_froms
  63. SETUP_FINALLY GET_ANEXT LOAD_CONST YIELD_FROM POP_BLOCK
  64. async_for_stmt38 ::= expr async_for
  65. store for_block
  66. COME_FROM_FINALLY
  67. END_ASYNC_FOR
  68. genexpr_func_async ::= LOAD_ARG func_async_prefix
  69. store comp_iter
  70. JUMP_BACK COME_FROM_FINALLY
  71. END_ASYNC_FOR
  72. # FIXME: "come_froms" after the "else_suite" or END_ASYNC_FOR distinguish which of
  73. # for / forelse is used. Add "come_froms" and check of add up control-flow detection phase.
  74. async_forelse_stmt38 ::= expr
  75. GET_AITER
  76. SETUP_FINALLY
  77. GET_ANEXT
  78. LOAD_CONST
  79. YIELD_FROM
  80. POP_BLOCK
  81. store for_block
  82. COME_FROM_FINALLY
  83. END_ASYNC_FOR
  84. else_suite
  85. # Seems to be used to discard values before a return in a "for" loop
  86. discard_top ::= ROT_TWO POP_TOP
  87. discard_tops ::= discard_top+
  88. return ::= return_expr
  89. discard_tops RETURN_VALUE
  90. return ::= popb_return
  91. return ::= pop_return
  92. return ::= pop_ex_return
  93. except_stmt ::= pop_ex_return
  94. pop_return ::= POP_TOP return_expr RETURN_VALUE
  95. popb_return ::= return_expr POP_BLOCK RETURN_VALUE
  96. pop_ex_return ::= return_expr ROT_FOUR POP_EXCEPT RETURN_VALUE
  97. # 3.8 can push a looping JUMP_BACK into into a JUMP_ from a statement that jumps to it
  98. lastl_stmt ::= ifpoplaststmtl
  99. ifpoplaststmtl ::= testexpr POP_TOP c_stmts_opt
  100. ifelsestmtl ::= testexpr c_stmts_opt jb_cfs else_suitel JUMP_BACK come_froms
  101. # Keep indices the same in ifelsestmtl
  102. cf_pt ::= COME_FROM POP_TOP
  103. ifelsestmtl ::= testexpr c_stmts cf_pt else_suite
  104. for38 ::= expr get_iter store for_block JUMP_BACK
  105. for38 ::= expr get_for_iter store for_block JUMP_BACK
  106. for38 ::= expr get_for_iter store for_block JUMP_BACK POP_BLOCK
  107. for38 ::= expr get_for_iter store for_block
  108. forelsestmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suite
  109. forelsestmt38 ::= expr get_for_iter store for_block JUMP_BACK _come_froms
  110. else_suite
  111. forelselaststmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suitec
  112. forelselaststmtl38 ::= expr get_for_iter store for_block POP_BLOCK else_suitel
  113. returns_in_except ::= _stmts except_return_value
  114. except_return_value ::= POP_BLOCK return
  115. except_return_value ::= expr POP_BLOCK RETURN_VALUE
  116. whilestmt38 ::= _come_froms testexpr l_stmts_opt COME_FROM JUMP_BACK
  117. POP_BLOCK
  118. whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK POP_BLOCK
  119. whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK come_froms
  120. whilestmt38 ::= _come_froms testexpr returns POP_BLOCK
  121. whilestmt38 ::= _come_froms testexpr l_stmts JUMP_BACK
  122. whilestmt38 ::= _come_froms testexpr l_stmts come_froms
  123. # while1elsestmt ::= l_stmts JUMP_BACK
  124. whileTruestmt ::= _come_froms l_stmts JUMP_BACK POP_BLOCK
  125. while1stmt ::= _come_froms l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
  126. whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK
  127. whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK COME_FROM_EXCEPT_CLAUSE
  128. whileTruestmt38 ::= _come_froms pass JUMP_BACK
  129. for_block ::= _come_froms l_stmts_opt _come_from_loops JUMP_BACK
  130. except_cond1 ::= DUP_TOP expr COMPARE_OP jmp_false
  131. POP_TOP POP_TOP POP_TOP
  132. POP_EXCEPT
  133. except_cond_as ::= DUP_TOP expr COMPARE_OP POP_JUMP_IF_FALSE
  134. POP_TOP STORE_FAST POP_TOP
  135. try_elsestmtl38 ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  136. except_handler38 COME_FROM
  137. else_suitel opt_come_from_except
  138. try_except ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  139. except_handler38
  140. try_except38 ::= SETUP_FINALLY POP_BLOCK POP_TOP suite_stmts_opt
  141. except_handler38a
  142. # suite_stmts has a return
  143. try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
  144. except_handler38b
  145. try_except38r ::= SETUP_FINALLY return_except
  146. except_handler38b
  147. return_except ::= stmts POP_BLOCK return
  148. # In 3.8 there seems to be some sort of code fiddle with POP_EXCEPT when there
  149. # is a final return in the "except" block.
  150. # So we treat the "return" separate from the other statements
  151. cond_except_stmt ::= except_cond1 except_stmts
  152. cond_except_stmts_opt ::= cond_except_stmt*
  153. try_except38r2 ::= SETUP_FINALLY
  154. suite_stmts_opt
  155. POP_BLOCK JUMP_FORWARD
  156. COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
  157. cond_except_stmts_opt
  158. POP_EXCEPT return
  159. END_FINALLY
  160. COME_FROM
  161. try_except38r3 ::= SETUP_FINALLY
  162. suite_stmts_opt
  163. POP_BLOCK JUMP_FORWARD
  164. COME_FROM_FINALLY
  165. cond_except_stmts_opt
  166. POP_EXCEPT return
  167. COME_FROM
  168. END_FINALLY
  169. COME_FROM
  170. try_except38r4 ::= SETUP_FINALLY
  171. returns_in_except
  172. COME_FROM_FINALLY
  173. except_cond1
  174. return
  175. COME_FROM
  176. END_FINALLY
  177. # suite_stmts has a return
  178. try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
  179. except_handler38b
  180. try_except_as ::= SETUP_FINALLY POP_BLOCK suite_stmts
  181. except_handler_as END_FINALLY COME_FROM
  182. try_except_as ::= SETUP_FINALLY suite_stmts
  183. except_handler_as END_FINALLY COME_FROM
  184. try_except_ret38 ::= SETUP_FINALLY returns except_ret38a
  185. try_except_ret38a ::= SETUP_FINALLY returns except_handler38c
  186. END_FINALLY come_from_opt
  187. # Note: there is a suite_stmts_opt which seems
  188. # to be bookkeeping which is not expressed in source code
  189. except_ret38 ::= SETUP_FINALLY expr ROT_FOUR POP_BLOCK POP_EXCEPT
  190. CALL_FINALLY RETURN_VALUE COME_FROM
  191. COME_FROM_FINALLY
  192. suite_stmts_opt END_FINALLY
  193. except_ret38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
  194. expr ROT_FOUR
  195. POP_EXCEPT RETURN_VALUE END_FINALLY
  196. except_handler38 ::= _jump COME_FROM_FINALLY
  197. except_stmts END_FINALLY opt_come_from_except
  198. except_handler38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
  199. POP_EXCEPT POP_TOP stmts END_FINALLY
  200. except_handler38c ::= COME_FROM_FINALLY except_cond1a except_stmts
  201. POP_EXCEPT JUMP_FORWARD COME_FROM
  202. except_handler_as ::= COME_FROM_FINALLY except_cond_as tryfinallystmt
  203. POP_EXCEPT JUMP_FORWARD COME_FROM
  204. tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  205. BEGIN_FINALLY COME_FROM_FINALLY suite_stmts_opt
  206. END_FINALLY
  207. lc_setup_finally ::= LOAD_CONST SETUP_FINALLY
  208. call_finally_pt ::= CALL_FINALLY POP_TOP
  209. cf_cf_finally ::= come_from_opt COME_FROM_FINALLY
  210. pop_finally_pt ::= POP_FINALLY POP_TOP
  211. ss_end_finally ::= suite_stmts END_FINALLY
  212. sf_pb_call_returns ::= SETUP_FINALLY POP_BLOCK CALL_FINALLY returns
  213. # FIXME: DRY rules below
  214. tryfinally38rstmt ::= sf_pb_call_returns
  215. cf_cf_finally
  216. ss_end_finally
  217. tryfinally38rstmt ::= sf_pb_call_returns
  218. cf_cf_finally END_FINALLY
  219. suite_stmts
  220. tryfinally38rstmt ::= sf_pb_call_returns
  221. cf_cf_finally POP_FINALLY
  222. ss_end_finally
  223. tryfinally38rstmt ::= sf_bp_call_returns
  224. COME_FROM_FINALLY POP_FINALLY
  225. ss_end_finally
  226. tryfinally38rstmt2 ::= lc_setup_finally POP_BLOCK call_finally_pt
  227. returns
  228. cf_cf_finally pop_finally_pt
  229. ss_end_finally POP_TOP
  230. tryfinally38rstmt3 ::= SETUP_FINALLY expr POP_BLOCK CALL_FINALLY RETURN_VALUE
  231. COME_FROM COME_FROM_FINALLY
  232. ss_end_finally
  233. tryfinally38stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  234. BEGIN_FINALLY COME_FROM_FINALLY
  235. POP_FINALLY suite_stmts_opt END_FINALLY
  236. tryfinally38astmt ::= LOAD_CONST SETUP_FINALLY suite_stmts_opt POP_BLOCK
  237. BEGIN_FINALLY COME_FROM_FINALLY
  238. POP_FINALLY POP_TOP suite_stmts_opt END_FINALLY POP_TOP
  239. """
  240. def p_38walrus(self, args):
  241. """
  242. # named_expr is also known as the "walrus op" :=
  243. expr ::= named_expr
  244. named_expr ::= expr DUP_TOP store
  245. """
  246. def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
  247. super(Python38Parser, self).__init__(debug_parser)
  248. self.customized = {}
  249. def remove_rules_38(self):
  250. self.remove_rules(
  251. """
  252. stmt ::= async_for_stmt37
  253. stmt ::= for
  254. stmt ::= forelsestmt
  255. stmt ::= try_except36
  256. stmt ::= async_forelse_stmt
  257. async_for_stmt ::= setup_loop expr
  258. GET_AITER
  259. SETUP_EXCEPT GET_ANEXT LOAD_CONST
  260. YIELD_FROM
  261. store
  262. POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT DUP_TOP
  263. LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  264. END_FINALLY COME_FROM
  265. for_block
  266. COME_FROM
  267. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
  268. COME_FROM_LOOP
  269. async_for_stmt37 ::= setup_loop expr
  270. GET_AITER
  271. SETUP_EXCEPT GET_ANEXT
  272. LOAD_CONST YIELD_FROM
  273. store
  274. POP_BLOCK JUMP_BACK COME_FROM_EXCEPT DUP_TOP
  275. LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  276. END_FINALLY for_block COME_FROM
  277. POP_TOP POP_TOP POP_TOP POP_EXCEPT
  278. POP_TOP POP_BLOCK
  279. COME_FROM_LOOP
  280. async_forelse_stmt ::= setup_loop expr
  281. GET_AITER
  282. SETUP_EXCEPT GET_ANEXT LOAD_CONST
  283. YIELD_FROM
  284. store
  285. POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT DUP_TOP
  286. LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  287. END_FINALLY COME_FROM
  288. for_block
  289. COME_FROM
  290. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
  291. else_suite COME_FROM_LOOP
  292. for ::= setup_loop expr get_for_iter store for_block POP_BLOCK
  293. for ::= setup_loop expr get_for_iter store for_block POP_BLOCK NOP
  294. for_block ::= l_stmts_opt COME_FROM_LOOP JUMP_BACK
  295. forelsestmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suite
  296. forelselaststmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitec
  297. forelselaststmtl ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitel
  298. tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  299. except_handler COME_FROM else_suitel
  300. opt_come_from_except
  301. try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  302. except_handler opt_come_from_except
  303. tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  304. LOAD_CONST COME_FROM_FINALLY suite_stmts_opt
  305. END_FINALLY
  306. tryfinally36 ::= SETUP_FINALLY returns
  307. COME_FROM_FINALLY suite_stmts_opt END_FINALLY
  308. tryfinally_return_stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
  309. LOAD_CONST COME_FROM_FINALLY
  310. """
  311. )
  312. def customize_reduce_checks_full38(self, tokens, customize):
  313. """
  314. Extra tests when a reduction is made in the full grammar.
  315. Reductions here are extended from those used in the lambda grammar
  316. """
  317. self.remove_rules_38()
  318. self.check_reduce["pop_return"] = "tokens"
  319. self.check_reduce["whileTruestmt38"] = "tokens"
  320. self.check_reduce["whilestmt38"] = "tokens"
  321. self.check_reduce["try_elsestmtl38"] = "AST"
  322. self.reduce_check_table["pop_return"] = pop_return_check
  323. def customize_grammar_rules(self, tokens, customize):
  324. super(Python37Parser, self).customize_grammar_rules(tokens, customize)
  325. self.customize_reduce_checks_full38(tokens, customize)
  326. # For a rough break out on the first word. This may
  327. # include instructions that don't need customization,
  328. # but we'll do a finer check after the rough breakout.
  329. customize_instruction_basenames = frozenset(
  330. (
  331. "BEFORE",
  332. "BUILD",
  333. "CALL",
  334. "DICT",
  335. "GET",
  336. "FORMAT",
  337. "LIST",
  338. "LOAD",
  339. "MAKE",
  340. "SETUP",
  341. "UNPACK",
  342. )
  343. )
  344. # Opcode names in the custom_ops_processed set have rules that get added
  345. # unconditionally and the rules are constant. So they need to be done
  346. # only once and if we see the opcode a second we don't have to consider
  347. # adding more rules.
  348. #
  349. custom_ops_processed = frozenset()
  350. # A set of instruction operation names that exist in the token stream.
  351. # We use this customize the grammar that we create.
  352. # 2.6-compatible set comprehensions
  353. self.seen_ops = frozenset([t.kind for t in tokens])
  354. self.seen_op_basenames = frozenset(
  355. [opname[: opname.rfind("_")] for opname in self.seen_ops]
  356. )
  357. custom_ops_processed = {"DICT_MERGE"}
  358. # Loop over instructions adding custom grammar rules based on
  359. # a specific instruction seen.
  360. if "PyPy" in customize:
  361. self.addRule(
  362. """
  363. stmt ::= assign3_pypy
  364. stmt ::= assign2_pypy
  365. assign3_pypy ::= expr expr expr store store store
  366. assign2_pypy ::= expr expr store store
  367. """,
  368. nop_func,
  369. )
  370. n = len(tokens)
  371. # Determine if we have an iteration CALL_FUNCTION_1.
  372. has_get_iter_call_function1 = False
  373. for i, token in enumerate(tokens):
  374. if token == "GET_ITER" and i < n - 2 and tokens[i + 1] == "CALL_FUNCTION_1":
  375. has_get_iter_call_function1 = True
  376. for i, token in enumerate(tokens):
  377. opname = token.kind
  378. # Do a quick breakout before testing potentially
  379. # each of the dozen or so instruction in if elif.
  380. if (
  381. opname[: opname.find("_")] not in customize_instruction_basenames
  382. or opname in custom_ops_processed
  383. ):
  384. continue
  385. opname_base = opname[: opname.rfind("_")]
  386. # Do a quick breakout before testing potentially
  387. # each of the dozen or so instruction in if elif.
  388. if (
  389. opname[: opname.find("_")] not in customize_instruction_basenames
  390. or opname in custom_ops_processed
  391. ):
  392. continue
  393. if opname_base in (
  394. "BUILD_LIST",
  395. "BUILD_SET",
  396. "BUILD_SET_UNPACK",
  397. "BUILD_TUPLE",
  398. "BUILD_TUPLE_UNPACK",
  399. ):
  400. v = token.attr
  401. is_LOAD_CLOSURE = False
  402. if opname_base == "BUILD_TUPLE":
  403. # If is part of a "load_closure", then it is not part of a
  404. # "list".
  405. is_LOAD_CLOSURE = True
  406. for j in range(v):
  407. if tokens[i - j - 1].kind != "LOAD_CLOSURE":
  408. is_LOAD_CLOSURE = False
  409. break
  410. if is_LOAD_CLOSURE:
  411. rule = "load_closure ::= %s%s" % (("LOAD_CLOSURE " * v), opname)
  412. self.add_unique_rule(rule, opname, token.attr, customize)
  413. elif opname_base == "BUILD_LIST":
  414. v = token.attr
  415. if v == 0:
  416. rule_str = """
  417. list ::= BUILD_LIST_0
  418. list_unpack ::= BUILD_LIST_0 expr LIST_EXTEND
  419. list ::= list_unpack
  420. """
  421. self.add_unique_doc_rules(rule_str, customize)
  422. elif opname == "BUILD_TUPLE_UNPACK_WITH_CALL":
  423. # FIXME: should this be parameterized by EX value?
  424. self.addRule(
  425. """expr ::= call_ex_kw3
  426. call_ex_kw3 ::= expr
  427. build_tuple_unpack_with_call
  428. expr
  429. CALL_FUNCTION_EX_KW
  430. """,
  431. nop_func,
  432. )
  433. if not is_LOAD_CLOSURE or v == 0:
  434. # We do this complicated test to speed up parsing of
  435. # pathelogically long literals, especially those over 1024.
  436. build_count = token.attr
  437. thousands = build_count // 1024
  438. thirty32s = (build_count // 32) % 32
  439. if thirty32s > 0:
  440. rule = "expr32 ::=%s" % (" expr" * 32)
  441. self.add_unique_rule(rule, opname_base, build_count, customize)
  442. pass
  443. if thousands > 0:
  444. self.add_unique_rule(
  445. "expr1024 ::=%s" % (" expr32" * 32),
  446. opname_base,
  447. build_count,
  448. customize,
  449. )
  450. pass
  451. collection = opname_base[opname_base.find("_") + 1 :].lower()
  452. rule = (
  453. ("%s ::= " % collection)
  454. + "expr1024 " * thousands
  455. + "expr32 " * thirty32s
  456. + "expr " * (build_count % 32)
  457. + opname
  458. )
  459. self.add_unique_rules(["expr ::= %s" % collection, rule], customize)
  460. continue
  461. continue
  462. elif opname == "BUILD_STRING_2":
  463. self.addRule(
  464. """
  465. expr ::= formatted_value_debug
  466. formatted_value_debug ::= LOAD_STR formatted_value2 BUILD_STRING_2
  467. formatted_value_debug ::= LOAD_STR formatted_value1 BUILD_STRING_2
  468. """,
  469. nop_func,
  470. )
  471. custom_ops_processed.add(opname)
  472. elif opname == "BUILD_STRING_3":
  473. self.addRule(
  474. """
  475. expr ::= formatted_value_debug
  476. formatted_value_debug ::= LOAD_STR formatted_value2 LOAD_STR BUILD_STRING_3
  477. formatted_value_debug ::= LOAD_STR formatted_value1 LOAD_STR BUILD_STRING_3
  478. """,
  479. nop_func,
  480. )
  481. custom_ops_processed.add(opname)
  482. elif opname == "LOAD_CLOSURE":
  483. self.addRule("""load_closure ::= LOAD_CLOSURE+""", nop_func)
  484. elif opname == "LOOKUP_METHOD":
  485. # A PyPy speciality - DRY with parse3
  486. self.addRule(
  487. """
  488. expr ::= attribute
  489. attribute ::= expr LOOKUP_METHOD
  490. """,
  491. nop_func,
  492. )
  493. custom_ops_processed.add(opname)
  494. elif opname == "MAKE_FUNCTION_8":
  495. if "LOAD_DICTCOMP" in self.seen_ops:
  496. # Is there something general going on here?
  497. rule = """
  498. dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
  499. MAKE_FUNCTION_8 expr
  500. GET_ITER CALL_FUNCTION_1
  501. """
  502. self.addRule(rule, nop_func)
  503. elif "LOAD_SETCOMP" in self.seen_ops:
  504. rule = """
  505. set_comp ::= load_closure LOAD_SETCOMP LOAD_STR
  506. MAKE_FUNCTION_CLOSURE expr
  507. GET_ITER CALL_FUNCTION_1
  508. """
  509. self.addRule(rule, nop_func)
  510. elif opname == "SETUP_WITH":
  511. rules_str = """
  512. stmt ::= with_as_pass
  513. with_as_pass ::= expr
  514. SETUP_WITH store pass
  515. POP_BLOCK BEGIN_FINALLY COME_FROM_WITH
  516. with_suffix
  517. """
  518. self.addRule(rules_str, nop_func)
  519. def reduce_is_invalid(self, rule, ast, tokens, first, last):
  520. invalid = super(Python38Parser, self).reduce_is_invalid(
  521. rule, ast, tokens, first, last
  522. )
  523. self.remove_rules_38()
  524. if invalid:
  525. return invalid
  526. lhs = rule[0]
  527. if lhs in ("whileTruestmt38", "whilestmt38"):
  528. jb_index = last - 1
  529. while jb_index > 0 and tokens[jb_index].kind.startswith("COME_FROM"):
  530. jb_index -= 1
  531. t = tokens[jb_index]
  532. if t.kind != "JUMP_BACK":
  533. return True
  534. return t.attr != tokens[first].off2int()
  535. pass
  536. return False
  537. class Python38ParserSingle(Python38Parser, PythonParserSingle):
  538. pass
  539. if __name__ == "__main__":
  540. # Check grammar
  541. # FIXME: DRY this with other parseXX.py routines
  542. p = Python38Parser()
  543. p.remove_rules_38()
  544. p.check_grammar()
  545. from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
  546. if PYTHON_VERSION_TRIPLE[:2] == (3, 8):
  547. lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets()
  548. from uncompyle6.scanner import get_scanner
  549. s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
  550. opcode_set = set(s.opc.opname).union(
  551. set(
  552. """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
  553. LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
  554. LAMBDA_MARKER RETURN_LAST
  555. """.split()
  556. )
  557. )
  558. remain_tokens = set(tokens) - opcode_set
  559. import re
  560. remain_tokens = set([re.sub(r"_\d+$", "", t) for t in remain_tokens])
  561. remain_tokens = set([re.sub("_CONT$", "", t) for t in remain_tokens])
  562. remain_tokens = set(remain_tokens) - opcode_set
  563. print(remain_tokens)
  564. import sys
  565. if len(sys.argv) > 1:
  566. from spark_parser.spark import rule2str
  567. for rule in sorted(p.rule2name.items()):
  568. print(rule2str(rule[0]))