You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
2.6- bug: while..and: stmt - on one line
If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. In Python 2.7+ it's a single op.
This commit is contained in:
BIN
test/bytecode_2.7/04_while_and_stmt_one_line.pyc
Normal file
BIN
test/bytecode_2.7/04_while_and_stmt_one_line.pyc
Normal file
Binary file not shown.
9
test/simple_source/bug26/04_while_and_stmt_one_line.py
Normal file
9
test/simple_source/bug26/04_while_and_stmt_one_line.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# From Python 2.6/MimeWriter.py
|
||||||
|
#
|
||||||
|
# Bug is detecting that "del" starts a statement
|
||||||
|
# and is not: del not lines[-1] and lines[-1]
|
||||||
|
#
|
||||||
|
# A complicating factor is that the "while"
|
||||||
|
# and statement are on the same line.
|
||||||
|
lines = __file__.split("\n")
|
||||||
|
while lines and not lines[-1]: del lines[-1]
|
@@ -56,13 +56,18 @@ class Scanner2(scan.Scanner):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
show_asm = self.show_asm if not show_asm else show_asm
|
show_asm = self.show_asm if not show_asm else show_asm
|
||||||
# show_asm = 'before'
|
# show_asm = 'both'
|
||||||
if show_asm in ('both', 'before'):
|
if show_asm in ('both', 'before'):
|
||||||
from xdis.bytecode import Bytecode
|
from xdis.bytecode import Bytecode
|
||||||
bytecode = Bytecode(co, self.opc)
|
bytecode = Bytecode(co, self.opc)
|
||||||
for instr in bytecode.get_instructions(co):
|
for instr in bytecode.get_instructions(co):
|
||||||
print(instr._disassemble())
|
print(instr._disassemble())
|
||||||
|
|
||||||
|
# from xdis.bytecode import Bytecode
|
||||||
|
# bytecode = Bytecode(co, self.opc)
|
||||||
|
# for instr in bytecode.get_instructions(co):
|
||||||
|
# print(instr._disassemble())
|
||||||
|
|
||||||
# Container for tokens
|
# Container for tokens
|
||||||
tokens = []
|
tokens = []
|
||||||
|
|
||||||
@@ -77,7 +82,7 @@ class Scanner2(scan.Scanner):
|
|||||||
self.build_lines_data(co, n)
|
self.build_lines_data(co, n)
|
||||||
self.build_prev_op(n)
|
self.build_prev_op(n)
|
||||||
|
|
||||||
# self.lines contains (block,addrLastInstr)
|
# class and names
|
||||||
if classname:
|
if classname:
|
||||||
classname = '_' + classname.lstrip('_') + '__'
|
classname = '_' + classname.lstrip('_') + '__'
|
||||||
|
|
||||||
@@ -120,6 +125,7 @@ class Scanner2(scan.Scanner):
|
|||||||
|
|
||||||
cf = self.find_jump_targets()
|
cf = self.find_jump_targets()
|
||||||
# contains (code, [addrRefToCode])
|
# contains (code, [addrRefToCode])
|
||||||
|
|
||||||
last_stmt = self.next_stmt[0]
|
last_stmt = self.next_stmt[0]
|
||||||
i = self.next_stmt[last_stmt]
|
i = self.next_stmt[last_stmt]
|
||||||
replace = {}
|
replace = {}
|
||||||
@@ -316,7 +322,7 @@ class Scanner2(scan.Scanner):
|
|||||||
self.lines = []
|
self.lines = []
|
||||||
linetuple = namedtuple('linetuple', ['l_no', 'next'])
|
linetuple = namedtuple('linetuple', ['l_no', 'next'])
|
||||||
|
|
||||||
# linestarts is a tuple of (offset, line number).
|
# self.linestarts is a tuple of (offset, line number).
|
||||||
# Turn that in a has that we can index
|
# Turn that in a has that we can index
|
||||||
self.linestarts = list(self.opc.findlinestarts(co))
|
self.linestarts = list(self.opc.findlinestarts(co))
|
||||||
self.linestartoffsets = {}
|
self.linestartoffsets = {}
|
||||||
@@ -382,12 +388,15 @@ class Scanner2(scan.Scanner):
|
|||||||
while code[j] == self.opc.JUMP_ABSOLUTE:
|
while code[j] == self.opc.JUMP_ABSOLUTE:
|
||||||
j = self.prev[j]
|
j = self.prev[j]
|
||||||
if (self.version >= 2.3 and
|
if (self.version >= 2.3 and
|
||||||
code[j] == self.opc.LIST_APPEND): # list comprehension
|
self.opc.opname[code[j]] == 'LIST_APPEND'): # list comprehension
|
||||||
|
stmts.remove(s)
|
||||||
|
continue
|
||||||
|
elif code[s] == self.opc.POP_TOP:
|
||||||
|
prev = code[self.prev[s]]
|
||||||
|
if (prev == self.opc.ROT_TWO or
|
||||||
|
self.version <= 2.6 and prev == self.opc.JUMP_IF_FALSE):
|
||||||
stmts.remove(s)
|
stmts.remove(s)
|
||||||
continue
|
continue
|
||||||
elif code[s] == self.opc.POP_TOP and code[self.prev[s]] == self.opc.ROT_TWO:
|
|
||||||
stmts.remove(s)
|
|
||||||
continue
|
|
||||||
elif code[s] in self.designator_ops:
|
elif code[s] in self.designator_ops:
|
||||||
j = self.prev[s]
|
j = self.prev[s]
|
||||||
while code[j] in self.designator_ops:
|
while code[j] in self.designator_ops:
|
||||||
@@ -654,7 +663,7 @@ class Scanner2(scan.Scanner):
|
|||||||
'end': pre[target]})
|
'end': pre[target]})
|
||||||
return
|
return
|
||||||
|
|
||||||
# Is it an "and" inside an "if" block
|
# Is it an "and" inside an "if" or "while" block
|
||||||
if op == self.opc.PJIF:
|
if op == self.opc.PJIF:
|
||||||
# Search for other POP_JUMP_IF_FALSE targetting the same op,
|
# Search for other POP_JUMP_IF_FALSE targetting the same op,
|
||||||
# in current statement, starting from current offset, and filter
|
# in current statement, starting from current offset, and filter
|
||||||
|
@@ -71,12 +71,20 @@ class Scanner26(scan.Scanner2):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def disassemble(self, co, classname=None, code_objects={}, show_asm=None):
|
def disassemble(self, co, classname=None, code_objects={}, show_asm=None):
|
||||||
'''
|
"""
|
||||||
Disassemble a code object, returning a list of 'Token'.
|
Pick out tokens from an uncompyle6 code object, and transform them,
|
||||||
|
returning a list of uncompyle6 'Token's.
|
||||||
|
|
||||||
The main part of this procedure is modelled after
|
The tranformations are made to assist the deparsing grammar.
|
||||||
dis.disassemble().
|
Specificially:
|
||||||
'''
|
- various types of LOAD_CONST's are categorized in terms of what they load
|
||||||
|
- COME_FROM instructions are added to assist parsing control structures
|
||||||
|
- MAKE_FUNCTION and FUNCTION_CALLS append the number of positional arguments
|
||||||
|
|
||||||
|
Also, when we encounter certain tokens, we add them to a set which will cause custom
|
||||||
|
grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST
|
||||||
|
cause specific rules for the specific number of arguments they take.
|
||||||
|
"""
|
||||||
|
|
||||||
show_asm = self.show_asm if not show_asm else show_asm
|
show_asm = self.show_asm if not show_asm else show_asm
|
||||||
# show_asm = 'both'
|
# show_asm = 'both'
|
||||||
@@ -102,9 +110,6 @@ class Scanner26(scan.Scanner2):
|
|||||||
self.build_lines_data(co, n)
|
self.build_lines_data(co, n)
|
||||||
self.build_prev_op(n)
|
self.build_prev_op(n)
|
||||||
|
|
||||||
# linestarts contains block code adresses (addr,block)
|
|
||||||
self.linestarts = list(self.opc.findlinestarts(co))
|
|
||||||
|
|
||||||
# class and names
|
# class and names
|
||||||
if classname:
|
if classname:
|
||||||
classname = '_' + classname.lstrip('_') + '__'
|
classname = '_' + classname.lstrip('_') + '__'
|
||||||
|
Reference in New Issue
Block a user