bang on scanner2{5,6}

This commit is contained in:
rocky
2016-05-29 17:42:15 -04:00
parent 58fd0f7fe5
commit bb2e9c0d31
5 changed files with 122 additions and 124 deletions

View File

@@ -37,7 +37,7 @@ entry_points={
]} ]}
ftp_url = None ftp_url = None
install_requires = ['spark-parser >= 1.2.1', install_requires = ['spark-parser >= 1.2.1',
'xdis >= 1.0.4'] 'xdis >= 1.0.5']
license = 'MIT' license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com' mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6' modname = 'uncompyle6'

View File

@@ -20,7 +20,6 @@ For example:
Finally we save token information. Finally we save token information.
""" """
from __future__ import print_function from __future__ import print_function
import inspect import inspect
@@ -79,6 +78,7 @@ class Scanner2(scan.Scanner):
free = co.co_cellvars + co.co_freevars free = co.co_cellvars + co.co_freevars
names = co.co_names names = co.co_names
varnames = co.co_varnames varnames = co.co_varnames
self.names = names
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, n): for i in self.op_range(0, n):
@@ -164,14 +164,7 @@ class Scanner2(scan.Scanner):
elif op in self.opc.hasfree: elif op in self.opc.hasfree:
pattr = free[oparg] pattr = free[oparg]
if op in (self.opc.BUILD_LIST, self.opc.BUILD_TUPLE, if op in self.varargs_ops:
self.opc.BUILD_SET, self.opc.BUILD_SLICE,
self.opc.UNPACK_SEQUENCE, self.opc.MAKE_FUNCTION,
self.opc.CALL_FUNCTION, self.opc.MAKE_CLOSURE,
self.opc.CALL_FUNCTION_VAR, self.opc.CALL_FUNCTION_KW,
self.opc.CALL_FUNCTION_VAR_KW, self.opc.DUP_TOPX,
self.opc.RAISE_VARARGS
):
# CE - Hack for >= 2.5 # CE - Hack for >= 2.5
# Now all values loaded via LOAD_CLOSURE are packed into # Now all values loaded via LOAD_CLOSURE are packed into
# a tuple before calling MAKE_CLOSURE. # a tuple before calling MAKE_CLOSURE.
@@ -328,14 +321,14 @@ class Scanner2(scan.Scanner):
# linestarts is a tuple of (offset, line number). # 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
linestarts = list(findlinestarts(co)) self.linestarts = list(findlinestarts(co))
self.linestartoffsets = {} self.linestartoffsets = {}
for offset, lineno in linestarts: for offset, lineno in self.linestarts:
self.linestartoffsets[offset] = lineno self.linestartoffsets[offset] = lineno
j = 0 j = 0
(prev_start_byte, prev_line_no) = linestarts[0] (prev_start_byte, prev_line_no) = self.linestarts[0]
for (start_byte, line_no) in linestarts[1:]: for (start_byte, line_no) in self.linestarts[1:]:
while j < start_byte: while j < start_byte:
self.lines.append(linetuple(prev_line_no, start_byte)) self.lines.append(linetuple(prev_line_no, start_byte))
j += 1 j += 1

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2015-2016 by Rocky Bernstein # Copyright (c) 2015-2016 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org> # Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
# #
""" """
Python 2.5 bytecode scanner/deparser Python 2.5 bytecode scanner/deparser

View File

