diff --git a/README.rst b/README.rst index b0a6f19a..502e9a0e 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ Introduction ------------ *uncompyle6* translates Python bytecode back into equivalent Python -source code. It accepts bytecodes from Python version 2.3 to 3.6 or +source code. It accepts bytecodes from Python version 2.2 to 3.6 or so, including PyPy bytecode. Why this? @@ -45,7 +45,7 @@ Requirements This project requires Python 2.6 or later, PyPy 3-2.4, or PyPy-5.0.1. The bytecode files it can read has been tested on Python bytecodes from -versions 2.3-2.7, and 3.2-3.6 and the above-mentioned PyPy versions. +versions 2.2-2.7, and 3.2-3.6 and the above-mentioned PyPy versions. Installation ------------ diff --git a/test/bytecode_2.2/00_assign.pyc b/test/bytecode_2.2/00_assign.pyc new file mode 100644 index 00000000..bd63a6ea Binary files /dev/null and b/test/bytecode_2.2/00_assign.pyc differ diff --git a/test/bytecode_2.2/00_import.pyc b/test/bytecode_2.2/00_import.pyc new file mode 100644 index 00000000..bccadb0c Binary files /dev/null and b/test/bytecode_2.2/00_import.pyc differ diff --git a/test/bytecode_2.2/00_pass.pyc b/test/bytecode_2.2/00_pass.pyc new file mode 100644 index 00000000..3df2c5a7 Binary files /dev/null and b/test/bytecode_2.2/00_pass.pyc differ diff --git a/test/bytecode_2.2/03_class_method.pyc b/test/bytecode_2.2/03_class_method.pyc new file mode 100644 index 00000000..03044567 Binary files /dev/null and b/test/bytecode_2.2/03_class_method.pyc differ diff --git a/test/bytecode_2.3/00_import.pyc b/test/bytecode_2.3/00_import.pyc index 29153663..80b58aba 100644 Binary files a/test/bytecode_2.3/00_import.pyc and b/test/bytecode_2.3/00_import.pyc differ diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index f897e2d5..aa19a91e 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -269,9 +269,6 @@ class PythonParser(GenericASTBuilder): """ _for ::= GET_ITER FOR_ITER - # Possibly before Python 2.3 - # _for ::= LOAD_CONST FOR_LOOP - for_block ::= l_stmts_opt _come_from JUMP_BACK for_block ::= return_stmts _come_from @@ -546,7 +543,13 @@ def get_python_parser( # FIXME: there has to be a better way... if version < 3.0: - if version == 2.3: + if version == 2.2: + import uncompyle6.parsers.parse22 as parse22 + if compile_mode == 'exec': + p = parse22.Python22Parser(debug_parser) + else: + p = parse22.Python22ParserSingle(debug_parser) + elif version == 2.3: import uncompyle6.parsers.parse23 as parse23 if compile_mode == 'exec': p = parse23.Python23Parser(debug_parser) diff --git a/uncompyle6/parsers/parse22.py b/uncompyle6/parsers/parse22.py new file mode 100644 index 00000000..42f5f21d --- /dev/null +++ b/uncompyle6/parsers/parse22.py @@ -0,0 +1,30 @@ +# Copyright (c) 2016 Rocky Bernstein +# Copyright (c) 2000-2002 by hartmut Goebel + +from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from uncompyle6.parser import PythonParserSingle +from uncompyle6.parsers.parse23 import Python23Parser + +class Python22Parser(Python23Parser): + + def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG): + super(Python23Parser, self).__init__(debug_parser) + self.customized = {} + + def p_misc22(self, args): + ''' + stmt ::= SET_LINENO + _for ::= LOAD_CONST FOR_LOOP + ''' + +class Python22ParserSingle(Python23Parser, PythonParserSingle): + pass + +if __name__ == '__main__': + # Check grammar + p = Python22Parser() + p.checkGrammar() + p.dumpGrammar() + +# local variables: +# tab-width: 4 diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 1a0d8758..3bec4eb2 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -22,7 +22,7 @@ from uncompyle6 import PYTHON3, IS_PYPY from uncompyle6.scanners.tok import Token # The byte code versions we support -PYTHON_VERSIONS = (2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6) +PYTHON_VERSIONS = (2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6) # FIXME: DRY if PYTHON3: diff --git a/uncompyle6/scanners/scanner22.py b/uncompyle6/scanners/scanner22.py new file mode 100644 index 00000000..8c773036 --- /dev/null +++ b/uncompyle6/scanners/scanner22.py @@ -0,0 +1,27 @@ +# Copyright (c) 2016 by Rocky Bernstein +""" +Python 2.2 bytecode scanner/deparser + +This overlaps Python's 2.2's dis module, but it can be run from +Python 3 and other versions of Python. Also, we save token +information for later use in deparsing. +""" + +import uncompyle6.scanners.scanner23 as scan + +# bytecode verification, verify(), uses JUMP_OPs from here +from xdis.opcodes import opcode_22 +JUMP_OPs = opcode_22.JUMP_OPs + +# We base this off of 2.3 instead of the other way around +# because we cleaned things up this way. +# The history is that 2.7 support is the cleanest, +# then from that we got 2.6 and so on. +class Scanner22(scan.Scanner23): + def __init__(self, show_asm=False): + scan.Scanner23.__init__(self, show_asm) + self.opc = opcode_22 + self.opname = opcode_22.opname + self.version = 2.2 + self.genexpr_name = ''; + return diff --git a/uncompyle6/scanners/scanner23.py b/uncompyle6/scanners/scanner23.py index 0c59b29d..116c0eb8 100644 --- a/uncompyle6/scanners/scanner23.py +++ b/uncompyle6/scanners/scanner23.py @@ -1,8 +1,8 @@ # Copyright (c) 2016 by Rocky Bernstein """ -Python 2.4 bytecode scanner/deparser +Python 2.3 bytecode scanner/deparser -This overlaps Python's 2.4's dis module, but it can be run from +This overlaps Python's 2.3's dis module, but it can be run from Python 3 and other versions of Python. Also, we save token information for later use in deparsing. """ @@ -20,6 +20,8 @@ JUMP_OPs = opcode_23.JUMP_OPs class Scanner23(scan.Scanner24): def __init__(self, show_asm): scan.Scanner24.__init__(self, show_asm) + self.opc = opcode_23 + self.opname = opcode_23.opname # These are the only differences in initialization between # 2.3-2.6 self.version = 2.3 diff --git a/uncompyle6/scanners/scanner24.py b/uncompyle6/scanners/scanner24.py index f2e86420..9ee88378 100755 --- a/uncompyle6/scanners/scanner24.py +++ b/uncompyle6/scanners/scanner24.py @@ -22,6 +22,8 @@ class Scanner24(scan.Scanner25): scan.Scanner25.__init__(self, show_asm) # These are the only differences in initialization between # 2.4, 2.5 and 2.6 + self.opc = opcode_24 + self.opname = opcode_24.opname self.version = 2.4 self.genexpr_name = ''; return diff --git a/uncompyle6/scanners/scanner25.py b/uncompyle6/scanners/scanner25.py index a11015a2..446f5091 100755 --- a/uncompyle6/scanners/scanner25.py +++ b/uncompyle6/scanners/scanner25.py @@ -21,6 +21,8 @@ class Scanner25(scan.Scanner26): def __init__(self, show_asm): # There are no differences in initialization between # 2.5 and 2.6 + self.opc = opcode_25 + self.opname = opcode_25.opname scan.Scanner26.__init__(self, show_asm) self.version = 2.5 return diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 9a1c4731..d22e176c 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -329,7 +329,9 @@ TABLE_DIRECT = { 'kv': ( '%c: %c', 3, 1 ), 'kv2': ( '%c: %c', 1, 2 ), 'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ), - + 'importstmt': ( '%|import %c\n', 2), + 'importfrom': ( '%|from %[2]{pattr} import %c\n', 3 ), + 'importstar': ( '%|from %[2]{pattr} import *\n', ), } @@ -560,14 +562,12 @@ class SourceWalker(GenericASTTraversal, object): 'importfrom20': ( '%|from %[1]{pattr} import %c\n', 2 ), 'importlist20': ( '%C', (0, maxint, ', ') ), }) + elif version >= 2.5: ######################## # Import style for 2.5+ ######################## TABLE_DIRECT.update({ - 'importstmt': ( '%|import %c\n', 2), - 'importstar': ( '%|from %[2]{pattr} import *\n', ), - 'importfrom': ( '%|from %[2]{pattr} import %c\n', 3 ), 'importmultiple': ( '%|import %c%c\n', 2, 3 ), 'import_cont' : ( ', %c', 2 ), })