You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Python 3 needs Python2's RETURN_END_IF
Make python2 and python3 scanner look more the same
This commit is contained in:
BIN
test/bytecode_3.4/10_if_else_ternary.pyc
Normal file
BIN
test/bytecode_3.4/10_if_else_ternary.pyc
Normal file
Binary file not shown.
@@ -115,7 +115,7 @@ class Python3Parser(PythonParser):
|
|||||||
|
|
||||||
return_if_stmts ::= return_if_stmt come_from_opt
|
return_if_stmts ::= return_if_stmt come_from_opt
|
||||||
return_if_stmts ::= _stmts return_if_stmt
|
return_if_stmts ::= _stmts return_if_stmt
|
||||||
return_if_stmt ::= ret_expr RETURN_VALUE
|
return_if_stmt ::= ret_expr RETURN_END_IF
|
||||||
|
|
||||||
stmt ::= break_stmt
|
stmt ::= break_stmt
|
||||||
break_stmt ::= BREAK_LOOP
|
break_stmt ::= BREAK_LOOP
|
||||||
|
@@ -272,6 +272,9 @@ class Scanner(object):
|
|||||||
target = parent['end']
|
target = parent['end']
|
||||||
return target
|
return target
|
||||||
|
|
||||||
|
def parse_fn_counts(argc):
|
||||||
|
return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
||||||
|
|
||||||
def get_scanner(version, show_asm=None):
|
def get_scanner(version, show_asm=None):
|
||||||
# Pick up appropriate scanner
|
# Pick up appropriate scanner
|
||||||
if version in PYTHON_VERSIONS:
|
if version in PYTHON_VERSIONS:
|
||||||
|
@@ -127,7 +127,7 @@ class Scanner2(scan.Scanner):
|
|||||||
k += 1
|
k += 1
|
||||||
|
|
||||||
op = self.code[offset]
|
op = self.code[offset]
|
||||||
op_name = self.opc.opname[op]
|
opname = self.opc.opname[op]
|
||||||
|
|
||||||
oparg = None; pattr = None
|
oparg = None; pattr = None
|
||||||
if op >= self.opc.HAVE_ARGUMENT:
|
if op >= self.opc.HAVE_ARGUMENT:
|
||||||
@@ -141,14 +141,14 @@ class Scanner2(scan.Scanner):
|
|||||||
if iscode(const):
|
if iscode(const):
|
||||||
oparg = const
|
oparg = const
|
||||||
if const.co_name == '<lambda>':
|
if const.co_name == '<lambda>':
|
||||||
assert op_name == 'LOAD_CONST'
|
assert opname == 'LOAD_CONST'
|
||||||
op_name = 'LOAD_LAMBDA'
|
opname = 'LOAD_LAMBDA'
|
||||||
elif const.co_name == '<genexpr>':
|
elif const.co_name == '<genexpr>':
|
||||||
op_name = 'LOAD_GENEXPR'
|
opname = 'LOAD_GENEXPR'
|
||||||
elif const.co_name == '<dictcomp>':
|
elif const.co_name == '<dictcomp>':
|
||||||
op_name = 'LOAD_DICTCOMP'
|
opname = 'LOAD_DICTCOMP'
|
||||||
elif const.co_name == '<setcomp>':
|
elif const.co_name == '<setcomp>':
|
||||||
op_name = 'LOAD_SETCOMP'
|
opname = 'LOAD_SETCOMP'
|
||||||
# verify() uses 'pattr' for comparison, since 'attr'
|
# verify() uses 'pattr' for comparison, since 'attr'
|
||||||
# now holds Code(const) and thus can not be used
|
# now holds Code(const) and thus can not be used
|
||||||
# for comparison (todo: think about changing this)
|
# for comparison (todo: think about changing this)
|
||||||
@@ -178,24 +178,24 @@ class Scanner2(scan.Scanner):
|
|||||||
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE:
|
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
op_name = '%s_%d' % (op_name, oparg)
|
opname = '%s_%d' % (opname, oparg)
|
||||||
if op != self.opc.BUILD_SLICE:
|
if op != self.opc.BUILD_SLICE:
|
||||||
customize[op_name] = oparg
|
customize[opname] = oparg
|
||||||
elif op == self.opc.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 (self.opc.END_FINALLY, self.opc.POP_BLOCK) \
|
if offset in self.stmts and self.code[offset+3] not in (self.opc.END_FINALLY, self.opc.POP_BLOCK) \
|
||||||
and offset not in self.not_continue:
|
and offset not in self.not_continue:
|
||||||
op_name = 'CONTINUE'
|
opname = 'CONTINUE'
|
||||||
else:
|
else:
|
||||||
op_name = 'JUMP_BACK'
|
opname = 'JUMP_BACK'
|
||||||
|
|
||||||
elif op == self.opc.LOAD_GLOBAL:
|
elif op == self.opc.LOAD_GLOBAL:
|
||||||
if offset in self.load_asserts:
|
if offset in self.load_asserts:
|
||||||
op_name = 'LOAD_ASSERT'
|
opname = 'LOAD_ASSERT'
|
||||||
elif op == self.opc.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'
|
opname = 'RETURN_END_IF'
|
||||||
|
|
||||||
if offset in self.linestartoffsets:
|
if offset in self.linestartoffsets:
|
||||||
linestart = self.linestartoffsets[offset]
|
linestart = self.linestartoffsets[offset]
|
||||||
@@ -203,7 +203,7 @@ class Scanner2(scan.Scanner):
|
|||||||
linestart = None
|
linestart = None
|
||||||
|
|
||||||
if offset not in replace:
|
if offset not in replace:
|
||||||
tokens.append(Token(op_name, oparg, pattr, offset, linestart))
|
tokens.append(Token(opname, oparg, pattr, offset, linestart))
|
||||||
else:
|
else:
|
||||||
tokens.append(Token(replace[offset], oparg, pattr, offset, linestart))
|
tokens.append(Token(replace[offset], oparg, pattr, offset, linestart))
|
||||||
pass
|
pass
|
||||||
@@ -507,11 +507,15 @@ class Scanner2(scan.Scanner):
|
|||||||
rtarget = self.restrict_to_parent(target, parent)
|
rtarget = self.restrict_to_parent(target, parent)
|
||||||
pre = self.prev
|
pre = self.prev
|
||||||
|
|
||||||
|
# Do not let jump to go out of parent struct bounds
|
||||||
if target != rtarget and parent['type'] == 'and/or':
|
if target != rtarget and parent['type'] == 'and/or':
|
||||||
self.fixed_jumps[pos] = rtarget
|
self.fixed_jumps[pos] = rtarget
|
||||||
return
|
return
|
||||||
# does this jump to right after another cond jump?
|
|
||||||
# if so, it's part of a larger conditional
|
# Does this jump to right after another cond jump that is
|
||||||
|
# not myself? If so, it's part of a larger conditional.
|
||||||
|
# rocky: if we have a conditional jump to the next instruction, then
|
||||||
|
# possibly I am "skipping over" a "pass" or null statement.
|
||||||
if (code[pre[target]] in (self.opc.JUMP_IF_FALSE_OR_POP,
|
if (code[pre[target]] in (self.opc.JUMP_IF_FALSE_OR_POP,
|
||||||
self.opc.JUMP_IF_TRUE_OR_POP,
|
self.opc.JUMP_IF_TRUE_OR_POP,
|
||||||
self.opc.PJIF, self.opc.PJIT)) and (target > pos):
|
self.opc.PJIF, self.opc.PJIT)) and (target > pos):
|
||||||
@@ -521,11 +525,15 @@ class Scanner2(scan.Scanner):
|
|||||||
'end': pre[target]})
|
'end': pre[target]})
|
||||||
return
|
return
|
||||||
|
|
||||||
# is this an if and
|
# Is it an "and" inside an "if" block
|
||||||
if op == self.opc.PJIF:
|
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
|
||||||
|
# everything inside inner 'or' jumps and midline ifs
|
||||||
match = self.rem_or(start, self.next_stmt[pos], self.opc.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 we still have any offsets in set, start working on it
|
||||||
if match:
|
if match:
|
||||||
if code[pre[rtarget]] in self.jump_forward \
|
if code[pre[rtarget]] in self.jump_forward \
|
||||||
and pre[rtarget] not in self.stmts \
|
and pre[rtarget] not in self.stmts \
|
||||||
@@ -598,11 +606,12 @@ class Scanner2(scan.Scanner):
|
|||||||
rtarget = pre[rtarget]
|
rtarget = pre[rtarget]
|
||||||
else:
|
else:
|
||||||
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 self.jump_forward:
|
if code[pre[rtarget]] in self.jump_forward:
|
||||||
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 and not an "if" statment?
|
||||||
if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.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
|
||||||
|
@@ -27,7 +27,7 @@ from array import array
|
|||||||
|
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
from xdis.bytecode import Bytecode, findlinestarts
|
from xdis.bytecode import Bytecode, findlinestarts
|
||||||
from uncompyle6.scanner import Token
|
from uncompyle6.scanner import Token, parse_fn_counts
|
||||||
|
|
||||||
# Get all the opcodes into globals
|
# Get all the opcodes into globals
|
||||||
import xdis.opcodes.opcode_33 as op3
|
import xdis.opcodes.opcode_33 as op3
|
||||||
@@ -129,9 +129,7 @@ class Scanner3(scan.Scanner):
|
|||||||
pattr = const
|
pattr = const
|
||||||
pass
|
pass
|
||||||
elif opname in ('MAKE_FUNCTION', 'MAKE_CLOSURE'):
|
elif opname in ('MAKE_FUNCTION', 'MAKE_CLOSURE'):
|
||||||
argc = inst.argval
|
pos_args, name_pair_args, annotate_args = parse_fn_counts(inst.argval)
|
||||||
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
|
||||||
pos_args, name_pair_args, annotate_args = attr
|
|
||||||
if name_pair_args > 0:
|
if name_pair_args > 0:
|
||||||
opname = '%s_N%d' % (opname, name_pair_args)
|
opname = '%s_N%d' % (opname, name_pair_args)
|
||||||
pass
|
pass
|
||||||
@@ -176,6 +174,9 @@ class Scanner3(scan.Scanner):
|
|||||||
else:
|
else:
|
||||||
opname = 'JUMP_BACK'
|
opname = 'JUMP_BACK'
|
||||||
|
|
||||||
|
elif opname == 'RETURN_VALUE':
|
||||||
|
if inst.offset in self.return_end_ifs:
|
||||||
|
opname = 'RETURN_END_IF'
|
||||||
elif inst.offset in self.load_asserts:
|
elif inst.offset in self.load_asserts:
|
||||||
opname = 'LOAD_ASSERT'
|
opname = 'LOAD_ASSERT'
|
||||||
|
|
||||||
@@ -517,13 +518,14 @@ class Scanner3(scan.Scanner):
|
|||||||
'end': prev_op[target]})
|
'end': prev_op[target]})
|
||||||
return
|
return
|
||||||
|
|
||||||
# Is it an and inside if block
|
# Is it an "and" inside an "if" block
|
||||||
if op == POP_JUMP_IF_FALSE:
|
if op == POP_JUMP_IF_FALSE:
|
||||||
# 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
|
||||||
# everything inside inner 'or' jumps and midline ifs
|
# everything inside inner 'or' jumps and midline ifs
|
||||||
match = self.rem_or(start, self.next_stmt[offset], POP_JUMP_IF_FALSE, target)
|
match = self.rem_or(start, self.next_stmt[offset], POP_JUMP_IF_FALSE, target)
|
||||||
match = self.remove_mid_line_ifs(match)
|
match = self.remove_mid_line_ifs(match)
|
||||||
|
|
||||||
# If we still have any offsets in set, start working on it
|
# If we still have any offsets in set, start working on it
|
||||||
if match:
|
if match:
|
||||||
if (code[prev_op[rtarget]] in (JUMP_FORWARD, JUMP_ABSOLUTE) and prev_op[rtarget] not in self.stmts and
|
if (code[prev_op[rtarget]] in (JUMP_FORWARD, JUMP_ABSOLUTE) and prev_op[rtarget] not in self.stmts and
|
||||||
@@ -580,11 +582,11 @@ class Scanner3(scan.Scanner):
|
|||||||
not (code[rtarget] == JUMP_ABSOLUTE and code[rtarget+3] == POP_BLOCK and code[prev_op[prev_op[rtarget]]] != JUMP_ABSOLUTE)):
|
not (code[rtarget] == JUMP_ABSOLUTE and code[rtarget+3] == POP_BLOCK and code[prev_op[prev_op[rtarget]]] != JUMP_ABSOLUTE)):
|
||||||
rtarget = prev_op[rtarget]
|
rtarget = prev_op[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[prev_op[rtarget]] in (JUMP_ABSOLUTE, JUMP_FORWARD):
|
if code[prev_op[rtarget]] in (JUMP_ABSOLUTE, JUMP_FORWARD):
|
||||||
if_end = self.get_target(prev_op[rtarget])
|
if_end = self.get_target(prev_op[rtarget])
|
||||||
|
|
||||||
# Is this a loop not an if?
|
# Is this a loop and not an "if" statement?
|
||||||
if (if_end < prev_op[rtarget]) and (code[prev_op[if_end]] == SETUP_LOOP):
|
if (if_end < prev_op[rtarget]) and (code[prev_op[if_end]] == SETUP_LOOP):
|
||||||
if(if_end > start):
|
if(if_end > start):
|
||||||
return
|
return
|
||||||
|
Reference in New Issue
Block a user