mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-11-27 07:00:42 +00:00
Handle PyPy JUMP_IF_NOT_DEBUG
Update README.rst to note PyPY and reorganize a little
This commit is contained in:
parent
285444e19a
commit
476eb50868
22
README.rst
22
README.rst
@ -12,20 +12,19 @@ Introduction
|
|||||||
|
|
||||||
*uncompyle6* translates Python bytecode back into equivalent Python
|
*uncompyle6* translates Python bytecode back into equivalent Python
|
||||||
source code. It accepts bytecodes from Python version 2.3 to 3.5 or
|
source code. It accepts bytecodes from Python version 2.3 to 3.5 or
|
||||||
so. The code requires Python 2.6 or later and has been tested on Python
|
so, including PyPy bytecode.
|
||||||
running versions 2.3-2.7, and 3.2-3.5.
|
|
||||||
|
|
||||||
Why this?
|
Why this?
|
||||||
---------
|
---------
|
||||||
|
|
||||||
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
|
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
|
||||||
forks around. All of them come basically from the same code base, and
|
forks around. All of them came basically from the same code base, and
|
||||||
almost all of them no longer maintained or worked on. Only one handled
|
almost all of them no were no longer actively maintained. Only one
|
||||||
Python 3, and even there, only 3.2. This code pulls these together,
|
handled Python 3, and even there, only 3.2. This code pulls these
|
||||||
handles a wide range of bytecodes and addresses a number of open
|
together and moves forward. It also addresses a number of open issues
|
||||||
issues in previous forks.
|
in the previous forks.
|
||||||
|
|
||||||
What makes this different from other CPython bytecode decompilers? Its
|
What makes this different from other CPython bytecode decompilers?: its
|
||||||
ability to deparse just fragments and give source-code information
|
ability to deparse just fragments and give source-code information
|
||||||
around a given bytecode offset.
|
around a given bytecode offset.
|
||||||
|
|
||||||
@ -41,6 +40,13 @@ location in more detail than just a line number. It can be also used
|
|||||||
when source-code information does not exist and there is just bytecode
|
when source-code information does not exist and there is just bytecode
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
This project requires Python 2.6 or later, PyPy 3-2.40, or PyPy-5.0.1.
|
||||||
|
The bytecode files it can read has been tested on Python bytecodes from
|
||||||
|
versions 2.3-2.7, and 3.2-3.5 and the above-mentioned PyPy versions.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
BIN
test/bytecode_pypy2.7/03_if_elif.pyc
Normal file
BIN
test/bytecode_pypy2.7/03_if_elif.pyc
Normal file
Binary file not shown.
@ -2,14 +2,19 @@
|
|||||||
# Bug in 2.6 is having multple COME_FROMs due to the
|
# Bug in 2.6 is having multple COME_FROMs due to the
|
||||||
# "and" in the "if" clause
|
# "and" in the "if" clause
|
||||||
if __name__:
|
if __name__:
|
||||||
if __file__ and name:
|
if __file__ and __name__:
|
||||||
pass
|
pass
|
||||||
elif name:
|
elif __name__:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 2.6.9 transformer.py
|
# 2.6.9 transformer.py
|
||||||
# Bug in 2.6 is multple COME_FROMs as a result
|
# Bug in 2.6 is multple COME_FROMs as a result
|
||||||
# of the "or" in the "assert"
|
# of the "or" in the "assert"
|
||||||
|
|
||||||
|
# In PyPy the assert is handled via PyPy's unique JUMP_IF_NOT_DEBUG
|
||||||
|
# instruction.
|
||||||
|
|
||||||
|
# Also note that the "else: pass" is superfluous
|
||||||
if __name__:
|
if __name__:
|
||||||
pass
|
pass
|
||||||
elif __file__:
|
elif __file__:
|
||||||
|
@ -275,6 +275,14 @@ class Python2Parser(PythonParser):
|
|||||||
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
||||||
op, v, customize)
|
op, v, customize)
|
||||||
continue
|
continue
|
||||||
|
elif k == 'JUMP_IF_NOT_DEBUG':
|
||||||
|
self.add_unique_rule(
|
||||||
|
"stmt ::= assert_pypy", op, v, customize)
|
||||||
|
self.add_unique_rule(
|
||||||
|
"assert_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true "
|
||||||
|
"LOAD_ASSERT RAISE_VARARGS_1 COME_FROM",
|
||||||
|
op, v, customize)
|
||||||
|
continue
|
||||||
elif op == 'BUILD_MAP':
|
elif op == 'BUILD_MAP':
|
||||||
kvlist_n = "kvlist_%s" % v
|
kvlist_n = "kvlist_%s" % v
|
||||||
rule = kvlist_n + ' ::= ' + ' kv3' * v
|
rule = kvlist_n + ' ::= ' + ' kv3' * v
|
||||||
|
@ -47,7 +47,10 @@ class Python27Parser(Python2Parser):
|
|||||||
|
|
||||||
def p_stmt27(self, args):
|
def p_stmt27(self, args):
|
||||||
"""
|
"""
|
||||||
|
# assert condition
|
||||||
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
|
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
|
||||||
|
|
||||||
|
# assert condition, expr
|
||||||
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
|
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
|
||||||
|
|
||||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt
|
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt
|
||||||
|
@ -250,6 +250,10 @@ class Python3Parser(PythonParser):
|
|||||||
def p_misc3(self, args):
|
def p_misc3(self, args):
|
||||||
"""
|
"""
|
||||||
try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM
|
try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM
|
||||||
|
for_block ::= l_stmts
|
||||||
|
iflaststmtl ::= testexpr c_stmts_opt
|
||||||
|
iflaststmt ::= testexpr c_stmts_opt34
|
||||||
|
c_stmts_opt34 ::= JUMP_BACK JUMP_ABSOLUTE c_stmts_opt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def p_jump3(self, args):
|
def p_jump3(self, args):
|
||||||
@ -298,14 +302,6 @@ class Python3Parser(PythonParser):
|
|||||||
binary_subscr2 ::= expr expr DUP_TOP_TWO BINARY_SUBSCR
|
binary_subscr2 ::= expr expr DUP_TOP_TWO BINARY_SUBSCR
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def p_misc3(self, args):
|
|
||||||
'''
|
|
||||||
for_block ::= l_stmts
|
|
||||||
iflaststmtl ::= testexpr c_stmts_opt
|
|
||||||
iflaststmt ::= testexpr c_stmts_opt34
|
|
||||||
c_stmts_opt34 ::= JUMP_BACK JUMP_ABSOLUTE c_stmts_opt
|
|
||||||
'''
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def call_fn_name(token):
|
def call_fn_name(token):
|
||||||
"""Customize CALL_FUNCTION to add the number of positional arguments"""
|
"""Customize CALL_FUNCTION to add the number of positional arguments"""
|
||||||
@ -475,6 +471,14 @@ class Python3Parser(PythonParser):
|
|||||||
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
||||||
opname, token.attr, customize)
|
opname, token.attr, customize)
|
||||||
continue
|
continue
|
||||||
|
elif opname == 'JUMP_IF_NOT_DEBUG':
|
||||||
|
self.add_unique_rule(
|
||||||
|
"stmt ::= assert_pypy", opname, v, customize)
|
||||||
|
self.add_unique_rule(
|
||||||
|
"assert_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true "
|
||||||
|
"LOAD_ASSERT RAISE_VARARGS_1 COME_FROM",
|
||||||
|
opname, token.attr, customize)
|
||||||
|
continue
|
||||||
elif opname_base == 'BUILD_MAP':
|
elif opname_base == 'BUILD_MAP':
|
||||||
kvlist_n = "kvlist_%s" % token.attr
|
kvlist_n = "kvlist_%s" % token.attr
|
||||||
if self.version >= 3.5:
|
if self.version >= 3.5:
|
||||||
|
@ -192,7 +192,7 @@ class Scanner2(scan.Scanner):
|
|||||||
opname = '%s_%d' % (opname, oparg)
|
opname = '%s_%d' % (opname, oparg)
|
||||||
if op != self.opc.BUILD_SLICE:
|
if op != self.opc.BUILD_SLICE:
|
||||||
customize[opname] = oparg
|
customize[opname] = oparg
|
||||||
elif self.is_pypy and opname == 'CALL_METHOD':
|
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
||||||
customize[opname] = oparg
|
customize[opname] = oparg
|
||||||
elif op == self.opc.JUMP_ABSOLUTE:
|
elif op == self.opc.JUMP_ABSOLUTE:
|
||||||
target = self.get_target(offset)
|
target = self.get_target(offset)
|
||||||
|
@ -237,7 +237,7 @@ class Scanner3(scan.Scanner):
|
|||||||
elif op in self.varargs:
|
elif op in self.varargs:
|
||||||
pos_args = inst.argval
|
pos_args = inst.argval
|
||||||
opname = '%s_%d' % (opname, pos_args)
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
elif self.is_pypy and opname == 'CALL_METHOD':
|
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
||||||
customize['CALL_METHOD'] = argval
|
customize['CALL_METHOD'] = argval
|
||||||
elif opname == 'UNPACK_EX':
|
elif opname == 'UNPACK_EX':
|
||||||
# FIXME: try with scanner and parser by
|
# FIXME: try with scanner and parser by
|
||||||
|
@ -381,6 +381,10 @@ TABLE_DIRECT = {
|
|||||||
#######################
|
#######################
|
||||||
'LOAD_CLASSDEREF': ( '%{pattr}', ),
|
'LOAD_CLASSDEREF': ( '%{pattr}', ),
|
||||||
|
|
||||||
|
########################
|
||||||
|
# PyPy Additions
|
||||||
|
#######################
|
||||||
|
'assert_pypy': ( '%|assert %c\n' , 1 ),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user