You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Fix 3.2 for/if loopback bug
problem was handling in Python 3.2 for ... if ... else: .... jump for come from if jump for In later Python 3's a "come from" is removed. Also, start to DRY parser{,2,3} grammar rules.
This commit is contained in:
BIN
test/bytecode_3.2/10_for_if_loopback.pyc
Normal file
BIN
test/bytecode_3.2/10_for_if_loopback.pyc
Normal file
Binary file not shown.
23
test/simple_source/looping/10_for_if_loopback.py
Normal file
23
test/simple_source/looping/10_for_if_loopback.py
Normal file
@@ -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
|
@@ -161,6 +161,27 @@ class PythonParser(GenericASTBuilder):
|
|||||||
assign3 ::= expr expr expr ROT_THREE ROT_TWO designator designator designator
|
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):
|
def p_import20(self, args):
|
||||||
'''
|
'''
|
||||||
stmt ::= importstmt
|
stmt ::= importstmt
|
||||||
|
@@ -344,25 +344,6 @@ class Python2Parser(PythonParser):
|
|||||||
l_stmts_opt JUMP_BACK
|
l_stmts_opt JUMP_BACK
|
||||||
POP_BLOCK
|
POP_BLOCK
|
||||||
else_suitec COME_FROM
|
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):
|
def p_expr2(self, args):
|
||||||
|
@@ -350,26 +350,21 @@ class Python3Parser(PythonParser):
|
|||||||
l_stmts_opt JUMP_BACK
|
l_stmts_opt JUMP_BACK
|
||||||
POP_BLOCK
|
POP_BLOCK
|
||||||
else_suitec COME_FROM
|
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):
|
def p_genexpr3(self, args):
|
||||||
'''
|
'''
|
||||||
load_genexpr ::= LOAD_GENEXPR
|
load_genexpr ::= LOAD_GENEXPR
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
"""
|
"""
|
||||||
Python 3.2 bytecode scanner/deparser
|
Python 3.2 bytecode scanner/deparser
|
||||||
|
|
||||||
This overlaps Python's 3.2's dis module, but it can be run from
|
This overlaps various Python3.2's dis module, but it can be run from
|
||||||
Python 2 and other versions of Python. Also, we save token information
|
Python versions other than the version running this code. Notably,
|
||||||
for later use in deparsing.
|
run from Python version 2. See doc comments in scanner3.py for more information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
Reference in New Issue
Block a user