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:
rocky
2016-05-08 12:09:50 -04:00
parent 4a79082872
commit a65a8bb68e
6 changed files with 60 additions and 40 deletions

Binary file not shown.

View 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

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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