diff --git a/ChangeLog b/ChangeLog index 50d2ba20..74d68010 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,85 @@ +2017-08-09 rocky + + * README.rst, __pkginfo__.py, uncompyle6/version.py: Get ready for + release 2.11.3 + +2017-08-02 rocky + + * __pkginfo__.py: Revert commit to wrong branch + +2017-08-02 rocky + + * __pkginfo__.py: Remove six from Python-2.4/2.5 package + +2017-07-17 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + xdis's "exception match" is now "exception-match" + +2017-07-15 rocky + + * __pkginfo__.py: xdis 3.5.1 is botched? + +2017-07-14 rocky + + * __pkginfo__.py: Use newer xdis + +2017-07-14 R. Bernstein + + * README.rst: Fixes issue #124 + +2017-07-14 rocky + + * HISTORY.md: History updates + +2017-07-09 rocky + + * README.rst: RsT doc formatting + +2017-07-09 rocky + + * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 + +2017-07-08 rocky + + * __pkginfo__.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py, + uncompyle6/scanners/tok.py: Use xdis 3.5.0's opcode sets + +2017-07-08 rocky + + * test/test_pyenvlib.py, uncompyle6/scanners/pypy32.py, + uncompyle6/scanners/pypy35.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, + uncompyle6/scanners/scanner35.py, uncompyle6/scanners/scanner36.py: + Start supporting Pypy 3.5 (5.7.1-beta) + +2017-07-05 rocky + + * test/simple_source/bug26/03_loop_if_cf.py, + uncompyle6/parsers/parse26.py: Loops in Python 2.4-2.6 loop + come_from Looks like Python 2.4-2.6 may have a COME_FROM(_LOOP) before the + jump_back. Fixes Issue #123 + +2017-06-29 rocky + + * : Work around not having real flow-control analysis + +2017-06-28 rocky + + * uncompyle6/semantics/make_function.py: A guard against badly + formated bytecode + +2017-06-25 rocky + + * ChangeLog, NEWS, test/simple_source/bug31/04_def_annotate.py, + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py: 3.x funciton and annotation bug + fixes + 2017-06-25 rocky * uncompyle6/version.py: Get ready for release 2.11.1 diff --git a/HISTORY.md b/HISTORY.md index 09ab5326..cadcc7d3 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -44,8 +44,8 @@ it appears that Hartmut did most of the work to get this code to accept the full Python language. He added precedence to the table specifiers, support for multiple versions of Python, the pretty-printing of docstrings, lists, and hashes. He also wrote test and verification routines of -deparsed bytecode, and used this in an extensive set of tests that he also wrote. He says he could verify against the -entire Python library. However I have subsequently found small and relatively obscure bugs in the decompilation code. +deparsed bytecode, and used this in an extensive set of tests that he also wrote. He says he could verify against the +entire Python library. However I have subsequently found small and relatively obscure bugs in the decompilation code. decompyle2.2 was packaged for Debian (sarge) by [Ben Burton around 2002](https://packages.qa.debian.org/d/decompyle.html). As @@ -66,7 +66,7 @@ code to handle first Python 2.3 and then 2.4 bytecodes. Because of jump optimization introduced in the CPython bytecode compiler at that time, various JUMP instructions were classifed as going backwards, and COME FROM instructions were reintroduced. See -[RELEASE-2.4-CHANGELOG.txt](https://github.com/rocky/python-uncompyle6/blob/master/DECOMPYLE-2.4-CHANGELOG.txt) +[RELEASE-2.4-CHANGELOG.txt](https://github.com/rocky/python-uncompyle6/blob/master/DECOMPYLE-2.4-CHANGELOG.txt) for more details here. There wasn't a public release of RELEASE-2.4 and bytecodes other than Python 2.4 weren't supported. Dan says the Python 2.3 version could verify the entire @@ -99,7 +99,7 @@ made a few commits later on. But mostly wibiti, and Guenther Starnberger got the code to where uncompyle2 was around 2012. In `uncompyle`, decompilation of python bytecode 2.5 & 2.6 is done by -transforming the byte code into a a pseudo 2.7 python bytecode and is +transforming the byte code into a pseudo-2.7 Python bytecode and is based on code from Eloi Vanderbeken. This project, `uncompyle6`, abandons that approach for various @@ -120,10 +120,10 @@ while, handling Python bytecodes from Python versions 2.5+ and 3.2+. In doing so, it has been expedient to separate this into three projects: -* bytecode loading and disassembly ([xdis](https://pypi.python.org/pypi/xdis)), +* marshaling/unmarshaling, bytecode loading and disassembly ([xdis](https://pypi.python.org/pypi/xdis)), * parsing and tree building ([spark_parser](https://pypi.python.org/pypi/spark_parser)), * this project - grammar and semantic actions for decompiling - ([uncompyle6](https://pypi.python.org/pypi/spark_parser)). + ([uncompyle6](https://pypi.python.org/pypi/uncompyle6)). Over the many years, code styles and Python features have @@ -162,5 +162,8 @@ support has been lagging. Tests for the project have been, or are being, culled from all of the projects mentioned. +For a little bit of the history of changes to the Early-algorithm parser, +see the file [NEW-FEATURES.rst](https://github.com/rocky/python-spark/blob/master/NEW-FEATURES.rst) in the [python-spark github repository](https://github.com/rocky/python-spark). + NB. If you find mistakes, want corrections, or want your name added (or removed), please contact me. diff --git a/HOW-TO-REPORT-A-BUG.md b/HOW-TO-REPORT-A-BUG.md index 7a2e1534..63c76f56 100644 --- a/HOW-TO-REPORT-A-BUG.md +++ b/HOW-TO-REPORT-A-BUG.md @@ -19,7 +19,7 @@ So it is likely you'll find a mistranslation in decompiling. The basic requirement is pretty simple: * Python bytecode -* Source text +* Python source text ## What to send (additional helpful information) @@ -50,7 +50,7 @@ one fool can learn, so can another." ## Narrowing the problem -I don't need the entire source code base for which one file or module +I don't need or want the entire source code base for which one file or module can't be decompiled. I just need that one file or module only. If there are several files, file a bug report for each file. diff --git a/NEWS b/NEWS index a673aacf..e1d418c2 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,26 @@ -uncompyle6 2.11.1 2016-06-22 +uncompyle6 2.11.2 2017-08-09 -- Python 3.x annotatoin and function signature fixes +Very minor changes + +- RsT doc fixes and updates +- use newer xdis, but not too new; 3.5.2 breaks uncompyle6 +- use xdis opcode sets +- xdis "exception match" is now "exception-match" + +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 + +uncompyle6 2.11.1 2017-06-25 + +- Python 3.x annotation and function signature fixes - Bump xdis version - Small pysource bug fixes -uncompyle6 2.11.0 2016-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 @@ -14,17 +30,17 @@ uncompyle6 2.11.0 2016-06-18 Fleetwood - Fixes yet again for make_function node handling; document what's up here - Fix bug in snowflake Python 3.5 *args kwargs -uncompyle6 2.10.1 2016-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 -uncompyle6 2.10.0 2016-05-30 Elaine Gordon +uncompyle6 2.10.0 2017-05-30 Elaine Gordon -- Add fuzzy offset deparse lookup -- 3.6 bugfixes +- Add fuzzy offset deparse look up +- 3.6 bug fixes - fix EXTENDED_ARGS handling (and in 2.6 and others) - semantic routine make_function fragments.py - MAKE_FUNCTION handling @@ -35,19 +51,19 @@ uncompyle6 2.10.0 2016-05-30 Elaine Gordon - 3.5 FUNCTION_VAR bug - 3.x pass statement insdie while True - Improve 3.2 decompilation -- Fixed -o argument processing (Gregrory) +- Fixed -o argument processing (grkov90) - Reduce scope of LOAD_ASSERT as expr to 3.4+ - "await" statement fixes - 2.3, 2.4 "if 1 .." fixes - 3.x annotation fixes -uncompyle6 2.9.11 2016-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 -uncompyle6 2.9.10 2016-02-25 +uncompyle6 2.9.10 2017-02-25 - Python grammar rule fixes - Add ability to get grammar coverage on runs @@ -114,7 +130,7 @@ uncompyle6 2.9.6 2016-11-20 uncompyle6 2.9.5 2016-11-13 - Fix Python 3 bugs: - * improprer while 1 else + * improper while 1 else * docstring indent * 3.3 default values in lambda expressions * start 3.0 decompilation (needs newer xdis) @@ -124,12 +140,12 @@ uncompyle6 2.9.5 2016-11-13 uncompyle6 2.9.4 2016-11-02 - Handle Python 3.x function annotations -- track def keywoard-parameter line-splitting in source code better +- track def keyword-parameter line-splitting in source code better - bump min xdis version to mask previous xdis bug uncompyle6 2.9.3 2016-10-26 -Release forced by incompatiblity change in xdis 3.2.0. +Release forced by incompatibility change in xdis 3.2.0. - Python 3.1 bugs: * handle "with ... as" @@ -161,7 +177,7 @@ uncompyle6 2.9.0 2016-10-09 this Forces change in requirements.txt and _pkg_info_.py - Start Python 1.5 decompiling; another round of work is needed to remove bugs -- Simpify python 2.1 grammar +- Simplify python 2.1 grammar - Fix bug with -t ... Wasn't showing source text when -t option was given - Fix 2.1-2.6 bug in list comprehension @@ -184,7 +200,7 @@ control-flow structure detection is done. . 3.0 .. 3.2 *args processing . 3.0 .. 3.2 call name and kwargs bug . 3.0 .. getting parameter of * - . 3.0 .. handling varible number of args + . 3.0 .. handling variable number of args . 3.0 .. "if" structure bugs * 3.5+ if/else bugs * 2.2-2.6 bugs @@ -235,7 +251,7 @@ uncompyle6 2.7.1 2016-07-26 uncompyle6 2.7.0 2016-07-15 -- Many Syntax and verifification bugs removed +- 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. @@ -262,9 +278,9 @@ uncompyle6 2.6.0 2016-07-07 - Better <2.6 vs. 2.7 grammar separation - Fix some 2.7 deparsing bugs - Fix bug in installing uncompyle6 script -- Doc improvments +- Doc improvements -uncompyle6 2.5.0 2016-06-22 Summer Solstace +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 @@ -276,7 +292,7 @@ uncompyle6 2.5.0 2016-06-22 Summer Solstace uncompyle6 2.4.0 2016-05-18 (in memory of Lewis Bernstein) - Many Python 3 bugs fixed: - * Python 3.2 to 3.5 libaries largely + * Python 3.2 to 3.5 libraries largely uncompyle and most verify - pydisassembler: * disassembles all code objects in a file @@ -334,7 +350,7 @@ uncompyle6 2.2.0 2016-04-30 uncompyle6 2.2.0 2016-04-02 -- Support single-mode (in addtion to exec-mode) compilation +- Support single-mode (in addition to exec-mode) compilation - Start to DRY Python 2 and Python 3 grammars - Fix bug in if else ternary construct - Fix bug in uncomplye6 -d and -r options (via lelicopter) diff --git a/README.rst b/README.rst index 56607fe3..1cbeb43e 100644 --- a/README.rst +++ b/README.rst @@ -171,8 +171,11 @@ See Also * https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here. * https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Include some fixes like supporting function annotations * The HISTORY_ file. -* `How to report a bug `_ -.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg +* `How to report a bug `_ +* https://github.com/rocky/python-xdis : Cross Python version disassembler +* https://github.com/rocky/python-xasm : Cross Python version assembler + + .. _trepan: https://pypi.python.org/pypi/trepan .. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md .. _debuggers: https://pypi.python.org/pypi/trepan3k diff --git a/__pkginfo__.py b/__pkginfo__.py index f84d9e5d..71b2e912 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ entry_points = { ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.5.1, < 3.6.0'] + 'xdis == 3.5.1, < 3.6.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' diff --git a/test/bytecode_2.6/03_loop_if_cf.pyc b/test/bytecode_2.6/03_loop_if_cf.pyc new file mode 100644 index 00000000..880855af Binary files /dev/null and b/test/bytecode_2.6/03_loop_if_cf.pyc differ diff --git a/test/simple_source/bug26/03_loop_if_cf.py b/test/simple_source/bug26/03_loop_if_cf.py new file mode 100644 index 00000000..b4f85870 --- /dev/null +++ b/test/simple_source/bug26/03_loop_if_cf.py @@ -0,0 +1,19 @@ +# Bug in < 2.6 is having a COME_FROM_LOOP (but we +# don't tag that so it is just COME_FROM *before* +# a jump back to the loop. +def pickup(self, open_players, open_buf, wrap_buf): + for aplayer in self._game.active_players: + + if aplayer in open_players: + aplayer.send(open_players) + + if self == aplayer: + for awatcher in self._watchers: + if awatcher._can_see_detail: + awatcher.send(open_buf) + else: + awatcher.send(wrap_buf) + else: + self._game.send(aplayer.side) + else: + self._game.send(aplayer.side, wrap_buf) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index d215cd14..a810d6e3 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -27,7 +27,7 @@ from fnmatch import fnmatch TEST_VERSIONS=('2.3.7', '2.4.6', '2.5.6', '2.6.9', 'pypy-2.4.0', 'pypy-2.6.1', - 'pypy-5.0.1', 'pypy-5.3.1', + 'pypy-5.0.1', 'pypy-5.3.1', 'pypy3.5-5.7.1-beta', '2.7.10', '2.7.11', '2.7.12', '2.7.13', '3.0.1', '3.1.5', '3.2.6', '3.3.5', '3.3.6', diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 70611f0d..c8561d59 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -84,6 +84,12 @@ class Python26Parser(Python2Parser): ja_cf_pop ::= JUMP_ABSOLUTE come_froms POP_TOP jf_cf_pop ::= JUMP_FORWARD come_froms POP_TOP + # The first optional COME_FROM when it appears is really + # COME_FROM_LOOP, but in <= 2.6 we don't distinguish + # this + + cf_jb_cf_pop ::= _come_from JUMP_BACK come_froms POP_TOP + bp_come_from ::= POP_BLOCK COME_FROM jb_bp_come_from ::= JUMP_BACK bp_come_from @@ -111,7 +117,8 @@ class Python26Parser(Python2Parser): break_stmt ::= BREAK_LOOP JUMP_BACK # Semantic actions want else_suitel to be at index 3 - ifelsestmtl ::= testexpr c_stmts_opt jb_cf_pop else_suitel + ifelsestmtl ::= testexpr c_stmts_opt cf_jb_cf_pop else_suitel + ifelsestmtc ::= testexpr c_stmts_opt ja_cf_pop else_suitec # Semantic actions want suite_stmts_opt to be at index 3 diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 580a2941..eb5fee45 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -87,7 +87,7 @@ class Scanner(object): if op is None: op = self.code[pos] target = self.get_argument(pos) - if op in self.opc.hasjrel: + if op in self.opc.JREL_OPS: target += pos + 3 return target @@ -98,7 +98,7 @@ class Scanner(object): def print_bytecode(self): for i in self.op_range(0, len(self.code)): op = self.code[i] - if op in self.opc.hasjabs+self.opc.hasjrel: + if op in self.JUMP_OPs: dest = self.get_target(i, op) print('%i\t%s\t%i' % (i, self.opname[op], dest)) else: diff --git a/uncompyle6/scanners/pypy32.py b/uncompyle6/scanners/pypy32.py index 264708ef..232c168b 100644 --- a/uncompyle6/scanners/pypy32.py +++ b/uncompyle6/scanners/pypy32.py @@ -1,22 +1,18 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2017 by Rocky Bernstein """ -Python PyPy 3.2 bytecode scanner/deparser +Python PyPy 3.2 decompiler scanner. -This overlaps Python's 3.2's dis module, but it can be run from -Python 3 and other versions of Python. Also, we save token -information for later use in deparsing. +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. """ import uncompyle6.scanners.scanner32 as scan # bytecode verification, verify(), uses JUMP_OPs from here -from xdis.opcodes import opcode_32 as opc # is this rgith? +from xdis.opcodes import opcode_32 as opc # is this right? JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) -# We base this off of 2.6 instead of the other way around -# because we cleaned things up this way. -# The history is that 2.7 support is the cleanest, -# then from that we got 2.6 and so on. +# We base this off of 3.2 class ScannerPyPy32(scan.Scanner32): def __init__(self, show_asm): # There are no differences in initialization between diff --git a/uncompyle6/scanners/pypy35.py b/uncompyle6/scanners/pypy35.py new file mode 100644 index 00000000..a2c660a9 --- /dev/null +++ b/uncompyle6/scanners/pypy35.py @@ -0,0 +1,22 @@ +# Copyright (c) 2017 by Rocky Bernstein +""" +Python PyPy 3.2 decompiler scanner. + +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. +""" + +import uncompyle6.scanners.scanner35 as scan + +# bytecode verification, verify(), uses JUMP_OPs from here +from xdis.opcodes import opcode_35 as opc # is this right? +JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) + +# We base this off of 3.5 +class ScannerPyPy35(scan.Scanner35): + def __init__(self, show_asm): + # There are no differences in initialization between + # pypy 3.5 and 3.5 + scan.Scanner35.__init__(self, show_asm, is_pypy=True) + self.version = 3.5 + return diff --git a/uncompyle6/scanners/scanner15.py b/uncompyle6/scanners/scanner15.py index 42c99e9e..21d86bda 100644 --- a/uncompyle6/scanners/scanner15.py +++ b/uncompyle6/scanners/scanner15.py @@ -1,6 +1,6 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ -Python 1.5 bytecode scanner/deparser +Python 1.5 bytecode decompiler scanner. This massages tokenized 1.5 bytecode to make it more amenable for grammar parsing. diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 92058ce8..2f224c0d 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -195,7 +195,7 @@ class Scanner2(Scanner): if op == self.opc.EXTENDED_ARG: extended_arg = oparg * L65536 continue - if op in self.opc.hasconst: + if op in self.opc.CONST_OPS: const = co.co_consts[oparg] if iscode(const): oparg = const @@ -216,23 +216,23 @@ class Scanner2(Scanner): pattr = '' else: pattr = const - elif op in self.opc.hasname: + elif op in self.opc.NAME_OPS: pattr = names[oparg] - elif op in self.opc.hasjrel: + elif op in self.opc.JREL_OPS: # use instead: hasattr(self, 'patch_continue'): ? if self.version == 2.7: self.patch_continue(tokens, offset, op) pattr = repr(offset + 3 + oparg) - elif op in self.opc.hasjabs: + elif op in self.opc.JABS_OPS: # use instead: hasattr(self, 'patch_continue'): ? if self.version == 2.7: self.patch_continue(tokens, offset, op) pattr = repr(oparg) - elif op in self.opc.haslocal: + elif op in self.opc.LOCAL_OPS: pattr = varnames[oparg] - elif op in self.opc.hascompare: + elif op in self.opc.COMPARE_OPS: pattr = self.opc.cmp_op[oparg] - elif op in self.opc.hasfree: + elif op in self.opc.FREE_OPS: pattr = free[oparg] if op in self.varargs_ops: @@ -458,7 +458,7 @@ class Scanner2(Scanner): self.not_continue.add(jmp) jmp = self.get_target(jmp) prev_offset = self.prev[except_match] - # COMPARE_OP argument should be "exception match" or 10 + # COMPARE_OP argument should be "exception-match" or 10 if (self.code[prev_offset] == self.opc.COMPARE_OP and self.code[prev_offset+1] != 10): return None @@ -609,7 +609,7 @@ class Scanner2(Scanner): if test == offset: loop_type = 'while 1' - elif self.code[test] in self.opc.hasjabs + self.opc.hasjrel: + elif self.code[test] in self.opc.JUMP_OPs: self.ignore_if.add(test) test_target = self.get_target(test) if test_target > (jump_back+3): @@ -911,7 +911,9 @@ class Scanner2(Scanner): 'start': start-3, 'end': pre_rtarget}) - self.not_continue.add(pre_rtarget) + # FIXME: this is yet another case were we need dominators. + if pre_rtarget not in self.linestartoffsets or self.version < 2.7: + self.not_continue.add(pre_rtarget) if rtarget < end: # We have an "else" block of some kind. @@ -998,11 +1000,11 @@ class Scanner2(Scanner): oparg = self.get_argument(offset) if label is None: - if op in self.opc.hasjrel and self.op_name(op) != 'FOR_ITER': - # if (op in self.opc.hasjrel and + if op in self.opc.JREL_OPS and self.op_name(op) != 'FOR_ITER': + # if (op in self.opc.JREL_OPS and # (self.version < 2.0 or op != self.opc.FOR_ITER)): label = offset + 3 + oparg - elif self.version == 2.7 and op in self.opc.hasjabs: + elif self.version == 2.7 and op in self.opc.JABS_OPS: if op in (self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP): if (oparg > offset): diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index f87b94b0..efe00747 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -183,7 +183,7 @@ class Scanner26(scan.Scanner2): if op == self.opc.EXTENDED_ARG: extended_arg = oparg * L65536 continue - if op in self.opc.hasconst: + if op in self.opc.CONST_OPS: const = co.co_consts[oparg] # We can't use inspect.iscode() because we may be # using a different version of Python than the @@ -208,9 +208,9 @@ class Scanner26(scan.Scanner2): pattr = '' else: pattr = const - elif op in self.opc.hasname: + elif op in self.opc.NAME_OPS: pattr = names[oparg] - elif op in self.opc.hasjrel: + elif op in self.opc.JREL_OPS: pattr = repr(offset + 3 + oparg) if op == self.opc.JUMP_FORWARD: target = self.get_target(offset) @@ -220,13 +220,13 @@ class Scanner26(scan.Scanner2): if len(tokens) and tokens[-1].type == 'JUMP_BACK': tokens[-1].type = intern('CONTINUE') - elif op in self.opc.hasjabs: + elif op in self.opc.JABS_OPS: pattr = repr(oparg) - elif op in self.opc.haslocal: + elif op in self.opc.LOCAL_OPS: pattr = varnames[oparg] - elif op in self.opc.hascompare: + elif op in self.opc.COMPARE_OPS: pattr = self.opc.cmp_op[oparg] - elif op in self.opc.hasfree: + elif op in self.opc.FREE_OPS: pattr = free[oparg] if op in self.varargs_ops: # CE - Hack for >= 2.5 diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index be359f85..47759f80 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -639,11 +639,11 @@ class Scanner3(Scanner): rel_offset = 0 if self.version >= 3.6: target = self.code[offset+1] - if op in self.opc.hasjrel: + if op in self.opc.JREL_OPS: rel_offset = offset + 2 else: target = self.code[offset+1] + self.code[offset+2] * 256 - if op in self.opc.hasjrel: + if op in self.opc.JREL_OPS: rel_offset = offset + 3 pass pass diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index c87034da..de0976e5 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -118,7 +118,7 @@ class Scanner30(Scanner3): if test == offset: loop_type = 'while 1' - elif self.code[test] in opc.hasjabs+opc.hasjrel: + elif self.code[test] in opc.JUMP_OPs: self.ignore_if.add(test) test_target = self.get_target(test) if test_target > (jump_back+3): diff --git a/uncompyle6/scanners/scanner32.py b/uncompyle6/scanners/scanner32.py index 589fb8df..b1b2fed8 100644 --- a/uncompyle6/scanners/scanner32.py +++ b/uncompyle6/scanners/scanner32.py @@ -1,6 +1,9 @@ -# Copyright (c) 2015-2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein """ -Python 3.2 bytecode scanner/deparser +Python 3.2 bytecode decompiler scanner. + +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. This sets up opcodes Python's 3.2 and calls a generalized scanner routine for Python 3. diff --git a/uncompyle6/scanners/scanner34.py b/uncompyle6/scanners/scanner34.py index 058c17af..80d14842 100644 --- a/uncompyle6/scanners/scanner34.py +++ b/uncompyle6/scanners/scanner34.py @@ -1,6 +1,9 @@ -# Copyright (c) 2015-2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein """ -Python 3.4 bytecode scanner/deparser +Python 3.4 bytecode decompiler scanner + +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. This sets up opcodes Python's 3.4 and calls a generalized scanner routine for Python 3. diff --git a/uncompyle6/scanners/scanner35.py b/uncompyle6/scanners/scanner35.py index 61f56a84..2d9265fa 100644 --- a/uncompyle6/scanners/scanner35.py +++ b/uncompyle6/scanners/scanner35.py @@ -1,6 +1,9 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2017 by Rocky Bernstein """ -Python 3.5 bytecode scanner/deparser +Python 3.5 bytecode decompiler scanner + +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. This sets up opcodes Python's 3.5 and calls a generalized scanner routine for Python 3. @@ -14,8 +17,8 @@ JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) class Scanner35(Scanner3): - def __init__(self, show_asm=None): - Scanner3.__init__(self, 3.5, show_asm) + def __init__(self, show_asm=None, is_pypy=False): + Scanner3.__init__(self, 3.5, show_asm, is_pypy) return pass diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index 417b5a1a..dd293d4f 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -1,6 +1,9 @@ # Copyright (c) 2016-2017 by Rocky Bernstein """ -Python 3.6 bytecode scanner/deparser +Python 3.6 bytecode decompiler scanner + +Does some additional massaging of xdis-disassembled instructions to +make things easier for decompilation. This sets up opcodes Python's 3.6 and calls a generalized scanner routine for Python 3. diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 2dadf451..641e69aa 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -71,10 +71,10 @@ class Token: if self.pattr: pattr = self.pattr if self.opc: - if self.op in self.opc.hasjrel: + if self.op in self.opc.JREL_OPS: if not self.pattr.startswith('to '): pattr = "to " + self.pattr - elif self.op in self.opc.hasjabs: + elif self.op in self.opc.JABS_OPS: self.pattr= str(self.pattr) if not self.pattr.startswith('to '): pattr = "to " + str(self.pattr) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 5ea303fb..c2815370 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -413,7 +413,8 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None): if code_has_star_star_arg(code): if argc > 0: self.write(', ') - self.write('**%s' % code.co_varnames[argc + kw_pairs]) + if argc + kw_pairs > 0: + self.write('**%s' % code.co_varnames[argc + kw_pairs]) if isLambda: self.write(": ") diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 91d31b5a..632937ca 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -1,3 +1,3 @@ # This file is suitable for sourcing inside bash as # well as importing into Python -VERSION='2.11.1' +VERSION='2.11.3'