diff --git a/test/bytecode_3.4/05_try_except.pyc b/test/bytecode_3.4/05_try_except.pyc new file mode 100644 index 00000000..3589b2e2 Binary files /dev/null and b/test/bytecode_3.4/05_try_except.pyc differ diff --git a/test/simple_source/exception/01_try_except.py b/test/simple_source/exception/01_try_except.py index 531e5be4..09b9076b 100644 --- a/test/simple_source/exception/01_try_except.py +++ b/test/simple_source/exception/01_try_except.py @@ -5,23 +5,28 @@ try: x = 1 -except RuntimeError as e: - y = 2 +except: + pass -# # Tests: -# # trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK -# # try_middle COME_FROM -# # except_stmt ::= except_cond1 except_suite -# # except_suite ::= ... +# Tests: +# trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK +# try_middle COME_FROM +# except_stmt ::= except_cond1 except_suite +# except_suite ::= ... -# try: -# x = 1 -# except ImportError: -# pass +try: + x = 1 +except ImportError: + pass -# try: -# x = 2 -# except ImportError: -# x = 3 -# finally: -# x = 4 +try: + x = 2 +except ImportError: + x = 3 +finally: + x = 4 + +try: + x = 1 +except ImportError as e: + x = 2 diff --git a/test/simple_source/exception/05_try_except.py b/test/simple_source/exception/05_try_except.py index a7bb51db..48ec82b9 100644 --- a/test/simple_source/exception/05_try_except.py +++ b/test/simple_source/exception/05_try_except.py @@ -1,6 +1,13 @@ +def handle(module): + try: + module = 1 + except ImportError as exc: + module = exc + return module + try: pass except ImportError as exc: pass finally: - del exc + y = 1 diff --git a/uncompyle6/main.py b/uncompyle6/main.py index b36e2649..3a2017b9 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -27,8 +27,10 @@ def uncompyle(version, co, out=None, showasm=False, showast=False, try: pysource.deparse_code(version, co, out, showasm, showast, showgrammar) - except pysource.ParserError as e : # parser failed, dump disassembly - print(e, file=real_out) + except pysource.WalkerError as e: + # deparsing failed + if real_out != out: + print(e, file=real_out) raise def uncompyle_file(filename, outstream=None, showasm=False, showast=False, diff --git a/uncompyle6/opcodes/opcode_34.py b/uncompyle6/opcodes/opcode_34.py index 2155934e..8c80d200 100644 --- a/uncompyle6/opcodes/opcode_34.py +++ b/uncompyle6/opcodes/opcode_34.py @@ -81,8 +81,10 @@ def_op('BINARY_TRUE_DIVIDE', 27) def_op('INPLACE_FLOOR_DIVIDE', 28) def_op('INPLACE_TRUE_DIVIDE', 29) -# Gone from Python 3 are -# Python 2's SLICE+0 .. SLICE+3 +# Gone from Python 3 are Python2's +# SLICE+0 .. SLICE+3 +# STORE_SLICE+0 .. STORE_SLICE+3 +# DELETE_SLICE+0 .. DELETE_SLICE+3 def_op('STORE_MAP', 54) def_op('INPLACE_ADD', 55) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index d793b3b3..fb5d30ae 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -449,6 +449,7 @@ class Python3Parser(PythonParser): except_stmt ::= except_cond1 except_suite except_stmt ::= except_cond2 except_suite + except_stmt ::= except_cond2 except_suite_finalize except_stmt ::= except # Python3 introduced POP_EXCEPT @@ -457,10 +458,11 @@ class Python3Parser(PythonParser): # This is used in Python 3 in # "except ... as e" to remove 'e' after the c_stmts_opt finishes - except_suite ::= SETUP_FINALLY c_stmts_opt - POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM LOAD_CONST - STORE_NAME DELETE_NAME END_FINALLY - JUMP_FORWARD + except_suite_finalize ::= SETUP_FINALLY c_stmts_opt except_var_finalize + END_FINALLY JUMP_FORWARD + + except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM LOAD_CONST + designator del_stmt except_suite ::= return_stmts diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 8360231b..9bf665fe 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -63,7 +63,6 @@ from __future__ import print_function import inspect, sys, re - from uncompyle6 import PYTHON3 from uncompyle6.parser import get_python_parser from uncompyle6.parsers.astnode import AST @@ -124,9 +123,14 @@ TAB = ' ' *4 # is less spacy than "\t" INDENT_PER_LEVEL = ' ' # additional intent per pretty-print level TABLE_R = { - 'POP_TOP': ( '%|%c\n', 0 ), 'STORE_ATTR': ( '%c.%[1]{pattr}', 0), # 'STORE_SUBSCR': ( '%c[%c]', 0, 1 ), + 'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ), +# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ), +} + +if not PYTHON3: + TABLE_R.update({ 'STORE_SLICE+0': ( '%c[:]', 0 ), 'STORE_SLICE+1': ( '%c[%p:]', 0, (1, 100) ), 'STORE_SLICE+2': ( '%c[:%p]', 0, (1, 100) ), @@ -135,9 +139,8 @@ TABLE_R = { 'DELETE_SLICE+1': ( '%|del %c[%c:]\n', 0, 1 ), 'DELETE_SLICE+2': ( '%|del %c[:%c]\n', 0, 1 ), 'DELETE_SLICE+3': ( '%|del %c[%c:%c]\n', 0, 1, 2 ), - 'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ), -# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ), -} + }) + TABLE_R0 = { # 'BUILD_LIST': ( '[%C]', (0,-1,', ') ), # 'BUILD_TUPLE': ( '(%C)', (0,-1,', ') ), @@ -317,6 +320,7 @@ TABLE_DIRECT = { 'except_cond1': ( '%|except %c:\n', 1 ), 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), + 'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ), 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), 'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3), @@ -438,7 +442,6 @@ class ParserError(python_parser.ParserError): lines.extend( ['', str(self.error)] ) return '\n'.join(lines) - def find_globals(node, globs): """Find globals in this statement.""" for n in node: @@ -467,6 +470,13 @@ def find_none(node): return True return False +class WalkerError(Exception): + def __init__(self, errmsg): + self.errmsg = errmsg + + def __str__(self): + return self.errmsg + class Walker(GenericASTTraversal, object): stacked_params = ('f', 'indent', 'isLambda', '_globals') @@ -1233,8 +1243,6 @@ class Walker(GenericASTTraversal, object): # self.print_("-----") # self.print(startnode) - # from trepan.api import debug - # debug(start_opts={'startup-profile': True}) fmt = entry[0] arg = 1 @@ -1262,7 +1270,18 @@ class Walker(GenericASTTraversal, object): elif typ == ',': pass elif typ == 'c': - self.preorder(node[entry[arg]]) + # FIXME: In Python3 sometimes like from + # importfrom + # importlist2 + # import_as + # designator + # STORE_NAME 'load_entry_point' + # POP_TOP '' (2, (0, 1)) + # we get that weird POP_TOP tuple, e.g (2, (0,1)). + # Why? and + # Is there some sort of invalid bounds access going on? + if isinstance(entry[arg], int): + self.preorder(node[entry[arg]]) arg += 1 elif typ == 'p': p = self.prec @@ -1637,6 +1656,8 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False, for g in deparsed.mod_globs: deparsed.write('# global %s ## Warning: Unused global' % g) + if deparsed.ERROR: + raise WalkerError("Deparsing stopped due to parse error") return deparsed if __name__ == '__main__':