parse24.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # Copyright (c) 2016-2018, 2020, 2022-2024 Rocky Bernstein
  2. """
  3. spark grammar differences over Python2.5 for Python 2.4.
  4. """
  5. from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
  6. from uncompyle6.parser import PythonParserSingle
  7. from uncompyle6.parsers.parse25 import Python25Parser
  8. class Python24Parser(Python25Parser):
  9. def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
  10. super(Python24Parser, self).__init__(debug_parser)
  11. self.customized = {}
  12. def p_misc24(self, args):
  13. """
  14. # Python 2.4 only adds something like the below for if 1:
  15. # However we will just treat it as a noop which messes up
  16. # simple verify of bytecode.
  17. # See also below in reduce_is_invalid where we check that the JUMP_FORWARD
  18. # target matches the COME_FROM target
  19. stmt ::= nop_stmt
  20. nop_stmt ::= JUMP_FORWARD POP_TOP COME_FROM
  21. # 2.5+ has two LOAD_CONSTs, one for the number '.'s in a relative import
  22. # keep positions similar to simplify semantic actions
  23. import ::= filler LOAD_CONST alias
  24. import_from ::= filler LOAD_CONST IMPORT_NAME importlist POP_TOP
  25. import_from_star ::= filler LOAD_CONST IMPORT_NAME IMPORT_STAR
  26. importmultiple ::= filler LOAD_CONST alias imports_cont
  27. import_cont ::= filler LOAD_CONST alias
  28. # Handle "if true else: ..." in Python 2.4
  29. stmt ::= iftrue_stmt24
  30. iftrue_stmt24 ::= _ifstmts_jump24 suite_stmts COME_FROM
  31. _ifstmts_jump24 ::= c_stmts_opt JUMP_FORWARD POP_TOP
  32. # Python 2.5+ omits POP_TOP POP_BLOCK
  33. while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK
  34. POP_TOP POP_BLOCK COME_FROM
  35. while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK
  36. POP_TOP POP_BLOCK
  37. continue ::= JUMP_BACK JUMP_ABSOLUTE
  38. # Python 2.4
  39. # The following has no "JUMP_BACK" after l_stmts because
  40. # l_stmts ends in a "break", "return", or "continue"
  41. while1stmt ::= SETUP_LOOP l_stmts
  42. POP_TOP POP_BLOCK
  43. # The following has a "COME_FROM" at the end which comes from
  44. # a "break" inside "l_stmts".
  45. while1stmt ::= SETUP_LOOP l_stmts COME_FROM JUMP_BACK
  46. POP_TOP POP_BLOCK COME_FROM
  47. # Python 2.5+:
  48. # call_stmt ::= expr POP_TOP
  49. # expr ::= yield
  50. call_stmt ::= yield
  51. # Python 2.5+ adds POP_TOP at the end
  52. gen_comp_body ::= expr YIELD_VALUE
  53. # Python 2.4
  54. # Python 2.6, 2.7 and 3.3+ use kv3
  55. # Python 2.3- use kv
  56. kvlist ::= kvlist kv2
  57. kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
  58. """
  59. def remove_rules_24(self):
  60. self.remove_rules(
  61. """
  62. expr ::= if_exp
  63. """
  64. )
  65. def customize_grammar_rules(self, tokens, customize):
  66. self.remove_rules(
  67. """
  68. gen_comp_body ::= expr YIELD_VALUE POP_TOP
  69. kvlist ::= kvlist kv3
  70. while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK COME_FROM
  71. while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK COME_FROM
  72. while1stmt ::= SETUP_LOOP returns COME_FROM
  73. whilestmt ::= SETUP_LOOP testexpr returns POP_BLOCK COME_FROM
  74. with ::= expr setupwith SETUP_FINALLY suite_stmts_opt POP_BLOCK
  75. LOAD_CONST COME_FROM with_cleanup
  76. with_as ::= expr setupwithas store suite_stmts_opt POP_BLOCK
  77. LOAD_CONST COME_FROM with_cleanup
  78. with_cleanup ::= LOAD_FAST DELETE_FAST WITH_CLEANUP END_FINALLY
  79. with_cleanup ::= LOAD_NAME DELETE_NAME WITH_CLEANUP END_FINALLY
  80. stmt ::= with
  81. stmt ::= with_as
  82. """
  83. )
  84. super(Python24Parser, self).customize_grammar_rules(tokens, customize)
  85. self.remove_rules_24()
  86. if self.version[:2] == (2, 4):
  87. self.check_reduce["nop_stmt"] = "tokens"
  88. if self.version[:2] <= (2, 4):
  89. # TODO: We may add something different or customize something
  90. del self.reduce_check_table["ifelsestmt"]
  91. def reduce_is_invalid(self, rule, ast, tokens, first, last):
  92. invalid = super(Python24Parser, self).reduce_is_invalid(
  93. rule, ast, tokens, first, last
  94. )
  95. if invalid or tokens is None:
  96. return invalid
  97. lhs = rule[0]
  98. if lhs == "nop_stmt":
  99. token_len = len(tokens)
  100. if 0 <= token_len < len(tokens):
  101. return not int(tokens[first].pattr) == tokens[last].offset
  102. class Python24ParserSingle(Python24Parser, PythonParserSingle):
  103. pass
  104. if __name__ == "__main__":
  105. # Check grammar
  106. p = Python24Parser()
  107. p.check_grammar()