diff --git a/test/bytecode_3.2/10_for_if_loopback.pyc b/test/bytecode_3.2/10_for_if_loopback.pyc deleted file mode 100644 index 4852bf41..00000000 Binary files a/test/bytecode_3.2/10_for_if_loopback.pyc and /dev/null differ diff --git a/test/bytecode_3.2_run/10_for_if_loopback.pyc b/test/bytecode_3.2_run/10_for_if_loopback.pyc new file mode 100644 index 00000000..a7670f20 Binary files /dev/null and b/test/bytecode_3.2_run/10_for_if_loopback.pyc differ diff --git a/test/bytecode_3.7_run/10_for_if_loopback.pyc b/test/bytecode_3.7_run/10_for_if_loopback.pyc new file mode 100644 index 00000000..7e5217e0 Binary files /dev/null and b/test/bytecode_3.7_run/10_for_if_loopback.pyc differ diff --git a/test/simple_source/looping/10_for_if_loopback.py b/test/simple_source/looping/10_for_if_loopback.py index 4c738c7a..9f9b4cf4 100644 --- a/test/simple_source/looping/10_for_if_loopback.py +++ b/test/simple_source/looping/10_for_if_loopback.py @@ -11,6 +11,7 @@ # 101_0 COME_FROM '50' statement: if name == ...to fictional "end if" # 101 JUMP_BACK '16' jump as before to loop head +# RUNNABLE! def _slotnames(cls): names = [] for c in cls.__mro__: @@ -21,3 +22,18 @@ def _slotnames(cls): continue else: names.append(name) # 3.2 bug here jumping to outer for + +# From 3.2.6 pdb.py +# There is no "come_from" after the "if" since the +# if jumps back to the loop. For this we use +# grammar rule "ifstmtl" +def lasti2lineno(linestarts, a): + for i in linestarts: + if a: + return a + return -1 + +assert lasti2lineno([], True) == -1 +assert lasti2lineno([], False) == -1 +assert lasti2lineno([1], False) == -1 +assert lasti2lineno([1], True) == 1 diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 73e48984..552f45a5 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -141,18 +141,20 @@ class Python3Parser(PythonParser): assert_expr_or ::= assert_expr jmp_true expr assert_expr_and ::= assert_expr jmp_false expr - ifstmt ::= testexpr _ifstmts_jump + ifstmt ::= testexpr _ifstmts_jump testexpr ::= testfalse testexpr ::= testtrue testfalse ::= expr jmp_false testtrue ::= expr jmp_true - _ifstmts_jump ::= return_if_stmts - _ifstmts_jump ::= c_stmts_opt come_froms + _ifstmts_jump ::= return_if_stmts + _ifstmts_jump ::= c_stmts_opt come_froms + _ifstmts_jumpl ::= return_if_stmts iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK + iflaststmtl ::= testexpr _ifstmts_jumpl # These are used to keep parse tree indices the same jump_forward_else ::= JUMP_FORWARD ELSE @@ -330,6 +332,10 @@ class Python3Parser(PythonParser): def p_stmt3(self, args): """ stmt ::= if_expr_lambda + + # If statement inside a loop: + lastl_stmt ::= ifstmtl + stmt ::= conditional_not_lambda if_expr_lambda ::= expr jmp_false expr return_if_lambda return_stmt_lambda LAMBDA_MARKER diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 26934a09..a044d81f 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -952,6 +952,8 @@ class Python37Parser(Python37BaseParser): """ stmt ::= if_expr_lambda stmt ::= conditional_not_lambda + + # If statement inside a loop: stmt ::= ifstmtl if_expr_lambda ::= expr jmp_false expr return_if_lambda diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 933a842d..71003f31 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -371,14 +371,13 @@ TABLE_DIRECT = { # 'return': ( '%|return %c\n', 0), 'return_if_stmt': ( 'return %c\n', 0), - 'ifstmt': ( '%|if %c:\n%+%c%-', + "ifstmt": ( "%|if %c:\n%+%c%-", 0, # "testexpr" or "testexpr_then" 1, # "_ifstmts_jump" or "return_stmts" ), - - 'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ), - 'iflaststmtl': ( '%|if %c:\n%+%c%-', 0, 1 ), - 'testtrue': ( 'not %p', + 'iflaststmt': ( "%|if %c:\n%+%c%-", 0, 1 ), + 'iflaststmtl': ( "%|if %c:\n%+%c%-", 0, 1 ), + 'testtrue': ( "not %p", (0, PRECEDENCE['unary_not']) ), # Generally the args here are 0: (some sort of) "testexpr",