You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
Compare commits
112 Commits
release-py
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
1358d40aef | ||
|
c8c6f1a63d | ||
|
850500c7ad | ||
|
470d203b40 | ||
|
4911d85237 | ||
|
93a218a8b1 | ||
|
9ec8918c1f | ||
|
08ed185608 | ||
|
32c4b84458 | ||
|
9cf345d446 | ||
|
c164df2795 | ||
|
3ad63071ac | ||
|
25cd759dbe | ||
|
000c060093 | ||
|
39d79217ca | ||
|
5390e3b838 | ||
|
8aeb0aad8c | ||
|
d0ca7b0363 | ||
|
a2e34ab75c | ||
|
5c2af69925 | ||
|
8076c60eee | ||
|
ea26084e6d | ||
|
1b4b6b334e | ||
|
482dbb5c82 | ||
|
fa203af665 | ||
|
08e27a8b0f | ||
|
55ffaa1aff | ||
|
51ac72ba1f | ||
|
d5bf7626af | ||
|
91fa73bf01 | ||
|
9a1b77aff4 | ||
|
79d5790e3f | ||
|
381a470d90 | ||
|
64b75625a9 | ||
|
7387e5094b | ||
|
1bcd21a6f4 | ||
|
536d45deb1 | ||
|
dce7e809e2 | ||
|
5ddbea73f4 | ||
|
71fe1e6c2c | ||
|
8a9a4ca6cc | ||
|
b8e9ce8a7a | ||
|
40a40b0bad | ||
|
528a2b0c22 | ||
|
d75bf1c32a | ||
|
cef3203601 | ||
|
5b657ac7d8 | ||
|
1509bc4828 | ||
|
fad5089175 | ||
|
52262dc38a | ||
|
b61255535e | ||
|
e3369edaed | ||
|
ce58ed7434 | ||
|
01859ce820 | ||
|
0a9dc57cc9 | ||
|
ada786e08c | ||
|
48bd832e7c | ||
|
cfb5c442e2 | ||
|
29a91fc015 | ||
|
37f953c353 | ||
|
4d84a723f4 | ||
|
ddbfc168c5 | ||
|
a463220df2 | ||
|
3e5f963c64 | ||
|
c7ebdb344b | ||
|
438c3b8d1d | ||
|
aa1d7abfdc | ||
|
d3e30cf0e0 | ||
|
36efc1fc8a | ||
|
f00080317b | ||
|
162423895e | ||
|
f2750cff50 | ||
|
256aaf0ef9 | ||
|
41314f95bb | ||
|
0645738775 | ||
|
ceb7c659bd | ||
|
8ac7a75372 | ||
|
15efaffe8d | ||
|
e8e006bb8c | ||
|
c68b74a9c6 | ||
|
f4bb0c44fe | ||
|
8d81f4ab27 | ||
|
e0a56d4739 | ||
|
054364cb22 | ||
|
83c8313a8e | ||
|
184bda1b03 | ||
|
f374485e93 | ||
|
fe7df87288 | ||
|
cfbb25df3d | ||
|
d4174832a1 | ||
|
345de81d06 | ||
|
3684b38310 | ||
|
f472275196 | ||
|
2bca6753d3 | ||
|
dd8f22e698 | ||
|
96b1e435c2 | ||
|
971757e997 | ||
|
2b154e0b88 | ||
|
5d35a75743 | ||
|
fc38e23d8f | ||
|
5c16c73a6c | ||
|
3f665b939d | ||
|
f2f49104ea | ||
|
c2ee564e11 | ||
|
f95db091bc | ||
|
78dbc8ae0f | ||
|
a0cb9c5d6a | ||
|
3ca66d0184 | ||
|
70b7e51df6 | ||
|
1164cd90dc | ||
|
4bbdbe3894 | ||
|
28855767fb |
@@ -1,4 +1,7 @@
|
||||
version: 2
|
||||
filters:
|
||||
branches:
|
||||
only: python-2.4
|
||||
jobs:
|
||||
build:
|
||||
parallelism: 1
|
||||
@@ -32,7 +35,12 @@ jobs:
|
||||
- v2-dependencies-
|
||||
|
||||
- run:
|
||||
command: sudo easy_install xdis spark-parser && sudo pip install -e . && sudo pip install -r requirements-dev.txt
|
||||
command: | # Use pip to install dependengcies
|
||||
sudo easy_install click==7.1.2
|
||||
# Until next release use github xdis
|
||||
sudo pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
sudo pip install -e .
|
||||
sudo pip install -r requirements-dev.txt
|
||||
|
||||
# Save dependency cache
|
||||
- save_cache:
|
||||
|
28
.editorconfig
Normal file
28
.editorconfig
Normal file
@@ -0,0 +1,28 @@
|
||||
# THis is an EditorConfig file
|
||||
# https://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[Makefile]
|
||||
indent_style = tab
|
30
.github/workflows/osx.yml
vendored
Normal file
30
.github/workflows/osx.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (osx)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS]
|
||||
python-version: [2.7]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# Until the next xdis release
|
||||
pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
pip install -e .
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Test uncompyle6
|
||||
run: |
|
||||
make check
|
30
.github/workflows/ubuntu.yml
vendored
Normal file
30
.github/workflows/ubuntu.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (ubuntu)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
# Until the next xdis release
|
||||
pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
pip install -e .
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Test uncompyle6
|
||||
run: |
|
||||
make check
|
30
.github/workflows/windows.yml
vendored
Normal file
30
.github/workflows/windows.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (windows)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows]
|
||||
python-version: [2.7]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# Until the next xdis release
|
||||
pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
pip install -e .
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Test uncompyle6
|
||||
run: |
|
||||
make check
|
@@ -4,6 +4,8 @@ python:
|
||||
- 2.7 # this is a cheat here because travis doesn't do 2.4-2.6
|
||||
|
||||
install:
|
||||
# Remove the next line when xdis 6.0.0 is released
|
||||
# - pip install git://github.com/rocky/python-xdis.git#egg=xdis
|
||||
- pip install -e .
|
||||
- pip install -r requirements-dev.txt
|
||||
|
||||
|
@@ -20,14 +20,9 @@
|
||||
This decompiler is a constant work in progress: Python keeps
|
||||
changing, and so does its code generation.
|
||||
|
||||
There is no Python decompiler yet that I know about that will
|
||||
decompile everything. Overall, I think this one probably does the best
|
||||
job of *any* Python decompiler that handles such a wide range of
|
||||
versions.
|
||||
There is no Python decompiler yet that I know about that will decompile everything. Overall, I think this one probably does the best job of *any* Python decompiler that handles such a wide range of versions.
|
||||
|
||||
But at any given time, there are a number of valid Python bytecode
|
||||
files that I know of that will cause problems. See, for example, the
|
||||
list in
|
||||
But at any given time, there are a number of valid Python bytecode files that I know of that will cause problems. See, for example, the list in
|
||||
[`test/stdlib/runtests.sh`](https://github.com/rocky/python-uncompyle6/blob/master/test/stdlib/runtests.sh).
|
||||
|
||||
There are far more bug reporters than there are bug fixers.
|
||||
@@ -40,7 +35,7 @@ Unless you are a sponsor of this project, it may take a while, maybe a week or s
|
||||
## Do you have valid bytecode?
|
||||
|
||||
As mentioned in README.rst, this project doesn't handle obfuscated
|
||||
code. See README.rst for suggestions for how to remove some kinds of
|
||||
code or release candidates. See README.rst for suggestions for how to remove some kinds of
|
||||
obfuscation.
|
||||
|
||||
Checking if bytecode is valid is pretty simple: disassemble the code.
|
||||
@@ -122,8 +117,7 @@ if False:
|
||||
|
||||
Python will eliminate the entire "if" statement.
|
||||
|
||||
So just because the text isn't the same, does not
|
||||
necessarily mean there's a bug.
|
||||
So just because the text isn't the same, this does not necessarily mean there's a bug.
|
||||
|
||||
# What to send (minimum requirements)
|
||||
|
||||
@@ -154,26 +148,18 @@ provide the input command and the output from that, please give:
|
||||
|
||||
## But I don't *have* the source code!
|
||||
|
||||
There is Python assembly code on parse errors, so simply by hand decompile that. To get a full disassembly, use `pydisasm` from the [xdis](https://pypi.python.org/pypi/xdis) package. Opcodes are described in the documentation for the[dis](https://docs.python.org/3.6/library/dis.html) module.
|
||||
There is Python assembly code on parse errors, so simply by hand decompile that. To get a full disassembly, use `pydisasm` from the [xdis](https://pypi.python.org/pypi/xdis) package. Opcodes are described in the documentation for the [dis](https://docs.python.org/3.6/library/dis.html) module.
|
||||
|
||||
### But I don't *have* the source code and am incapable of figuring how to do a hand disassembly!
|
||||
|
||||
Well, you could learn. No one is born into this world knowing how to
|
||||
disassemble Python bytecode. And as Richard Feynman once said, "What
|
||||
one fool can learn, so can another."
|
||||
Well, you could learn. No one is born into this world knowing how to disassemble Python bytecode. And as Richard Feynman once said, "What one fool can learn, so can another."
|
||||
|
||||
If this is too difficult, or too time consuming, or not of interest to
|
||||
you, then you might consider sponsoring the project. [Crazy
|
||||
Compilers](http://www.crazy-compilers.com/decompyle/) offers a
|
||||
byte-code decompiler service for versions of Python up to 2.6. (If
|
||||
there are others around let me know and I'll list them here.)
|
||||
If this is too difficult, or too time consuming, or not of interest to you, then you might consider [sponsoring](https://github.com/sponsors/rocky) the project. [Crazy
|
||||
Compilers](http://www.crazy-compilers.com/decompyle/) offers a byte-code decompiler service for versions of Python up to 2.6. (If there are others around let me know and I'll list them here.)
|
||||
|
||||
# Narrowing the problem
|
||||
|
||||
I don't need or want the entire source code base for the file(s) or
|
||||
module(s) can't be decompiled. I just need those file(s) or module(s).
|
||||
If there are problems in several files, file a bug report for each
|
||||
file.
|
||||
I don't need or want the entire source code base for the file(s) or module(s) can't be decompiled. I just need those file(s) or module(s). If there are problems in several files, file a bug report for each file.
|
||||
|
||||
Python modules can get quite large, and usually decompilation problems
|
||||
occur in a single function or maybe the main-line code but not any of
|
||||
|
11
NEWS.md
11
NEWS.md
@@ -1,3 +1,14 @@
|
||||
3.8.0: 2020-10-29
|
||||
=================
|
||||
|
||||
* Better handling of invalid bytecode magic
|
||||
* Support running from 3.9 and 3.10 although we do not support those bytecodes
|
||||
* Redo version comparisons using tuples instead of floats. This is needed for Python 3.10
|
||||
* Split out into 3 branches so that the master branch can assume Python 3.6+ conventions, especially type annotations
|
||||
* Source Fragment fixes
|
||||
* Lambda-bug fixes #360
|
||||
* Bug fixes
|
||||
|
||||
3.7.4: 2020-8-05
|
||||
================
|
||||
|
||||
|
@@ -240,7 +240,7 @@ be solved if one were to put in the time to do so. The problem is that
|
||||
there aren't that many people who have been working on bug fixing.
|
||||
|
||||
Some of the bugs in 3.7 and 3.8 are simply a matter of back-porting
|
||||
the fixes in decmopyle3.
|
||||
the fixes in decompyle3.
|
||||
|
||||
You may run across a bug, that you want to report. Please do so. But
|
||||
be aware that it might not get my attention for a while. If you
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018, 2020 Rocky Bernstein <rocky@gnu.org>
|
||||
# Copyright (C) 2018, 2020-2021 Rocky Bernstein <rocky@gnu.org>
|
||||
#
|
||||
# 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
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
# Things that change more often go here.
|
||||
copyright = """
|
||||
Copyright (C) 2015-2020 Rocky Bernstein <rb@dustyfeet.com>.
|
||||
Copyright (C) 2015-2021 Rocky Bernstein <rb@dustyfeet.com>.
|
||||
"""
|
||||
|
||||
classifiers = [
|
||||
@@ -43,10 +43,12 @@ classifiers = [
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.4",
|
||||
"Programming Language :: Python :: 2.5",
|
||||
"Programming Language :: Python :: 2.6",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.0",
|
||||
"Programming Language :: Python :: 3.1",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
@@ -56,6 +58,9 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
"Topic :: Software Development :: Debuggers",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
@@ -70,7 +75,7 @@ entry_points = {
|
||||
]
|
||||
}
|
||||
ftp_url = None
|
||||
install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 5.0.4, <5.1.0"]
|
||||
install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.2, < 6.1.0"]
|
||||
|
||||
license = "GPL3"
|
||||
mailing_list = "python-debugger@googlegroups.com"
|
||||
@@ -98,6 +103,6 @@ def read(*rnames):
|
||||
return open(os.path.join(srcdir, *rnames)).read()
|
||||
|
||||
|
||||
# Get info from files; set: long_description and VERSION
|
||||
# Get info from files; set: long_description and __version__
|
||||
long_description = read("README.rst") + "\n"
|
||||
exec(read("uncompyle6/version.py"))
|
||||
|
@@ -6,7 +6,7 @@ owd=$(pwd)
|
||||
trap finish EXIT
|
||||
|
||||
cd $(dirname ${BASH_SOURCE[0]})
|
||||
if ! source ./pyenv-older-versions ; then
|
||||
if ! source ./pyenv-2.4-2.7-versions ; then
|
||||
exit $?
|
||||
fi
|
||||
if ! source ./setup-python-2.4.sh ; then
|
@@ -8,7 +8,7 @@ owd=$(pwd)
|
||||
trap finish EXIT
|
||||
|
||||
cd $(dirname ${BASH_SOURCE[0]})
|
||||
if ! source ./pyenv-newer-versions ; then
|
||||
if ! source ./pyenv-newest-versions ; then
|
||||
exit $?
|
||||
fi
|
||||
if ! source ./setup-master.sh ; then
|
@@ -57,9 +57,9 @@
|
||||
$ . ./admin-tools/make-dist-older.sh
|
||||
$ pyenv local 3.8.5
|
||||
$ twine check dist/uncompyle6-$VERSION*
|
||||
$ git tag release-python-2.4-$VERSION
|
||||
$ ./admin-tools/make-dist-newer.sh
|
||||
$ twine check dist/uncompyle6-$VERSION*
|
||||
$ git tag release-python-2.4-$VERSION
|
||||
|
||||
# Check package on github
|
||||
|
||||
|
@@ -9,7 +9,7 @@ owd=$(pwd)
|
||||
trap finish EXIT
|
||||
|
||||
cd $(dirname ${BASH_SOURCE[0]})
|
||||
if ! source ./pyenv-older-versions ; then
|
||||
if ! source ./pyenv-2.4-2.7-versions ; then
|
||||
exit $?
|
||||
fi
|
||||
if ! source ./setup-python-2.4.sh ; then
|
||||
@@ -18,7 +18,7 @@ fi
|
||||
|
||||
cd ..
|
||||
source $PACKAGE/version.py
|
||||
echo $VERSION
|
||||
echo $__version__
|
||||
|
||||
for pyversion in $PYVERSIONS; do
|
||||
if ! pyenv local $pyversion ; then
|
||||
@@ -29,11 +29,15 @@ for pyversion in $PYVERSIONS; do
|
||||
python setup.py bdist_egg
|
||||
done
|
||||
|
||||
pyenv local 2.7.18
|
||||
python setup.py bdist_wheel
|
||||
mv -v dist/${PACKAGE}-$__version__-py2{.py3,}-none-any.whl
|
||||
|
||||
# Pypi can only have one source tarball.
|
||||
# Tarballs can get created from the above setup, so make sure to remove them since we want
|
||||
# the tarball from master.
|
||||
|
||||
tarball=dist/${PACKAGE}-$VERSION-tar.gz
|
||||
tarball=dist/${PACKAGE}-${__version_}_-tar.gz
|
||||
if [[ -f $tarball ]]; then
|
||||
rm -v dist/${PACKAGE}-$VERSION-tar.gz
|
||||
rm -v dist/${PACKAGE}-${__version__}-tar.gz
|
||||
fi
|
38
admin-tools/make-dist-3.3-3.5.sh
Executable file
38
admin-tools/make-dist-3.3-3.5.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
PACKAGE=uncompyle6
|
||||
|
||||
# FIXME put some of the below in a common routine
|
||||
function finish {
|
||||
cd $owd
|
||||
}
|
||||
|
||||
cd $(dirname ${BASH_SOURCE[0]})
|
||||
owd=$(pwd)
|
||||
trap finish EXIT
|
||||
|
||||
if ! source ./pyenv-3.3-3.5-versions ; then
|
||||
exit $?
|
||||
fi
|
||||
if ! source ./setup-python-3.3.sh ; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
cd ..
|
||||
source $PACKAGE/version.py
|
||||
echo $__version__
|
||||
|
||||
for pyversion in $PYVERSIONS; do
|
||||
if ! pyenv local $pyversion ; then
|
||||
exit $?
|
||||
fi
|
||||
# pip bdist_egg create too-general wheels. So
|
||||
# we narrow that by moving the generated wheel.
|
||||
|
||||
# Pick out first two number of version, e.g. 3.5.1 -> 35
|
||||
first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//')
|
||||
rm -fr build
|
||||
python setup.py bdist_egg bdist_wheel
|
||||
mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl
|
||||
done
|
||||
|
||||
python ./setup.py sdist
|
@@ -10,7 +10,7 @@ cd $(dirname ${BASH_SOURCE[0]})
|
||||
owd=$(pwd)
|
||||
trap finish EXIT
|
||||
|
||||
if ! source ./pyenv-newer-versions ; then
|
||||
if ! source ./pyenv-newest-versions ; then
|
||||
exit $?
|
||||
fi
|
||||
if ! source ./setup-master.sh ; then
|
||||
@@ -19,7 +19,7 @@ fi
|
||||
|
||||
cd ..
|
||||
source $PACKAGE/version.py
|
||||
echo $VERSION
|
||||
echo $__version__
|
||||
|
||||
for pyversion in $PYVERSIONS; do
|
||||
if ! pyenv local $pyversion ; then
|
||||
@@ -32,7 +32,7 @@ for pyversion in $PYVERSIONS; do
|
||||
first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//')
|
||||
rm -fr build
|
||||
python setup.py bdist_egg bdist_wheel
|
||||
mv -v dist/${PACKAGE}-$VERSION-{py2.py3,py$first_two}-none-any.whl
|
||||
mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl
|
||||
done
|
||||
|
||||
python ./setup.py sdist
|
9
admin-tools/pyenv-2.4-2.7-versions
Normal file
9
admin-tools/pyenv-2.4-2.7-versions
Normal file
@@ -0,0 +1,9 @@
|
||||
# -*- shell-script -*-
|
||||
# Sets PYVERSIONS to be pyenv versions that
|
||||
# we can use in the python-2.4-to-2.7 branch.
|
||||
|
||||
if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='2.4.6 2.5.6 2.6.9 2.7.18'
|
@@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='2.4.6 2.5.6'
|
||||
export PYVERSIONS='3.1.5 3.2.6'
|
8
admin-tools/pyenv-3.3-3.5-versions
Normal file
8
admin-tools/pyenv-3.3-3.5-versions
Normal file
@@ -0,0 +1,8 @@
|
||||
# -*- shell-script -*-
|
||||
# Sets PYVERSIONS to be pyenv versions that
|
||||
# we can use in the python-3.3-to-3.5 branch.
|
||||
if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS=' 3.3.7 3.4.10 3.5.10 '
|
@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='3.5.9 3.6.12 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.9 3.8.5'
|
||||
export PYVERSIONS='3.6.15 3.7.12 pyston-2.3 3.8.11 3.9.7 3.10.0'
|
8
admin-tools/pyenv-versions
Normal file
8
admin-tools/pyenv-versions
Normal file
@@ -0,0 +1,8 @@
|
||||
# -*- shell-script -*-
|
||||
# Sets PYVERSIONS to be pyenv versions that
|
||||
# we can use in the master branch.
|
||||
if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='3.7.11 3.8.12 3.9.7 3.10.0'
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PYTHON_VERSION=3.7.7
|
||||
PYTHON_VERSION=3.7.12
|
||||
|
||||
# FIXME put some of the below in a common routine
|
||||
function finish {
|
||||
@@ -20,4 +20,4 @@ cd $fulldir/..
|
||||
(cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \
|
||||
git checkout master && pyenv local $PYTHON_VERSION && git pull
|
||||
cd $owd
|
||||
rm -v */.python-version || true
|
||||
rm -v */.python-version >/dev/null 2>&1 || true
|
||||
|
@@ -11,7 +11,7 @@ mydir=$(dirname $bs)
|
||||
fulldir=$(readlink -f $mydir)
|
||||
cd $fulldir/..
|
||||
(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \
|
||||
(cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \
|
||||
(cd ../python-xdis && . ./admin-tools/setup-python-2.4.sh) && \
|
||||
git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull
|
||||
cd $owd
|
||||
rm -v */.python-version || true
|
||||
|
15
admin-tools/setup-python-3.3.sh
Normal file
15
admin-tools/setup-python-3.3.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
PYTHON_VERSION=3.3.7
|
||||
pyenv local $PYTHON_VERSION
|
||||
|
||||
owd=$(pwd)
|
||||
bs=${BASH_SOURCE[0]}
|
||||
|
||||
mydir=$(dirname $bs)
|
||||
fulldir=$(readlink -f $mydir)
|
||||
cd $fulldir/..
|
||||
(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh)
|
||||
cd $owd
|
||||
rm -v */.python-version || true
|
||||
|
||||
git checkout python-3.3-to-3.5 && git pull && pyenv local $PYTHON_VERSION
|
79
appveyor.yml
79
appveyor.yml
@@ -1,79 +0,0 @@
|
||||
environment:
|
||||
global:
|
||||
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
|
||||
# /E:ON and /V:ON options are not enabled in the batch script intepreter
|
||||
# See: http://stackoverflow.com/a/13751649/163740
|
||||
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd"
|
||||
|
||||
matrix:
|
||||
|
||||
# Pre-installed Python versions, which Appveyor may upgrade to
|
||||
# a later point release.
|
||||
# See: http://www.appveyor.com/docs/installed-software#python
|
||||
|
||||
# - PYTHON: "C:\\Python27"
|
||||
# PYTHON_VERSION: "2.7.x"
|
||||
# PYTHON_ARCH: "32"
|
||||
|
||||
- PYTHON: "C:\\Python27-x64"
|
||||
PYTHON_VERSION: "2.7.x"
|
||||
PYTHON_ARCH: "64"
|
||||
|
||||
# - PYTHON: "C:\\Python26"
|
||||
# PYTHON_VERSION: "2.6.x"
|
||||
# PYTHON_ARCH: "32"
|
||||
|
||||
# - PYTHON: "C:\\Python26-x64"
|
||||
# PYTHON_VERSION: "2.6.x"
|
||||
# PYTHON_ARCH: "64"
|
||||
|
||||
install:
|
||||
# We need wheel installed to build wheels
|
||||
- "%PYTHON%\\python.exe -m pip install wheel"
|
||||
|
||||
# Install Python (from the official .msi of http://python.org) and pip when
|
||||
# not already installed.
|
||||
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
|
||||
|
||||
# Prepend newly installed Python to the PATH of this build (this cannot be
|
||||
# done from inside the powershell script as it would require to restart
|
||||
# the parent CMD process).
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
- "SET HOME=."
|
||||
|
||||
# Check that we have the expected version and architecture for Python
|
||||
- "python --version"
|
||||
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||
|
||||
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||
# about it being out of date.
|
||||
- "%PYTHON%\\python.exe -m pip install --disable-pip-version-check --user --upgrade pip"
|
||||
|
||||
# Install the build dependencies of the project. If some dependencies contain
|
||||
# compiled extensions and are not provided as pre-built wheel packages,
|
||||
# pip will build them from source using the MSVC compiler matching the
|
||||
# target Python version and architecture
|
||||
- "%CMD_IN_ENV% pip install git+git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6-3.6.6"
|
||||
- "%CMD_IN_ENV% pip install -r requirements.txt"
|
||||
|
||||
build_script:
|
||||
# Build the compiled extension
|
||||
- "%CMD_IN_ENV% python setup.py build"
|
||||
|
||||
test_script:
|
||||
# Run the project tests
|
||||
- "%CMD_IN_ENV% python test/test_pyenvlib.py --native --syntax-verify"
|
||||
|
||||
after_test:
|
||||
# If tests are successful, create binary packages for the project.
|
||||
- "%CMD_IN_ENV% python setup.py bdist_wininst"
|
||||
- "%CMD_IN_ENV% python setup.py bdist_msi"
|
||||
- ps: "ls dist"
|
||||
|
||||
artifacts:
|
||||
# Archive the generated packages in the ci.appveyor.com build report.
|
||||
- path: dist\*
|
||||
|
||||
#on_success:
|
||||
# - TODO: upload the content of dist/*.whl to a public wheelhouse
|
||||
#
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY, version_tuple_to_str
|
||||
from uncompyle6.scanner import get_scanner
|
||||
def bug(state, slotstate):
|
||||
if state:
|
||||
@@ -21,8 +21,8 @@ def bug_loop(disassemble, tb=None):
|
||||
|
||||
def test_if_in_for():
|
||||
code = bug.func_code
|
||||
scan = get_scanner(PYTHON_VERSION)
|
||||
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
|
||||
scan = get_scanner(PYTHON_VERSION_TRIPLE)
|
||||
if (2, 7) <= PYTHON_VERSION_TRIPLE < (3, 1) and not IS_PYPY:
|
||||
scan.build_instructions(code)
|
||||
fjt = scan.find_jump_targets(False)
|
||||
|
||||
@@ -51,7 +51,7 @@ def test_if_in_for():
|
||||
# previous bug was not mistaking while-loop for if-then
|
||||
{'start': 48, 'end': 67, 'type': 'while-loop'}]
|
||||
|
||||
elif 3.2 < PYTHON_VERSION <= 3.4:
|
||||
elif (3, 2) < PYTHON_VERSION_TRIPLE <= (3, 4):
|
||||
scan.build_instructions(code)
|
||||
fjt = scan.find_jump_targets(False)
|
||||
assert {69: [66], 63: [18]} == fjt
|
||||
@@ -62,6 +62,6 @@ def test_if_in_for():
|
||||
{'end': 59, 'type': 'for-loop', 'start': 31},
|
||||
{'end': 63, 'type': 'for-else', 'start': 62}]
|
||||
else:
|
||||
print("FIXME: should fix for %s" % PYTHON_VERSION)
|
||||
print("FIXME: should fix for %s" % version_tuple_to_str())
|
||||
assert True
|
||||
return
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import re
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY # , PYTHON_VERSION
|
||||
from uncompyle6.parser import get_python_parser, python_parser
|
||||
from uncompyle6.scanner import get_scanner
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY
|
||||
|
||||
|
||||
def test_grammar():
|
||||
@@ -16,19 +16,19 @@ def test_grammar():
|
||||
p.dump_grammar(),
|
||||
)
|
||||
|
||||
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
|
||||
p = get_python_parser(PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY)
|
||||
(lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets()
|
||||
|
||||
# We have custom rules that create the below
|
||||
expect_lhs = set(["pos_arg"])
|
||||
|
||||
if PYTHON_VERSION < 3.8:
|
||||
if PYTHON_VERSION < 3.7:
|
||||
if PYTHON_VERSION_TRIPLE < (3, 8):
|
||||
if PYTHON_VERSION_TRIPLE < (3, 7):
|
||||
expect_lhs.add("attribute")
|
||||
|
||||
expect_lhs.add("get_iter")
|
||||
|
||||
if PYTHON_VERSION > 3.7 or PYTHON_VERSION < 3.0:
|
||||
if PYTHON_VERSION_TRIPLE >= (3, 8) or PYTHON_VERSION_TRIPLE < (3, 0):
|
||||
expect_lhs.add("stmts_opt")
|
||||
else:
|
||||
expect_lhs.add("async_with_as_stmt")
|
||||
@@ -38,10 +38,10 @@ def test_grammar():
|
||||
|
||||
expect_right_recursive = set([("designList", ("store", "DUP_TOP", "designList"))])
|
||||
|
||||
if PYTHON_VERSION <= 3.6:
|
||||
if PYTHON_VERSION_TRIPLE[:2] <= (3, 6):
|
||||
unused_rhs.add("call")
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION_TRIPLE >= (2, 7):
|
||||
expect_lhs.add("kvlist")
|
||||
expect_lhs.add("kv3")
|
||||
unused_rhs.add("dict")
|
||||
@@ -49,7 +49,7 @@ def test_grammar():
|
||||
# NOTE: this may disappear
|
||||
expect_lhs.add("except_handler_else")
|
||||
|
||||
if PYTHON_VERSION < 3.7 and PYTHON_VERSION != 2.7:
|
||||
if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] != (2, 7):
|
||||
# NOTE: this may disappear
|
||||
expect_lhs.add("except_handler_else")
|
||||
|
||||
@@ -63,8 +63,8 @@ def test_grammar():
|
||||
""".split()
|
||||
)
|
||||
)
|
||||
if PYTHON_VERSION >= 3.0:
|
||||
if PYTHON_VERSION < 3.7:
|
||||
if PYTHON_VERSION_TRIPLE >= (3, 0):
|
||||
if PYTHON_VERSION_TRIPLE < (3, 7):
|
||||
expect_lhs.add("annotate_arg")
|
||||
expect_lhs.add("annotate_tuple")
|
||||
unused_rhs.add("mkfunc_annotate")
|
||||
@@ -72,7 +72,7 @@ def test_grammar():
|
||||
unused_rhs.add("dict_comp")
|
||||
unused_rhs.add("classdefdeco1")
|
||||
unused_rhs.add("tryelsestmtl")
|
||||
if PYTHON_VERSION >= 3.5:
|
||||
if PYTHON_VERSION_TRIPLE >= (3, 5):
|
||||
expect_right_recursive.add(
|
||||
(("l_stmts", ("lastl_stmt", "come_froms", "l_stmts")))
|
||||
)
|
||||
@@ -83,7 +83,7 @@ def test_grammar():
|
||||
expect_lhs.add("kwarg")
|
||||
|
||||
# FIXME
|
||||
if PYTHON_VERSION < 3.8:
|
||||
if PYTHON_VERSION_TRIPLE < (3, 8):
|
||||
assert expect_lhs == set(lhs)
|
||||
assert unused_rhs == set(rhs)
|
||||
|
||||
@@ -106,7 +106,7 @@ def test_grammar():
|
||||
print(k, reduced_dup_rhs[k])
|
||||
# assert not reduced_dup_rhs, reduced_dup_rhs
|
||||
|
||||
s = get_scanner(PYTHON_VERSION, IS_PYPY)
|
||||
s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
|
||||
ignore_set = set(
|
||||
"""
|
||||
JUMP_BACK CONTINUE
|
||||
@@ -119,12 +119,13 @@ def test_grammar():
|
||||
RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST
|
||||
""".split()
|
||||
)
|
||||
if 2.6 <= PYTHON_VERSION <= 2.7:
|
||||
|
||||
if (2, 6) <= PYTHON_VERSION_TRIPLE <= (2, 7):
|
||||
opcode_set = set(s.opc.opname).union(ignore_set)
|
||||
if PYTHON_VERSION == 2.6:
|
||||
if PYTHON_VERSION_TRIPLE[:2] == (2, 6):
|
||||
opcode_set.add("THEN")
|
||||
check_tokens(tokens, opcode_set)
|
||||
elif PYTHON_VERSION == 3.4:
|
||||
elif PYTHON_VERSION_TRIPLE[:2] == (3, 4):
|
||||
ignore_set.add("LOAD_CLASSNAME")
|
||||
ignore_set.add("STORE_LOCALS")
|
||||
opcode_set = set(s.opc.opname).union(ignore_set)
|
||||
@@ -135,7 +136,7 @@ def test_dup_rule():
|
||||
import inspect
|
||||
|
||||
python_parser(
|
||||
PYTHON_VERSION,
|
||||
PYTHON_VERSION_TRIPLE,
|
||||
inspect.currentframe().f_code,
|
||||
is_pypy=IS_PYPY,
|
||||
parser_debug={
|
||||
|
@@ -1,6 +1,7 @@
|
||||
from uncompyle6 import PYTHON_VERSION, code_deparse
|
||||
from uncompyle6 import code_deparse
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION_TRIPLE >= (2, 7):
|
||||
def test_single_mode():
|
||||
single_expressions = (
|
||||
'i = 1',
|
||||
|
@@ -9,12 +9,13 @@ import tempfile
|
||||
import functools
|
||||
|
||||
# uncompyle6 / xdis
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse
|
||||
from uncompyle6 import code_deparse
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY
|
||||
|
||||
# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
|
||||
from xdis import Bytecode, get_opcode
|
||||
|
||||
opc = get_opcode(PYTHON_VERSION, IS_PYPY)
|
||||
opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY)
|
||||
Bytecode = functools.partial(Bytecode, opc=opc)
|
||||
import six
|
||||
|
||||
@@ -127,7 +128,7 @@ def validate_uncompyle(text, mode="exec"):
|
||||
original_text = text
|
||||
|
||||
deparsed = code_deparse(
|
||||
original_code, out=six.StringIO(), version=PYTHON_VERSION, compile_mode=mode
|
||||
original_code, out=six.StringIO(), version=PYTHON_VERSION_TRIPLE, compile_mode=mode
|
||||
)
|
||||
uncompyled_text = deparsed.text
|
||||
uncompyled_code = compile(uncompyled_text, "<string>", "exec")
|
||||
|
58
setup.cfg
58
setup.cfg
@@ -1,11 +1,57 @@
|
||||
[bdist_rpm]
|
||||
release = 1
|
||||
packager = rocky <rb@dustyfeet.com>
|
||||
doc_files = README
|
||||
release = 0
|
||||
packager = rocky <rb@dustyfeet.com
|
||||
doc_files = README.rst
|
||||
ChangeLog
|
||||
COPYING
|
||||
DECOMPYLE-2.4-CHANGELOG.txt
|
||||
HISTORY.md
|
||||
HOW-TO_REPORT-A-BUG.md
|
||||
NEWS.md
|
||||
# doc/
|
||||
# examples/
|
||||
|
||||
[bdist_wheel]
|
||||
universal=1
|
||||
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
[metadata]
|
||||
description_file = README.rst
|
||||
|
||||
[flake8]
|
||||
# max-line-length setting: NO we do not want everyone writing 120-character lines!
|
||||
# We are setting the maximum line length big here because there are longer
|
||||
# lines allowed by black in some cases that are forbidden by flake8. Since
|
||||
# black has the final say about code formatting issues, this setting is here to
|
||||
# make sure that flake8 doesn't fail the build on longer lines allowed by
|
||||
# black.
|
||||
max-line-length = 120
|
||||
max-complexity = 12
|
||||
select = E,F,W,C,B,B9
|
||||
ignore =
|
||||
# E123 closing bracket does not match indentation of opening bracket's line
|
||||
E123
|
||||
# E203 whitespace before ':' (Not PEP8 compliant, Python Black)
|
||||
E203
|
||||
# E501 line too long (82 > 79 characters) (replaced by B950 from flake8-bugbear,
|
||||
# https://github.com/PyCQA/flake8-bugbear)
|
||||
E501
|
||||
# W503 line break before binary operator (Not PEP8 compliant, Python Black)
|
||||
W503
|
||||
# W504 line break after binary operator (Not PEP8 compliant, Python Black)
|
||||
W504
|
||||
# C901 function too complex - since many of zz9 functions are too complex with a lot
|
||||
# of if branching
|
||||
C901
|
||||
# module level import not at top of file. This is too restrictive. Can't even have a
|
||||
# docstring higher.
|
||||
E402
|
||||
per-file-ignores =
|
||||
# These are config files. The `c` variable them is injected not defined.
|
||||
pow/ansible/roles/jupyterhub/templates/jupyterhub_config*.py:F821
|
||||
# Ignore some errors in files that are stolen from other projects to avoid lots
|
||||
# of merge problems later .
|
||||
pow/ansible/roles/webtier/files/supervisor_httpgroupok.py:E126,E128,E222,E225,E226,E261,E301,E302,E305,F841,E201,E202
|
||||
silhouette/src/silhouette/gprof2dot.py:E711,E713,E741,F401
|
||||
# Ignore undefined name errors in "expectation" test Python code.
|
||||
# These files get exec'd in an environment that defines the variables.
|
||||
server/tests/files/expectations/*.py:F821
|
||||
|
18
setup.py
18
setup.py
@@ -6,12 +6,18 @@ import sys
|
||||
SYS_VERSION = sys.version_info[0:2]
|
||||
if not ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess = "Python Release 2.4 .. 2.7 are supported in this code branch."
|
||||
if ((3, 2) <= SYS_VERSION <= (3, 8)):
|
||||
if ((3, 6) <= SYS_VERSION < (3, 9)):
|
||||
mess += ("\nFor your Python, version %s, use the master code/branch." %
|
||||
sys.version[0:3])
|
||||
else:
|
||||
mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s."
|
||||
% sys.version[0:3])
|
||||
elif (3, 3) <= SYS_VERSION <= (3, 6):
|
||||
mess += (
|
||||
"\nFor your Python, version %s, use the python-3.3-3.5 code/branch."
|
||||
% sys.version[0:3]
|
||||
)
|
||||
elif SYS_VERSION < (2, 4):
|
||||
mess += (
|
||||
"\nThis package is not supported for Python before Python 2.4 version %s." % sys.version[0:3]
|
||||
)
|
||||
print(mess)
|
||||
raise Exception(mess)
|
||||
|
||||
@@ -26,7 +32,7 @@ from __pkginfo__ import (
|
||||
modname,
|
||||
py_modules,
|
||||
short_desc,
|
||||
VERSION,
|
||||
__version__,
|
||||
web,
|
||||
zip_safe,
|
||||
)
|
||||
@@ -49,6 +55,6 @@ setup(
|
||||
test_suite="nose.collector",
|
||||
url=web,
|
||||
tests_require=["nose>=1.0"],
|
||||
version=VERSION,
|
||||
version=__version__,
|
||||
zip_safe=zip_safe,
|
||||
)
|
||||
|
@@ -13,7 +13,7 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea
|
||||
GIT2CL ?= git2cl
|
||||
PYTHON ?= python
|
||||
|
||||
PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2)
|
||||
PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2 | head -1)
|
||||
NATIVE_CHECK = check-$(PYTHON_VERSION)
|
||||
|
||||
# Set COMPILE='--compile' to force compilation before check
|
||||
@@ -22,8 +22,8 @@ COVER_DIR=../tmp/grammar-cover
|
||||
|
||||
# Run short tests
|
||||
check-short:
|
||||
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
||||
$(MAKE) check-bytecode-$${PYTHON_VERSION}
|
||||
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2` | head -1; \
|
||||
$(MAKE) check-bytecode-${PYTHON_VERSION}
|
||||
|
||||
# Run all tests
|
||||
check:
|
||||
@@ -77,6 +77,12 @@ check-3.7: check-bytecode
|
||||
# $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
|
||||
# $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE)
|
||||
|
||||
check-3.9: check-bytecode
|
||||
@echo "Note that we do not support decompiling Python 3.9 bytecode - no 3.9 tests run"
|
||||
|
||||
check-3.10: check-bytecode
|
||||
@echo "Note that we do not support decompiling Python 3.10 bytecode - no 3.10 tests run"
|
||||
|
||||
# FIXME
|
||||
#: this is called when running under pypy3.5-5.8.0, pypy2-5.6.0, or pypy3.6-7.3.0
|
||||
5.8 5.6:
|
||||
|
BIN
test/bytecode_2.4_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.4_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.6_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.7_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_3.7_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_3.8_run/01_lambda_call.pyc
Normal file
Binary file not shown.
4
test/simple_source/bug22/01_lambda_call.py
Normal file
4
test/simple_source/bug22/01_lambda_call.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# From https://github.com/rocky/python-uncompyle6/issues/350
|
||||
# This is RUNNABLE!
|
||||
a = (lambda x: x)(abs)
|
||||
assert a(-3) == 3
|
@@ -1,5 +1,5 @@
|
||||
# Python 3.3 pyclbr.py
|
||||
# Note that Python 3 adds a lot of unecessary "continues"
|
||||
# Note that Python 3 adds a lot of unnecessary "continues"
|
||||
# and puts that in for "pass"
|
||||
def _readmodule(g, token, path):
|
||||
for tokentype in g:
|
||||
|
@@ -30,6 +30,8 @@ import xdis.magics as magics
|
||||
# ----- configure this for your needs
|
||||
|
||||
python_versions = [v for v in magics.python_versions if re.match("^[0-9.]+$", v)]
|
||||
print(python_versions)
|
||||
sys.exit(0)
|
||||
|
||||
# FIXME: we should remove Python versions that we don't support.
|
||||
# These include Jython, and Python bytecode changes pre release.
|
||||
|
@@ -30,10 +30,7 @@ import sys
|
||||
|
||||
__docformat__ = "restructuredtext"
|
||||
|
||||
from uncompyle6.version import VERSION
|
||||
|
||||
# This ensures VERSION will appear in pydoc
|
||||
__version__ = VERSION
|
||||
from uncompyle6.version import __version__
|
||||
|
||||
PYTHON3 = sys.version_info >= (3, 0)
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
# Mode: -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2015-2016, 2018 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
# Copyright (c) 2015-2016, 2018, 2020 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
#
|
||||
import sys, os, getopt
|
||||
|
||||
from uncompyle6.disas import disassemble_file
|
||||
from uncompyle6.version import VERSION
|
||||
from uncompyle6.version import __version__
|
||||
|
||||
program, ext = os.path.splitext(os.path.basename(__file__))
|
||||
|
||||
@@ -57,7 +57,7 @@ Type -h for for full help.""" % program
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
elif opt in ('-V', '--version'):
|
||||
print("%s %s" % (program, VERSION))
|
||||
print("%s %s" % (program, __version__))
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(opt)
|
||||
|
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# Mode: -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2015-2017, 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2017, 2019-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
import sys, os, getopt, time
|
||||
from xdis.version_info import version_tuple_to_str
|
||||
|
||||
program = 'uncompyle6'
|
||||
|
||||
@@ -62,7 +63,7 @@ program = 'uncompyle6'
|
||||
|
||||
from uncompyle6 import verify
|
||||
from uncompyle6.main import main, status_msg
|
||||
from uncompyle6.version import VERSION
|
||||
from uncompyle6.version import __version__
|
||||
|
||||
def usage():
|
||||
print(__doc__)
|
||||
@@ -70,9 +71,12 @@ def usage():
|
||||
|
||||
|
||||
def main_bin():
|
||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7))):
|
||||
sys.stderr.write('Error: this branch of %s requires Python 2.4, 2.5, 2.6 or 2.7'
|
||||
% program)
|
||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7), (3, 0),
|
||||
(3, 1), (3, 2), (3, 3),
|
||||
(3, 4), (3, 5), (3, 6),
|
||||
(3, 7), (3, 8), (3, 9), (3, 10)
|
||||
)):
|
||||
print('Error: %s requires Python 2.4-3.10' % program)
|
||||
sys.exit(-1)
|
||||
|
||||
do_verify = recurse_dirs = False
|
||||
@@ -101,7 +105,7 @@ def main_bin():
|
||||
print(__doc__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-V', '--version'):
|
||||
print("%s %s" % (program, VERSION))
|
||||
print("%s %s" % (program, __version__))
|
||||
sys.exit(0)
|
||||
elif opt == '--verify':
|
||||
options['do_verify'] = 'strong'
|
||||
@@ -193,6 +197,9 @@ def main_bin():
|
||||
mess = status_msg(do_verify, *result)
|
||||
print('# ' + mess)
|
||||
pass
|
||||
except ImportError:
|
||||
print(str(sys.exc_info()[1]))
|
||||
sys.exit(2)
|
||||
except (KeyboardInterrupt):
|
||||
pass
|
||||
except verify.VerifyCmpError:
|
||||
@@ -221,7 +228,7 @@ def main_bin():
|
||||
if f is None:
|
||||
break
|
||||
(t, o, f, v) = \
|
||||
main(src_base, out_base, [f], None, outfile, **options)
|
||||
main(src_base, out_base, [f], [], outfile, **options)
|
||||
tot_files += t
|
||||
okay_files += o
|
||||
failed_files += f
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2016, 2818-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2016, 2818-2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -33,6 +33,7 @@ import sys
|
||||
from collections import deque
|
||||
|
||||
from xdis import check_object_path, iscode, load_module
|
||||
from xdis.version_info import version_tuple_to_str
|
||||
from uncompyle6.scanner import get_scanner
|
||||
|
||||
|
||||
@@ -45,7 +46,7 @@ def disco(version, co, out=None, is_pypy=False):
|
||||
|
||||
# store final output stream for case of error
|
||||
real_out = out or sys.stdout
|
||||
real_out.write("# Python %s\n" % version)
|
||||
real_out.write("# Python %s\n" % version_tuple_to_str(version))
|
||||
if co.co_filename:
|
||||
real_out.write("# Embedded file name: %s\n" % co.co_filename)
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2020 Rocky Bernstein <rocky@gnu.org>
|
||||
# Copyright (C) 2018-2021 Rocky Bernstein <rocky@gnu.org>
|
||||
#
|
||||
# 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
|
||||
@@ -14,12 +14,13 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import datetime, os, subprocess, sys
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
||||
from xdis import iscode, sysinfo2float
|
||||
from uncompyle6 import verify
|
||||
from xdis import iscode
|
||||
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str
|
||||
from uncompyle6.disas import check_object_path
|
||||
from uncompyle6.semantics import pysource
|
||||
from uncompyle6.parser import ParserError
|
||||
from uncompyle6.version import VERSION
|
||||
from uncompyle6.version import __version__
|
||||
|
||||
# from uncompyle6.linenumbers import line_number_mapping
|
||||
|
||||
@@ -29,7 +30,6 @@ from uncompyle6.semantics.linemap import deparse_code_with_map
|
||||
|
||||
from xdis.load import load_module
|
||||
|
||||
|
||||
def _get_outstream(outfile):
|
||||
dir = os.path.dirname(outfile)
|
||||
failed_file = outfile + "_failed"
|
||||
@@ -66,7 +66,7 @@ def decompile(
|
||||
Caller is responsible for closing `out` and `mapstream`
|
||||
"""
|
||||
if bytecode_version is None:
|
||||
bytecode_version = sysinfo2float()
|
||||
bytecode_version = PYTHON_VERSION_TRIPLE
|
||||
|
||||
# store final output stream for case of error
|
||||
real_out = out or sys.stdout
|
||||
@@ -75,7 +75,7 @@ def decompile(
|
||||
s += "\n"
|
||||
real_out.write(s)
|
||||
|
||||
assert iscode(co)
|
||||
assert iscode(co), ("%s does not smell like code" % co)
|
||||
|
||||
if is_pypy:
|
||||
co_pypy_str = "PyPy "
|
||||
@@ -97,20 +97,21 @@ def decompile(
|
||||
write("# -*- coding: %s -*-" % source_encoding)
|
||||
write(
|
||||
"# uncompyle6 version %s\n"
|
||||
"# %sPython bytecode %s%s\n# Decompiled from: %sPython %s" %
|
||||
(VERSION,
|
||||
co_pypy_str,
|
||||
bytecode_version,
|
||||
"# %sPython bytecode %s%s\n# Decompiled from: %sPython %s"
|
||||
% (
|
||||
__version__,
|
||||
co_pypy_str,
|
||||
version_tuple_to_str(bytecode_version),
|
||||
" (%s)" % m, run_pypy_str,
|
||||
"\n# ".join(sys_version_lines),
|
||||
)
|
||||
"\n# ".join(sys_version_lines),
|
||||
)
|
||||
)
|
||||
if bytecode_version >= 3.0:
|
||||
write(
|
||||
"# Warning: this version of Python has problems handling the Python 3 byte type in constants properly.\n"
|
||||
)
|
||||
if co.co_filename:
|
||||
write("# Embedded file name: %s" % co.co_filename,)
|
||||
write("# Embedded file name: %s" % co.co_filename)
|
||||
if timestamp:
|
||||
write("# Compiled at: %s" %
|
||||
datetime.datetime.fromtimestamp(timestamp))
|
||||
@@ -161,9 +162,9 @@ def compile_file(source_path):
|
||||
basename = source_path
|
||||
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
bytecode_path = "%s-pypy%s.pyc" % (basename, PYTHON_VERSION)
|
||||
bytecode_path = "%s-pypy%s.pyc" % (basename, version_tuple_to_str())
|
||||
else:
|
||||
bytecode_path = "%s-%s.pyc" % (basename, PYTHON_VERSION)
|
||||
bytecode_path = "%s-%s.pyc" % (basename, version_tuple_to_str())
|
||||
|
||||
print("compiling %s to %s" % (source_path, bytecode_path))
|
||||
py_compile.compile(source_path, bytecode_path, "exec")
|
||||
@@ -297,7 +298,7 @@ def main(
|
||||
else:
|
||||
buffering = 0
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering)
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION_TRIPLE > (2, 6):
|
||||
tee = subprocess.Popen(["tee", current_outfile],
|
||||
stdin=subprocess.PIPE)
|
||||
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -21,9 +21,9 @@ Common uncompyle6 parser routines.
|
||||
|
||||
import sys
|
||||
|
||||
from xdis import iscode, py_str2float
|
||||
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
from uncompyle6.show import maybe_show_asm
|
||||
from xdis import iscode
|
||||
|
||||
|
||||
class ParserError(Exception):
|
||||
@@ -640,107 +640,109 @@ def get_python_parser(
|
||||
|
||||
# If version is a string, turn that into the corresponding float.
|
||||
if isinstance(version, str):
|
||||
version = py_str2float(version)
|
||||
version = tuple([int(v) for v in version.split(".")[:2]])
|
||||
|
||||
version = version[:2]
|
||||
|
||||
# FIXME: there has to be a better way...
|
||||
# We could do this as a table lookup, but that would force us
|
||||
# in import all of the parsers all of the time. Perhaps there is
|
||||
# a lazy way of doing the import?
|
||||
|
||||
if version < 3.0:
|
||||
if version < 2.2:
|
||||
if version == 1.0:
|
||||
if version < (3, 0):
|
||||
if version < (2, 2):
|
||||
if version == (1, 0):
|
||||
import uncompyle6.parsers.parse10 as parse10
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse10.Python10Parser(debug_parser)
|
||||
else:
|
||||
p = parse10.Python01ParserSingle(debug_parser)
|
||||
elif version == 1.1:
|
||||
elif version == (1, 1):
|
||||
import uncompyle6.parsers.parse11 as parse11
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse11.Python11Parser(debug_parser)
|
||||
else:
|
||||
p = parse11.Python11ParserSingle(debug_parser)
|
||||
if version == 1.2:
|
||||
if version == (1, 2):
|
||||
import uncompyle6.parsers.parse12 as parse12
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse12.Python12Parser(debug_parser)
|
||||
else:
|
||||
p = parse12.Python12ParserSingle(debug_parser)
|
||||
if version == 1.3:
|
||||
if version == (1, 3):
|
||||
import uncompyle6.parsers.parse13 as parse13
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse13.Python13Parser(debug_parser)
|
||||
else:
|
||||
p = parse13.Python13ParserSingle(debug_parser)
|
||||
elif version == 1.4:
|
||||
elif version == (1, 4):
|
||||
import uncompyle6.parsers.parse14 as parse14
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse14.Python14Parser(debug_parser)
|
||||
else:
|
||||
p = parse14.Python14ParserSingle(debug_parser)
|
||||
elif version == 1.5:
|
||||
elif version == (1, 5):
|
||||
import uncompyle6.parsers.parse15 as parse15
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse15.Python15Parser(debug_parser)
|
||||
else:
|
||||
p = parse15.Python15ParserSingle(debug_parser)
|
||||
elif version == 1.6:
|
||||
elif version == (1, 6):
|
||||
import uncompyle6.parsers.parse16 as parse16
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse16.Python16Parser(debug_parser)
|
||||
else:
|
||||
p = parse16.Python16ParserSingle(debug_parser)
|
||||
elif version == 2.1:
|
||||
elif version == (2, 1):
|
||||
import uncompyle6.parsers.parse21 as parse21
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse21.Python21Parser(debug_parser)
|
||||
else:
|
||||
p = parse21.Python21ParserSingle(debug_parser)
|
||||
elif version == 2.2:
|
||||
elif version == (2, 2):
|
||||
import uncompyle6.parsers.parse22 as parse22
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse22.Python22Parser(debug_parser)
|
||||
else:
|
||||
p = parse22.Python22ParserSingle(debug_parser)
|
||||
elif version == 2.3:
|
||||
elif version == (2, 3):
|
||||
import uncompyle6.parsers.parse23 as parse23
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse23.Python23Parser(debug_parser)
|
||||
else:
|
||||
p = parse23.Python23ParserSingle(debug_parser)
|
||||
elif version == 2.4:
|
||||
elif version == (2, 4):
|
||||
import uncompyle6.parsers.parse24 as parse24
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse24.Python24Parser(debug_parser)
|
||||
else:
|
||||
p = parse24.Python24ParserSingle(debug_parser)
|
||||
elif version == 2.5:
|
||||
elif version == (2, 5):
|
||||
import uncompyle6.parsers.parse25 as parse25
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse25.Python25Parser(debug_parser)
|
||||
else:
|
||||
p = parse25.Python25ParserSingle(debug_parser)
|
||||
elif version == 2.6:
|
||||
elif version == (2, 6):
|
||||
import uncompyle6.parsers.parse26 as parse26
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse26.Python26Parser(debug_parser)
|
||||
else:
|
||||
p = parse26.Python26ParserSingle(debug_parser)
|
||||
elif version == 2.7:
|
||||
elif version == (2, 7):
|
||||
import uncompyle6.parsers.parse27 as parse27
|
||||
|
||||
if compile_mode == "exec":
|
||||
@@ -760,63 +762,63 @@ def get_python_parser(
|
||||
else:
|
||||
import uncompyle6.parsers.parse3 as parse3
|
||||
|
||||
if version == 3.0:
|
||||
if version == (3, 0):
|
||||
import uncompyle6.parsers.parse30 as parse30
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse30.Python30Parser(debug_parser)
|
||||
else:
|
||||
p = parse30.Python30ParserSingle(debug_parser)
|
||||
elif version == 3.1:
|
||||
elif version == (3, 1):
|
||||
import uncompyle6.parsers.parse31 as parse31
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse31.Python31Parser(debug_parser)
|
||||
else:
|
||||
p = parse31.Python31ParserSingle(debug_parser)
|
||||
elif version == 3.2:
|
||||
elif version == (3, 2):
|
||||
import uncompyle6.parsers.parse32 as parse32
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse32.Python32Parser(debug_parser)
|
||||
else:
|
||||
p = parse32.Python32ParserSingle(debug_parser)
|
||||
elif version == 3.3:
|
||||
elif version == (3, 3):
|
||||
import uncompyle6.parsers.parse33 as parse33
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse33.Python33Parser(debug_parser)
|
||||
else:
|
||||
p = parse33.Python33ParserSingle(debug_parser)
|
||||
elif version == 3.4:
|
||||
elif version == (3, 4):
|
||||
import uncompyle6.parsers.parse34 as parse34
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse34.Python34Parser(debug_parser)
|
||||
else:
|
||||
p = parse34.Python34ParserSingle(debug_parser)
|
||||
elif version == 3.5:
|
||||
elif version == (3, 5):
|
||||
import uncompyle6.parsers.parse35 as parse35
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse35.Python35Parser(debug_parser)
|
||||
else:
|
||||
p = parse35.Python35ParserSingle(debug_parser)
|
||||
elif version == 3.6:
|
||||
elif version == (3, 6):
|
||||
import uncompyle6.parsers.parse36 as parse36
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse36.Python36Parser(debug_parser)
|
||||
else:
|
||||
p = parse36.Python36ParserSingle(debug_parser)
|
||||
elif version == 3.7:
|
||||
elif version == (3, 7):
|
||||
import uncompyle6.parsers.parse37 as parse37
|
||||
|
||||
if compile_mode == "exec":
|
||||
p = parse37.Python37Parser(debug_parser)
|
||||
else:
|
||||
p = parse37.Python37ParserSingle(debug_parser)
|
||||
elif version == 3.8:
|
||||
elif version == (3, 8):
|
||||
import uncompyle6.parsers.parse38 as parse38
|
||||
|
||||
if compile_mode == "exec":
|
||||
@@ -875,16 +877,23 @@ def python_parser(
|
||||
# For heavy grammar debugging
|
||||
# parser_debug = {'rules': True, 'transition': True, 'reduce' : True,
|
||||
# 'showstack': 'full'}
|
||||
|
||||
p = get_python_parser(version, parser_debug)
|
||||
|
||||
# FIXME: have p.insts update in a better way
|
||||
# modularity is broken here
|
||||
p.insts = scanner.insts
|
||||
p.offset2inst_index = scanner.offset2inst_index
|
||||
|
||||
return parse(p, tokens, customize, co)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
def parse_test(co):
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY
|
||||
|
||||
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
|
||||
ast = python_parser(PYTHON_VERSION_TRIPLE[:2], co, showasm=True, is_pypy=IS_PYPY)
|
||||
print(ast)
|
||||
return
|
||||
parse_test(parse_test.func_code)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -317,7 +317,7 @@ class Python2Parser(PythonParser):
|
||||
build_count = token.attr
|
||||
thousands = build_count // 1024
|
||||
thirty32s = (build_count // 32) % 32
|
||||
if thirty32s > 0:
|
||||
if thirty32s > 0 or thousands > 0:
|
||||
rule = "expr32 ::=%s" % (" expr" * 32)
|
||||
self.add_unique_rule(rule, opname_base, build_count, customize)
|
||||
if thousands > 0:
|
||||
@@ -348,7 +348,7 @@ class Python2Parser(PythonParser):
|
||||
],
|
||||
customize,
|
||||
)
|
||||
if self.version >= 2.7:
|
||||
if self.version >= (2, 7):
|
||||
self.add_unique_rule(
|
||||
"dict_comp_func ::= BUILD_MAP_n LOAD_FAST FOR_ITER store "
|
||||
"comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST",
|
||||
@@ -575,7 +575,7 @@ class Python2Parser(PythonParser):
|
||||
customize,
|
||||
)
|
||||
|
||||
if self.version >= 2.7:
|
||||
if self.version >= (2, 7):
|
||||
if i > 0:
|
||||
prev_tok = tokens[i - 1]
|
||||
if prev_tok == "LOAD_DICTCOMP":
|
||||
|
@@ -91,7 +91,7 @@ class Python24Parser(Python25Parser):
|
||||
""")
|
||||
super(Python24Parser, self).customize_grammar_rules(tokens, customize)
|
||||
self.remove_rules_24()
|
||||
if self.version == 2.4:
|
||||
if self.version[:2] == (2, 4):
|
||||
self.check_reduce['nop_stmt'] = 'tokens'
|
||||
|
||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
|
@@ -97,7 +97,7 @@ class Python25Parser(Python26Parser):
|
||||
return_stmt_lambda LAMBDA_MARKER
|
||||
""")
|
||||
super(Python25Parser, self).customize_grammar_rules(tokens, customize)
|
||||
if self.version == 2.5:
|
||||
if self.version[:2] == (2, 5):
|
||||
self.check_reduce["try_except"] = "tokens"
|
||||
self.check_reduce["aug_assign1"] = "AST"
|
||||
self.check_reduce["ifelsestmt"] = "AST"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2020 Rocky Bernstein
|
||||
# Copyright (c) 2017-2021 Rocky Bernstein
|
||||
"""
|
||||
spark grammar differences over Python2 for Python 2.6.
|
||||
"""
|
||||
@@ -390,7 +390,7 @@ class Python26Parser(Python2Parser):
|
||||
# For now, we won't let the 2nd 'expr' be a "if_exp_not"
|
||||
# However in < 2.6 where we don't have if/else expression it *can*
|
||||
# be.
|
||||
if self.version >= 2.6 and ast[2][0] == "if_exp_not":
|
||||
if self.version >= (2, 6) and ast[2][0] == "if_exp_not":
|
||||
return True
|
||||
|
||||
test_index = last
|
||||
@@ -424,7 +424,7 @@ class Python26Parser(Python2Parser):
|
||||
# since the operand can be a relative offset rather than
|
||||
# an absolute offset.
|
||||
setup_inst = self.insts[self.offset2inst_index[tokens[first].offset]]
|
||||
if self.version <= 2.2 and tokens[last] == "COME_FROM":
|
||||
if self.version <= (2, 2) and tokens[last] == "COME_FROM":
|
||||
last += 1
|
||||
return tokens[last-1].off2int() > setup_inst.argval
|
||||
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -538,7 +538,7 @@ class Python3Parser(PythonParser):
|
||||
# FIXME: What's the deal with the two rules? Different Python versions?
|
||||
# Different situations? Note that the above rule is based on the CALL_FUNCTION
|
||||
# token found, while this one doesn't.
|
||||
if self.version < 3.6:
|
||||
if self.version < (3, 6):
|
||||
call_function = self.call_fn_name(call_fn_tok)
|
||||
args_pos, args_kw = self.get_pos_kw(call_fn_tok)
|
||||
rule = "build_class ::= LOAD_BUILD_CLASS mkfunc %s" "%s" % (
|
||||
@@ -593,7 +593,7 @@ class Python3Parser(PythonParser):
|
||||
|
||||
# Note: 3.5+ have subclassed this method; so we don't handle
|
||||
# 'CALL_FUNCTION_VAR' or 'CALL_FUNCTION_EX' here.
|
||||
if is_pypy and self.version >= 3.6:
|
||||
if is_pypy and self.version >= (3, 6):
|
||||
if token == "CALL_FUNCTION":
|
||||
token.kind = self.call_fn_name(token)
|
||||
rule = (
|
||||
@@ -627,7 +627,7 @@ class Python3Parser(PythonParser):
|
||||
"""Python 3.3 added a an addtional LOAD_STR before MAKE_FUNCTION and
|
||||
this has an effect on many rules.
|
||||
"""
|
||||
if self.version >= 3.3:
|
||||
if self.version >= (3, 3):
|
||||
if PYTHON3 or not self.is_pypy:
|
||||
load_op = "LOAD_STR "
|
||||
else:
|
||||
@@ -776,7 +776,7 @@ class Python3Parser(PythonParser):
|
||||
rule = "kvlist_n ::="
|
||||
self.add_unique_rule(rule, "kvlist_n", 1, customize)
|
||||
rule = "dict ::= BUILD_MAP_n kvlist_n"
|
||||
elif self.version >= 3.5:
|
||||
elif self.version >= (3, 5):
|
||||
if not opname.startswith("BUILD_MAP_WITH_CALL"):
|
||||
# FIXME: Use the attr
|
||||
# so this doesn't run into exponential parsing time.
|
||||
@@ -846,7 +846,7 @@ class Python3Parser(PythonParser):
|
||||
build_count = token.attr
|
||||
thousands = build_count // 1024
|
||||
thirty32s = (build_count // 32) % 32
|
||||
if thirty32s > 0:
|
||||
if thirty32s > 0 or thousands > 0:
|
||||
rule = "expr32 ::=%s" % (" expr" * 32)
|
||||
self.add_unique_rule(rule, opname_base, build_count, customize)
|
||||
pass
|
||||
@@ -1061,7 +1061,7 @@ class Python3Parser(PythonParser):
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
|
||||
# FIXME: Fold test into add_make_function_rule
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
j = 1
|
||||
else:
|
||||
j = 2
|
||||
@@ -1123,7 +1123,7 @@ class Python3Parser(PythonParser):
|
||||
kwargs_str = ""
|
||||
|
||||
# Note order of kwargs and pos args changed between 3.3-3.4
|
||||
if self.version <= 3.2:
|
||||
if self.version <= (3, 2):
|
||||
if annotate_args > 0:
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%s%sannotate_tuple load_closure LOAD_CODE %s"
|
||||
@@ -1140,7 +1140,7 @@ class Python3Parser(PythonParser):
|
||||
"pos_arg " * args_pos,
|
||||
opname,
|
||||
)
|
||||
elif self.version == 3.3:
|
||||
elif self.version == (3, 3):
|
||||
if annotate_args > 0:
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%s%sannotate_tuple load_closure LOAD_CODE LOAD_STR %s"
|
||||
@@ -1158,7 +1158,7 @@ class Python3Parser(PythonParser):
|
||||
opname,
|
||||
)
|
||||
|
||||
elif self.version >= 3.4:
|
||||
elif self.version >= (3, 4):
|
||||
if PYTHON3 or not self.is_pypy:
|
||||
load_op = "LOAD_STR"
|
||||
else:
|
||||
@@ -1192,7 +1192,7 @@ class Python3Parser(PythonParser):
|
||||
)
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
|
||||
if self.version < 3.4:
|
||||
if self.version < (3, 4):
|
||||
rule = "mkfunc ::= %sload_closure LOAD_CODE %s" % (
|
||||
"expr " * args_pos,
|
||||
opname,
|
||||
@@ -1202,7 +1202,7 @@ class Python3Parser(PythonParser):
|
||||
pass
|
||||
elif opname_base.startswith("MAKE_FUNCTION"):
|
||||
# DRY with MAKE_CLOSURE
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
# The semantics of MAKE_FUNCTION in 3.6 are totally different from
|
||||
# before.
|
||||
args_pos, args_kw, annotate_args, closure = token.attr
|
||||
@@ -1264,7 +1264,7 @@ class Python3Parser(PythonParser):
|
||||
if self.is_pypy or (
|
||||
i >= 2 and tokens[i - 2] == "LOAD_LISTCOMP"
|
||||
):
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
# 3.6+ sometimes bundles all of the
|
||||
# 'exprs' in the rule above into a
|
||||
# tuple.
|
||||
@@ -1295,12 +1295,12 @@ class Python3Parser(PythonParser):
|
||||
)
|
||||
continue
|
||||
|
||||
if self.version < 3.6:
|
||||
if self.version < (3, 6):
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
else:
|
||||
args_pos, args_kw, annotate_args, closure = token.attr
|
||||
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
j = 1
|
||||
else:
|
||||
j = 2
|
||||
@@ -1341,7 +1341,7 @@ class Python3Parser(PythonParser):
|
||||
else:
|
||||
kwargs = "kwargs"
|
||||
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
# positional args after keyword args
|
||||
rule = "mkfunc ::= %s %s%s%s" % (
|
||||
kwargs,
|
||||
@@ -1355,7 +1355,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE ",
|
||||
opname,
|
||||
)
|
||||
elif self.version == 3.3:
|
||||
elif self.version == (3, 3):
|
||||
# positional args after keyword args
|
||||
rule = "mkfunc ::= %s %s%s%s" % (
|
||||
kwargs,
|
||||
@@ -1363,7 +1363,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE LOAD_STR ",
|
||||
opname,
|
||||
)
|
||||
elif self.version > 3.5:
|
||||
elif self.version >= (3, 6):
|
||||
# positional args before keyword args
|
||||
rule = "mkfunc ::= %s%s %s%s" % (
|
||||
"pos_arg " * args_pos,
|
||||
@@ -1371,7 +1371,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE LOAD_STR ",
|
||||
opname,
|
||||
)
|
||||
elif self.version > 3.3:
|
||||
elif self.version >= (3, 4):
|
||||
# positional args before keyword args
|
||||
rule = "mkfunc ::= %s%s %s%s" % (
|
||||
"pos_arg " * args_pos,
|
||||
@@ -1388,7 +1388,7 @@ class Python3Parser(PythonParser):
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
|
||||
if re.search("^MAKE_FUNCTION.*_A", opname):
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%sannotate_tuple LOAD_CODE LOAD_STR %s"
|
||||
% (
|
||||
@@ -1406,11 +1406,11 @@ class Python3Parser(PythonParser):
|
||||
opname,
|
||||
)
|
||||
)
|
||||
if self.version >= 3.3:
|
||||
if self.version >= (3, 3):
|
||||
# Normally we remove EXTENDED_ARG from the opcodes, but in the case of
|
||||
# annotated functions can use the EXTENDED_ARG tuple to signal we have an annotated function.
|
||||
# Yes this is a little hacky
|
||||
if self.version == 3.3:
|
||||
if self.version == (3, 3):
|
||||
# 3.3 puts kwargs before pos_arg
|
||||
pos_kw_tuple = (
|
||||
("kwargs " * args_kw),
|
||||
@@ -1550,7 +1550,7 @@ class Python3Parser(PythonParser):
|
||||
"try_except": tryexcept,
|
||||
}
|
||||
|
||||
if self.version == 3.6:
|
||||
if self.version == (3, 6):
|
||||
self.reduce_check_table["and"] = and_check
|
||||
self.check_reduce["and"] = "AST"
|
||||
|
||||
@@ -1562,7 +1562,7 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce["ifelsestmtc"] = "AST"
|
||||
self.check_reduce["ifstmt"] = "AST"
|
||||
self.check_reduce["ifstmtl"] = "AST"
|
||||
if self.version == 3.6:
|
||||
if self.version == (3, 6):
|
||||
self.reduce_check_table["iflaststmtl"] = iflaststmt
|
||||
self.check_reduce["iflaststmt"] = "AST"
|
||||
self.check_reduce["iflaststmtl"] = "AST"
|
||||
@@ -1570,7 +1570,7 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce["testtrue"] = "tokens"
|
||||
if not PYTHON3:
|
||||
self.check_reduce["kwarg"] = "noAST"
|
||||
if self.version < 3.6 and not self.is_pypy:
|
||||
if self.version < (3, 6) and not self.is_pypy:
|
||||
# 3.6+ can remove a JUMP_FORWARD which messes up our testing here
|
||||
# Pypy we need to go over in better detail
|
||||
self.check_reduce["try_except"] = "AST"
|
||||
@@ -1597,11 +1597,11 @@ class Python3Parser(PythonParser):
|
||||
elif lhs == "kwarg":
|
||||
arg = tokens[first].attr
|
||||
return not (isinstance(arg, str) or isinstance(arg, unicode))
|
||||
elif lhs in ("iflaststmt", "iflaststmtl") and self.version == 3.6:
|
||||
elif lhs in ("iflaststmt", "iflaststmtl") and self.version[:2] == (3, 6):
|
||||
return ifstmt(self, lhs, n, rule, ast, tokens, first, last)
|
||||
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
|
||||
# FIXME: go over what's up with 3.0. Evetually I'd like to remove RETURN_END_IF
|
||||
if self.version <= 3.0 or tokens[last] == "RETURN_END_IF":
|
||||
if self.version <= (3, 0) or tokens[last] == "RETURN_END_IF":
|
||||
return False
|
||||
if ifstmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
return True
|
||||
@@ -1643,7 +1643,7 @@ class Python3Parser(PythonParser):
|
||||
if while1stmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
return True
|
||||
|
||||
if self.version == 3.0:
|
||||
if self.version == (3, 0):
|
||||
return False
|
||||
|
||||
if 0 <= last < len(tokens) and tokens[last] in (
|
||||
@@ -1685,7 +1685,7 @@ class Python3Parser(PythonParser):
|
||||
if last == n:
|
||||
return False
|
||||
# 3.8+ Doesn't have SETUP_LOOP
|
||||
return self.version < 3.8 and tokens[first].attr > tokens[last].offset
|
||||
return self.version < (3, 8) and tokens[first].attr > tokens[last].offset
|
||||
elif rule == (
|
||||
"ifelsestmt",
|
||||
(
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017, 2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2019, 2021 Rocky Bernstein
|
||||
"""
|
||||
spark grammar differences over Python 3.4 for Python 3.5.
|
||||
"""
|
||||
@@ -156,7 +156,7 @@ class Python35Parser(Python34Parser):
|
||||
# FIXME: I suspect this is wrong for 3.6 and 3.5, but
|
||||
# I haven't verified what the 3.7ish fix is
|
||||
elif opname == 'BUILD_MAP_UNPACK_WITH_CALL':
|
||||
if self.version < 3.7:
|
||||
if self.version < (3, 7):
|
||||
self.addRule("expr ::= unmapexpr", nop_func)
|
||||
nargs = token.attr % 256
|
||||
map_unpack_n = "map_unpack_%s" % nargs
|
||||
@@ -167,10 +167,9 @@ class Python35Parser(Python34Parser):
|
||||
call_token = tokens[i+1]
|
||||
rule = 'call ::= expr unmapexpr ' + call_token.kind
|
||||
self.addRule(rule, nop_func)
|
||||
elif opname == 'BEFORE_ASYNC_WITH' and self.version < 3.8:
|
||||
elif opname == 'BEFORE_ASYNC_WITH' and self.version < (3, 8):
|
||||
# Some Python 3.5+ async additions
|
||||
rules_str = """
|
||||
async_with_stmt ::= expr
|
||||
stmt ::= async_with_stmt
|
||||
async_with_pre ::= BEFORE_ASYNC_WITH GET_AWAITABLE LOAD_CONST YIELD_FROM SETUP_ASYNC_WITH
|
||||
async_with_post ::= COME_FROM_ASYNC_WITH
|
||||
|
@@ -395,7 +395,7 @@ class Python36Parser(Python35Parser):
|
||||
starred ::= expr
|
||||
call_ex ::= expr starred CALL_FUNCTION_EX
|
||||
""", nop_func)
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
if 'BUILD_MAP_UNPACK_WITH_CALL' in self.seen_ops:
|
||||
self.addRule("""
|
||||
expr ::= call_ex_kw
|
||||
|
@@ -1291,7 +1291,7 @@ class Python37Parser(Python37BaseParser):
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
|
@@ -209,7 +209,7 @@ class Python37BaseParser(PythonParser):
|
||||
stmt ::= async_with_as_stmt
|
||||
"""
|
||||
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
stmt ::= async_with_stmt SETUP_ASYNC_WITH
|
||||
c_stmt ::= c_async_with_stmt SETUP_ASYNC_WITH
|
||||
@@ -1034,7 +1034,7 @@ class Python37BaseParser(PythonParser):
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
with_suffix
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
|
@@ -10,7 +10,7 @@ def except_handler(self, lhs, n, rule, ast, tokens, first, last):
|
||||
|
||||
# FIXME: Figure out why this doesn't work on
|
||||
# bytecode-1.4/anydbm.pyc
|
||||
if self.version == 1.4:
|
||||
if self.version[:2] == (1, 4):
|
||||
return False
|
||||
|
||||
# Make sure come froms all come from within "except_handler".
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) 2020 Rocky Bernstein
|
||||
# Copyright (c) 2020-2021 Rocky Bernstein
|
||||
|
||||
def except_handler_else(self, lhs, n, rule, ast, tokens, first, last):
|
||||
# FIXME: expand this to other versions
|
||||
if self.version not in (2.7, 3.5):
|
||||
if self.version[:2] not in ((2, 7), (3, 5)):
|
||||
return False
|
||||
|
||||
if tokens[first] in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020 Rocky Bernstein
|
||||
# Copyright (c) 2020-2021 Rocky Bernstein
|
||||
|
||||
from uncompyle6.scanners.tok import Token
|
||||
|
||||
@@ -158,7 +158,7 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
# just the last one.
|
||||
if len(ast) == 5:
|
||||
end_come_froms = ast[-1]
|
||||
if end_come_froms.kind != "else_suite" and self.version >= 3.0:
|
||||
if end_come_froms.kind != "else_suite" and self.version >= (3, 0):
|
||||
if end_come_froms == "opt_come_from_except" and len(end_come_froms) > 0:
|
||||
end_come_froms = end_come_froms[0]
|
||||
if not isinstance(end_come_froms, Token):
|
||||
@@ -169,12 +169,12 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
|
||||
# FIXME: There is weirdness in the grammar we need to work around.
|
||||
# we need to clean up the grammar.
|
||||
if self.version < 3.0:
|
||||
if self.version < (3, 0):
|
||||
last_token = ast[-1]
|
||||
else:
|
||||
last_token = tokens[last]
|
||||
if last_token == "COME_FROM" and tokens[first].offset > last_token.attr:
|
||||
if self.version < 3.0 and self.insts[self.offset2inst_index[last_token.attr]].opname != "SETUP_LOOP":
|
||||
if self.version < (3, 0) and self.insts[self.offset2inst_index[last_token.attr]].opname != "SETUP_LOOP":
|
||||
return True
|
||||
|
||||
testexpr = ast[0]
|
||||
@@ -191,7 +191,7 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
if last == n:
|
||||
last -= 1
|
||||
jmp = if_condition[1]
|
||||
if self.version > 2.6:
|
||||
if self.version >= (2, 7):
|
||||
jmp_target = jmp[0].attr
|
||||
else:
|
||||
jmp_target = int(jmp[0].pattr)
|
||||
|
@@ -44,7 +44,7 @@ def or_check(self, lhs, n, rule, ast, tokens, first, last):
|
||||
return True
|
||||
|
||||
# If the jmp is backwards
|
||||
if last_token == "POP_JUMP_IF_FALSE" and not self.version in (2.7, 3.5, 3.6):
|
||||
if last_token == "POP_JUMP_IF_FALSE" and not self.version[:2] in ((2, 7), (3, 5), (3, 6)):
|
||||
if last_token.attr < last_token_offset:
|
||||
# For a backwards loop, well compare to the instruction *after*
|
||||
# then POP_JUMP...
|
||||
|
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) 2020 Rocky Bernstein
|
||||
# Copyright (c) 2020-2021 Rocky Bernstein
|
||||
|
||||
|
||||
def testtrue(self, lhs, n, rule, ast, tokens, first, last):
|
||||
# FIXME: make this work for all versions
|
||||
if self.version != 3.7:
|
||||
if self.version[:2] != (3, 7):
|
||||
return False
|
||||
if rule == ("testtrue", ("expr", "jmp_true")):
|
||||
pjit = tokens[min(last - 1, n - 2)]
|
||||
|
@@ -20,4 +20,4 @@ def while1elsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
# not while1else. Also do for whileTrue?
|
||||
last += 1
|
||||
# 3.8+ Doesn't have SETUP_LOOP
|
||||
return self.version < 3.8 and tokens[first].attr > tokens[last].off2int()
|
||||
return self.version < (3, 8) and tokens[first].attr > tokens[last].off2int()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016, 2018-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2016, 2018-2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -24,47 +24,56 @@ scanners, e.g. for Python 2.7 or 3.4.
|
||||
from array import array
|
||||
import sys
|
||||
|
||||
from uncompyle6 import PYTHON3, IS_PYPY, PYTHON_VERSION
|
||||
from uncompyle6.scanners.tok import Token
|
||||
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, PYTHON3, version_tuple_to_str
|
||||
import xdis
|
||||
from xdis import Bytecode, canonic_python_version, code2num, instruction_size, extended_arg_val, next_offset
|
||||
from xdis import (
|
||||
Bytecode,
|
||||
canonic_python_version,
|
||||
code2num,
|
||||
instruction_size,
|
||||
extended_arg_val,
|
||||
next_offset,
|
||||
)
|
||||
|
||||
if PYTHON_VERSION < 2.6:
|
||||
if PYTHON_VERSION_TRIPLE < (2, 6):
|
||||
from xdis.namedtuple24 import namedtuple
|
||||
else:
|
||||
from collections import namedtuple
|
||||
|
||||
# The byte code versions we support.
|
||||
# Note: these all have to be floats
|
||||
# Note: these all have to be tuples of 2 ints
|
||||
PYTHON_VERSIONS = frozenset(
|
||||
(
|
||||
1.0,
|
||||
1.1,
|
||||
1.3,
|
||||
1.4,
|
||||
1.5,
|
||||
1.6,
|
||||
2.1,
|
||||
2.2,
|
||||
2.3,
|
||||
2.4,
|
||||
2.5,
|
||||
2.6,
|
||||
2.7,
|
||||
3.0,
|
||||
3.1,
|
||||
3.2,
|
||||
3.3,
|
||||
3.4,
|
||||
3.5,
|
||||
3.6,
|
||||
3.7,
|
||||
3.8,
|
||||
3.9,
|
||||
(1, 0),
|
||||
(1, 1),
|
||||
(1, 3),
|
||||
(1, 4),
|
||||
(1, 5),
|
||||
(1, 6),
|
||||
(2, 1),
|
||||
(2, 2),
|
||||
(2, 3),
|
||||
(2, 4),
|
||||
(2, 5),
|
||||
(2, 6),
|
||||
(2, 7),
|
||||
(3, 0),
|
||||
(3, 1),
|
||||
(3, 2),
|
||||
(3, 3),
|
||||
(3, 4),
|
||||
(3, 5),
|
||||
(3, 6),
|
||||
(3, 7),
|
||||
(3, 8),
|
||||
)
|
||||
)
|
||||
|
||||
CANONIC2VERSION = dict((canonic_python_version[str(v)], v) for v in PYTHON_VERSIONS)
|
||||
CANONIC2VERSION = dict(
|
||||
(canonic_python_version[version_tuple_to_str(python_version)], python_version)
|
||||
for python_version in PYTHON_VERSIONS
|
||||
)
|
||||
|
||||
# Magic changed mid version for Python 3.5.2. Compatibility was added for
|
||||
# the older 3.5 interpreter magic.
|
||||
@@ -105,15 +114,19 @@ class Scanner(object):
|
||||
self.show_asm = show_asm
|
||||
self.is_pypy = is_pypy
|
||||
|
||||
if version in PYTHON_VERSIONS:
|
||||
if version[:2] in PYTHON_VERSIONS:
|
||||
v_str = "opcode_%s" % version_tuple_to_str(
|
||||
version, start=0, end=2, delimiter=""
|
||||
)
|
||||
if is_pypy:
|
||||
v_str = "opcode_%spypy" % (int(version * 10))
|
||||
else:
|
||||
v_str = "opcode_%s" % (int(version * 10))
|
||||
v_str += "pypy"
|
||||
exec("from xdis.opcodes import %s" % v_str)
|
||||
exec("self.opc = %s" % v_str)
|
||||
else:
|
||||
raise TypeError("%s is not a Python version I know about" % version)
|
||||
raise TypeError(
|
||||
"%s is not a Python version I know about"
|
||||
% version_tuple_to_str(version)
|
||||
)
|
||||
|
||||
self.opname = self.opc.opname
|
||||
|
||||
@@ -146,7 +159,7 @@ class Scanner(object):
|
||||
|
||||
# Offset: lineno pairs, only for offsets which start line.
|
||||
# Locally we use list for more convenient iteration using indices
|
||||
if self.version > 1.4:
|
||||
if self.version > (1, 4):
|
||||
linestarts = list(self.opc.findlinestarts(code_obj))
|
||||
else:
|
||||
linestarts = [[0, 1]]
|
||||
@@ -535,8 +548,8 @@ def get_scanner(version, is_pypy=False, show_asm=None):
|
||||
version = CANONIC2VERSION[canonic_version]
|
||||
|
||||
# Pick up appropriate scanner
|
||||
if version in PYTHON_VERSIONS:
|
||||
v_str = "%s" % (int(version * 10))
|
||||
if version[:2] in PYTHON_VERSIONS:
|
||||
v_str = version_tuple_to_str(version, start=0, end=2, delimiter="")
|
||||
try:
|
||||
import importlib
|
||||
|
||||
@@ -568,7 +581,10 @@ def get_scanner(version, is_pypy=False, show_asm=None):
|
||||
"scan.Scanner%s(show_asm=show_asm)" % v_str, locals(), globals()
|
||||
)
|
||||
else:
|
||||
raise RuntimeError("Unsupported Python version %s" % version)
|
||||
raise RuntimeError(
|
||||
"Unsupported Python version, %s, for decompilation"
|
||||
% version_tuple_to_str(version)
|
||||
)
|
||||
return scanner
|
||||
|
||||
|
||||
@@ -578,5 +594,5 @@ if __name__ == "__main__":
|
||||
co = inspect.currentframe().f_code
|
||||
# scanner = get_scanner('2.7.13', True)
|
||||
# scanner = get_scanner(sys.version[:5], False)
|
||||
scanner = get_scanner(uncompyle6.PYTHON_VERSION, IS_PYPY, True)
|
||||
scanner = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY, True)
|
||||
tokens, customize = scanner.ingest(co, {}, show_asm="after")
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python PyPy 2.7 bytecode scanner/deparser
|
||||
|
||||
@@ -22,5 +22,5 @@ class ScannerPyPy27(scan.Scanner27):
|
||||
# There are no differences in initialization between
|
||||
# pypy 2.7 and 2.7
|
||||
scan.Scanner27.__init__(self, show_asm, is_pypy=True)
|
||||
self.version = 2.7
|
||||
self.version = (2, 7)
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017 by Rocky Bernstein
|
||||
# Copyright (c) 2017, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python PyPy 3.2 decompiler scanner.
|
||||
|
||||
@@ -18,6 +18,6 @@ class ScannerPyPy32(scan.Scanner32):
|
||||
# There are no differences in initialization between
|
||||
# pypy 3.2 and 3.2
|
||||
scan.Scanner32.__init__(self, show_asm, is_pypy=True)
|
||||
self.version = 3.2
|
||||
self.version = (3, 2)
|
||||
self.opc = opc
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2019-2021 by Rocky Bernstein
|
||||
"""
|
||||
Python PyPy 3.3 decompiler scanner.
|
||||
|
||||
@@ -19,6 +19,6 @@ class ScannerPyPy33(scan.Scanner33):
|
||||
# There are no differences in initialization between
|
||||
# pypy 3.3 and 3.3
|
||||
scan.Scanner33.__init__(self, show_asm, is_pypy=True)
|
||||
self.version = 3.3
|
||||
self.version = (3, 3)
|
||||
self.opc = opc
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017, 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2017, 2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python PyPy 3.5 decompiler scanner.
|
||||
|
||||
@@ -18,5 +18,5 @@ class ScannerPyPy35(scan.Scanner35):
|
||||
# There are no differences in initialization between
|
||||
# pypy 3.5 and 3.5
|
||||
scan.Scanner35.__init__(self, show_asm, is_pypy=True)
|
||||
self.version = 3.5
|
||||
self.version = (3, 5)
|
||||
return
|
||||
|
@@ -18,5 +18,5 @@ class ScannerPyPy36(scan.Scanner36):
|
||||
# There are no differences in initialization between
|
||||
# pypy 3.6 and 3.6
|
||||
scan.Scanner36.__init__(self, show_asm, is_pypy=True)
|
||||
self.version = 3.6
|
||||
self.version = (3, 6)
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.0 bytecode decompiler massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner10(scan.Scanner11):
|
||||
scan.Scanner11.__init__(self, show_asm)
|
||||
self.opc = opcode_10
|
||||
self.opname = opcode_10.opname
|
||||
self.version = 1.0
|
||||
self.version = (1, 0)
|
||||
return
|
||||
|
||||
# def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.1 bytecode decompiler massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner11(scan.Scanner13): # no scanner 1.2
|
||||
scan.Scanner13.__init__(self, show_asm)
|
||||
self.opc = opcode_11
|
||||
self.opname = opcode_11.opname
|
||||
self.version = 1.1
|
||||
self.version = (1, 1)
|
||||
return
|
||||
|
||||
# def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.2 bytecode decompiler massaging.
|
||||
|
||||
@@ -23,7 +23,7 @@ class Scanner12(scan.Scanner13):
|
||||
scan.Scanner14.__init__(self, show_asm)
|
||||
self.opc = opcode_11
|
||||
self.opname = opcode_11.opname
|
||||
self.version = 1.2 # Note: is the same as 1.1 bytecode
|
||||
self.version = (1, 2) # Note: is the same as 1.1 bytecode
|
||||
return
|
||||
|
||||
# def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2018-2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.3 bytecode decompiler massaging.
|
||||
|
||||
@@ -24,7 +24,7 @@ class Scanner13(scan.Scanner14):
|
||||
scan.Scanner14.__init__(self, show_asm)
|
||||
self.opc = opcode_13
|
||||
self.opname = opcode_13.opname
|
||||
self.version = 1.3
|
||||
self.version = (1, 3)
|
||||
return
|
||||
|
||||
# def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2018-2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.4 bytecode decompiler massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner14(scan.Scanner15):
|
||||
scan.Scanner15.__init__(self, show_asm)
|
||||
self.opc = opcode_14
|
||||
self.opname = opcode_14.opname
|
||||
self.version = 1.4
|
||||
self.version = (1, 4)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
return
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.5 bytecode decompiler massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner15(scan.Scanner21):
|
||||
scan.Scanner21.__init__(self, show_asm=False)
|
||||
self.opc = opcode_15
|
||||
self.opname = opcode_15.opname
|
||||
self.version = 1.5
|
||||
self.version = (1, 5)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
return
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 1.6 bytecode decompiler massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner16(scan.Scanner21):
|
||||
scan.Scanner21.__init__(self, show_asm)
|
||||
self.opc = opcode_16
|
||||
self.opname = opcode_16.opname
|
||||
self.version = 1.6
|
||||
self.version = (1, 6)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
return
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
@@ -288,7 +288,7 @@ class Scanner2(Scanner):
|
||||
# last_offset = jump_offset
|
||||
come_from_name = "COME_FROM"
|
||||
op_name = self.opname_for_offset(jump_offset)
|
||||
if op_name.startswith("SETUP_") and self.version == 2.7:
|
||||
if op_name.startswith("SETUP_") and self.version[:2] == (2, 7):
|
||||
come_from_type = op_name[len("SETUP_") :]
|
||||
if come_from_type not in ("LOOP", "EXCEPT"):
|
||||
come_from_name = "COME_FROM_%s" % come_from_type
|
||||
@@ -350,12 +350,12 @@ class Scanner2(Scanner):
|
||||
pattr = names[oparg]
|
||||
elif op in self.opc.JREL_OPS:
|
||||
# use instead: hasattr(self, 'patch_continue'): ?
|
||||
if self.version == 2.7:
|
||||
if self.version[:2] == (2, 7):
|
||||
self.patch_continue(tokens, offset, op)
|
||||
pattr = repr(offset + 3 + oparg)
|
||||
elif op in self.opc.JABS_OPS:
|
||||
# use instead: hasattr(self, 'patch_continue'): ?
|
||||
if self.version == 2.7:
|
||||
if self.version[:2] == (2, 7):
|
||||
self.patch_continue(tokens, offset, op)
|
||||
pattr = repr(oparg)
|
||||
elif op in self.opc.LOCAL_OPS:
|
||||
@@ -515,7 +515,7 @@ class Scanner2(Scanner):
|
||||
while code[j] == self.opc.JUMP_ABSOLUTE:
|
||||
j = self.prev[j]
|
||||
if (
|
||||
self.version >= 2.3 and self.opname_for_offset(j) == "LIST_APPEND"
|
||||
self.version >= (2, 3) and self.opname_for_offset(j) == "LIST_APPEND"
|
||||
): # list comprehension
|
||||
stmts.remove(s)
|
||||
continue
|
||||
@@ -529,7 +529,7 @@ class Scanner2(Scanner):
|
||||
prev = code[self.prev[s]]
|
||||
if (
|
||||
prev == self.opc.ROT_TWO
|
||||
or self.version < 2.7
|
||||
or self.version < (2, 7)
|
||||
and prev
|
||||
in (
|
||||
self.opc.JUMP_IF_FALSE,
|
||||
@@ -543,7 +543,7 @@ class Scanner2(Scanner):
|
||||
j = self.prev[s]
|
||||
while code[j] in self.designator_ops:
|
||||
j = self.prev[j]
|
||||
if self.version > 2.1 and code[j] == self.opc.FOR_ITER:
|
||||
if self.version > (2, 1) and code[j] == self.opc.FOR_ITER:
|
||||
stmts.remove(s)
|
||||
continue
|
||||
last_stmt = s
|
||||
@@ -563,7 +563,7 @@ class Scanner2(Scanner):
|
||||
jmp = self.prev[self.get_target(except_match)]
|
||||
|
||||
# In Python < 2.7 we may have jumps to jumps
|
||||
if self.version < 2.7 and self.code[jmp] in self.jump_forward:
|
||||
if self.version < (2, 7) and self.code[jmp] in self.jump_forward:
|
||||
self.not_continue.add(jmp)
|
||||
jmp = self.get_target(jmp)
|
||||
prev_offset = self.prev[except_match]
|
||||
@@ -587,7 +587,7 @@ class Scanner2(Scanner):
|
||||
op = self.code[i]
|
||||
if op == self.opc.END_FINALLY:
|
||||
if count_END_FINALLY == count_SETUP_:
|
||||
if self.version == 2.7:
|
||||
if self.version[:2] == (2, 7):
|
||||
assert self.code[self.prev[i]] in self.jump_forward | frozenset(
|
||||
[self.opc.RETURN_VALUE]
|
||||
)
|
||||
@@ -649,7 +649,7 @@ class Scanner2(Scanner):
|
||||
# Account for the fact that < 2.7 has an explicit
|
||||
# POP_TOP instruction in the equivalate POP_JUMP_IF
|
||||
# construct
|
||||
if self.version < 2.7:
|
||||
if self.version < (2, 7):
|
||||
jump_forward_offset = jump_back_offset + 4
|
||||
return_val_offset1 = self.prev[
|
||||
self.prev[self.prev[loop_end_offset]]
|
||||
@@ -691,7 +691,7 @@ class Scanner2(Scanner):
|
||||
jump_back_offset += 1
|
||||
|
||||
if_offset = None
|
||||
if self.version < 2.7:
|
||||
if self.version < (2, 7):
|
||||
# Look for JUMP_IF POP_TOP ...
|
||||
if code[self.prev[next_line_byte]] == self.opc.POP_TOP and (
|
||||
code[self.prev[self.prev[next_line_byte]]] in self.pop_jump_if
|
||||
@@ -703,7 +703,7 @@ class Scanner2(Scanner):
|
||||
if if_offset:
|
||||
loop_type = "while"
|
||||
self.ignore_if.add(if_offset)
|
||||
if self.version < 2.7 and (
|
||||
if self.version < (2, 7) and (
|
||||
code[self.prev[jump_back_offset]] == self.opc.RETURN_VALUE
|
||||
):
|
||||
self.ignore_if.add(self.prev[jump_back_offset])
|
||||
@@ -735,7 +735,7 @@ class Scanner2(Scanner):
|
||||
|
||||
setup_target = self.get_target(jump_back_offset, self.opc.JUMP_ABSOLUTE)
|
||||
|
||||
if self.version > 2.1 and code[setup_target] in (
|
||||
if self.version > (2, 1) and code[setup_target] in (
|
||||
self.opc.FOR_ITER,
|
||||
self.opc.GET_ITER,
|
||||
):
|
||||
@@ -745,7 +745,7 @@ class Scanner2(Scanner):
|
||||
# Look for a test condition immediately after the
|
||||
# SETUP_LOOP while
|
||||
if (
|
||||
self.version < 2.7
|
||||
self.version < (2, 7)
|
||||
and self.code[self.prev[next_line_byte]] == self.opc.POP_TOP
|
||||
):
|
||||
test_op_offset = self.prev[self.prev[next_line_byte]]
|
||||
@@ -822,7 +822,7 @@ class Scanner2(Scanner):
|
||||
if target != start_else:
|
||||
end_else = self.get_target(jmp)
|
||||
if self.code[jmp] == self.opc.JUMP_FORWARD:
|
||||
if self.version <= 2.6:
|
||||
if self.version <= (2, 6):
|
||||
self.fixed_jumps[jmp] = target
|
||||
else:
|
||||
self.fixed_jumps[jmp] = -1
|
||||
@@ -833,7 +833,7 @@ class Scanner2(Scanner):
|
||||
if end_else != start_else:
|
||||
r_end_else = self.restrict_to_parent(end_else, parent)
|
||||
# May be able to drop the 2.7 test.
|
||||
if self.version == 2.7:
|
||||
if self.version[:2] == (2, 7):
|
||||
self.structs.append(
|
||||
{"type": "try-else", "start": i + 1, "end": r_end_else}
|
||||
)
|
||||
@@ -861,7 +861,7 @@ class Scanner2(Scanner):
|
||||
# possibly I am "skipping over" a "pass" or null statement.
|
||||
|
||||
test_target = target
|
||||
if self.version < 2.7:
|
||||
if self.version < (2, 7):
|
||||
# Before 2.7 we have to deal with the fact that there is an extra
|
||||
# POP_TOP that is logically associated with the JUMP_IF's (even though
|
||||
# the instance set is called "self.pop_jump_if")
|
||||
@@ -981,7 +981,7 @@ class Scanner2(Scanner):
|
||||
self.fixed_jumps[offset] = fix or match[-1]
|
||||
return
|
||||
else:
|
||||
if self.version < 2.7 and parent["type"] in (
|
||||
if self.version < (2, 7) and parent["type"] in (
|
||||
"root",
|
||||
"for-loop",
|
||||
"if-then",
|
||||
@@ -997,7 +997,7 @@ class Scanner2(Scanner):
|
||||
self.fixed_jumps[offset] = match[-1]
|
||||
return
|
||||
else: # op != self.opc.PJIT
|
||||
if self.version < 2.7 and code[offset + 3] == self.opc.POP_TOP:
|
||||
if self.version < (2, 7) and code[offset + 3] == self.opc.POP_TOP:
|
||||
assert_offset = offset + 4
|
||||
else:
|
||||
assert_offset = offset + 3
|
||||
@@ -1039,7 +1039,7 @@ class Scanner2(Scanner):
|
||||
if offset in self.ignore_if:
|
||||
return
|
||||
|
||||
if self.version == 2.7:
|
||||
if self.version == (2, 7):
|
||||
if (
|
||||
code[pre_rtarget] == self.opc.JUMP_ABSOLUTE
|
||||
and pre_rtarget in self.stmts
|
||||
@@ -1109,7 +1109,7 @@ class Scanner2(Scanner):
|
||||
|
||||
if_then_maybe = None
|
||||
|
||||
if 2.2 <= self.version <= 2.6:
|
||||
if (2, 2) <= self.version <= (2, 6):
|
||||
# Take the JUMP_IF target. In an "if/then", it will be
|
||||
# a POP_TOP instruction and the instruction before it
|
||||
# will be a JUMP_FORWARD to just after the POP_TOP.
|
||||
@@ -1159,13 +1159,13 @@ class Scanner2(Scanner):
|
||||
"end": pre_rtarget,
|
||||
}
|
||||
|
||||
elif self.version == 2.7:
|
||||
elif self.version[:2] == (2, 7):
|
||||
self.structs.append(
|
||||
{"type": "if-then", "start": start - 3, "end": pre_rtarget}
|
||||
)
|
||||
|
||||
# FIXME: this is yet another case were we need dominators.
|
||||
if pre_rtarget not in self.linestarts or self.version < 2.7:
|
||||
if pre_rtarget not in self.linestarts or self.version < (2, 7):
|
||||
self.not_continue.add(pre_rtarget)
|
||||
|
||||
if rtarget < end_offset:
|
||||
@@ -1194,7 +1194,7 @@ class Scanner2(Scanner):
|
||||
{"type": "else", "start": rtarget, "end": end_offset}
|
||||
)
|
||||
elif code_pre_rtarget == self.opc.RETURN_VALUE:
|
||||
if self.version == 2.7 or pre_rtarget not in self.ignore_if:
|
||||
if self.version[:2] == (2, 7) or pre_rtarget not in self.ignore_if:
|
||||
# Below, 10 is exception-match. If there is an exception
|
||||
# match in the compare, then this is an exception
|
||||
# clause not an if-then clause
|
||||
@@ -1207,7 +1207,7 @@ class Scanner2(Scanner):
|
||||
)
|
||||
self.thens[start] = rtarget
|
||||
if (
|
||||
self.version == 2.7
|
||||
self.version[:2] == (2, 7)
|
||||
or code[pre_rtarget + 1] != self.opc.JUMP_FORWARD
|
||||
):
|
||||
# The below is a big hack until we get
|
||||
@@ -1220,7 +1220,7 @@ class Scanner2(Scanner):
|
||||
# instruction before.
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
if (
|
||||
self.version == 2.7
|
||||
self.version[:2] == (2, 7)
|
||||
and self.insts[
|
||||
self.offset2inst_index[pre[pre_rtarget]]
|
||||
].is_jump_target
|
||||
@@ -1291,7 +1291,7 @@ class Scanner2(Scanner):
|
||||
# if (op in self.opc.JREL_OPS and
|
||||
# (self.version < 2.0 or op != self.opc.FOR_ITER)):
|
||||
label = offset + 3 + oparg
|
||||
elif self.version == 2.7 and op in self.opc.JABS_OPS:
|
||||
elif self.version[:2] == (2, 7) and op in self.opc.JABS_OPS:
|
||||
if op in (
|
||||
self.opc.JUMP_IF_FALSE_OR_POP,
|
||||
self.opc.JUMP_IF_TRUE_OR_POP,
|
||||
@@ -1307,7 +1307,7 @@ class Scanner2(Scanner):
|
||||
# We REALLY REALLY need a better way to handle control flow
|
||||
# Expecially for < 2.7
|
||||
if label is not None and label != -1:
|
||||
if self.version == 2.7:
|
||||
if self.version[:2] == (2, 7):
|
||||
# FIXME: rocky: I think we need something like this...
|
||||
if label in self.setup_loops:
|
||||
source = self.setup_loops[label]
|
||||
@@ -1342,7 +1342,7 @@ class Scanner2(Scanner):
|
||||
# handle COME_FROM's from a loop inside if's
|
||||
# It probably should.
|
||||
if (
|
||||
self.version > 2.6
|
||||
self.version > (2, 6)
|
||||
or self.code[source] != self.opc.SETUP_LOOP
|
||||
or self.code[label] != self.opc.JUMP_FORWARD
|
||||
):
|
||||
@@ -1354,7 +1354,7 @@ class Scanner2(Scanner):
|
||||
elif (
|
||||
op == self.opc.END_FINALLY
|
||||
and offset in self.fixed_jumps
|
||||
and self.version == 2.7
|
||||
and self.version[:2] == (2, 7)
|
||||
):
|
||||
label = self.fixed_jumps[offset]
|
||||
targets[label] = targets.get(label, []) + [offset]
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.1 bytecode massaging.
|
||||
|
||||
@@ -22,6 +22,6 @@ class Scanner21(scan.Scanner22):
|
||||
scan.Scanner22.__init__(self, show_asm=False)
|
||||
self.opc = opcode_21
|
||||
self.opname = opcode_21.opname
|
||||
self.version = 2.1
|
||||
self.version = (2, 1)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.2 bytecode massaging.
|
||||
|
||||
@@ -22,7 +22,7 @@ class Scanner22(scan.Scanner23):
|
||||
scan.Scanner23.__init__(self, show_asm=False)
|
||||
self.opc = opcode_22
|
||||
self.opname = opcode_22.opname
|
||||
self.version = 2.2
|
||||
self.version = (2, 2)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
self.parent_ingest = self.ingest
|
||||
self.ingest = self.ingest22
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.3 bytecode massaging.
|
||||
|
||||
@@ -23,6 +23,6 @@ class Scanner23(scan.Scanner24):
|
||||
self.opname = opcode_23.opname
|
||||
# These are the only differences in initialization between
|
||||
# 2.3-2.6
|
||||
self.version = 2.3
|
||||
self.version = (2, 3)
|
||||
self.genexpr_name = '<generator expression>'
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.4 bytecode massaging.
|
||||
|
||||
@@ -10,6 +10,7 @@ import uncompyle6.scanners.scanner25 as scan
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
from xdis.opcodes import opcode_24
|
||||
|
||||
JUMP_OPS = opcode_24.JUMP_OPS
|
||||
|
||||
# We base this off of 2.5 instead of the other way around
|
||||
@@ -23,6 +24,6 @@ class Scanner24(scan.Scanner25):
|
||||
# 2.4, 2.5 and 2.6
|
||||
self.opc = opcode_24
|
||||
self.opname = opcode_24.opname
|
||||
self.version = 2.4
|
||||
self.genexpr_name = '<generator expression>'
|
||||
self.version = (2, 4)
|
||||
self.genexpr_name = "<generator expression>"
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.5 bytecode massaging.
|
||||
|
||||
@@ -24,5 +24,5 @@ class Scanner25(scan.Scanner26):
|
||||
self.opc = opcode_25
|
||||
self.opname = opcode_25.opname
|
||||
scan.Scanner26.__init__(self, show_asm)
|
||||
self.version = 2.5
|
||||
self.version = (2, 5)
|
||||
return
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2017, 2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
@@ -40,7 +40,7 @@ JUMP_OPS = opcode_26.JUMP_OPS
|
||||
|
||||
class Scanner26(scan.Scanner2):
|
||||
def __init__(self, show_asm=False):
|
||||
super(Scanner26, self).__init__(2.6, show_asm)
|
||||
super(Scanner26, self).__init__((2, 6), show_asm)
|
||||
|
||||
# "setup" opcodes
|
||||
self.setup_ops = frozenset([
|
||||
@@ -213,13 +213,13 @@ class Scanner26(scan.Scanner2):
|
||||
# CE - Hack for >= 2.5
|
||||
# Now all values loaded via LOAD_CLOSURE are packed into
|
||||
# a tuple before calling MAKE_CLOSURE.
|
||||
if (self.version >= 2.5 and op == self.opc.BUILD_TUPLE and
|
||||
if (self.version >= (2, 5) and op == self.opc.BUILD_TUPLE and
|
||||
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE):
|
||||
continue
|
||||
else:
|
||||
op_name = '%s_%d' % (op_name, oparg)
|
||||
customize[op_name] = oparg
|
||||
elif self.version > 2.0 and op == self.opc.CONTINUE_LOOP:
|
||||
elif self.version > (2, 0) and op == self.opc.CONTINUE_LOOP:
|
||||
customize[op_name] = 0
|
||||
elif op_name in """
|
||||
CONTINUE_LOOP EXEC_STMT LOAD_LISTCOMP LOAD_SETCOMP
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.7 bytecode ingester.
|
||||
|
||||
@@ -9,78 +9,116 @@ grammar parsing.
|
||||
|
||||
from uncompyle6.scanners.scanner2 import Scanner2
|
||||
|
||||
from uncompyle6 import PYTHON3
|
||||
from xdis.version_info import PYTHON3, version_tuple_to_str
|
||||
|
||||
if PYTHON3:
|
||||
import sys
|
||||
|
||||
intern = sys.intern
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
from xdis.opcodes import opcode_27
|
||||
|
||||
JUMP_OPS = opcode_27.JUMP_OPs
|
||||
|
||||
|
||||
class Scanner27(Scanner2):
|
||||
def __init__(self, show_asm=False, is_pypy=False):
|
||||
super(Scanner27, self).__init__(2.7, show_asm, is_pypy)
|
||||
super(Scanner27, self).__init__((2, 7), show_asm, is_pypy)
|
||||
|
||||
# opcodes that start statements
|
||||
self.statement_opcodes = frozenset(
|
||||
self.statement_opcodes | set([
|
||||
# New in 2.7
|
||||
self.opc.SETUP_WITH,
|
||||
self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1,
|
||||
self.opc.STORE_SLICE_2, self.opc.STORE_SLICE_3,
|
||||
self.opc.DELETE_SLICE_0, self.opc.DELETE_SLICE_1,
|
||||
self.opc.DELETE_SLICE_2, self.opc.DELETE_SLICE_3,
|
||||
]))
|
||||
self.statement_opcodes
|
||||
| set(
|
||||
[
|
||||
# New in 2.7
|
||||
self.opc.SETUP_WITH,
|
||||
self.opc.STORE_SLICE_0,
|
||||
self.opc.STORE_SLICE_1,
|
||||
self.opc.STORE_SLICE_2,
|
||||
self.opc.STORE_SLICE_3,
|
||||
self.opc.DELETE_SLICE_0,
|
||||
self.opc.DELETE_SLICE_1,
|
||||
self.opc.DELETE_SLICE_2,
|
||||
self.opc.DELETE_SLICE_3,
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
# opcodes which expect a variable number pushed values and whose
|
||||
# count is in the opcode. For parsing we generally change the
|
||||
# opcode name to include that number.
|
||||
varargs_ops = set([
|
||||
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
||||
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
|
||||
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
|
||||
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
|
||||
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
|
||||
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS,
|
||||
# New in Python 2.7
|
||||
self.opc.BUILD_SET, self.opc.BUILD_MAP])
|
||||
varargs_ops = set(
|
||||
[
|
||||
self.opc.BUILD_LIST,
|
||||
self.opc.BUILD_TUPLE,
|
||||
self.opc.BUILD_SLICE,
|
||||
self.opc.UNPACK_SEQUENCE,
|
||||
self.opc.MAKE_FUNCTION,
|
||||
self.opc.CALL_FUNCTION,
|
||||
self.opc.MAKE_CLOSURE,
|
||||
self.opc.CALL_FUNCTION_VAR,
|
||||
self.opc.CALL_FUNCTION_KW,
|
||||
self.opc.CALL_FUNCTION_VAR_KW,
|
||||
self.opc.DUP_TOPX,
|
||||
self.opc.RAISE_VARARGS,
|
||||
# New in Python 2.7
|
||||
self.opc.BUILD_SET,
|
||||
self.opc.BUILD_MAP,
|
||||
]
|
||||
)
|
||||
|
||||
if is_pypy:
|
||||
varargs_ops.add(self.opc.CALL_METHOD)
|
||||
self.varargs_ops = frozenset(varargs_ops)
|
||||
|
||||
# "setup" opcodes
|
||||
self.setup_ops = frozenset([
|
||||
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
|
||||
# New in 2.7
|
||||
self.opc.SETUP_WITH])
|
||||
self.setup_ops = frozenset(
|
||||
[
|
||||
self.opc.SETUP_EXCEPT,
|
||||
self.opc.SETUP_FINALLY,
|
||||
# New in 2.7
|
||||
self.opc.SETUP_WITH,
|
||||
]
|
||||
)
|
||||
|
||||
# opcodes that store values into a variable
|
||||
self.designator_ops = frozenset([
|
||||
self.opc.STORE_FAST, self.opc.STORE_NAME,
|
||||
self.opc.STORE_GLOBAL, self.opc.STORE_DEREF, self.opc.STORE_ATTR,
|
||||
self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, self.opc.STORE_SLICE_2,
|
||||
self.opc.STORE_SLICE_3, self.opc.STORE_SUBSCR, self.opc.UNPACK_SEQUENCE,
|
||||
self.opc.JUMP_ABSOLUTE
|
||||
])
|
||||
self.designator_ops = frozenset(
|
||||
[
|
||||
self.opc.STORE_FAST,
|
||||
self.opc.STORE_NAME,
|
||||
self.opc.STORE_GLOBAL,
|
||||
self.opc.STORE_DEREF,
|
||||
self.opc.STORE_ATTR,
|
||||
self.opc.STORE_SLICE_0,
|
||||
self.opc.STORE_SLICE_1,
|
||||
self.opc.STORE_SLICE_2,
|
||||
self.opc.STORE_SLICE_3,
|
||||
self.opc.STORE_SUBSCR,
|
||||
self.opc.UNPACK_SEQUENCE,
|
||||
self.opc.JUMP_ABSOLUTE,
|
||||
]
|
||||
)
|
||||
|
||||
self.pop_jump_if_or_pop = frozenset([self.opc.JUMP_IF_FALSE_OR_POP,
|
||||
self.opc.JUMP_IF_TRUE_OR_POP])
|
||||
self.pop_jump_if_or_pop = frozenset(
|
||||
[self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP]
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
if PYTHON_VERSION == 2.7:
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
||||
|
||||
if PYTHON_VERSION_TRIPLE[:2] == (2, 7):
|
||||
import inspect
|
||||
|
||||
co = inspect.currentframe().f_code
|
||||
tokens, customize = Scanner27().ingest(co)
|
||||
for t in tokens:
|
||||
print(t)
|
||||
pass
|
||||
else:
|
||||
print("Need to be Python 2.7 to demo; I am %s." %
|
||||
PYTHON_VERSION)
|
||||
print("Need to be Python 2.7 to demo; I am %s." % version_tuple_to_str())
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2019, 2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
@@ -71,7 +71,7 @@ class Scanner3(Scanner):
|
||||
# at the their targets.
|
||||
# Some blocks and END_ statements. And they can start
|
||||
# a new statement
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
setup_ops = [
|
||||
self.opc.SETUP_LOOP,
|
||||
self.opc.SETUP_EXCEPT,
|
||||
@@ -84,11 +84,11 @@ class Scanner3(Scanner):
|
||||
setup_ops = [self.opc.SETUP_FINALLY]
|
||||
self.setup_ops_no_loop = frozenset(setup_ops)
|
||||
|
||||
if self.version >= 3.2:
|
||||
if self.version >= (3, 2):
|
||||
setup_ops.append(self.opc.SETUP_WITH)
|
||||
self.setup_ops = frozenset(setup_ops)
|
||||
|
||||
if self.version == 3.0:
|
||||
if self.version[:2] == (3, 0):
|
||||
self.pop_jump_tf = frozenset(
|
||||
[self.opc.JUMP_IF_FALSE, self.opc.JUMP_IF_TRUE]
|
||||
)
|
||||
@@ -119,7 +119,7 @@ class Scanner3(Scanner):
|
||||
self.opc.JUMP_ABSOLUTE,
|
||||
]
|
||||
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
statement_opcodes += [self.opc.BREAK_LOOP, self.opc.CONTINUE_LOOP]
|
||||
|
||||
self.statement_opcodes = frozenset(statement_opcodes) | self.setup_ops_no_loop
|
||||
@@ -140,7 +140,7 @@ class Scanner3(Scanner):
|
||||
]
|
||||
)
|
||||
|
||||
if self.version > 3.0:
|
||||
if self.version > (3, 0):
|
||||
self.jump_if_pop = frozenset(
|
||||
[self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP]
|
||||
)
|
||||
@@ -187,9 +187,9 @@ class Scanner3(Scanner):
|
||||
]
|
||||
)
|
||||
|
||||
if is_pypy or self.version >= 3.7:
|
||||
if is_pypy or self.version >= (3, 7):
|
||||
varargs_ops.add(self.opc.CALL_METHOD)
|
||||
if self.version >= 3.5:
|
||||
if self.version >= (3, 5):
|
||||
varargs_ops |= set(
|
||||
[
|
||||
self.opc.BUILD_SET_UNPACK,
|
||||
@@ -198,7 +198,7 @@ class Scanner3(Scanner):
|
||||
self.opc.BUILD_TUPLE_UNPACK,
|
||||
]
|
||||
)
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
varargs_ops.add(self.opc.BUILD_CONST_KEY_MAP)
|
||||
# Below is in bit order, "default = bit 0, closure = bit 3
|
||||
self.MAKE_FUNCTION_FLAGS = tuple(
|
||||
@@ -265,7 +265,7 @@ class Scanner3(Scanner):
|
||||
# If we have a JUMP_FORWARD after the
|
||||
# RAISE_VARARGS then we have a "raise" statement
|
||||
# else we have an "assert" statement.
|
||||
if self.version == 3.0:
|
||||
if self.version[:2] == (3, 0):
|
||||
# Like 2.6, 3.0 doesn't have POP_JUMP_IF... so we have
|
||||
# to go through more machinations
|
||||
assert_can_follow = inst.opname == "POP_TOP" and i + 1 < n
|
||||
@@ -387,7 +387,7 @@ class Scanner3(Scanner):
|
||||
# pattr = 'code_object @ 0x%x %s->%s' %\
|
||||
# (id(const), const.co_filename, const.co_name)
|
||||
pattr = "<code_object " + const.co_name + ">"
|
||||
elif isinstance(const, str) or xdis.PYTHON_VERSION <= 2.7 and isinstance(const, unicode):
|
||||
elif isinstance(const, str) or PYTHON_VERSION <= 2.7 and isinstance(const, unicode):
|
||||
opname = "LOAD_STR"
|
||||
else:
|
||||
if isinstance(inst.arg, int) and inst.arg < len(co.co_consts):
|
||||
@@ -398,7 +398,7 @@ class Scanner3(Scanner):
|
||||
pattr = const
|
||||
pass
|
||||
elif opname in ("MAKE_FUNCTION", "MAKE_CLOSURE"):
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
# 3.6+ doesn't have MAKE_CLOSURE, so opname == 'MAKE_FUNCTION'
|
||||
flags = argval
|
||||
opname = "MAKE_FUNCTION_%d" % (flags)
|
||||
@@ -452,7 +452,7 @@ class Scanner3(Scanner):
|
||||
# as JUMP_IF_NOT_DEBUG. The value is not used in these cases, so we put
|
||||
# in arbitrary value 0.
|
||||
customize[opname] = 0
|
||||
elif self.version >= 3.6 and argval > 255:
|
||||
elif self.version >= (3, 6) and argval > 255:
|
||||
opname = "CALL_FUNCTION_KW"
|
||||
pass
|
||||
|
||||
@@ -491,7 +491,7 @@ class Scanner3(Scanner):
|
||||
and self.insts[i + 1].opname == "JUMP_FORWARD"
|
||||
)
|
||||
|
||||
if (self.version == 3.0 and self.insts[i + 1].opname == "JUMP_FORWARD"
|
||||
if (self.version[:2] == (3, 0) and self.insts[i + 1].opname == "JUMP_FORWARD"
|
||||
and not is_continue):
|
||||
target_prev = self.offset2inst_index[self.prev_op[target]]
|
||||
is_continue = (
|
||||
@@ -593,7 +593,7 @@ class Scanner3(Scanner):
|
||||
if inst.has_arg:
|
||||
label = self.fixed_jumps.get(offset)
|
||||
oparg = inst.arg
|
||||
if self.version >= 3.6 and self.code[offset] == self.opc.EXTENDED_ARG:
|
||||
if self.version >= (3, 6) and self.code[offset] == self.opc.EXTENDED_ARG:
|
||||
j = xdis.next_offset(op, self.opc, offset)
|
||||
next_offset = xdis.next_offset(op, self.opc, j)
|
||||
else:
|
||||
@@ -740,7 +740,7 @@ class Scanner3(Scanner):
|
||||
end = current_end
|
||||
parent = struct
|
||||
|
||||
if self.version < 3.8 and op == self.opc.SETUP_LOOP:
|
||||
if self.version < (3, 8) and op == self.opc.SETUP_LOOP:
|
||||
# We categorize loop types: 'for', 'while', 'while 1' with
|
||||
# possibly suffixes '-loop' and '-else'
|
||||
# Try to find the jump_back instruction of the loop.
|
||||
@@ -871,7 +871,7 @@ class Scanner3(Scanner):
|
||||
# In some cases the pretarget can be a jump to the next instruction
|
||||
# and these aren't and/or's either. We limit to 3.5+ since we experienced there
|
||||
# but it might be earlier versions, or might be a general principle.
|
||||
if self.version < 3.5 or pretarget.argval != target:
|
||||
if self.version < (3, 5) or pretarget.argval != target:
|
||||
# FIXME: this is not accurate The commented out below
|
||||
# is what it should be. However grammar rules right now
|
||||
# assume the incorrect offsets.
|
||||
@@ -965,7 +965,7 @@ class Scanner3(Scanner):
|
||||
)
|
||||
):
|
||||
pass
|
||||
elif self.version <= 3.2:
|
||||
elif self.version <= (3, 2):
|
||||
fix = None
|
||||
jump_ifs = self.inst_matches(
|
||||
start,
|
||||
@@ -984,7 +984,7 @@ class Scanner3(Scanner):
|
||||
self.fixed_jumps[offset] = fix or match[-1]
|
||||
return
|
||||
else:
|
||||
if self.version < 3.6:
|
||||
if self.version < (3, 6):
|
||||
# FIXME: this is putting in COME_FROMs in the wrong place.
|
||||
# Fix up grammar so we don't need to do this.
|
||||
# See cf_for_iter use in parser36.py
|
||||
@@ -1052,20 +1052,20 @@ class Scanner3(Scanner):
|
||||
# if the condition jump is to a forward location.
|
||||
# Also the existence of a jump to the instruction after "END_FINALLY"
|
||||
# will distinguish "try/else" from "try".
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rtarget_break = (self.opc.RETURN_VALUE, self.opc.BREAK_LOOP)
|
||||
else:
|
||||
rtarget_break = (self.opc.RETURN_VALUE,)
|
||||
|
||||
if self.is_jump_forward(pre_rtarget) or (
|
||||
rtarget_is_ja and self.version >= 3.5
|
||||
rtarget_is_ja and self.version >= (3, 5)
|
||||
):
|
||||
if_end = self.get_target(pre_rtarget)
|
||||
|
||||
# If the jump target is back, we are looping
|
||||
if (
|
||||
if_end < pre_rtarget
|
||||
and self.version < 3.8
|
||||
and self.version < (3, 8)
|
||||
and (code[prev_op[if_end]] == self.opc.SETUP_LOOP)
|
||||
):
|
||||
if if_end > start:
|
||||
@@ -1102,11 +1102,11 @@ class Scanner3(Scanner):
|
||||
if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP:
|
||||
if self.opc.cmp_op[code[jump_prev + 1]] == "exception-match":
|
||||
return
|
||||
if self.version >= 3.5:
|
||||
if self.version >= (3, 5):
|
||||
# Python 3.5 may remove as dead code a JUMP
|
||||
# instruction after a RETURN_VALUE. So we check
|
||||
# based on seeing SETUP_EXCEPT various places.
|
||||
if self.version < 3.6 and code[rtarget] == self.opc.SETUP_EXCEPT:
|
||||
if self.version < (3, 6) and code[rtarget] == self.opc.SETUP_EXCEPT:
|
||||
return
|
||||
# Check that next instruction after pops and jump is
|
||||
# not from SETUP_EXCEPT
|
||||
@@ -1119,14 +1119,14 @@ class Scanner3(Scanner):
|
||||
for try_op in targets[next_op]:
|
||||
come_from_op = code[try_op]
|
||||
if (
|
||||
self.version < 3.8
|
||||
self.version < (3, 8)
|
||||
and come_from_op == self.opc.SETUP_EXCEPT
|
||||
):
|
||||
return
|
||||
pass
|
||||
pass
|
||||
|
||||
if self.version >= 3.4:
|
||||
if self.version >= (3, 4):
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
|
||||
if code[pre_rtarget] == self.opc.RETURN_VALUE:
|
||||
@@ -1145,8 +1145,8 @@ class Scanner3(Scanner):
|
||||
# FIXME: this is very convoluted and based on rather hacky
|
||||
# empirical evidence. It should go a way when
|
||||
# we have better control-flow analysis
|
||||
normal_jump = self.version >= 3.6
|
||||
if self.version == 3.5:
|
||||
normal_jump = self.version >= (3, 6)
|
||||
if self.version[:2] == (3, 5):
|
||||
j = self.offset2inst_index[target]
|
||||
if j + 2 < len(self.insts) and self.insts[j + 2].is_jump_target:
|
||||
normal_jump = self.insts[j + 1].opname == "POP_BLOCK"
|
||||
@@ -1163,7 +1163,7 @@ class Scanner3(Scanner):
|
||||
if rtarget > offset:
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
|
||||
elif self.version < 3.8 and op == self.opc.SETUP_EXCEPT:
|
||||
elif self.version < (3, 8) and op == self.opc.SETUP_EXCEPT:
|
||||
target = self.get_target(offset)
|
||||
end = self.restrict_to_parent(target, parent)
|
||||
self.fixed_jumps[offset] = end
|
||||
@@ -1196,7 +1196,7 @@ class Scanner3(Scanner):
|
||||
self.fixed_jumps[offset] = self.restrict_to_parent(target, parent)
|
||||
pass
|
||||
pass
|
||||
elif self.version >= 3.5:
|
||||
elif self.version >= (3, 5):
|
||||
# 3.5+ has Jump optimization which too often causes RETURN_VALUE to get
|
||||
# misclassified as RETURN_END_IF. Handle that here.
|
||||
# In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF
|
||||
@@ -1286,7 +1286,7 @@ class Scanner3(Scanner):
|
||||
start, end, instr, target, include_beyond_target
|
||||
)
|
||||
# Get all POP_JUMP_IF_TRUE (or) offsets
|
||||
if self.version == 3.0:
|
||||
if self.version[:2] == (3, 0):
|
||||
jump_true_op = self.opc.JUMP_IF_TRUE
|
||||
else:
|
||||
jump_true_op = self.opc.POP_JUMP_IF_TRUE
|
||||
@@ -1303,17 +1303,16 @@ class Scanner3(Scanner):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
||||
|
||||
if PYTHON_VERSION >= 3.2:
|
||||
if PYTHON_VERSION_TRIPLE >= (3, 2):
|
||||
import inspect
|
||||
|
||||
co = inspect.currentframe().f_code
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
|
||||
tokens, customize = Scanner3(PYTHON_VERSION).ingest(co)
|
||||
tokens, customize = Scanner3(PYTHON_VERSION_TRIPLE).ingest(co)
|
||||
for t in tokens:
|
||||
print(t)
|
||||
else:
|
||||
print("Need to be Python 3.2 or greater to demo; I am %s." % PYTHON_VERSION)
|
||||
print("Need to be Python 3.2 or greater to demo; I am %s." % sys.version)
|
||||
pass
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017, 2020 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2020-2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 3.0 bytecode scanner/deparser
|
||||
|
||||
@@ -18,7 +18,7 @@ from uncompyle6.scanners.scanner3 import Scanner3
|
||||
|
||||
class Scanner30(Scanner3):
|
||||
def __init__(self, show_asm=None, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.0, show_asm, is_pypy)
|
||||
Scanner3.__init__(self, (3, 0), show_asm, is_pypy)
|
||||
return
|
||||
|
||||
pass
|
||||
@@ -471,7 +471,7 @@ class Scanner30(Scanner3):
|
||||
if __name__ == "__main__":
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
|
||||
if PYTHON_VERSION == 3.0:
|
||||
if PYTHON_VERSION == (3, 0):
|
||||
import inspect
|
||||
|
||||
co = inspect.currentframe().f_code
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 3.1 bytecode scanner/deparser
|
||||
|
||||
@@ -14,13 +14,13 @@ from uncompyle6.scanners.scanner3 import Scanner3
|
||||
class Scanner31(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=None, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.1, show_asm, is_pypy)
|
||||
Scanner3.__init__(self, (3, 1), show_asm, is_pypy)
|
||||
return
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
if PYTHON_VERSION == 3.1:
|
||||
if PYTHON_VERSION == (3, 1):
|
||||
import inspect
|
||||
co = inspect.currentframe().f_code
|
||||
tokens, customize = Scanner31().ingest(co)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2017, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 3.2 bytecode decompiler scanner.
|
||||
|
||||
@@ -17,7 +17,7 @@ from uncompyle6.scanners.scanner3 import Scanner3
|
||||
class Scanner32(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=None, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.2, show_asm, is_pypy)
|
||||
Scanner3.__init__(self, (3, 2), show_asm, is_pypy)
|
||||
return
|
||||
pass
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2019, 2021 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
|
||||
@@ -27,7 +27,7 @@ from uncompyle6.scanners.scanner3 import Scanner3
|
||||
class Scanner33(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=False, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.3, show_asm)
|
||||
Scanner3.__init__(self, (3, 3), show_asm)
|
||||
return
|
||||
pass
|
||||
|
||||
|
@@ -32,7 +32,7 @@ from uncompyle6.scanners.scanner3 import Scanner3
|
||||
class Scanner34(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner3.__init__(self, 3.4, show_asm)
|
||||
Scanner3.__init__(self, (3, 4), show_asm)
|
||||
return
|
||||
pass
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017 by Rocky Bernstein
|
||||
# Copyright (c) 2017, 2021 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
|
||||
@@ -31,7 +31,7 @@ JUMP_OPS = opc.JUMP_OPS
|
||||
class Scanner35(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=None, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.5, show_asm, is_pypy)
|
||||
Scanner3.__init__(self, (3, 5), show_asm, is_pypy)
|
||||
return
|
||||
pass
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 3.6 bytecode decompiler scanner
|
||||
|
||||
@@ -18,12 +18,12 @@ JUMP_OPS = opc.JUMP_OPS
|
||||
class Scanner36(Scanner3):
|
||||
|
||||
def __init__(self, show_asm=None, is_pypy=False):
|
||||
Scanner3.__init__(self, 3.6, show_asm, is_pypy)
|
||||
Scanner3.__init__(self, (3, 6), show_asm, is_pypy)
|
||||
return
|
||||
|
||||
def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||
tokens, customize = Scanner3.ingest(self, co, classname, code_objects, show_asm)
|
||||
not_pypy36 = not (self.version == 3.6 and self.is_pypy)
|
||||
not_pypy36 = not (self.version[:2] == (3, 6) and self.is_pypy)
|
||||
for t in tokens:
|
||||
# The lowest bit of flags indicates whether the
|
||||
# var-keyword argument is placed at the top of the stack
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2019, 2021 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
|
||||
@@ -33,7 +33,7 @@ JUMP_OPs = opc.JUMP_OPS
|
||||
|
||||
class Scanner37(Scanner37Base):
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner37Base.__init__(self, 3.7, show_asm)
|
||||
Scanner37Base.__init__(self, (3, 7), show_asm)
|
||||
return
|
||||
|
||||
pass
|
||||
|
@@ -55,7 +55,7 @@ class Scanner37Base(Scanner):
|
||||
# Ops that start SETUP_ ... We will COME_FROM with these names
|
||||
# Some blocks and END_ statements. And they can start
|
||||
# a new statement
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
setup_ops = [
|
||||
self.opc.SETUP_LOOP,
|
||||
self.opc.SETUP_EXCEPT,
|
||||
@@ -468,7 +468,7 @@ class Scanner37Base(Scanner):
|
||||
and self.insts[i + 1].opname == "JUMP_FORWARD"
|
||||
)
|
||||
|
||||
if self.version < 3.8 and (
|
||||
if self.version < (3, 8) and (
|
||||
is_continue
|
||||
or (
|
||||
inst.offset in self.stmts
|
||||
@@ -712,7 +712,7 @@ class Scanner37Base(Scanner):
|
||||
end = current_end
|
||||
parent = struct
|
||||
|
||||
if self.version < 3.8 and op == self.opc.SETUP_LOOP:
|
||||
if self.version < (3, 8) and op == self.opc.SETUP_LOOP:
|
||||
# We categorize loop types: 'for', 'while', 'while 1' with
|
||||
# possibly suffixes '-loop' and '-else'
|
||||
# Try to find the jump_back instruction of the loop.
|
||||
@@ -820,7 +820,7 @@ class Scanner37Base(Scanner):
|
||||
target = inst.argval
|
||||
self.fixed_jumps[offset] = target
|
||||
|
||||
elif self.version < 3.8 and op == self.opc.SETUP_EXCEPT:
|
||||
elif self.version < (3, 8) and op == self.opc.SETUP_EXCEPT:
|
||||
target = self.get_target(offset)
|
||||
end = self.restrict_to_parent(target, parent)
|
||||
self.fixed_jumps[offset] = end
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2019-2021 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
|
||||
@@ -35,7 +35,7 @@ JUMP_OPs = opc.JUMP_OPS
|
||||
|
||||
class Scanner38(Scanner37):
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner37Base.__init__(self, 3.8, show_asm)
|
||||
Scanner37Base.__init__(self, (3, 8), show_asm)
|
||||
self.debug = False
|
||||
return
|
||||
|
||||
@@ -61,7 +61,7 @@ class Scanner38(Scanner37):
|
||||
if self.debug and jump_back_targets:
|
||||
print(jump_back_targets)
|
||||
loop_ends = []
|
||||
next_end = tokens[len(tokens)-1].off2int() + 10
|
||||
next_end = tokens[len(tokens) - 1].off2int() + 10
|
||||
for i, token in enumerate(tokens):
|
||||
opname = token.kind
|
||||
offset = token.offset
|
||||
@@ -78,8 +78,10 @@ class Scanner38(Scanner37):
|
||||
if offset in jump_back_targets:
|
||||
next_end = off2int(jump_back_targets[offset], prefer_last=False)
|
||||
if self.debug:
|
||||
print("%sadding loop offset %s ending at %s" %
|
||||
(' ' * len(loop_ends), offset, next_end))
|
||||
print(
|
||||
"%sadding loop offset %s ending at %s"
|
||||
% (" " * len(loop_ends), offset, next_end)
|
||||
)
|
||||
loop_ends.append(next_end)
|
||||
|
||||
# Turn JUMP opcodes into "BREAK_LOOP" opcodes.
|
||||
@@ -110,10 +112,7 @@ class Scanner38(Scanner37):
|
||||
jump_back_token = tokens[jump_back_index]
|
||||
|
||||
# Is this a forward jump not next to a JUMP_BACK ? ...
|
||||
break_loop = (
|
||||
token.linestart
|
||||
and jump_back_token != "JUMP_BACK"
|
||||
)
|
||||
break_loop = token.linestart and jump_back_token != "JUMP_BACK"
|
||||
|
||||
# or if there is looping jump back, then that loop
|
||||
# should start before where the "break" instruction sits.
|
||||
@@ -139,5 +138,4 @@ if __name__ == "__main__":
|
||||
print(t.format())
|
||||
pass
|
||||
else:
|
||||
print("Need to be Python 3.8 to demo; I am %s." %
|
||||
PYTHON_VERSION)
|
||||
print("Need to be Python 3.8 to demo; I am %s." % PYTHON_VERSION)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019, 2021 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
|
||||
@@ -33,7 +33,7 @@ JUMP_OPs = opc.JUMP_OPS
|
||||
|
||||
class Scanner39(Scanner38):
|
||||
def __init__(self, show_asm=None):
|
||||
Scanner37Base.__init__(self, 3.9, show_asm)
|
||||
Scanner37Base.__init__(self, (3, 9), show_asm)
|
||||
return
|
||||
|
||||
pass
|
||||
|
@@ -86,7 +86,21 @@ class Token: # Python 2.4 can't have empty ()
|
||||
self.pattr = None
|
||||
|
||||
if opc is None:
|
||||
from xdis.std import _std_api
|
||||
try:
|
||||
from xdis.std import _std_api
|
||||
except KeyError:
|
||||
e = sys.exec_info()[1]
|
||||
print("I don't know about Python version %s yet." % e)
|
||||
try:
|
||||
version_tuple = tuple(int(i) for i in str(e)[1:-1].split("."))
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if version_tuple > (3, 9):
|
||||
print("Python versions 3.9 and greater are not supported.")
|
||||
else:
|
||||
print("xdis might need to be informed about version {e}" % e)
|
||||
return
|
||||
|
||||
self.opc = _std_api.opc
|
||||
else:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2018-2019, 2021 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
|
||||
@@ -60,8 +60,8 @@ def customize_for_version(self, is_pypy, version):
|
||||
"assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2),
|
||||
"try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3),
|
||||
})
|
||||
if version >= 3.0:
|
||||
if version >= 3.2:
|
||||
if version >= (3, 0):
|
||||
if version >= (3, 2):
|
||||
TABLE_DIRECT.update(
|
||||
{"del_deref_stmt": ("%|del %c\n", 0), "DELETE_DEREF": ("%{pattr}", 0)}
|
||||
)
|
||||
@@ -72,20 +72,20 @@ def customize_for_version(self, is_pypy, version):
|
||||
TABLE_DIRECT.update(
|
||||
{"except_cond3": ("%|except %c, %c:\n", (1, "expr"), (-2, "store"))}
|
||||
)
|
||||
if version <= 2.6:
|
||||
if version <= (2, 6):
|
||||
TABLE_DIRECT["testtrue_then"] = TABLE_DIRECT["testtrue"]
|
||||
|
||||
if 2.4 <= version <= 2.6:
|
||||
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:
|
||||
if version >= (2, 5):
|
||||
from uncompyle6.semantics.customize25 import customize_for_version25
|
||||
|
||||
customize_for_version25(self, version)
|
||||
|
||||
if version >= 2.6:
|
||||
if version >= (2, 6):
|
||||
from uncompyle6.semantics.customize26_27 import (
|
||||
customize_for_version26_27,
|
||||
)
|
||||
@@ -137,7 +137,7 @@ def customize_for_version(self, is_pypy, version):
|
||||
),
|
||||
}
|
||||
)
|
||||
if version == 2.4:
|
||||
if version == (2, 4):
|
||||
def n_iftrue_stmt24(node):
|
||||
self.template_engine(("%c", 0), node)
|
||||
self.default(node)
|
||||
@@ -146,7 +146,7 @@ def customize_for_version(self, is_pypy, version):
|
||||
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:
|
||||
if version <= (2, 1):
|
||||
TABLE_DIRECT.update(
|
||||
{
|
||||
"importmultiple": ("%c", 2),
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 by Rocky Bernstein
|
||||
# Copyright (c) 2019 2021 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
|
||||
@@ -28,7 +28,7 @@ def customize_for_version26_27(self, version):
|
||||
# For 2.6 we use the older syntax which
|
||||
# matches how we parse this in bytecode
|
||||
########################################
|
||||
if version > 2.6:
|
||||
if version > (2, 6):
|
||||
TABLE_DIRECT.update({
|
||||
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
|
||||
# When a generator is a single parameter of a function,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2018-2021 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
|
||||
@@ -58,7 +58,7 @@ def customize_for_version3(self, version):
|
||||
}
|
||||
)
|
||||
|
||||
assert version >= 3.0
|
||||
assert version >= (3, 0)
|
||||
|
||||
# In 2.5+ and 3.0+ "except" handlers and the "finally" can appear in one
|
||||
# "try" statement. So the below has the effect of combining the
|
||||
@@ -107,7 +107,7 @@ def customize_for_version3(self, version):
|
||||
collections = [node[-3]]
|
||||
list_ifs = []
|
||||
|
||||
if self.version == 3.0 and n != "list_iter":
|
||||
if self.version[:2] == (3, 0) and n != "list_iter":
|
||||
# FIXME 3.0 is a snowflake here. We need
|
||||
# special code for this. Not sure if this is totally
|
||||
# correct.
|
||||
@@ -204,10 +204,10 @@ def customize_for_version3(self, version):
|
||||
self.listcomp_closure3 = listcomp_closure3
|
||||
|
||||
def n_classdef3(node):
|
||||
"""Handle "classdef" nonterminal for 3.0 >= version 3.0 <= 3.5
|
||||
"""Handle "classdef" nonterminal for 3.0 >= version 3.0 < 3.6
|
||||
"""
|
||||
|
||||
assert 3.0 <= self.version <= 3.5
|
||||
assert (3, 0) <= self.version < (3, 6)
|
||||
|
||||
# class definition ('class X(A,B,C):')
|
||||
cclass = self.currentclass
|
||||
@@ -220,7 +220,7 @@ def customize_for_version3(self, version):
|
||||
# * subclass_code - the code for the subclass body
|
||||
subclass_info = None
|
||||
if node == "classdefdeco2":
|
||||
if self.version <= 3.3:
|
||||
if self.version < (3, 4):
|
||||
class_name = node[2][0].attr
|
||||
else:
|
||||
class_name = node[1][2].attr
|
||||
@@ -233,7 +233,7 @@ def customize_for_version3(self, version):
|
||||
assert "mkfunc" == build_class[1]
|
||||
mkfunc = build_class[1]
|
||||
if mkfunc[0] in ("kwargs", "no_kwargs"):
|
||||
if 3.0 <= self.version <= 3.2:
|
||||
if (3, 0) <= self.version < (3, 3):
|
||||
for n in mkfunc:
|
||||
if hasattr(n, "attr") and iscode(n.attr):
|
||||
subclass_code = n.attr
|
||||
@@ -355,7 +355,7 @@ def customize_for_version3(self, version):
|
||||
|
||||
self.n_yield_from = n_yield_from
|
||||
|
||||
if 3.2 <= version <= 3.4:
|
||||
if (3, 2) <= version <= (3, 4):
|
||||
|
||||
def n_call(node):
|
||||
|
||||
@@ -398,7 +398,7 @@ def customize_for_version3(self, version):
|
||||
self.default(node)
|
||||
|
||||
self.n_call = n_call
|
||||
elif version < 3.2:
|
||||
elif version < (3, 2):
|
||||
|
||||
def n_call(node):
|
||||
mapping = self._get_mapping(node)
|
||||
@@ -419,9 +419,9 @@ def customize_for_version3(self, version):
|
||||
else:
|
||||
i = 0
|
||||
|
||||
if self.version <= 3.2:
|
||||
if self.version < (3, 3):
|
||||
code = node[-2 + i]
|
||||
elif self.version >= 3.3 or node[-2] == "kwargs":
|
||||
elif self.version >= (3, 3) or node[-2] == "kwargs":
|
||||
# LOAD_CONST code object ..
|
||||
# LOAD_CONST 'x0' if >= 3.3
|
||||
# EXTENDED_ARG
|
||||
@@ -471,7 +471,7 @@ def customize_for_version3(self, version):
|
||||
"LOAD_CLASSDEREF": ("%{pattr}",),
|
||||
}
|
||||
)
|
||||
if version >= 3.4:
|
||||
if version >= (3, 4):
|
||||
#######################
|
||||
# Python 3.4+ Changes #
|
||||
#######################
|
||||
@@ -481,13 +481,13 @@ def customize_for_version3(self, version):
|
||||
"yield_from": ("yield from %c", (0, "expr")),
|
||||
}
|
||||
)
|
||||
if version >= 3.5:
|
||||
if version >= (3, 5):
|
||||
customize_for_version35(self, version)
|
||||
if version >= 3.6:
|
||||
if version >= (3, 6):
|
||||
customize_for_version36(self, version)
|
||||
if version >= 3.7:
|
||||
if version >= (3, 7):
|
||||
customize_for_version37(self, version)
|
||||
if version >= 3.8:
|
||||
if version >= (3, 8):
|
||||
customize_for_version38(self, version)
|
||||
pass # version >= 3.8
|
||||
pass # 3.7
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2019-2021 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
|
||||
@@ -275,11 +275,16 @@ def customize_for_version37(self, version):
|
||||
and opname == "CALL_FUNCTION_1"
|
||||
or not re.match(r"\d", opname[-1])
|
||||
):
|
||||
if node[0][0] == "_mklambda":
|
||||
template = "(%c)(%p)"
|
||||
else:
|
||||
template = "%c(%p)"
|
||||
self.template_engine(
|
||||
("%c(%p)",
|
||||
(template,
|
||||
(0, "expr"),
|
||||
(1, PRECEDENCE["yield"]-1)),
|
||||
node)
|
||||
node
|
||||
)
|
||||
self.prec = p
|
||||
self.prune()
|
||||
else:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user