You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Compare commits
314 Commits
releaes-3.
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
bff171897a | ||
|
189d7c6562 | ||
|
a54a558a44 | ||
|
6443257e60 | ||
|
343f01cb8f | ||
|
87d0b6e3fb | ||
|
eb317480d8 | ||
|
663b6ca50f | ||
|
908dea4a23 | ||
|
309ccb8734 | ||
|
d687b44f70 | ||
|
b94d67e99a | ||
|
1f8a5dfa06 | ||
|
d420b2864e | ||
|
12e46504f3 | ||
|
d3bd73c281 | ||
|
86e29eaac8 | ||
|
e934d79170 | ||
|
398981e887 | ||
|
96c9a67554 | ||
|
44ffb04ee1 | ||
|
c78f9a3b7d | ||
|
f088ded236 | ||
|
beaedc7ca1 | ||
|
f9392ed908 | ||
|
eb30181e51 | ||
|
9edeb84adc | ||
|
f7a8aabdee | ||
|
214f5f32a3 | ||
|
53b471a3df | ||
|
2b730628d5 | ||
|
48006ab350 | ||
|
b3642094b2 | ||
|
a574168ca8 | ||
|
263b4b5653 | ||
|
19818ae632 | ||
|
477d73c71d | ||
|
7272ac4a60 | ||
|
7659277c5c | ||
|
761eee7ae7 | ||
|
600cee26d9 | ||
|
61466808f5 | ||
|
de25c5f003 | ||
|
8880568045 | ||
|
3c7d460036 | ||
|
ee3f2446f9 | ||
|
0b24eca8d7 | ||
|
3116ac8323 | ||
|
19bb16270d | ||
|
35c41f8065 | ||
|
9d36e7742e | ||
|
75f3624f31 | ||
|
2e78c007ee | ||
|
f5a10ed5d0 | ||
|
de75849ae3 | ||
|
30d6dcdd69 | ||
|
c48345a5c0 | ||
|
a1cdc5e40c | ||
|
661bfd4e52 | ||
|
6ac48bb0e1 | ||
|
a18b4b1505 | ||
|
b2c832e19f | ||
|
1462a8beb0 | ||
|
f877e65919 | ||
|
78898ed187 | ||
|
ef03d78c4d | ||
|
48b251273a | ||
|
c91b5e1164 | ||
|
f8fd474b55 | ||
|
bc5f43ab05 | ||
|
1da2118e13 | ||
|
67e8f5d1a7 | ||
|
2a76013ed5 | ||
|
681bbd616b | ||
|
46390a161e | ||
|
28d0ec7a2a | ||
|
8a842c57d3 | ||
|
fb333f1505 | ||
|
ab257dc7ce | ||
|
e3d8751338 | ||
|
a1532bbfea | ||
|
128963d2e9 | ||
|
1cb9fc8b43 | ||
|
b9147b7872 | ||
|
5496271000 | ||
|
16b5df4ba4 | ||
|
fee6114d74 | ||
|
b14655dd43 | ||
|
3de2890050 | ||
|
90ae3e42f6 | ||
|
158a1886fe | ||
|
d2285f0d61 | ||
|
2e44ac25a1 | ||
|
9d425039a2 | ||
|
832f04a486 | ||
|
657d5ef024 | ||
|
e92c2503d1 | ||
|
b74662cf3d | ||
|
ed3b0e81b9 | ||
|
75755c8cfc | ||
|
4ce769399f | ||
|
d0dfdcfcde | ||
|
4e949a798d | ||
|
4fb379afb4 | ||
|
eb7484c671 | ||
|
79470ffff7 | ||
|
44af6c42a2 | ||
|
d7380dc549 | ||
|
b2f6e1cf1a | ||
|
7c9437f0a9 | ||
|
162bb0a85f | ||
|
e44ccd5787 | ||
|
c4612b7484 | ||
|
731c5a2092 | ||
|
7efbd55b69 | ||
|
5dbec5b383 | ||
|
f28ad69c38 | ||
|
49a71819a1 | ||
|
ed7d11525a | ||
|
5b1dcccddc | ||
|
992a08f5ce | ||
|
49ef408699 | ||
|
0487f2fb7a | ||
|
e43c8acd30 | ||
|
97604a93dd | ||
|
d266e9e123 | ||
|
7ac8bf91df | ||
|
772d36015c | ||
|
f381211291 | ||
|
aca4cb233d | ||
|
01ef3b774f | ||
|
9041dead7f | ||
|
4ea308f75a | ||
|
e5f06eb551 | ||
|
c68030e9fa | ||
|
fd95839701 | ||
|
6305023219 | ||
|
c7dda72a84 | ||
|
7caedcb50d | ||
|
1856e09a0c | ||
|
e47568e147 | ||
|
c702ce3802 | ||
|
a37f403410 | ||
|
9248a954bd | ||
|
89a7ad6f81 | ||
|
f432f4f698 | ||
|
5ef2d5cd9f | ||
|
204612ca85 | ||
|
df8c092212 | ||
|
55d2e598db | ||
|
3c67c7b32c | ||
|
5264ffc0e5 | ||
|
27b217a4ed | ||
|
d756548ac3 | ||
|
0171e4d899 | ||
|
a2054fb7dd | ||
|
f07c9c6dcf | ||
|
c677c946ea | ||
|
87063851be | ||
|
516c1a7910 | ||
|
2293f77841 | ||
|
212771244a | ||
|
5fc33aeef5 | ||
|
fff0d1c988 | ||
|
987b5a2290 | ||
|
910d210e52 | ||
|
b719a0ee35 | ||
|
25329d2752 | ||
|
df4d80ff26 | ||
|
13ab06ecb1 | ||
|
72e2d1a2bf | ||
|
c90210c063 | ||
|
21a8726a47 | ||
|
ca7f267103 | ||
|
7b15e54b7d | ||
|
ccd007355c | ||
|
36aba02093 | ||
|
a5dd330218 | ||
|
fc0eb87620 | ||
|
0b9fca2263 | ||
|
0d9464bb92 | ||
|
ff435227e9 | ||
|
fcdc3f67af | ||
|
299936e554 | ||
|
2e192f0467 | ||
|
9062f19a97 | ||
|
f51e40a1de | ||
|
e411024696 | ||
|
01a27e22b4 | ||
|
7553c4aed9 | ||
|
593304bc43 | ||
|
a9ca30fe34 | ||
|
6030730870 | ||
|
b9436e4851 | ||
|
b0a7452d48 | ||
|
5e05e521d9 | ||
|
7a052c349a | ||
|
35aca37557 | ||
|
57fe56d72e | ||
|
218e73540a | ||
|
0965e2cc96 | ||
|
5cf4f0a82f | ||
|
9b0225db60 | ||
|
8c0959de42 | ||
|
ccd71c857f | ||
|
b89dbb0ee7 | ||
|
a5bdc1acd0 | ||
|
a279784d8d | ||
|
3a9f4f2984 | ||
|
51ae8313cf | ||
|
38f04f0073 | ||
|
f3da5d770d | ||
|
24fb13cf23 | ||
|
524e8c8410 | ||
|
52d1e44560 | ||
|
6055c5e165 | ||
|
e0ed187ea6 | ||
|
eafe048c7e | ||
|
c0e553dbb5 | ||
|
7e59987af7 | ||
|
1f012f7c46 | ||
|
d1a3d42ab8 | ||
|
05fd992c48 | ||
|
47f1d888eb | ||
|
ca9c227837 | ||
|
5df384bb71 | ||
|
e80b36347a | ||
|
9e37495493 | ||
|
77b93c5f21 | ||
|
0b198ee881 | ||
|
9e0c65881d | ||
|
c796d6a799 | ||
|
3892fb533a | ||
|
2ea7487ca7 | ||
|
d4f6cec3d0 | ||
|
b1705e283d | ||
|
eee751e22a | ||
|
2b0fefb95f | ||
|
1a627ba207 | ||
|
ea75bcf47e | ||
|
6c6dcab857 | ||
|
0654aed6c8 | ||
|
3447ca0767 | ||
|
1e858efafd | ||
|
ce88a72ea1 | ||
|
7725b8e7de | ||
|
62ddbe320d | ||
|
a694601264 | ||
|
e06f88043f | ||
|
8fc3fd146f | ||
|
ce5066bddb | ||
|
93f18e2449 | ||
|
783e62f3ca | ||
|
c38dc61021 | ||
|
45782bbb39 | ||
|
4c9cd5657e | ||
|
dc627d13b8 | ||
|
ddc3489991 | ||
|
5b24c20331 | ||
|
8bb01143d8 | ||
|
a9635da96a | ||
|
e790cb75fd | ||
|
348afeebbf | ||
|
6888553773 | ||
|
0f489672b9 | ||
|
b7d8cbfaf5 | ||
|
df8d253f78 | ||
|
89b42e3696 | ||
|
22e5a4a283 | ||
|
61810172d1 | ||
|
658c8b4be7 | ||
|
d4dab54c7b | ||
|
5566b9ba6c | ||
|
e56ab2dcd5 | ||
|
d6c45979ba | ||
|
a06e9bf32e | ||
|
7e8f7ba674 | ||
|
09eb7f7f78 | ||
|
f7a910ec66 | ||
|
6d6a73eea7 | ||
|
e4a7641927 | ||
|
b24b46d48c | ||
|
a65d7dce5b | ||
|
718a0a5d34 | ||
|
ea9e3ab3f5 | ||
|
770e988ff8 | ||
|
0fa0641974 | ||
|
c13e23cdae | ||
|
fab4ebb768 | ||
|
89429339fa | ||
|
6ed129bd7a | ||
|
c4fde6b53e | ||
|
a7d93e88b4 | ||
|
9891494142 | ||
|
f8544dfbbe | ||
|
b00651d428 | ||
|
da8dccbaca | ||
|
37272ae827 | ||
|
7f2bee46b7 | ||
|
c8a4dcf72b | ||
|
012ff91cfb | ||
|
e690ddd50a | ||
|
45b7c1948c | ||
|
e2fb7ca3d2 | ||
|
b3bda76582 | ||
|
ab6d322eca | ||
|
1a8a0df107 | ||
|
0a37709b0a | ||
|
98cd1417df | ||
|
460069ceaa | ||
|
316aa44f23 | ||
|
7133540c23 | ||
|
590231741d | ||
|
a9349b8f3d |
@@ -42,7 +42,7 @@ jobs:
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run:
|
||||
working_directory: ~/rocky/python-uncompyle6
|
||||
command: pyenv local 2.7.11 && pyenv rehash && pip install virtualenv && pip install nose && pip install pep8 && pip install six && pyenv rehash
|
||||
command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && easy_install nose && pyenv rehash
|
||||
# Dependencies
|
||||
# This would typically go in either a build or a build-and-test job when using workflows
|
||||
# Restore the dependency cache
|
||||
@@ -55,9 +55,7 @@ jobs:
|
||||
# Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
|
||||
- v1-dep-
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run: pip install --upgrade setuptools
|
||||
- run: pip install -e .
|
||||
- run: pip install pytest==3.2.5 hypothesis==3.0.0
|
||||
- run: easy_install spark_parser==1.8.5 && easy_install xdis==3.8.4
|
||||
# Save dependency cache
|
||||
- save_cache:
|
||||
key: v1-dep-{{ .Branch }}-{{ epoch }}
|
||||
@@ -75,8 +73,8 @@ jobs:
|
||||
# Test
|
||||
# This would typically be a build job when using workflows, possibly combined with build
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run: python ./setup.py develop && make check-2.7
|
||||
- run: cd ./test/stdlib && pyenv local 2.7.11 && bash ./runtests.sh 'test_[p-z]*.py'
|
||||
- run: python ./setup.py develop && make check-2.4
|
||||
- run: cd ./test/stdlib && pyenv local 2.4.6 && bash ./runtests.sh 'test_[p-z]*.py'
|
||||
# Teardown
|
||||
# If you break your build into multiple jobs with workflows, you will probably want to do the parts of this that are relevant in each
|
||||
# Save test results
|
||||
|
13
.travis.yml
13
.travis.yml
@@ -1,16 +1,9 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- '3.5'
|
||||
- '2.7'
|
||||
- '2.6'
|
||||
- '3.4'
|
||||
- '3.6'
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- python: '3.7'
|
||||
dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069)
|
||||
python:
|
||||
- '2.7' # this is a cheat here because travis doesn't do 2.4-2.6
|
||||
|
||||
install:
|
||||
- pip install -e .
|
||||
|
4
Makefile
4
Makefile
@@ -40,6 +40,10 @@ check-3.0 check-3.1 check-3.2 check-3.6:
|
||||
check-3.7: pytest
|
||||
$(MAKE) -C test check
|
||||
|
||||
#:Tests for Python 2.4-2.5 (don't have pytest)
|
||||
check-2.4 check-2.5:
|
||||
$(MAKE) -C test $@
|
||||
|
||||
#:PyPy 2.6.1 PyPy 5.0.1, or PyPy 5.8.0-beta0
|
||||
# Skip for now
|
||||
2.6 5.0 5.3 5.6 5.8:
|
||||
|
235
NEWS.md → NEWS
235
NEWS.md → NEWS
@@ -1,74 +1,43 @@
|
||||
3.2.6 2019-03-23 Mueller Report
|
||||
=======================================
|
||||
|
||||
Mostly more of the same: bug fixes and pull requests.
|
||||
|
||||
Bug Fixes
|
||||
-----------
|
||||
|
||||
* [#155: Python 3.x bytecode confusing "try/else" with "try" in a loop](https://github.com/rocky/python-uncompyle6/issues/155),
|
||||
* [#200: Python 3 bug in not detecting end bounds of an "if" ... "elif"](https://github.com/rocky/python-uncompyle6/issues/200),
|
||||
* [#208: Comma placement in 3.6 and 3.7 **kwargs](https://github.com/rocky/python-uncompyle6/issues/208),
|
||||
* [#209: Fix "if" return boundary in 3.6+](https://github.com/rocky/python-uncompyle6/issues/209),
|
||||
* [#215: 2.7 can have two JUMP_BACKs at the end of a while loop](https://github.com/rocky/python-uncompyle6/issues/215)
|
||||
|
||||
Pull Requests
|
||||
----------------
|
||||
|
||||
* [#202: Better "assert" statement detemination in Python 2.7](https://github.com/rocky/python-uncompyle6/pull/211)
|
||||
* [#204: Python 3.7 testing](https://github.com/rocky/python-uncompyle6/pull/204)
|
||||
* [#205: Run more f-string tests on Python 3.7](https://github.com/rocky/python-uncompyle6/pull/205)
|
||||
* [#211: support utf-8 chars in Python 3 sourcecode](https://github.com/rocky/python-uncompyle6/pull/202)
|
||||
|
||||
|
||||
|
||||
3.2.5 2018-12-30 Clearout sale
|
||||
======================================
|
||||
uncompyle6 3.2.5 2019-12-30 Clearout sale
|
||||
|
||||
- 3.7.2 Remove deprecation warning on regexp string that isn't raw
|
||||
- main.main() parameter `codes` is not used - note that
|
||||
- Improve Python 3.6+ control flow detection
|
||||
- More complete fragment instruction annotation for `imports`
|
||||
|
||||
3.2.4 2018-10-27 7x9 release
|
||||
===================================
|
||||
uncompyle6 3.2.4 2018-10-27 7x9 release
|
||||
|
||||
- Bug fixes #180, #182, #187, #192
|
||||
- Enhancements #189
|
||||
- Internal improvements
|
||||
|
||||
3.2.3 2018-06-04 Michael Cohen flips and Fleetwood Redux
|
||||
======================================================================
|
||||
uncompyle6 3.2.3 2018-06-04 Michael Cohen flips and Fleetwood Redux
|
||||
|
||||
- Python 1.3 support 3.0 bug and
|
||||
- fix botched parameter ordering of 3.x in last release
|
||||
|
||||
3.2.2 2018-06-04 When I'm 64
|
||||
===================================
|
||||
uncompyle6 3.2.2 2018-06-04 When I'm 64
|
||||
|
||||
- Python 3.0 support and bug fixes
|
||||
|
||||
3.2.1 2018-06-04 MF
|
||||
=======================
|
||||
uncompyle6 3.2.1 2018-06-04 MF
|
||||
|
||||
- Python 1.4 and 1.5 bug fixes
|
||||
|
||||
3.2.0 2018-05-19 Rocket Scientist
|
||||
=========================================
|
||||
uncompyle6 3.2.0 2018-05-19 Rocket Scientist
|
||||
|
||||
- Add rudimentary 1.4 support (still a bit buggy)
|
||||
- add --tree+ option to show formatting rule, when it is constant
|
||||
- Python 2.7.15candidate1 support (via xdis)
|
||||
- bug fixes, especially for 3.7 (but 2.7 and 3.6 and others as well)
|
||||
|
||||
3.1.3 2018-04-16
|
||||
====================
|
||||
uncompyle6 3.1.3 2018-04-16
|
||||
|
||||
- Add some Python 3.7 rules, such as for handling LOAD_METHOD (not complete)
|
||||
- Fix some fragment bugs
|
||||
- small doc changes
|
||||
|
||||
3.1.2 2018-04-08 Eastern Orthodox Easter
|
||||
==================================================
|
||||
uncompyle6 3.1.2 2018-04-08 Eastern Orthodox Easter
|
||||
|
||||
- Python 3.x subclass and call parsing fixes
|
||||
- Allow/note running on Python 3.1
|
||||
@@ -76,8 +45,7 @@ Pull Requests
|
||||
- DRY instruction building code between 2.x and 3.x
|
||||
- expand testing
|
||||
|
||||
3.1.1 2018-04-01 Easter April Fool's
|
||||
=============================================
|
||||
uncompyle6 3.1.1 2018-04-01 Easter April Fool's
|
||||
|
||||
Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
||||
|
||||
@@ -90,8 +58,7 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
||||
- more runtime testing of decompiled code
|
||||
- more removal of parenthesis around calls via setting precidence
|
||||
|
||||
3.1.0 2018-03-21 Equinox
|
||||
==============================
|
||||
uncompyle6 3.1.0 2018-03-21 Equinox
|
||||
|
||||
- Add code_deparse_with_offset() fragment function.
|
||||
- Correct paramenter call fragment deparse_code()
|
||||
@@ -99,8 +66,7 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
||||
About 5% of 3.6 fail parsing now. But
|
||||
semantics still needs much to be desired.
|
||||
|
||||
3.0.1 2018-02-17
|
||||
====================
|
||||
uncompyle6 3.0.1 2018-02-17
|
||||
|
||||
- All Python 2.6.9 standard library files weakly verify
|
||||
- Many 3.6 fixes. 84% of the first 200 standard library files weakly compile.
|
||||
@@ -110,8 +76,7 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
||||
- And more add tests target previous existing bugs more completely
|
||||
- sync recent license changes in metadata
|
||||
|
||||
3.0.0 2018-02-17
|
||||
====================
|
||||
uncompyle6 3.0.0 2018-02-17
|
||||
|
||||
- deparse_code() and lookalikes from the various semantic actions are
|
||||
now deprecated. Instead use new API code_deparse() which makes the
|
||||
@@ -133,8 +98,7 @@ A bit more work is still needed for 3.6 especially in the area of
|
||||
function calls and definitions.
|
||||
|
||||
|
||||
2.16.0 2018-02-17
|
||||
=====================
|
||||
uncompyle6 2.16.0 2018-02-17
|
||||
|
||||
- API additions:
|
||||
- add fragments.op_at_code_loc() and
|
||||
@@ -146,21 +110,18 @@ function calls and definitions.
|
||||
- Fix Python 3.5+ CALL_FUNCTION_VAR and BUILD_LIST_UNPACK in call; with this
|
||||
we can can handle 3.5+ f(a, b, *c, *d, *e) now
|
||||
|
||||
2.15.1 2018-02-05
|
||||
=====================
|
||||
uncompyle6 2.15.1 2018-02-05
|
||||
|
||||
- More bug fixes and revert an improper bug fix in 2.15.0
|
||||
|
||||
2.15.0 2018-02-05 pycon2018.co
|
||||
=====================================
|
||||
uncompyle6 2.15.0 2018-02-05 pycon2018.co
|
||||
|
||||
- Bug fixes
|
||||
- Code fragment improvements
|
||||
- Code cleanups
|
||||
- Expand testing
|
||||
|
||||
2.15.1 2018-01-27
|
||||
=====================
|
||||
uncompyle6 2.15.1 2018-01-27
|
||||
|
||||
- Add --linemap option to give line correspondences
|
||||
between original source lines and reconstructed line sources.
|
||||
@@ -172,8 +133,7 @@ function calls and definitions.
|
||||
- Correct 3.6+ calls with kwargs
|
||||
- Describe the difficulty of 3.6 in README
|
||||
|
||||
2.14.3 2018-01-19
|
||||
=====================
|
||||
uncompyle6 2.14.3 2018-01-19
|
||||
|
||||
- Fix bug in 3.5+ await stmt
|
||||
- Better version to magic handling; handle 3.5.2 .. 3.5.4 versions
|
||||
@@ -185,8 +145,7 @@ function calls and definitions.
|
||||
- better tests in setup.py for running the right version of Python
|
||||
- Fix 2.6- parsing of "for .. try/else" ... with "continue" inside
|
||||
|
||||
2.14.2 2018-01-09 Samish
|
||||
==============================
|
||||
uncompyle6 2.14.2 2018-01-09 Samish
|
||||
|
||||
Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
|
||||
@@ -204,8 +163,7 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
Python versions
|
||||
- Match Python AST names more closely when possible
|
||||
|
||||
2.14.1 2017-12-10 Dr. Gecko
|
||||
===================================
|
||||
uncompyle6 2.14.1 2017-12-10 Dr. Gecko
|
||||
|
||||
- Many decompilation bugfixes
|
||||
- Grammar rule reduction and version isolation
|
||||
@@ -213,8 +171,7 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
with Python AST
|
||||
- Start automated Python stdlib testing - full round trip
|
||||
|
||||
2.14.0 2017-11-26 johnnybamazing
|
||||
=========================================
|
||||
uncompyle6 2.14.0 2017-11-26 johnnybamazing
|
||||
|
||||
- Start to isolate grammar rules between versions
|
||||
and remove used grammar rules
|
||||
@@ -222,8 +179,7 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
(many more remain)
|
||||
- Add stdlib/runtests.sh for even more rigorous testing
|
||||
|
||||
2.13.3 2017-11-13
|
||||
=====================
|
||||
uncompyle6 2.13.3 2017-11-13
|
||||
|
||||
Overall: better 3.6 decompiling and some much needed code refactoring and cleanup
|
||||
|
||||
@@ -249,26 +205,22 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
- reinstate some bytecode tests since decompiling has gotten better
|
||||
- Revise how to report a bug
|
||||
|
||||
2.13.2 2017-10-12
|
||||
=====================
|
||||
uncompyle6 2.13.2 2017-10-12
|
||||
|
||||
- Re-release using a more automated approach
|
||||
|
||||
2.13.1 2017-10-11
|
||||
=====================
|
||||
uncompyle6 2.13.1 2017-10-11
|
||||
|
||||
- Re-release because Python 2.4 source uploaded rather than 2.6-3.6
|
||||
|
||||
2.13.0 2017-10-10
|
||||
=====================
|
||||
uncompyle6 2.13.0 2017-10-10
|
||||
|
||||
- Fixes in deparsing lambda expressions
|
||||
- Improve table-semantics descriptions
|
||||
- Document hacky customize arg count better (until we can remove it)
|
||||
- Update to use xdis 3.7.0 or greater
|
||||
|
||||
2.12.0 2017-09-26
|
||||
=====================
|
||||
uncompyle6 2.12.0 2017-09-26
|
||||
|
||||
- Use xdis 3.6.0 or greater now
|
||||
- Small semantic table cleanups
|
||||
@@ -276,13 +228,11 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
- Slightly more Python 3.7, but still failing a lot
|
||||
- Cross Python 2/3 compatibility with annotation arguments
|
||||
|
||||
2.11.5 2017-08-31
|
||||
=====================
|
||||
uncompyle6 2.11.5 2017-08-31
|
||||
|
||||
- Skeletal support for Python 3.7
|
||||
|
||||
2.11.4 2017-08-15
|
||||
=====================
|
||||
uncompyle6 2.11.4 2017-08-15
|
||||
|
||||
* scanner and parser now allow 3-part version string lookups,
|
||||
e.g. 2.7.1 We allow a float here, but if passed a string like '2.7'. or
|
||||
@@ -294,8 +244,7 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
* Some PyPy tolerance in validate testing.
|
||||
* Some pyston tolerance
|
||||
|
||||
2.11.3 2017-08-09
|
||||
=====================
|
||||
uncompyle6 2.11.3 2017-08-09
|
||||
|
||||
Very minor changes
|
||||
|
||||
@@ -304,24 +253,20 @@ Very minor changes
|
||||
- use xdis opcode sets
|
||||
- xdis "exception match" is now "exception-match"
|
||||
|
||||
2.11.2 2017-07-09
|
||||
=====================
|
||||
uncompyle6 2.11.2 2017-07-09
|
||||
|
||||
- Start supporting Pypy 3.5 (5.7.1-beta)
|
||||
- use xdis 3.5.0's opcode sets and require xdis 3.5.0
|
||||
- Correct some Python 2.4-2.6 loop detection
|
||||
- guard against badly formatted bytecode
|
||||
|
||||
2.11.1 2017-06-25
|
||||
=====================
|
||||
uncompyle6 2.11.1 2017-06-25
|
||||
|
||||
- Python 3.x annotation and function signature fixes
|
||||
- Bump xdis version
|
||||
- Small pysource bug fixes
|
||||
|
||||
2.11.0 2017-06-18 Fleetwood
|
||||
==================================
|
||||
|
||||
uncompyle6 2.11.0 2017-06-18 Fleetwood
|
||||
- Major improvements in fragment tracking
|
||||
* Add nonterminal node in extractInfo
|
||||
* tag more offsets in expressions
|
||||
@@ -331,16 +276,14 @@ Very minor changes
|
||||
- Fixes yet again for make_function node handling; document what's up here
|
||||
- Fix bug in snowflake Python 3.5 *args kwargs
|
||||
|
||||
2.10.1 2017-06-3 Marylin Frankel
|
||||
========================================
|
||||
uncompyle6 2.10.1 2017-06-3 Marylin Frankel
|
||||
|
||||
- fix some fragments parsing bugs
|
||||
- was returning the wrong type sometimes in deparse_code_around_offset()
|
||||
- capture function name in offsets
|
||||
- track changes to ifelstrmtr node from pysource into fragments
|
||||
|
||||
2.10.0 2017-05-30 Elaine Gordon
|
||||
=======================================
|
||||
uncompyle6 2.10.0 2017-05-30 Elaine Gordon
|
||||
|
||||
- Add fuzzy offset deparse look up
|
||||
- 3.6 bug fixes
|
||||
@@ -360,21 +303,19 @@ Very minor changes
|
||||
- 2.3, 2.4 "if 1 .." fixes
|
||||
- 3.x annotation fixes
|
||||
|
||||
2.9.11 2017-04-06
|
||||
=====================
|
||||
uncompyle6 2.9.11 2017-04-06
|
||||
|
||||
- Better support for Python 3.5+ BUILD_MAP_UNPACK
|
||||
- Start 3.6 CALL_FUNCTION_EX support
|
||||
- Many decompilation bug fixes. (Many more remain). See ChangeLog
|
||||
|
||||
2.9.10 2017-02-25
|
||||
=====================
|
||||
uncompyle6 2.9.10 2017-02-25
|
||||
|
||||
- Python grammar rule fixes
|
||||
- Add ability to get grammar coverage on runs
|
||||
- Handle Python 3.6 opcode BUILD_CONST_KEYMAP
|
||||
|
||||
2.9.9 2016-12-16
|
||||
uncompyle6 2.9.9 2016-12-16
|
||||
|
||||
- Remaining Python 3.5 ops handled
|
||||
(this also means more Python 3.6 ops are handled)
|
||||
@@ -384,8 +325,7 @@ Very minor changes
|
||||
- Better control-flow detection
|
||||
- Code cleanups and misc bug fixes
|
||||
|
||||
2.9.8 2016-12-16
|
||||
====================
|
||||
uncompyle6 2.9.8 2016-12-16
|
||||
|
||||
- Better control-flow detection
|
||||
- pseudo instruction THEN in 2.x
|
||||
@@ -398,8 +338,7 @@ Very minor changes
|
||||
- verify call fixes for Python <= 2.4
|
||||
- more Python lint
|
||||
|
||||
2.9.7 2016-12-16
|
||||
====================
|
||||
uncompyle6 2.9.7 2016-12-16
|
||||
|
||||
- Start to handle 3.5/3.6 build_map_unpack_with_call
|
||||
- Some Python 3.6 bytecode to wordcode conversion fixes
|
||||
@@ -409,8 +348,7 @@ Very minor changes
|
||||
- some 3.2 compatibility
|
||||
- Better Python 3 control flow detection by adding Pseudo ELSE opcodes
|
||||
|
||||
2.9.6 2016-12-04
|
||||
====================
|
||||
uncompyle6 2.9.6 2016-12-04
|
||||
|
||||
- Shorten Python3 grammars with + and *
|
||||
this requires spark parser 1.5.1
|
||||
@@ -418,8 +356,7 @@ Very minor changes
|
||||
decompile accuracy. This too requires
|
||||
spark parser 1.5.1
|
||||
|
||||
2.9.6 2016-11-20
|
||||
====================
|
||||
uncompyle6 2.9.6 2016-11-20
|
||||
|
||||
- Correct MANIFEST.in
|
||||
- More AST grammar checking
|
||||
@@ -436,8 +373,7 @@ Very minor changes
|
||||
- Python 2 and 3 detect structure code is more similar
|
||||
- Handle Docstrings with embedded triple quotes (""")
|
||||
|
||||
2.9.5 2016-11-13
|
||||
====================
|
||||
uncompyle6 2.9.5 2016-11-13
|
||||
|
||||
- Fix Python 3 bugs:
|
||||
* improper while 1 else
|
||||
@@ -447,15 +383,13 @@ Very minor changes
|
||||
- Start grammar misparse checking
|
||||
|
||||
|
||||
2.9.4 2016-11-02
|
||||
====================
|
||||
uncompyle6 2.9.4 2016-11-02
|
||||
|
||||
- Handle Python 3.x function annotations
|
||||
- track def keyword-parameter line-splitting in source code better
|
||||
- bump min xdis version to mask previous xdis bug
|
||||
|
||||
2.9.3 2016-10-26
|
||||
====================
|
||||
uncompyle6 2.9.3 2016-10-26
|
||||
|
||||
Release forced by incompatibility change in xdis 3.2.0.
|
||||
|
||||
@@ -470,8 +404,7 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
* Handle 3.6 handle single and multiple fstring better
|
||||
|
||||
|
||||
2.9.2 2016-10-15
|
||||
====================
|
||||
uncompyle6 2.9.2 2016-10-15
|
||||
|
||||
- use source-code line breaks to assist in where to break
|
||||
in tuples and maps
|
||||
@@ -479,14 +412,12 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
- Fix some Python 2.6 and below bugs
|
||||
- DRY fragments.py code a little
|
||||
|
||||
2.9.1 2016-10-09
|
||||
====================
|
||||
uncompyle6 2.9.1 2016-10-09
|
||||
|
||||
- Improved Python 1.5 decompiling
|
||||
- Handle old-style pre Python 2.2 classes
|
||||
|
||||
2.9.0 2016-10-09
|
||||
====================
|
||||
uncompyle6 2.9.0 2016-10-09
|
||||
|
||||
- Use xdis 3.0.0 protocol load_module.
|
||||
this Forces change in requirements.txt and _pkg_info_.py
|
||||
@@ -496,8 +427,7 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
- Fix bug with -t ... Wasn't showing source text when -t option was given
|
||||
- Fix 2.1-2.6 bug in list comprehension
|
||||
|
||||
2.8.4 2016-10-08
|
||||
====================
|
||||
uncompyle6 2.8.4 2016-10-08
|
||||
|
||||
- Python 3 disassembly bug fixes
|
||||
- Python 3.6 fstring bug fixes (from moagstar)
|
||||
@@ -505,8 +435,7 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
- COME_FROM suffixes added in Python3
|
||||
- use .py extension in verification disassembly
|
||||
|
||||
2.8.3 2016-09-11 live from NYC!
|
||||
=======================================
|
||||
uncompyle6 2.8.3 2016-09-11 live from NYC!
|
||||
|
||||
NOTE: this is possibly the last release before a major reworking of
|
||||
control-flow structure detection is done.
|
||||
@@ -534,16 +463,14 @@ control-flow structure detection is done.
|
||||
- bump xdis requirement so we can deparse dropbox 2.5 code
|
||||
- Added H. Goebel's changes before 2.4 in DECOMPYLE-2.4-CHANGELOG.txt
|
||||
|
||||
2.8.2 2016-08-29
|
||||
====================
|
||||
uncompyle6 2.8.2 2016-08-29
|
||||
|
||||
- Handle Python 3.6 format string conversions !r, !s, !a
|
||||
- Start to handle 3.1 bytecode
|
||||
- Fix some PyPy translation bugs
|
||||
- We now only handle 3.6.0a3+ since that is incompatible with 3.6 before that
|
||||
|
||||
2.8.1 2016-08-20
|
||||
====================
|
||||
uncompyle6 2.8.1 2016-08-20
|
||||
|
||||
- Add Python 2.2 decompilation
|
||||
|
||||
@@ -551,8 +478,7 @@ control-flow structure detection is done.
|
||||
* PyPy LOOKUP_METHOD bug
|
||||
* Python 3.6 FORMAT_VALUE handles expressions now
|
||||
|
||||
2.8.0 2016-08-03
|
||||
====================
|
||||
uncompyle6 2.8.0 2016-08-03
|
||||
|
||||
- Start Python 3.6 support (moagstar)
|
||||
more work on PEP 498 needed
|
||||
@@ -563,23 +489,20 @@ control-flow structure detection is done.
|
||||
- better grammar and semantic action segregation based
|
||||
on python bytecode version
|
||||
|
||||
2.7.1 2016-07-26
|
||||
====================
|
||||
uncompyle6 2.7.1 2016-07-26
|
||||
|
||||
- PyPy bytecodes for 2.7 and 3.2 added
|
||||
- Instruction formatting improved slightly
|
||||
- 2.7 bytecode "continue" bug fixed
|
||||
|
||||
2.7.0 2016-07-15
|
||||
====================
|
||||
uncompyle6 2.7.0 2016-07-15
|
||||
|
||||
- Many Syntax and verification bugs removed
|
||||
tested on standard libraries from 2.3.7 to 3.5.1
|
||||
and they all decompile and verify fine.
|
||||
I'm sure there are more bugs though.
|
||||
|
||||
2.6.2 2016-07-11 Manhattenhenge
|
||||
=======================================
|
||||
uncompyle6 2.6.2 2016-07-11 Manhattenhenge
|
||||
|
||||
- Extend bytecodes back to 2.3
|
||||
- Fix bugs:
|
||||
@@ -588,15 +511,13 @@ control-flow structure detection is done.
|
||||
* continue statements
|
||||
- DRY and segregate grammar more
|
||||
|
||||
2.6.1 2016-07-08
|
||||
====================
|
||||
uncompyle6 2.6.1 2016-07-08
|
||||
|
||||
- Go over Python 2.5 bytecode deparsing
|
||||
all library programs now deparse
|
||||
- Fix a couple bugs in 2.6 deparsing
|
||||
|
||||
2.6.0 2016-07-07
|
||||
====================
|
||||
uncompyle6 2.6.0 2016-07-07
|
||||
|
||||
- Improve Python 2.6 bytecode deparsing:
|
||||
stdlib now will deparse something
|
||||
@@ -605,8 +526,7 @@ control-flow structure detection is done.
|
||||
- Fix bug in installing uncompyle6 script
|
||||
- Doc improvements
|
||||
|
||||
2.5.0 2016-06-22 Summer Solstice
|
||||
========================================
|
||||
uncompyle6 2.5.0 2016-06-22 Summer Solstice
|
||||
|
||||
- Much better Python 3.2-3.5 coverage.
|
||||
3.4.6 is probably the best;3.2 and 3.5 are weaker
|
||||
@@ -615,8 +535,7 @@ control-flow structure detection is done.
|
||||
- Better fragment offset tracking
|
||||
- Some (much-needed) code refactoring
|
||||
|
||||
2.4.0 2016-05-18 (in memory of Lewis Bernstein)
|
||||
===========================================================
|
||||
uncompyle6 2.4.0 2016-05-18 (in memory of Lewis Bernstein)
|
||||
|
||||
- Many Python 3 bugs fixed:
|
||||
* Python 3.2 to 3.5 libraries largely
|
||||
@@ -631,8 +550,7 @@ control-flow structure detection is done.
|
||||
* handle complex number unmarshaling
|
||||
* Running on Python 2 to works on Python 3.5 bytecodes now
|
||||
|
||||
2.3.5 and 2.3.6 2016-05-14
|
||||
=================================
|
||||
uncompyle6 2.3.5 and 2.3.6 2016-05-14
|
||||
|
||||
- Python 2 class decorator fix (thanks to Tey)
|
||||
- Fix fragment parsing bugs
|
||||
@@ -644,23 +562,20 @@ control-flow structure detection is done.
|
||||
- Correct history based on info from Dan Pascu
|
||||
- Fix up pip packaging, ugh.
|
||||
|
||||
2.3.4 2016-05-5
|
||||
===================
|
||||
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
|
||||
|
||||
2.3.3 2016-05-3
|
||||
===================
|
||||
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
|
||||
|
||||
2.3.2 2016-05-1
|
||||
===================
|
||||
uncompyle6 2.3.2 2016-05-1
|
||||
|
||||
- Add --version option standalone scripts
|
||||
- Correct License information in package
|
||||
@@ -669,20 +584,17 @@ control-flow structure detection is done.
|
||||
specific grammar code
|
||||
- Fix bug in 3.5+ constant map parsing
|
||||
|
||||
2.3.0, 2.3.1 2016-04-30
|
||||
=============================
|
||||
uncompyle6 2.3.0, 2.3.1 2016-04-30
|
||||
|
||||
- Require spark_parser >= 1.1.0
|
||||
|
||||
2.2.0 2016-04-30
|
||||
====================
|
||||
uncompyle6 2.2.0 2016-04-30
|
||||
|
||||
- Spark is no longer here but pulled separate package spark_parse
|
||||
- Python 3 parsing fixes
|
||||
- More tests
|
||||
|
||||
2.2.0 2016-04-02
|
||||
====================
|
||||
uncompyle6 2.2.0 2016-04-02
|
||||
|
||||
- Support single-mode (in addition to exec-mode) compilation
|
||||
- Start to DRY Python 2 and Python 3 grammars
|
||||
@@ -690,8 +602,7 @@ control-flow structure detection is done.
|
||||
- Fix bug in uncomplye6 -d and -r options (via lelicopter)
|
||||
|
||||
|
||||
2.1.3 2016-01-02
|
||||
====================
|
||||
uncompyle6 2.1.3 2016-01-02
|
||||
|
||||
- Limited support for decompiling Python 3.5
|
||||
- Improve Python 3 class deparsing
|
||||
@@ -700,21 +611,18 @@ control-flow structure detection is done.
|
||||
- increase test coverage
|
||||
- fix misc small bugs and some improvements
|
||||
|
||||
2.1.2 2015-12-31
|
||||
====================
|
||||
uncompyle6 2.1.2 2015-12-31
|
||||
|
||||
- Fix cross-version Marshal loading
|
||||
- Handle Python 3.3 . dotted class names
|
||||
- Limited 3.5 support: allows deparsing other versions
|
||||
- Refactor code more, misc bug fixes
|
||||
|
||||
2.1.1 2015-12-27
|
||||
====================
|
||||
uncompyle6 2.1.1 2015-12-27
|
||||
|
||||
- packaging issues
|
||||
|
||||
2.1.0 2015-12-27
|
||||
====================
|
||||
uncompyle6 2.1.0 2015-12-27
|
||||
|
||||
- Python 3.x deparsing much more solid
|
||||
- Better cross-version deparsing
|
||||
@@ -723,8 +631,7 @@ Some bugs squashed while other run rampant. Some code cleanup while
|
||||
much more is yet needed. More tests added, but many more are needed.
|
||||
|
||||
|
||||
2.0.0 2015-12-11
|
||||
====================
|
||||
uncompyle6 2.0.0 2015-12-11
|
||||
|
||||
Changes from uncompyle2
|
||||
|
@@ -57,7 +57,7 @@ entry_points = {
|
||||
]}
|
||||
ftp_url = None
|
||||
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
|
||||
'xdis >= 3.9.0, < 3.10.0']
|
||||
'xdis >= 3.8.9, < 3.9.0']
|
||||
|
||||
license = 'GPL3'
|
||||
mailing_list = 'python-debugger@googlegroups.com'
|
||||
|
0
admin-tools/check-newer-versions.sh
Executable file → Normal file
0
admin-tools/check-newer-versions.sh
Executable file → Normal file
0
admin-tools/check-older-versions.sh
Executable file → Normal file
0
admin-tools/check-older-versions.sh
Executable file → Normal file
@@ -30,9 +30,9 @@
|
||||
|
||||
$ make ChangeLog
|
||||
|
||||
# Update NEWS.md from ChangeLog:
|
||||
# Update NEWS from ChangeLog:
|
||||
|
||||
$ emacs NEWS.md
|
||||
$ emacs NEWS
|
||||
$ make check
|
||||
$ git commit --amend .
|
||||
$ git push # get CI testing going early
|
||||
|
46
admin-tools/how-to-make-a-release.txt
Normal file
46
admin-tools/how-to-make-a-release.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
git pull
|
||||
|
||||
Change version in uncompyle6/version.py
|
||||
source uncompyle6/version.py
|
||||
echo $VERSION
|
||||
git commit -m"Get ready for release $VERSION" .
|
||||
|
||||
Update ChangeLog:
|
||||
make ChangeLog
|
||||
|
||||
Update NEWS from ChangeLog
|
||||
make check
|
||||
|
||||
git commit --amend .
|
||||
|
||||
git push
|
||||
|
||||
Make sure pyenv is running
|
||||
# Pyenv
|
||||
|
||||
source admin-tools/check-newer-versions.sh
|
||||
|
||||
|
||||
# Switch to python-2.4 and build that first...
|
||||
source admin-tools/setup-python-2.4
|
||||
|
||||
rm ChangeLog
|
||||
git merge master
|
||||
|
||||
Update NEWS from master branch
|
||||
|
||||
git commit -m"Get ready for release $VERSION" .
|
||||
|
||||
source admin-tools/check-older-versions.sh
|
||||
source admin-tools/check-newer-versions.sh
|
||||
|
||||
make-dist-older.sh
|
||||
|
||||
git tag release-python-2.4-$VERSION
|
||||
|
||||
./make-dist-newer.sh
|
||||
|
||||
git tag release-$VERSION
|
||||
|
||||
|
||||
twine upload dist/uncompyle6-${VERSION}*
|
@@ -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.2.6 3.6.8 3.7.2 2.6.9 3.3.7 2.7.15 3.2.6 3.1.5 3.4.8'
|
||||
export PYVERSIONS='3.5.5 3.6.8 3.7.2 2.6.9 3.3.7 2.7.15 3.2.6 3.1.5 3.4.8'
|
||||
|
0
admin-tools/setup-master.sh
Executable file → Normal file
0
admin-tools/setup-master.sh
Executable file → Normal file
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
3
admin-tools/update-sources.sh
Executable file
3
admin-tools/update-sources.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname ${BASH_SOURCE[0]})/..
|
||||
git pull
|
@@ -30,7 +30,7 @@ def list_comp():
|
||||
[y for y in range(3)]
|
||||
|
||||
def get_parsed_for_fn(fn):
|
||||
code = fn.__code__ if PYTHON3 else fn.func_code
|
||||
code = fn.func_code
|
||||
return deparse(code, version=PYTHON_VERSION)
|
||||
|
||||
def check_expect(expect, parsed, fn_name):
|
||||
|
@@ -10,7 +10,7 @@ else:
|
||||
maxint = sys.maxint
|
||||
from uncompyle6.semantics.helper import print_docstring
|
||||
|
||||
class PrintFake():
|
||||
class PrintFake:
|
||||
def __init__(self):
|
||||
self.pending_newlines = 0
|
||||
self.f = StringIO()
|
||||
|
@@ -20,7 +20,7 @@ def bug_loop(disassemble, tb=None):
|
||||
disassemble(tb)
|
||||
|
||||
def test_if_in_for():
|
||||
code = bug.__code__
|
||||
code = bug.func_code
|
||||
scan = get_scanner(PYTHON_VERSION)
|
||||
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
|
||||
scan.build_instructions(code)
|
||||
|
@@ -1,154 +0,0 @@
|
||||
# std
|
||||
# test
|
||||
from uncompyle6 import PYTHON_VERSION, deparse_code
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skipif(PYTHON_VERSION <= 2.6,
|
||||
reason='hypothesis needs 2.7 or later')
|
||||
if PYTHON_VERSION > 2.6:
|
||||
|
||||
import hypothesis
|
||||
from hypothesis import strategies as st
|
||||
|
||||
# uncompyle6
|
||||
|
||||
|
||||
@st.composite
|
||||
def expressions(draw):
|
||||
# todo : would be nice to generate expressions using hypothesis however
|
||||
# this is pretty involved so for now just use a corpus of expressions
|
||||
# from which to select.
|
||||
return draw(st.sampled_from((
|
||||
'abc',
|
||||
'len(items)',
|
||||
'x + 1',
|
||||
'lineno',
|
||||
'container',
|
||||
'self.attribute',
|
||||
'self.method()',
|
||||
# These expressions are failing, I think these are control
|
||||
# flow problems rather than problems with FORMAT_VALUE,
|
||||
# however I need to confirm this...
|
||||
#'sorted(items, key=lambda x: x.name)',
|
||||
#'func(*args, **kwargs)',
|
||||
#'text or default',
|
||||
#'43 if life_the_universe and everything else None'
|
||||
)))
|
||||
|
||||
|
||||
@st.composite
|
||||
def format_specifiers(draw):
|
||||
"""
|
||||
Generate a valid format specifier using the rules:
|
||||
|
||||
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
|
||||
fill ::= <any character>
|
||||
align ::= "<" | ">" | "=" | "^"
|
||||
sign ::= "+" | "-" | " "
|
||||
width ::= integer
|
||||
precision ::= integer
|
||||
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
|
||||
|
||||
See https://docs.python.org/2/library/string.html
|
||||
|
||||
:param draw: Let hypothesis draw from other strategies.
|
||||
|
||||
:return: An example format_specifier.
|
||||
"""
|
||||
alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'))
|
||||
fill = draw(st.one_of(alphabet_strategy, st.none()))
|
||||
align = draw(st.sampled_from(list('<>=^')))
|
||||
fill_align = (fill + align or '') if fill else ''
|
||||
|
||||
type_ = draw(st.sampled_from('bcdeEfFgGnosxX%'))
|
||||
can_have_sign = type_ in 'deEfFgGnoxX%'
|
||||
can_have_comma = type_ in 'deEfFgG%'
|
||||
can_have_precision = type_ in 'fFgG'
|
||||
can_have_pound = type_ in 'boxX%'
|
||||
can_have_zero = type_ in 'oxX'
|
||||
|
||||
sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else ''
|
||||
pound = draw(st.sampled_from(('#', '',))) if can_have_pound else ''
|
||||
zero = draw(st.sampled_from(('0', '',))) if can_have_zero else ''
|
||||
|
||||
int_strategy = st.integers(min_value=1, max_value=1000)
|
||||
|
||||
width = draw(st.one_of(int_strategy, st.none()))
|
||||
width = str(width) if width is not None else ''
|
||||
|
||||
comma = draw(st.sampled_from((',', '',))) if can_have_comma else ''
|
||||
if can_have_precision:
|
||||
precision = draw(st.one_of(int_strategy, st.none()))
|
||||
precision = '.' + str(precision) if precision else ''
|
||||
else:
|
||||
precision = ''
|
||||
|
||||
return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,))
|
||||
|
||||
|
||||
@st.composite
|
||||
def fstrings(draw):
|
||||
"""
|
||||
Generate a valid f-string.
|
||||
See https://www.python.org/dev/peps/pep-0498/#specification
|
||||
|
||||
:param draw: Let hypothsis draw from other strategies.
|
||||
|
||||
:return: A valid f-string.
|
||||
"""
|
||||
character_strategy = st.characters(
|
||||
blacklist_characters='\r\n\'\\s{}',
|
||||
min_codepoint=1,
|
||||
max_codepoint=1000,
|
||||
)
|
||||
is_raw = draw(st.booleans())
|
||||
integer_strategy = st.integers(min_value=0, max_value=3)
|
||||
expression_count = draw(integer_strategy)
|
||||
content = []
|
||||
for _ in range(expression_count):
|
||||
expression = draw(expressions())
|
||||
conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
|
||||
has_specifier = draw(st.booleans())
|
||||
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
|
||||
content.append('{{{}{}}}'.format(expression, conversion, specifier))
|
||||
content.append(draw(st.text(character_strategy)))
|
||||
content = ''.join(content)
|
||||
return "f{}'{}'".format('r' if is_raw else '', content)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason='need Python 3.6')
|
||||
@hypothesis.given(format_specifiers())
|
||||
def test_format_specifiers(format_specifier):
|
||||
"""Verify that format_specifiers generates valid specifiers"""
|
||||
try:
|
||||
exec('"{:' + format_specifier + '}".format(0)')
|
||||
except ValueError as e:
|
||||
if 'Unknown format code' not in str(e):
|
||||
raise
|
||||
|
||||
|
||||
def run_test(text):
|
||||
hypothesis.assume(len(text))
|
||||
hypothesis.assume("f'{" in text)
|
||||
expr = text + '\n'
|
||||
code = compile(expr, '<string>', 'single')
|
||||
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
||||
recompiled = compile(deparsed.text, '<string>', 'single')
|
||||
if recompiled != code:
|
||||
assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')'
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason='need Python 3.6')
|
||||
@hypothesis.given(fstrings())
|
||||
def test_uncompyle_fstring(fstring):
|
||||
"""Verify uncompyling fstring bytecode"""
|
||||
run_test(fstring)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need Python 3.6+')
|
||||
@pytest.mark.parametrize('fstring', [
|
||||
"f'{abc}{abc!s}'",
|
||||
"f'{abc}0'",
|
||||
])
|
||||
def test_uncompyle_direct(fstring):
|
||||
"""useful for debugging"""
|
||||
run_test(fstring)
|
@@ -1,185 +0,0 @@
|
||||
import string
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
from hypothesis import given, assume, example, settings, strategies as st
|
||||
from validate import validate_uncompyle
|
||||
from test_fstring import expressions
|
||||
|
||||
alpha = st.sampled_from(string.ascii_lowercase)
|
||||
numbers = st.sampled_from(string.digits)
|
||||
alphanum = st.sampled_from(string.ascii_lowercase + string.digits)
|
||||
|
||||
|
||||
@st.composite
|
||||
def function_calls(draw,
|
||||
min_keyword_args=0, max_keyword_args=5,
|
||||
min_positional_args=0, max_positional_args=5,
|
||||
min_star_args=0, max_star_args=1,
|
||||
min_double_star_args=0, max_double_star_args=1):
|
||||
"""
|
||||
Strategy factory for generating function calls.
|
||||
|
||||
:param draw: Callable which draws examples from other strategies.
|
||||
|
||||
:return: The function call text.
|
||||
"""
|
||||
st_positional_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_positional_args,
|
||||
max_size=max_positional_args
|
||||
)
|
||||
st_keyword_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_keyword_args,
|
||||
max_size=max_keyword_args
|
||||
)
|
||||
st_star_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_star_args,
|
||||
max_size=max_star_args
|
||||
)
|
||||
st_double_star_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_double_star_args,
|
||||
max_size=max_double_star_args
|
||||
)
|
||||
|
||||
positional_args = draw(st_positional_args)
|
||||
keyword_args = draw(st_keyword_args)
|
||||
st_values = st.lists(
|
||||
expressions(),
|
||||
min_size=len(keyword_args),
|
||||
max_size=len(keyword_args)
|
||||
)
|
||||
keyword_args = [
|
||||
x + '=' + e
|
||||
for x, e in
|
||||
zip(keyword_args, draw(st_values))
|
||||
]
|
||||
star_args = ['*' + x for x in draw(st_star_args)]
|
||||
double_star_args = ['**' + x for x in draw(st_double_star_args)]
|
||||
|
||||
arguments = positional_args + keyword_args + star_args + double_star_args
|
||||
draw(st.randoms()).shuffle(arguments)
|
||||
arguments = ','.join(arguments)
|
||||
|
||||
function_call = 'fn({arguments})'.format(arguments=arguments)
|
||||
try:
|
||||
# TODO: Figure out the exact rules for ordering of positional, keyword,
|
||||
# star args, double star args and in which versions the various
|
||||
# types of arguments are supported so we don't need to check that the
|
||||
# expression compiles like this.
|
||||
compile(function_call, '<string>', 'single')
|
||||
except:
|
||||
assume(False)
|
||||
return function_call
|
||||
|
||||
|
||||
def test_function_no_args():
|
||||
validate_uncompyle("fn()")
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
def isolated_function_calls(which):
|
||||
"""
|
||||
Returns a strategy for generating function calls, but isolated to
|
||||
particular types of arguments, for example only positional arguments.
|
||||
|
||||
This can help reason about debugging errors in specific types of function
|
||||
calls.
|
||||
|
||||
:param which: One of 'keyword', 'positional', 'star', 'double_star'
|
||||
|
||||
:return: Strategy for generating an function call isolated to specific
|
||||
argument types.
|
||||
"""
|
||||
kwargs = dict(
|
||||
max_keyword_args=0,
|
||||
max_positional_args=0,
|
||||
max_star_args=0,
|
||||
max_double_star_args=0,
|
||||
)
|
||||
kwargs['_'.join(('min', which, 'args'))] = 1
|
||||
kwargs['_'.join(('max', which, 'args'))] = 5 if 'star' not in which else 1
|
||||
return function_calls(**kwargs)
|
||||
|
||||
|
||||
with settings(max_examples=25):
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('positional'))
|
||||
@example("fn(0)")
|
||||
def test_function_positional_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('keyword'))
|
||||
@example("fn(a=0)")
|
||||
def test_function_call_keyword_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('star'))
|
||||
@example("fn(*items)")
|
||||
def test_function_call_star_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('double_star'))
|
||||
@example("fn(**{})")
|
||||
def test_function_call_double_star_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_CONST_KEY_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(w=0,m=0,**v)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(a=0,**g)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*g,**j)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*z,u=0)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(**a)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(b,b,b=0,*a)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*c,v)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_CONST_KEY_MAP_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(i=0,y=0,*p)")
|
||||
|
||||
|
||||
@pytest.mark.skip(reason='skipping property based test until all individual tests are passing')
|
||||
@given(function_calls())
|
||||
def test_function_call(function_call):
|
||||
validate_uncompyle(function_call)
|
@@ -7,7 +7,7 @@ def test_grammar():
|
||||
|
||||
def check_tokens(tokens, opcode_set):
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
remain_tokens = set([re.sub(r'_\d+$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_\d+$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$','', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
assert remain_tokens == set([]), \
|
||||
@@ -46,7 +46,6 @@ def test_grammar():
|
||||
unused_rhs.add("mkfunc_annotate")
|
||||
unused_rhs.add("dict_comp")
|
||||
unused_rhs.add("classdefdeco1")
|
||||
unused_rhs.add("tryelsestmtl")
|
||||
if PYTHON_VERSION >= 3.5:
|
||||
expect_right_recursive.add((('l_stmts',
|
||||
('lastl_stmt', 'come_froms', 'l_stmts'))))
|
||||
|
@@ -8,12 +8,8 @@ from uncompyle6.semantics.consts import (
|
||||
|
||||
if PYTHON3:
|
||||
from io import StringIO
|
||||
def iteritems(d):
|
||||
return d.items()
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
def iteritems(d):
|
||||
return d.iteritems()
|
||||
|
||||
from uncompyle6.semantics.pysource import SourceWalker as SourceWalker
|
||||
|
||||
@@ -30,7 +26,7 @@ def test_template_engine():
|
||||
# FIXME: and so on...
|
||||
|
||||
from uncompyle6.semantics.consts import (
|
||||
TABLE_DIRECT, TABLE_R,
|
||||
TABLE_R, TABLE_DIRECT,
|
||||
)
|
||||
|
||||
from uncompyle6.semantics.fragments import (
|
||||
@@ -44,7 +40,7 @@ def test_tables():
|
||||
(TABLE_DIRECT, 'TABLE_DIRECT', False),
|
||||
(TABLE_R, 'TABLE_R', False),
|
||||
(TABLE_DIRECT_FRAGMENT, 'TABLE_DIRECT_FRAGMENT', True)):
|
||||
for k, entry in iteritems(t):
|
||||
for k, entry in t.iteritems():
|
||||
if k in skip_for_now:
|
||||
continue
|
||||
fmt = entry[0]
|
||||
|
@@ -1,7 +1,4 @@
|
||||
import pytest
|
||||
from uncompyle6 import PYTHON_VERSION, code_deparse
|
||||
pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
def test_single_mode():
|
||||
|
2
pytest/testdata/if-2.7.right
vendored
2
pytest/testdata/if-2.7.right
vendored
@@ -9,4 +9,4 @@
|
||||
12 JUMP_FORWARD 0 'to 15'
|
||||
15_0 COME_FROM 12 '12'
|
||||
15 LOAD_CONST 0 None
|
||||
18 RETURN_VALUE
|
||||
18 RETURN_VALUE
|
||||
|
2
pytest/testdata/ifelse-2.7.right
vendored
2
pytest/testdata/ifelse-2.7.right
vendored
@@ -12,4 +12,4 @@
|
||||
18 STORE_NAME 2 'd'
|
||||
21_0 COME_FROM 12 '12'
|
||||
21 LOAD_CONST 2 None
|
||||
24 RETURN_VALUE
|
||||
24 RETURN_VALUE
|
||||
|
@@ -1,28 +1,25 @@
|
||||
# future
|
||||
from __future__ import print_function
|
||||
# std
|
||||
import os
|
||||
import difflib
|
||||
import subprocess
|
||||
import tempfile
|
||||
import functools
|
||||
from StringIO import StringIO
|
||||
|
||||
# uncompyle6 / xdis
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, deparse_code
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY, deparse_code
|
||||
# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
|
||||
from xdis.bytecode import Bytecode
|
||||
from xdis.main import get_opcode
|
||||
opc = get_opcode(PYTHON_VERSION, IS_PYPY)
|
||||
Bytecode = functools.partial(Bytecode, opc=opc)
|
||||
import six
|
||||
|
||||
if PYTHON3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
|
||||
def _dis_to_text(co):
|
||||
return Bytecode(co).dis()
|
||||
from StringIO import StringIO
|
||||
|
||||
try:
|
||||
import functools
|
||||
Bytecode = functools.partial(Bytecode, opc=opc)
|
||||
def _dis_to_text(co):
|
||||
return Bytecode(co).dis()
|
||||
except:
|
||||
pass
|
||||
|
||||
def print_diff(original, uncompyled):
|
||||
"""
|
||||
@@ -45,8 +42,11 @@ def print_diff(original, uncompyled):
|
||||
print('\nTo display diff highlighting run:\n pip install BeautifulSoup4')
|
||||
diff = difflib.HtmlDiff().make_table(*args)
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
f = tempfile.NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
f.write(str(diff).encode('utf-8'))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
try:
|
||||
print()
|
||||
@@ -63,8 +63,7 @@ def print_diff(original, uncompyled):
|
||||
print('\nFor side by side diff install elinks')
|
||||
diff = difflib.Differ().compare(original_lines, uncompyled_lines)
|
||||
print('\n'.join(diff))
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def are_instructions_equal(i1, i2):
|
||||
@@ -126,8 +125,9 @@ def validate_uncompyle(text, mode='exec'):
|
||||
original_text = text
|
||||
|
||||
deparsed = deparse_code(PYTHON_VERSION, original_code,
|
||||
|
||||
compile_mode=mode,
|
||||
out=six.StringIO(),
|
||||
out=StringIO(),
|
||||
is_pypy=IS_PYPY)
|
||||
uncompyled_text = deparsed.text
|
||||
uncompyled_code = compile(uncompyled_text, '<string>', 'exec')
|
||||
|
16
setup.py
16
setup.py
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
"""Setup script for the 'uncompyle6' distribution."""
|
||||
|
||||
import sys
|
||||
|
||||
SYS_VERSION = sys.version_info[0:2]
|
||||
if not ((2, 6) <= SYS_VERSION <= (3, 7)):
|
||||
mess = "Python Release 2.6 .. 3.7 are supported in this code branch."
|
||||
if ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess += ("\nFor your Python, version %s, use the python-2.4 code/branch." %
|
||||
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, 7)):
|
||||
mess += ("\nFor your Python, version %s, use the master code/branch." %
|
||||
sys.version[0:3])
|
||||
elif SYS_VERSION < (2, 4):
|
||||
mess += ("\nThis package is not supported for Python version %s."
|
||||
else:
|
||||
mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s."
|
||||
% sys.version[0:3])
|
||||
print(mess)
|
||||
raise Exception(mess)
|
||||
|
55
test-unit/test_grammar.py
Normal file
55
test-unit/test_grammar.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import re
|
||||
import unittest
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY # , PYTHON_VERSION
|
||||
from uncompyle6.parser import get_python_parser, python_parser
|
||||
|
||||
class TestGrammar(unittest.TestCase):
|
||||
def test_grammar(self):
|
||||
|
||||
def check_tokens(tokens, opcode_set):
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
remain_tokens = set([re.sub('_\d+$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$','', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
self.assertEqual(remain_tokens, set([]),
|
||||
"Remaining tokens %s\n====\n%s" % (remain_tokens, p.dump_grammar()))
|
||||
|
||||
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
|
||||
(lhs, rhs, tokens,
|
||||
right_recursive, dup_rhs) = p.check_sets()
|
||||
expect_lhs = set(['expr1024', 'pos_arg'])
|
||||
unused_rhs = set(['list', 'call', 'mkfunc',
|
||||
'mklambda',
|
||||
'unpack',])
|
||||
|
||||
expect_right_recursive = frozenset([('designList',
|
||||
('store', 'DUP_TOP', 'designList'))])
|
||||
expect_lhs.add('kwarg')
|
||||
|
||||
self.assertEqual(expect_lhs, set(lhs))
|
||||
self.assertEqual(unused_rhs, set(rhs))
|
||||
self.assertEqual(expect_right_recursive, right_recursive)
|
||||
|
||||
expect_dup_rhs = frozenset([('COME_FROM',), ('CONTINUE',), ('JUMP_ABSOLUTE',),
|
||||
('LOAD_CONST',),
|
||||
('JUMP_BACK',), ('JUMP_FORWARD',)])
|
||||
|
||||
reduced_dup_rhs = {}
|
||||
for k in dup_rhs:
|
||||
if k not in expect_dup_rhs:
|
||||
reduced_dup_rhs[k] = dup_rhs[k]
|
||||
pass
|
||||
pass
|
||||
for k in reduced_dup_rhs:
|
||||
print(k, reduced_dup_rhs[k])
|
||||
# assert not reduced_dup_rhs, reduced_dup_rhs
|
||||
|
||||
def test_dup_rule(self):
|
||||
import inspect
|
||||
python_parser(PYTHON_VERSION, inspect.currentframe().f_code,
|
||||
is_pypy=IS_PYPY,
|
||||
parser_debug={
|
||||
'dups': True, 'transition': False, 'reduce': False,
|
||||
'rules': False, 'errorstack': None, 'context': True})
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@@ -29,7 +29,7 @@ check:
|
||||
$(MAKE) check-$(PYTHON_VERSION)
|
||||
|
||||
#: Run working tests from Python 2.6 or 2.7
|
||||
check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short
|
||||
check-2.4 check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short
|
||||
|
||||
#: Run working tests from Python 3.0
|
||||
check-3.0: check-bytecode
|
||||
@@ -64,12 +64,10 @@ check-3.5: check-bytecode
|
||||
#: Run working tests from Python 3.6
|
||||
check-3.6: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6-run --verify-run
|
||||
|
||||
#: Run working tests from Python 3.7
|
||||
check-3.7: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run
|
||||
|
||||
# FIXME
|
||||
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
|
||||
@@ -91,9 +89,8 @@ check-bytecode-2:
|
||||
#: Check deparsing bytecode 3.x only
|
||||
check-bytecode-3:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 \
|
||||
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
|
||||
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-3.7 \
|
||||
--bytecode-pypy3.2
|
||||
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
|
||||
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-pypy3.2
|
||||
|
||||
#: Check deparsing on selected bytecode 3.x
|
||||
check-bytecode-3-short:
|
||||
@@ -269,6 +266,10 @@ check-native-short:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION)-run --verify-run $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.6's lib files known to be okay
|
||||
check-2.4-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.4 --verify $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.6's lib files known to be okay
|
||||
check-2.6-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.6 --weak-verify $(COMPILE)
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.2/10_del.pyc
Normal file
BIN
test/bytecode_2.2/10_del.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/01_ops.pyc
Normal file
BIN
test/bytecode_2.4/01_ops.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/01_triple_compare.pyc
Normal file
BIN
test/bytecode_2.4/01_triple_compare.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_unary_convert.pyc
Normal file
BIN
test/bytecode_2.4/02_unary_convert.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_yield_bug.pyc
Normal file
BIN
test/bytecode_2.4/02_yield_bug.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.4_run/04_try_else_confuse.pyc
Normal file
BIN
test/bytecode_2.4_run/04_try_else_confuse.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.
BIN
test/bytecode_2.5/06_setif_comprehension.pyc
Normal file
BIN
test/bytecode_2.5/06_setif_comprehension.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.
Binary file not shown.
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# Mode: -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
# Copyright (c) 2015, 2017 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
import dis, os.path
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6 import uncompyle
|
||||
from uncompyle6.main import decompile
|
||||
from xdis.magics import sysinfo2float
|
||||
import sys, inspect
|
||||
|
@@ -1,10 +0,0 @@
|
||||
# Python 2.4 (and before?) bug in handling unconditional "else if true"
|
||||
# Doesn't occur in Python > 2.4
|
||||
# From Issue #187
|
||||
def unconditional_if_true_24(foo):
|
||||
if not foo:
|
||||
pass
|
||||
elif 1:
|
||||
pass
|
||||
else:
|
||||
return None
|
7
test/simple_source/bug25/02_yield_bug.py
Normal file
7
test/simple_source/bug25/02_yield_bug.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# From 2.4 test_array.py
|
||||
# In Python 2.4 and earlier "yield" is not valid and instead
|
||||
# we must use "yield None". Bug was not adding "None"
|
||||
|
||||
def yield_bug():
|
||||
yield None
|
||||
return
|
19
test/simple_source/bug25/04_try_else_confuse.py
Normal file
19
test/simple_source/bug25/04_try_else_confuse.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# From 2.4 test_sax.py
|
||||
# Bug was distinguishing try from try/else
|
||||
|
||||
def verify_empty_attrs():
|
||||
gvqk = 3
|
||||
try:
|
||||
gvk = 1/0
|
||||
except ZeroDivisionError:
|
||||
gvk = 1
|
||||
|
||||
try:
|
||||
gvqk = 0
|
||||
except KeyError:
|
||||
gvqk = 1
|
||||
|
||||
# If try/else was used above the return will be 4
|
||||
return gvk + gvqk
|
||||
|
||||
assert 1 == verify_empty_attrs()
|
@@ -1,16 +0,0 @@
|
||||
# Bug in Python 2.7. Bug is bytecode for while loop having
|
||||
# two consecutive JUMP_BACKS at the end of 'elif' and 'while'
|
||||
# to the same place
|
||||
def PreprocessConditionalStatement(self, IfList, ReplacedLine):
|
||||
while self:
|
||||
if self.__Token:
|
||||
x = 1
|
||||
elif not IfList:
|
||||
if self <= 2:
|
||||
continue
|
||||
RegionSizeGuid = 3
|
||||
if not RegionSizeGuid:
|
||||
RegionLayoutLine = 5
|
||||
continue
|
||||
RegionLayoutLine = self.CurrentLineNumber
|
||||
return 1
|
@@ -1,22 +0,0 @@
|
||||
# Bug in Python 2.7 is code creating a (useless) JUMP_ABSOLUTE to the instruction right after
|
||||
# the "raise" which causes the
|
||||
|
||||
# RUNNABLE!
|
||||
def testit(a, b):
|
||||
if a:
|
||||
if not b:
|
||||
raise AssertionError("test JUMP_ABSOLUTE to next instruction")
|
||||
|
||||
def testit2(a, b):
|
||||
if a:
|
||||
if not b:
|
||||
raise AssertionError("test with dead code after raise")
|
||||
x = 10
|
||||
|
||||
testit(False, True)
|
||||
testit(False, False)
|
||||
testit(True, True)
|
||||
|
||||
testit2(False, True)
|
||||
testit2(False, False)
|
||||
testit2(True, True)
|
@@ -1,24 +0,0 @@
|
||||
# Bug based on 2.7 test_itertools.py but mis-decompiled in Python 3.x bytecode
|
||||
# The bug is confusing "try/else" with "try" as a result of the loop which causes
|
||||
# the end of the except to jump back to the beginning of the loop, outside of the
|
||||
# try. In 3.x we not distinguising this jump out of the loop with a jump to the
|
||||
# end of the "try".
|
||||
|
||||
# RUNNABLE!
|
||||
def testit(stmts):
|
||||
|
||||
# Bug was confusing When the except jumps back to the beginning of the block
|
||||
# to the beginning of this for loop
|
||||
x = 1
|
||||
results = []
|
||||
for stmt in stmts:
|
||||
try:
|
||||
x = eval(stmt)
|
||||
except SyntaxError:
|
||||
results.append(1)
|
||||
else:
|
||||
results.append(x)
|
||||
return results
|
||||
|
||||
results = testit(["1 + 2", "1 +"])
|
||||
assert results == [3, 1], "try with else failed"
|
@@ -1,15 +0,0 @@
|
||||
# Python 3 bug in not detecting the end bounds of if elif.
|
||||
def testit(b):
|
||||
if b == 1:
|
||||
a = 1
|
||||
elif b == 2:
|
||||
a = 2
|
||||
else:
|
||||
a = 4
|
||||
|
||||
return a
|
||||
|
||||
for x in (1, 2, 4):
|
||||
x = testit(x)
|
||||
assert x is not None, "Should have returned a value, not None"
|
||||
assert x == x
|
@@ -1,10 +0,0 @@
|
||||
# Bug in 3.6 and above.
|
||||
#Not detecting 2nd return is outside of
|
||||
# if/then. Fix was to ensure COME_FROM
|
||||
def return_return_bug(foo):
|
||||
if foo =='say_hello':
|
||||
return "hello"
|
||||
return "world"
|
||||
|
||||
assert return_return_bug('say_hello') == 'hello'
|
||||
assert return_return_bug('world') == 'world'
|
@@ -1,16 +0,0 @@
|
||||
# Bug in 3.6 was not taking "else" branch after compond "if"
|
||||
# In earlier versions we had else detection needed here.
|
||||
|
||||
def f(a, b, c):
|
||||
if a and b:
|
||||
x = 1
|
||||
else:
|
||||
x = 2
|
||||
if c:
|
||||
x = 3
|
||||
return(x)
|
||||
|
||||
assert f(True, True, True) == 3
|
||||
assert f(True, True, False) == 1
|
||||
assert f(True, False, True) == 3
|
||||
assert f(True, False, False) == 2
|
@@ -1,8 +0,0 @@
|
||||
# The bug in python 3.6+ was in parsing that we
|
||||
# add END_IF_THEN and using that inside "return results"
|
||||
def whcms_license_info(md5hash, datahash, results):
|
||||
if md5hash == datahash:
|
||||
try:
|
||||
return md5hash
|
||||
except:
|
||||
return results
|
@@ -1,9 +0,0 @@
|
||||
# Bug in Python 3.6 and 3.7 was getting comma before **kw
|
||||
|
||||
def fn(arg, *, kwarg='test', **kw):
|
||||
assert arg == 1
|
||||
assert kwarg == 'testing'
|
||||
assert kw['foo'] == 'bar'
|
||||
|
||||
|
||||
fn(1, kwarg='testing', foo='bar')
|
@@ -1,19 +0,0 @@
|
||||
# From Python 3.7 pickle.py
|
||||
# Bug was different code generation for chained comparisons than prior Python versions
|
||||
|
||||
|
||||
def chained_compare_a(protocol):
|
||||
if not 0 <= protocol <= 7:
|
||||
raise ValueError("pickle protocol must be <= %d" % 7)
|
||||
|
||||
def chained_compare_b(a, obj):
|
||||
if a:
|
||||
if -0x80000000 <= obj <= 0x7fffffff:
|
||||
return 5
|
||||
|
||||
chained_compare_a(3)
|
||||
try:
|
||||
chained_compare_a(8)
|
||||
except ValueError:
|
||||
pass
|
||||
chained_compare_b(True, 0x0)
|
@@ -43,10 +43,10 @@ case $PYVERSION in
|
||||
2.5)
|
||||
SKIP_TESTS=(
|
||||
[test_contextlib.py]=1 # Syntax error - look at
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
|
@@ -20,8 +20,7 @@ Step 2: Run the test:
|
||||
test_pyenvlib --mylib --verify # decompile verify 'mylib'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6 import main, PYTHON3
|
||||
import os, time, re, shutil, sys
|
||||
from fnmatch import fnmatch
|
||||
|
||||
|
@@ -27,8 +27,6 @@ Step 2: Run the test:
|
||||
test_pythonlib.py --mylib --verify # decompile verify 'mylib'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import getopt, os, py_compile, sys, shutil, tempfile, time
|
||||
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
@@ -130,8 +128,10 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
if opts['do_compile']:
|
||||
compiled_version = opts['compiled_version']
|
||||
if compiled_version and PYTHON_VERSION != compiled_version:
|
||||
print("Not compiling: desired Python version is %s but we are running %s" %
|
||||
(compiled_version, PYTHON_VERSION), file=sys.stderr)
|
||||
sys.stderr.write("Not compiling: "
|
||||
"desired Python version is %s "
|
||||
"but we are running %s" %
|
||||
(compiled_version, PYTHON_VERSION))
|
||||
else:
|
||||
for root, dirs, basenames in os.walk(src_dir):
|
||||
file_matches(files, root, basenames, PY)
|
||||
@@ -149,8 +149,8 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
file_matches(files, dirname, basenames, obj_patterns)
|
||||
|
||||
if not files:
|
||||
print("Didn't come up with any files to test! Try with --compile?",
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Didn't come up with any files to test! "
|
||||
"Try with --compile?")
|
||||
exit(1)
|
||||
|
||||
os.chdir(cwd)
|
||||
@@ -164,9 +164,9 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
print(time.ctime())
|
||||
print('Source directory: ', src_dir)
|
||||
print('Output directory: ', target_dir)
|
||||
print time.ctime()
|
||||
print 'Source directory: ', src_dir
|
||||
print 'Output directory: ', target_dir
|
||||
try:
|
||||
_, _, failed_files, failed_verify = \
|
||||
main(src_dir, target_dir, files, [],
|
||||
@@ -242,14 +242,13 @@ if __name__ == '__main__':
|
||||
if os.path.isdir(src_dir):
|
||||
checked_dirs.append([src_dir, pattern, target_dir])
|
||||
else:
|
||||
print("Can't find directory %s. Skipping" % src_dir,
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Can't find directory %s. Skipping" % src_dir)
|
||||
continue
|
||||
last_compile_version = compiled_version
|
||||
pass
|
||||
|
||||
if not checked_dirs:
|
||||
print("No directories found to check", file=sys.stderr)
|
||||
sys.stderr.write("No directories found to check\n")
|
||||
sys.exit(1)
|
||||
|
||||
test_opts['compiled_version'] = last_compile_version
|
||||
|
2
tox.ini
2
tox.ini
@@ -3,7 +3,7 @@
|
||||
[flake8]
|
||||
exclude = .tox,./build,./trepan/processor/command/tmp
|
||||
filename = *.py
|
||||
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E402,E501,F401,E701,E702
|
||||
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E501,F401,E701,E702
|
||||
|
||||
[tox]
|
||||
envlist = py27, py34, pypy
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#
|
||||
# Copyright (c) 2015-2016, 2018 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
import sys, os, getopt
|
||||
|
||||
from uncompyle6.disas import disassemble_file
|
||||
@@ -13,8 +12,8 @@ program, ext = os.path.splitext(os.path.basename(__file__))
|
||||
|
||||
__doc__ = """
|
||||
Usage:
|
||||
{0} [OPTIONS]... FILE
|
||||
{0} [--help | -h | -V | --version]
|
||||
%s [OPTIONS]... FILE
|
||||
%s [--help | -h | -V | --version]
|
||||
|
||||
Disassemble FILE with the instruction mangling that is done to
|
||||
assist uncompyle6 in parsing the instruction stream. For example
|
||||
@@ -23,9 +22,9 @@ BUILD_LIST have arguement counts appended to the instruction name, and
|
||||
COME_FROM instructions are inserted into the instruction stream.
|
||||
|
||||
Examples:
|
||||
{0} foo.pyc
|
||||
{0} foo.py # same thing as above but find the file
|
||||
{0} foo.pyc bar.pyc # disassemble foo.pyc and bar.pyc
|
||||
%s foo.pyc
|
||||
%s foo.py # same thing as above but find the file
|
||||
%s foo.pyc bar.pyc # disassemble foo.pyc and bar.pyc
|
||||
|
||||
See also `pydisasm' from the `xdis' package.
|
||||
|
||||
@@ -33,7 +32,7 @@ Options:
|
||||
-V | --version show version and stop
|
||||
-h | --help show this message
|
||||
|
||||
""".format(program)
|
||||
""" % ((program,) * 5)
|
||||
|
||||
PATTERNS = ('*.pyc', '*.pyo')
|
||||
|
||||
@@ -42,15 +41,15 @@ def main():
|
||||
Type -h for for full help.""" % program
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print("No file(s) given", file=sys.stderr)
|
||||
print(Usage_short, file=sys.stderr)
|
||||
sys.stderr.write("No file(s) given\n")
|
||||
sys.stderr.write(Usage_short)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
opts, files = getopt.getopt(sys.argv[1:], 'hVU',
|
||||
['help', 'version', 'uncompyle6'])
|
||||
except getopt.GetoptError as e:
|
||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||
except getopt.GetoptError(e):
|
||||
sys.stderr.write('%s: %s' % (os.path.basename(sys.argv[0]), e))
|
||||
sys.exit(-1)
|
||||
|
||||
for opt, val in opts:
|
||||
@@ -62,15 +61,14 @@ Type -h for for full help.""" % program
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(opt)
|
||||
print(Usage_short, file=sys.stderr)
|
||||
sys.stderr.write(Usage_short)
|
||||
sys.exit(1)
|
||||
|
||||
for file in files:
|
||||
if os.path.exists(files[0]):
|
||||
disassemble_file(file, sys.stdout)
|
||||
else:
|
||||
print("Can't read %s - skipping" % files[0],
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Can't read %s - skipping\n" % files[0])
|
||||
pass
|
||||
pass
|
||||
return
|
||||
|
@@ -4,7 +4,6 @@
|
||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
import sys, os, getopt, time
|
||||
|
||||
program = 'uncompyle6'
|
||||
@@ -69,13 +68,9 @@ def usage():
|
||||
|
||||
|
||||
def main_bin():
|
||||
if not (sys.version_info[0:2] in ((2, 6), (2, 7), (3, 0),
|
||||
(3, 1), (3, 2), (3, 3),
|
||||
(3, 4), (3, 5), (3, 6),
|
||||
(3, 7)
|
||||
)):
|
||||
print('Error: %s requires Python 2.6-3.7' % program,
|
||||
file=sys.stderr)
|
||||
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)
|
||||
sys.exit(-1)
|
||||
|
||||
do_verify = recurse_dirs = False
|
||||
@@ -93,8 +88,8 @@ def main_bin():
|
||||
'fragments verify verify-run version '
|
||||
'weak-verify '
|
||||
'showgrammar'.split(' '))
|
||||
except getopt.GetoptError as e:
|
||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||
except getopt.GetoptError(e):
|
||||
sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e))
|
||||
sys.exit(-1)
|
||||
|
||||
options = {}
|
||||
@@ -137,7 +132,7 @@ def main_bin():
|
||||
elif opt in ('--recurse', '-r'):
|
||||
recurse_dirs = True
|
||||
else:
|
||||
print(opt, file=sys.stderr)
|
||||
sys.stderr.write(opt)
|
||||
usage()
|
||||
|
||||
# expand directory if specified
|
||||
@@ -162,7 +157,7 @@ def main_bin():
|
||||
files = [f[sb_len:] for f in files]
|
||||
|
||||
if not files:
|
||||
print("No files given", file=sys.stderr)
|
||||
sys.stderr.write("No files given\n")
|
||||
usage()
|
||||
|
||||
if outfile == '-':
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2016, 2818-2019 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2016, 2818 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
|
||||
@@ -29,8 +29,6 @@ Second, we need structured instruction information for the
|
||||
want to run on earlier Python versions.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from collections import deque
|
||||
|
||||
@@ -49,10 +47,9 @@ def disco(version, co, out=None, is_pypy=False):
|
||||
|
||||
# store final output stream for case of error
|
||||
real_out = out or sys.stdout
|
||||
print('# Python %s' % version, file=real_out)
|
||||
real_out.write('# Python %s\n' % version)
|
||||
if co.co_filename:
|
||||
print('# Embedded file name: %s' % co.co_filename,
|
||||
file=real_out)
|
||||
real_out.write('# Embedded file name: %s\n' % co.co_filename)
|
||||
|
||||
scanner = get_scanner(version, is_pypy=is_pypy)
|
||||
|
||||
@@ -64,31 +61,30 @@ def disco_loop(disasm, queue, real_out):
|
||||
while len(queue) > 0:
|
||||
co = queue.popleft()
|
||||
if co.co_name != '<module>':
|
||||
print('\n# %s line %d of %s' %
|
||||
(co.co_name, co.co_firstlineno, co.co_filename),
|
||||
file=real_out)
|
||||
real_out.write('\n# %s line %d of %s\n' %
|
||||
(co.co_name, co.co_firstlineno, co.co_filename))
|
||||
tokens, customize = disasm(co)
|
||||
for t in tokens:
|
||||
if iscode(t.pattr):
|
||||
queue.append(t.pattr)
|
||||
elif iscode(t.attr):
|
||||
queue.append(t.attr)
|
||||
print(t, file=real_out)
|
||||
real_out.write(t)
|
||||
pass
|
||||
pass
|
||||
|
||||
# def disassemble_fp(fp, outstream=None):
|
||||
# """
|
||||
# disassemble Python byte-code from an open file
|
||||
# """
|
||||
# (version, timestamp, magic_int, co, is_pypy,
|
||||
# source_size) = load_from_fp(fp)
|
||||
# if type(co) == list:
|
||||
# for con in co:
|
||||
# disco(version, con, outstream)
|
||||
# else:
|
||||
# disco(version, co, outstream, is_pypy=is_pypy)
|
||||
# co = None
|
||||
def disassemble_fp(fp, outstream=None):
|
||||
"""
|
||||
disassemble Python byte-code from an open file
|
||||
"""
|
||||
(version, timestamp, magic_int, co, is_pypy,
|
||||
source_size) = load_from_fp(fp)
|
||||
if type(co) == list:
|
||||
for con in co:
|
||||
disco(version, con, outstream)
|
||||
else:
|
||||
disco(version, co, outstream, is_pypy=is_pypy)
|
||||
co = None
|
||||
|
||||
def disassemble_file(filename, outstream=None):
|
||||
"""
|
||||
@@ -120,6 +116,5 @@ def _test():
|
||||
fn = sys.argv[1]
|
||||
disassemble_file(fn)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test()
|
||||
|
@@ -25,7 +25,7 @@ def line_number_mapping(pyc_filename, src_filename):
|
||||
source_size) = load_module(pyc_filename)
|
||||
try:
|
||||
code2 = load_file(src_filename)
|
||||
except SyntaxError as e:
|
||||
except SyntaxError, e:
|
||||
return str(e)
|
||||
|
||||
queue = deque([code1, code2])
|
||||
|
@@ -12,10 +12,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from __future__ import print_function
|
||||
import datetime, os, subprocess, sys, tempfile
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
||||
import datetime, os, subprocess, sys
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY
|
||||
from xdis.code import iscode
|
||||
from xdis.magics import sysinfo2float
|
||||
from uncompyle6.disas import check_object_path
|
||||
@@ -39,10 +39,7 @@ def _get_outstream(outfile):
|
||||
os.makedirs(dir)
|
||||
except OSError:
|
||||
pass
|
||||
if PYTHON_VERSION < 3.0:
|
||||
return open(outfile, mode='wb')
|
||||
else:
|
||||
return open(outfile, mode='w', encoding='utf-8')
|
||||
return open(outfile, 'wb')
|
||||
|
||||
def decompile(
|
||||
bytecode_version, co, out=None, showasm=None, showast=False,
|
||||
@@ -69,20 +66,35 @@ def decompile(
|
||||
|
||||
assert iscode(co)
|
||||
|
||||
co_pypy_str = 'PyPy ' if is_pypy else ''
|
||||
run_pypy_str = 'PyPy ' if IS_PYPY else ''
|
||||
if is_pypy:
|
||||
co_pypy_str = 'PyPy '
|
||||
else:
|
||||
co_pypy_str = ''
|
||||
|
||||
if IS_PYPY:
|
||||
run_pypy_str = 'PyPy '
|
||||
else:
|
||||
run_pypy_str = ''
|
||||
|
||||
if magic_int:
|
||||
m = str(magic_int)
|
||||
else:
|
||||
m = ""
|
||||
|
||||
sys_version_lines = sys.version.split('\n')
|
||||
write('# uncompyle6 version %s\n'
|
||||
'# %sPython bytecode %s%s\n# Decompiled from: %sPython %s' %
|
||||
(VERSION, co_pypy_str, bytecode_version,
|
||||
" (%s)" % str(magic_int) if magic_int else "",
|
||||
run_pypy_str, '\n# '.join(sys_version_lines)))
|
||||
" (%s)" % m, run_pypy_str,
|
||||
'\n# '.join(sys_version_lines)))
|
||||
if co.co_filename:
|
||||
write('# Embedded file name: %s' % co.co_filename,)
|
||||
if timestamp:
|
||||
write('# Compiled at: %s' % datetime.datetime.fromtimestamp(timestamp))
|
||||
write('# Compiled at: %s' %
|
||||
datetime.datetime.fromtimestamp(timestamp))
|
||||
if source_size:
|
||||
write('# Size of source mod 2**32: %d bytes' % source_size)
|
||||
real_out.write('# Size of source mod 2**32: %d bytes\n' %
|
||||
source_size)
|
||||
|
||||
debug_opts = {
|
||||
'asm': showasm,
|
||||
@@ -115,7 +127,7 @@ def decompile(
|
||||
is_pypy=is_pypy)
|
||||
pass
|
||||
return deparsed
|
||||
except pysource.SourceWalkerError as e:
|
||||
except pysource.SourceWalkerError, e:
|
||||
# deparsing failed
|
||||
raise pysource.SourceWalkerError(str(e))
|
||||
|
||||
@@ -197,17 +209,10 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
prefix = prefix[:-len('.py')]
|
||||
|
||||
# Unbuffer output if possible
|
||||
buffering = -1 if sys.stdout.isatty() else 0
|
||||
if PYTHON_VERSION >= 3.5:
|
||||
t = tempfile.NamedTemporaryFile(mode='w+b',
|
||||
buffering=buffering,
|
||||
suffix='.py',
|
||||
prefix=prefix)
|
||||
if sys.stdout.isatty():
|
||||
buffering = -1
|
||||
else:
|
||||
t = tempfile.NamedTemporaryFile(mode='w+b',
|
||||
suffix='.py',
|
||||
prefix=prefix)
|
||||
current_outfile = t.name
|
||||
buffering = 0
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering)
|
||||
tee = subprocess.Popen(["tee", current_outfile],
|
||||
stdin=subprocess.PIPE)
|
||||
@@ -246,9 +251,9 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
pass
|
||||
pass
|
||||
tot_files += 1
|
||||
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e:
|
||||
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError):
|
||||
sys.stdout.write("\n")
|
||||
sys.stderr.write("\n# file %s\n# %s\n" % (infile, e))
|
||||
sys.stderr.write("# file %s\n" % (infile))
|
||||
failed_files += 1
|
||||
tot_files += 1
|
||||
except KeyboardInterrupt:
|
||||
@@ -286,13 +291,16 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
else:
|
||||
okay_files += 1
|
||||
pass
|
||||
except verify.VerifyCmpError as e:
|
||||
except verify.VerifyCmpError, e:
|
||||
print(e)
|
||||
verify_failed_files += 1
|
||||
os.rename(current_outfile, current_outfile + '_unverified')
|
||||
sys.stderr.write("### Error Verifying %s\n" % filename)
|
||||
sys.stderr.write(str(e) + "\n")
|
||||
if not outfile:
|
||||
sys.stderr.write("### Error Verifiying %s" %
|
||||
filename)
|
||||
sys.stderr.write(e)
|
||||
if raise_on_error:
|
||||
raise
|
||||
pass
|
||||
@@ -302,31 +310,23 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
okay_files += 1
|
||||
pass
|
||||
elif do_verify:
|
||||
sys.stderr.write("\n### uncompile successful, but no file to compare against\n")
|
||||
sys.stderr.write("\n### uncompile successful, "
|
||||
"but no file to compare against")
|
||||
pass
|
||||
else:
|
||||
okay_files += 1
|
||||
if not current_outfile:
|
||||
mess = '\n# okay decompiling'
|
||||
# mem_usage = __memUsage()
|
||||
print(mess, infile)
|
||||
print mess, infile
|
||||
if current_outfile:
|
||||
sys.stdout.write("%s\r" %
|
||||
status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
verify_failed_files, do_verify))
|
||||
try:
|
||||
# FIXME: Something is weird with Pypy here
|
||||
sys.stdout.flush()
|
||||
except:
|
||||
pass
|
||||
sys.stdout.flush()
|
||||
if current_outfile:
|
||||
sys.stdout.write("\n")
|
||||
try:
|
||||
# FIXME: Something is weird with Pypy here
|
||||
sys.stdout.flush()
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
sys.stdout.flush()
|
||||
return (tot_files, okay_files, failed_files, verify_failed_files)
|
||||
|
||||
|
||||
|
@@ -19,8 +19,6 @@
|
||||
Common uncompyle6 parser routines.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
from xdis.code import iscode
|
||||
@@ -37,9 +35,7 @@ class ParserError(Exception):
|
||||
return "Parse error at or near `%r' instruction at offset %s\n" % \
|
||||
(self.token, self.offset)
|
||||
|
||||
|
||||
def nop_func(self, args):
|
||||
return None
|
||||
nop_func = lambda self, args: None
|
||||
|
||||
class PythonParser(GenericASTBuilder):
|
||||
|
||||
@@ -188,7 +184,7 @@ class PythonParser(GenericASTBuilder):
|
||||
indent = ' '
|
||||
else:
|
||||
indent = '-> '
|
||||
print("%s%s" % (indent, instructions[i]))
|
||||
print "%s%s" % (indent, instructions[i])
|
||||
raise ParserError(err_token, err_token.offset)
|
||||
else:
|
||||
raise ParserError(None, -1)
|
||||
@@ -794,7 +790,6 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
|
||||
p = get_python_parser(version, parser_debug)
|
||||
return parse(p, tokens, customize)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def parse_test(co):
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY
|
||||
@@ -802,4 +797,4 @@ if __name__ == '__main__':
|
||||
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
|
||||
print(ast)
|
||||
return
|
||||
parse_test(parse_test.__code__)
|
||||
# parse_test(parse_test.__code__)
|
||||
|
@@ -25,8 +25,6 @@ If we succeed in creating a parse tree, then we have a Python program
|
||||
that a later phase can turn into a sequence of ASCII text.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
@@ -533,11 +531,14 @@ class Python2Parser(PythonParser):
|
||||
# Dead code testing...
|
||||
# if lhs == 'while1elsestmt':
|
||||
# from trepan.api import debug; debug()
|
||||
|
||||
if lhs in ('aug_assign1', 'aug_assign2') and ast[0] and ast[0][0] in ('and', 'or'):
|
||||
return True
|
||||
elif lhs in ('raise_stmt1',):
|
||||
# We will assume 'LOAD_ASSERT' will be handled by an assert grammar rule
|
||||
return (tokens[first] == 'LOAD_ASSERT' and (last >= len(tokens)))
|
||||
# We will assme 'LOAD_ASSERT' will be handled by an assert grammar rule
|
||||
return (tokens[first] == 'LOAD_ASSERT' and
|
||||
(last >= len(tokens) or tokens[last] not in
|
||||
('COME_FROM', 'JUMP_BACK','JUMP_FORWARD')))
|
||||
elif rule == ('or', ('expr', 'jmp_true', 'expr', '\\e_come_from_opt')):
|
||||
expr2 = ast[2]
|
||||
return expr2 == 'expr' and expr2[0] == 'LOAD_ASSERT'
|
||||
|
@@ -87,15 +87,6 @@ class Python24Parser(Python25Parser):
|
||||
l = len(tokens)
|
||||
if 0 <= l < len(tokens):
|
||||
return not int(tokens[first].pattr) == tokens[last].offset
|
||||
elif lhs == 'try_except':
|
||||
if last == len(tokens):
|
||||
last -= 1
|
||||
if tokens[last] != 'COME_FROM' and tokens[last-1] == 'COME_FROM':
|
||||
last -= 1
|
||||
return (tokens[last] == 'COME_FROM'
|
||||
and tokens[last-1] == 'END_FINALLY'
|
||||
and tokens[last-2] == 'POP_TOP'
|
||||
and tokens[last-3].kind != 'JUMP_FORWARD')
|
||||
|
||||
return False
|
||||
|
||||
|
@@ -19,6 +19,9 @@ class Python25Parser(Python26Parser):
|
||||
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF JUMP_BACK
|
||||
|
||||
# We have no jumps to jumps, so no "come_froms" but a single "COME_FROM"
|
||||
ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite COME_FROM
|
||||
|
||||
# Python 2.6 uses ROT_TWO instead of the STORE_xxx
|
||||
# withas is allowed as a "from future" in 2.5
|
||||
# 2.6 and 2.7 do something slightly different
|
||||
@@ -36,6 +39,8 @@ class Python25Parser(Python26Parser):
|
||||
# loop. FIXME: should "come_froms" below be a single COME_FROM?
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite come_froms
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel
|
||||
|
||||
# Python 2.6 omits the LOAD_FAST DELETE_FAST below
|
||||
# withas is allowed as a "from future" in 2.5
|
||||
@@ -54,6 +59,9 @@ class Python25Parser(Python26Parser):
|
||||
def customize_grammar_rules(self, tokens, customize):
|
||||
# Remove grammar rules inherited from Python 2.6 or Python 2
|
||||
self.remove_rules("""
|
||||
# No jump to jumps in 2.4 so we have a single "COME_FROM", not "come_froms"
|
||||
ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite come_froms
|
||||
|
||||
setupwith ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 POP_TOP
|
||||
withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY
|
||||
@@ -85,17 +93,15 @@ class Python25Parser(Python26Parser):
|
||||
super(Python25Parser, self).customize_grammar_rules(tokens, customize)
|
||||
if self.version == 2.5:
|
||||
self.check_reduce['try_except'] = 'tokens'
|
||||
self.check_reduce['aug_assign1'] = 'AST'
|
||||
|
||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
invalid = super(Python25Parser,
|
||||
self).reduce_is_invalid(rule, ast,
|
||||
tokens, first, last)
|
||||
if invalid or tokens is None:
|
||||
return invalid
|
||||
if rule == ('aug_assign1', ('expr', 'expr', 'inplace_op', 'store')):
|
||||
return ast[0][0] == 'and'
|
||||
return False
|
||||
## Don't need this for 2.5 yet..
|
||||
# def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
# invalid = super(Python25Parser,
|
||||
# self).reduce_is_invalid(rule, ast,
|
||||
# tokens, first, last)
|
||||
# if invalid or tokens is None:
|
||||
# return invalid
|
||||
# return False
|
||||
|
||||
|
||||
class Python25ParserSingle(Python26Parser, PythonParserSingle):
|
||||
|
@@ -1,10 +1,9 @@
|
||||
# Copyright (c) 2016-2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2018 Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <hartmut@goebel.noris.de>
|
||||
|
||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
from xdis import next_offset
|
||||
from uncompyle6.parser import PythonParserSingle, nop_func
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from uncompyle6.parsers.parse2 import Python2Parser
|
||||
|
||||
class Python27Parser(Python2Parser):
|
||||
@@ -156,13 +155,7 @@ class Python27Parser(Python2Parser):
|
||||
|
||||
while1stmt ::= SETUP_LOOP returns bp_come_from
|
||||
while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM
|
||||
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms
|
||||
|
||||
# Should this be JUMP_BACK+ ?
|
||||
# JUMP_BACK should all be to the same location
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK _come_froms
|
||||
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_BLOCK
|
||||
else_suitel COME_FROM
|
||||
whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
||||
@@ -203,13 +196,6 @@ class Python27Parser(Python2Parser):
|
||||
POP_BLOCK LOAD_CONST COME_FROM suite_stmts_opt
|
||||
END_FINALLY
|
||||
""")
|
||||
if 'PyPy' in customize:
|
||||
# PyPy-specific customizations
|
||||
self.addRule("""
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF come_froms
|
||||
""", nop_func)
|
||||
|
||||
|
||||
super(Python27Parser, self).customize_grammar_rules(tokens, customize)
|
||||
self.check_reduce['and'] = 'AST'
|
||||
# self.check_reduce['or'] = 'AST'
|
||||
@@ -217,17 +203,14 @@ class Python27Parser(Python2Parser):
|
||||
self.check_reduce['list_if_not'] = 'AST'
|
||||
self.check_reduce['list_if'] = 'AST'
|
||||
self.check_reduce['conditional_true'] = 'AST'
|
||||
self.check_reduce['whilestmt'] = 'tokens'
|
||||
return
|
||||
|
||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
invalid = super(Python27Parser,
|
||||
self).reduce_is_invalid(rule, ast,
|
||||
tokens, first, last)
|
||||
|
||||
if invalid:
|
||||
return invalid
|
||||
|
||||
if rule == ('and', ('expr', 'jmp_false', 'expr', '\\e_come_from_opt')):
|
||||
# Test that jmp_false jumps to the end of "and"
|
||||
# or that it jumps to the same place as the end of "and"
|
||||
@@ -237,12 +220,6 @@ class Python27Parser(Python2Parser):
|
||||
tokens[last].pattr == jmp_false.pattr)
|
||||
elif rule[0] == ('raise_stmt1'):
|
||||
return ast[0] == 'expr' and ast[0][0] == 'or'
|
||||
elif rule[0] in ('assert', 'assert2'):
|
||||
jump_inst = ast[1][0]
|
||||
jump_target = jump_inst.attr
|
||||
return not (last >= len(tokens)
|
||||
or jump_target == tokens[last].offset
|
||||
or jump_target == next_offset(ast[-1].op, ast[-1].opc, ast[-1].offset))
|
||||
elif rule == ('list_if_not', ('expr', 'jmp_true', 'list_iter')):
|
||||
jump_inst = ast[1][0]
|
||||
jump_offset = jump_inst.attr
|
||||
@@ -258,16 +235,6 @@ class Python27Parser(Python2Parser):
|
||||
jmp_target = jmp_true.offset + jmp_true.attr + 3
|
||||
return not (jmp_target == tokens[last].offset or
|
||||
tokens[last].pattr == jmp_true.pattr)
|
||||
|
||||
elif (rule[0] == 'whilestmt' and
|
||||
rule[1][0:-2] ==
|
||||
('SETUP_LOOP', 'testexpr', 'l_stmts_opt',
|
||||
'JUMP_BACK', 'JUMP_BACK')):
|
||||
# Make sure that the jump backs all go to the same place
|
||||
i = last-1
|
||||
while (tokens[i] != 'JUMP_BACK'):
|
||||
i -= 1
|
||||
return tokens[i].attr != tokens[i-1].attr
|
||||
# elif rule[0] == ('conditional_true'):
|
||||
# # FIXME: the below is a hack: we check expr for
|
||||
# # nodes that could have possibly been a been a Boolean.
|
||||
@@ -302,4 +269,5 @@ if __name__ == '__main__':
|
||||
for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
print(remain_tokens)
|
||||
# p.dump_grammar()
|
||||
p.check_grammar()
|
||||
p.dump_grammar()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2019 Rocky Bernstein
|
||||
# Copyright (c) 2015-2018 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
|
||||
@@ -26,11 +26,11 @@ If we succeed in creating a parse tree, then we have a Python program
|
||||
that a later phase can turn into a sequence of ASCII text.
|
||||
"""
|
||||
|
||||
from uncompyle6.scanners.tok import Token
|
||||
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
|
||||
from uncompyle6.parsers.treenode import SyntaxTree
|
||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
from xdis import PYTHON3
|
||||
from itertools import islice,chain,repeat
|
||||
|
||||
class Python3Parser(PythonParser):
|
||||
|
||||
@@ -185,11 +185,23 @@ class Python3Parser(PythonParser):
|
||||
# one COME_FROM for Python 2.7 seems to associate the
|
||||
# COME_FROM targets from the wrong places
|
||||
|
||||
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler opt_come_from_except
|
||||
|
||||
# this is nested inside a try_except
|
||||
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST
|
||||
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
||||
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite come_from_except_clauses
|
||||
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite come_froms
|
||||
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel come_from_except_clauses
|
||||
|
||||
except_handler ::= jmp_abs COME_FROM except_stmts
|
||||
END_FINALLY
|
||||
except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
|
||||
@@ -309,7 +321,7 @@ class Python3Parser(PythonParser):
|
||||
# FIXME: Common with 2.7
|
||||
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 COME_FROM ret_expr_or_cond
|
||||
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
|
||||
|
||||
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
|
||||
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
|
||||
@@ -552,10 +564,9 @@ class Python3Parser(PythonParser):
|
||||
# include instructions that don't need customization,
|
||||
# but we'll do a finer check after the rough breakout.
|
||||
customize_instruction_basenames = frozenset(
|
||||
('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET',
|
||||
'JUMP', 'LOAD', 'LOOKUP', 'MAKE',
|
||||
'RETURN', 'RAISE', 'SETUP',
|
||||
'UNPACK'))
|
||||
('BUILD', 'CALL', 'CONTINUE', 'DELETE', 'GET',
|
||||
'JUMP', 'LOAD', 'LOOKUP', 'MAKE',
|
||||
'RETURN', 'RAISE', 'UNPACK'))
|
||||
|
||||
# Opcode names in the custom_ops_processed set have rules that get added
|
||||
# unconditionally and the rules are constant. So they need to be done
|
||||
@@ -583,6 +594,7 @@ class Python3Parser(PythonParser):
|
||||
stmt ::= assign2_pypy
|
||||
assign3_pypy ::= expr expr expr store store store
|
||||
assign2_pypy ::= expr expr store store
|
||||
return_if_lambda ::= RETURN_END_IF_LAMBDA
|
||||
stmt ::= conditional_lambda
|
||||
stmt ::= conditional_not_lambda
|
||||
conditional_lambda ::= expr jmp_false expr return_if_lambda
|
||||
@@ -1107,26 +1119,6 @@ class Python3Parser(PythonParser):
|
||||
raise_stmt2 ::= expr expr RAISE_VARARGS_2
|
||||
""", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == 'SETUP_EXCEPT':
|
||||
self.addRule("""
|
||||
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler opt_come_from_except
|
||||
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite come_from_except_clauses
|
||||
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite come_froms
|
||||
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel come_from_except_clauses
|
||||
|
||||
stmt ::= tryelsestmtl3
|
||||
tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler COME_FROM else_suitel
|
||||
opt_come_from_except
|
||||
""", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname_base in ('UNPACK_EX',):
|
||||
before_count, after_count = token.attr
|
||||
rule = 'unpack ::= ' + opname + ' store' * (before_count + after_count + 1)
|
||||
@@ -1145,11 +1137,8 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce['aug_assign2'] = 'AST'
|
||||
self.check_reduce['while1stmt'] = 'noAST'
|
||||
self.check_reduce['while1elsestmt'] = 'noAST'
|
||||
self.check_reduce['ifelsestmt'] = 'AST'
|
||||
self.check_reduce['annotate_tuple'] = 'noAST'
|
||||
self.check_reduce['kwarg'] = 'noAST'
|
||||
self.check_reduce['try_except'] = 'AST'
|
||||
|
||||
# FIXME: remove parser errors caused by the below
|
||||
# self.check_reduce['while1elsestmt'] = 'noAST'
|
||||
return
|
||||
@@ -1191,16 +1180,6 @@ class Python3Parser(PythonParser):
|
||||
if last == n:
|
||||
return False
|
||||
return tokens[first].attr > tokens[last].offset
|
||||
elif rule == ('try_except',
|
||||
('SETUP_EXCEPT', 'suite_stmts_opt', 'POP_BLOCK',
|
||||
'except_handler', 'opt_come_from_except')):
|
||||
come_from_except = ast[-1]
|
||||
if come_from_except[0] == 'COME_FROM':
|
||||
# There should be at last two COME_FROMs, one from an
|
||||
# exception handler and one from the try. Otherwise
|
||||
# we have a try/else.
|
||||
return True
|
||||
pass
|
||||
elif lhs == 'while1stmt':
|
||||
|
||||
# If there is a fall through to the COME_FROM_LOOP. then this is
|
||||
@@ -1216,7 +1195,7 @@ class Python3Parser(PythonParser):
|
||||
|
||||
if tokens[cfl-1] != 'JUMP_BACK':
|
||||
cfl_offset = tokens[cfl-1].offset
|
||||
insn = next(i for i in self.insts if cfl_offset == i.offset)
|
||||
insn = chain((i for i in self.insts if cfl_offset == i.offset), repeat(None)).next()
|
||||
if insn and insn.is_jump_target:
|
||||
return True
|
||||
|
||||
@@ -1234,14 +1213,6 @@ class Python3Parser(PythonParser):
|
||||
if offset != tokens[first].attr:
|
||||
return True
|
||||
return False
|
||||
elif rule == ('ifelsestmt',
|
||||
('testexpr', 'c_stmts_opt', 'jump_forward_else', 'else_suite', '_come_froms')):
|
||||
# Make sure the highest/smallest "come from" offset comes inside the "if".
|
||||
come_froms = ast[-1]
|
||||
if not isinstance(come_froms, Token):
|
||||
return tokens[first].offset > come_froms[-1].attr
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
class Python30Parser(Python3Parser):
|
||||
|
@@ -2,7 +2,6 @@
|
||||
"""
|
||||
spark grammar differences over Python 3.1 for Python 3.0.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from uncompyle6.parsers.parse31 import Python31Parser
|
||||
|
@@ -2,7 +2,6 @@
|
||||
"""
|
||||
spark grammar differences over Python 3.2 for Python 3.1.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from uncompyle6.parsers.parse32 import Python32Parser
|
||||
|
@@ -2,8 +2,6 @@
|
||||
"""
|
||||
spark grammar differences over Python 3 for Python 3.2.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from uncompyle6.parsers.parse3 import Python3Parser
|
||||
|
||||
|
@@ -2,7 +2,6 @@
|
||||
"""
|
||||
spark grammar differences over Python 3.2 for Python 3.3.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from uncompyle6.parsers.parse32 import Python32Parser
|
||||
|
@@ -84,7 +84,7 @@ if __name__ == '__main__':
|
||||
""".split()))
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
import re
|
||||
remain_tokens = set([re.sub(r'_\d+$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_\d+$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
print(remain_tokens)
|
||||
|
@@ -1,8 +1,7 @@
|
||||
# Copyright (c) 2016-2017, 2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2017 Rocky Bernstein
|
||||
"""
|
||||
spark grammar differences over Python 3.4 for Python 3.5.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6.parser import PythonParserSingle, nop_func
|
||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
@@ -104,8 +103,6 @@ class Python35Parser(Python34Parser):
|
||||
# In <.3.5 the below is a JUMP_FORWARD to a JUMP_ABSOLUTE.
|
||||
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF POP_BLOCK
|
||||
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
|
||||
|
||||
|
||||
jb_else ::= JUMP_BACK ELSE
|
||||
ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec
|
||||
@@ -269,7 +266,7 @@ if __name__ == '__main__':
|
||||
""".split()))
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
import re
|
||||
remain_tokens = set([re.sub(r'_\d+$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_\d+$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$', '', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
print(remain_tokens)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user