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 = 'before'
|
||||
# show_asm = 'both'
|
||||
if show_asm in ('both', 'before'):
|
||||
from xdis.bytecode import Bytecode
|
||||
bytecode = Bytecode(co, self.opc)
|
||||
for instr in bytecode.get_instructions(co):
|
||||
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
|
||||
tokens = []
|
||||
|
||||
@@ -77,7 +82,7 @@ class Scanner2(scan.Scanner):
|
||||
self.build_lines_data(co, n)
|
||||
self.build_prev_op(n)
|
||||
|
||||
# self.lines contains (block,addrLastInstr)
|
||||
# class and names
|
||||
if classname:
|
||||
classname = '_' + classname.lstrip('_') + '__'
|
||||
|
||||
@@ -120,6 +125,7 @@ class Scanner2(scan.Scanner):
|
||||
|
||||
cf = self.find_jump_targets()
|
||||
# contains (code, [addrRefToCode])
|
||||
|
||||
last_stmt = self.next_stmt[0]
|
||||
i = self.next_stmt[last_stmt]
|
||||
replace = {}
|
||||
@@ -316,7 +322,7 @@ class Scanner2(scan.Scanner):
|
||||
self.lines = []
|
||||
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
|
||||
self.linestarts = list(self.opc.findlinestarts(co))
|
||||
self.linestartoffsets = {}
|
||||
@@ -382,10 +388,13 @@ class Scanner2(scan.Scanner):
|
||||
while code[j] == self.opc.JUMP_ABSOLUTE:
|
||||
j = self.prev[j]
|
||||
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 and code[self.prev[s]] == self.opc.ROT_TWO:
|
||||
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)
|
||||
continue
|
||||
elif code[s] in self.designator_ops:
|
||||
@@ -654,7 +663,7 @@ class Scanner2(scan.Scanner):
|
||||
'end': pre[target]})
|
||||
return
|
||||
|
||||
# Is it an "and" inside an "if" block
|
||||
# Is it an "and" inside an "if" or "while" block
|
||||
if op == self.opc.PJIF:
|
||||
# Search for other POP_JUMP_IF_FALSE targetting the same op,
|
||||
# in current statement, starting from current offset, and filter
|
||||
|
@@ -71,12 +71,20 @@ class Scanner26(scan.Scanner2):
|
||||
return
|
||||
|
||||
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
|
||||
dis.disassemble().
|
||||
'''
|
||||
The tranformations are made to assist the deparsing grammar.
|
||||
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 = 'both'
|
||||
@@ -102,9 +110,6 @@ class Scanner26(scan.Scanner2):
|
||||
self.build_lines_data(co, n)
|
||||
self.build_prev_op(n)
|
||||
|
||||
# linestarts contains block code adresses (addr,block)
|
||||
self.linestarts = list(self.opc.findlinestarts(co))
|
||||
|
||||
# class and names
|
||||
if classname:
|
||||
classname = '_' + classname.lstrip('_') + '__'
|
||||
|
Reference in New Issue
Block a user