Compare commits

..

74 Commits

Author SHA1 Message Date
rocky
4377354cf9 Get ready for release 2.3.4 2016-05-05 05:05:01 -04:00
rocky
6caa2c12fa Remove pypy3 add python 3.2 testing
Reorder list for testing preference
2016-05-05 04:45:00 -04:00
rocky
3153a955d4 Remove pypy 2016-05-05 04:42:23 -04:00
rocky
6f3a88d7e2 Fix up 3.2 tests
Remove pypy
2016-05-05 04:41:23 -04:00
rocky
109737cbef Try pypy and pypy3 2016-05-05 04:14:03 -04:00
rocky
05733c6171 Python 3.5 abc.py bug distilled 2016-05-05 04:11:53 -04:00
rocky
6765a2ea97 Add cross-Python-protable 3.5 dis module 2016-05-05 03:17:25 -04:00
rocky
c85496a92d Handle 3.5 with [as]
scanner35.py: Fix a small variable-name typo
2016-05-04 22:15:03 -04:00
rocky
e4ba73adfb One more test 2016-05-03 22:27:26 -04:00
rocky
7bf93980ce Don't repeat next_except_jump 2016-05-03 19:39:01 -04:00
rocky
8241a5e3a8 Wrong package name 2016-05-03 14:35:00 -04:00
rocky
faac11ad8c More package administrivia 2016-05-03 05:50:57 -04:00
rocky
fe04b97c6b Remove one more old-style Python class 2016-05-03 03:55:43 -04:00
rocky
62f6220082 DRY Python 2.7 scanner more 2016-05-03 03:29:56 -04:00
rocky
11e6eff427 Include LICENSE in package 2016-05-03 03:14:17 -04:00
rocky
2286aa5320 Get ready for release 2.3.3 2016-05-03 03:02:36 -04:00
rocky
72ac7eb27c Be more explicit that we need Python 2.6 or later 2016-05-02 21:32:44 -04:00
rocky
a8c5f71cfe Merge branch 'master' of github.com:rocky/python-uncompyle6 2016-05-02 21:25:35 -04:00
rocky
feec241da8 Misc: long lists, DRY 2/3 grammars, '%' count
parse{2,3,r}.py: DRY Python expressions between Python 2 and 3
pysource.py, fragment.py, parser.py: handle long lists by grouping in chunks of 32
and 256
bin/uncompyle6: count %s properly
2016-05-02 21:25:16 -04:00
rocky
c5f359f9be Note relation to other uncompyle forks
Add some other minor corrections and additions as well.
2016-05-02 12:19:57 -04:00
rocky
bfe8357f52 Trivial spacing change 2016-05-02 10:44:48 -04:00
rocky
ceb47aba9c Add -V | --version and simplfy changing it 2016-05-02 04:09:51 -04:00
rocky
08720474bf Expose uncompyle_file 2016-05-01 23:11:48 -04:00
rocky
119bb9bb26 Bug 2016-05-01 21:14:25 -04:00
rocky
4455b5e280 Add test for last fix.
Drop 2.5 test until we figure out what's wrong
2016-05-01 21:07:10 -04:00
rocky
dcbf8d2cf7 Bug in 3.5 constant map parsing 2016-05-01 20:54:42 -04:00
rocky
b52baddab6 Export module load and fns load_file, load_module 2016-05-01 13:27:00 -04:00
rocky
03bb54f8ea License is MIT
marsh.py: remove unused import
2016-05-01 11:58:46 -04:00
rocky
313e468bdc Forgot to define Python3ParserSingle 2016-05-01 07:18:29 -04:00
rocky
dc80b140c6 Start to DRY Python2 and Python3 grammars
Separate out 3.2, and 3.5+ specific grammar code
2016-05-01 07:13:36 -04:00
rocky
fa48c9fc61 Get ready for release 2.3.1 2016-04-30 11:33:50 -04:00
rocky
0a32a16d88 Python 3.0..3.2 bug in LOAD_FAST/STORE_LOCAL
LOAD_FAST         '__locals__'
STORE_LOCALS      ''

Also have to adjust doc constants for this crap

astnode.py: minor format change
2016-04-30 09:12:03 -04:00
rocky
4aa703d727 Test optimized Python code and Python 3.2 2016-04-30 06:54:01 -04:00
rocky
f3a4e6ee54 Pevious commit grammar change is Python 3.5 and up 2016-04-30 04:03:38 -04:00
rocky
43f5c5dcca Python 3.5 if statments decompyle
Sometimes it doesn't need JUMP_FORWARD _come_from _come_from

For example:

def handle2(module):
    if module == 'foo':
        try:
            module = 1
        except ImportError as exc:
            module = exc

    return module

And:

if __name__:
    for i in (1, 2):
        x = 3
2016-04-30 03:51:54 -04:00
rocky
3e49aa56bb spark -> spark_parser 2016-04-28 19:03:51 -04:00
rocky
9cc9fc99c2 Really remove spark - Use external package instead 2016-04-28 02:12:30 -04:00
R. Bernstein
2ebc558b40 Merge pull request #8 from rocky/external-spark
External spark
2016-04-27 23:30:36 -04:00
rocky
34a582b64c Administrivia 2016-04-27 23:26:31 -04:00
rocky
2711c8d06f Note dependencies on spark 2016-04-27 23:09:30 -04:00
rocky
40badefe9d Use external spark now. 2016-04-27 23:04:31 -04:00
rocky
d9ef5ff69a Back to 2.7.8 2016-04-20 05:31:38 -04:00
rocky
a4e839960f Try python 2.7.10 2016-04-20 05:16:25 -04:00
rocky
7b3c7e83ec Remove link to Mysterie uncompyle2 per request 2016-04-19 04:05:05 -04:00
rocky
1b71d0a049 Get ready for release 2.2.0 2016-04-19 03:36:21 -04:00
rocky
17b0caa4f0 Another typo 2016-04-18 05:58:35 -04:00
R. Bernstein
b88e97c17d Merge pull request #7 from rocky/single-compile
Support single-mode compile
2016-04-18 05:52:33 -04:00
R. Bernstein
158bdd9b04 Merge pull request #6 from graingert/wheels
declare Python3 support in wheel and trove
2016-04-18 05:50:16 -04:00
rocky
b0d3a4e47b Doc typo 2016-04-18 05:43:14 -04:00
Thomas Grainger
4ba2eb6981 declare Python3 support in wheel and trove 2016-04-18 10:38:22 +01:00
rocky
76768c889a Start to DRY Python 2 and Python 3 grammar code
Move common code to parser.py
2016-04-18 05:32:30 -04:00
rocky
8ae7e22f2e Add simgle-mode compilation 2016-04-18 05:14:47 -04:00
rocky
7e0526d627 Towards single compilation 2016-04-17 22:47:03 -04:00
rocky
2c7fcf9e62 Back off if_else_ternary pending
Fails on Python 3.4 investigation
Python 3.5 works though
2016-04-10 21:59:06 -04:00
rocky
5a813621cb Test administrivia 2016-04-10 21:27:41 -04:00
rocky
9f7d36f8fb Handle Ternary "or". Remove mention of uncompyle3
uncompyle3 removed per Mysterie's request
[Fixes Issue #5]
2016-04-07 07:18:46 -04:00
rocky
4e57c3da5b remove uncompyle3 and make test work again
* uncompyle3 removed by request
* make test on python 2.7 is failing on some python3 and python3.5
  bytecodes. Remove for now.
2016-03-11 02:10:07 -05:00
R. Bernstein
0de3efb01a Merge pull request #3 from lelicopter/master
Bug correction (parse cmd options)
2016-02-23 21:15:30 -05:00
lelicopter
fff4283f73 Bug correction
Bug correction of parsing cmdline parameters
2016-02-24 12:05:32 +10:00
rocky
551e2174cb Add Python 3.5 tests that we can do. 2016-01-07 04:32:20 -05:00
R. Bernstein
f25c9b45a4 Grammar fixes 2016-01-05 07:47:31 -05:00
rocky
077bca6141 Get ready for release 2.1.3 2016-01-02 23:04:55 -05:00
rocky
31ebe88b38 Start to DRY opcode code. Limited support for decopyling Python 3.5 2016-01-02 22:59:02 -05:00
rocky
bc2a36b9f7 Start 3.4 library verify tests 2016-01-02 16:48:59 -05:00
rocky
66739752d8 Regularize spelling of bytecode 2016-01-02 15:55:48 -05:00
rocky
716ee6d361 Add download shield. Add check-rst target 2016-01-02 15:54:24 -05:00
R. Bernstein
ca00e433b7 Update README.rst 2016-01-02 13:32:32 -05:00
rocky
f0cc2df543 Track recent source class semantic actions in fragment actions 2016-01-02 13:11:19 -05:00
rocky
52da6f4a8f Make ScannerXX() initialization the same on Python 2.x and 3.x 2016-01-02 07:54:21 -05:00
rocky
54a0af733b Verify 3.4 bytecode. verify API call bug fixed. 2016-01-02 07:50:09 -05:00
rocky
2927921856 Python 3 class deparsing. stop earlier in uncompyle6 on a syntax error. 2016-01-02 05:38:22 -05:00
rocky
cd480c8670 Fix make_closure compilation from 2.x of 3.3 bytecode 2016-01-01 22:17:53 -05:00
rocky
7d42329c31 Work on MAKE_CLOSURE rules for Python 3.3 2016-01-01 21:55:14 -05:00
rocky
b89177d234 track source deparsing superclass bug fix 2015-12-31 15:24:24 -05:00
117 changed files with 2550 additions and 2217 deletions

3
.gitignore vendored
View File

@@ -3,9 +3,12 @@
/.cache
/.eggs
/.python-version
/.tox
/README
/__pkginfo__.pyc
/dist
/how-to-make-a-release.txt
/tmp
/uncompyle6.egg-info
__pycache__
build

View File

@@ -3,12 +3,14 @@ language: python
sudo: false
python:
- '2.6'
- '2.7'
- '3.4'
- '3.5'
- '2.7'
- '2.6'
- '3.4'
- '3.2'
install:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
script:

348
ChangeLog
View File

@@ -1,6 +1,352 @@
2016-05-05 rocky <rocky@gnu.org>
* uncompyle6/version.py: Get ready for release 2.3.4
2016-05-05 rocky <rocky@gnu.org>
* .travis.yml: Remove pypy3 add python 3.2 testing Reorder list for testing preference
2016-05-05 rocky <rocky@gnu.org>
* .travis.yml: Remove pypy
2016-05-05 rocky <rocky@gnu.org>
* Makefile, test/Makefile, uncompyle6/semantics/pysource.py: Fix up
3.2 tests Remove pypy
2016-05-05 rocky <rocky@gnu.org>
* .travis.yml: Try pypy and pypy3
2016-05-05 rocky <rocky@gnu.org>
* test/simple_source/def/05_abc_class.py,
test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py:
Python 3.5 abc.py bug distilled
2016-05-05 rocky <rocky@gnu.org>
* uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py:
Add cross-Python-protable 3.5 dis module
2016-05-04 rocky <rocky@gnu.org>
* test/simple_source/stmts/05_with.py,
uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py,
uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py:
Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo
2016-05-03 rocky <rocky@gnu.org>
* : One more test
2016-05-03 rocky <rocky@gnu.org>
* uncompyle6/scanners/scanner3.py,
uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py:
Don't repeat next_except_jump
2016-05-03 rocky <rb@dustyfeet.com>
* __pkginfo__.py, requirements.txt: Wrong package name
2016-05-03 rocky <rocky@gnu.org>
* __pkginfo__.py, requirements.txt, setup.py: More package
administrivia
2016-05-03 rocky <rocky@gnu.org>
* uncompyle6/scanner.py: Remove one more old-style Python class
2016-05-03 rocky <rocky@gnu.org>
* uncompyle6/scanners/scanner27.py: DRY Python 2.7 scanner more
2016-05-03 rocky <rocky@gnu.org>
* MANIFEST.in: Include LICENSE in package
2016-05-03 rocky <rocky@gnu.org>
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release
2.3.3
2016-05-02 rocky <rocky@gnu.org>
* README.rst: Be more explicit that we need Python 2.6 or later
2016-05-02 rocky <rocky@gnu.org>
* : commit feec241da88107b97bbdfbabeb3ae7131a7aa923 Author: rocky
<rocky@gnu.org> Date: Mon May 2 21:20:17 2016 -0400
2016-05-02 rocky <rb@dustyfeet.com>
* README.rst: Note relation to other uncompyle forks Add some other minor corrections and additions as well.
2016-05-02 rocky <rb@dustyfeet.com>
* uncompyle6/__init__.py: Trivial spacing change
2016-05-02 rocky <rocky@gnu.org>
* ChangeLog, NEWS, __pkginfo__.py, bin/pydisassemble,
bin/uncompyle6, setup.py, uncompyle6/__init__.py,
uncompyle6/version.py: Add -V | --version and simplfy changing it
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/__init__.py: Expose uncompyle_file
2016-05-01 rocky <rocky@gnu.org>
* test/Makefile, uncompyle6/semantics/pysource.py: Bug
2016-05-01 rocky <rocky@gnu.org>
* test/Makefile, test/simple_source/expression/05_const_map.py: Add
test for last fix. Drop 2.5 test until we figure out what's wrong
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py,
uncompyle6/semantics/pysource.py: Bug in 3.5 constant map parsing
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/__init__.py: Export module load and fns load_file,
load_module
2016-05-01 rocky <rocky@gnu.org>
* __pkginfo__.py, setup.py, uncompyle6/marsh.py: License is MIT marsh.py: remove unused import
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py: Forgot to define Python3ParserSingle
2016-05-01 rocky <rocky@gnu.org>
* uncompyle6/parser.py, uncompyle6/parsers/parse2.py,
uncompyle6/parsers/parse3.py: Start to DRY Python2 and Python3
grammars Separate out 3.2, and 3.5+ specific grammar code
2016-04-30 rocky <rocky@gnu.org>
* ChangeLog, NEWS, README.rst, __pkginfo__.py: Get ready for release
2.3.1
2016-04-30 rocky <rocky@gnu.org>
* uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse3.py,
uncompyle6/semantics/pysource.py: Python 3.0..3.2 bug in
LOAD_FAST/STORE_LOCAL LOAD_FAST '__locals__' STORE_LOCALS '' Also have to adjust doc constants for this crap astnode.py: minor format change
2016-04-30 rocky <rocky@gnu.org>
* test/Makefile, test/simple_source/def/06_classbug.py,
test/test_pythonlib.py: Test optimized Python code and Python 3.2
2016-04-30 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py: Pevious commit grammar change is
Python 3.5 and up
2016-04-30 rocky <rocky@gnu.org>
* uncompyle6/parsers/parse3.py: Python 3.5 if statments decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3
2016-04-28 rocky <rocky@gnu.org>
* requirements.txt, uncompyle6/parser.py,
uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py,
uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py:
spark -> spark_parser
2016-04-28 rocky <rocky@gnu.org>
* uncompyle6/parsers/spark.py: Really remove spark - Use external
package instead
2016-04-27 R. Bernstein <rocky@users.noreply.github.com>
* : Merge pull request #8 from rocky/external-spark External spark
2016-04-27 rocky <rocky@gnu.org>
* .travis.yml, circle.yml: Note dependencies on spark
2016-04-27 rocky <rocky@gnu.org>
* .gitignore, README.rst, requirements.txt, uncompyle6/parser.py,
uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py,
uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py,
uncompyle6/semantics/pysource.py: Use external spark now.
2016-04-20 rocky <rocky@gnu.org>
* circle.yml: Back to 2.7.8
2016-04-20 rocky <rocky@gnu.org>
* circle.yml: Try python 2.7.10
2016-04-19 rocky <rocky@gnu.org>
* README.rst: Remove link to Mysterie uncompyle2 per request
2016-04-19 rocky <rocky@gnu.org>
* ChangeLog, NEWS, __pkginfo__.py: Get ready for release 2.2.0
2016-04-18 rocky <rocky@gnu.org>
* README.rst: Another typo
2016-04-18 R. Bernstein <rocky@users.noreply.github.com>
* : Merge pull request #7 from rocky/single-compile Support single-mode compile
2016-04-18 rocky <rocky@gnu.org>
* README.rst: Doc typo
2016-04-18 Thomas Grainger <tom.grainger@procensus.com>
* __pkginfo__.py, setup.cfg, setup.py: declare Python3 support in
wheel and trove
2016-04-18 rocky <rocky@gnu.org>
* uncompyle6/parser.py, uncompyle6/parsers/parse2.py,
uncompyle6/parsers/parse3.py: Start to DRY Python 2 and Python 3
grammar code Move common code to parser.py
2016-04-18 rocky <rocky@gnu.org>
* pytest/test_single_compile.py, uncompyle6/parser.py,
uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Add
simgle-mode compilation
2016-04-17 rocky <rocky@gnu.org>
* pytest/test_single_compile.py, uncompyle6/parser.py,
uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py,
uncompyle6/semantics/pysource.py: Towards single compilation
2016-04-10 rocky <rb@dustyfeet.com>
* : Back off if_else_ternary pending Fails on Python 3.4 investigation Python 3.5 works though
2016-04-10 rocky <rb@dustyfeet.com>
* .gitignore: Test administrivia
2016-04-07 rocky <rb@dustyfeet.com>
* HISTORY.md, README.rst,
test/simple_source/branching/10_if_else_ternary.py,
uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Handle
Ternary "or". Remove mention of uncompyle3 uncompyle3 removed per Mysterie's request [Fixes Issue #5]
2016-03-11 rocky <rb@dustyfeet.com>
* test/Makefile: remove uncompyle3 and make test work again * uncompyle3 removed by request * make test on python 2.7 is failing on some python3 and python3.5 bytecodes. Remove for now.
2016-02-23 R. Bernstein <rocky@users.noreply.github.com>
* : Merge pull request #3 from lelicopter/master Bug correction (parse cmd options)
2016-01-07 rocky <rb@dustyfeet.com>
* test/Makefile, test/bytecompile-tests, test/test_pythonlib.py: Add
Python 3.5 tests that we can do.
2016-01-05 R. Bernstein <rocky@users.noreply.github.com>
* HISTORY.md: Grammar fixes
2016-01-02 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, __pkginfo__.py: Get ready for release 2.1.3
2016-01-02 rocky <rb@dustyfeet.com>
* uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_25.py,
uncompyle6/opcodes/opcode_26.py, uncompyle6/opcodes/opcode_27.py,
uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py,
uncompyle6/opcodes/opcode_34.py, uncompyle6/opcodes/opcode_35.py,
uncompyle6/opcodes/opcode_3x.py, uncompyle6/parser.py,
uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py,
uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py,
uncompyle6/scanners/scanner35.py: Start to DRY opcode code. Limited
support for decopyling Python 3.5
2016-01-02 rocky <rb@dustyfeet.com>
* test/Makefile, test/ok_lib3.4/antigravity.py,
test/ok_lib3.4/bisect.py, test/test_pythonlib.py: Start 3.4 library
verify tests
2016-01-02 rocky <rb@dustyfeet.com>
* README.rst: Regularize spelling of bytecode
2016-01-02 rocky <rb@dustyfeet.com>
* Makefile, README.rst: Add download shield. Add check-rst target
2016-01-02 R. Bernstein <rocky@users.noreply.github.com>
* README.rst: Update README.rst
2016-01-02 rocky <rb@dustyfeet.com>
* uncompyle6/semantics/fragments.py: Track recent source class
semantic actions in fragment actions
2016-01-02 rocky <rb@dustyfeet.com>
* uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py,
uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py:
Make ScannerXX() initialization the same on Python 2.x and 3.x
2016-01-02 rocky <rb@dustyfeet.com>
* test/Makefile,
test/simple_source/comprehension/05_list_comprehension.py,
test/simple_source/def/02_closure.py, test/test_pythonlib.py,
uncompyle6/main.py, uncompyle6/verify.py: Verify 3.4 bytecode.
verify API call bug fixed.
2016-01-02 rocky <rb@dustyfeet.com>
* test/simple_source/def/05_class.py, uncompyle6/load.py,
uncompyle6/main.py, uncompyle6/parsers/parse3.py,
uncompyle6/semantics/pysource.py: Python 3 class deparsing. stop
earlier in uncompyle6 on a syntax error.
2016-01-01 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner3.py: Fix make_closure compilation from
2.x of 3.3 bytecode
2016-01-01 rocky <rb@dustyfeet.com>
* test/simple_source/def/02_closure.py,
uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Work
on MAKE_CLOSURE rules for Python 3.3
2015-12-31 rocky <rb@dustyfeet.com>
* __pkginfo__.py: Get ready for release 2.1.2
* uncompyle6/semantics/fragments.py: track source deparsing
superclass bug fix
2015-12-31 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, __pkginfo__.py: Get ready for release 2.1.2
2015-12-31 rocky <rb@dustyfeet.com>

View File

@@ -30,7 +30,7 @@ The last mention of a release of SPARK from John is around 2002.
In the fall of 2000, Hartmut Goebel
[took over maintaining the code](https://groups.google.com/forum/#!searchin/comp.lang.python/hartmut$20goebel/comp.lang.python/35s3mp4-nuY/UZALti6ujnQJ). The
first subsequennt public release announcement that I can find is
first subsequent public release announcement that I can find is
["decompyle - A byte-code-decompiler version 2.2 beta 1"](https://mail.python.org/pipermail/python-announce-list/2002-February/001272.html).
From the CHANGES file found in
@@ -38,9 +38,8 @@ From the CHANGES file found in
it appears that Hartmut did most of the work to get this code to
accept the full Python language. He added precidence to the table
specifiers, support for multiple versions of Python, the
pretty-printing of docstrings, lists and hashes. He also wrote
extensive tests and routines to the testing and verification of
decompiled bytecode.
pretty-printing of docstrings, lists, and hashes. He also wrote test and verification routines of
deparsed bytecode, and used this in an extensive set of tests that he also wrote. He could verify against the entire Python library.
decompyle2.2 was packaged for Debian (sarge) by
[Ben Burton around 2002](https://packages.qa.debian.org/d/decompyle.html). As
@@ -91,10 +90,6 @@ Hartmut a decade an a half ago:
NB. This is not a masterpiece of software, but became more like a hack.
Probably a complete rewrite would be sensefull. hG/2000-12-27
One of the attempts to modernize it and make it available for Python3
is [the one by Anton Vorobyov (DarkFenX)](https://github.com/DarkFenX/uncompyle3). I've
followed some of the ideas there in this project.
Lastly, I should mention [unpyc](https://code.google.com/p/unpyc3/)
and most especially [pycdc](https://github.com/zrax/pycdc), largely by
Michael Hansen and Darryl Pogue. If they supported getting source-code

View File

@@ -1,6 +1,7 @@
include README.rst
include HISTORY.md
include ChangeLog
include HISTORY.md
include LICENSE
include __pkginfo__.py
recursive-include uncompyle6 *.py
include bin/uncompyle6

View File

@@ -28,7 +28,7 @@ check-2.7 check-3.3 check-3.4: pytest
$(MAKE) -C test $@
#: Tests for Python 3.5 - pytest doesn't work here
check-3.5:
check-3.2 check-3.5:
$(MAKE) -C test $@
#:Tests for Python 2.6 (doesn't have pytest)
@@ -60,6 +60,11 @@ sdist:
#: Style check. Set env var LINT to pyflakes, flake, or flake8
lint: flake8
# Check StructuredText long description formatting
check-rst:
$(PYTHON) setup.py --long-description | rst2html.py > python3-trepan.html
#: Lint program
flake8:
$(LINT) uncompyle6

49
NEWS
View File

@@ -1,3 +1,52 @@
uncompyle6 2.3.4 2016-05-5
- More Python 3.5 parsing bugs addressed
- decompiling Python 3.5 from other Python versions works
- test from Python 3.2
- remove "__module__ = __name__" in 3.0 <= Python 3.2
uncompyle6 2.3.3 2016-05-3
- Fix bug in running uncompyle6 script on Python 3
- Speed up performance on deparsing long lists by grouping in chunks of 32 and 256 items
- DRY Python expressions between Python 2 and 3
uncompyle6 2.3.2 2016-05-1
- Add --version option standalone scripts
- Correct License information in package
- expose fns uncompyle_file, load_file, and load_module
- Start to DRY Python2 and Python3 grammars Separate out 3.2, and 3.5+
specific grammar code
- Fix bug in 3.5+ constant map parsing
uncompyle6 2.3.0, 2.3.1 2016-04-30
- Require spark_parser >= 1.1.0
uncompyle6 2.2.0 2016-04-30
- Spark is no longer here but pulled separate package spark_parse
- Python 3 parsing fixes
- More tests
uncompyle6 2.2.0 2016-04-02
- Support single-mode (in addtion to exec-mode) compilation
- Start to DRY Python 2 and Python 3 grammars
- Fix bug in if else ternary construct
- Fix bug in uncomplye6 -d and -r options (via lelicopter)
uncompyle6 2.1.3 2016-01-02
- Limited support for decompiling Python 3.5
- Improve Python 3 class deparsing
- Handle MAKE_CLOSURE opcode
- Start to DRY opcode code.
- increase test coverage
- fix misc small bugs and some improvements
uncompyle6 2.1.2 2015-12-31
- Fix cross-version Marshal loading

View File

@@ -3,28 +3,33 @@
uncompyle6
==========
A native Python Byte-code Disassembler, Decompiler, Fragment Decompiler
and byte-code library
A native Python bytecode Disassembler, Decompiler, Fragment Decompiler
and bytecode library. Follows in the tradition of decompyle, uncompyle, and uncompyle2.
Introduction
------------
*uncompyle6* translates Python byte-code back into equivalent Python
source code. It accepts byte-codes from Python version 2.5 to 3.4 or
so and has been tested on Python running versions 2.6, 2.7, 3.3,
3.4 and 3.5.
*uncompyle6* translates Python bytecode back into equivalent Python
source code. It accepts bytecodes from Python version 2.5 to 3.4 or
so. The code requires Python 2.6 or later and has been tested on Python
running versions 2.6, 2.7, 3.3, 3.4 and 3.5.
Why this?
---------
What makes this different other CPython byte-code decompilers? Its
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
forks around. All of them come basically from the same code base, and
almost all of them not maintained very well. This code pulls these together
and addresses a number of open issues in those.
What makes this different from other CPython bytecode decompilers? Its
ability to deparse just fragments and give source-code information
around a given bytecode offset.
I using this to deparse fragments of code inside my trepan_
I use this to deparse fragments of code inside my trepan_
debuggers_. For that, I need to record text fragments for all
byte-code offsets (of interest). This purpose although largely
bytecode offsets (of interest). This purpose although largely
compatible with the original intention is yet a little bit different.
See this_ for more information.
@@ -37,7 +42,7 @@ information.
Other parts of the library can be used inside Python for various
bytecode-related tasks. For example you can read in bytecode,
i.e. perform a version-independent `marshal.loads()`, and disassemble
the bytecode using version of Python different from the one used to
the bytecode using a version of Python different from the one used to
compile the bytecode.
@@ -48,6 +53,8 @@ This uses setup.py, so it follows the standard Python routine:
::
pip install -r requirements.txt
pip install -r requirements-dev.txt
python setup.py install # may need sudo
# or if you have pyenv:
python setup.py develop
@@ -77,27 +84,28 @@ Run
::
./bin/uncompyle6 -h
./bin/pydisassemble -y
./bin/pydisassemble -h
for usage help
for usage help.
Known Bugs/Restrictions
-----------------------
Python 2 deparsing is probably as solid as the various versions of
uncompyle2. Python 3 deparsing is okay but not as solid.
uncompyle2. Python 3 deparsing is okay but not as solid. Python 3.5 is missing some of new opcodes added, but still often works.
See Also
--------
* https://github.com/zrax/pycdc
* https://github.com/Mysterie/uncompyle2
* https://github.com/DarkFenX/uncompyle3
* https://code.google.com/p/unpyc3/
* https://github.com/zrax/pycdc : supports all versions of Python and is written in C++
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only
The above projects use a different decompiling technique what is used here.
The HISTORY file.
.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg
.. _trepan: https://pypi.python.org/pypi/trepan
.. _debuggers: https://pypi.python.org/pypi/trepan3k
.. _remake: https://bashdb.sf.net/remake

View File

@@ -9,13 +9,20 @@
# Things that change more often go here.
copyright = """
Copyright (C) 2015 Rocky Bernstein <rb@dustyfeet.com>.
Copyright (C) 2015, 2016 Rocky Bernstein <rb@dustyfeet.com>.
"""
classifiers = ['Development Status :: 3 - Alpha',
classifiers = ['Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Debuggers',
'Topic :: Software Development :: Libraries :: Python Modules',
]
@@ -24,7 +31,10 @@ classifiers = ['Development Status :: 3 - Alpha',
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
author_email = "rb@dustyfeet.com"
ftp_url = None
# license = 'BSDish'
install_requires = ['spark-parser >= 1.1.1']
license = 'GPL'
license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'
packages = ['uncompyle6', 'uncompyle6.opcodes', 'uncompyle6.semantics', 'uncompyle6.scanners', 'uncompyle6.parsers']
@@ -40,7 +50,6 @@ def get_srcdir():
return os.path.realpath(filename)
ns = {}
version = '2.1.2'
web = 'https://github.com/rocky/python-uncompyle6/'
# tracebacks in zip files are funky and not debuggable

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
# Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com>
#
from __future__ import print_function
import sys, os, getopt
@@ -9,7 +9,9 @@ import sys, os, getopt
program = os.path.basename(__file__)
__doc__ = """
Usage: %s [OPTIONS]... FILE
Usage:
%s [OPTIONS]... FILE
%s [--help | -h | -V | --version]
Examples:
%s foo.pyc
@@ -24,7 +26,7 @@ Options:
<path>
--help show this message
""" % ((program,) * 5)
""" % ((program,) * 6)
Usage_short = \
@@ -32,6 +34,7 @@ Usage_short = \
from uncompyle6 import check_python_version
from uncompyle6.disas import disassemble_files
from uncompyle6.version import VERSION
check_python_version(program)
@@ -40,7 +43,7 @@ out_base = None
try:
opts, files = getopt.getopt(sys.argv[1:], 'ho:', ['help'])
opts, files = getopt.getopt(sys.argv[1:], 'hVo:', ['help', 'version'])
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
sys.exit(-1)
@@ -48,6 +51,9 @@ except getopt.GetoptError as e:
for opt, val in opts:
if opt in ('-h', '--help'):
print(__doc__)
sys.exit(1)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
sys.exit(0)
elif opt == '-o':
outfile = val

View File

@@ -1,16 +1,23 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015-2016 by Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2015 by Rocky Bernstein
#
from __future__ import print_function
import sys, os, getopt, time
"""
Usage: uncompyle6 [OPTIONS]... [ FILE | DIR]...
program = os.path.basename(__file__)
__doc__ = """
Usage:
%s [OPTIONS]... [ FILE | DIR]...
%s [--help | -h | --V | --version]
Examples:
uncompyle6 foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
uncompyle6 -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
uncompyle6 -o /tmp /usr/lib/python1.5 # decompile whole library
%s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
%s -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
%s -o /tmp /usr/lib/python1.5 # decompile whole library
Options:
-o <path> output decompiled files to this path:
@@ -34,26 +41,25 @@ Options:
Debugging Options:
--asm -a include byte-code (disables --verify)
--grammar -g show matching grammar
--treee -t include syntax tree (disables --verify)
--tree -t include syntax tree (disables --verify)
Extensions of generated files:
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
+ '_unverified' successfully decompile but --verify failed
+ '_failed' decompile failed (contact author for enhancement)
"""
from __future__ import print_function
import sys, os, getopt, time
""" % ((program,) * 5)
program = os.path.basename(__file__)
from uncompyle6 import verify, check_python_version
from uncompyle6.main import main, status_msg
from uncompyle6.version import VERSION
def usage():
print("""usage:
%s [--help] [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
""" % program)
%s [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
%s [--help | -h | --version | -V]
""" % (program, program))
sys.exit(1)
@@ -68,8 +74,8 @@ timestamp = False
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
try:
opts, files = getopt.getopt(sys.argv[1:], 'hagtdro:c:p:',
'help asm grammar recurse timestamp tree verify '
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar recurse timestamp tree verify version '
'showgrammar'.split(' '))
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
@@ -80,6 +86,9 @@ for opt, val in opts:
if opt in ('-h', '--help'):
print(__doc__)
sys.exit(0)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
sys.exit(0)
elif opt == '--verify':
options['do_verify'] = True
elif opt in ('--asm', '-a'):
@@ -92,13 +101,13 @@ for opt, val in opts:
options['showgrammar'] = True
elif opt == '-o':
outfile = val
elif opt == ('--timestamp', '-d'):
elif opt in ('--timestamp', '-d'):
timestamp = True
elif opt == '-c':
codes.append(val)
elif opt == '-p':
numproc = int(val)
elif opt == ('--recurse', '-r'):
elif opt in ('--recurse', '-r'):
recurse_dirs = True
else:
print(opt, file=sys.stderr)

View File

@@ -6,7 +6,8 @@ machine:
dependencies:
override:
- pip install -r test-requirements.txt
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
test:
override:
- python ./setup.py develop && make check-2.7

View File

@@ -0,0 +1,21 @@
import pytest
from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code
def test_single_mode():
single_expressions = (
'i = 1',
'i and (j or k)',
'i += 1',
'i = j % 4',
'i = {}',
'i = []',
'while i < 1 or stop:\n i\n',
'while i < 1 or stop:\n print%s\n' % ('(i)' if PYTHON3 else ' i'),
'for i in range(10):\n i\n',
'for i in range(10):\n for j in range(10):\n i + j\n',
'try:\n i\nexcept Exception:\n j\nelse:\n k\n'
)
for expr in single_expressions:
code = compile(expr + '\n', '<string>', 'single')
assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n'

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
spark-parser >= 1.1.1

View File

@@ -6,3 +6,6 @@ doc_files = README
# USAGE.txt
# doc/
# examples/
[bdist_wheel]
universal=1

View File

@@ -1,32 +1,25 @@
#! python
#!/usr/bin/env python
"""Setup script for the 'uncompyle6' distribution."""
from distutils.core import setup, Extension
# Get the package information used in setup().
# from __pkginfo__ import \
# author, author_email, classifiers, \
# install_requires, license, long_description, \
# modname, packages, py_modules, \
# short_desc, version, web, zip_safe
from __pkginfo__ import \
author, author_email, \
long_description, \
author, author_email, install_requires, \
license, long_description, classifiers, \
modname, packages, py_modules, scripts, \
short_desc, version, web, zip_safe
short_desc, web, zip_safe
__import__('pkg_resources')
from setuptools import setup
exec(open('uncompyle6/version.py').read())
setup(
author = author,
author_email = author_email,
# classifiers = classifiers,
classifiers = classifiers,
description = short_desc,
# install_requires = install_requires,
# license = license,
install_requires = install_requires,
license = license,
long_description = long_description,
py_modules = py_modules,
name = modname,
@@ -35,5 +28,5 @@ setup(
url = web,
setup_requires = ['nose>=1.0'],
scripts = scripts,
version = version,
version = VERSION,
zip_safe = zip_safe)

View File

@@ -1 +0,0 @@
pytest

View File

@@ -20,7 +20,11 @@ check:
$(MAKE) check-$$PYTHON_VERSION
#: Run working tests from Python 2.6 or 2.7
check-2.6 check-2.7: check-bytecode check-2.7-ok
check-2.6 check-2.7: check-bytecode-sans-3.5 check-2.7-ok
#: Run working tests from Python 3.2
check-3.2: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.2 --verify $(COMPILE)
#: Run working tests from Python 3.3
check-3.3: check-bytecode
@@ -30,7 +34,8 @@ check-3.3: check-bytecode
check-3.5: check-bytecode
#: Run working tests from Python 3.4
check-3.4: check-bytecode check-2.7-ok
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
$(PYTHON) test_pythonlib.py --bytecode-3.4 --verify $(COMPILE)
#: Check deparsing only, but from a different Python version
check-disasm:
@@ -42,6 +47,11 @@ check-bytecode-2:
#: Check deparsing bytecode only
check-bytecode:
$(PYTHON) test_pythonlib.py --bytecode-2.5 --bytecode-2.6 --bytecode-2.7 \
--bytecode-3.2 --bytecode-3.3 --bytecode-3.4 --bytecode-3.5
#: Check deparsing bytecode only
check-bytecode-sans-3.5:
$(PYTHON) test_pythonlib.py --bytecode-2.5 --bytecode-2.6 --bytecode-2.7 \
--bytecode-3.2 --bytecode-3.3 --bytecode-3.4
@@ -69,6 +79,10 @@ check-bytecode-3.3:
check-bytecode-3.4:
$(PYTHON) test_pythonlib.py --bytecode-3.4
#: Check deparsing Python 3.5
check-bytecode-3.5:
$(PYTHON) test_pythonlib.py --bytecode-3.5
#: short tests for bytecodes only for this version of Python
check-native-short:
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --verify $(COMPILE)
@@ -77,6 +91,14 @@ check-native-short:
check-2.7-ok:
$(PYTHON) test_pythonlib.py --ok-2.7 --verify $(COMPILE)
#: Run longer Python 3.2's lib files known to be okay
check-3.2-ok:
$(PYTHON) test_pythonlib.py --ok-3.2 --verify $(COMPILE)
#: Run longer Python 3.4's lib files known to be okay
check-3.4-ok:
$(PYTHON) test_pythonlib.py --ok-3.4 --verify $(COMPILE)
clean: clean-py-dis clean-dis clean-unverified
clean-dis:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
test/bytecode_3.5/05_if.pyc Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -70,7 +70,8 @@ for root, dirs, basenames in os.walk('simple_source'):
simple_source.append(os.path.join(root, basename)[0:-3])
pass
tests['2.6'] = tests['2.7'] = tests['3.2'] = tests['3.3'] = tests['3.4'] = simple_source
tests['2.6'] = tests['2.7'] = tests['3.2'] = \
tests['3.3'] = tests['3.4'] = tests['3.5'] = simple_source
total_tests = len(tests['2.7'])
#tests['2.2'].sort(); print tests['2.2']

BIN
test/ok_lib2.7/_abcoll.pyc Normal file

Binary file not shown.

BIN
test/ok_lib2.7/_abcoll.pyo Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,17 @@
import webbrowser
import hashlib
webbrowser.open("http://xkcd.com/353/")
def geohash(latitude, longitude, datedow):
'''Compute geohash() using the Munroe algorithm.
>>> geohash(37.421542, -122.085589, b'2005-05-26-10458.68')
37.857713 -122.544543
'''
# http://xkcd.com/426/
h = hashlib.md5(datedow).hexdigest()
p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))

Binary file not shown.

92
test/ok_lib3.4/bisect.py Normal file
View File

@@ -0,0 +1,92 @@
"""Bisection algorithms."""
def insort_right(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the right of the rightmost x.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
a.insert(lo, x)
insort = insort_right # backward compatibility
def bisect_right(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e <= x, and all e in
a[i:] have e > x. So if x already appears in the list, a.insert(x) will
insert just after the rightmost x already there.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
return lo
bisect = bisect_right # backward compatibility
def insort_left(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the left of the leftmost x.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] < x: lo = mid+1
else: hi = mid
a.insert(lo, x)
def bisect_left(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e < x, and all e in
a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
insert just before the leftmost x already there.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] < x: lo = mid+1
else: hi = mid
return lo
# Overwrite above definitions with a fast C implementation
try:
from _bisect import *
except ImportError:
pass

BIN
test/ok_lib3.4/bisect.pyc Normal file

Binary file not shown.

View File

@@ -0,0 +1,11 @@
# Tests:
# ret_expr_or_cond ::= ret_expr
# ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
# ret_expr_or_cond ::= ret_cond
# ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
# See https://github.com/rocky/python-uncompyle6/issues/5
def minimize(x, y):
return x or (x if x < y else y)

View File

@@ -19,4 +19,4 @@
# list_for ::= expr _for designator list_iter JUMP_BACK
# list_iter ::= lc_body
# lc_body ::= expr LIST_APPEND
[ i * j for i in range(4) for j in range(7) ]
# [ i * j for i in range(4) for j in range(7) ]

View File

@@ -0,0 +1,19 @@
# Tests
# Python3:
# funcdef ::= mkfunc designator
# designator ::= STORE_DEREF
# mkfunc ::= load_closure BUILD_TUPLE_1 LOAD_CONST LOAD_CONST MAKE_CLOSURE_0
# load_closure ::= LOAD_CLOSURE
#
# Python2:
# funcdef ::= mkfunc designator
# designator ::= STORE_DEREF
# mkfunc ::= load_closure LOAD_CONST MAKE_CLOSURE_0
# load_closure ::= LOAD_CLOSURE
def bug():
def convert(node):
return node and convert(node.left)
return

View File

@@ -0,0 +1,14 @@
# Python3.5 bug from abc.py:
# stmt ::= LOAD_CLOSURE RETURN_VALUE RETURN_LAST
#
# And this gets ignored.
# Note this is similar to 06_classbug.py but not the same.
# classmethod -> object
class abstractclassmethod(classmethod):
__isabstractmethod__ = True
def __init__(self, callable):
callable.__isabstractmethod__ = True
super().__init__(callable)

View File

@@ -11,3 +11,7 @@
import io
class BZ2File(io.BufferedIOBase):
pass
class ABC(metaclass=BZ2File):
pass

View File

@@ -0,0 +1,16 @@
# Python 3.2 Bug from abc.py
# Make sure we handle:
# LOAD_FAST '__locals__'
# STORE_LOCALS ''
# Note this is similar to 05_abc_class.py but not the same:
# object -> classmethod
class abstractclassmethod(object):
"""A Python 3.2 STORE_LOCALS bug
"""
def __init__(self, callable):
callable.__isabstractmethod__ = True

View File

@@ -0,0 +1,7 @@
# Addresses a bug in the way Python 3.5+ handles
# creation of map constants
opts = {'highlight': True,
'start_line': -1,
'end_line': None
}
print(opts)

View File

@@ -0,0 +1,3 @@
# Long lists pose a slowdown in uncompiling.
x = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
print(x)

View File

@@ -0,0 +1,2 @@
with (sys) as f:
print(f)

View File

@@ -55,22 +55,31 @@ PYO = ('*.pyo', )
PYOC = ('*.pyc', '*.pyo')
test_options = {
# name: (src_basedir, pattern, output_base_suffix, pythoin_version)
# name: (src_basedir, pattern, output_base_suffix, python_version)
'test':
('test', PYC, 'test'),
'ok-2.6':
(os.path.join(src_dir, 'ok_2.6'),
PYC, 'ok-2.6', 2.6),
PYOC, 'ok-2.6', 2.6),
'ok-2.7': (os.path.join(src_dir, 'ok_lib2.7'),
PYC, 'ok-2.7', 2.7),
PYOC, 'ok-2.7', 2.7),
'ok-3.2': (os.path.join(src_dir, 'ok_lib3.2'),
PYOC, 'ok-3.2', 3.5),
'base-2.7': (os.path.join(src_dir, 'base_tests', 'python2.7'),
PYC, 'base_2.7', 2.7),
PYOC, 'base_2.7', 2.7),
}
for vers in (2.5, 2.6, 2.7, 3.2, 3.3, 3.4):
for vers in (2.7, 3.4, 3.5):
pythonlib = "ok_lib%s" % vers
key = "ok-%s" % vers
test_options[key] = (os.path.join(src_dir, pythonlib), PYOC, key, vers)
pass
for vers in (2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5):
bytecode = "bytecode_%s" % vers
key = "bytecode-%s" % vers
test_options[key] = (bytecode, PYC, bytecode, vers)
@@ -78,7 +87,7 @@ for vers in (2.5, 2.6, 2.7, 3.2, 3.3, 3.4):
pythonlib = "python%s" % vers
if vers >= 3.0:
pythonlib = os.path.join(pythonlib, '__pycache__')
test_options[key] = (os.path.join(lib_prefix, pythonlib), PYC, pythonlib, vers)
test_options[key] = (os.path.join(lib_prefix, pythonlib), PYOC, pythonlib, vers)
#-----
@@ -93,7 +102,6 @@ def help():
# decompile and verify known good python 2.7
test_pythonlib.py --ok-2.7 --verify
""")
sys.exit(1)

View File

@@ -30,13 +30,15 @@ from __future__ import print_function
import sys
__docformat__ = 'restructuredtext'
PYTHON3 = (sys.version_info >= (3, 0))
# We do this crazy way to support Python 2.6 which
# doesn't support version_major, and has a bug in
# floating point so we can't divide 26 by 10 and get
# 2.6
PYTHON_VERSION = sys.version_info[0]+ (sys.version_info[1] / 10.0)
PYTHON_VERSION = sys.version_info[0] + (sys.version_info[1] / 10.0)
PYTHON_VERSION_STR = "%s.%s" % (sys.version_info[0], sys.version_info[1])
sys.setrecursionlimit(5000)
@@ -50,6 +52,11 @@ def check_python_version(program):
import uncompyle6.semantics.pysource
import uncompyle6.semantics.fragments
import uncompyle6.load
# Export some functions
from uncompyle6.load import load_module, load_file
from uncompyle6.main import uncompyle_file
# Conventience functions so you can say:
# from uncompyle6 import deparse_code

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2015 by Rocky Bernstein
# Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
from __future__ import print_function
import imp, marshal, os, py_compile, sys, tempfile
@@ -26,7 +26,7 @@ def check_object_path(path):
spath = path if PYTHON3 else path.decode('utf-8')
path = tempfile.mkstemp(prefix=basename + '-',
suffix='.pyc', text=False)[1]
py_compile.compile(spath, cfile=path)
py_compile.compile(spath, cfile=path, doraise=True)
if not path.endswith(".pyc") and not path.endswith(".pyo"):
raise ValueError("path %s must point to a .py or .pyc file\n" %

View File

@@ -1,5 +1,5 @@
from __future__ import print_function
import datetime, inspect, os, sys
import datetime, os, sys
from uncompyle6 import verify, PYTHON_VERSION
from uncompyle6.code import iscode
@@ -57,9 +57,10 @@ def uncompyle_file(filename, outstream=None, showasm=False, showast=False,
timestamp, showgrammar, code_objects=code_objects)
co = None
# FIXME: combine into an options parameter
def main(in_base, out_base, files, codes, outfile=None,
showasm=False, showast=False, do_verify=False,
showgrammar=False):
showgrammar=False, raise_on_error=False):
"""
in_base base directory for input files
out_base base directory for output files (ignored when
@@ -108,7 +109,7 @@ def main(in_base, out_base, files, codes, outfile=None,
try:
uncompyle_file(infile, outstream, showasm, showast, showgrammar)
tot_files += 1
except ValueError as e:
except (ValueError, SyntaxError) as e:
sys.stderr.write("\n# %s" % e)
failed_files += 1
except KeyboardInterrupt:
@@ -117,14 +118,14 @@ def main(in_base, out_base, files, codes, outfile=None,
os.remove(outfile)
sys.stderr.write("\nLast file: %s " % (infile))
raise
except:
failed_files += 1
if outfile:
outstream.close()
os.rename(outfile, outfile + '_failed')
else:
sys.stderr.write("\n# %s" % sys.exc_info()[1])
sys.stderr.write("\n# Can't uncompile %s\n" % infile)
# except:
# failed_files += 1
# if outfile:
# outstream.close()
# os.rename(outfile, outfile + '_failed')
# else:
# sys.stderr.write("\n# %s" % sys.exc_info()[1])
# sys.stderr.write("\n# Can't uncompile %s\n" % infile)
else: # uncompile successful
if outfile:
outstream.close()
@@ -143,6 +144,8 @@ def main(in_base, out_base, files, codes, outfile=None,
if not outfile:
print("### Error Verifiying %s" % filename, file=sys.stderr)
print(e, file=sys.stderr)
if raise_on_error:
raise
pass
pass
pass

View File

@@ -18,7 +18,6 @@ from __future__ import print_function
import sys, types
from struct import unpack
import uncompyle6.scanners.scanner3 as scan3
from uncompyle6.magics import PYTHON_MAGIC_INT
from uncompyle6.code import Code3

View File

@@ -7,6 +7,8 @@ This is a superset of Python 2.3's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
# FIXME: DRY this along the lines of opcode_3x.
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')

View File

@@ -7,6 +7,8 @@ This is a superset of Python 2.5's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
# FIXME: DRY this along the lines of opcode_3x.
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')

View File

@@ -7,6 +7,8 @@ This is a superset of Python 3.4's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
# FIXME: DRY this along the lines of opcode_3x.
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')

View File

@@ -7,6 +7,8 @@ This is a superset of Python 3.4's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
# FIXME: DRY this along the lines of opcode_3x.
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')

View File

@@ -3,42 +3,27 @@ CPython 3.2 bytecode opcodes
This is used in scanner (bytecode disassembly) and parser (Python grammar).
This is a superset of Python 3.4's opcode.py with some opcodes that simplify
This is a superset of Python 3.2's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')
from copy import deepcopy
hasconst = []
hasname = []
hasjrel = []
hasjabs = []
haslocal = []
hascompare = []
hasfree = []
hasnargs = []
import uncompyle6.opcodes.opcode_3x as opcode_3x
from uncompyle6.opcodes.opcode_3x import fields2copy
# FIXME: can we DRY this even more?
opmap = {}
opname = [''] * 256
for op in range(256): opname[op] = '<%r>' % (op,)
del op
hasjrel = []
hasjabs = []
def def_op(name, op):
opname[op] = name
opmap[name] = op
for object in fields2copy:
globals()[object] = deepcopy(getattr(opcode_3x, object))
def name_op(name, op):
def_op(name, op)
hasname.append(op)
def jrel_op(name, op):
def_op(name, op)
hasjrel.append(op)
def jabs_op(name, op):
def_op(name, op)
hasjabs.append(op)
# There are no opcodes to add or change.
# If there were, they'd be listed below.
def updateGlobal():
# JUMP_OPs are used in verification are set in the scanner
@@ -50,165 +35,14 @@ def updateGlobal():
globals().update(dict([(k.replace('+', '_'), v) for (k, v) in opmap.items()]))
globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code
# Blank lines correspond to available opcodes
def_op('STOP_CODE', 0)
def_op('POP_TOP', 1)
def_op('ROT_TWO', 2)
def_op('ROT_THREE', 3)
def_op('DUP_TOP', 4)
def_op('DUP_TOP_TWO', 5)
def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10)
def_op('UNARY_NEGATIVE', 11)
def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15)
def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20)
def_op('BINARY_MODULO', 22)
def_op('BINARY_ADD', 23)
def_op('BINARY_SUBTRACT', 24)
def_op('BINARY_SUBSCR', 25)
def_op('BINARY_FLOOR_DIVIDE', 26)
def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29)
# Gone from Python 3 are Python2's
# SLICE+0 .. SLICE+3
# STORE_SLICE+0 .. STORE_SLICE+3
# DELETE_SLICE+0 .. DELETE_SLICE+3
def_op('STORE_MAP', 54)
def_op('INPLACE_ADD', 55)
def_op('INPLACE_SUBTRACT', 56)
def_op('INPLACE_MULTIPLY', 57)
def_op('INPLACE_MODULO', 59)
def_op('STORE_SUBSCR', 60)
def_op('DELETE_SUBSCR', 61)
def_op('BINARY_LSHIFT', 62)
def_op('BINARY_RSHIFT', 63)
def_op('BINARY_AND', 64)
def_op('BINARY_XOR', 65)
def_op('BINARY_OR', 66)
def_op('INPLACE_POWER', 67)
def_op('GET_ITER', 68)
def_op('STORE_LOCALS', 69)
def_op('PRINT_EXPR', 70)
def_op('LOAD_BUILD_CLASS', 71)
# Python3 drops/changes:
# def_op('PRINT_ITEM', 71)
# def_op('PRINT_NEWLINE', 72)
# def_op('PRINT_ITEM_TO', 73)
# def_op('PRINT_NEWLINE_TO', 74)
def_op('INPLACE_LSHIFT', 75)
def_op('INPLACE_RSHIFT', 76)
def_op('INPLACE_AND', 77)
def_op('INPLACE_XOR', 78)
def_op('INPLACE_OR', 79)
def_op('BREAK_LOOP', 80)
def_op('WITH_CLEANUP', 81)
def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84)
def_op('YIELD_VALUE', 86)
def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88)
def_op('POP_EXCEPT', 89)
HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
name_op('STORE_NAME', 90) # Index in name list
name_op('DELETE_NAME', 91) # ""
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
jrel_op('FOR_ITER', 93)
def_op('UNPACK_EX', 94)
name_op('STORE_ATTR', 95) # Index in name list
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""
# Python 2's DUP_TOPX is gone
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
def_op('BUILD_TUPLE', 102) # Number of tuple items
def_op('BUILD_LIST', 103) # Number of list items
def_op('BUILD_SET', 104) # Number of set items
def_op('BUILD_MAP', 105) # Number of dict entries (upto 255)
name_op('LOAD_ATTR', 106) # Index in name list
def_op('COMPARE_OP', 107) # Comparison operator
hascompare.append(107)
name_op('IMPORT_NAME', 108) # Index in name list
name_op('IMPORT_FROM', 109) # Index in name list
jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
jabs_op('JUMP_ABSOLUTE', 113) # ""
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
name_op('LOAD_GLOBAL', 116) # Index in name list
jabs_op('CONTINUE_LOOP', 119) # Target address
jrel_op('SETUP_LOOP', 120) # Distance to target address
jrel_op('SETUP_EXCEPT', 121) # ""
jrel_op('SETUP_FINALLY', 122) # ""
def_op('LOAD_FAST', 124) # Local variable number
haslocal.append(124)
def_op('STORE_FAST', 125) # Local variable number
haslocal.append(125)
def_op('DELETE_FAST', 126) # Local variable number
haslocal.append(126)
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
hasnargs.append(131)
def_op('MAKE_FUNCTION', 132) # Number of args with default values
def_op('BUILD_SLICE', 133) # Number of items
def_op('MAKE_CLOSURE', 134)
def_op('LOAD_CLOSURE', 135)
hasfree.append(135)
def_op('LOAD_DEREF', 136)
hasfree.append(136)
def_op('STORE_DEREF', 137)
hasfree.append(137)
def_op('DELETE_DEREF', 138)
hasfree.append(138)
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
hasnargs.append(140)
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
hasnargs.append(141)
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
hasnargs.append(142)
jrel_op('SETUP_WITH', 143)
def_op('LIST_APPEND', 145)
def_op('SET_ADD', 146)
def_op('MAP_ADD', 147)
def_op('EXTENDED_ARG', 144)
EXTENDED_ARG = 144
updateGlobal()
del def_op, name_op, jrel_op, jabs_op
from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION == 3.2:
import dis
# for item in dis.opmap.items():
# if item not in opmap.items():
# print(item)
assert all(item in opmap.items() for item in dis.opmap.items())
# opcode_3x.dump_opcodes(opmap)

View File

@@ -7,37 +7,31 @@ This is a superset of Python 3.3's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')
from copy import deepcopy
hasconst = []
hasname = []
hasjrel = []
hasjabs = []
haslocal = []
hascompare = []
hasfree = []
import uncompyle6.opcodes.opcode_3x as opcode_3x
from uncompyle6.opcodes.opcode_3x import fields2copy, rm_op
# FIXME: can we DRY this even more?
opmap = {}
opname = [''] * 256
for op in range(256): opname[op] = '<%r>' % (op,)
del op
hasconst = []
hasjrel = []
hasjabs = []
def def_op(name, op):
opname[op] = name
opmap[name] = op
def name_op(name, op):
def_op(name, op)
hasname.append(op)
for object in fields2copy:
globals()[object] = deepcopy(getattr(opcode_3x, object))
def jrel_op(name, op):
def_op(name, op)
hasjrel.append(op)
# Below are opcodes since Python 3.2
def jabs_op(name, op):
def_op(name, op)
hasjabs.append(op)
rm_op(opname, opmap, 'STOP_CODE', 0)
def_op('YIELD_FROM', 72)
def updateGlobal():
# JUMP_OPs are used in verification are set in the scanner
@@ -49,156 +43,9 @@ def updateGlobal():
globals().update(dict([(k.replace('+', '_'), v) for (k, v) in opmap.items()]))
globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code
# Blank lines correspond to available opcodes
def_op('STOP_CODE', 0)
def_op('POP_TOP', 1)
def_op('ROT_TWO', 2)
def_op('ROT_THREE', 3)
def_op('DUP_TOP', 4)
def_op('DUP_TOP_TWO', 5)
def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10)
def_op('UNARY_NEGATIVE', 11)
def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15)
def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20)
def_op('BINARY_MODULO', 22)
def_op('BINARY_ADD', 23)
def_op('BINARY_SUBTRACT', 24)
def_op('BINARY_SUBSCR', 25)
def_op('BINARY_FLOOR_DIVIDE', 26)
def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29)
# Gone from Python 3 are
# Python 2's SLICE+0 .. SLICE+3
def_op('STORE_MAP', 54)
def_op('INPLACE_ADD', 55)
def_op('INPLACE_SUBTRACT', 56)
def_op('INPLACE_MULTIPLY', 57)
def_op('INPLACE_MODULO', 59)
def_op('STORE_SUBSCR', 60)
def_op('DELETE_SUBSCR', 61)
def_op('BINARY_LSHIFT', 62)
def_op('BINARY_RSHIFT', 63)
def_op('BINARY_AND', 64)
def_op('BINARY_XOR', 65)
def_op('BINARY_OR', 66)
def_op('INPLACE_POWER', 67)
def_op('GET_ITER', 68)
def_op('STORE_LOCALS', 69)
def_op('PRINT_EXPR', 70)
def_op('LOAD_BUILD_CLASS', 71)
# Python3 drops/changes:
# def_op('PRINT_ITEM', 71)
# def_op('PRINT_NEWLINE', 72)
def_op('YIELD_FROM', 72)
# def_op('PRINT_ITEM_TO', 73)
# def_op('PRINT_NEWLINE_TO', 74)
def_op('INPLACE_LSHIFT', 75)
def_op('INPLACE_RSHIFT', 76)
def_op('INPLACE_AND', 77)
def_op('INPLACE_XOR', 78)
def_op('INPLACE_OR', 79)
def_op('BREAK_LOOP', 80)
def_op('WITH_CLEANUP', 81)
def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84)
def_op('YIELD_VALUE', 86)
def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88)
def_op('POP_EXCEPT', 89)
HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
name_op('STORE_NAME', 90) # Index in name list
name_op('DELETE_NAME', 91) # ""
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
jrel_op('FOR_ITER', 93)
def_op('UNPACK_EX', 94)
name_op('STORE_ATTR', 95) # Index in name list
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
def_op('BUILD_TUPLE', 102) # Number of tuple items
def_op('BUILD_LIST', 103) # Number of list items
def_op('BUILD_SET', 104) # Number of set items
def_op('BUILD_MAP', 105) # Number of dict entries (upto 255)
name_op('LOAD_ATTR', 106) # Index in name list
def_op('COMPARE_OP', 107) # Comparison operator
hascompare.append(107)
name_op('IMPORT_NAME', 108) # Index in name list
name_op('IMPORT_FROM', 109) # Index in name list
jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
jabs_op('JUMP_ABSOLUTE', 113) # ""
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
name_op('LOAD_GLOBAL', 116) # Index in name list
jabs_op('CONTINUE_LOOP', 119) # Target address
jrel_op('SETUP_LOOP', 120) # Distance to target address
jrel_op('SETUP_EXCEPT', 121) # ""
jrel_op('SETUP_FINALLY', 122) # ""
def_op('LOAD_FAST', 124) # Local variable number
haslocal.append(124)
def_op('STORE_FAST', 125) # Local variable number
haslocal.append(125)
def_op('DELETE_FAST', 126) # Local variable number
haslocal.append(126)
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
def_op('MAKE_FUNCTION', 132) # Number of args with default values
def_op('BUILD_SLICE', 133) # Number of items
def_op('MAKE_CLOSURE', 134)
def_op('LOAD_CLOSURE', 135)
hasfree.append(135)
def_op('LOAD_DEREF', 136)
hasfree.append(136)
def_op('STORE_DEREF', 137)
hasfree.append(137)
def_op('DELETE_DEREF', 138)
hasfree.append(138)
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
jrel_op('SETUP_WITH', 143)
def_op('LIST_APPEND', 145)
def_op('SET_ADD', 146)
def_op('MAP_ADD', 147)
def_op('EXTENDED_ARG', 144)
EXTENDED_ARG = 144
updateGlobal()
del def_op, name_op, jrel_op, jabs_op
# FIXME: turn into pytest test
from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION == 3.3:
import dis
@@ -206,3 +53,5 @@ if PYTHON_VERSION == 3.3:
# if item not in opmap.items():
# print(item)
assert all(item in opmap.items() for item in dis.opmap.items())
# opcode3x.dump_opcodes(opmap)

View File

@@ -1,44 +1,41 @@
"""
CPython 3.4 bytecode opcodes
This is used in scanner (bytecode disassembly) and parser (Python grammar).
used in scanner (bytecode disassembly) and parser (Python grammar)
This is a superset of Python 3.4's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')
from copy import deepcopy
hasconst = []
hasname = []
hasjrel = []
hasjabs = []
haslocal = []
hascompare = []
hasfree = []
hasnargs = []
import uncompyle6.opcodes.opcode_3x as opcode_3x
from uncompyle6.opcodes.opcode_3x import fields2copy, hasfree, rm_op
# FIXME: can we DRY this even more?
opmap = {}
opname = [''] * 256
for op in range(256): opname[op] = '<%r>' % (op,)
del op
hasconst = []
hasjrel = []
hasjabs = []
def def_op(name, op):
opname[op] = name
opmap[name] = op
def name_op(name, op):
def_op(name, op)
hasname.append(op)
for object in fields2copy:
globals()[object] = deepcopy(getattr(opcode_3x, object))
def jrel_op(name, op):
def_op(name, op)
hasjrel.append(op)
# Below are opcodes changes since Python 3.2
def jabs_op(name, op):
def_op(name, op)
hasjabs.append(op)
rm_op(opname, opmap, 'STOP_CODE', 0)
rm_op(opname, opmap, 'STORE_LOCALS', 69)
# These are new since Python 3.3
def_op('YIELD_FROM', 72)
def_op('LOAD_CLASSDEREF', 148)
hasfree.append(148)
def updateGlobal():
# JUMP_OPs are used in verification are set in the scanner
@@ -50,171 +47,15 @@ def updateGlobal():
globals().update(dict([(k.replace('+', '_'), v) for (k, v) in opmap.items()]))
globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code
# Blank lines correspond to available opcodes
def_op('STOP_CODE', 0)
def_op('POP_TOP', 1)
def_op('ROT_TWO', 2)
def_op('ROT_THREE', 3)
def_op('DUP_TOP', 4)
def_op('DUP_TOP_TWO', 5)
def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10)
def_op('UNARY_NEGATIVE', 11)
def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15)
def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20)
def_op('BINARY_MODULO', 22)
def_op('BINARY_ADD', 23)
def_op('BINARY_SUBTRACT', 24)
def_op('BINARY_SUBSCR', 25)
def_op('BINARY_FLOOR_DIVIDE', 26)
def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29)
# Gone from Python 3 are Python2's
# SLICE+0 .. SLICE+3
# STORE_SLICE+0 .. STORE_SLICE+3
# DELETE_SLICE+0 .. DELETE_SLICE+3
def_op('STORE_MAP', 54)
def_op('INPLACE_ADD', 55)
def_op('INPLACE_SUBTRACT', 56)
def_op('INPLACE_MULTIPLY', 57)
def_op('INPLACE_MODULO', 59)
def_op('STORE_SUBSCR', 60)
def_op('DELETE_SUBSCR', 61)
def_op('BINARY_LSHIFT', 62)
def_op('BINARY_RSHIFT', 63)
def_op('BINARY_AND', 64)
def_op('BINARY_XOR', 65)
def_op('BINARY_OR', 66)
def_op('INPLACE_POWER', 67)
def_op('GET_ITER', 68)
# FIXME: no code generates this
def_op('STORE_LOCALS', 69)
def_op('PRINT_EXPR', 70)
def_op('LOAD_BUILD_CLASS', 71)
def_op('YIELD_FROM', 72)
# Python3 drops/changes:
# def_op('PRINT_ITEM', 71)
# def_op('PRINT_NEWLINE', 72)
# def_op('PRINT_ITEM_TO', 73)
# def_op('PRINT_NEWLINE_TO', 74)
def_op('INPLACE_LSHIFT', 75)
def_op('INPLACE_RSHIFT', 76)
def_op('INPLACE_AND', 77)
def_op('INPLACE_XOR', 78)
def_op('INPLACE_OR', 79)
def_op('BREAK_LOOP', 80)
def_op('WITH_CLEANUP', 81)
def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84)
def_op('YIELD_VALUE', 86)
def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88)
def_op('POP_EXCEPT', 89)
HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
name_op('STORE_NAME', 90) # Index in name list
name_op('DELETE_NAME', 91) # ""
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
jrel_op('FOR_ITER', 93)
def_op('UNPACK_EX', 94)
name_op('STORE_ATTR', 95) # Index in name list
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""
# Python 2's DUP_TOPX is gone
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
def_op('BUILD_TUPLE', 102) # Number of tuple items
def_op('BUILD_LIST', 103) # Number of list items
def_op('BUILD_SET', 104) # Number of set items
def_op('BUILD_MAP', 105) # Number of dict entries (upto 255)
name_op('LOAD_ATTR', 106) # Index in name list
def_op('COMPARE_OP', 107) # Comparison operator
hascompare.append(107)
name_op('IMPORT_NAME', 108) # Index in name list
name_op('IMPORT_FROM', 109) # Index in name list
jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
jabs_op('JUMP_ABSOLUTE', 113) # ""
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
name_op('LOAD_GLOBAL', 116) # Index in name list
jabs_op('CONTINUE_LOOP', 119) # Target address
jrel_op('SETUP_LOOP', 120) # Distance to target address
jrel_op('SETUP_EXCEPT', 121) # ""
jrel_op('SETUP_FINALLY', 122) # ""
def_op('LOAD_FAST', 124) # Local variable number
haslocal.append(124)
def_op('STORE_FAST', 125) # Local variable number
haslocal.append(125)
def_op('DELETE_FAST', 126) # Local variable number
haslocal.append(126)
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
hasnargs.append(131)
def_op('MAKE_FUNCTION', 132) # Number of args with default values
def_op('BUILD_SLICE', 133) # Number of items
def_op('MAKE_CLOSURE', 134)
def_op('LOAD_CLOSURE', 135)
hasfree.append(135)
def_op('LOAD_DEREF', 136)
hasfree.append(136)
def_op('STORE_DEREF', 137)
hasfree.append(137)
def_op('DELETE_DEREF', 138)
hasfree.append(138)
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
hasnargs.append(140)
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
hasnargs.append(141)
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
hasnargs.append(142)
jrel_op('SETUP_WITH', 143)
def_op('LIST_APPEND', 145)
def_op('SET_ADD', 146)
def_op('MAP_ADD', 147)
def_op('LOAD_CLASSDEREF', 148)
hasfree.append(148)
def_op('EXTENDED_ARG', 144)
EXTENDED_ARG = 144
updateGlobal()
del def_op, name_op, jrel_op, jabs_op
# FIXME: turn into pytest test
from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION == 3.4:
import dis
# for item in dis.opmap.items():
# if item not in opmap.items():
# print(item)
assert all(item in opmap.items() for item in dis.opmap.items())
# opcode_3x.dump_opcodes(opmap)

View File

@@ -0,0 +1,84 @@
# (C) Copyright 2016 by Rocky Bernstein
"""
CPython 3.5 bytecode opcodes
used in scanner (bytecode disassembly) and parser (Python grammar)
This is a superset of Python 3.5's opcode.py with some opcodes that simplify
parsing and semantic interpretation.
"""
from copy import deepcopy
import uncompyle6.opcodes.opcode_3x as opcode_3x
from uncompyle6.opcodes.opcode_3x import fields2copy, hasfree, rm_op
# FIXME: can we DRY this even more?
opmap = {}
opname = [''] * 256
hasconst = []
hasjrel = []
hasjabs = []
def def_op(name, op):
opname[op] = name
opmap[name] = op
for object in fields2copy:
globals()[object] = deepcopy(getattr(opcode_3x, object))
# Below are opcodes changes since Python 3.2
rm_op(opname, opmap, 'STOP_CODE', 0)
rm_op(opname, opmap, 'STORE_LOCALS', 69)
# These are new since Python 3.3
def_op('YIELD_FROM', 72)
def_op('LOAD_CLASSDEREF', 148)
# These are removed since Python 3.4
rm_op(opname, opmap, 'WITH_CLEANUP', 81)
# These are new since Python 3.4
def_op('BINARY_MATRIX_MULTIPLY', 16)
def_op('INPLACE_MATRIX_MULTIPLY', 17)
def_op('GET_AITER', 50)
def_op('GET_ANEXT', 51)
def_op('BEFORE_ASYNC_WITH', 52)
def_op('GET_YIELD_FROM_ITER', 69)
def_op('GET_AWAITABLE', 73)
def_op('WITH_CLEANUP_START', 81)
def_op('WITH_CLEANUP_FINISH', 82)
def_op('BUILD_LIST_UNPACK', 149)
def_op('BUILD_MAP_UNPACK', 150)
def_op('BUILD_MAP_UNPACK_WITH_CALL', 151)
def_op('BUILD_TUPLE_UNPACK', 152)
def_op('BUILD_SET_UNPACK', 153)
def_op('SETUP_ASYNC_WITH', 154)
hasfree.append(148)
def updateGlobal():
# JUMP_OPs are used in verification are set in the scanner
# and used in the parser grammar
globals().update({'PJIF': opmap['POP_JUMP_IF_FALSE']})
globals().update({'PJIT': opmap['POP_JUMP_IF_TRUE']})
globals().update({'JA': opmap['JUMP_ABSOLUTE']})
globals().update({'JF': opmap['JUMP_FORWARD']})
globals().update(dict([(k.replace('+', '_'), v) for (k, v) in opmap.items()]))
globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
updateGlobal()
# FIXME: turn into pytest test
from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION == 3.5:
import dis
for item in dis.opmap.items():
if item not in opmap.items():
print(item)
assert all(item in opmap.items() for item in dis.opmap.items())
# opcode_3x.dump_opcodes(opmap)

View File

@@ -0,0 +1,210 @@
"""
CPython 3.2 bytecode opcodes to be used as a base for other opcodes including 3.2.
If this file changes the other opcode files may have to a adjusted accordingly.
"""
cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
'is not', 'exception match', 'BAD')
hasconst = []
hasname = []
hasjrel = []
hasjabs = []
haslocal = []
hascompare = []
hasfree = []
hasnargs = []
opmap = {}
opname = [''] * 256
for op in range(256): opname[op] = '<%r>' % (op,)
del op
def def_op(name, op):
opname[op] = name
opmap[name] = op
def name_op(name, op):
def_op(name, op)
hasname.append(op)
def jrel_op(name, op):
def_op(name, op)
hasjrel.append(op)
def jabs_op(name, op):
def_op(name, op)
hasjabs.append(op)
# Instruction opcodes for compiled code
# Blank lines correspond to available opcodes
def_op('STOP_CODE', 0)
def_op('POP_TOP', 1)
def_op('ROT_TWO', 2)
def_op('ROT_THREE', 3)
def_op('DUP_TOP', 4)
def_op('DUP_TOP_TWO', 5)
def_op('NOP', 9)
def_op('UNARY_POSITIVE', 10)
def_op('UNARY_NEGATIVE', 11)
def_op('UNARY_NOT', 12)
def_op('UNARY_INVERT', 15)
def_op('BINARY_POWER', 19)
def_op('BINARY_MULTIPLY', 20)
def_op('BINARY_MODULO', 22)
def_op('BINARY_ADD', 23)
def_op('BINARY_SUBTRACT', 24)
def_op('BINARY_SUBSCR', 25)
def_op('BINARY_FLOOR_DIVIDE', 26)
def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29)
# Gone from Python 3 are Python2's
# SLICE+0 .. SLICE+3
# STORE_SLICE+0 .. STORE_SLICE+3
# DELETE_SLICE+0 .. DELETE_SLICE+3
def_op('STORE_MAP', 54)
def_op('INPLACE_ADD', 55)
def_op('INPLACE_SUBTRACT', 56)
def_op('INPLACE_MULTIPLY', 57)
def_op('INPLACE_MODULO', 59)
def_op('STORE_SUBSCR', 60)
def_op('DELETE_SUBSCR', 61)
def_op('BINARY_LSHIFT', 62)
def_op('BINARY_RSHIFT', 63)
def_op('BINARY_AND', 64)
def_op('BINARY_XOR', 65)
def_op('BINARY_OR', 66)
def_op('INPLACE_POWER', 67)
def_op('GET_ITER', 68)
def_op('STORE_LOCALS', 69)
def_op('PRINT_EXPR', 70)
def_op('LOAD_BUILD_CLASS', 71)
# Python3 drops/changes:
# def_op('PRINT_ITEM', 71)
# def_op('PRINT_NEWLINE', 72)
# def_op('PRINT_ITEM_TO', 73)
# def_op('PRINT_NEWLINE_TO', 74)
def_op('INPLACE_LSHIFT', 75)
def_op('INPLACE_RSHIFT', 76)
def_op('INPLACE_AND', 77)
def_op('INPLACE_XOR', 78)
def_op('INPLACE_OR', 79)
def_op('BREAK_LOOP', 80)
def_op('WITH_CLEANUP', 81)
def_op('RETURN_VALUE', 83)
def_op('IMPORT_STAR', 84)
def_op('YIELD_VALUE', 86)
def_op('POP_BLOCK', 87)
def_op('END_FINALLY', 88)
def_op('POP_EXCEPT', 89)
HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
name_op('STORE_NAME', 90) # Index in name list
name_op('DELETE_NAME', 91) # ""
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
jrel_op('FOR_ITER', 93)
def_op('UNPACK_EX', 94)
name_op('STORE_ATTR', 95) # Index in name list
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""
# Python 2's DUP_TOPX is gone
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
def_op('BUILD_TUPLE', 102) # Number of tuple items
def_op('BUILD_LIST', 103) # Number of list items
def_op('BUILD_SET', 104) # Number of set items
def_op('BUILD_MAP', 105) # Number of dict entries (upto 255)
name_op('LOAD_ATTR', 106) # Index in name list
def_op('COMPARE_OP', 107) # Comparison operator
hascompare.append(107)
name_op('IMPORT_NAME', 108) # Index in name list
name_op('IMPORT_FROM', 109) # Index in name list
jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
jabs_op('JUMP_ABSOLUTE', 113) # ""
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
name_op('LOAD_GLOBAL', 116) # Index in name list
jabs_op('CONTINUE_LOOP', 119) # Target address
jrel_op('SETUP_LOOP', 120) # Distance to target address
jrel_op('SETUP_EXCEPT', 121) # ""
jrel_op('SETUP_FINALLY', 122) # ""
def_op('LOAD_FAST', 124) # Local variable number
haslocal.append(124)
def_op('STORE_FAST', 125) # Local variable number
haslocal.append(125)
def_op('DELETE_FAST', 126) # Local variable number
haslocal.append(126)
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
hasnargs.append(131)
def_op('MAKE_FUNCTION', 132) # Number of args with default values
def_op('BUILD_SLICE', 133) # Number of items
def_op('MAKE_CLOSURE', 134)
def_op('LOAD_CLOSURE', 135)
hasfree.append(135)
def_op('LOAD_DEREF', 136)
hasfree.append(136)
def_op('STORE_DEREF', 137)
hasfree.append(137)
def_op('DELETE_DEREF', 138)
hasfree.append(138)
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
hasnargs.append(140)
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
hasnargs.append(141)
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
hasnargs.append(142)
jrel_op('SETUP_WITH', 143)
def_op('LIST_APPEND', 145)
def_op('SET_ADD', 146)
def_op('MAP_ADD', 147)
def_op('EXTENDED_ARG', 144)
EXTENDED_ARG = 144
fields2copy = """cmp_op hasconst hasname hasjrel hasjabs haslocal hascompare hasfree hasnargs
opmap opname HAVE_ARGUMENT EXTENDED_ARG""".split()
def rm_op(opname, opmap, name, op):
# opname is an array, so we need to keep the position in there.
opname[op] = ''
assert opmap[name] == op
del opmap[name]
def dump_opcodes(opmap):
"""Utility for dumping opcodes"""
op2name = {}
for k in opmap.keys():
op2name[opmap[k]] = k
for i in sorted(op2name.keys()):
print("%-3s %s" % (str(i), op2name[i]))

View File

@@ -1,9 +1,9 @@
# Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2015-2016 Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2015 Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
"""
Common spark parser routines Python.
Common uncompyle parser routines.
"""
from __future__ import print_function
@@ -11,7 +11,7 @@ from __future__ import print_function
import sys
from uncompyle6.code import iscode
from uncompyle6.parsers.spark import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
class ParserError(Exception):
def __init__(self, token, offset):
@@ -69,6 +69,323 @@ class PythonParser(GenericASTBuilder):
# print >> sys.stderr, 'resolve', str(list)
return GenericASTBuilder.resolve(self, list)
##############################################
## Common Python 2 and Python 3 grammar rules
##############################################
def p_start(self, args):
'''
# The start or goal symbol
stmts ::= stmts sstmt
stmts ::= sstmt
'''
def p_call_stmt(self, args):
'''
# eval-mode compilation. Single-mode interactive compilation
# adds another rule.
call_stmt ::= expr POP_TOP
'''
def p_funcdef(self, args):
'''
stmt ::= funcdef
funcdef ::= mkfunc designator
stmt ::= funcdefdeco
funcdefdeco ::= mkfuncdeco designator
mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1
mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1
mkfuncdeco0 ::= mkfunc
load_closure ::= load_closure LOAD_CLOSURE
load_closure ::= LOAD_CLOSURE
'''
def p_genexpr(self, args):
'''
expr ::= genexpr
genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= genexpr_func
genexpr_func ::= LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK
'''
def p_dictcomp(self, args):
'''
expr ::= dictcomp
dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= dictcomp_func
dictcomp_func ::= BUILD_MAP LOAD_FAST FOR_ITER designator
comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST
'''
def p_augmented_assign(self, args):
'''
stmt ::= augassign1
stmt ::= augassign2
augassign1 ::= expr expr inplace_op designator
augassign1 ::= expr expr inplace_op ROT_THREE STORE_SUBSCR
augassign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0
augassign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+1
augassign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2
augassign1 ::= expr expr inplace_op ROT_FOUR STORE_SLICE+3
augassign2 ::= expr DUP_TOP LOAD_ATTR expr
inplace_op ROT_TWO STORE_ATTR
inplace_op ::= INPLACE_ADD
inplace_op ::= INPLACE_SUBTRACT
inplace_op ::= INPLACE_MULTIPLY
inplace_op ::= INPLACE_DIVIDE
inplace_op ::= INPLACE_TRUE_DIVIDE
inplace_op ::= INPLACE_FLOOR_DIVIDE
inplace_op ::= INPLACE_MODULO
inplace_op ::= INPLACE_POWER
inplace_op ::= INPLACE_LSHIFT
inplace_op ::= INPLACE_RSHIFT
inplace_op ::= INPLACE_AND
inplace_op ::= INPLACE_XOR
inplace_op ::= INPLACE_OR
'''
def p_assign(self, args):
'''
stmt ::= assign
assign ::= expr DUP_TOP designList
assign ::= expr designator
stmt ::= assign2
stmt ::= assign3
assign2 ::= expr expr ROT_TWO designator designator
assign3 ::= expr expr expr ROT_THREE ROT_TWO designator designator designator
'''
def p_import20(self, args):
'''
stmt ::= importstmt
stmt ::= importfrom
stmt ::= importstar
stmt ::= importmultiple
importlist2 ::= importlist2 import_as
importlist2 ::= import_as
import_as ::= IMPORT_NAME designator
import_as ::= IMPORT_NAME load_attrs designator
import_as ::= IMPORT_FROM designator
importstmt ::= LOAD_CONST LOAD_CONST import_as
importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME IMPORT_STAR
importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist2 POP_TOP
importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT IMPORT_STAR
importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT importlist2 POP_TOP
importmultiple ::= LOAD_CONST LOAD_CONST import_as imports_cont
imports_cont ::= imports_cont import_cont
imports_cont ::= import_cont
import_cont ::= LOAD_CONST LOAD_CONST import_as_cont
import_as_cont ::= IMPORT_NAME_CONT designator
import_as_cont ::= IMPORT_NAME_CONT load_attrs designator
import_as_cont ::= IMPORT_FROM designator
load_attrs ::= LOAD_ATTR
load_attrs ::= load_attrs LOAD_ATTR
'''
def p_list_comprehension(self, args):
"""
expr ::= list_compr
list_compr ::= BUILD_LIST_0 list_iter
list_iter ::= list_for
list_iter ::= list_if
list_iter ::= list_if_not
list_iter ::= lc_body
_come_from ::= COME_FROM
_come_from ::=
list_if ::= expr jmp_false list_iter
list_if_not ::= expr jmp_true list_iter
lc_body ::= expr LIST_APPEND
"""
def p_setcomp(self, args):
"""
expr ::= setcomp
setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= setcomp_func
setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter
JUMP_BACK RETURN_VALUE RETURN_LAST
comp_iter ::= comp_if
comp_iter ::= comp_ifnot
comp_iter ::= comp_for
comp_iter ::= comp_body
comp_body ::= set_comp_body
comp_body ::= gen_comp_body
comp_body ::= dict_comp_body
set_comp_body ::= expr SET_ADD
gen_comp_body ::= expr YIELD_VALUE POP_TOP
dict_comp_body ::= expr expr MAP_ADD
comp_if ::= expr jmp_false comp_iter
comp_ifnot ::= expr jmp_true comp_iter
"""
def p_expr(self, args):
'''
expr ::= _mklambda
expr ::= SET_LINENO
expr ::= LOAD_FAST
expr ::= LOAD_NAME
expr ::= LOAD_CONST
expr ::= LOAD_GLOBAL
expr ::= LOAD_DEREF
expr ::= load_attr
expr ::= binary_expr
expr ::= binary_expr_na
expr ::= build_list
expr ::= cmp
expr ::= mapexpr
expr ::= and
expr ::= and2
expr ::= or
expr ::= unary_expr
expr ::= call_function
expr ::= unary_not
expr ::= unary_convert
expr ::= binary_subscr
expr ::= binary_subscr2
expr ::= load_attr
expr ::= get_iter
expr ::= slice0
expr ::= slice1
expr ::= slice2
expr ::= slice3
expr ::= buildslice2
expr ::= buildslice3
expr ::= yield
binary_expr ::= expr expr binary_op
binary_op ::= BINARY_ADD
binary_op ::= BINARY_MULTIPLY
binary_op ::= BINARY_AND
binary_op ::= BINARY_OR
binary_op ::= BINARY_XOR
binary_op ::= BINARY_SUBTRACT
binary_op ::= BINARY_DIVIDE
binary_op ::= BINARY_TRUE_DIVIDE
binary_op ::= BINARY_FLOOR_DIVIDE
binary_op ::= BINARY_MODULO
binary_op ::= BINARY_LSHIFT
binary_op ::= BINARY_RSHIFT
binary_op ::= BINARY_POWER
unary_expr ::= expr unary_op
unary_op ::= UNARY_POSITIVE
unary_op ::= UNARY_NEGATIVE
unary_op ::= UNARY_INVERT
unary_not ::= expr UNARY_NOT
unary_convert ::= expr UNARY_CONVERT
binary_subscr ::= expr expr BINARY_SUBSCR
binary_subscr2 ::= expr expr DUP_TOPX_2 BINARY_SUBSCR
load_attr ::= expr LOAD_ATTR
get_iter ::= expr GET_ITER
slice0 ::= expr SLICE+0
slice0 ::= expr DUP_TOP SLICE+0
slice1 ::= expr expr SLICE+1
slice1 ::= expr expr DUP_TOPX_2 SLICE+1
slice2 ::= expr expr SLICE+2
slice2 ::= expr expr DUP_TOPX_2 SLICE+2
slice3 ::= expr expr expr SLICE+3
slice3 ::= expr expr expr DUP_TOPX_3 SLICE+3
buildslice3 ::= expr expr expr BUILD_SLICE_3
buildslice2 ::= expr expr BUILD_SLICE_2
yield ::= expr YIELD_VALUE
_mklambda ::= load_closure mklambda
_mklambda ::= mklambda
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
or ::= expr jmp_true expr _come_from
and ::= expr jmp_false expr _come_from
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
and2 ::= _jump jmp_false COME_FROM expr COME_FROM
expr ::= conditional
conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM
conditional ::= expr jmp_false expr JUMP_ABSOLUTE expr
expr ::= conditionalnot
conditionalnot ::= expr jmp_true expr _jump expr COME_FROM
ret_expr ::= expr
ret_expr ::= ret_and
ret_expr ::= ret_or
ret_expr_or_cond ::= ret_expr
ret_expr_or_cond ::= ret_cond
ret_expr_or_cond ::= ret_cond_not
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
ret_cond_not ::= expr POP_JUMP_IF_TRUE expr RETURN_END_IF ret_expr_or_cond
stmt ::= return_lambda
stmt ::= conditional_lambda
return_lambda ::= ret_expr RETURN_VALUE LAMBDA_MARKER
conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER
cmp ::= cmp_list
cmp ::= compare
compare ::= expr expr COMPARE_OP
cmp_list ::= expr cmp_list1 ROT_TWO POP_TOP
_come_from
cmp_list1 ::= expr DUP_TOP ROT_THREE
COMPARE_OP JUMP_IF_FALSE_OR_POP
cmp_list1 COME_FROM
cmp_list1 ::= expr DUP_TOP ROT_THREE
COMPARE_OP jmp_false
cmp_list1 _come_from
cmp_list1 ::= expr DUP_TOP ROT_THREE
COMPARE_OP JUMP_IF_FALSE_OR_POP
cmp_list2 COME_FROM
cmp_list1 ::= expr DUP_TOP ROT_THREE
COMPARE_OP jmp_false
cmp_list2 _come_from
cmp_list2 ::= expr COMPARE_OP JUMP_FORWARD
cmp_list2 ::= expr COMPARE_OP RETURN_VALUE
mapexpr ::= BUILD_MAP kvlist
kvlist ::= kvlist kv
kvlist ::= kvlist kv2
kvlist ::= kvlist kv3
kvlist ::=
kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
kv3 ::= expr expr STORE_MAP
exprlist ::= exprlist expr
exprlist ::= expr
nullexprlist ::=
expr32 ::= expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr
expr1024 ::= expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32
'''
def parse(p, tokens, customize):
p.add_custom_rules(tokens, customize)
ast = p.parse(tokens)
@@ -76,20 +393,50 @@ def parse(p, tokens, customize):
return ast
def get_python_parser(version, debug_parser):
"""
Returns parser object for Python version 2 or 3
depending on the parameter passed.
def get_python_parser(version, debug_parser, compile_mode='exec'):
"""Returns parser object for Python version 2 or 3, 3.2, 3.5on,
etc., depending on the parameters passed. *compile_mode* is either
'exec', 'eval', or 'single'. See
https://docs.python.org/3.6/library/functions.html#compile for an
explanation of the different modes.
"""
if version < 3.0:
import uncompyle6.parsers.parse2 as parse2
if compile_mode == 'exec':
p = parse2.Python2Parser(debug_parser)
else:
p = parse2.Python2ParserSingle(debug_parser)
else:
import uncompyle6.parsers.parse3 as parse3
if version == 3.2:
if compile_mode == 'exec':
p = parse3.Python32Parser(debug_parser)
else:
p = parse3.Python32ParserSingle(debug_parser)
elif version >= 3.5:
if compile_mode == 'exec':
p = parse3.Python35onParser(debug_parser)
else:
p = parse3.Python35onParserSingle(debug_parser)
else:
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)
else:
p = parse3.Python3ParserSingle(debug_parser)
p.version = version
return p
class PythonParserSingle(PythonParser):
def p_call_stmt(self, args):
'''
# single-mode compilation. Eval-mode interactive compilation
# drops the last rule.
call_stmt ::= expr POP_TOP
call_stmt ::= expr PRINT_EXPR
'''
def python_parser(version, co, out=sys.stdout, showasm=False,
parser_debug=PARSER_DEFAULT_DEBUG):
assert iscode(co)
@@ -100,12 +447,14 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
for t in tokens:
print(t)
# For heavy grammar debugging
# parser_debug = {'rules': True, 'transition': True, 'reduce' : True}
p = get_python_parser(version, parser_debug)
return parse(p, tokens, customize)
if __name__ == '__main__':
def parse_test(co):
from uncompyl6e import PYTHON_VERSION
from uncompyle6 import PYTHON_VERSION
ast = python_parser(PYTHON_VERSION, co, showasm=True)
print(ast)
return

View File

@@ -10,8 +10,8 @@ else:
class AST(UserList):
def __init__(self, type, kids=[]):
self.type = intern(type)
def __init__(self, kind, kids=[]):
self.type = intern(kind)
UserList.__init__(self, kids)
def isNone(self):
@@ -28,7 +28,8 @@ class AST(UserList):
else:
return self.type == o
def __hash__(self): return hash(self.type)
def __hash__(self):
return hash(self.type)
def __repr__(self, indent=''):
rv = str(self.type)

Some files were not shown because too many files have changed in this diff Show More