From 5d86a4e5362c3ef09513ee3d5148610865af53d2 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 19 Jun 2016 10:19:45 -0400 Subject: [PATCH] Python 3 except clause parsing bug --- test/bytecode_3.4/08_while_except_bug.pyc | Bin 0 -> 240 bytes .../looping/08_while_except_bug.py | 9 +++++++ uncompyle6/parser.py | 22 ++++++++++++++++-- uncompyle6/parsers/parse2.py | 12 +--------- uncompyle6/parsers/parse3.py | 15 ++---------- uncompyle6/semantics/pysource.py | 1 - 6 files changed, 32 insertions(+), 27 deletions(-) create mode 100644 test/bytecode_3.4/08_while_except_bug.pyc create mode 100644 test/simple_source/looping/08_while_except_bug.py diff --git a/test/bytecode_3.4/08_while_except_bug.pyc b/test/bytecode_3.4/08_while_except_bug.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04ec3591674607a674dae3948a18fbec2f70a99a GIT binary patch literal 240 zcmaFI!^@>IJ1zVO0|UcjAcg}@Aj<)Wi%o$IDE0W_=QcDsubBb^A=cSg%BMGczC<5sP6TftdGjj`aQsayBON)|I^>gy`3o`T4 z^$jfI%QG^8;y`_=1tsxGrRjPFmA5!-a`RJ4b5iY?L9XWk5}b_8jBJd&K$4#k0BATo AH2?qr literal 0 HcmV?d00001 diff --git a/test/simple_source/looping/08_while_except_bug.py b/test/simple_source/looping/08_while_except_bug.py new file mode 100644 index 00000000..afb43c43 --- /dev/null +++ b/test/simple_source/looping/08_while_except_bug.py @@ -0,0 +1,9 @@ +# From python 3.4 contextlib +# JUMP_BACK in while causes a problem +while exit_callbacks: + try: + if cb: + exc_details = 5 + except: + exc_details = new_exc_details +pass diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 02688097..fd079a8e 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -40,8 +40,13 @@ class PythonParser(GenericASTBuilder): setattr(self, i, None) def error(self, tokens, index): - start = index - 2 if index - 2 > 0 else 0 - finish = index +2 if index + 2 < len(tokens) else len(tokens) + # Find the last line boundary + for start in range(index, -1, -1): + if tokens[start].linestart: break + pass + for finish in range(index+1, len(tokens)): + if tokens[finish].linestart: break + pass err_token = tokens[index] print("Token context:") for i in range(start, finish): @@ -118,6 +123,19 @@ class PythonParser(GenericASTBuilder): genexpr_func ::= LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK ''' + def p_jump(self, args): + """ + _jump ::= JUMP_ABSOLUTE + _jump ::= JUMP_FORWARD + _jump ::= JUMP_BACK + + # Note: Python < 2.7 doesn't have POP_JUMP_IF ... + jmp_false ::= POP_JUMP_IF_FALSE + jmp_false ::= JUMP_IF_FALSE + jmp_true ::= POP_JUMP_IF_TRUE + jmp_true ::= JUMP_IF_TRUE + """ + def p_dictcomp(self, args): ''' expr ::= dictcomp diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 4ec83330..7cb0dc42 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -189,15 +189,6 @@ class Python2Parser(PythonParser): classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS - _jump ::= JUMP_ABSOLUTE - _jump ::= JUMP_FORWARD - _jump ::= JUMP_BACK - - jmp_false ::= POP_JUMP_IF_FALSE - jmp_false ::= JUMP_IF_FALSE - jmp_true ::= POP_JUMP_IF_TRUE - jmp_true ::= JUMP_IF_TRUE - assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2 @@ -270,8 +261,7 @@ class Python2Parser(PythonParser): except_cond2 ::= DUP_TOP expr COMPARE_OP jmp_false POP_TOP designator POP_TOP - except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt JUMP_FORWARD - except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt jmp_abs + except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt _jump except ::= POP_TOP POP_TOP POP_TOP return_stmts jmp_abs ::= JUMP_ABSOLUTE diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 62048849..6f8da5e1 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -195,15 +195,6 @@ class Python3Parser(PythonParser): classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS - _jump ::= JUMP_ABSOLUTE - _jump ::= JUMP_FORWARD - _jump ::= JUMP_BACK - - jmp_false ::= POP_JUMP_IF_FALSE - jmp_false ::= JUMP_IF_FALSE - jmp_true ::= POP_JUMP_IF_TRUE - jmp_true ::= JUMP_IF_TRUE - assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2 @@ -293,15 +284,14 @@ class Python3Parser(PythonParser): except_cond2 ::= DUP_TOP expr COMPARE_OP jmp_false POP_TOP designator POP_TOP - except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt POP_EXCEPT JUMP_FORWARD + except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt POP_EXCEPT _jump except ::= POP_TOP POP_TOP POP_TOP return_stmts - except_pop_except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt JUMP_FORWARD - except_pop_except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt jmp_abs jmp_abs ::= JUMP_ABSOLUTE jmp_abs ::= JUMP_BACK + withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY @@ -314,7 +304,6 @@ class Python3Parser(PythonParser): def p_misc(self, args): """ - _jump ::= NOP try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM """ diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 3e063d6f..202f29c2 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -331,7 +331,6 @@ TABLE_DIRECT = { 'tf_trystmt': ( '%c%-%c%+', 1, 3 ), 'tf_tryelsestmt': ( '%c%-%c%|else:\n%+%c', 1, 3, 4 ), 'except': ('%|except:\n%+%c%-', 3 ), - 'except_pop_except': ('%|except:\n%+%c%-', 4 ), 'except_cond1': ( '%|except %c:\n', 1 ), 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ),