diff --git a/test/bytecode_3.4/04_raise.pyc b/test/bytecode_3.4/04_raise.pyc new file mode 100644 index 00000000..e8f3023b Binary files /dev/null and b/test/bytecode_3.4/04_raise.pyc differ diff --git a/test/bytecode_3.4/15_assert.pyc-notyet b/test/bytecode_3.4/15_assert.pyc-notyet deleted file mode 100644 index 5b5632b4..00000000 Binary files a/test/bytecode_3.4/15_assert.pyc-notyet and /dev/null differ diff --git a/test/bytecode_3.5/04_raise.pyc b/test/bytecode_3.5/04_raise.pyc new file mode 100644 index 00000000..569e6923 Binary files /dev/null and b/test/bytecode_3.5/04_raise.pyc differ diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 345c3c6d..4fe41a4b 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -148,6 +148,7 @@ def main(in_base, out_base, files, codes, outfile=None, else: print('\n# %s\n\t%s', infile, msg) except verify.VerifyCmpError as e: + print(e) verify_failed_files += 1 os.rename(outfile, outfile + '_unverified') if not outfile: diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 4279f909..ffd1935c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -247,7 +247,7 @@ class Python3Parser(PythonParser): ''' - def p_misc(self, args): + def p_misc3(self, args): """ try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM """ @@ -288,7 +288,6 @@ class Python3Parser(PythonParser): def p_expr3(self, args): ''' expr ::= LOAD_CLASSNAME - expr ::= LOAD_ASSERT # Python 3.4+ expr ::= LOAD_CLASSDEREF @@ -615,7 +614,7 @@ class Python35onParser(Python3Parser): expr ::= yield_from yield_from ::= expr GET_YIELD_FROM_ITER LOAD_CONST YIELD_FROM - # Python 3.5 has more loop optimization that removes + # Python 3.4+ has more loop optimization that removes # JUMP_FORWARD in some cases, and hence we also don't # see COME_FROM _ifstmts_jump ::= c_stmts_opt diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index 6be0a665..280d2bd4 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -37,6 +37,10 @@ class Python34Parser(Python3Parser): # Is this 3.4 only? yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM + # Python 3.4+ has more loop optimization that removes + # JUMP_FORWARD in some cases, and hence we also don't + # see COME_FROM + _ifstmts_jump ::= c_stmts_opt """ class Python34ParserSingle(Python34Parser, PythonParserSingle): pass diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 74bca070..4abf4983 100755 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -89,8 +89,14 @@ class Scanner2(scan.Scanner): varnames = co.co_varnames self.names = names + # Scan for assertions. Later we will + # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'. + # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() for i in self.op_range(0, n): + # We need to detect the difference between + # "raise AssertionError" and + # "assert" if self.code[i] == self.opc.PJIT and self.code[i+3] == self.opc.LOAD_GLOBAL: if names[self.get_argument(i+3)] == 'AssertionError': self.load_asserts.add(i+3) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 8ad6854c..5366efaf 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -125,8 +125,14 @@ class Scanner26(scan.Scanner2): codelen = len(self.code) + # Scan for assertions. Later we will + # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'. + # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() for i in self.op_range(0, n): + # We need to detect the difference between + # "raise AssertionError" and + # "assert" if (self.code[i] == self.opc.JUMP_IF_TRUE and i + 4 < codelen and self.code[i+3] == self.opc.POP_TOP and diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index be49626d..1f81d313 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -134,16 +134,19 @@ class Scanner3(scan.Scanner): bytecode = Bytecode(co, self.opc) # Scan for assertions. Later we will - # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT' for those - # assertions + # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'. + # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() bs = list(bytecode) n = len(bs) for i in range(n): inst = bs[i] - if inst.opname == 'POP_JUMP_IF_TRUE' and i+1 < n: - next_inst = bs[i+1] + # We need to detect the difference between + # "raise AssertionError" and + # "assert" + if inst.opname == 'POP_JUMP_IF_TRUE' and i+3 < n: + next_inst = bs[i+3] if (next_inst.opname == 'LOAD_GLOBAL' and next_inst.argval == 'AssertionError'): self.load_asserts.add(next_inst.offset) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index fc8754cb..21e90f01 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -180,7 +180,13 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''): if member in __IGNORE_CODE_MEMBERS__: pass elif member == 'co_code': - if version == 2.5: + if version == 2.3: + import uncompyle6.scanners.scanner23 as scan + scanner = scan.Scanner26() + elif version == 2.4: + import uncompyle6.scanners.scanner24 as scan + scanner = scan.Scanner25() + elif version == 2.5: import uncompyle6.scanners.scanner25 as scan scanner = scan.Scanner25() elif version == 2.6: @@ -206,8 +212,8 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''): JUMP_OPs = list(scan.JUMP_OPs) + ['JUMP_BACK'] # use changed Token class - # We (re)set this here to save exception handling, - # which would get confusing. + # We (re)set this here to save exception handling, + # which would get confusing. scanner.setTokenClass(Token) try: # disassemble both code-objects