mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-11-23 13:09:49 +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
|
||||
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
|
||||
running versions 2.3-2.7, and 3.2-3.5.
|
||||
so, including PyPy bytecode.
|
||||
|
||||
Why this?
|
||||
---------
|
||||
|
||||
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
|
||||
forks around. All of them come basically from the same code base, and
|
||||
almost all of them no longer maintained or worked on. Only one handled
|
||||
Python 3, and even there, only 3.2. This code pulls these together,
|
||||
handles a wide range of bytecodes and addresses a number of open
|
||||
issues in previous forks.
|
||||
forks around. All of them came basically from the same code base, and
|
||||
almost all of them no were no longer actively maintained. Only one
|
||||
handled Python 3, and even there, only 3.2. This code pulls these
|
||||
together and moves forward. It also addresses a number of open issues
|
||||
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
|
||||
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
|
||||
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
|
||||
------------
|
||||
|
||||
|
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
|
||||
# "and" in the "if" clause
|
||||
if __name__:
|
||||
if __file__ and name:
|
||||
if __file__ and __name__:
|
||||
pass
|
||||
elif name:
|
||||
elif __name__:
|
||||
pass
|
||||
|
||||
# 2.6.9 transformer.py
|
||||
# Bug in 2.6 is multple COME_FROMs as a result
|
||||
# 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__:
|
||||
pass
|
||||
elif __file__:
|
||||
|
@ -275,6 +275,14 @@ class Python2Parser(PythonParser):
|
||||
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
||||
op, v, customize)
|
||||
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':
|
||||
kvlist_n = "kvlist_%s" % v
|
||||
rule = kvlist_n + ' ::= ' + ' kv3' * v
|
||||
|
@ -47,7 +47,10 @@ class Python27Parser(Python2Parser):
|
||||
|
||||
def p_stmt27(self, args):
|
||||
"""
|
||||
# assert condition
|
||||
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
|
||||
|
||||
# assert condition, expr
|
||||
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
|
||||
|
||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt
|
||||
|
@ -250,6 +250,10 @@ class Python3Parser(PythonParser):
|
||||
def p_misc3(self, args):
|
||||
"""
|
||||
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):
|
||||
@ -298,14 +302,6 @@ class Python3Parser(PythonParser):
|
||||
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
|
||||
def call_fn_name(token):
|
||||
"""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",
|
||||
opname, token.attr, customize)
|
||||
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':
|
||||
kvlist_n = "kvlist_%s" % token.attr
|
||||
if self.version >= 3.5:
|
||||
|
@ -192,7 +192,7 @@ class Scanner2(scan.Scanner):
|
||||
opname = '%s_%d' % (opname, oparg)
|
||||
if op != self.opc.BUILD_SLICE:
|
||||
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
|
||||
elif op == self.opc.JUMP_ABSOLUTE:
|
||||
target = self.get_target(offset)
|
||||
|
@ -237,7 +237,7 @@ class Scanner3(scan.Scanner):
|
||||
elif op in self.varargs:
|
||||
pos_args = inst.argval
|
||||
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
|
||||
elif opname == 'UNPACK_EX':
|
||||
# FIXME: try with scanner and parser by
|
||||
|
@ -381,6 +381,10 @@ TABLE_DIRECT = {
|
||||
#######################
|
||||
'LOAD_CLASSDEREF': ( '%{pattr}', ),
|
||||
|
||||
########################
|
||||
# PyPy Additions
|
||||
#######################
|
||||
'assert_pypy': ( '%|assert %c\n' , 1 ),
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user