parse2.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. # Copyright (c) 2015-2021, 2024 Rocky Bernstein
  2. # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
  3. #
  4. # Copyright (c) 1999 John Aycock
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. """
  18. Base grammar for Python 2.x.
  19. However instead of terminal symbols being the usual ASCII text,
  20. e.g. 5, myvariable, "for", etc. they are CPython Bytecode tokens,
  21. e.g. "LOAD_CONST 5", "STORE NAME myvariable", "SETUP_LOOP", etc.
  22. If we succeed in creating a parse tree, then we have a Python program
  23. that a later phase can turn into a sequence of ASCII text.
  24. """
  25. from __future__ import print_function
  26. from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
  27. from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
  28. from uncompyle6.parsers.reducecheck import except_handler_else, ifelsestmt, tryelsestmt
  29. from uncompyle6.parsers.treenode import SyntaxTree
  30. class Python2Parser(PythonParser):
  31. def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
  32. super(Python2Parser, self).__init__(SyntaxTree, "stmts", debug=debug_parser)
  33. self.new_rules = set()
  34. def p_print2(self, args):
  35. """
  36. stmt ::= print_items_stmt
  37. stmt ::= print_nl
  38. stmt ::= print_items_nl_stmt
  39. print_items_stmt ::= expr PRINT_ITEM print_items_opt
  40. print_items_nl_stmt ::= expr PRINT_ITEM print_items_opt PRINT_NEWLINE_CONT
  41. print_items_opt ::= print_items?
  42. print_items ::= print_item+
  43. print_item ::= expr PRINT_ITEM_CONT
  44. print_nl ::= PRINT_NEWLINE
  45. """
  46. def p_print_to(self, args):
  47. """
  48. stmt ::= print_to
  49. stmt ::= print_to_nl
  50. stmt ::= print_nl_to
  51. print_to ::= expr print_to_items POP_TOP
  52. print_to_nl ::= expr print_to_items PRINT_NEWLINE_TO
  53. print_nl_to ::= expr PRINT_NEWLINE_TO
  54. print_to_items ::= print_to_items print_to_item
  55. print_to_items ::= print_to_item
  56. print_to_item ::= DUP_TOP expr ROT_TWO PRINT_ITEM_TO
  57. """
  58. def p_grammar(self, args):
  59. """
  60. sstmt ::= stmt
  61. sstmt ::= return RETURN_LAST
  62. return_if_stmts ::= return_if_stmt
  63. return_if_stmts ::= _stmts return_if_stmt
  64. return_if_stmt ::= return_expr RETURN_END_IF
  65. return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA
  66. stmt ::= break
  67. break ::= BREAK_LOOP
  68. stmt ::= continue
  69. continue ::= CONTINUE
  70. continues ::= _stmts lastl_stmt continue
  71. continues ::= lastl_stmt continue
  72. continues ::= continue
  73. stmt ::= assert2
  74. stmt ::= raise_stmt0
  75. stmt ::= raise_stmt1
  76. stmt ::= raise_stmt2
  77. stmt ::= raise_stmt3
  78. raise_stmt0 ::= RAISE_VARARGS_0
  79. raise_stmt1 ::= expr RAISE_VARARGS_1
  80. raise_stmt2 ::= expr expr RAISE_VARARGS_2
  81. raise_stmt3 ::= expr expr expr RAISE_VARARGS_3
  82. for ::= SETUP_LOOP expr for_iter store
  83. for_block POP_BLOCK _come_froms
  84. delete ::= delete_subscript
  85. delete_subscript ::= expr expr DELETE_SUBSCR
  86. delete ::= expr DELETE_ATTR
  87. _lambda_body ::= load_closure lambda_body
  88. kwarg ::= LOAD_CONST expr
  89. kv3 ::= expr expr STORE_MAP
  90. classdef ::= buildclass store
  91. buildclass ::= LOAD_CONST expr mkfunc
  92. CALL_FUNCTION_0 BUILD_CLASS
  93. # Class decorators starting in 2.6
  94. stmt ::= classdefdeco
  95. classdefdeco ::= classdefdeco1 store
  96. classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1
  97. classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
  98. classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
  99. assert_expr ::= expr
  100. assert_expr ::= assert_expr_or
  101. assert_expr ::= assert_expr_and
  102. assert_expr_or ::= assert_expr jmp_true expr
  103. assert_expr_and ::= assert_expr jmp_false expr
  104. ifstmt ::= testexpr _ifstmts_jump
  105. testexpr ::= testfalse
  106. testexpr ::= testtrue
  107. testfalse ::= expr jmp_false
  108. testtrue ::= expr jmp_true
  109. _ifstmts_jump ::= return_if_stmts
  110. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
  111. iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK
  112. # this is nested inside a try_except
  113. tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
  114. POP_BLOCK LOAD_CONST
  115. COME_FROM suite_stmts_opt END_FINALLY
  116. lastc_stmt ::= tryelsestmtc
  117. # Move to 2.7? 2.6 may use come_froms
  118. tryelsestmtc ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  119. except_handler_else else_suitec COME_FROM
  120. tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  121. except_handler_else else_suitel COME_FROM
  122. try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  123. except_handler COME_FROM
  124. # Note: except_stmts may have many jumps after END_FINALLY
  125. except_handler ::= JUMP_FORWARD COME_FROM except_stmts
  126. END_FINALLY come_froms
  127. except_handler ::= jmp_abs COME_FROM except_stmts
  128. END_FINALLY
  129. except_handler_else ::= except_handler
  130. except_stmts ::= except_stmt+
  131. except_stmt ::= except_cond1 except_suite
  132. except_stmt ::= except
  133. except_suite ::= c_stmts_opt JUMP_FORWARD
  134. except_suite ::= c_stmts_opt jmp_abs
  135. except_suite ::= returns
  136. except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt _jump
  137. except ::= POP_TOP POP_TOP POP_TOP returns
  138. jmp_abs ::= JUMP_ABSOLUTE
  139. jmp_abs ::= JUMP_BACK
  140. jmp_abs ::= CONTINUE
  141. """
  142. def p_generator_exp2(self, args):
  143. """
  144. generator_exp ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
  145. """
  146. def p_expr2(self, args):
  147. """
  148. expr ::= LOAD_LOCALS
  149. expr ::= LOAD_ASSERT
  150. expr ::= slice0
  151. expr ::= slice1
  152. expr ::= slice2
  153. expr ::= slice3
  154. expr ::= unary_convert
  155. expr_jt ::= expr jmp_true
  156. or ::= expr_jt expr come_from_opt
  157. and ::= expr jmp_false expr come_from_opt
  158. unary_convert ::= expr UNARY_CONVERT
  159. # In Python 3, DUP_TOPX_2 is DUP_TOP_TWO
  160. subscript2 ::= expr expr DUP_TOPX_2 BINARY_SUBSCR
  161. """
  162. def p_slice2(self, args):
  163. """
  164. store ::= expr STORE_SLICE+0
  165. store ::= expr expr STORE_SLICE+1
  166. store ::= expr expr STORE_SLICE+2
  167. store ::= expr expr expr STORE_SLICE+3
  168. aug_assign1 ::= expr expr inplace_op ROT_FOUR STORE_SLICE+3
  169. aug_assign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+1
  170. aug_assign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2
  171. aug_assign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0
  172. slice0 ::= expr SLICE+0
  173. slice0 ::= expr DUP_TOP SLICE+0
  174. slice1 ::= expr expr SLICE+1
  175. slice1 ::= expr expr DUP_TOPX_2 SLICE+1
  176. slice2 ::= expr expr SLICE+2
  177. slice2 ::= expr expr DUP_TOPX_2 SLICE+2
  178. slice3 ::= expr expr expr SLICE+3
  179. slice3 ::= expr expr expr DUP_TOPX_3 SLICE+3
  180. """
  181. def p_op2(self, args):
  182. """
  183. inplace_op ::= INPLACE_DIVIDE
  184. binary_operator ::= BINARY_DIVIDE
  185. """
  186. def customize_grammar_rules(self, tokens, customize):
  187. """The base grammar we start out for a Python version even with the
  188. subclassing is, well, is pretty base. And we want it that way: lean and
  189. mean so that parsing will go faster.
  190. Here, we add additional grammar rules based on specific instructions
  191. that are in the instruction/token stream. In classes that
  192. inherit from from here and other versions, grammar rules may
  193. also be removed.
  194. For example if we see a pretty rare JUMP_IF_NOT_DEBUG
  195. instruction we'll add the grammar for that.
  196. More importantly, here we add grammar rules for instructions
  197. that may access a variable number of stack items. CALL_FUNCTION,
  198. BUILD_LIST and so on are like this.
  199. Without custom rules, there can be an super-exponential number of
  200. derivations. See the deparsing paper for an elaboration of
  201. this.
  202. """
  203. if "PyPy" in customize:
  204. # PyPy-specific customizations
  205. self.addRule(
  206. """
  207. stmt ::= assign3_pypy
  208. stmt ::= assign2_pypy
  209. assign3_pypy ::= expr expr expr store store store
  210. assign2_pypy ::= expr expr store store
  211. list_comp ::= expr BUILD_LIST_FROM_ARG for_iter store list_iter
  212. JUMP_BACK
  213. """,
  214. nop_func,
  215. )
  216. # For a rough break out on the first word. This may
  217. # include instructions that don't need customization,
  218. # but we'll do a finer check after the rough breakout.
  219. customize_instruction_basenames = frozenset(
  220. (
  221. "BUILD",
  222. "CALL",
  223. "CONTINUE",
  224. "DELETE",
  225. "DUP",
  226. "EXEC",
  227. "GET",
  228. "JUMP",
  229. "LOAD",
  230. "LOOKUP",
  231. "MAKE",
  232. "SETUP",
  233. "RAISE",
  234. "UNPACK",
  235. )
  236. )
  237. # Opcode names in the custom_seen_ops set have rules that get added
  238. # unconditionally and the rules are constant. So they need to be done
  239. # only once and if we see the opcode a second we don't have to consider
  240. # adding more rules.
  241. #
  242. custom_seen_ops = set()
  243. for i, token in enumerate(tokens):
  244. opname = token.kind
  245. # Do a quick breakout before testing potentially
  246. # each of the dozen or so instruction in if elif.
  247. if (
  248. opname[: opname.find("_")] not in customize_instruction_basenames
  249. or opname in custom_seen_ops
  250. ):
  251. continue
  252. opname_base = opname[: opname.rfind("_")]
  253. if opname in ("BUILD_CONST_LIST", "BUILD_CONST_SET"):
  254. rule = (
  255. """
  256. add_consts ::= add_value+
  257. add_value ::= ADD_VALUE
  258. add_value ::= ADD_VALUE_VAR
  259. const_list ::= COLLECTION_START add_consts %s
  260. expr ::= const_list
  261. """
  262. % opname
  263. )
  264. self.addRule(rule, nop_func)
  265. # The order of opname listed is roughly sorted below
  266. if opname_base in ("BUILD_LIST", "BUILD_SET", "BUILD_TUPLE"):
  267. # We do this complicated test to speed up parsing of
  268. # pathelogically long literals, especially those over 1024.
  269. build_count = token.attr
  270. thousands = build_count // 1024
  271. thirty32s = (build_count // 32) % 32
  272. if thirty32s > 0 or thousands > 0:
  273. rule = "expr32 ::=%s" % (" expr" * 32)
  274. self.add_unique_rule(rule, opname_base, build_count, customize)
  275. if thousands > 0:
  276. self.add_unique_rule(
  277. "expr1024 ::=%s" % (" expr32" * 32),
  278. opname_base,
  279. build_count,
  280. customize,
  281. )
  282. collection = opname_base[opname_base.find("_") + 1 :].lower()
  283. rule = (
  284. ("%s ::= " % collection)
  285. + "expr1024 " * thousands
  286. + "expr32 " * thirty32s
  287. + "expr " * (build_count % 32)
  288. + opname
  289. )
  290. self.add_unique_rules(["expr ::= %s" % collection, rule], customize)
  291. continue
  292. elif opname_base == "BUILD_MAP":
  293. if opname == "BUILD_MAP_n":
  294. # PyPy sometimes has no count. Sigh.
  295. self.add_unique_rules(
  296. [
  297. "kvlist_n ::= kvlist_n kv3",
  298. "kvlist_n ::=",
  299. "dict ::= BUILD_MAP_n kvlist_n",
  300. ],
  301. customize,
  302. )
  303. if self.version >= (2, 7):
  304. self.add_unique_rule(
  305. "dict_comp_func ::= BUILD_MAP_n LOAD_FAST FOR_ITER store "
  306. "comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST",
  307. "dict_comp_func",
  308. 0,
  309. customize,
  310. )
  311. else:
  312. kvlist_n = " kv3" * token.attr
  313. rule = "dict ::= %s%s" % (opname, kvlist_n)
  314. self.addRule(rule, nop_func)
  315. continue
  316. elif opname_base == "BUILD_SLICE":
  317. slice_num = token.attr
  318. if slice_num == 2:
  319. self.add_unique_rules(
  320. [
  321. "expr ::= build_slice2",
  322. "build_slice2 ::= expr expr BUILD_SLICE_2",
  323. ],
  324. customize,
  325. )
  326. else:
  327. assert slice_num == 3, (
  328. "BUILD_SLICE value must be 2 or 3; is %s" % slice_num
  329. )
  330. self.add_unique_rules(
  331. [
  332. "expr ::= build_slice3",
  333. "build_slice3 ::= expr expr expr BUILD_SLICE_3",
  334. ],
  335. customize,
  336. )
  337. continue
  338. elif opname_base in (
  339. "CALL_FUNCTION",
  340. "CALL_FUNCTION_VAR",
  341. "CALL_FUNCTION_VAR_KW",
  342. "CALL_FUNCTION_KW",
  343. ):
  344. args_pos, args_kw = self.get_pos_kw(token)
  345. # number of apply equiv arguments:
  346. nak = (len(opname_base) - len("CALL_FUNCTION")) // 3
  347. rule = (
  348. "call ::= expr "
  349. + "expr " * args_pos
  350. + "kwarg " * args_kw
  351. + "expr " * nak
  352. + opname
  353. )
  354. elif opname_base == "CALL_METHOD":
  355. # PyPy only - DRY with parse3
  356. args_pos, args_kw = self.get_pos_kw(token)
  357. # number of apply equiv arguments:
  358. nak = (len(opname_base) - len("CALL_METHOD")) // 3
  359. rule = (
  360. "call ::= expr "
  361. + "expr " * args_pos
  362. + "kwarg " * args_kw
  363. + "expr " * nak
  364. + opname
  365. )
  366. elif opname == "CONTINUE_LOOP":
  367. self.addRule("continue ::= CONTINUE_LOOP", nop_func)
  368. custom_seen_ops.add(opname)
  369. continue
  370. elif opname == "DELETE_ATTR":
  371. self.addRule("delete ::= expr DELETE_ATTR", nop_func)
  372. custom_seen_ops.add(opname)
  373. continue
  374. elif opname.startswith("DELETE_SLICE"):
  375. self.addRule(
  376. """
  377. del_expr ::= expr
  378. delete ::= del_expr DELETE_SLICE+0
  379. delete ::= del_expr del_expr DELETE_SLICE+1
  380. delete ::= del_expr del_expr DELETE_SLICE+2
  381. delete ::= del_expr del_expr del_expr DELETE_SLICE+3
  382. """,
  383. nop_func,
  384. )
  385. custom_seen_ops.add(opname)
  386. self.check_reduce["del_expr"] = "AST"
  387. continue
  388. elif opname == "DELETE_DEREF":
  389. self.addRule(
  390. """
  391. stmt ::= del_deref_stmt
  392. del_deref_stmt ::= DELETE_DEREF
  393. """,
  394. nop_func,
  395. )
  396. custom_seen_ops.add(opname)
  397. continue
  398. elif opname == "DELETE_SUBSCR":
  399. self.addRule(
  400. """
  401. delete ::= delete_subscript
  402. delete_subscript ::= expr expr DELETE_SUBSCR
  403. """,
  404. nop_func,
  405. )
  406. self.check_reduce["delete_subscript"] = "AST"
  407. custom_seen_ops.add(opname)
  408. continue
  409. elif opname == "GET_ITER":
  410. self.addRule(
  411. """
  412. expr ::= get_iter
  413. attribute ::= expr GET_ITER
  414. """,
  415. nop_func,
  416. )
  417. custom_seen_ops.add(opname)
  418. continue
  419. elif opname_base in ("DUP_TOPX", "RAISE_VARARGS"):
  420. # FIXME: remove these conditions if they are not needed.
  421. # no longer need to add a rule
  422. continue
  423. elif opname == "EXEC_STMT":
  424. self.addRule(
  425. """
  426. stmt ::= exec_stmt
  427. exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT
  428. exec_stmt ::= expr exprlist EXEC_STMT
  429. exprlist ::= expr+
  430. """,
  431. nop_func,
  432. )
  433. continue
  434. elif opname == "JUMP_IF_NOT_DEBUG":
  435. self.addRule(
  436. """
  437. jmp_true_false ::= POP_JUMP_IF_TRUE
  438. jmp_true_false ::= POP_JUMP_IF_FALSE
  439. stmt ::= assert_pypy
  440. stmt ::= assert2_pypy
  441. assert_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true_false
  442. LOAD_ASSERT RAISE_VARARGS_1 COME_FROM
  443. assert2_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true_false
  444. LOAD_ASSERT expr CALL_FUNCTION_1
  445. RAISE_VARARGS_1 COME_FROM
  446. """,
  447. nop_func,
  448. )
  449. continue
  450. elif opname == "LOAD_ATTR":
  451. self.addRule(
  452. """
  453. expr ::= attribute
  454. attribute ::= expr LOAD_ATTR
  455. """,
  456. nop_func,
  457. )
  458. custom_seen_ops.add(opname)
  459. continue
  460. elif opname == "LOAD_LISTCOMP":
  461. self.addRule("expr ::= list_comp", nop_func)
  462. custom_seen_ops.add(opname)
  463. continue
  464. elif opname == "LOAD_SETCOMP":
  465. self.add_unique_rules(
  466. [
  467. "expr ::= set_comp",
  468. "set_comp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1",
  469. ],
  470. customize,
  471. )
  472. custom_seen_ops.add(opname)
  473. continue
  474. elif opname == "LOOKUP_METHOD":
  475. # A PyPy speciality - DRY with parse3
  476. self.addRule(
  477. """
  478. expr ::= attribute
  479. attribute ::= expr LOOKUP_METHOD
  480. """,
  481. nop_func,
  482. )
  483. custom_seen_ops.add(opname)
  484. continue
  485. elif opname_base == "MAKE_FUNCTION":
  486. if i > 0 and tokens[i - 1] == "LOAD_LAMBDA":
  487. self.addRule(
  488. "lambda_body ::= %s LOAD_LAMBDA %s"
  489. % ("pos_arg " * token.attr, opname),
  490. nop_func,
  491. )
  492. rule = "mkfunc ::= %s LOAD_CODE %s" % ("expr " * token.attr, opname)
  493. elif opname_base == "MAKE_CLOSURE":
  494. # FIXME: use add_unique_rules to tidy this up.
  495. if i > 0 and tokens[i - 1] == "LOAD_LAMBDA":
  496. self.addRule(
  497. "lambda_body ::= %s load_closure LOAD_LAMBDA %s"
  498. % ("expr " * token.attr, opname),
  499. nop_func,
  500. )
  501. if i > 0:
  502. prev_tok = tokens[i - 1]
  503. if prev_tok == "LOAD_GENEXPR":
  504. self.add_unique_rules(
  505. [
  506. (
  507. "generator_exp ::= %s load_closure LOAD_GENEXPR %s expr"
  508. " GET_ITER CALL_FUNCTION_1"
  509. % ("expr " * token.attr, opname)
  510. )
  511. ],
  512. customize,
  513. )
  514. pass
  515. self.add_unique_rules(
  516. [
  517. (
  518. "mkfunc ::= %s load_closure LOAD_CODE %s"
  519. % ("expr " * token.attr, opname)
  520. )
  521. ],
  522. customize,
  523. )
  524. if self.version >= (2, 7):
  525. if i > 0:
  526. prev_tok = tokens[i - 1]
  527. if prev_tok == "LOAD_DICTCOMP":
  528. self.add_unique_rules(
  529. [
  530. (
  531. "dict_comp ::= %s load_closure LOAD_DICTCOMP %s expr"
  532. " GET_ITER CALL_FUNCTION_1"
  533. % ("expr " * token.attr, opname)
  534. )
  535. ],
  536. customize,
  537. )
  538. elif prev_tok == "LOAD_SETCOMP":
  539. self.add_unique_rules(
  540. [
  541. "expr ::= set_comp",
  542. (
  543. "set_comp ::= %s load_closure LOAD_SETCOMP %s expr"
  544. " GET_ITER CALL_FUNCTION_1"
  545. % ("expr " * token.attr, opname)
  546. ),
  547. ],
  548. customize,
  549. )
  550. pass
  551. pass
  552. continue
  553. elif opname == "SETUP_EXCEPT":
  554. if "PyPy" in customize:
  555. self.add_unique_rules(
  556. [
  557. "stmt ::= try_except_pypy",
  558. "try_except_pypy ::= SETUP_EXCEPT suite_stmts_opt except_handler_pypy",
  559. "except_handler_pypy ::= COME_FROM except_stmts END_FINALLY COME_FROM",
  560. ],
  561. customize,
  562. )
  563. custom_seen_ops.add(opname)
  564. continue
  565. elif opname == "SETUP_FINALLY":
  566. if "PyPy" in customize:
  567. self.addRule(
  568. """
  569. stmt ::= tryfinallystmt_pypy
  570. tryfinallystmt_pypy ::= SETUP_FINALLY suite_stmts_opt COME_FROM_FINALLY
  571. suite_stmts_opt END_FINALLY""",
  572. nop_func,
  573. )
  574. custom_seen_ops.add(opname)
  575. continue
  576. elif opname_base in ("UNPACK_TUPLE", "UNPACK_SEQUENCE"):
  577. custom_seen_ops.add(opname)
  578. rule = "unpack ::= " + opname + " store" * token.attr
  579. elif opname_base == "UNPACK_LIST":
  580. custom_seen_ops.add(opname)
  581. rule = "unpack_list ::= " + opname + " store" * token.attr
  582. else:
  583. continue
  584. self.addRule(rule, nop_func)
  585. pass
  586. self.reduce_check_table = {
  587. # "and": and_invalid,
  588. "except_handler_else": except_handler_else,
  589. "ifelsestmt": ifelsestmt,
  590. # "or": or_invalid,
  591. "tryelsestmt": tryelsestmt,
  592. "tryelsestmtl": tryelsestmt,
  593. }
  594. self.check_reduce["and"] = "AST"
  595. self.check_reduce["assert_expr_and"] = "AST"
  596. self.check_reduce["aug_assign2"] = "AST"
  597. self.check_reduce["except_handler_else"] = "tokens"
  598. self.check_reduce["ifelsestmt"] = "AST"
  599. self.check_reduce["ifstmt"] = "tokens"
  600. self.check_reduce["or"] = "AST"
  601. self.check_reduce["raise_stmt1"] = "tokens"
  602. self.check_reduce["tryelsestmt"] = "AST"
  603. self.check_reduce["tryelsestmtl"] = "AST"
  604. # self.check_reduce['_stmts'] = 'AST'
  605. # Dead code testing...
  606. # self.check_reduce['while1elsestmt'] = 'tokens'
  607. return
  608. def reduce_is_invalid(self, rule, ast, tokens, first, last):
  609. if tokens is None:
  610. return False
  611. lhs = rule[0]
  612. n = len(tokens)
  613. fn = self.reduce_check_table.get(lhs, None)
  614. if fn:
  615. if fn(self, lhs, n, rule, ast, tokens, first, last):
  616. return True
  617. pass
  618. if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")):
  619. # If the instruction after the instructions forming the "and" is an "YIELD_VALUE"
  620. # then this is probably an "if" inside a comprehension.
  621. if tokens[last] == "YIELD_VALUE":
  622. # Note: We might also consider testing last+1 being "POP_TOP"
  623. return True
  624. # Test that jump_false jump somewhere beyond the end of the "and"
  625. # it might not be exactly the end of the "and" because this and can
  626. # be a part of a larger condition. Oddly in 2.7 there doesn't seem to be
  627. # an optimization where the "and" jump_false is back to a loop.
  628. jmp_false = ast[1]
  629. if jmp_false[0] == "POP_JUMP_IF_FALSE":
  630. while first < last and isinstance(tokens[last].offset, str):
  631. last -= 1
  632. if jmp_false[0].attr < tokens[last].offset:
  633. return True
  634. # Test that jmp_false jumps to the end of "and"
  635. # or that it jumps to the same place as the end of "and"
  636. jmp_false = ast[1][0]
  637. jmp_target = jmp_false.offset + jmp_false.attr + 3
  638. return not (
  639. jmp_target == tokens[last].offset
  640. or tokens[last].pattr == jmp_false.pattr
  641. )
  642. # Dead code testing...
  643. # if lhs == 'while1elsestmt':
  644. # from trepan.api import debug; debug()
  645. elif (
  646. lhs in ("aug_assign1", "aug_assign2")
  647. and ast[0]
  648. and ast[0][0] in ("and", "or")
  649. ):
  650. return True
  651. elif lhs == "assert_expr_and":
  652. jmp_false = ast[1]
  653. jump_target = jmp_false[0].attr
  654. return jump_target > tokens[last].off2int()
  655. elif lhs in ("raise_stmt1",):
  656. # We will assume 'LOAD_ASSERT' will be handled by an assert grammar rule
  657. return tokens[first] == "LOAD_ASSERT" and (last >= len(tokens))
  658. elif rule == ("or", ("expr", "jmp_true", "expr", "\\e_come_from_opt")):
  659. expr2 = ast[2]
  660. return expr2 == "expr" and expr2[0] == "LOAD_ASSERT"
  661. elif lhs in ("delete_subscript", "del_expr"):
  662. op = ast[0][0]
  663. return op.kind in ("and", "or")
  664. return False
  665. class Python2ParserSingle(Python2Parser, PythonParserSingle):
  666. pass
  667. if __name__ == "__main__":
  668. # Check grammar
  669. p = Python2Parser()
  670. p.check_grammar()