diff --git a/test/bytecode_3.2/10_for_if_loopback.pyc b/test/bytecode_3.2/10_for_if_loopback.pyc new file mode 100644 index 00000000..4852bf41 Binary files /dev/null and b/test/bytecode_3.2/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 new file mode 100644 index 00000000..4c738c7a --- /dev/null +++ b/test/simple_source/looping/10_for_if_loopback.py @@ -0,0 +1,23 @@ +# In Python 3.2 JUMP_ABSOLUTE's (which can +# turn into COME_FROM's) are not optimized as +# they are in later Python's. +# +# So an if statement can jump to the end of a for loop +# which in turn jump's back to the beginning of that loop. +# +# Should handle in Python 3.2 +# +# 98 JUMP_BACK '16' statement after: names.append(name) to loop head +# 101_0 COME_FROM '50' statement: if name == ...to fictional "end if" +# 101 JUMP_BACK '16' jump as before to loop head + +def _slotnames(cls): + names = [] + for c in cls.__mro__: + if "__slots__" in c.__dict__: + slots = c.__dict__['__slots__'] + for name in slots: + if name == "__dict__": + continue + else: + names.append(name) # 3.2 bug here jumping to outer for diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index a12720e6..6c1dbefc 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -161,6 +161,27 @@ class PythonParser(GenericASTBuilder): assign3 ::= expr expr expr ROT_THREE ROT_TWO designator designator designator ''' + def p_forstmt(self, args): + """ + _for ::= GET_ITER FOR_ITER + _for ::= LOAD_CONST FOR_LOOP + + for_block ::= l_stmts_opt JUMP_BACK + for_block ::= return_stmts _come_from + + forstmt ::= SETUP_LOOP expr _for designator + for_block POP_BLOCK _come_from + + forelsestmt ::= SETUP_LOOP expr _for designator + for_block POP_BLOCK else_suite COME_FROM + + forelselaststmt ::= SETUP_LOOP expr _for designator + for_block POP_BLOCK else_suitec COME_FROM + + forelselaststmtl ::= SETUP_LOOP expr _for designator + for_block POP_BLOCK else_suitel COME_FROM + """ + def p_import20(self, args): ''' stmt ::= importstmt diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 49bac881..02cacae0 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -344,25 +344,6 @@ class Python2Parser(PythonParser): l_stmts_opt JUMP_BACK POP_BLOCK else_suitec COME_FROM - - _for ::= GET_ITER FOR_ITER - _for ::= LOAD_CONST FOR_LOOP - - for_block ::= l_stmts_opt JUMP_BACK - for_block ::= return_stmts _come_from - - forstmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK COME_FROM - - forelsestmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suite COME_FROM - - forelselaststmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suitec COME_FROM - - forelselaststmtl ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suitel COME_FROM - ''' def p_expr2(self, args): diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 646a5d2b..db51e223 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -350,26 +350,21 @@ class Python3Parser(PythonParser): l_stmts_opt JUMP_BACK POP_BLOCK else_suitec COME_FROM - - _for ::= GET_ITER FOR_ITER - _for ::= LOAD_CONST FOR_LOOP - - for_block ::= l_stmts_opt JUMP_BACK - for_block ::= return_stmts _come_from - - forstmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK _come_from - - forelsestmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suite COME_FROM - - forelselaststmt ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suitec COME_FROM - - forelselaststmtl ::= SETUP_LOOP expr _for designator - for_block POP_BLOCK else_suitel COME_FROM ''' + def p_for3(self, args): + """ + # In Python 3.2 JUMP_ABSOLUTE's (which can + # turn into COME_FROM's) are not optimized as + # they are in later Python's. + # + # So an if statement can jump to the end of a for loop + # which in turn jump's back to the beginning of that loop. + # + # Therefore we allow COME_FROM JUMP_BACK below. + for_block ::= l_stmts_opt COME_FROM JUMP_BACK + """ + def p_genexpr3(self, args): ''' load_genexpr ::= LOAD_GENEXPR diff --git a/uncompyle6/scanners/scanner32.py b/uncompyle6/scanners/scanner32.py index 39a20287..a648c4c3 100644 --- a/uncompyle6/scanners/scanner32.py +++ b/uncompyle6/scanners/scanner32.py @@ -2,9 +2,9 @@ """ Python 3.2 bytecode scanner/deparser -This overlaps Python's 3.2's dis module, but it can be run from -Python 2 and other versions of Python. Also, we save token information -for later use in deparsing. +This overlaps various Python3.2's dis module, but it can be run from +Python versions other than the version running this code. Notably, +run from Python version 2. See doc comments in scanner3.py for more information. """ from __future__ import print_function