@@ -15,7 +15,7 @@ from collections import namedtuple
from array import array from array import array
from uncompyle6.opcodes.opcode_26 import * from uncompyle6.opcodes.opcode_26 import *
import dis from xdis.bytecode import findlinestarts
import uncompyle6.scanners.scanner2 as scan import uncompyle6.scanners.scanner2 as scan
class Scanner26(scan.Scanner2): class Scanner26(scan.Scanner2):
@@ -43,6 +43,17 @@ class Scanner26(scan.Scanner2):
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY, self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
]) ])
# opcodes with expect a variable number pushed values whose
# count is in the opcode. For parsing we generally change the
# opcode name to include that number.
self.varargs_ops = frozenset([
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS])
# opcodes that store values into a variable # opcodes that store values into a variable
self.designator_ops = frozenset([ self.designator_ops = frozenset([
self.opc.STORE_FAST, self.opc.STORE_NAME, self.opc.STORE_FAST, self.opc.STORE_NAME,
@@ -70,13 +81,12 @@ class Scanner26(scan.Scanner2):
customize = {} customize = {}
Token = self.Token # shortcut Token = self.Token # shortcut
self.code = array('B', co.co_code)
for i in self.op_range(0, len(self.code)): n = self.setup_code(co)
if self.code[i] in (RETURN_VALUE, END_FINALLY): self.build_lines_data(co, n)
n = i + 1
self.code = array('B', co.co_code[:n])
# linestarts contains block code adresses (addr,block) # linestarts contains block code adresses (addr,block)
self.linestarts = list(dis.findlinestarts(co)) self.linestarts = list(findlinestarts(co))
self.prev = [0] self.prev = [0]
# class and names # class and names
if classname: if classname:
@@ -107,31 +117,10 @@ class Scanner26(scan.Scanner2):
if self.op_hasArgument(op): if self.op_hasArgument(op):
self.prev.append(i) self.prev.append(i)
self.prev.append(i) self.prev.append(i)
j = 0
linestarts = self.linestarts
self.lines = []
linetuple = namedtuple('linetuple', ['l_no', 'next'])
# linestarts is a tuple of (offset, line number).
# Turn that in a has that we can index
linestartoffsets = {}
for offset, lineno in linestarts:
linestartoffsets[offset] = lineno
(prev_start_byte, prev_line_no) = linestarts[0]
for (start_byte, line_no) in linestarts[1:]:
while j < start_byte:
self.lines.append(linetuple(prev_line_no, start_byte))
j += 1
prev_line_no = line_no
while j < codelen:
self.lines.append(linetuple(prev_line_no, codelen))
j+=1
# self.lines contains (block,addrLastInstr)
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, codelen): for i in self.op_range(0, codelen):
if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL: if self.code[i] == self.opc.PJIT and self.code[i + 3] == self.opc.LOAD_GLOBAL:
if names[self.get_argument(i+3)] == 'AssertionError': if names[self.get_argument(i+3)] == 'AssertionError':
self.load_asserts.add(i+3) self.load_asserts.add(i+3)
@@ -141,22 +130,24 @@ class Scanner26(scan.Scanner2):
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 = {}
while i < codelen-1: while i < codelen - 1:
if self.lines[last_stmt].next > i: if self.lines[last_stmt].next > i:
if self.code[last_stmt] == PRINT_ITEM: if self.code[last_stmt] == self.opc.PRINT_ITEM:
if self.code[i] == PRINT_ITEM: if self.code[i] == self.opc.PRINT_ITEM:
replace[i] = 'PRINT_ITEM_CONT' replace[i] = 'PRINT_ITEM_CONT'
elif self.code[i] == PRINT_NEWLINE: elif self.code[i] == self.opc.PRINT_NEWLINE:
replace[i] = 'PRINT_NEWLINE_CONT' replace[i] = 'PRINT_NEWLINE_CONT'
last_stmt = i last_stmt = i
i = self.next_stmt[i] i = self.next_stmt[i]
imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR)) imports = self.all_instr(0, codelen,
(self.opc.IMPORT_NAME, self.opc.IMPORT_FROM,
self.opc.IMPORT_STAR))
if len(imports) > 1: if len(imports) > 1:
last_import = imports[0] last_import = imports[0]
for i in imports[1:]: for i in imports[1:]:
if self.lines[last_import].next > i: if self.lines[last_import].next > i:
if self.code[last_import] == IMPORT_NAME == self.code[i]: if self.code[last_import] == self.opc.IMPORT_NAME == self.code[i]:
replace[i] = 'IMPORT_NAME_CONT' replace[i] = 'IMPORT_NAME_CONT'
last_import = i last_import = i
@@ -175,11 +166,11 @@ class Scanner26(scan.Scanner2):
if self.op_hasArgument(op): if self.op_hasArgument(op):
oparg = self.get_argument(offset) + extended_arg oparg = self.get_argument(offset) + extended_arg
extended_arg = 0 extended_arg = 0
if op == EXTENDED_ARG: if op == self.opc.EXTENDED_ARG:
raise NotImplementedError raise NotImplementedError
extended_arg = oparg * scan.L65536 extended_arg = oparg * scan.L65536
continue continue
if op in hasconst: if op in self.opc.hasconst:
const = co.co_consts[oparg] const = co.co_consts[oparg]
# We can't use inspect.iscode() because we may be # We can't use inspect.iscode() because we may be
# using a different version of Python than the # using a different version of Python than the
@@ -204,59 +195,54 @@ class Scanner26(scan.Scanner2):
pattr = '<code_object ' + const.co_name + '>' pattr = '<code_object ' + const.co_name + '>'
else: else:
pattr = const pattr = const
elif op in hasname: elif op in self.opc.hasname:
pattr = names[oparg] pattr = names[oparg]
elif op in hasjrel: elif op in self.opc.hasjrel:
pattr = repr(offset + 3 + oparg) pattr = repr(offset + 3 + oparg)
elif op in hasjabs: elif op in self.opc.hasjabs:
pattr = repr(oparg) pattr = repr(oparg)
elif op in haslocal: elif op in self.opc.haslocal:
pattr = varnames[oparg] pattr = varnames[oparg]
elif op in hascompare: elif op in self.opc.hascompare:
try: pattr = self.opc.cmp_op[oparg]
pattr = cmp_op[oparg] elif op in self.opc.hasfree:
except:
from trepan.api import debug; debug()
elif op in hasfree:
pattr = free[oparg] pattr = free[oparg]
if offset in self.toChange: if offset in self.toChange:
if self.code[offset] == JA and self.code[oparg] == WITH_CLEANUP: if (self.code[offset] == self.opc.JA and
self.code[oparg] == self.opc.WITH_CLEANUP):
op_name = 'SETUP_WITH' op_name = 'SETUP_WITH'
cf[oparg] = cf.get(oparg, []) + [offset] cf[oparg] = cf.get(oparg, []) + [offset]
if op in (BUILD_LIST, BUILD_TUPLE, BUILD_SLICE, if op in self.varargs_ops:
UNPACK_SEQUENCE,
MAKE_FUNCTION, CALL_FUNCTION, MAKE_CLOSURE,
CALL_FUNCTION_VAR, CALL_FUNCTION_KW,
CALL_FUNCTION_VAR_KW, DUP_TOPX, RAISE_VARARGS
):
# CE - Hack for >= 2.5 # CE - Hack for >= 2.5
# Now all values loaded via LOAD_CLOSURE are packed into # Now all values loaded via LOAD_CLOSURE are packed into
# a tuple before calling MAKE_CLOSURE. # a tuple before calling MAKE_CLOSURE.
if op == BUILD_TUPLE and \ if (op == self.opc.BUILD_TUPLE and
self.code[self.prev[offset]] == LOAD_CLOSURE: self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE):
continue continue
else: else:
op_name = '%s_%d' % (op_name, oparg) op_name = '%s_%d' % (op_name, oparg)
if op != BUILD_SLICE: if op != self.opc.BUILD_SLICE:
customize[op_name] = oparg customize[op_name] = oparg
elif op == JA: elif op == self.opc.JA:
target = self.get_target(offset) target = self.get_target(offset)
if target < offset: if target < offset:
if offset in self.stmts and self.code[offset+3] not in (END_FINALLY, POP_BLOCK) \ if (offset in self.stmts
and offset not in self.not_continue: and self.code[offset + 3] not in (self.opc.END_FINALLY,
self.opc.POP_BLOCK)
and offset not in self.not_continue):
op_name = 'CONTINUE' op_name = 'CONTINUE'
else: else:
op_name = 'JUMP_BACK' op_name = 'JUMP_BACK'
elif op == LOAD_GLOBAL: elif op == self.opc.LOAD_GLOBAL:
if offset in self.load_asserts: if offset in self.load_asserts:
op_name = 'LOAD_ASSERT' op_name = 'LOAD_ASSERT'
elif op == RETURN_VALUE: elif op == self.opc.RETURN_VALUE:
if offset in self.return_end_ifs: if offset in self.return_end_ifs:
op_name = 'RETURN_END_IF' op_name = 'RETURN_END_IF'
if offset in linestartoffsets: if offset in self.linestartoffsets:
linestart = linestartoffsets[offset] linestart = self.linestartoffsets[offset]
else: else:
linestart = None linestart = None
@@ -282,10 +268,15 @@ class Scanner26(scan.Scanner2):
if i+opsize >= len(self.code): if i+opsize >= len(self.code):
return None return None
if opcode == EXTENDED_ARG: if opcode == self.opc.EXTENDED_ARG:
raise NotImplementedError raise NotImplementedError
# modification of some jump structure # modification of some jump structure
if opcode in (PJIF, PJIT, JA, JF, RETURN_VALUE): if opcode in (self.opc.PJIF,
self.opc.PJIT,
self.opc.JA,
self.opc.JF,
self.opc.RETURN_VALUE):
toDel = [] toDel = []
# del POP_TOP # del POP_TOP
if self.code[i+opsize] == POP_TOP: if self.code[i+opsize] == POP_TOP:
@@ -445,24 +436,24 @@ class Scanner26(scan.Scanner2):
if listDel: if listDel:
for jmp in self.op_range(0, len(self.code)): for jmp in self.op_range(0, len(self.code)):
op = self.code[jmp] op = self.code[jmp]
if op in hasjrel+hasjabs: if op in self.opc.hasjrel + self.opc.hasjabs:
offset = 0 offset = 0
jmpTarget = self.get_target(jmp) jmpTarget = self.get_target(jmp)
for toDel in listDel: for toDel in listDel:
if toDel < jmpTarget: if toDel < jmpTarget:
if op in hasjabs or jmp < toDel: if op in self.opc.hasjabs or jmp < toDel:
offset-=self.op_size(self.code[toDel]) offset-=self.op_size(self.code[toDel])
self.restructJump(jmp, jmpTarget+offset) self.restructJump(jmp, jmpTarget+offset)
if listExp: if listExp:
jmp = 0 jmp = 0
while jmp < len(self.code): # we can't use op_range for the moment while jmp < len(self.code): # we can't use op_range for the moment
op = self.code[jmp] op = self.code[jmp]
if op in hasjrel+hasjabs: if op in self.opc.hasjrel + self.opc.hasjabs:
offset = 0 offset = 0
jmpTarget = self.get_target(jmp) jmpTarget = self.get_target(jmp)
for toExp in listExp: for toExp in listExp:
if toExp < jmpTarget: if toExp < jmpTarget:
if op in hasjabs or jmp < toExp: if op in self.opc.hasjabs or jmp < toExp:
offset+=2 offset+=2
self.restructJump(jmp, jmpTarget+offset) self.restructJump(jmp, jmpTarget+offset)
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended: if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
@@ -520,9 +511,10 @@ class Scanner26(scan.Scanner2):
i=0 i=0
while i < len(self.code): # we can't use op_range for the moment while i < len(self.code): # we can't use op_range for the moment
op = self.code[i] op = self.code[i]
if(op in (PJIF, PJIT)): if op in self.pop_jump_if:
target = self.get_argument(i) target = self.get_argument(i)
target += i + 3 target += i + 3
self.restructJump(i, target) self.restructJump(i, target)
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended: if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
i += 3 i += 3
@@ -531,9 +523,9 @@ class Scanner26(scan.Scanner2):
i=0 i=0
while i < len(self.code): # we can't use op_range for the moment while i < len(self.code): # we can't use op_range for the moment
op = self.code[i] op = self.code[i]
if(op in (PJIF, PJIT)): if op in self.pop_jump_if:
target = self.get_target(i) target = self.get_target(i)
if self.code[target] == JA: if self.code[target] == self.opc.JA:
target = self.get_target(target) target = self.get_target(target)
self.restructJump(i, target) self.restructJump(i, target)
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended: if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
@@ -541,7 +533,7 @@ class Scanner26(scan.Scanner2):
else: i += 1 else: i += 1
def restructJump(self, pos, newTarget): def restructJump(self, pos, newTarget):
if not (self.code[pos] in hasjabs+hasjrel): if self.code[pos] not in self.opc.hasjabs + self.opc.hasjrel:
raise 'Can t change this argument. Opcode is not a jump' raise 'Can t change this argument. Opcode is not a jump'
if newTarget > 0xFFFF: if newTarget > 0xFFFF:
raise NotImplementedError raise NotImplementedError
@@ -577,7 +569,7 @@ class Scanner26(scan.Scanner2):
end = _end end = _end
parent = s parent = s
if op == SETUP_LOOP: if op == self.opc.SETUP_LOOP:
start = pos+3 start = pos+3
target = self.get_target(pos, op) target = self.get_target(pos, op)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
@@ -586,18 +578,19 @@ class Scanner26(scan.Scanner2):
self.fixed_jumps[pos] = end self.fixed_jumps[pos] = end
(line_no, next_line_byte) = self.lines[pos] (line_no, next_line_byte) = self.lines[pos]
jump_back = self.last_instr(start, end, JA, jump_back = self.last_instr(start, end, self.opc.JA, next_line_byte, False)
next_line_byte, False) if (jump_back and jump_back != self.prev[end]
if jump_back and jump_back != self.prev[end] and code[jump_back+3] in (JA, JF): and code[jump_back + 3] in (self.opc.JA, self.opc.JF)):
if code[self.prev[end]] == RETURN_VALUE or \ if (code[self.prev[end]] == self.opc.RETURN_VALUE
(code[self.prev[end]] == POP_BLOCK and code[self.prev[self.prev[end]]] == RETURN_VALUE): or code[self.prev[end]] == self.opc.POP_BLOCK
and code[self.prev[self.prev[end]]] == self.opc.RETURN_VALUE):
jump_back = None jump_back = None
if not jump_back: # loop suite ends in return. wtf right? if not jump_back: # loop suite ends in return. wtf right?
jump_back = self.last_instr(start, end, RETURN_VALUE) jump_back = self.last_instr(start, end, self.opc.JA, start, False)
if not jump_back: if not jump_back:
return return
jump_back += 1 jump_back += 1
if code[self.prev[next_line_byte]] not in (PJIF, PJIT): if code[self.prev[next_line_byte]] not in self.pop_jump_if:
loop_type = 'for' loop_type = 'for'
else: else:
loop_type = 'while' loop_type = 'while'
@@ -606,10 +599,9 @@ class Scanner26(scan.Scanner2):
end = jump_back + 3 end = jump_back + 3
else: else:
if self.get_target(jump_back) >= next_line_byte: if self.get_target(jump_back) >= next_line_byte:
jump_back = self.last_instr(start, end, JA, jump_back = self.last_instr(start, end, self.opc.JA, start, False)
start, False) if end > jump_back + 4 and code[end] in (self.opc.JF, self.opc.JA):
if end > jump_back+4 and code[end] in (JF, JA): if code[jump_back + 4] in (self.opc.JA, self.opc.JF):
if code[jump_back+4] in (JA, JF):
if self.get_target(jump_back+4) == self.get_target(end): if self.get_target(jump_back+4) == self.get_target(end):
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
end = jump_back+4 end = jump_back+4
@@ -617,16 +609,16 @@ class Scanner26(scan.Scanner2):
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
end = jump_back+4 end = jump_back+4
target = self.get_target(jump_back, JA) target = self.get_target(jump_back, self.opc.JA)
if code[target] in (FOR_ITER, GET_ITER): if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
loop_type = 'for' loop_type = 'for'
else: else:
loop_type = 'while' loop_type = 'while'
test = self.prev[next_line_byte] test = self.prev[next_line_byte]
if test == pos: if test == pos:
loop_type = 'while 1' loop_type = 'while 1'
elif self.code[test] in hasjabs+hasjrel: elif self.code[test] in self.opc.hasjabs + self.opc.hasjrel:
self.ignore_if.add(test) self.ignore_if.add(test)
test_target = self.get_target(test) test_target = self.get_target(test)
if test_target > (jump_back+3): if test_target > (jump_back+3):
@@ -640,7 +632,7 @@ class Scanner26(scan.Scanner2):
self.structs.append({'type': loop_type + '-else', self.structs.append({'type': loop_type + '-else',
'start': jump_back+3, 'start': jump_back+3,
'end': end}) 'end': end})
elif op == SETUP_EXCEPT: elif op == self.opc.SETUP_EXCEPT:
start = pos+3 start = pos+3
target = self.get_target(pos, op) target = self.get_target(pos, op)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
@@ -656,12 +648,12 @@ class Scanner26(scan.Scanner2):
# Add the except blocks # Add the except blocks
i = end i = end
while i < len(self.code) and self.code[i] != END_FINALLY: while i < len(self.code) and self.code[i] != self.opc.END_FINALLY:
jmp = self.next_except_jump(i) jmp = self.next_except_jump(i)
if jmp is None: # check if jmp is None: # check
i = self.next_stmt[i] i = self.next_stmt[i]
continue continue
if self.code[jmp] == RETURN_VALUE: if self.code[jmp] == self.opc.RETURN_VALUE:
self.structs.append({'type': 'except', self.structs.append({'type': 'except',
'start': i, 'start': i,
'end': jmp+1}) 'end': jmp+1})
@@ -669,7 +661,7 @@ class Scanner26(scan.Scanner2):
else: else:
if self.get_target(jmp) != start_else: if self.get_target(jmp) != start_else:
end_else = self.get_target(jmp) end_else = self.get_target(jmp)
if self.code[jmp] == JF: if self.code[jmp] == self.opc.JF:
self.fixed_jumps[jmp] = -1 self.fixed_jumps[jmp] = -1
self.structs.append({'type': 'except', self.structs.append({'type': 'except',
'start': i, 'start': i,
@@ -686,7 +678,7 @@ class Scanner26(scan.Scanner2):
else: else:
self.fixed_jumps[i] = i+1 self.fixed_jumps[i] = i+1
elif op in (PJIF, PJIT): elif op in self.pop_jump_if:
start = pos+3 start = pos+3
target = self.get_target(pos, op) target = self.get_target(pos, op)
rtarget = self.restrict_to_parent(target, parent) rtarget = self.restrict_to_parent(target, parent)
@@ -697,7 +689,7 @@ class Scanner26(scan.Scanner2):
return return
# does this jump to right after another cond jump? # does this jump to right after another cond jump?
# if so, it's part of a larger conditional # if so, it's part of a larger conditional
if (code[pre[target]] in (PJIF, PJIT)) and (target > pos): if code[pre[target]] in self.pop_jump_if and target > pos:
self.fixed_jumps[pos] = pre[target] self.fixed_jumps[pos] = pre[target]
self.structs.append({'type': 'and/or', self.structs.append({'type': 'and/or',
'start': start, 'start': start,
@@ -705,18 +697,19 @@ class Scanner26(scan.Scanner2):
return return
# is this an if and # is this an if and
if op == PJIF: if op == self.opc.PJIF:
match = self.rem_or(start, self.next_stmt[pos], PJIF, target) match = self.rem_or(start, self.next_stmt[pos], self.opc.PJIF, target)
match = self.remove_mid_line_ifs(match) match = self.remove_mid_line_ifs(match)
if match: if match:
if code[pre[rtarget]] in (JF, JA) \ if (code[pre[rtarget]] in (self.opc.JF, self.opc.JA)
and pre[rtarget] not in self.stmts \ and pre[rtarget] not in self.stmts
and self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget: and self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget):
if code[pre[pre[rtarget]]] == JA \ if (code[pre[pre[rtarget]]] == self.opc.JA
and self.remove_mid_line_ifs([pos]) \ and self.remove_mid_line_ifs([pos])
and target == self.get_target(pre[pre[rtarget]]) \ and target == self.get_target(pre[pre[rtarget]])
and (pre[pre[rtarget]] not in self.stmts or self.get_target(pre[pre[rtarget]]) > pre[pre[rtarget]])\ and (pre[pre[rtarget]] not in self.stmts
and 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], (PJIF, PJIT), target))): or self.get_target(pre[pre[rtarget]]) > pre[pre[rtarget]])
and 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], self.pop_jump_if, target)))):
pass pass
elif code[pre[pre[rtarget]]] == RETURN_VALUE \ elif code[pre[pre[rtarget]]] == RETURN_VALUE \
and self.remove_mid_line_ifs([pos]) \ and self.remove_mid_line_ifs([pos]) \
@@ -771,11 +764,11 @@ class Scanner26(scan.Scanner2):
and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA): and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA):
rtarget = pre[rtarget] rtarget = pre[rtarget]
# does the if jump just beyond a jump op, then this is probably an if statement # does the if jump just beyond a jump op, then this is probably an if statement
if code[pre[rtarget]] in (JA, JF): if code[pre[rtarget]] in (self.opc.JA, self.opc.JF):
if_end = self.get_target(pre[rtarget]) if_end = self.get_target(pre[rtarget])
# is this a loop not an if? # is this a loop not an if?
if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP): if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return
@@ -790,9 +783,9 @@ class Scanner26(scan.Scanner2):
self.structs.append({'type': 'if-else', self.structs.append({'type': 'if-else',
'start': rtarget, 'start': rtarget,
'end': end}) 'end': end})
elif code[pre[rtarget]] == RETURN_VALUE: elif code[pre[rtarget]] == self.opc.RETURN_VALUE:
# if it's an old JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP (return 1<2<3 case) # if it's an old JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP (return 1<2<3 case)
if pos < rtarget and code[rtarget] == ROT_TWO: if pos < rtarget and code[rtarget] == self.opc.ROT_TWO:
return return
self.structs.append({'type': 'if-then', self.structs.append({'type': 'if-then',
'start': start, 'start': start,

View File

@@ -44,6 +44,19 @@ class Scanner27(Scanner2):
self.opc.DELETE_SLICE_2, self.opc.DELETE_SLICE_3, self.opc.DELETE_SLICE_2, self.opc.DELETE_SLICE_3,
]) ])
# opcodes with expect a variable number pushed values whose
# count is in the opcode. For parsing we generally change the
# opcode name to include that number.
self.varargs_ops = frozenset([
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS,
# New in Python 2.7
self.opc.BUILD_SET])
# "setup" opcodes # "setup" opcodes
self.setup_ops = frozenset([ self.setup_ops = frozenset([
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY, self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,