You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
@@ -37,7 +37,7 @@ entry_points={
|
|||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.4.0',
|
install_requires = ['spark-parser >= 1.4.0',
|
||||||
'xdis >= 1.1.2']
|
'xdis >= 1.1.3']
|
||||||
license = 'MIT'
|
license = 'MIT'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
modname = 'uncompyle6'
|
modname = 'uncompyle6'
|
||||||
|
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.6/06_return_if.pyc
Normal file
BIN
test/bytecode_2.6/06_return_if.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/07_for_if_continue.pyc
Normal file
BIN
test/bytecode_2.6/07_for_if_continue.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/07_withstmt_fn.pyc
Normal file
BIN
test/bytecode_2.6/07_withstmt_fn.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
11
test/simple_source/stmts/06_return_if.py
Normal file
11
test/simple_source/stmts/06_return_if.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# from 2.6.9 Bastion.py
|
||||||
|
# Should see in 2.6.9:
|
||||||
|
# return_if_stmt ::= ret_expr RETURN_END_IF come_from_pop
|
||||||
|
|
||||||
|
def Bastion(object, filter = lambda name: name[:1] != '_'):
|
||||||
|
def get1(name, attribute, MethodType, object=object, filter=filter):
|
||||||
|
if filter(name):
|
||||||
|
attribute = getattr(object, name)
|
||||||
|
if type(attribute) == MethodType:
|
||||||
|
return attribute
|
||||||
|
raise AttributeError, name
|
16
test/simple_source/stmts/07_for_if_continue.py
Normal file
16
test/simple_source/stmts/07_for_if_continue.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Python 2.6.9 Cookie.py
|
||||||
|
# Problem in 2.6 is making sure
|
||||||
|
# the two JUMP_ABSOLUTES get turned into:
|
||||||
|
# 26 CONTINUE 7 '7'
|
||||||
|
# 29 JUMP_BACK 7 '7'
|
||||||
|
# The fact that the "continue" is on the same
|
||||||
|
# line as the "if" is important.
|
||||||
|
|
||||||
|
for K in items:
|
||||||
|
if V: continue
|
||||||
|
|
||||||
|
# 32 CONTINUE 7 '7'
|
||||||
|
# 35 JUMP_FORWARD 1 (to 39)
|
||||||
|
for K,V in items:
|
||||||
|
if V == "": continue
|
||||||
|
if K not in attrs: continue
|
11
test/simple_source/stmts/07_withstmt_fn.py
Normal file
11
test/simple_source/stmts/07_withstmt_fn.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Python 2.6 has a truly weird way of handling with here.
|
||||||
|
# added rule for 2.6
|
||||||
|
# setupwith ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 POP_TOP
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from warnings import catch_warnings
|
||||||
|
with catch_warnings():
|
||||||
|
if sys.py3kwarning:
|
||||||
|
sys.filterwarnings("ignore", ".*mimetools has been removed",
|
||||||
|
DeprecationWarning)
|
||||||
|
import mimetools
|
@@ -200,10 +200,10 @@ class PythonParser(GenericASTBuilder):
|
|||||||
_jump ::= JUMP_BACK
|
_jump ::= JUMP_BACK
|
||||||
|
|
||||||
# Note: Python < 2.7 doesn't have POP_JUMP_IF ...
|
# Note: Python < 2.7 doesn't have POP_JUMP_IF ...
|
||||||
|
# FIXME: segregate 2.7+
|
||||||
|
|
||||||
jmp_false ::= POP_JUMP_IF_FALSE
|
jmp_false ::= POP_JUMP_IF_FALSE
|
||||||
jmp_false ::= JUMP_IF_FALSE
|
|
||||||
jmp_true ::= POP_JUMP_IF_TRUE
|
jmp_true ::= POP_JUMP_IF_TRUE
|
||||||
jmp_true ::= JUMP_IF_TRUE
|
|
||||||
|
|
||||||
# Zero or more COME_FROM
|
# Zero or more COME_FROM
|
||||||
# loops can have this
|
# loops can have this
|
||||||
@@ -465,10 +465,14 @@ class PythonParser(GenericASTBuilder):
|
|||||||
_mklambda ::= load_closure mklambda
|
_mklambda ::= load_closure mklambda
|
||||||
_mklambda ::= mklambda
|
_mklambda ::= mklambda
|
||||||
|
|
||||||
|
# Note: Python < 2.7 doesn't have *POP* or this. Remove from here?
|
||||||
|
# FIXME: segregate 2.7+
|
||||||
|
|
||||||
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
|
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
|
||||||
|
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
|
||||||
|
|
||||||
or ::= expr jmp_true expr come_from_opt
|
or ::= expr jmp_true expr come_from_opt
|
||||||
and ::= expr jmp_false expr come_from_opt
|
and ::= expr jmp_false expr come_from_opt
|
||||||
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
|
|
||||||
and2 ::= _jump jmp_false COME_FROM expr COME_FROM
|
and2 ::= _jump jmp_false COME_FROM expr COME_FROM
|
||||||
|
|
||||||
expr ::= conditional
|
expr ::= conditional
|
||||||
@@ -485,6 +489,9 @@ class PythonParser(GenericASTBuilder):
|
|||||||
ret_expr_or_cond ::= ret_cond
|
ret_expr_or_cond ::= ret_cond
|
||||||
ret_expr_or_cond ::= ret_cond_not
|
ret_expr_or_cond ::= ret_cond_not
|
||||||
|
|
||||||
|
# Note: Python < 2.7 doesn't have *POP* or this. Remove from here?
|
||||||
|
# FIXME: segregate 2.7+
|
||||||
|
|
||||||
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
|
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
|
||||||
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
|
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
|
||||||
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
|
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
|
||||||
@@ -588,12 +595,25 @@ def get_python_parser(version, debug_parser, compile_mode='exec'):
|
|||||||
p = parse23.Python23Parser(debug_parser)
|
p = parse23.Python23Parser(debug_parser)
|
||||||
else:
|
else:
|
||||||
p = parse23.Python23ParserSingle(debug_parser)
|
p = parse23.Python23ParserSingle(debug_parser)
|
||||||
|
elif version == 2.5:
|
||||||
|
# For now, we'll consider 2.5 exactly like 2.6
|
||||||
|
import uncompyle6.parsers.parse26 as parse25
|
||||||
|
if compile_mode == 'exec':
|
||||||
|
p = parse25.Python26Parser(debug_parser)
|
||||||
|
else:
|
||||||
|
p = parse25.Python26ParserSingle(debug_parser)
|
||||||
elif version == 2.6:
|
elif version == 2.6:
|
||||||
import uncompyle6.parsers.parse26 as parse26
|
import uncompyle6.parsers.parse26 as parse26
|
||||||
if compile_mode == 'exec':
|
if compile_mode == 'exec':
|
||||||
p = parse26.Python26Parser(debug_parser)
|
p = parse26.Python26Parser(debug_parser)
|
||||||
else:
|
else:
|
||||||
p = parse26.Python26ParserSingle(debug_parser)
|
p = parse26.Python26ParserSingle(debug_parser)
|
||||||
|
elif version == 2.7:
|
||||||
|
import uncompyle6.parsers.parse27 as parse27
|
||||||
|
if compile_mode == 'exec':
|
||||||
|
p = parse27.Python27Parser(debug_parser)
|
||||||
|
else:
|
||||||
|
p = parse27.Python27ParserSingle(debug_parser)
|
||||||
else:
|
else:
|
||||||
import uncompyle6.parsers.parse2 as parse2
|
import uncompyle6.parsers.parse2 as parse2
|
||||||
if compile_mode == 'exec':
|
if compile_mode == 'exec':
|
||||||
|
@@ -134,7 +134,6 @@ class Python2Parser(PythonParser):
|
|||||||
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
|
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
|
||||||
classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
|
classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
|
||||||
|
|
||||||
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
|
|
||||||
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1
|
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1
|
||||||
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
|
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
|
||||||
|
|
||||||
@@ -152,7 +151,6 @@ class Python2Parser(PythonParser):
|
|||||||
testtrue ::= expr jmp_true
|
testtrue ::= expr jmp_true
|
||||||
|
|
||||||
_ifstmts_jump ::= return_if_stmts
|
_ifstmts_jump ::= return_if_stmts
|
||||||
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM
|
|
||||||
|
|
||||||
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
|
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
|
||||||
|
|
||||||
@@ -167,9 +165,6 @@ class Python2Parser(PythonParser):
|
|||||||
ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel
|
ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel
|
||||||
|
|
||||||
|
|
||||||
trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
|
||||||
try_middle COME_FROM
|
|
||||||
|
|
||||||
# this is nested inside a trystmt
|
# this is nested inside a trystmt
|
||||||
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
|
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
|
||||||
POP_BLOCK LOAD_CONST
|
POP_BLOCK LOAD_CONST
|
||||||
@@ -184,10 +179,8 @@ class Python2Parser(PythonParser):
|
|||||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
try_middle else_suitel COME_FROM
|
try_middle else_suitel COME_FROM
|
||||||
|
|
||||||
try_middle ::= jmp_abs COME_FROM except_stmts
|
trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
END_FINALLY
|
try_middle COME_FROM
|
||||||
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
|
||||||
END_FINALLY COME_FROM
|
|
||||||
|
|
||||||
except_stmts ::= except_stmts except_stmt
|
except_stmts ::= except_stmts except_stmt
|
||||||
except_stmts ::= except_stmt
|
except_stmts ::= except_stmt
|
||||||
@@ -200,12 +193,6 @@ class Python2Parser(PythonParser):
|
|||||||
except_suite ::= c_stmts_opt jmp_abs
|
except_suite ::= c_stmts_opt jmp_abs
|
||||||
except_suite ::= return_stmts
|
except_suite ::= return_stmts
|
||||||
|
|
||||||
except_cond1 ::= DUP_TOP expr COMPARE_OP
|
|
||||||
jmp_false POP_TOP POP_TOP POP_TOP
|
|
||||||
|
|
||||||
except_cond2 ::= DUP_TOP expr COMPARE_OP
|
|
||||||
jmp_false POP_TOP designator POP_TOP
|
|
||||||
|
|
||||||
except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt _jump
|
except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt _jump
|
||||||
except ::= POP_TOP POP_TOP POP_TOP return_stmts
|
except ::= POP_TOP POP_TOP POP_TOP return_stmts
|
||||||
|
|
||||||
|
@@ -14,11 +14,144 @@ class Python26Parser(Python2Parser):
|
|||||||
self.customized = {}
|
self.customized = {}
|
||||||
|
|
||||||
|
|
||||||
def p_lis_iter(self, args):
|
def p_try_except26(self, args):
|
||||||
|
"""
|
||||||
|
except_cond1 ::= DUP_TOP expr COMPARE_OP
|
||||||
|
JUMP_IF_FALSE POP_TOP POP_TOP POP_TOP POP_TOP
|
||||||
|
except_cond2 ::= DUP_TOP expr COMPARE_OP
|
||||||
|
JUMP_IF_FALSE POP_TOP POP_TOP designator POP_TOP
|
||||||
|
|
||||||
|
# Might be a bug from when COME_FROM wasn't properly handled
|
||||||
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
||||||
|
POP_TOP END_FINALLY come_froms
|
||||||
|
|
||||||
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
||||||
|
END_FINALLY come_froms
|
||||||
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
||||||
|
come_from_pop END_FINALLY come_froms
|
||||||
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
||||||
|
END_FINALLY come_froms
|
||||||
|
|
||||||
|
try_middle ::= jmp_abs COME_FROM except_stmts
|
||||||
|
POP_TOP END_FINALLY
|
||||||
|
|
||||||
|
try_middle ::= jmp_abs COME_FROM except_stmts
|
||||||
|
come_from_pop END_FINALLY
|
||||||
|
|
||||||
|
try_middle ::= jmp_abs COME_FROM except_stmts
|
||||||
|
END_FINALLY
|
||||||
|
|
||||||
|
trystmt ::= SETUP_EXCEPT suite_stmts_opt come_from_pop
|
||||||
|
try_middle
|
||||||
|
|
||||||
|
# Sometimes we don't put in COME_FROM to the next statement
|
||||||
|
# like we do in 2.7. Perhaps we should?
|
||||||
|
trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
|
try_middle
|
||||||
|
|
||||||
|
except_suite ::= c_stmts_opt JUMP_FORWARD come_from_pop
|
||||||
|
|
||||||
|
# Python 3 also has this.
|
||||||
|
come_froms ::= come_froms COME_FROM
|
||||||
|
come_froms ::= COME_FROM
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# In contrast to Python 2.7, Python 2.6 has a lot of
|
||||||
|
# POP_TOP's which come right after various jumps.
|
||||||
|
# The COME_FROM instructions our scanner adds, here it is to assist
|
||||||
|
# distinguishing the extraneous POP_TOPs from those that start
|
||||||
|
# after one of these jumps
|
||||||
|
def p_jumps26(self, args):
|
||||||
|
"""
|
||||||
|
jmp_false ::= JUMP_IF_FALSE
|
||||||
|
jmp_true ::= JUMP_IF_TRUE
|
||||||
|
jmp_true ::= JUMP_IF_TRUE POP_TOP
|
||||||
|
jmp_false ::= JUMP_IF_FALSE POP_TOP
|
||||||
|
jf_pop ::= JUMP_FORWARD come_from_pop
|
||||||
|
jb_pop ::= JUMP_BACK come_from_pop
|
||||||
|
|
||||||
|
jb_cf_pop ::= JUMP_BACK come_froms POP_TOP
|
||||||
|
ja_cf_pop ::= JUMP_ABSOLUTE come_from_pop
|
||||||
|
|
||||||
|
_ifstmts_jump ::= c_stmts_opt jf_pop COME_FROM
|
||||||
|
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM come_from_pop
|
||||||
|
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms POP_TOP COME_FROM
|
||||||
|
|
||||||
|
# This is what happens after a jump where
|
||||||
|
# we start a new block. For reasons I don't fully
|
||||||
|
# understand, there is also a value on the top of the stack
|
||||||
|
come_from_pop ::= COME_FROM POP_TOP
|
||||||
|
"""
|
||||||
|
|
||||||
|
def p_stmt26(self, args):
|
||||||
|
"""
|
||||||
|
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 come_from_pop
|
||||||
|
|
||||||
|
ifelsestmt ::= testexpr c_stmts_opt jf_pop else_suite COME_FROM
|
||||||
|
ifelsestmt ::= testexpr c_stmts_opt else_suitel come_froms POP_TOP
|
||||||
|
|
||||||
|
# Semantic actions want else_suitel to be at index 2 or 3
|
||||||
|
ifelsestmtl ::= testexpr c_stmts_opt jb_cf_pop else_suitel
|
||||||
|
ifelsestmtc ::= testexpr c_stmts_opt ja_cf_pop else_suitec
|
||||||
|
|
||||||
|
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP
|
||||||
|
|
||||||
|
# Semantic actions want suite_stmts_opt to be at index 3
|
||||||
|
withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt
|
||||||
|
POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY
|
||||||
|
|
||||||
|
# This is truly weird. 2.7 does this (not including POP_TOP) with
|
||||||
|
# opcode SETUP_WITH
|
||||||
|
setupwith ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 POP_TOP
|
||||||
|
|
||||||
|
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK _come_from
|
||||||
|
|
||||||
|
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop POP_BLOCK COME_FROM
|
||||||
|
|
||||||
|
return_if_stmt ::= ret_expr RETURN_END_IF come_from_pop
|
||||||
|
|
||||||
|
iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK come_from_pop
|
||||||
|
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_from_pop
|
||||||
|
"""
|
||||||
|
|
||||||
|
def p_comp26(self, args):
|
||||||
'''
|
'''
|
||||||
list_iter ::= list_if JUMP_BACK
|
list_for ::= expr _for designator list_iter JUMP_BACK come_froms POP_TOP
|
||||||
|
|
||||||
|
list_iter ::= list_if JUMP_BACK
|
||||||
|
list_compr ::= BUILD_LIST_0 DUP_TOP
|
||||||
|
designator list_iter del_stmt
|
||||||
|
list_compr ::= BUILD_LIST_0 DUP_TOP
|
||||||
|
designator list_iter JUMP_BACK del_stmt
|
||||||
|
lc_body ::= LOAD_NAME expr LIST_APPEND
|
||||||
|
lc_body ::= LOAD_FAST expr LIST_APPEND
|
||||||
|
|
||||||
|
# Make sure we keep indices the same as 2.7
|
||||||
|
setup_loop_lf ::= SETUP_LOOP LOAD_FAST
|
||||||
|
genexpr_func ::= setup_loop_lf FOR_ITER designator comp_iter JUMP_BACK POP_BLOCK COME_FROM
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
def p_ret26(self, args):
|
||||||
|
'''
|
||||||
|
ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM
|
||||||
|
ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM
|
||||||
|
ret_cond ::= expr jmp_false expr RETURN_END_IF come_from_pop ret_expr_or_cond
|
||||||
|
ret_cond ::= expr jmp_false expr ret_expr_or_cond
|
||||||
|
ret_cond_not ::= expr jmp_true expr RETURN_END_IF come_from_pop ret_expr_or_cond
|
||||||
|
|
||||||
|
# FIXME: split into Python 2.5
|
||||||
|
ret_cond ::= expr jmp_false expr JUMP_RETURN come_from_pop ret_expr_or_cond
|
||||||
|
ret_or ::= expr jmp_true ret_expr_or_cond come_froms
|
||||||
|
'''
|
||||||
|
|
||||||
|
def p_except26(self, args):
|
||||||
|
'''
|
||||||
|
except_suite ::= c_stmts_opt jmp_abs new_block
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Python26ParserSingle(Python2Parser, PythonParserSingle):
|
class Python26ParserSingle(Python2Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
37
uncompyle6/parsers/parse27.py
Normal file
37
uncompyle6/parsers/parse27.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from uncompyle6.parser import PythonParserSingle
|
||||||
|
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||||
|
from uncompyle6.parsers.parse2 import Python2Parser
|
||||||
|
|
||||||
|
class Python27Parser(Python2Parser):
|
||||||
|
|
||||||
|
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
|
||||||
|
super(Python27Parser, self).__init__(debug_parser)
|
||||||
|
self.customized = {}
|
||||||
|
|
||||||
|
def p_try27(self, args):
|
||||||
|
"""
|
||||||
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts
|
||||||
|
END_FINALLY COME_FROM
|
||||||
|
try_middle ::= jmp_abs COME_FROM except_stmts
|
||||||
|
END_FINALLY
|
||||||
|
|
||||||
|
except_cond1 ::= DUP_TOP expr COMPARE_OP
|
||||||
|
jmp_false POP_TOP POP_TOP POP_TOP
|
||||||
|
|
||||||
|
except_cond2 ::= DUP_TOP expr COMPARE_OP
|
||||||
|
jmp_false POP_TOP designator POP_TOP
|
||||||
|
"""
|
||||||
|
|
||||||
|
def p_misc27(self, args):
|
||||||
|
"""
|
||||||
|
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
|
||||||
|
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Python27ParserSingle(Python27Parser, PythonParserSingle):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Check grammar
|
||||||
|
p = Python27Parser()
|
||||||
|
p.checkGrammar()
|
@@ -358,6 +358,12 @@ class Scanner2(scan.Scanner):
|
|||||||
except_match = self.first_instr(start, len(self.code), self.opc.PJIF)
|
except_match = self.first_instr(start, len(self.code), self.opc.PJIF)
|
||||||
if except_match:
|
if except_match:
|
||||||
jmp = self.prev[self.get_target(except_match)]
|
jmp = self.prev[self.get_target(except_match)]
|
||||||
|
|
||||||
|
# In Python <= 2.6 we may have jumps to jumps
|
||||||
|
if self.version <= 2.6 and self.code[jmp] in self.jump_forward:
|
||||||
|
self.not_continue.add(jmp)
|
||||||
|
jmp = self.get_target(jmp)
|
||||||
|
|
||||||
self.ignore_if.add(except_match)
|
self.ignore_if.add(except_match)
|
||||||
self.not_continue.add(jmp)
|
self.not_continue.add(jmp)
|
||||||
return jmp
|
return jmp
|
||||||
@@ -508,10 +514,12 @@ class Scanner2(scan.Scanner):
|
|||||||
# Add the try-else block
|
# Add the try-else block
|
||||||
if end_else != start_else:
|
if end_else != start_else:
|
||||||
r_end_else = self.restrict_to_parent(end_else, parent)
|
r_end_else = self.restrict_to_parent(end_else, parent)
|
||||||
self.structs.append({'type': 'try-else',
|
# May be able to drop the 2.7 test.
|
||||||
'start': i+1,
|
if self.version == 2.7:
|
||||||
'end': r_end_else})
|
self.structs.append({'type': 'try-else',
|
||||||
self.fixed_jumps[i] = r_end_else
|
'start': i+1,
|
||||||
|
'end': r_end_else})
|
||||||
|
self.fixed_jumps[i] = r_end_else
|
||||||
else:
|
else:
|
||||||
self.fixed_jumps[i] = i+1
|
self.fixed_jumps[i] = i+1
|
||||||
|
|
||||||
@@ -691,7 +699,8 @@ class Scanner2(scan.Scanner):
|
|||||||
if op in self.opc.hasjrel and op != self.opc.FOR_ITER:
|
if op in self.opc.hasjrel and op != self.opc.FOR_ITER:
|
||||||
label = i + 3 + oparg
|
label = i + 3 + oparg
|
||||||
elif self.version == 2.7 and op in self.opc.hasjabs:
|
elif self.version == 2.7 and op in self.opc.hasjabs:
|
||||||
if op in (self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP):
|
if op in (self.opc.JUMP_IF_FALSE_OR_POP,
|
||||||
|
self.opc.JUMP_IF_TRUE_OR_POP):
|
||||||
if (oparg > i):
|
if (oparg > i):
|
||||||
label = oparg
|
label = oparg
|
||||||
|
|
||||||
|
@@ -70,350 +70,3 @@ class Scanner25(scan.Scanner26):
|
|||||||
# Add an empty set make processing more uniform.
|
# Add an empty set make processing more uniform.
|
||||||
self.pop_jump_if_or_pop = frozenset([])
|
self.pop_jump_if_or_pop = frozenset([])
|
||||||
return
|
return
|
||||||
|
|
||||||
def restructCode(self, listDel, listExp):
|
|
||||||
'''
|
|
||||||
restruct linestarts and jump destination
|
|
||||||
'''
|
|
||||||
# restruct linestarts with deleted / modificated opcode
|
|
||||||
result = list()
|
|
||||||
for block in self.linestarts:
|
|
||||||
startBlock = 0
|
|
||||||
for toDel in listDel:
|
|
||||||
if toDel < block[0]:
|
|
||||||
startBlock -= self.op_size(self.code[toDel])
|
|
||||||
for toExp in listExp:
|
|
||||||
if toExp < block[0]:
|
|
||||||
startBlock += 2
|
|
||||||
result.append((block[0]+startBlock, block[1]))
|
|
||||||
self.linestarts = result
|
|
||||||
# handle opcodeToChange deplacement
|
|
||||||
for index in range(len(self.toChange)):
|
|
||||||
change = self.toChange[index]
|
|
||||||
delta = 0
|
|
||||||
for toDel in listDel:
|
|
||||||
if change > toDel:
|
|
||||||
delta -= self.op_size(self.code[toDel])
|
|
||||||
for toExp in listExp:
|
|
||||||
if change > toExp:
|
|
||||||
delta += 2
|
|
||||||
self.toChange[index] += delta
|
|
||||||
# restruct jmp opcode
|
|
||||||
if listDel:
|
|
||||||
for jmp in self.op_range(0, len(self.code)):
|
|
||||||
op = self.code[jmp]
|
|
||||||
if op in self.opc.hasjrel + self.opc.hasjabs:
|
|
||||||
offset = 0
|
|
||||||
jmpTarget = self.get_target(jmp)
|
|
||||||
for toDel in listDel:
|
|
||||||
if toDel < jmpTarget:
|
|
||||||
if op in self.opc.hasjabs or jmp < toDel:
|
|
||||||
offset-=self.op_size(self.code[toDel])
|
|
||||||
self.restructJump(jmp, jmpTarget+offset)
|
|
||||||
if listExp:
|
|
||||||
jmp = 0
|
|
||||||
while jmp < len(self.code): # we can't use op_range for the moment
|
|
||||||
op = self.code[jmp]
|
|
||||||
if op in self.opc.hasjrel + self.opc.hasjabs:
|
|
||||||
offset = 0
|
|
||||||
jmpTarget = self.get_target(jmp)
|
|
||||||
for toExp in listExp:
|
|
||||||
if toExp < jmpTarget:
|
|
||||||
if op in self.opc.hasjabs or jmp < toExp:
|
|
||||||
offset+=2
|
|
||||||
self.restructJump(jmp, jmpTarget+offset)
|
|
||||||
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
|
||||||
jmp += 3
|
|
||||||
else: jmp += 1
|
|
||||||
|
|
||||||
def restructBytecode(self):
|
|
||||||
'''
|
|
||||||
add/change/delete bytecode for suiting bytecode 2.7
|
|
||||||
'''
|
|
||||||
# we can't use op_range for the moment
|
|
||||||
# convert jump opcode to 2.7
|
|
||||||
self.restructRelativeJump()
|
|
||||||
|
|
||||||
listExp = self.getOpcodeToExp()
|
|
||||||
# change code structure
|
|
||||||
if listExp:
|
|
||||||
listExp = sorted(list(set(listExp)))
|
|
||||||
self.restructCode([], listExp)
|
|
||||||
# we add arg to expended opcode
|
|
||||||
offset=0
|
|
||||||
for toExp in listExp:
|
|
||||||
self.code.insert(toExp+offset+1, 0)
|
|
||||||
self.code.insert(toExp+offset+1, 0)
|
|
||||||
offset+=2
|
|
||||||
# op_range is now ok :)
|
|
||||||
# add instruction to change in "toChange" list + MAJ toDel
|
|
||||||
listDel = []
|
|
||||||
for i in self.op_range(0, len(self.code)):
|
|
||||||
ret = self.getOpcodeToDel(i)
|
|
||||||
if ret is not None:
|
|
||||||
listDel += ret
|
|
||||||
|
|
||||||
# change code structure after deleting byte
|
|
||||||
if listDel:
|
|
||||||
listDel = sorted(list(set(listDel)))
|
|
||||||
self.restructCode(listDel, [])
|
|
||||||
# finaly we delete useless opcode
|
|
||||||
delta = 0
|
|
||||||
for x in listDel:
|
|
||||||
if self.op_hasArgument(self.code[x-delta]):
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 3
|
|
||||||
else:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 1
|
|
||||||
|
|
||||||
def detect_structure(self, pos, op=None):
|
|
||||||
'''
|
|
||||||
Detect type of block structures and their boundaries to fix optimizied jumps
|
|
||||||
in python2.3+
|
|
||||||
'''
|
|
||||||
|
|
||||||
code = self.code
|
|
||||||
# Ev remove this test and make op a mandatory argument -Dan
|
|
||||||
if op is None:
|
|
||||||
op = code[pos]
|
|
||||||
|
|
||||||
# Detect parent structure
|
|
||||||
parent = self.structs[0]
|
|
||||||
start = parent['start']
|
|
||||||
end = parent['end']
|
|
||||||
for s in self.structs:
|
|
||||||
_start = s['start']
|
|
||||||
_end = s['end']
|
|
||||||
if (_start <= pos < _end) and (_start >= start and _end <= end):
|
|
||||||
start = _start
|
|
||||||
end = _end
|
|
||||||
parent = s
|
|
||||||
# We need to know how many new structures were added in this run
|
|
||||||
|
|
||||||
|
|
||||||
if op == self.opc.SETUP_LOOP:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
|
|
||||||
if target != end:
|
|
||||||
self.fixed_jumps[pos] = end
|
|
||||||
|
|
||||||
(line_no, next_line_byte) = self.lines[pos]
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JA, next_line_byte, False)
|
|
||||||
if jump_back and jump_back != self.prev[end] and code[jump_back+3] in (JA, JF):
|
|
||||||
if code[self.prev[end]] == RETURN_VALUE or \
|
|
||||||
(code[self.prev[end]] == POP_BLOCK and code[self.prev[self.prev[end]]] == RETURN_VALUE):
|
|
||||||
jump_back = None
|
|
||||||
if not jump_back: # loop suite ends in return. wtf right?
|
|
||||||
jump_back = self.last_instr(start, end, RETURN_VALUE)
|
|
||||||
if not jump_back:
|
|
||||||
return
|
|
||||||
jump_back += 1
|
|
||||||
if code[self.prev[next_line_byte]] not in self.pop_jump_if:
|
|
||||||
loop_type = 'for'
|
|
||||||
else:
|
|
||||||
loop_type = 'while'
|
|
||||||
self.ignore_if.add(self.prev[next_line_byte])
|
|
||||||
target = next_line_byte
|
|
||||||
end = jump_back + 3
|
|
||||||
else:
|
|
||||||
if self.get_target(jump_back) >= next_line_byte:
|
|
||||||
jump_back = self.last_instr(start, end, JA,
|
|
||||||
start, False)
|
|
||||||
if end > jump_back+4 and code[end] in (JF, JA):
|
|
||||||
if code[jump_back+4] in (JA, JF):
|
|
||||||
if self.get_target(jump_back+4) == self.get_target(end):
|
|
||||||
self.fixed_jumps[pos] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
elif target < pos:
|
|
||||||
self.fixed_jumps[pos] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
|
|
||||||
target = self.get_target(jump_back, self.opc.JA)
|
|
||||||
|
|
||||||
if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
|
|
||||||
loop_type = 'for'
|
|
||||||
else:
|
|
||||||
loop_type = 'while'
|
|
||||||
test = self.prev[next_line_byte]
|
|
||||||
if test == pos:
|
|
||||||
loop_type = 'while 1'
|
|
||||||
elif self.code[test] in self.opc.hasjabs + self.opc.hasjrel:
|
|
||||||
self.ignore_if.add(test)
|
|
||||||
test_target = self.get_target(test)
|
|
||||||
if test_target > (jump_back+3):
|
|
||||||
jump_back = test_target
|
|
||||||
self.not_continue.add(jump_back)
|
|
||||||
self.loops.append(target)
|
|
||||||
self.structs.append({'type': loop_type + '-loop',
|
|
||||||
'start': target,
|
|
||||||
'end': jump_back})
|
|
||||||
if jump_back+3 != end:
|
|
||||||
self.structs.append({'type': loop_type + '-else',
|
|
||||||
'start': jump_back+3,
|
|
||||||
'end': end})
|
|
||||||
elif op == self.opc.SETUP_EXCEPT:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
if target != end:
|
|
||||||
self.fixed_jumps[pos] = end
|
|
||||||
# Add the try block
|
|
||||||
self.structs.append({'type': 'try',
|
|
||||||
'start': start,
|
|
||||||
'end': end-4})
|
|
||||||
# Now isolate the except and else blocks
|
|
||||||
end_else = start_else = self.get_target(self.prev[end])
|
|
||||||
|
|
||||||
# Add the except blocks
|
|
||||||
i = end
|
|
||||||
while i < len(self.code) and self.code[i] != self.opc.END_FINALLY:
|
|
||||||
jmp = self.next_except_jump(i)
|
|
||||||
if jmp is None: # check
|
|
||||||
i = self.next_stmt[i]
|
|
||||||
continue
|
|
||||||
if self.code[jmp] == self.opc.RETURN_VALUE:
|
|
||||||
self.structs.append({'type': 'except',
|
|
||||||
'start': i,
|
|
||||||
'end': jmp+1})
|
|
||||||
i = jmp + 1
|
|
||||||
else:
|
|
||||||
if self.get_target(jmp) != start_else:
|
|
||||||
end_else = self.get_target(jmp)
|
|
||||||
if self.code[jmp] == self.opc.JF:
|
|
||||||
self.fixed_jumps[jmp] = -1
|
|
||||||
self.structs.append({'type': 'except',
|
|
||||||
'start': i,
|
|
||||||
'end': jmp})
|
|
||||||
i = jmp + 3
|
|
||||||
|
|
||||||
# Add the try-else block
|
|
||||||
if end_else != start_else:
|
|
||||||
r_end_else = self.restrict_to_parent(end_else, parent)
|
|
||||||
self.structs.append({'type': 'try-else',
|
|
||||||
'start': i+2, # check
|
|
||||||
'end': r_end_else})
|
|
||||||
self.fixed_jumps[i] = r_end_else
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[i] = i+1
|
|
||||||
|
|
||||||
elif op in self.pop_jump_if:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
rtarget = self.restrict_to_parent(target, parent)
|
|
||||||
pre = self.prev
|
|
||||||
|
|
||||||
if target != rtarget and parent['type'] == 'and/or':
|
|
||||||
self.fixed_jumps[pos] = rtarget
|
|
||||||
return
|
|
||||||
# does this jump to right after another cond jump?
|
|
||||||
# if so, it's part of a larger conditional
|
|
||||||
if (code[pre[target]] in (PJIF, PJIT)) and (target > pos):
|
|
||||||
self.fixed_jumps[pos] = pre[target]
|
|
||||||
self.structs.append({'type': 'and/or',
|
|
||||||
'start': start,
|
|
||||||
'end': pre[target]})
|
|
||||||
return
|
|
||||||
|
|
||||||
# is this an if and
|
|
||||||
if op == PJIF:
|
|
||||||
match = self.rem_or(start, self.next_stmt[pos], PJIF, target)
|
|
||||||
match = self.remove_mid_line_ifs(match)
|
|
||||||
if match:
|
|
||||||
if code[pre[rtarget]] in (JF, JA) \
|
|
||||||
and pre[rtarget] not in self.stmts \
|
|
||||||
and self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget:
|
|
||||||
if code[pre[pre[rtarget]]] == JA \
|
|
||||||
and self.remove_mid_line_ifs([pos]) \
|
|
||||||
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 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], (PJIF, PJIT), target))):
|
|
||||||
pass
|
|
||||||
elif code[pre[pre[rtarget]]] == RETURN_VALUE \
|
|
||||||
and self.remove_mid_line_ifs([pos]) \
|
|
||||||
and 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]],
|
|
||||||
(PJIF, PJIT), target)))
|
|
||||||
| set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]],
|
|
||||||
(PJIF, PJIT, JA), pre[rtarget], True))))):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
fix = None
|
|
||||||
jump_ifs = self.all_instr(start, self.next_stmt[pos], PJIF)
|
|
||||||
last_jump_good = True
|
|
||||||
for j in jump_ifs:
|
|
||||||
if target == self.get_target(j):
|
|
||||||
if self.lines[j].next == j+3 and last_jump_good:
|
|
||||||
fix = j
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
last_jump_good = False
|
|
||||||
self.fixed_jumps[pos] = fix or match[-1]
|
|
||||||
return
|
|
||||||
elif pos < rtarget and code[target] == self.opc.ROT_TWO:
|
|
||||||
self.fixed_jumps[pos] = target
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[pos] = match[-1]
|
|
||||||
return
|
|
||||||
else: # op == PJIT
|
|
||||||
if (pos+3) in self.load_asserts:
|
|
||||||
if code[pre[rtarget]] == self.opc.RAISE_VARARGS:
|
|
||||||
return
|
|
||||||
self.load_asserts.remove(pos+3)
|
|
||||||
|
|
||||||
next = self.next_stmt[pos]
|
|
||||||
if pre[next] == pos:
|
|
||||||
pass
|
|
||||||
elif code[next] in (JF, JA) and target == self.get_target(next):
|
|
||||||
if code[pre[next]] == PJIF:
|
|
||||||
if code[next] == JF or target != rtarget or code[pre[pre[rtarget]]] not in (JA, RETURN_VALUE):
|
|
||||||
self.fixed_jumps[pos] = pre[next]
|
|
||||||
return
|
|
||||||
elif code[next] == JA and code[target] in (JA, JF) \
|
|
||||||
and self.get_target(target) == self.get_target(next):
|
|
||||||
self.fixed_jumps[pos] = pre[next]
|
|
||||||
return
|
|
||||||
# don't add a struct for a while test, it's already taken care of
|
|
||||||
if pos in self.ignore_if:
|
|
||||||
return
|
|
||||||
|
|
||||||
if code[pre[rtarget]] == JA and pre[rtarget] in self.stmts \
|
|
||||||
and pre[rtarget] != pos and pre[pre[rtarget]] != pos \
|
|
||||||
and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA):
|
|
||||||
rtarget = pre[rtarget]
|
|
||||||
# does the if jump just beyond a jump op, then this is probably an if statement
|
|
||||||
if code[pre[rtarget]] in (JA, JF):
|
|
||||||
if_end = self.get_target(pre[rtarget])
|
|
||||||
|
|
||||||
# is this a loop not an if?
|
|
||||||
if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.SETUP_LOOP):
|
|
||||||
if(if_end > start):
|
|
||||||
return
|
|
||||||
|
|
||||||
end = self.restrict_to_parent(if_end, parent)
|
|
||||||
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': pre[rtarget]})
|
|
||||||
self.not_continue.add(pre[rtarget])
|
|
||||||
|
|
||||||
if rtarget < end:
|
|
||||||
self.structs.append({'type': 'if-else',
|
|
||||||
'start': rtarget,
|
|
||||||
'end': end})
|
|
||||||
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 pos < rtarget and code[rtarget] == self.opc.ROT_TWO:
|
|
||||||
return
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': rtarget})
|
|
||||||
self.return_end_ifs.add(pre[rtarget])
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
return
|
|
||||||
pass
|
|
||||||
|
@@ -10,6 +10,11 @@ other versions of Python. Also, we save token information for later
|
|||||||
use in deparsing.
|
use in deparsing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from uncompyle6 import PYTHON3
|
||||||
|
if PYTHON3:
|
||||||
|
intern = sys.intern
|
||||||
|
|
||||||
from xdis.bytecode import findlinestarts
|
from xdis.bytecode import findlinestarts
|
||||||
import uncompyle6.scanners.scanner2 as scan
|
import uncompyle6.scanners.scanner2 as scan
|
||||||
|
|
||||||
@@ -120,16 +125,21 @@ class Scanner26(scan.Scanner2):
|
|||||||
|
|
||||||
# list of instruction to remove/add or change to match with bytecode 2.7
|
# list of instruction to remove/add or change to match with bytecode 2.7
|
||||||
self.toChange = []
|
self.toChange = []
|
||||||
self.restructBytecode()
|
# Rocky: the restructure code isn't adjusting linestarts
|
||||||
|
# and this causes problems
|
||||||
|
# self.restructBytecode()
|
||||||
codelen = len(self.code)
|
codelen = len(self.code)
|
||||||
|
|
||||||
self.build_prev_op(codelen)
|
self.build_prev_op(codelen)
|
||||||
|
|
||||||
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] == self.opc.PJIT and self.code[i + 3] == self.opc.LOAD_GLOBAL:
|
if (self.code[i] == self.opc.JUMP_IF_TRUE and
|
||||||
if names[self.get_argument(i+3)] == 'AssertionError':
|
i + 4 < codelen and
|
||||||
self.load_asserts.add(i+3)
|
self.code[i+3] == self.opc.POP_TOP and
|
||||||
|
self.code[i+4] == self.opc.LOAD_GLOBAL):
|
||||||
|
if names[self.get_argument(i+4)] == 'AssertionError':
|
||||||
|
self.load_asserts.add(i+4)
|
||||||
|
|
||||||
cf = self.find_jump_targets()
|
cf = self.find_jump_targets()
|
||||||
# contains (code, [addrRefToCode])
|
# contains (code, [addrRefToCode])
|
||||||
@@ -170,6 +180,7 @@ class Scanner26(scan.Scanner2):
|
|||||||
tokens.append(Token('COME_FROM', None, repr(j),
|
tokens.append(Token('COME_FROM', None, repr(j),
|
||||||
offset="%s_%d" % (offset, k) ))
|
offset="%s_%d" % (offset, k) ))
|
||||||
k += 1
|
k += 1
|
||||||
|
|
||||||
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
|
||||||
@@ -206,6 +217,17 @@ class Scanner26(scan.Scanner2):
|
|||||||
pattr = names[oparg]
|
pattr = names[oparg]
|
||||||
elif op in self.opc.hasjrel:
|
elif op in self.opc.hasjrel:
|
||||||
pattr = repr(offset + 3 + oparg)
|
pattr = repr(offset + 3 + oparg)
|
||||||
|
if op == self.opc.JUMP_FORWARD:
|
||||||
|
target = self.get_target(offset)
|
||||||
|
if target > offset and self.code[target] == self.opc.RETURN_VALUE:
|
||||||
|
# Python 2.5 sometimes has this
|
||||||
|
op_name = 'JUMP_RETURN'
|
||||||
|
# FIXME: this is a hack to catch stuff like:
|
||||||
|
# if x: continue
|
||||||
|
# the "continue" is not on a new line.
|
||||||
|
if tokens[-1].type == 'JUMP_BACK':
|
||||||
|
tokens[-1].type = intern('CONTINUE')
|
||||||
|
|
||||||
elif op in self.opc.hasjabs:
|
elif op in self.opc.hasjabs:
|
||||||
pattr = repr(oparg)
|
pattr = repr(oparg)
|
||||||
elif op in self.opc.haslocal:
|
elif op in self.opc.haslocal:
|
||||||
@@ -234,12 +256,17 @@ class Scanner26(scan.Scanner2):
|
|||||||
target = self.get_target(offset)
|
target = self.get_target(offset)
|
||||||
if target < offset:
|
if target < offset:
|
||||||
if (offset in self.stmts
|
if (offset in self.stmts
|
||||||
and self.code[offset + 3] not in (self.opc.END_FINALLY,
|
and self.code[offset+3] not in (self.opc.END_FINALLY,
|
||||||
self.opc.POP_BLOCK)
|
self.opc.POP_BLOCK)
|
||||||
and offset not in self.not_continue):
|
and offset not in self.not_continue):
|
||||||
op_name = 'CONTINUE'
|
op_name = 'CONTINUE'
|
||||||
else:
|
else:
|
||||||
op_name = 'JUMP_BACK'
|
op_name = 'JUMP_BACK'
|
||||||
|
# FIXME: this is a hack to catch stuff like:
|
||||||
|
# if x: continue
|
||||||
|
# the "continue" is not on a new line.
|
||||||
|
if tokens[-1].type == 'JUMP_BACK':
|
||||||
|
tokens[-1].type = intern('CONTINUE')
|
||||||
|
|
||||||
elif op == self.opc.LOAD_GLOBAL:
|
elif op == self.opc.LOAD_GLOBAL:
|
||||||
if offset in self.load_asserts:
|
if offset in self.load_asserts:
|
||||||
@@ -266,553 +293,6 @@ class Scanner26(scan.Scanner2):
|
|||||||
print()
|
print()
|
||||||
return tokens, customize
|
return tokens, customize
|
||||||
|
|
||||||
def getOpcodeToDel(self, i):
|
|
||||||
'''
|
|
||||||
check validity of the opcode at position I and return a list of opcode to delete
|
|
||||||
'''
|
|
||||||
opcode = self.code[i]
|
|
||||||
opsize = self.op_size(opcode)
|
|
||||||
|
|
||||||
if i+opsize >= len(self.code):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if opcode == self.opc.EXTENDED_ARG:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
# modification of some jump structures
|
|
||||||
if opcode in (self.opc.PJIF,
|
|
||||||
self.opc.PJIT,
|
|
||||||
self.opc.JA,
|
|
||||||
self.opc.JF,
|
|
||||||
self.opc.RETURN_VALUE):
|
|
||||||
toDel = []
|
|
||||||
# del POP_TOP
|
|
||||||
if self.code[i+opsize] == self.opc.POP_TOP:
|
|
||||||
if self.code[i+opsize] == self.code[i+opsize+1] and self.code[i+opsize] == self.code[i+opsize+2] \
|
|
||||||
and opcode in self.jump_forward and self.code[i+opsize] != self.code[i+opsize+3]:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
toDel += [i+opsize]
|
|
||||||
# conditional tuple (not optimal at all, no good solution...)
|
|
||||||
if self.code[i] == self.opc.JA and self.code[i+opsize] == self.opc.POP_TOP \
|
|
||||||
and self.code[i+opsize+1] == self.opc.JA and self.code[i+opsize+4] == self.opc.POP_BLOCK:
|
|
||||||
jmpabs1target = self.get_target(i)
|
|
||||||
jmpabs2target = self.get_target(i+opsize+1)
|
|
||||||
if jmpabs1target == jmpabs2target and self.code[jmpabs1target] == self.opc.FOR_ITER \
|
|
||||||
and self.code[jmpabs1target-1] != self.opc.GET_ITER:
|
|
||||||
destFor = self.get_target(jmpabs1target)
|
|
||||||
if destFor == i+opsize+4:
|
|
||||||
setupLoop = self.last_instr(0, jmpabs1target, self.opc.SETUP_LOOP)
|
|
||||||
standarFor = self.last_instr(setupLoop, jmpabs1target, self.opc.GET_ITER)
|
|
||||||
if standarFor is None:
|
|
||||||
self.restructJump(jmpabs1target, destFor+self.op_size(self.opc.POP_BLOCK))
|
|
||||||
toDel += [setupLoop, i+opsize+1, i+opsize+4]
|
|
||||||
|
|
||||||
if len(toDel) > 0:
|
|
||||||
return toDel
|
|
||||||
return None
|
|
||||||
# raise_varagsis not really handled for the moment
|
|
||||||
if opcode == self.opc.RAISE_VARARGS:
|
|
||||||
if self.code[i+opsize] == self.opc.POP_TOP:
|
|
||||||
return [i+opsize]
|
|
||||||
|
|
||||||
# modification of list structure
|
|
||||||
if opcode == self.opc.BUILD_LIST:
|
|
||||||
if (self.code[i+opsize] == self.opc.DUP_TOP and
|
|
||||||
self.code[i+opsize+1] in (self.opc.STORE_NAME, self.opc.STORE_FAST)):
|
|
||||||
# del DUP/STORE_NAME x
|
|
||||||
toDel = [i+opsize, i+opsize+1]
|
|
||||||
nameDel = self.get_argument(i+opsize+1)
|
|
||||||
start = i+opsize+1
|
|
||||||
end = start
|
|
||||||
# del LOAD_NAME x
|
|
||||||
while end < len(self.code):
|
|
||||||
end = self.first_instr(end, len(self.code), (self.opc.LOAD_NAME, self.opc.LOAD_FAST))
|
|
||||||
if nameDel == self.get_argument(end):
|
|
||||||
toDel += [end]
|
|
||||||
break
|
|
||||||
if self.code[end] == self.opc.LOAD_NAME:
|
|
||||||
end += self.op_size(self.opc.LOAD_NAME)
|
|
||||||
else:
|
|
||||||
end += self.op_size(self.opc.LOAD_FAST)
|
|
||||||
# log JA/POP_TOP to del and update PJIF
|
|
||||||
while start < end:
|
|
||||||
start = self.first_instr(start, end, self.pop_jump_if)
|
|
||||||
if start is None: break
|
|
||||||
target = self.get_target(start)
|
|
||||||
if self.code[target] == self.opc.POP_TOP and self.code[target-3] == self.opc.JA:
|
|
||||||
toDel += [target, target-3]
|
|
||||||
# update PJIF
|
|
||||||
target = self.get_target(target-3)
|
|
||||||
self.restructJump(start, target)
|
|
||||||
start += self.op_size(self.opc.PJIF)
|
|
||||||
# del DELETE_NAME x
|
|
||||||
start = end
|
|
||||||
while end < len(self.code):
|
|
||||||
end = self.first_instr(end, len(self.code),
|
|
||||||
(self.opc.DELETE_NAME, self.opc.DELETE_FAST))
|
|
||||||
if end:
|
|
||||||
if nameDel == self.get_argument(end):
|
|
||||||
toDel += [end]
|
|
||||||
break
|
|
||||||
if self.code[end] == self.opc.DELETE_NAME:
|
|
||||||
end += self.op_size(self.opc.DELETE_NAME)
|
|
||||||
else:
|
|
||||||
end += self.op_size(self.opc.DELETE_FAST)
|
|
||||||
return toDel
|
|
||||||
# for / while struct
|
|
||||||
if opcode == self.opc.SETUP_LOOP:
|
|
||||||
# change join(for..) struct
|
|
||||||
if self.code[i+3] == self.opc.LOAD_FAST and self.code[i+6] == self.opc.FOR_ITER:
|
|
||||||
end = self.first_instr(i, len(self.code), self.opc.RETURN_VALUE)
|
|
||||||
end = self.first_instr(i, end, self.opc.YIELD_VALUE)
|
|
||||||
if end and self.code[end+1] == self.opc.POP_TOP and self.code[end+2] == self.opc.JA and self.code[end+5] == self.opc.POP_BLOCK:
|
|
||||||
return [i, end+5]
|
|
||||||
# with stmt
|
|
||||||
if opcode == self.opc.WITH_CLEANUP:
|
|
||||||
allRot = self.all_instr(0, i, (self.opc.ROT_TWO))
|
|
||||||
chckRot = -1
|
|
||||||
for rot in allRot:
|
|
||||||
if self.code[rot+1] == self.opc.LOAD_ATTR and self.code[rot-3] == self.opc.LOAD_ATTR \
|
|
||||||
and self.code[rot-4] == self.opc.DUP_TOP:
|
|
||||||
chckRot = rot
|
|
||||||
assert chckRot > 0
|
|
||||||
toDel = [chckRot-4, chckRot-3, chckRot]
|
|
||||||
chckStp = -1
|
|
||||||
allSetup = self.all_instr(chckRot+1, i, (self.opc.SETUP_FINALLY))
|
|
||||||
for stp in allSetup:
|
|
||||||
if i == self.get_target(stp):
|
|
||||||
chckStp = stp
|
|
||||||
assert chckStp > 0
|
|
||||||
toDel += [chckStp]
|
|
||||||
chckDel = chckRot+1+self.op_size(self.code[chckRot+1])
|
|
||||||
while chckDel < chckStp-3:
|
|
||||||
toDel += [chckDel]
|
|
||||||
chckDel += self.op_size(self.code[chckDel])
|
|
||||||
if (self.code[chckStp-3] in (self.opc.STORE_NAME, self.opc.STORE_FAST) and
|
|
||||||
self.code[chckStp+3] in (self.opc.LOAD_NAME, self.opc.LOAD_FAST)
|
|
||||||
and self.code[chckStp+6] in (self.opc.DELETE_NAME, self.opc.DELETE_FAST)):
|
|
||||||
toDel += [chckStp-3, chckStp+3, chckStp+6]
|
|
||||||
# SETUP_WITH opcode dosen't exist in 2.6 but is necessary for the grammar
|
|
||||||
self.code[chckRot+1] = self.opc.JUMP_ABSOLUTE # ugly hack
|
|
||||||
self.restructJump(chckRot+1, i)
|
|
||||||
self.toChange.append(chckRot+1)
|
|
||||||
return toDel
|
|
||||||
if opcode == self.opc.NOP:
|
|
||||||
return [i]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def getOpcodeToExp(self):
|
|
||||||
# we handle listExp, if opcode have to be resized
|
|
||||||
listExp = []
|
|
||||||
i=0
|
|
||||||
while i < len(self.code): # we can't use op_range for the moment
|
|
||||||
op = self.code[i]
|
|
||||||
if op in self.opc.hasArgumentExtended:
|
|
||||||
listExp += [i]
|
|
||||||
elif self.op_hasArgument(op):
|
|
||||||
i+=2
|
|
||||||
i+=1
|
|
||||||
return listExp
|
|
||||||
|
|
||||||
def restructCode(self, listDel, listExp):
|
|
||||||
'''
|
|
||||||
restruct linestarts and jump destination after converting bytecode
|
|
||||||
'''
|
|
||||||
# restruct linestarts with deleted / modificated opcode
|
|
||||||
result = list()
|
|
||||||
for block in self.linestarts:
|
|
||||||
startBlock = 0
|
|
||||||
for toDel in listDel:
|
|
||||||
if toDel < block[0]:
|
|
||||||
startBlock -= self.op_size(self.code[toDel])
|
|
||||||
for toExp in listExp:
|
|
||||||
if toExp < block[0]:
|
|
||||||
startBlock += 2
|
|
||||||
result.append((block[0]+startBlock, block[1]))
|
|
||||||
self.linestarts = result
|
|
||||||
# handle opcodeToChange deplacement
|
|
||||||
for index in range(len(self.toChange)):
|
|
||||||
change = self.toChange[index]
|
|
||||||
delta = 0
|
|
||||||
for toDel in listDel:
|
|
||||||
if change > toDel:
|
|
||||||
delta -= self.op_size(self.code[toDel])
|
|
||||||
for toExp in listExp:
|
|
||||||
if change > toExp:
|
|
||||||
delta += 2
|
|
||||||
self.toChange[index] += delta
|
|
||||||
# restruct jmp opcode
|
|
||||||
if listDel:
|
|
||||||
for jmp in self.op_range(0, len(self.code)):
|
|
||||||
op = self.code[jmp]
|
|
||||||
if op in self.opc.hasjrel + self.opc.hasjabs:
|
|
||||||
offset = 0
|
|
||||||
jmpTarget = self.get_target(jmp)
|
|
||||||
for toDel in listDel:
|
|
||||||
if toDel < jmpTarget:
|
|
||||||
if op in self.opc.hasjabs or jmp < toDel:
|
|
||||||
offset-=self.op_size(self.code[toDel])
|
|
||||||
self.restructJump(jmp, jmpTarget+offset)
|
|
||||||
if listExp:
|
|
||||||
jmp = 0
|
|
||||||
while jmp < len(self.code): # we can't use op_range for the moment
|
|
||||||
op = self.code[jmp]
|
|
||||||
if op in self.opc.hasjrel + self.opc.hasjabs:
|
|
||||||
offset = 0
|
|
||||||
jmpTarget = self.get_target(jmp)
|
|
||||||
for toExp in listExp:
|
|
||||||
if toExp < jmpTarget:
|
|
||||||
if op in self.opc.hasjabs or jmp < toExp:
|
|
||||||
offset+=2
|
|
||||||
self.restructJump(jmp, jmpTarget+offset)
|
|
||||||
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
|
|
||||||
jmp += 3
|
|
||||||
else: jmp += 1
|
|
||||||
|
|
||||||
def restructBytecode(self):
|
|
||||||
'''
|
|
||||||
add/change/delete bytecode for suiting bytecode 2.7
|
|
||||||
'''
|
|
||||||
# we can't use op_range for the moment
|
|
||||||
# convert jump opcode to 2.7
|
|
||||||
self.restructRelativeJump()
|
|
||||||
|
|
||||||
listExp = self.getOpcodeToExp()
|
|
||||||
# change code structure
|
|
||||||
if listExp:
|
|
||||||
listExp = sorted(list(set(listExp)))
|
|
||||||
self.restructCode([], listExp)
|
|
||||||
# we add arg to expended opcode
|
|
||||||
offset=0
|
|
||||||
for toExp in listExp:
|
|
||||||
self.code.insert(toExp+offset+1, 0)
|
|
||||||
self.code.insert(toExp+offset+1, 0)
|
|
||||||
offset+=2
|
|
||||||
# op_range is now ok :)
|
|
||||||
# add instruction to change in "toChange" list + MAJ toDel
|
|
||||||
listDel = []
|
|
||||||
for i in self.op_range(0, len(self.code)):
|
|
||||||
ret = self.getOpcodeToDel(i)
|
|
||||||
if ret is not None:
|
|
||||||
listDel += ret
|
|
||||||
|
|
||||||
# change code structure after deleting byte
|
|
||||||
if listDel:
|
|
||||||
listDel = sorted(list(set(listDel)))
|
|
||||||
self.restructCode(listDel, [])
|
|
||||||
# finaly we delete useless opcode
|
|
||||||
delta = 0
|
|
||||||
for x in listDel:
|
|
||||||
if self.op_hasArgument(self.code[x-delta]):
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 3
|
|
||||||
else:
|
|
||||||
self.code.pop(x-delta)
|
|
||||||
delta += 1
|
|
||||||
|
|
||||||
def restructRelativeJump(self):
|
|
||||||
'''
|
|
||||||
change relative JUMP_IF_FALSE/TRUE to absolut jump
|
|
||||||
and remap the target of PJIF/PJIT
|
|
||||||
'''
|
|
||||||
i=0
|
|
||||||
while i < len(self.code): # we can't use op_range for the moment
|
|
||||||
op = self.code[i]
|
|
||||||
if op in self.pop_jump_if:
|
|
||||||
target = self.get_argument(i)
|
|
||||||
target += i + 3
|
|
||||||
self.restructJump(i, target)
|
|
||||||
i += self.op_size(op)
|
|
||||||
|
|
||||||
i=0
|
|
||||||
while i < len(self.code): # we can't use op_range for the moment
|
|
||||||
op = self.code[i]
|
|
||||||
if op in self.pop_jump_if:
|
|
||||||
target = self.get_target(i)
|
|
||||||
if self.code[target] == self.opc.JA:
|
|
||||||
target = self.get_target(target)
|
|
||||||
self.restructJump(i, target)
|
|
||||||
i += self.op_size(op)
|
|
||||||
i=0
|
|
||||||
# while i < len(self.code): # we can't use op_range for the moment
|
|
||||||
# op = self.code[i]
|
|
||||||
# name = self.opc.opname[op]
|
|
||||||
# if self.op_hasArgument(op):
|
|
||||||
# oparg = self.get_argument(i)
|
|
||||||
# print("%d %s %d" % (i, name, oparg))
|
|
||||||
# else:
|
|
||||||
# print("%d %s" % (i, name))
|
|
||||||
# i += self.op_size(op)
|
|
||||||
|
|
||||||
def restructJump(self, pos, newTarget):
|
|
||||||
if self.code[pos] not in self.opc.hasjabs + self.opc.hasjrel:
|
|
||||||
raise 'Can t change this argument. Opcode is not a jump'
|
|
||||||
if newTarget > 0xFFFF:
|
|
||||||
raise NotImplementedError
|
|
||||||
offset = newTarget-self.get_target(pos)
|
|
||||||
target = self.get_argument(pos)+offset
|
|
||||||
if target < 0 or target > 0xFFFF:
|
|
||||||
raise NotImplementedError
|
|
||||||
self.code[pos+2] = (target >> 8) & 0xFF
|
|
||||||
self.code[pos+1] = target & 0xFF
|
|
||||||
|
|
||||||
def detect_structure(self, pos, op=None):
|
|
||||||
'''
|
|
||||||
Detect type of block structures and their boundaries to fix optimized jumps
|
|
||||||
in python2.3+
|
|
||||||
'''
|
|
||||||
|
|
||||||
# TODO: check the struct boundaries more precisely -Dan
|
|
||||||
|
|
||||||
code = self.code
|
|
||||||
# Ev remove this test and make op a mandatory argument -Dan
|
|
||||||
if op is None:
|
|
||||||
op = code[pos]
|
|
||||||
|
|
||||||
# Detect parent structure
|
|
||||||
parent = self.structs[0]
|
|
||||||
start = parent['start']
|
|
||||||
end = parent['end']
|
|
||||||
for s in self.structs:
|
|
||||||
_start = s['start']
|
|
||||||
_end = s['end']
|
|
||||||
if (_start <= pos < _end) and (_start >= start and _end <= end):
|
|
||||||
start = _start
|
|
||||||
end = _end
|
|
||||||
parent = s
|
|
||||||
|
|
||||||
if op == self.opc.SETUP_LOOP:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
|
|
||||||
if target != end:
|
|
||||||
self.fixed_jumps[pos] = end
|
|
||||||
|
|
||||||
(line_no, next_line_byte) = self.lines[pos]
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JA, next_line_byte, False)
|
|
||||||
if (jump_back and jump_back != self.prev[end]
|
|
||||||
and code[jump_back + 3] in self.jump_forward):
|
|
||||||
if (code[self.prev[end]] == self.opc.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
|
|
||||||
if not jump_back: # loop suite ends in return. wtf right?
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JA, start, False)
|
|
||||||
if not jump_back:
|
|
||||||
return
|
|
||||||
jump_back += 1
|
|
||||||
if code[self.prev[next_line_byte]] not in self.pop_jump_if:
|
|
||||||
loop_type = 'for'
|
|
||||||
else:
|
|
||||||
loop_type = 'while'
|
|
||||||
self.ignore_if.add(self.prev[next_line_byte])
|
|
||||||
target = next_line_byte
|
|
||||||
end = jump_back + 3
|
|
||||||
else:
|
|
||||||
if self.get_target(jump_back) >= next_line_byte:
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JA, start, False)
|
|
||||||
if end > jump_back + 4 and code[end] in self.jump_forward:
|
|
||||||
if code[jump_back + 4] in (self.opc.JA, self.opc.JF):
|
|
||||||
if self.get_target(jump_back+4) == self.get_target(end):
|
|
||||||
self.fixed_jumps[pos] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
elif target < pos:
|
|
||||||
self.fixed_jumps[pos] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
|
|
||||||
target = self.get_target(jump_back, self.opc.JA)
|
|
||||||
|
|
||||||
if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
|
|
||||||
loop_type = 'for'
|
|
||||||
else:
|
|
||||||
loop_type = 'while'
|
|
||||||
test = self.prev[next_line_byte]
|
|
||||||
if test == pos:
|
|
||||||
loop_type = 'while 1'
|
|
||||||
elif self.code[test] in self.opc.hasjabs + self.opc.hasjrel:
|
|
||||||
self.ignore_if.add(test)
|
|
||||||
test_target = self.get_target(test)
|
|
||||||
if test_target > (jump_back+3):
|
|
||||||
jump_back = test_target
|
|
||||||
self.not_continue.add(jump_back)
|
|
||||||
self.loops.append(target)
|
|
||||||
self.structs.append({'type': loop_type + '-loop',
|
|
||||||
'start': target,
|
|
||||||
'end': jump_back})
|
|
||||||
if jump_back+3 != end:
|
|
||||||
self.structs.append({'type': loop_type + '-else',
|
|
||||||
'start': jump_back+3,
|
|
||||||
'end': end})
|
|
||||||
elif op == self.opc.SETUP_EXCEPT:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
if target != end:
|
|
||||||
self.fixed_jumps[pos] = end
|
|
||||||
# print target, end, parent
|
|
||||||
# Add the try block
|
|
||||||
self.structs.append({'type': 'try',
|
|
||||||
'start': start,
|
|
||||||
'end': end-4})
|
|
||||||
# Now isolate the except and else blocks
|
|
||||||
end_else = start_else = self.get_target(self.prev[end])
|
|
||||||
|
|
||||||
# Add the except blocks
|
|
||||||
i = end
|
|
||||||
while i < len(self.code) and self.code[i] != self.opc.END_FINALLY:
|
|
||||||
jmp = self.next_except_jump(i)
|
|
||||||
if jmp is None: # check
|
|
||||||
i = self.next_stmt[i]
|
|
||||||
continue
|
|
||||||
if self.code[jmp] == self.opc.RETURN_VALUE:
|
|
||||||
self.structs.append({'type': 'except',
|
|
||||||
'start': i,
|
|
||||||
'end': jmp+1})
|
|
||||||
i = jmp + 1
|
|
||||||
else:
|
|
||||||
if self.get_target(jmp) != start_else:
|
|
||||||
end_else = self.get_target(jmp)
|
|
||||||
if self.code[jmp] == self.opc.JF:
|
|
||||||
self.fixed_jumps[jmp] = -1
|
|
||||||
self.structs.append({'type': 'except',
|
|
||||||
'start': i,
|
|
||||||
'end': jmp})
|
|
||||||
i = jmp + 3
|
|
||||||
|
|
||||||
# Add the try-else block
|
|
||||||
if end_else != start_else:
|
|
||||||
r_end_else = self.restrict_to_parent(end_else, parent)
|
|
||||||
self.structs.append({'type': 'try-else',
|
|
||||||
'start': i+2, # check
|
|
||||||
'end': r_end_else})
|
|
||||||
self.fixed_jumps[i] = r_end_else
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[i] = i+1
|
|
||||||
|
|
||||||
elif op in self.pop_jump_if:
|
|
||||||
start = pos+3
|
|
||||||
target = self.get_target(pos, op)
|
|
||||||
rtarget = self.restrict_to_parent(target, parent)
|
|
||||||
pre = self.prev
|
|
||||||
|
|
||||||
if target != rtarget and parent['type'] == 'and/or':
|
|
||||||
self.fixed_jumps[pos] = rtarget
|
|
||||||
return
|
|
||||||
# does this jump to right after another cond jump?
|
|
||||||
# if so, it's part of a larger conditional
|
|
||||||
if code[pre[target]] in self.pop_jump_if and target > pos:
|
|
||||||
self.fixed_jumps[pos] = pre[target]
|
|
||||||
self.structs.append({'type': 'and/or',
|
|
||||||
'start': start,
|
|
||||||
'end': pre[target]})
|
|
||||||
return
|
|
||||||
|
|
||||||
# is this an if and
|
|
||||||
if op == self.opc.PJIF:
|
|
||||||
match = self.rem_or(start, self.next_stmt[pos], self.opc.PJIF, target)
|
|
||||||
## We can't remove mid-line ifs because line structures have changed
|
|
||||||
## from restructBytecode().
|
|
||||||
## match = self.remove_mid_line_ifs(match)
|
|
||||||
if match:
|
|
||||||
if (code[pre[rtarget]] in (self.opc.JF, self.opc.JA)
|
|
||||||
and pre[rtarget] not in self.stmts
|
|
||||||
and self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget):
|
|
||||||
if (code[pre[pre[rtarget]]] == self.opc.JA
|
|
||||||
and self.remove_mid_line_ifs([pos])
|
|
||||||
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 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], self.pop_jump_if, target)))):
|
|
||||||
pass
|
|
||||||
elif code[pre[pre[rtarget]]] == self.opc.RETURN_VALUE \
|
|
||||||
and self.remove_mid_line_ifs([pos]) \
|
|
||||||
and 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]],
|
|
||||||
self.pop_jump_if, target)))
|
|
||||||
| set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]],
|
|
||||||
(self.opc.PJIF, self.opc.PJIT, self.opc.JA), pre[rtarget], True))))):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
fix = None
|
|
||||||
jump_ifs = self.all_instr(start, self.next_stmt[pos], self.opc.PJIF)
|
|
||||||
last_jump_good = True
|
|
||||||
for j in jump_ifs:
|
|
||||||
if target == self.get_target(j):
|
|
||||||
if self.lines[j].next == j+3 and last_jump_good:
|
|
||||||
fix = j
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
last_jump_good = False
|
|
||||||
self.fixed_jumps[pos] = fix or match[-1]
|
|
||||||
return
|
|
||||||
elif pos < rtarget and code[target] == self.opc.ROT_TWO:
|
|
||||||
self.fixed_jumps[pos] = target
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[pos] = match[-1]
|
|
||||||
return
|
|
||||||
else: # op == PJIT
|
|
||||||
if (pos+3) in self.load_asserts:
|
|
||||||
if code[pre[rtarget]] == self.opc.RAISE_VARARGS:
|
|
||||||
return
|
|
||||||
self.load_asserts.remove(pos+3)
|
|
||||||
|
|
||||||
next = self.next_stmt[pos]
|
|
||||||
if pre[next] == pos:
|
|
||||||
pass
|
|
||||||
elif code[next] in self.jump_forward and target == self.get_target(next):
|
|
||||||
if code[pre[next]] == self.opc.PJIF:
|
|
||||||
if code[next] == self.opc.JF or target != rtarget or code[pre[pre[rtarget]]] not in (self.opc.JA, self.opc.RETURN_VALUE):
|
|
||||||
self.fixed_jumps[pos] = pre[next]
|
|
||||||
return
|
|
||||||
elif code[next] == self.opc.JA and code[target] in self.opc.jump_foward \
|
|
||||||
and self.get_target(target) == self.get_target(next):
|
|
||||||
self.fixed_jumps[pos] = pre[next]
|
|
||||||
return
|
|
||||||
# don't add a struct for a while test, it's already taken care of
|
|
||||||
if pos in self.ignore_if:
|
|
||||||
return
|
|
||||||
|
|
||||||
if code[pre[rtarget]] == self.opc.JA and pre[rtarget] in self.stmts \
|
|
||||||
and pre[rtarget] != pos and pre[pre[rtarget]] != pos \
|
|
||||||
and not (code[rtarget] == self.opc.JA and code[rtarget+3] == self.opc.POP_BLOCK and code[pre[pre[rtarget]]] != self.opc.JA):
|
|
||||||
rtarget = pre[rtarget]
|
|
||||||
# does the if jump just beyond a jump op, then this is probably an if statement
|
|
||||||
if code[pre[rtarget]] in (self.opc.JA, self.opc.JF):
|
|
||||||
if_end = self.get_target(pre[rtarget])
|
|
||||||
|
|
||||||
# is this a loop not an if?
|
|
||||||
if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.SETUP_LOOP):
|
|
||||||
if(if_end > start):
|
|
||||||
return
|
|
||||||
|
|
||||||
end = self.restrict_to_parent(if_end, parent)
|
|
||||||
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': pre[rtarget]})
|
|
||||||
self.not_continue.add(pre[rtarget])
|
|
||||||
|
|
||||||
if rtarget < end:
|
|
||||||
self.structs.append({'type': 'if-else',
|
|
||||||
'start': rtarget,
|
|
||||||
'end': end})
|
|
||||||
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 pos < rtarget and code[rtarget] == self.opc.ROT_TWO:
|
|
||||||
return
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': rtarget})
|
|
||||||
self.return_end_ifs.add(pre[rtarget])
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
return
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from uncompyle6 import PYTHON_VERSION
|
from uncompyle6 import PYTHON_VERSION
|
||||||
if PYTHON_VERSION == 2.6:
|
if PYTHON_VERSION == 2.6:
|
||||||
|
@@ -27,10 +27,10 @@ node 2 range information, it in %c, is copied to nodes 0 and 1.
|
|||||||
2. %r
|
2. %r
|
||||||
-----
|
-----
|
||||||
|
|
||||||
%n associates recursively location information for the string that follows
|
%r associates recursively location information for the string that follows
|
||||||
|
|
||||||
For example in:
|
For example in:
|
||||||
'break_stmt': ( '%|%nbreak\n', ),
|
'break_stmt': ( '%|%rbreak\n', ),
|
||||||
|
|
||||||
The node will be associated with the text break, excluding the trailing newline.
|
The node will be associated with the text break, excluding the trailing newline.
|
||||||
|
|
||||||
|
@@ -849,8 +849,14 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.println()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
def n_ifelsestmt(self, node, preprocess=0):
|
def n_ifelsestmt(self, node, preprocess=False):
|
||||||
n = node[3][0]
|
if node[2].type.startswith('else_suite'):
|
||||||
|
else_suite = node[2]
|
||||||
|
elif node[3].type.startswith('else_suite'):
|
||||||
|
else_suite = node[3]
|
||||||
|
|
||||||
|
n = else_suite[0]
|
||||||
|
|
||||||
if len(n) == 1 == len(n[0]) and n[0] == '_stmts':
|
if len(n) == 1 == len(n[0]) and n[0] == '_stmts':
|
||||||
n = n[0][0][0]
|
n = n[0][0][0]
|
||||||
elif n[0].type in ('lastc_stmt', 'lastl_stmt'):
|
elif n[0].type in ('lastc_stmt', 'lastl_stmt'):
|
||||||
@@ -868,7 +874,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
n.type = 'elifelsestmtr'
|
n.type = 'elifelsestmtr'
|
||||||
elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'):
|
elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'):
|
||||||
node.type = 'ifelifstmt'
|
node.type = 'ifelifstmt'
|
||||||
self.n_ifelsestmt(n, preprocess=1)
|
self.n_ifelsestmt(n, preprocess=True)
|
||||||
if n == 'ifelifstmt':
|
if n == 'ifelifstmt':
|
||||||
n.type = 'elifelifstmt'
|
n.type = 'elifelifstmt'
|
||||||
elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'):
|
elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'):
|
||||||
@@ -1000,8 +1006,13 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
"""
|
"""
|
||||||
p = self.prec
|
p = self.prec
|
||||||
self.prec = 27
|
self.prec = 27
|
||||||
n = node[-1]
|
if self.version >= 2.7:
|
||||||
|
n = node[-1]
|
||||||
|
elif node[-1] == 'del_stmt':
|
||||||
|
n = node[-3] if node[-2] == 'JUMP_BACK' else node[-2]
|
||||||
|
|
||||||
assert n == 'list_iter'
|
assert n == 'list_iter'
|
||||||
|
|
||||||
# find innermost node
|
# find innermost node
|
||||||
while n == 'list_iter':
|
while n == 'list_iter':
|
||||||
n = n[0] # recurse one step
|
n = n[0] # recurse one step
|
||||||
@@ -1010,8 +1021,19 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
elif n == 'list_if_not': n= n[2]
|
elif n == 'list_if_not': n= n[2]
|
||||||
assert n == 'lc_body'
|
assert n == 'lc_body'
|
||||||
self.write( '[ ')
|
self.write( '[ ')
|
||||||
self.preorder(n[0]) # lc_body
|
|
||||||
self.preorder(node[-1]) # for/if parts
|
if self.version >= 2.7:
|
||||||
|
expr = n[0]
|
||||||
|
list_iter = node[-1]
|
||||||
|
else:
|
||||||
|
expr = n[1]
|
||||||
|
list_iter = node[-3] if node[-2] == 'JUMP_BACK' else node[-2]
|
||||||
|
|
||||||
|
assert expr == 'expr'
|
||||||
|
assert list_iter == 'list_iter'
|
||||||
|
|
||||||
|
self.preorder(expr)
|
||||||
|
self.preorder(list_iter)
|
||||||
self.write( ' ]')
|
self.write( ' ]')
|
||||||
self.prec = p
|
self.prec = p
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
@@ -1051,6 +1073,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
n = ast[iter_index]
|
n = ast[iter_index]
|
||||||
assert n == 'comp_iter'
|
assert n == 'comp_iter'
|
||||||
|
|
||||||
# find innermost node
|
# find innermost node
|
||||||
while n == 'comp_iter': # list_iter
|
while n == 'comp_iter': # list_iter
|
||||||
n = n[0] # recurse one step
|
n = n[0] # recurse one step
|
||||||
@@ -1572,8 +1595,8 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
def n_except_cond2(self, node):
|
def n_except_cond2(self, node):
|
||||||
if node[5][0] == 'unpack':
|
if node[-2][0] == 'unpack':
|
||||||
node[5][0].type = 'unpack_w_parens'
|
node[-2][0].type = 'unpack_w_parens'
|
||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
def engine(self, entry, startnode):
|
def engine(self, entry, startnode):
|
||||||
|
Reference in New Issue
Block a user