You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Merge branch 'master' into python-2.4
This commit is contained in:
@@ -12,7 +12,7 @@ Introduction
|
||||
|
||||
*uncompyle6* translates Python bytecode back into equivalent Python
|
||||
source code. It accepts bytecodes from Python version 1.3 to version
|
||||
3.7, spanning over 22 years of Python releases. We include Dropbox's
|
||||
3.8, spanning over 24 years of Python releases. We include Dropbox's
|
||||
Python 2.5 bytecode and some PyPy bytecode.
|
||||
|
||||
Why this?
|
||||
@@ -76,7 +76,7 @@ Requirements
|
||||
The code here can be run on Python versions 2.6 or later, PyPy 3-2.4,
|
||||
or PyPy-5.0.1. Python versions 2.4-2.7 are supported in the
|
||||
python-2.4 branch. The bytecode files it can read have been tested on
|
||||
Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.6 and the
|
||||
Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.8 and the
|
||||
above-mentioned PyPy versions.
|
||||
|
||||
Installation
|
||||
|
@@ -43,6 +43,7 @@ classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Software Development :: Debuggers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
]
|
||||
|
Binary file not shown.
BIN
test/bytecode_3.4_run/06_while_return.pyc
Normal file
BIN
test/bytecode_3.4_run/06_while_return.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5_run/06_while_return.pyc
Normal file
BIN
test/bytecode_3.5_run/06_while_return.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/04_call_function.pyc
Normal file
BIN
test/bytecode_3.7/04_call_function.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8/04_call_function.pyc
Normal file
BIN
test/bytecode_3.8/04_call_function.pyc
Normal file
Binary file not shown.
@@ -1,28 +1,32 @@
|
||||
# From Python 3.4 asynchat.py
|
||||
# Tests presence or absense of
|
||||
# SETUP_LOOP testexpr return_stmts POP_BLOCK COME_FROM_LOOP
|
||||
# Note: that there is no JUMP_BACK because of the return_stmts.
|
||||
|
||||
def initiate_send(self, num_sent, first):
|
||||
while self.producer_fifo and self.connected:
|
||||
def initiate_send(a, b, c, num_sent):
|
||||
while a and b:
|
||||
try:
|
||||
5
|
||||
except OSError:
|
||||
return
|
||||
1 / (b - 1)
|
||||
except ZeroDivisionError:
|
||||
return 1
|
||||
|
||||
if num_sent:
|
||||
if first:
|
||||
self.producer_fifo = '6'
|
||||
else:
|
||||
del self.producer_fifo[0]
|
||||
return
|
||||
c = 2
|
||||
return c
|
||||
|
||||
|
||||
# FIXME: this causes a parse error:
|
||||
# def initiate_send(self):
|
||||
# while self.producer_fifo and self.connected:
|
||||
# try:
|
||||
# 6
|
||||
# except OSError:
|
||||
# return
|
||||
def initiate_send2(a, b):
|
||||
while a and b:
|
||||
try:
|
||||
1 / (b - 1)
|
||||
except ZeroDivisionError:
|
||||
return 1
|
||||
|
||||
# return
|
||||
return 2
|
||||
|
||||
assert initiate_send(1, 1, 2, False) == 1
|
||||
assert initiate_send(1, 2, 3, False) == 3
|
||||
assert initiate_send(1, 2, 3, True) == 2
|
||||
|
||||
assert initiate_send2(1, 1) == 1
|
||||
assert initiate_send2(1, 2) == 2
|
||||
|
@@ -101,6 +101,7 @@ class Python3Parser(PythonParser):
|
||||
return_if_stmts ::= return_if_stmt come_from_opt
|
||||
return_if_stmts ::= _stmts return_if_stmt
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF
|
||||
returns ::= _stmts return_if_stmt
|
||||
|
||||
stmt ::= break
|
||||
break ::= BREAK_LOOP
|
||||
|
@@ -34,6 +34,8 @@ class Python34Parser(Python33Parser):
|
||||
# passtmt is needed for semantic actions to add "pass"
|
||||
suite_stmts_opt ::= pass
|
||||
|
||||
whilestmt ::= SETUP_LOOP testexpr returns come_froms POP_BLOCK COME_FROM_LOOP
|
||||
|
||||
# Seems to be needed starting 3.4.4 or so
|
||||
while1stmt ::= SETUP_LOOP l_stmts
|
||||
COME_FROM JUMP_BACK POP_BLOCK COME_FROM_LOOP
|
||||
|
@@ -27,7 +27,6 @@ class Python35Parser(Python34Parser):
|
||||
while1stmt ::= SETUP_LOOP l_stmts POP_BLOCK COME_FROM_LOOP
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK
|
||||
POP_BLOCK else_suite COME_FROM_LOOP
|
||||
whilestmt ::= SETUP_LOOP testexpr returns POP_BLOCK COME_FROM_LOOP
|
||||
|
||||
# The following rule is for Python 3.5+ where we can have stuff like
|
||||
# while ..
|
||||
@@ -105,7 +104,6 @@ class Python35Parser(Python34Parser):
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF POP_BLOCK
|
||||
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
|
||||
|
||||
|
||||
jb_else ::= JUMP_BACK ELSE
|
||||
ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec
|
||||
ifelsestmtl ::= testexpr c_stmts_opt jb_else else_suitel
|
||||
|
@@ -22,13 +22,16 @@ This sets up opcodes Python's 3.7 and calls a generalized
|
||||
scanner routine for Python 3.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.scanners.scanner36 import Scanner36
|
||||
from uncompyle6.scanners.scanner3 import Scanner3
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
from xdis.opcodes import opcode_37 as opc
|
||||
JUMP_OPs = opc.JUMP_OPS
|
||||
|
||||
class Scanner37(Scanner3):
|
||||
class Scanner37(Scanner36):
|
||||
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner3.__init__(self, 3.7, show_asm)
|
||||
|
@@ -24,13 +24,14 @@ scanner routine for Python 3.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.scanners.scanner37 import Scanner37
|
||||
from uncompyle6.scanners.scanner3 import Scanner3
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
from xdis.opcodes import opcode_38 as opc
|
||||
JUMP_OPs = opc.JUMP_OPS
|
||||
|
||||
class Scanner38(Scanner3):
|
||||
class Scanner38(Scanner37):
|
||||
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner3.__init__(self, 3.8, show_asm)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018 by Rocky Bernstein
|
||||
# Copyright (c) 2018-2019 by Rocky Bernstein
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -48,13 +48,77 @@ def customize_for_version(self, is_pypy, version):
|
||||
'assign3': ( '%|%c, %c, %c = %c, %c, %c\n',
|
||||
5, 6, 7, 0, 1, 2 ),
|
||||
})
|
||||
if version < 3.0:
|
||||
if version >= 3.0:
|
||||
TABLE_DIRECT.update({
|
||||
# Gotta love Python for its futzing around with syntax like this
|
||||
'raise_stmt2': ( '%|raise %c from %c\n', 0, 1),
|
||||
})
|
||||
|
||||
if version >= 3.2:
|
||||
TABLE_DIRECT.update({
|
||||
'del_deref_stmt': ( '%|del %c\n', 0),
|
||||
'DELETE_DEREF': ( '%{pattr}', 0 ),
|
||||
})
|
||||
from uncompyle6.semantics.customize3 import customize_for_version3
|
||||
customize_for_version3(self, version)
|
||||
else: # < 3.0
|
||||
if 2.4 <= version <= 2.6:
|
||||
TABLE_DIRECT.update({
|
||||
'comp_for': ( ' for %c in %c', 3, 1 ),
|
||||
})
|
||||
else:
|
||||
TABLE_DIRECT.update({
|
||||
'comp_for': ( ' for %c in %c%c', 2, 0, 3 ),
|
||||
})
|
||||
|
||||
if version >= 2.5:
|
||||
from uncompyle6.semantics.customize25 import customize_for_version25
|
||||
customize_for_version25(self, version)
|
||||
|
||||
if version >= 2.6:
|
||||
from uncompyle6.semantics.customize26_27 import customize_for_version26_27
|
||||
customize_for_version26_27(self, version)
|
||||
pass
|
||||
else: # < 2.5
|
||||
global NAME_MODULE
|
||||
NAME_MODULE = SyntaxTree('stmt',
|
||||
[ SyntaxTree('assign',
|
||||
[ SyntaxTree('expr',
|
||||
[Token('LOAD_GLOBAL', pattr='__name__',
|
||||
offset=0, has_arg=True)]),
|
||||
SyntaxTree('store',
|
||||
[ Token('STORE_NAME', pattr='__module__',
|
||||
offset=3, has_arg=True)])
|
||||
])])
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%|import %c%c\n', 2, 3),
|
||||
'import_cont' : ( ', %c', 2),
|
||||
'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-',
|
||||
(1, 'suite_stmts_opt') ,
|
||||
(5, 'suite_stmts_opt') )
|
||||
})
|
||||
if version == 2.4:
|
||||
def n_iftrue_stmt24(node):
|
||||
self.template_engine(('%c', 0), node)
|
||||
self.default(node)
|
||||
self.prune()
|
||||
self.n_iftrue_stmt24 = n_iftrue_stmt24
|
||||
else: # version <= 2.3:
|
||||
TABLE_DIRECT.update({
|
||||
'if1_stmt': ( '%|if 1\n%+%c%-', 5 )
|
||||
})
|
||||
if version <= 2.1:
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%c', 2 ),
|
||||
# FIXME: not quite right. We have indiividual imports
|
||||
# when there is in fact one: "import a, b, ..."
|
||||
'imports_cont': ( '%C%,', (1, 100, '\n') ),
|
||||
})
|
||||
pass
|
||||
pass
|
||||
pass # < 2.5
|
||||
|
||||
# < 3.0 continues
|
||||
|
||||
TABLE_R.update({
|
||||
'STORE_SLICE+0': ( '%c[:]', 0 ),
|
||||
@@ -87,109 +151,6 @@ def customize_for_version(self, is_pypy, version):
|
||||
self.prune() # stop recursing
|
||||
self.n_exec_smt = n_exec_stmt
|
||||
|
||||
else:
|
||||
TABLE_DIRECT.update({
|
||||
# Gotta love Python for its futzing around with syntax like this
|
||||
'raise_stmt2': ( '%|raise %c from %c\n', 0, 1),
|
||||
})
|
||||
pass # < 3.0
|
||||
|
||||
if version >= 3.2:
|
||||
TABLE_DIRECT.update({
|
||||
'del_deref_stmt': ( '%|del %c\n', 0),
|
||||
'DELETE_DEREF': ( '%{pattr}', 0 ),
|
||||
})
|
||||
|
||||
if version <= 2.4:
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%|import %c%c\n', 2, 3),
|
||||
'import_cont' : ( ', %c', 2),
|
||||
'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-',
|
||||
(1, 'suite_stmts_opt') ,
|
||||
(5, 'suite_stmts_opt') )
|
||||
})
|
||||
if version == 2.3:
|
||||
TABLE_DIRECT.update({
|
||||
'if1_stmt': ( '%|if 1\n%+%c%-', 5 )
|
||||
})
|
||||
|
||||
global NAME_MODULE
|
||||
NAME_MODULE = SyntaxTree('stmt',
|
||||
[ SyntaxTree('assign',
|
||||
[ SyntaxTree('expr',
|
||||
[Token('LOAD_GLOBAL', pattr='__name__',
|
||||
offset=0, has_arg=True)]),
|
||||
SyntaxTree('store',
|
||||
[ Token('STORE_NAME', pattr='__module__',
|
||||
offset=3, has_arg=True)])
|
||||
])])
|
||||
pass
|
||||
if version <= 2.3:
|
||||
if version <= 2.1:
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%c', 2 ),
|
||||
# FIXME: not quite right. We have indiividual imports
|
||||
# when there is in fact one: "import a, b, ..."
|
||||
'imports_cont': ( '%C%,', (1, 100, '\n') ),
|
||||
})
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
elif version >= 2.5:
|
||||
########################
|
||||
# Import style for 2.5+
|
||||
########################
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%|import %c%c\n', 2, 3 ),
|
||||
'import_cont' : ( ', %c', 2 ),
|
||||
# With/as is allowed as "from future" thing in 2.5
|
||||
# Note: It is safe to put the variables after "as" in parenthesis,
|
||||
# and sometimes it is needed.
|
||||
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
|
||||
'withasstmt': ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3),
|
||||
})
|
||||
|
||||
# In 2.5+ "except" handlers and the "finally" can appear in one
|
||||
# "try" statement. So the below has the effect of combining the
|
||||
# "tryfinally" with statement with the "try_except" statement
|
||||
def tryfinallystmt(node):
|
||||
if len(node[1][0]) == 1 and node[1][0][0] == 'stmt':
|
||||
if node[1][0][0][0] == 'try_except':
|
||||
node[1][0][0][0].kind = 'tf_try_except'
|
||||
if node[1][0][0][0] == 'tryelsestmt':
|
||||
node[1][0][0][0].kind = 'tf_tryelsestmt'
|
||||
self.default(node)
|
||||
self.n_tryfinallystmt = tryfinallystmt
|
||||
|
||||
########################################
|
||||
# Python 2.6+
|
||||
# except <condition> as <var>
|
||||
# vs. older:
|
||||
# except <condition> , <var>
|
||||
#
|
||||
# For 2.6 we use the older syntax which
|
||||
# matches how we parse this in bytecode
|
||||
########################################
|
||||
if version > 2.6:
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
|
||||
})
|
||||
else:
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond3': ( '%|except %c, %c:\n', 1, 6 ),
|
||||
'testtrue_then': ( 'not %p', (0, 22) ),
|
||||
|
||||
})
|
||||
|
||||
if 2.4 <= version <= 2.6:
|
||||
TABLE_DIRECT.update({
|
||||
'comp_for': ( ' for %c in %c', 3, 1 ),
|
||||
})
|
||||
else:
|
||||
TABLE_DIRECT.update({
|
||||
'comp_for': ( ' for %c in %c%c', 2, 0, 3 ),
|
||||
})
|
||||
|
||||
if version >= 3.0:
|
||||
from uncompyle6.semantics.customize3 import customize_for_version3
|
||||
customize_for_version3(self, version)
|
||||
return
|
||||
|
48
uncompyle6/semantics/customize25.py
Normal file
48
uncompyle6/semantics/customize25.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Isolate Python 2.5+ version-specific semantic actions here.
|
||||
"""
|
||||
|
||||
from uncompyle6.semantics.consts import TABLE_DIRECT
|
||||
|
||||
#######################
|
||||
# Python 2.5+ Changes #
|
||||
#######################
|
||||
def customize_for_version25(self, version):
|
||||
|
||||
########################
|
||||
# Import style for 2.5+
|
||||
########################
|
||||
TABLE_DIRECT.update({
|
||||
'importmultiple': ( '%|import %c%c\n', 2, 3 ),
|
||||
'import_cont' : ( ', %c', 2 ),
|
||||
# With/as is allowed as "from future" thing in 2.5
|
||||
# Note: It is safe to put the variables after "as" in parenthesis,
|
||||
# and sometimes it is needed.
|
||||
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
|
||||
'withasstmt': ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3),
|
||||
})
|
||||
|
||||
# In 2.5+ "except" handlers and the "finally" can appear in one
|
||||
# "try" statement. So the below has the effect of combining the
|
||||
# "tryfinally" with statement with the "try_except" statement
|
||||
def tryfinallystmt(node):
|
||||
if len(node[1][0]) == 1 and node[1][0][0] == 'stmt':
|
||||
if node[1][0][0][0] == 'try_except':
|
||||
node[1][0][0][0].kind = 'tf_try_except'
|
||||
if node[1][0][0][0] == 'tryelsestmt':
|
||||
node[1][0][0][0].kind = 'tf_tryelsestmt'
|
||||
self.default(node)
|
||||
self.n_tryfinallystmt = tryfinallystmt
|
40
uncompyle6/semantics/customize26_27.py
Normal file
40
uncompyle6/semantics/customize26_27.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Isolate Python 2.6 and 2.7 version-specific semantic actions here.
|
||||
"""
|
||||
|
||||
from uncompyle6.semantics.consts import TABLE_DIRECT
|
||||
|
||||
def customize_for_version26_27(self, version):
|
||||
|
||||
########################################
|
||||
# Python 2.6+
|
||||
# except <condition> as <var>
|
||||
# vs. older:
|
||||
# except <condition> , <var>
|
||||
#
|
||||
# For 2.6 we use the older syntax which
|
||||
# matches how we parse this in bytecode
|
||||
########################################
|
||||
if version > 2.6:
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
|
||||
})
|
||||
else:
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond3': ( '%|except %c, %c:\n', 1, 6 ),
|
||||
'testtrue_then': ( 'not %p', (0, 22) ),
|
||||
|
||||
})
|
@@ -27,8 +27,13 @@ from uncompyle6.semantics.customize38 import customize_for_version38
|
||||
|
||||
def customize_for_version3(self, version):
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
|
||||
'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0),
|
||||
'importmultiple': ( '%|import %c%c\n', 2, 3 ),
|
||||
'import_cont' : ( ', %c', 2 ),
|
||||
'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
|
||||
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
|
||||
'withasstmt': ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3),
|
||||
})
|
||||
|
||||
assert version >= 3.0
|
||||
@@ -269,8 +274,8 @@ def customize_for_version3(self, version):
|
||||
(5, 'else_suitel') ),
|
||||
})
|
||||
if version >= 3.4:
|
||||
########################
|
||||
# Python 3.4+ Additions
|
||||
#######################
|
||||
# Python 3.4+ Changes #
|
||||
#######################
|
||||
TABLE_DIRECT.update({
|
||||
'LOAD_CLASSDEREF': ( '%{pattr}', ),
|
||||
|
@@ -21,8 +21,8 @@ from uncompyle6.semantics.consts import (
|
||||
INDENT_PER_LEVEL, TABLE_DIRECT)
|
||||
from uncompyle6.semantics.helper import flatten_list
|
||||
|
||||
########################
|
||||
# Python 3.5+ Additions
|
||||
#######################
|
||||
# Python 3.5+ Changes #
|
||||
#######################
|
||||
def customize_for_version35(self, version):
|
||||
TABLE_DIRECT.update({
|
||||
|
@@ -46,8 +46,12 @@ def customize_for_version38(self, version):
|
||||
(0, 'expr'), (6, 'store'),
|
||||
(7, 'suite_stmts') ),
|
||||
|
||||
'except_handler38': (
|
||||
'%c', (2, 'except_stmts') ),
|
||||
|
||||
'except_handler38a': (
|
||||
'%c', (-2, 'stmts') ),
|
||||
|
||||
'except_ret38a': (
|
||||
'return %c', (4, 'expr') ),
|
||||
'except_ret38': ( '%|return %c\n', (1, 'expr') ),
|
||||
|
@@ -1825,7 +1825,6 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
# print(startnode)
|
||||
# print(entry[0])
|
||||
# print('======')
|
||||
|
||||
fmt = entry[0]
|
||||
arg = 1
|
||||
i = 0
|
||||
|
Reference in New Issue
Block a user