From a9349b8f3d12b2aa0cd88286617c1af9cccad018 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 22 Nov 2016 17:49:47 -0500 Subject: [PATCH 001/489] Making it run on Python 2.4 and 2.5 --- .travis.yml | 6 +- Makefile | 2 +- __pkginfo__.py | 4 +- circle.yml | 4 +- .../{test_disasm.py => test_disasm.py-notyet} | 0 pytest/test_fstring.py | 150 ------------------ test/Makefile | 2 +- test/test_pythonlib.py | 23 ++- uncompyle6/bin/pydisassemble.py | 16 +- uncompyle6/bin/uncompile.py | 15 +- uncompyle6/disas.py | 14 +- uncompyle6/linenumbers.py | 2 +- uncompyle6/main.py | 43 +++-- uncompyle6/parser.py | 2 - uncompyle6/parsers/parse2.py | 2 - uncompyle6/parsers/parse3.py | 2 - uncompyle6/parsers/parse30.py | 1 - uncompyle6/parsers/parse31.py | 1 - uncompyle6/parsers/parse32.py | 2 - uncompyle6/parsers/parse33.py | 1 - uncompyle6/parsers/parse35.py | 1 - uncompyle6/parsers/parse36.py | 1 - uncompyle6/scanner.py | 2 - uncompyle6/scanners/scanner2.py | 4 +- uncompyle6/scanners/scanner27.py | 2 - uncompyle6/scanners/scanner3.py | 4 +- uncompyle6/scanners/scanner30.py | 2 - uncompyle6/scanners/scanner31.py | 2 - uncompyle6/scanners/scanner32.py | 2 - uncompyle6/scanners/scanner33.py | 2 - uncompyle6/scanners/scanner34.py | 2 - uncompyle6/scanners/scanner35.py | 2 - uncompyle6/scanners/scanner36.py | 2 - uncompyle6/semantics/fragments.py | 20 +-- uncompyle6/semantics/make_function.py | 17 +- uncompyle6/semantics/pysource.py | 14 +- uncompyle6/verify.py | 4 +- 37 files changed, 84 insertions(+), 291 deletions(-) rename pytest/{test_disasm.py => test_disasm.py-notyet} (100%) delete mode 100644 pytest/test_fstring.py diff --git a/.travis.yml b/.travis.yml index e8e83467e..e2808adb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,7 @@ language: python sudo: false python: - - '3.5' - - '2.7.12' - - '2.6' - - '3.3' - - '3.4' + - '2.7' # this is a cheat here because travis doesn't do 2.4-2.6 install: - pip install -r requirements.txt diff --git a/Makefile b/Makefile index 1d8ece17e..a431800e8 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ check-3.0 check-3.1 check-3.2 check-3.5 check-3.6: $(MAKE) -C test $@ #:Tests for Python 2.6 (doesn't have pytest) -check-2.6: +check-2.5 check-2.6: $(MAKE) -C test $@ #:PyPy 2.6.1 or PyPy 5.0.1 diff --git a/__pkginfo__.py b/__pkginfo__.py index 59df58e34..7652cba5d 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -16,10 +16,10 @@ 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.4', + 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', diff --git a/circle.yml b/circle.yml index 4fcb34578..4da534f90 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: python: - version: 2.7.12 + version: 2.6.9 environment: COMPILE: --compile @@ -10,4 +10,4 @@ dependencies: - pip install -r requirements-dev.txt test: override: - - python ./setup.py develop && make check-2.7 + - python ./setup.py develop && make check-2.6 diff --git a/pytest/test_disasm.py b/pytest/test_disasm.py-notyet similarity index 100% rename from pytest/test_disasm.py rename to pytest/test_disasm.py-notyet diff --git a/pytest/test_fstring.py b/pytest/test_fstring.py deleted file mode 100644 index 2789d82ad..000000000 --- a/pytest/test_fstring.py +++ /dev/null @@ -1,150 +0,0 @@ -# std -import os -# test -import pytest -import hypothesis -from hypothesis import strategies as st -# uncompyle6 -from uncompyle6 import PYTHON_VERSION, deparse_code - - -@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 ::= - 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 at least 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, '', 'single') - deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single') - recompiled = compile(deparsed.text, '', 'single') - if recompiled != code: - assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')' - - -@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least 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 at least 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) diff --git a/test/Makefile b/test/Makefile index 2f8e56ca2..f837216c6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -20,7 +20,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-2.7-ok +check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-2.7-ok #: Run working tests from Python 3.1 check-3.0: check-bytecode diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 8deb221cf..494f296f2 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -27,8 +27,6 @@ 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 @@ -127,8 +125,10 @@ def file_matches(files, root, basenames, patterns): 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) @@ -146,8 +146,8 @@ def file_matches(files, root, basenames, patterns): 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) @@ -161,9 +161,9 @@ def file_matches(files, root, basenames, patterns): 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, [], @@ -227,14 +227,13 @@ def file_matches(files, root, basenames, patterns): 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 diff --git a/uncompyle6/bin/pydisassemble.py b/uncompyle6/bin/pydisassemble.py index b2f5862ed..77f74d6a5 100755 --- a/uncompyle6/bin/pydisassemble.py +++ b/uncompyle6/bin/pydisassemble.py @@ -3,7 +3,6 @@ # # Copyright (c) 2015-2016 by Rocky Bernstein # -from __future__ import print_function import sys, os, getopt from uncompyle6.disas import disassemble_file @@ -26,7 +25,7 @@ -V | --version show version and stop -h | --help show this message -""".format(program) +""" % (program, program) PATTERNS = ('*.pyc', '*.pyo') @@ -37,15 +36,15 @@ def main(): native = True 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: @@ -59,7 +58,7 @@ def main(): native = False else: print(opt) - print(Usage_short, file=sys.stderr) + sys.stderr.write(Usage_short) sys.exit(1) @@ -67,8 +66,7 @@ def main(): if os.path.exists(files[0]): disassemble_file(file, sys.stdout, native) 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 diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 5315b2a8c..0371c3deb 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -4,7 +4,6 @@ # Copyright (c) 2015-2016 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # -from __future__ import print_function import sys, os, getopt, time program, ext = os.path.splitext(os.path.basename(__file__)) @@ -65,11 +64,11 @@ def usage(): def main_bin(): - if not (sys.version_info[0:2] in ((2, 6), (2, 7), + if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6))): - print('Error: %s requires Python 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, or 3.6' % program, - file=sys.stderr) + sys.stderr.write('Error: %s requires Python 2.4 2.5 2.6, 2.7, ' + '3.2, 3.3, 3.4, 3.5, or 3.6' % program) sys.exit(-1) do_verify = recurse_dirs = False @@ -84,8 +83,8 @@ def main_bin(): opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:', 'help asm grammar linemaps recurse timestamp tree ' 'verify version showgrammar'.split(' ')) - except getopt.GetoptError as e: - print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr) + except getopt.GetoptError(e): + sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e)) sys.exit(-1) options = {} @@ -119,7 +118,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 @@ -145,7 +144,7 @@ def main_bin(): del sb_len if not files: - print("No files given", file=sys.stderr) + sys.stderr.write("No files given\n") usage() if outfile == '-': diff --git a/uncompyle6/disas.py b/uncompyle6/disas.py index 8989c4bef..bb3589897 100644 --- a/uncompyle6/disas.py +++ b/uncompyle6/disas.py @@ -16,8 +16,6 @@ want to run on Python 2.7. """ -from __future__ import print_function - import sys from collections import deque @@ -37,10 +35,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) @@ -52,16 +49,15 @@ def disco_loop(disasm, queue, real_out): while len(queue) > 0: co = queue.popleft() if co.co_name != '': - 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 diff --git a/uncompyle6/linenumbers.py b/uncompyle6/linenumbers.py index 3b5d1f908..17e75a695 100644 --- a/uncompyle6/linenumbers.py +++ b/uncompyle6/linenumbers.py @@ -10,7 +10,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]) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 9c3de62a5..c1fc48406 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -1,4 +1,3 @@ -from __future__ import print_function import datetime, os, subprocess, sys, tempfile from uncompyle6 import verify, IS_PYPY @@ -24,29 +23,22 @@ def uncompyle( real_out = out or sys.stdout co_pypy_str = 'PyPy ' if is_pypy else '' run_pypy_str = 'PyPy ' if IS_PYPY else '' - print('# uncompyle6 version %s\n' - '# %sPython bytecode %s%s\n# Decompiled from: %sPython %s' % + real_out.write('# uncompyle6 version %s\n' + '# %sPython bytecode %s%s\n# Decompiled from: %sPython %s\n' % (VERSION, co_pypy_str, bytecode_version, " (%d)" % magic_int if magic_int else "", - run_pypy_str, '\n# '.join(sys.version.split('\n'))), - file=real_out) + run_pypy_str, '\n# '.join(sys.version.split('\n')))) 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) if timestamp: - print('# Compiled at: %s' % datetime.datetime.fromtimestamp(timestamp), - file=real_out) + real_out.write('# Compiled at: %s\n' % + datetime.datetime.fromtimestamp(timestamp)) if source_size: - print('# Size of source mod 2**32: %d bytes' % source_size, - file=real_out) + real_out.write('# Size of source mod 2**32: %d bytes\n' % source_size) - try: - pysource.deparse_code(bytecode_version, co, out, showasm, showast, - showgrammar, code_objects=code_objects, - is_pypy=is_pypy) - except pysource.SourceWalkerError as e: - # deparsing failed - raise pysource.SourceWalkerError(str(e)) + pysource.deparse_code(bytecode_version, co, out, showasm, showast, + showgrammar, code_objects=code_objects, + is_pypy=is_pypy) @@ -145,9 +137,9 @@ def _get_outstream(outfile): try: uncompyle_file(infile, outstream, showasm, showast, showgrammar) 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 except KeyboardInterrupt: if outfile: @@ -185,21 +177,22 @@ def _get_outstream(outfile): okay_files += 1 else: print('\n# %s\n\t%s', infile, msg) - except verify.VerifyCmpError as e: + except verify.VerifyCmpError(e): print(e) verify_failed_files += 1 os.rename(outfile, outfile + '_unverified') if not outfile: - print("### Error Verifiying %s" % filename, file=sys.stderr) - print(e, file=sys.stderr) + sys.stder.write("### Error Verifiying %s" % + filename) + sys.stderr.write(e) if raise_on_error: raise pass pass pass elif do_verify: - print("\n### uncompile successful, but no file to compare against", - file=sys.stderr) + sys.stderr.write("\n### uncompile successful, " + "but no file to compare against") pass else: okay_files += 1 diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index abe73d5bc..5f402065d 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -6,8 +6,6 @@ Common uncompyle parser routines. """ -from __future__ import print_function - import sys from xdis.code import iscode diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index e71ab46de..eb09dbaa6 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -12,8 +12,6 @@ that a later phase can tern into a sequence of ASCII text. """ -from __future__ import print_function - from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.astnode import AST from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 3788a7385..7ff048d0c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -15,8 +15,6 @@ 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.astnode import AST from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index f02f686ba..27b646297 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -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.parse3 import Python3Parser diff --git a/uncompyle6/parsers/parse31.py b/uncompyle6/parsers/parse31.py index 647ed4219..f22f05a9f 100644 --- a/uncompyle6/parsers/parse31.py +++ b/uncompyle6/parsers/parse31.py @@ -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 diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index 9f3430662..ab27f3780 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -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 diff --git a/uncompyle6/parsers/parse33.py b/uncompyle6/parsers/parse33.py index a48066b25..41ae4ebff 100644 --- a/uncompyle6/parsers/parse33.py +++ b/uncompyle6/parsers/parse33.py @@ -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 diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index 996eec72b..f02b803dd 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -2,7 +2,6 @@ """ spark grammar differences over Python 3.4 for Python 3.5. """ -from __future__ import print_function from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 47a256dbf..70227691f 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -2,7 +2,6 @@ """ spark grammar differences over Python 3.5 for Python 3.6. """ -from __future__ import print_function from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 2d44490b1..487e74229 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -10,8 +10,6 @@ scanners, e.g. for Python 2.7 or 3.4. """ -from __future__ import print_function - import sys from uncompyle6 import PYTHON3, IS_PYPY diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 877f51707..0b6e9f4b6 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -20,9 +20,7 @@ Finally we save token information. """ -from __future__ import print_function - -from collections import namedtuple +from xdis.namedtuple25 import namedtuple from array import array from uncompyle6.scanner import op_has_argument diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 885be81e2..706d9a620 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -7,8 +7,6 @@ """ -from __future__ import print_function - from uncompyle6.scanners.scanner2 import Scanner2 from uncompyle6 import PYTHON3 diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index c8ae49264..d3750ca61 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -20,9 +20,7 @@ Finally we save token information. """ -from __future__ import print_function - -from collections import namedtuple +from xdis.namedtuple25 import namedtuple from array import array from uncompyle6.scanner import Scanner, op_has_argument diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index b39b4ee69..21bc44e95 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_30 as opc JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) diff --git a/uncompyle6/scanners/scanner31.py b/uncompyle6/scanners/scanner31.py index 97f082cc5..15f569188 100644 --- a/uncompyle6/scanners/scanner31.py +++ b/uncompyle6/scanners/scanner31.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_31 as opc JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) diff --git a/uncompyle6/scanners/scanner32.py b/uncompyle6/scanners/scanner32.py index 710a282a3..589fb8dff 100644 --- a/uncompyle6/scanners/scanner32.py +++ b/uncompyle6/scanners/scanner32.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_32 as opc JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) diff --git a/uncompyle6/scanners/scanner33.py b/uncompyle6/scanners/scanner33.py index f329cdf2a..06268003d 100644 --- a/uncompyle6/scanners/scanner33.py +++ b/uncompyle6/scanners/scanner33.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_33 as opc JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) diff --git a/uncompyle6/scanners/scanner34.py b/uncompyle6/scanners/scanner34.py index bb0f3f871..058c17af1 100644 --- a/uncompyle6/scanners/scanner34.py +++ b/uncompyle6/scanners/scanner34.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from xdis.opcodes import opcode_34 as opc # bytecode verification, verify(), uses JUMP_OPs from here diff --git a/uncompyle6/scanners/scanner35.py b/uncompyle6/scanners/scanner35.py index bbb3dfbbe..61f56a845 100644 --- a/uncompyle6/scanners/scanner35.py +++ b/uncompyle6/scanners/scanner35.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from uncompyle6.scanners.scanner3 import Scanner3 # bytecode verification, verify(), uses JUMP_OPs from here diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index b491033ba..5cb70f8b7 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from uncompyle6.scanners.scanner3 import Scanner3 # bytecode verification, verify(), uses JUMP_OPs from here diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 1ab236906..52f87c442 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -51,8 +51,6 @@ # FIXME: DRY code with pysource -from __future__ import print_function - import re, sys from uncompyle6 import PYTHON3, IS_PYPY @@ -75,16 +73,14 @@ from uncompyle6.semantics.make_function import find_all_globals, find_none if PYTHON3: - from itertools import zip_longest from io import StringIO else: - from itertools import izip_longest as zip_longest from StringIO import StringIO from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from collections import namedtuple +from xdis.namedtuple25 import namedtuple NodeInfo = namedtuple("NodeInfo", "node start finish") ExtractInfo = namedtuple("ExtractInfo", "lineNo lineStartOffset markerLine selectedLine selectedText") @@ -980,7 +976,9 @@ def build_ast(self, tokens, customize, isLambda=False, noneInNames=False): tokens.append(Token('LAMBDA_MARKER')) try: ast = parser.parse(self.p, tokens, customize) - except (parser.ParserError, AssertionError) as e: + except parser.ParserError(e): + raise ParserError(e, tokens) + except AssertionError(e): raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) return ast @@ -1005,7 +1003,9 @@ def build_ast(self, tokens, customize, isLambda=False, noneInNames=False): # Build AST from disassembly. try: ast = parser.parse(self.p, tokens, customize) - except (parser.ParserError, AssertionError) as e: + except parser.ParserError(e): + raise ParserError(e, tokens) + except AssertionError(e): raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) @@ -1642,16 +1642,16 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError as p: + except ParserError(p): self.write(str(p)) self.ERROR = p return # build parameters + tup = [paramnames, defparams] params = [build_param(ast, name, default) for - name, default in zip_longest(paramnames, defparams, fillvalue=None)] - + name, default in map(lambda *tup:tup, *tup)] params.reverse() # back to correct order if 4 & code.co_flags: # flag 2 -> variable number of args diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 1b61e2d71..e1a6f9341 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -6,14 +6,9 @@ from xdis.code import iscode from uncompyle6.scanner import Code from uncompyle6.parsers.astnode import AST -from uncompyle6 import PYTHON3 from uncompyle6.semantics.parser_error import ParserError from uncompyle6.semantics.helper import print_docstring -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest from uncompyle6.show import maybe_show_ast_param_default @@ -122,7 +117,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError as p: + except ParserError(p): self.write(str(p)) self.ERROR = p return @@ -301,7 +296,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError as p: + except ParserError(p): self.write(str(p)) self.ERROR = p return @@ -310,8 +305,9 @@ def build_param(ast, name, default): indent = self.indent # build parameters + tup = [paramnames, defparams] params = [build_param(ast, name, default) for - name, default in zip_longest(paramnames, defparams, fillvalue=None)] + name, default in map(lambda *tup:tup, *tup)] params.reverse() # back to correct order if 4 & code.co_flags: # flag 2 -> variable number of args @@ -437,7 +433,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError as p: + except ParserError(p): self.write(str(p)) self.ERROR = p return @@ -447,8 +443,9 @@ def build_param(ast, name, default): # build parameters if self.version != 3.2: + tup = [paramnames, defparams] params = [build_param(ast, name, default) for - name, default in zip_longest(paramnames, defparams, fillvalue=None)] + name, default in map(lambda *tup:tup, *tup)] params.reverse() # back to correct order if 4 & code.co_flags: # flag 2 -> variable number of args diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index f987e8d1f..2109e25bd 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -67,8 +67,6 @@ The '%' may optionally be followed by a number (C) in square brackets, which makes the engine walk down to N[C] before evaluating the escape code. """ -from __future__ import print_function - import sys, re from uncompyle6 import PYTHON3 @@ -2170,7 +2168,9 @@ def build_ast(self, tokens, customize, isLambda=False, tokens.append(Token('LAMBDA_MARKER')) try: ast = python_parser.parse(self.p, tokens, customize) - except (python_parser.ParserError, AssertionError) as e: + except python_parser.ParserError(e): + raise ParserError(e, tokens) + except AssertionError(e): raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) return ast @@ -2197,7 +2197,9 @@ def build_ast(self, tokens, customize, isLambda=False, # Build AST from disassembly. try: ast = python_parser.parse(self.p, tokens, customize) - except (python_parser.ParserError, AssertionError) as e: + except python_parser.ParserError(e): + raise ParserError(e, tokens) + except AssertionError(e): raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) @@ -2275,10 +2277,10 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False, if __name__ == '__main__': def deparse_test(co): "This is a docstring" - sys_version = sys.version_info.major + (sys.version_info.minor / 10.0) + sys_version = float(sys.version[0:3]) deparsed = deparse_code(sys_version, co, showasm='after', showast=True) # deparsed = deparse_code(sys_version, co, showasm=None, showast=False, # showgrammar=True) print(deparsed.text) return - deparse_test(deparse_test.__code__) + deparse_test(deparse_test.func_code) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 0063be7b2..fea389f0e 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -6,8 +6,6 @@ byte-code verification """ -from __future__ import print_function - import dis, operator import uncompyle6 @@ -400,7 +398,7 @@ def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): return msg try: code_obj2 = load_file(src_filename) - except SyntaxError as e: + except SyntaxError(e): return str(e) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) return None From 7133540c235e16f02d2db62cb903b70aa311de20 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 23 Nov 2016 08:26:12 -0500 Subject: [PATCH 002/489] Make work on 2.4 --- Makefile | 2 +- test/Makefile | 2 +- uncompyle6/main.py | 20 +++++++++++--- uncompyle6/parser.py | 5 +++- uncompyle6/parsers/parse3.py | 5 +++- uncompyle6/scanners/scanner2.py | 10 +++++-- uncompyle6/scanners/scanner26.py | 4 ++- uncompyle6/scanners/scanner3.py | 4 ++- uncompyle6/scanners/tok.py | 12 ++++++-- uncompyle6/semantics/fragments.py | 15 ++++++++-- uncompyle6/semantics/make_function.py | 20 +++++++++++--- uncompyle6/semantics/pysource.py | 40 +++++++++++++++++++++------ uncompyle6/show.py | 15 ++++++++-- 13 files changed, 120 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index a431800e8..5e8d471e6 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ check-3.0 check-3.1 check-3.2 check-3.5 check-3.6: $(MAKE) -C test $@ #:Tests for Python 2.6 (doesn't have pytest) -check-2.5 check-2.6: +check-2.4 check-2.5 check-2.6: $(MAKE) -C test $@ #:PyPy 2.6.1 or PyPy 5.0.1 diff --git a/test/Makefile b/test/Makefile index f837216c6..cadd8a03c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -20,7 +20,7 @@ check: $(MAKE) check-$$PYTHON_VERSION #: Run working tests from Python 2.6 or 2.7 -check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-2.7-ok +check-2.4 check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-2.7-ok #: Run working tests from Python 3.1 check-3.0: check-bytecode diff --git a/uncompyle6/main.py b/uncompyle6/main.py index c1fc48406..ab7a05524 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -21,13 +21,25 @@ def uncompyle( # store final output stream for case of error real_out = out or sys.stdout - 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 = "" real_out.write('# uncompyle6 version %s\n' '# %sPython bytecode %s%s\n# Decompiled from: %sPython %s\n' % (VERSION, co_pypy_str, bytecode_version, - " (%d)" % magic_int if magic_int else "", - run_pypy_str, '\n# '.join(sys.version.split('\n')))) + " (%s)" % m, run_pypy_str, + '\n# '.join(sys.version.split('\n')))) if co.co_filename: real_out.write('# Embedded file name: %s\n' % co.co_filename) if timestamp: diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 5f402065d..babbaea87 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -78,7 +78,10 @@ def error(self, instructions, index): err_token = instructions[index] print("Instruction context:") for i in range(start, finish): - indent = ' ' if i != index else '-> ' + if i != index: + indent = ' ' + else: + indent = '-> ' print("%s%s" % (indent, instructions[i])) raise ParserError(err_token, err_token.offset) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 7ff048d0c..dea78bd52 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -453,7 +453,10 @@ def add_make_function_rule(self, rule, opname, attr, customize): """Python 3.3 added a an addtional LOAD_CONST before MAKE_FUNCTION and this has an effect on many rules. """ - new_rule = rule % (('LOAD_CONST ') * (1 if self.version >= 3.3 else 0)) + if self.version >= 3.3: + new_rule = rule % (('LOAD_CONST ') * 1) + else: + new_rule = rule % (('LOAD_CONST ') * 0) self.add_unique_rule(new_rule, opname, attr, customize) def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 62b5d176a..e25928687 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -83,7 +83,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): cause specific rules for the specific number of arguments they take. """ - show_asm = self.show_asm if not show_asm else show_asm + if not show_asm: + show_asm = self.show_asm + # show_asm = 'after' if show_asm in ('both', 'before'): from xdis.bytecode import Bytecode @@ -908,8 +910,10 @@ def find_jump_targets(self, debug): # FIXME: rocky: I think we need something like this... if offset not in set(self.ignore_if) or self.version == 2.7: - source = (self.setup_loops[label] - if label in self.setup_loops else offset) + if label in self.setup_loops: + source = self.setup_loops[label] + else: + source = offset targets[label] = targets.get(label, []) + [source] pass diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 4f65d9f1e..6476e883f 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -86,7 +86,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): cause specific rules for the specific number of arguments they take. """ - show_asm = self.show_asm if not show_asm else show_asm + if not show_asm: + show_asm = self.show_asm + # show_asm = 'after' if show_asm in ('both', 'before'): from xdis.bytecode import Bytecode diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index d3750ca61..564ea9be3 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -146,7 +146,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): cause specific rules for the specific number of arguments they take. """ - show_asm = self.show_asm if not show_asm else show_asm + if not show_asm: + show_asm = self.show_asm + # show_asm = 'after' if show_asm in ('both', 'before'): bytecode = Bytecode(co, self.opc) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index a260a24c2..def37ff13 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -56,12 +56,18 @@ def __str__(self): return self.format(line_prefix='') def format(self, line_prefix=''): - prefix = ('\n%s%4d ' % (line_prefix, self.linestart) - if self.linestart else (' ' * (6 + len(line_prefix)))) + if self.linestart: + prefix = '\n%s%4d ' % (line_prefix, self.linestart) + else: + prefix = ' ' * (6 + len(line_prefix)) offset_opname = '%6s %-17s' % (self.offset, self.type) if not self.has_arg: return "%s%s" % (prefix, offset_opname) - argstr = "%6d " % self.attr if isinstance(self.attr, int) else (' '*7) + + if isinstance(self.attr, int): + argstr = "%6d " % self.attr + else: + argstr = ' '*7 if self.pattr: pattr = self.pattr if self.opc: diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 52f87c442..36fc13e8f 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -732,7 +732,10 @@ def listcomprehension_walk2(self, node): def n_genexpr(self, node): start = len(self.f.getvalue()) self.write('(') - code_index = -6 if self.version > 3.2 else -5 + if self.version > 3.2: + code_index = -6 + else: + code_index = -5 self.comprehension_walk(node, iter_index=3, code_index=code_index) self.write(')') self.set_pos_info(node, start, len(self.f.getvalue())) @@ -886,7 +889,10 @@ def n_classdef(self, node): subclass = n.attr break pass - subclass_info = node if node == 'classdefdeco2' else node[0] + if node == 'classdefdeco2': + subclass_info = node + else: + subclass_info = node[0] elif buildclass[1][0] == 'load_closure': # Python 3 with closures not functions load_closure = buildclass[1] @@ -910,7 +916,10 @@ def n_classdef(self, node): subclass = buildclass[1][0].attr subclass_info = node[0] else: - buildclass = node if (node == 'classdefdeco2') else node[0] + if node == 'classdefdeco2': + buildclass = node + else: + buildclass = node[0] build_list = buildclass[1][0] if hasattr(buildclass[-3][0], 'attr'): subclass = buildclass[-3][0].attr diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index e1a6f9341..b388e49bd 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -151,7 +151,10 @@ def build_param(ast, name, default): self.write(': %s' % value) suffix = ', ' - suffix = ', ' if i > 0 else '' + if i > 0: + suffix = ', ' + else: + suffix = '' for n in node: if n == 'pos_arg': self.write(suffix) @@ -301,7 +304,10 @@ def build_param(ast, name, default): self.ERROR = p return - kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0 + if self.version >= 3.0: + kw_pairs = args_node.attr[1] + else: + kw_pairs = 0 indent = self.indent # build parameters @@ -438,7 +444,10 @@ def build_param(ast, name, default): self.ERROR = p return - kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0 + if self.version >= 3.0: + kw_pairs = args_node.attr[1] + else: + kw_pairs = 0 indent = self.indent # build parameters @@ -480,7 +489,10 @@ def build_param(ast, name, default): i = len(paramnames) - len(defparams) self.write(", ".join(paramnames[:i])) - suffix = ', ' if i > 0 else '' + if i > 0: + suffix = ', ' + else: + suffix = '' for n in node: if n == 'pos_arg': self.write(suffix) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 2109e25bd..c148986f1 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -600,7 +600,10 @@ def n_mkfunc_annotate(node): code = node[-3] self.indentMore() - annotate_last = -4 if self.version == 3.1 else -5 + if self.version == 3.1: + annotate_last = -4 + else: + annotate_last = -5 # FIXME: handle and pass full annotate args make_function3_annotate(self, node, isLambda=False, @@ -1114,7 +1117,10 @@ def n_list_compr(self, node): return n = node[-1] elif node[-1] == 'del_stmt': - n = node[-3] if node[-2] == 'JUMP_BACK' else node[-2] + if node[-2] == 'JUMP_BACK': + n = node[-3] + else: + n = node[-2] assert n == 'list_iter' @@ -1132,7 +1138,10 @@ def n_list_compr(self, node): list_iter = node[-1] else: expr = n[1] - list_iter = node[-3] if node[-2] == 'JUMP_BACK' else node[-2] + if node[-2] == 'JUMP_BACK': + list_iter = node[-3] + else: + list_iter = node[-2] assert expr == 'expr' assert list_iter == 'list_iter' @@ -1174,7 +1183,10 @@ def n_list_compr_pypy27(self, node): self.write( '[ ') expr = n[0] - list_iter = node[-2] if self.is_pypy and node[-1] == 'JUMP_BACK' else node[-1] + if self.is_pypy and node[-1] == 'JUMP_BACK': + list_iter = node[-2] + else: + list_iter = node[-1] assert expr == 'expr' assert list_iter == 'list_iter' @@ -1248,7 +1260,10 @@ def comprehension_walk(self, node, iter_index, code_index=-5): self.write(' for ') self.preorder(ast[iter_index-1]) self.write(' in ') - iter_expr = node[2] if node[2] == 'expr' else node[-3] + if node[2] == 'expr': + iter_expr = node[2] + else: + iter_expr = node[-3] assert iter_expr == 'expr' self.preorder(iter_expr) self.preorder(ast[iter_index]) @@ -1256,7 +1271,10 @@ def comprehension_walk(self, node, iter_index, code_index=-5): def n_genexpr(self, node): self.write('(') - code_index = -6 if self.version > 3.2 else -5 + if self.version > 3.2: + code_index = -6 + else: + code_index = -5 self.comprehension_walk(node, iter_index=3, code_index=code_index) self.write(')') self.prune() @@ -1490,7 +1508,10 @@ def n_classdef(self, node): break pass pass - subclass_info = node if node == 'classdefdeco2' else node[0] + if node == 'classdefdeco2': + subclass_info = node + else: + subclass_info = node[0] elif buildclass[1][0] == 'load_closure': # Python 3 with closures not functions load_closure = buildclass[1] @@ -1514,7 +1535,10 @@ def n_classdef(self, node): subclass = buildclass[1][0].attr subclass_info = node[0] else: - buildclass = node if (node == 'classdefdeco2') else node[0] + if node == 'classdefdeco2': + buildclass = node + else: + buildclass = node[0] build_list = buildclass[1][0] if hasattr(buildclass[-3][0], 'attr'): subclass = buildclass[-3][0].attr diff --git a/uncompyle6/show.py b/uncompyle6/show.py index 8a886f58b..dea00a47a 100644 --- a/uncompyle6/show.py +++ b/uncompyle6/show.py @@ -12,7 +12,10 @@ def maybe_show_asm(showasm, tokens): :param tokens: The asm tokens to show. """ if showasm: - stream = showasm if hasattr(showasm, 'write') else sys.stdout + if hasattr(showasm, 'write'): + stream = showasm + else: + stream = sys.stdout for t in tokens: stream.write(str(t)) stream.write('\n') @@ -29,7 +32,10 @@ def maybe_show_ast(showast, ast): :param ast: The ast to show. """ if showast: - stream = showast if hasattr(showast, 'write') else sys.stdout + if hasattr(showast, 'write'): + stream = showast + else: + stream = sys.stdout stream.write(str(ast)) stream.write('\n') @@ -48,7 +54,10 @@ def maybe_show_ast_param_default(showast, name, default): :param default: The function parameter default. """ if showast: - stream = showast if hasattr(showast, 'write') else sys.stdout + if hasattr(showast, 'write'): + stream = showast + else: + stream = sys.stdout stream.write('\n') stream.write('--' + name) stream.write('\n') From 316aa44f2311395e5f7562d499ccb988bb8927c4 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 24 Nov 2016 04:09:32 -0500 Subject: [PATCH 003/489] Python 2.6 grammary bug and.. __pkginfo.py__: Bump spark_parser version for parse_flags 'dups' --- __pkginfo__.py | 2 +- pytest/test_grammar.py | 4 ++-- uncompyle6/parser.py | 4 ++-- uncompyle6/parsers/parse26.py | 3 +++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 7652cba5d..7ee929f1d 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -37,7 +37,7 @@ 'pydisassemble=uncompyle6.bin.pydisassemble:main', ]} ftp_url = None -install_requires = ['spark-parser >= 1.4.0, < 1.5.0', +install_requires = ['spark-parser >= 1.4.3, < 1.5.0', 'xdis >= 3.2.3, < 3.3.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index a99da771c..13e8159c1 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -59,5 +59,5 @@ def test_dup_rule(): python_parser(PYTHON_VERSION, inspect.currentframe().f_code, is_pypy=IS_PYPY, parser_debug={ - 'rules': True, 'transition': False, 'reduce': False, - 'errorstack': None, 'context': True}) + 'dups': True, 'transition': False, 'reduce': False, + 'rules': False, 'errorstack': None, 'context': True}) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index babbaea87..99d49dd65 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -710,8 +710,8 @@ def python_parser(version, co, out=sys.stdout, showasm=False, maybe_show_asm(showasm, tokens) # For heavy grammar debugging - parser_debug = {'rules': True, 'transition': True, 'reduce' : True, - 'showstack': 'full'} + # parser_debug = {'rules': True, 'transition': True, 'reduce' : True, + # 'showstack': 'full'} p = get_python_parser(version, parser_debug) return parse(p, tokens, customize) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 47c0ac0b8..c485b00f3 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -84,6 +84,7 @@ def p_jumps26(self, args): jb_cont ::= CONTINUE jb_cf_pop ::= JUMP_BACK come_froms POP_TOP + jb_cf_pop ::= JUMP_BACK POP_TOP ja_cf_pop ::= JUMP_ABSOLUTE come_froms POP_TOP jf_cf_pop ::= JUMP_FORWARD come_froms POP_TOP @@ -188,6 +189,8 @@ def p_comp26(self, args): comp_body ::= gen_comp_body + for_block ::= l_stmts_opt _come_from POP_TOP JUMP_BACK + # Make sure we keep indices the same as 2.7 setup_loop_lf ::= SETUP_LOOP LOAD_FAST genexpr_func ::= setup_loop_lf FOR_ITER designator comp_iter jb_bp_come_from From 460069ceaaa94c0a0cce4882d02664df40f2bae1 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 24 Nov 2016 05:15:35 -0500 Subject: [PATCH 004/489] Bug in 2.4 "if" dectection and... Wrong language used in old-style exceptions: use "except Error,e" not "except Error(e)"" --- test/test_pyenvlib.py | 2 -- uncompyle6/linenumbers.py | 2 +- uncompyle6/main.py | 2 +- uncompyle6/scanners/scanner2.py | 6 ++++++ uncompyle6/semantics/make_function.py | 6 +++--- uncompyle6/semantics/pysource.py | 8 ++++---- uncompyle6/verify.py | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index a7f85b414..54e879bce 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -19,8 +19,6 @@ test_pyenvlib --mylib --verify # decompile verify 'mylib' """ -from __future__ import print_function - from uncompyle6 import main, PYTHON3 import os, time, shutil from fnmatch import fnmatch diff --git a/uncompyle6/linenumbers.py b/uncompyle6/linenumbers.py index 17e75a695..a760934b0 100644 --- a/uncompyle6/linenumbers.py +++ b/uncompyle6/linenumbers.py @@ -10,7 +10,7 @@ def line_number_mapping(pyc_filename, src_filename): source_size) = load_module(pyc_filename) try: code2 = load_file(src_filename) - except SyntaxError(e): + except SyntaxError, e: return str(e) queue = deque([code1, code2]) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index ab7a05524..71e3daaf8 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -189,7 +189,7 @@ def _get_outstream(outfile): okay_files += 1 else: print('\n# %s\n\t%s', infile, msg) - except verify.VerifyCmpError(e): + except verify.VerifyCmpError, e: print(e) verify_failed_files += 1 os.rename(outfile, outfile + '_unverified') diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index e25928687..384da59b9 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -446,10 +446,16 @@ def next_except_jump(self, start): if self.version < 2.7 and self.code[jmp] in self.jump_forward: self.not_continue.add(jmp) jmp = self.get_target(jmp) + prev_offset = self.prev[except_match] + # 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 if jmp not in self.pop_jump_if | self.jump_forward: self.ignore_if.add(except_match) return None + self.ignore_if.add(except_match) self.not_continue.add(jmp) return jmp diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index b388e49bd..c6f57523f 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -117,7 +117,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError(p): + except ParserError, p: self.write(str(p)) self.ERROR = p return @@ -299,7 +299,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError(p): + except ParserError, p: self.write(str(p)) self.ERROR = p return @@ -439,7 +439,7 @@ def build_param(ast, name, default): code._customize, isLambda = isLambda, noneInNames = ('None' in code.co_names)) - except ParserError(p): + except ParserError, p: self.write(str(p)) self.ERROR = p return diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index c148986f1..26b92440a 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2192,9 +2192,9 @@ def build_ast(self, tokens, customize, isLambda=False, tokens.append(Token('LAMBDA_MARKER')) try: ast = python_parser.parse(self.p, tokens, customize) - except python_parser.ParserError(e): + except python_parser.ParserError, e: raise ParserError(e, tokens) - except AssertionError(e): + except AssertionError, e: raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) return ast @@ -2221,9 +2221,9 @@ def build_ast(self, tokens, customize, isLambda=False, # Build AST from disassembly. try: ast = python_parser.parse(self.p, tokens, customize) - except python_parser.ParserError(e): + except python_parser.ParserError, e: raise ParserError(e, tokens) - except AssertionError(e): + except AssertionError, e: raise ParserError(e, tokens) maybe_show_ast(self.showast, ast) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index fea389f0e..c09fcd104 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -398,7 +398,7 @@ def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): return msg try: code_obj2 = load_file(src_filename) - except SyntaxError(e): + except SyntaxError, e: return str(e) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) return None From 98cd1417df542ded4aef910e81bdbf22bf2a1e4a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 24 Nov 2016 05:36:43 -0500 Subject: [PATCH 005/489] Remove dup Python 3 grammar rule --- uncompyle6/parsers/parse3.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index dea78bd52..7a678e8d0 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -352,8 +352,6 @@ def p_loop_stmt3(self, args): COME_FROM_LOOP whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP COME_FROM_LOOP - whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP - COME_FROM_LOOP forstmt ::= SETUP_LOOP expr _for designator for_block POP_BLOCK NOP COME_FROM_LOOP """ From 0a37709b0aa8fa2b2501835e717af5a32b032b52 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 24 Nov 2016 05:41:31 -0500 Subject: [PATCH 006/489] CircleCI build --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 4da534f90..65b8c1d0c 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: python: - version: 2.6.9 + version: 2.7.10 environment: COMPILE: --compile From ab6d322eca2ef7ef37243af45eb4f5178dce1966 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Dec 2016 14:09:53 -0500 Subject: [PATCH 007/489] Get ready for release 2.9.7 --- ChangeLog | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26f9f2e47..b3eb09560 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2016-12-04 rocky - * uncompyle6/version.py: Get ready for release 2.9.7 + * : commit d22931cb49f0e28a0fbe48a7c1526b1f170a5b52 Author: rocky + Date: Sun Dec 4 07:31:34 2016 -0500 2016-11-28 rocky @@ -51,11 +52,34 @@ * uncompyle6/semantics/pysource.py: Better line number tracking Indent Python 2 list comprehensions, albeit badly. DRY code a little via indent_if_source_nl +2016-11-24 rocky + + * circle.yml: CircleCI build + +2016-11-24 rocky + + * uncompyle6/parsers/parse3.py: Remove dup Python 3 grammar rule + 2016-11-24 rocky * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: <2.7 "if" detection and dup Python 3 grammar rule +2016-11-24 rocky + + * test/test_pyenvlib.py, uncompyle6/linenumbers.py, + uncompyle6/main.py, uncompyle6/scanners/scanner2.py, + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py: Bug in 2.4 + "if" dectection and... Wrong language used in old-style exceptions: use "except Error,e" + not "except Error(e)"" + +2016-11-24 rocky + + * __pkginfo__.py, pytest/test_grammar.py, uncompyle6/parser.py, + uncompyle6/parsers/parse26.py: Python 2.6 grammary bug and.. __pkginfo.py__: Bump spark_parser + version for parse_flags 'dups' + 2016-11-23 rocky * __pkginfo__.py, pytest/test_grammar.py, uncompyle6/parser.py, @@ -67,8 +91,17 @@ 2016-11-23 rocky - * : commit 6aa1531972de83ecab15b4c96b89c873ea5a7458 Author: rocky - Date: Wed Nov 23 00:48:38 2016 -0500 + * : commit 7133540c235e16f02d2db62cb903b70aa311de20 Author: rocky + Date: Wed Nov 23 08:26:12 2016 -0500 + +2016-11-23 rocky + + * : commit a9349b8f3d12b2aa0cd88286617c1af9cccad018 Author: rocky + Date: Tue Nov 22 17:49:47 2016 -0500 + +2016-11-23 rocky + + * circle.yml: Circle CI uses 2.7.10 and 2.7.12 is not available 2016-11-22 rocky From e2fb7ca3d2c2f79677e6717158fd03d0c7eb567b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Dec 2016 06:36:27 -0500 Subject: [PATCH 008/489] Python 2.6/2.7 tolerance in Python 2.4 branch --- uncompyle6/parser.py | 5 ++++- uncompyle6/scanner.py | 5 ++++- uncompyle6/scanners/scanner2.py | 8 +++++++- uncompyle6/scanners/scanner3.py | 8 +++++++- uncompyle6/semantics/fragments.py | 8 ++++++-- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 403b00c15..821135ee7 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -74,7 +74,10 @@ def debug_reduce(self, rule, tokens, parent, i): def fix(c): s = str(c) i = s.find('_') - return s if i == -1 else s[:i] + if i == -1: + return s + else: + return s[:i] prefix = '' if parent and tokens: diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index bc67d34e6..6e260c3d3 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -226,7 +226,10 @@ def op_size(self, op): if op < self.opc.HAVE_ARGUMENT: return 1 else: - return 2 if self.version >= 3.6 else 3 + if self.version >= 3.6: + return 2 + else: + return 3 def remove_mid_line_ifs(self, ifs): """ diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 63ea391e0..1cd7b57fc 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -20,7 +20,13 @@ Finally we save token information. """ -from xdis.namedtuple25 import namedtuple +from uncompyle6 import PYTHON_VERSION + +if PYTHON_VERSION < 2.6: + from xdis.namedtuple25 import namedtuple +else: + from collections import namedtuple + from array import array from uncompyle6.scanner import op_has_argument diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 667957661..2e040eb9c 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -20,7 +20,13 @@ Finally we save token information. """ -from xdis.namedtuple25 import namedtuple +from uncompyle6 import PYTHON_VERSION + +if PYTHON_VERSION < 2.6: + from xdis.namedtuple25 import namedtuple +else: + from collections import namedtuple + from array import array from uncompyle6.scanner import Scanner, op_has_argument diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 94ff973e2..134a2e1d9 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -53,7 +53,7 @@ import re, sys -from uncompyle6 import PYTHON3, IS_PYPY +from uncompyle6 import PYTHON3, IS_PYPY, PYTHON_VERSION from xdis.code import iscode from uncompyle6.semantics import pysource from uncompyle6 import parser @@ -80,7 +80,11 @@ from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from xdis.namedtuple25 import namedtuple +if PYTHON_VERSION < 2.6: + from xdis.namedtuple25 import namedtuple +else: + from collections import namedtuple + NodeInfo = namedtuple("NodeInfo", "node start finish") ExtractInfo = namedtuple("ExtractInfo", "lineNo lineStartOffset markerLine selectedLine selectedText") From 45b7c1948c3c637aceb5c6b955c26d325451534f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Dec 2016 07:57:31 -0500 Subject: [PATCH 009/489] show-asm on python2.5 is optional Make scanner2 a little more like scanner3. --- uncompyle6/scanners/scanner2.py | 19 ++++++++++++++++--- uncompyle6/scanners/scanner25.py | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 1cd7b57fc..ed7925e07 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -748,7 +748,7 @@ def detect_structure(self, offset, op): else: if (self.version < 2.7 and parent['type'] in ('root', 'for-loop', 'if-then', - 'if-else', 'try')): + 'else', 'try')): self.fixed_jumps[offset] = rtarget else: # note test for < 2.7 might be superflous although informative @@ -801,7 +801,20 @@ def detect_structure(self, offset, op): else: rtarget = pre[rtarget] - # Does the "if" jump just beyond a jump op, then this is probably an if statement + # Does the "jump if" jump beyond a jump op? + # That is, we have something like: + # POP_JUMP_IF_FALSE HERE + # ... + # JUMP_FORWARD + # HERE: + # + # If so, this can be block inside an "if" statement + # or a conditional assignment like: + # x = 1 if x else 2 + # + # There are other contexts we may need to consider + # like whether the target is "END_FINALLY" + # or if the condition jump is to a forward location pre_rtarget = pre[rtarget] code_pre_rtarget = code[pre_rtarget] @@ -836,7 +849,7 @@ def detect_structure(self, offset, op): self.not_continue.add(pre_rtarget) if rtarget < end: - self.structs.append({'type': 'if-else', + self.structs.append({'type': 'else', 'start': rtarget, 'end': end}) elif code_pre_rtarget == self.opc.RETURN_VALUE: diff --git a/uncompyle6/scanners/scanner25.py b/uncompyle6/scanners/scanner25.py index 446f5091d..c270d003d 100755 --- a/uncompyle6/scanners/scanner25.py +++ b/uncompyle6/scanners/scanner25.py @@ -18,7 +18,7 @@ # The history is that 2.7 support is the cleanest, # then from that we got 2.6 and so on. class Scanner25(scan.Scanner26): - def __init__(self, show_asm): + def __init__(self, show_asm=False): # There are no differences in initialization between # 2.5 and 2.6 self.opc = opcode_25 From c8a4dcf72b6604e75d626fd234a5ef00029a5b5f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 25 Dec 2016 09:02:15 -0500 Subject: [PATCH 010/489] Removing NAME_MODULE, lint and bug fixes scanner*.py: show_asm param is optional verify.py: call correct scanners main.py, verify.py: Use older Python print statements --- uncompyle6/main.py | 6 +++--- uncompyle6/scanners/scanner15.py | 4 ++-- uncompyle6/scanners/scanner21.py | 2 +- uncompyle6/scanners/scanner22.py | 2 +- uncompyle6/scanners/scanner23.py | 9 ++++----- uncompyle6/scanners/scanner24.py | 7 +++---- uncompyle6/semantics/pysource.py | 24 ++++++++++++++++++++---- uncompyle6/verify.py | 8 ++++---- 8 files changed, 38 insertions(+), 24 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 49b459716..22d760ae4 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -183,10 +183,10 @@ def _get_outstream(outfile): msg = verify.compare_code_with_srcfile(infile, outfile, weak_verify=weak_verify) if not outfile: if not msg: - print('\n# okay decompiling %s' % infile) + print '\n# okay decompiling %s' % infile okay_files += 1 else: - print('\n# %s\n\t%s', infile, msg) + print '\n# %s\n\t%s', infile, msg except verify.VerifyCmpError, e: print(e) verify_failed_files += 1 @@ -211,7 +211,7 @@ def _get_outstream(outfile): if not outfile: mess = '\n# okay decompiling' # mem_usage = __memUsage() - print(mess, infile) + print mess, infile if outfile: sys.stdout.write("%s\r" % status_msg(do_verify, tot_files, okay_files, failed_files, verify_failed_files)) diff --git a/uncompyle6/scanners/scanner15.py b/uncompyle6/scanners/scanner15.py index 74844a798..42c99e9e6 100644 --- a/uncompyle6/scanners/scanner15.py +++ b/uncompyle6/scanners/scanner15.py @@ -13,13 +13,13 @@ from xdis.opcodes import opcode_15 JUMP_OPs = opcode_15.JUMP_OPs -# We base this off of 2.2 instead of the other way around +# We base this off of 2.1 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. class Scanner15(scan.Scanner21): def __init__(self, show_asm=False): - scan.Scanner21.__init__(self, show_asm) + scan.Scanner21.__init__(self, show_asm=False) self.opc = opcode_15 self.opname = opcode_15.opname self.version = 1.5 diff --git a/uncompyle6/scanners/scanner21.py b/uncompyle6/scanners/scanner21.py index 813dde115..53a5b405f 100644 --- a/uncompyle6/scanners/scanner21.py +++ b/uncompyle6/scanners/scanner21.py @@ -19,7 +19,7 @@ # then from that we got 2.6 and so on. class Scanner21(scan.Scanner22): def __init__(self, show_asm=False): - scan.Scanner22.__init__(self, show_asm) + scan.Scanner22.__init__(self, show_asm=False) self.opc = opcode_21 self.opname = opcode_21.opname self.version = 2.1 diff --git a/uncompyle6/scanners/scanner22.py b/uncompyle6/scanners/scanner22.py index 96f62b70c..d2f8eecd5 100644 --- a/uncompyle6/scanners/scanner22.py +++ b/uncompyle6/scanners/scanner22.py @@ -19,7 +19,7 @@ # then from that we got 2.6 and so on. class Scanner22(scan.Scanner23): def __init__(self, show_asm=False): - scan.Scanner23.__init__(self, show_asm) + scan.Scanner23.__init__(self, show_asm=False) self.opc = opcode_22 self.opname = opcode_22.opname self.version = 2.2 diff --git a/uncompyle6/scanners/scanner23.py b/uncompyle6/scanners/scanner23.py index 0d8de2826..688fa1b6b 100644 --- a/uncompyle6/scanners/scanner23.py +++ b/uncompyle6/scanners/scanner23.py @@ -2,9 +2,8 @@ """ Python 2.3 bytecode scanner/deparser -This overlaps Python's 2.3'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. +This massages tokenized 2.3 bytecode to make it more amenable for +grammar parsing. """ import uncompyle6.scanners.scanner24 as scan @@ -13,12 +12,12 @@ from xdis.opcodes import opcode_23 JUMP_OPs = opcode_23.JUMP_OPs -# We base this off of 2.5 instead of the other way around +# We base this off of 2.4 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. class Scanner23(scan.Scanner24): - def __init__(self, show_asm): + def __init__(self, show_asm=False): scan.Scanner24.__init__(self, show_asm) self.opc = opcode_23 self.opname = opcode_23.opname diff --git a/uncompyle6/scanners/scanner24.py b/uncompyle6/scanners/scanner24.py index 9f5500252..b994241ed 100755 --- a/uncompyle6/scanners/scanner24.py +++ b/uncompyle6/scanners/scanner24.py @@ -2,9 +2,8 @@ """ Python 2.4 bytecode scanner/deparser -This overlaps Python's 2.4'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. +This massages tokenized 2.7 bytecode to make it more amenable for +grammar parsing. """ import uncompyle6.scanners.scanner25 as scan @@ -18,7 +17,7 @@ # The history is that 2.7 support is the cleanest, # then from that we got 2.6 and so on. class Scanner24(scan.Scanner25): - def __init__(self, show_asm): + def __init__(self, show_asm=False): scan.Scanner25.__init__(self, show_asm) # These are the only differences in initialization between # 2.4, 2.5 and 2.6 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 9709252b4..d065c0477 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -129,12 +129,16 @@ NAME_MODULE = AST('stmt', [ AST('assign', - [ AST('expr', [Token('LOAD_NAME', pattr='__name__')]), - AST('designator', [ Token('STORE_NAME', pattr='__module__')]) + [ AST('expr', + [Token('LOAD_NAME', pattr='__name__', offset=0, has_arg=True)]), + AST('designator', + [ Token('STORE_NAME', pattr='__module__', offset=3, has_arg=True)]) ])]) -# TAB = '\t' # as God intended -TAB = ' ' *4 # is less spacy than "\t" +# God intended \t, but Python has decided to use 4 spaces. +# If you want real tabs, use Go. +# TAB = '\t' +TAB = ' ' * 4 INDENT_PER_LEVEL = ' ' # additional intent per pretty-print level TABLE_R = { @@ -542,6 +546,18 @@ def customize_for_version(self, is_pypy, version): TABLE_DIRECT.update({ 'importlist2': ( '%C', (0, maxint, ', ') ), }) + if version <= 2.4: + global NAME_MODULE + NAME_MODULE = AST('stmt', + [ AST('assign', + [ AST('expr', + [Token('LOAD_GLOBAL', pattr='__name__', + offset=0, has_arg=True)]), + AST('designator', + [ Token('STORE_NAME', pattr='__module__', + offset=3, has_arg=True)]) + ])]) + pass if version <= 2.3: TABLE_DIRECT.update({ 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 4 ) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 21192603a..8c2aaa959 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -182,16 +182,16 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, elif member == 'co_code' and not ignore_code: if version == 2.3: import uncompyle6.scanners.scanner23 as scan - scanner = scan.Scanner26() + scanner = scan.Scanner23(show_asm=False) elif version == 2.4: import uncompyle6.scanners.scanner24 as scan - scanner = scan.Scanner25() + scanner = scan.Scanner24(show_asm=False) elif version == 2.5: import uncompyle6.scanners.scanner25 as scan - scanner = scan.Scanner25() + scanner = scan.Scanner25(show_asm=False) elif version == 2.6: import uncompyle6.scanners.scanner26 as scan - scanner = scan.Scanner26() + scanner = scan.Scanner26(show_asm=False) elif version == 2.7: if is_pypy: import uncompyle6.scanners.pypy27 as scan From 7f2bee46b7c668617b17c868a7c7125c84c6c99d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 26 Dec 2016 01:55:16 -0500 Subject: [PATCH 011/489] Bug in using python2 ast checking in python 2.5 --- uncompyle6/parsers/parse25.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index df60375ef..195d15dfd 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -41,8 +41,11 @@ def add_custom_rules(self, tokens, customize): self.check_reduce['tryelsestmt'] = 'tokens' def reduce_is_invalid(self, rule, ast, tokens, first, last): - super(Python25Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) - + invalid = super(Python25Parser, + self).reduce_is_invalid(rule, ast, + tokens, first, last) + if invalid: + return invalid lhs = rule[0] if lhs in ('tryelsestmt', ): # The end of the else part of try/else come_from has to come From b00651d428eee73eead7204131676a198c3c69d9 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 31 Dec 2016 05:19:21 -0500 Subject: [PATCH 012/489] Merge master branche Handle 2.2 list_if --- test/Makefile | 2 +- test/bytecode_2.6/04_if_and_bug.pyc | Bin 0 -> 573 bytes test/bytecode_2.6/05_ifelse.pyc | Bin 983 -> 0 bytes test/bytecode_3.4/05_while_true_break.pyc | Bin 0 -> 365 bytes uncompyle6/main.py | 11 +- uncompyle6/parsers/parse26.py | 69 ++++++++--- uncompyle6/scanners/scanner2.py | 129 ++++++++++++++++----- uncompyle6/scanners/scanner26.py | 30 ++--- uncompyle6/scanners/scanner3.py | 135 ++++++++++++++-------- uncompyle6/semantics/pysource.py | 6 +- uncompyle6/verify.py | 1 + 11 files changed, 268 insertions(+), 115 deletions(-) create mode 100644 test/bytecode_2.6/04_if_and_bug.pyc delete mode 100644 test/bytecode_2.6/05_ifelse.pyc create mode 100644 test/bytecode_3.4/05_while_true_break.pyc diff --git a/test/Makefile b/test/Makefile index 2e52264c2..aaa3efe7b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -100,7 +100,7 @@ check-bytecode-2.5: #: Check deparsing Python 2.6 check-bytecode-2.6: - $(PYTHON) test_pythonlib.py --bytecode-2.6 + $(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify #: Check deparsing Python 2.7 check-bytecode-2.7: diff --git a/test/bytecode_2.6/04_if_and_bug.pyc b/test/bytecode_2.6/04_if_and_bug.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f2bb75c4d8a8273eda0a18484d1fc8a8e34d18c GIT binary patch literal 573 zcmZut!Ab)`41L*cYb{ox2o}8x_N1bs9z^^CFJ5FX!`ew@wC&dJ6zREN=+PhW1M~y* z&8$@q4kVM8yu5_Gyti9d$Nk$rzF&?16|JlZpnwG)5)>a0l?YN4Zv@E_yb`3)8Z7IA zMGBW-0c3U91X@QoYd{+T1fdqhreJC;l}at9cL-KsE3i%w#m+PN;iZw+V~N5Q_`m6F z*+hwo*WpY7SKf;208bF9R;uQ7H@C88*j}6Dke4COwRPO|8oY-4-i_46Aly6BLTTWpr8i6R1~ZeX z_EoJL-;+KseTTWf>ZbG@5r>Al@kMO!k%nJa?h=-6G#RQXi`lfV2Y0jkqtk=K6XOOZ nA6rAbKbiX`i5H{7&W3uKgr+Xto^+)pZQ8c1%O0&QoungQVAOFF literal 0 HcmV?d00001 diff --git a/test/bytecode_2.6/05_ifelse.pyc b/test/bytecode_2.6/05_ifelse.pyc deleted file mode 100644 index babe289481d2de28d6750864d0434a3b79d727bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 983 zcmaJ^2C9Yc;Teu_zOHJyPpZ35pO16l9!1|mz)H0| z-DcYL(Dro7^hpoa6jx8^m>eRnTx+2o^2b?7mdK;l*w5nX*bb5+PkUqspN1VlkY#u# zWab}&bQ=j`U^W;kw56O>_^+Vts@yLn2-=hP6!fKpI%%d_w};OwhMEEimDHSL~0dB iu}Y@lMOd?Vb@4j{X9Cw0k`O diff --git a/test/bytecode_3.4/05_while_true_break.pyc b/test/bytecode_3.4/05_while_true_break.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c64c7ce1a862d3cdc4d4bb516fcbd4315aac9327 GIT binary patch literal 365 zcmYk1u};G<6h)uwG%XPo%yeT5NVF(hwK4BLW(^Rf+1$$8G$WfBBaCkZ}} literal 0 HcmV?d00001 diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 22d760ae4..996fc660b 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -130,8 +130,9 @@ def _get_outstream(outfile): prefix = prefix[:-len('.py')] junk, outfile = tempfile.mkstemp(suffix=".py", prefix=prefix) - # Unbuffer output - sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + # Unbuffer output if possible + buffering = -1 if sys.stdout.isatty() else 0 + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) tee = subprocess.Popen(["tee", outfile], stdin=subprocess.PIPE) os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) @@ -238,11 +239,11 @@ def status_msg(do_verify, tot_files, okay_files, failed_files, verify_failed_files): if tot_files == 1: if failed_files: - return "decompile failed" + return "\n# decompile failed" elif verify_failed_files: - return "decompile verify failed" + return "\n# decompile verify failed" else: - return "Successfully decompiled file" + return "\n# Successfully decompiled file" pass pass mess = "decompiled %i files: %i okay, %i failed" % (tot_files, okay_files, failed_files) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index c65ab602c..c3b485255 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -113,16 +113,10 @@ def p_stmt26(self, args): break_stmt ::= BREAK_LOOP JUMP_BACK - # Semantic actions want the else to be at position 3 - ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite come_froms - ifelsestmt ::= testexpr c_stmts_opt filler else_suitel come_froms POP_TOP - # Semantic actions want else_suitel to be at index 3 ifelsestmtl ::= testexpr c_stmts_opt jb_cf_pop else_suitel ifelsestmtc ::= testexpr c_stmts_opt ja_cf_pop else_suitec - iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP - # Semantic actions want suite_stmts_opt to be at index 3 withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY @@ -159,6 +153,29 @@ def p_stmt26(self, args): while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK COME_FROM + ifstmt ::= testexpr_then _ifstmts_jump + + # Semantic actions want the else to be at position 3 + ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite come_froms + ifelsestmt ::= testexpr_then c_stmts_opt jf_cf_pop else_suite come_froms + ifelsestmt ::= testexpr c_stmts_opt filler else_suitel come_froms POP_TOP + ifelsestmt ::= testexpr_then c_stmts_opt filler else_suitel come_froms POP_TOP + + # Semantic actions want else_suitel to be at index 3 + ifelsestmtl ::= testexpr_then c_stmts_opt jb_cf_pop else_suitel + ifelsestmtc ::= testexpr_then c_stmts_opt ja_cf_pop else_suitec + + iflaststmt ::= testexpr_then c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP + iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP + + testexpr_then ::= testtrue_then + testexpr_then ::= testfalse_then + testtrue_then ::= expr jmp_true_then + testfalse_then ::= expr jmp_false_then + + jmp_false_then ::= JUMP_IF_FALSE THEN POP_TOP + jmp_true_then ::= JUMP_IF_TRUE THEN POP_TOP + # Common with 2.7 while1stmt ::= SETUP_LOOP return_stmts bp_come_from while1stmt ::= SETUP_LOOP return_stmts COME_FROM @@ -196,16 +213,16 @@ def p_comp26(self, args): genexpr_func ::= setup_loop_lf FOR_ITER designator comp_iter JUMP_BACK come_from_pop jb_bp_come_from genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 COME_FROM - + list_if ::= list_if ::= expr jmp_false_then list_iter ''' def p_ret26(self, args): ''' - ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM - ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM - ret_cond ::= expr jmp_false expr RETURN_END_IF POP_TOP ret_expr_or_cond - ret_cond ::= expr jmp_false expr ret_expr_or_cond - ret_cond_not ::= expr jmp_true expr RETURN_END_IF POP_TOP ret_expr_or_cond + ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM + ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM + ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond + ret_cond ::= expr jmp_false_then expr ret_expr_or_cond + ret_cond_not ::= expr jmp_true_then expr RETURN_END_IF POP_TOP ret_expr_or_cond return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP return_stmt ::= ret_expr RETURN_VALUE POP_TOP @@ -215,17 +232,37 @@ def p_ret26(self, args): ''' def p_except26(self, args): - ''' + """ except_suite ::= c_stmts_opt jmp_abs POP_TOP - ''' + """ def p_misc26(self, args): - ''' + """ conditional ::= expr jmp_false expr jf_cf_pop expr come_from_opt and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP cmp_list ::= expr cmp_list1 ROT_TWO COME_FROM POP_TOP _come_from - ''' + conditional_lambda ::= expr jmp_false_then return_if_stmt return_stmt LAMBDA_MARKER + """ + + def add_custom_rules(self, tokens, customize): + super(Python26Parser, self).add_custom_rules(tokens, customize) + self.check_reduce['and'] = 'AST' + + def reduce_is_invalid(self, rule, ast, tokens, first, last): + invalid = super(Python26Parser, + 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" + jmp_false = ast[1][0] + jmp_target = jmp_false.offset + jmp_false.attr + 3 + return not (jmp_target == tokens[last].offset or + tokens[last].pattr == jmp_false.pattr) + return False class Python26ParserSingle(Python2Parser, PythonParserSingle): pass diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index a7f376c50..35635fc1b 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -484,7 +484,7 @@ def next_except_jump(self, start): elif op in self.setup_ops: count_SETUP_ += 1 - def detect_structure(self, offset, op): + def detect_control_flow(self, offset, op): """ Detect type of block structures and their boundaries to fix optimized jumps in python2.3+ @@ -682,6 +682,8 @@ def detect_structure(self, offset, op): self.fixed_jumps[offset] = rtarget return + jump_if_offset = offset + start = offset+3 pre = self.prev @@ -704,6 +706,10 @@ def detect_structure(self, offset, op): 'end': pre[target]}) return + # The op offset just before the target jump offset is important + # in making a determination of what we have. Save that. + pre_rtarget = pre[rtarget] + # Is it an "and" inside an "if" or "while" block if op == self.opc.PJIF: @@ -714,22 +720,22 @@ def detect_structure(self, offset, op): # If we still have any offsets in set, start working on it if match: - if code[pre[rtarget]] in self.jump_forward \ - and pre[rtarget] not in self.stmts \ - and self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget: - if code[pre[pre[rtarget]]] == self.opc.JUMP_ABSOLUTE \ + if code[pre_rtarget] in self.jump_forward \ + and pre_rtarget not in self.stmts \ + and self.restrict_to_parent(self.get_target(pre_rtarget), parent) == rtarget: + if code[pre[pre_rtarget]] == self.opc.JUMP_ABSOLUTE \ and self.remove_mid_line_ifs([offset]) \ - and target == self.get_target(pre[pre[rtarget]]) \ - and (pre[pre[rtarget]] not in self.stmts or self.get_target(pre[pre[rtarget]]) > pre[pre[rtarget]])\ - and 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], self.pop_jump_if, target))): + and target == self.get_target(pre[pre_rtarget]) \ + and (pre[pre_rtarget] not in self.stmts or self.get_target(pre[pre_rtarget]) > pre[pre_rtarget])\ + and 1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre_rtarget], self.pop_jump_if, target))): pass - elif code[pre[pre[rtarget]]] == self.opc.RETURN_VALUE \ + elif code[pre[pre_rtarget]] == self.opc.RETURN_VALUE \ and self.remove_mid_line_ifs([offset]) \ and 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, - pre[pre[rtarget]], + pre[pre_rtarget], self.pop_jump_if, target))) - | set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], - (self.opc.PJIF, self.opc.PJIT, self.opc.JUMP_ABSOLUTE), pre[rtarget], True))))): + | set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre_rtarget], + (self.opc.PJIF, self.opc.PJIT, self.opc.JUMP_ABSOLUTE), pre_rtarget, True))))): pass else: fix = None @@ -762,7 +768,7 @@ def detect_structure(self, offset, op): else: assert_offset = offset + 3 if (assert_offset) in self.load_asserts: - if code[pre[rtarget]] == self.opc.RAISE_VARARGS: + if code[pre_rtarget] == self.opc.RAISE_VARARGS: return self.load_asserts.remove(assert_offset) @@ -771,7 +777,7 @@ def detect_structure(self, offset, op): pass elif code[next] in self.jump_forward and target == self.get_target(next): if code[pre[next]] == self.opc.PJIF: - if code[next] == self.opc.JUMP_FORWARD or target != rtarget or code[pre[pre[rtarget]]] not in (self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE): + if code[next] == self.opc.JUMP_FORWARD or target != rtarget or code[pre[pre_rtarget]] not in (self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE): self.fixed_jumps[offset] = pre[next] return elif code[next] == self.opc.JUMP_ABSOLUTE and code[target] in self.jump_forward: @@ -788,17 +794,17 @@ def detect_structure(self, offset, op): return if self.version == 2.7: - if code[pre[rtarget]] == self.opc.JUMP_ABSOLUTE and pre[rtarget] in self.stmts \ - and pre[rtarget] != offset and pre[pre[rtarget]] != offset: + if code[pre_rtarget] == self.opc.JUMP_ABSOLUTE and pre_rtarget in self.stmts \ + and pre_rtarget != offset and pre[pre_rtarget] != offset: if code[rtarget] == self.opc.JUMP_ABSOLUTE and code[rtarget+3] == self.opc.POP_BLOCK: - if code[pre[pre[rtarget]]] != self.opc.JUMP_ABSOLUTE: + if code[pre[pre_rtarget]] != self.opc.JUMP_ABSOLUTE: pass - elif self.get_target(pre[pre[rtarget]]) != target: + elif self.get_target(pre[pre_rtarget]) != target: pass else: - rtarget = pre[rtarget] + rtarget = pre_rtarget else: - rtarget = pre[rtarget] + rtarget = pre_rtarget # Does the "jump if" jump beyond a jump op? # That is, we have something like: @@ -814,7 +820,6 @@ def detect_structure(self, offset, op): # There are other contexts we may need to consider # like whether the target is "END_FINALLY" # or if the condition jump is to a forward location - pre_rtarget = pre[rtarget] code_pre_rtarget = code[pre_rtarget] if code_pre_rtarget in self.jump_forward: @@ -834,20 +839,86 @@ def detect_structure(self, offset, op): jump_target = self.get_target(next_offset, next_op) if jump_target in self.setup_loops: self.structs.append({'type': 'while-loop', - 'start': start - 3, + 'start': jump_if_offset, 'end': jump_target}) - self.fixed_jumps[start-3] = jump_target + self.fixed_jumps[jump_if_offset] = jump_target return end = self.restrict_to_parent(if_end, parent) - self.structs.append({'type': 'if-then', - 'start': start-3, - 'end': pre_rtarget}) + if_then_maybe = None + + if 2.2 <= self.version <= 2.6: + # Take the JUMP_IF target. In an "if/then", it will be + # a POP_TOP instruction and the instruction before it + # will be a JUMP_FORWARD to just after the POP_TOP. + # For example: + # Good: + # 3 JUMP_IF_FALSE 33 'to 39' + # .. + # 36 JUMP_FORWARD 1 'to 40' + # 39 POP_TOP + # 40 ... + # example: + + # BAD (is an "and"): + # 28 JUMP_IF_FALSE 4 'to 35' + # ... + # 32 JUMP_ABSOLUTE 40 'to 40' # should be 36 or there should + # # be a COME_FROM at the pop top + # # before 40 to 35 + # 35 POP_TOP + # 36 ... + # 39 POP_TOP + # 39_0 COME_FROM 3 + # 40 ... + + if self.opc.opname[code[jump_if_offset]].startswith('JUMP_IF'): + jump_if_target = code[jump_if_offset+1] + if self.opc.opname[code[jump_if_target + jump_if_offset + 3]] == 'POP_TOP': + jump_inst = jump_if_target + jump_if_offset + jump_offset = code[jump_inst+1] + jump_op = self.opc.opname[code[jump_inst]] + if (jump_op == 'JUMP_FORWARD' and jump_offset == 1): + self.structs.append({'type': 'if-then', + 'start': start-3, + 'end': pre_rtarget}) + + self.thens[start] = end + elif jump_op == 'JUMP_ABSOLUTE': + if_then_maybe = {'type': 'if-then', + 'start': start-3, + 'end': pre_rtarget} + + elif self.version == 2.7: + self.structs.append({'type': 'if-then', + 'start': start-3, + 'end': pre_rtarget}) self.not_continue.add(pre_rtarget) if rtarget < end: + # We have an "else" block of some kind. + # Is it associated with "if_then_maybe" seen above? + # These will be linked in this funny way: + + # 198 JUMP_IF_FALSE 18 'to 219' + # 201 POP_TOP + # ... + # 216 JUMP_ABSOLUTE 256 'to 256' + # 219 POP_TOP + # ... + # 252 JUMP_FORWARD 1 'to 256' + # 255 POP_TOP + # 256 + if if_then_maybe and jump_op == 'JUMP_ABSOLUTE': + jump_target = self.get_target(jump_inst, code[jump_inst]) + if self.opc.opname[code[end]] == 'JUMP_FORWARD': + end_target = self.get_target(end, code[end]) + if jump_target == end_target: + self.structs.append(if_then_maybe) + self.thens[start] = end + self.structs.append({'type': 'else', 'start': rtarget, 'end': end}) @@ -856,6 +927,7 @@ def detect_structure(self, offset, op): self.structs.append({'type': 'if-then', 'start': start, 'end': rtarget}) + self.thens[start] = rtarget if self.version == 2.7 or code[pre_rtarget+1] != self.opc.JUMP_FORWARD: self.return_end_ifs.add(pre_rtarget) @@ -889,11 +961,12 @@ def find_jump_targets(self, debug): self.ignore_if = set() self.build_statement_indices() - # Containers filled by detect_structure() + # Containers filled by detect_control_flow() self.not_continue = set() self.return_end_ifs = set() self.setup_loop_targets = {} # target given setup_loop offset self.setup_loops = {} # setup_loop offset given target + self.thens = {} # JUMP_IF's that separate the 'then' part of an 'if' targets = {} for offset in self.op_range(0, n): @@ -901,7 +974,7 @@ def find_jump_targets(self, debug): # Determine structures and fix jumps in Python versions # since 2.3 - self.detect_structure(offset, op) + self.detect_control_flow(offset, op) if op_has_argument(op, self.opc): label = self.fixed_jumps.get(offset) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index d44c934bf..df6b0b234 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -96,35 +96,32 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): for instr in bytecode.get_instructions(co): print(instr._disassemble()) - # from xdis.bytecode import Bytecode - # bytecode = Bytecode(co, self.opc) - # for instr in bytecode.get_instructions(co): - # print(instr._disassemble()) - # Container for tokens tokens = [] customize = {} + if self.is_pypy: + customize['PyPy'] = 1 + Token = self.Token # shortcut - n = self.setup_code(co) + codelen = self.setup_code(co) - self.build_lines_data(co, n) - self.build_prev_op(n) + self.build_lines_data(co, codelen) + self.build_prev_op(codelen) free, names, varnames = self.unmangle_code_names(co, classname) self.names = names - codelen = len(self.code) - # Scan for assertions. Later we will # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'. # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() - for i in self.op_range(0, n): - # We need to detect the difference between - # "raise AssertionError" and - # "assert" + for i in self.op_range(0, codelen): + # We need to detect the difference between: + # raise AssertionError + # and + # assert ... if (self.code[i] == self.opc.JUMP_IF_TRUE and i + 4 < codelen and self.code[i+3] == self.opc.POP_TOP and @@ -169,6 +166,11 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): offset="%s_%d" % (offset, jump_idx), has_arg = True)) jump_idx += 1 + elif offset in self.thens: + tokens.append(Token( + 'THEN', None, self.thens[offset], + offset="%s_0" % offset, + has_arg = True)) has_arg = (op >= self.opc.HAVE_ARGUMENT) if has_arg: diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 28fb7c48a..0348f5b77 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -205,6 +205,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # Get jump targets # Format: {target offset: [jump offsets]} jump_targets = self.find_jump_targets(show_asm) + last_op_was_break = False for inst in bytecode: @@ -327,10 +328,12 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if target <= inst.offset: next_opname = self.opname[self.code[inst.offset+3]] if (inst.offset in self.stmts and - next_opname not in ('END_FINALLY', 'POP_BLOCK', + (next_opname not in ('END_FINALLY', 'POP_BLOCK', # Python 3.0 only uses POP_TOP 'POP_TOP') - and inst.offset not in self.not_continue): + and inst.offset not in self.not_continue) or + (tokens[-1].type == 'RETURN_VALUE' and + self.version < 3.5)): opname = 'CONTINUE' else: opname = 'JUMP_BACK' @@ -340,15 +343,21 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # There are other situations where we don't catch # CONTINUE as well. if tokens[-1].type == 'JUMP_BACK' and tokens[-1].attr <= argval: - # intern is used because we are changing the *previous* token - tokens[-1].type = intern('CONTINUE') - + if tokens[-2].type == 'BREAK_LOOP': + del tokens[-1] + else: + # intern is used because we are changing the *previous* token + tokens[-1].type = intern('CONTINUE') + if last_op_was_break and opname == 'CONTINUE': + last_op_was_break = False + continue elif op == self.opc.RETURN_VALUE: if inst.offset in self.return_end_ifs: opname = 'RETURN_END_IF' elif inst.offset in self.load_asserts: opname = 'LOAD_ASSERT' + last_op_was_break = opname == 'BREAK_LOOP' tokens.append( Token( type_ = opname, @@ -440,7 +449,7 @@ def find_jump_targets(self, debug): self.build_statement_indices() self.else_start = {} - # Containers filled by detect_structure() + # Containers filled by detect_control_flow() self.not_continue = set() self.return_end_ifs = set() self.setup_loop_targets = {} # target given setup_loop offset @@ -452,7 +461,7 @@ def find_jump_targets(self, debug): # Determine structures and fix jumps in Python versions # since 2.3 - self.detect_structure(offset, targets) + self.detect_control_flow(offset, targets) has_arg = (op >= op3.HAVE_ARGUMENT) if has_arg: @@ -579,7 +588,7 @@ def get_target(self, offset): return target - def detect_structure(self, offset, targets): + def detect_control_flow(self, offset, targets): """ Detect structures and their boundaries to fix optimized jumps in python2.3+ @@ -606,7 +615,6 @@ def detect_structure(self, offset, targets): parent = struct if op == self.opc.SETUP_LOOP: - # We categorize loop types: 'for', 'while', 'while 1' with # possibly suffixes '-loop' and '-else' # Try to find the jump_back instruction of the loop. @@ -624,20 +632,30 @@ def detect_structure(self, offset, targets): jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, next_line_byte, False) - if jump_back and jump_back != self.prev_op[end] and self.is_jump_forward(jump_back+3): - if (code[self.prev_op[end]] == self.opc.RETURN_VALUE - or (code[self.prev_op[end]] == self.opc.POP_BLOCK - and code[self.prev_op[self.prev_op[end]]] == self.opc.RETURN_VALUE)): + jump_forward_offset = jump_back+3 + return_val_offset1 = self.prev[self.prev[end]] + + if (jump_back and jump_back != self.prev_op[end] + and self.is_jump_forward(jump_forward_offset)): + if (code[self.prev_op[end]] == self.opc.RETURN_VALUE or + (code[self.prev_op[end]] == self.opc.POP_BLOCK + and code[return_val_offset1] == self.opc.RETURN_VALUE)): jump_back = None - if not jump_back: # loop suite ends in return. wtf right? + if not jump_back: + # loop suite ends in return jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE) + 1 if not jump_back: return + + jump_back += 1 + if_offset = None if code[self.prev_op[next_line_byte]] not in POP_JUMP_TF: - loop_type = 'for' - else: + if_offset = self.prev[next_line_byte] + if if_offset: loop_type = 'while' - self.ignore_if.add(self.prev_op[next_line_byte]) + self.ignore_if.add(if_offset) + else: + loop_type = 'for' target = next_line_byte end = jump_back + 3 else: @@ -651,6 +669,7 @@ def detect_structure(self, offset, targets): elif target < offset: self.fixed_jumps[offset] = jump_back+4 end = jump_back+4 + target = self.get_target(jump_back) if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER): @@ -658,6 +677,7 @@ def detect_structure(self, offset, targets): else: loop_type = 'while' test = self.prev_op[next_line_byte] + if test == offset: loop_type = 'while 1' elif self.code[test] in op3.hasjabs+op3.hasjrel: @@ -698,38 +718,40 @@ def detect_structure(self, offset, targets): 'end': prev_op[target]}) return - # Is it an "and" inside an "if" block + # The op offset just before the target jump offset is important + # in making a determination of what we have. Save that. + pre_rtarget = prev_op[rtarget] + + # Is it an "and" inside an "if" or "while" block if op == self.opc.POP_JUMP_IF_FALSE: + # Search for another POP_JUMP_IF_FALSE targetting the same op, # in current statement, starting from current offset, and filter # everything inside inner 'or' jumps and midline ifs match = self.rem_or(start, self.next_stmt[offset], self.opc.POP_JUMP_IF_FALSE, target) - # We can't remove mid-line ifs because line structures have changed - # from restructBytecode(). - # match = self.remove_mid_line_ifs(match) # If we still have any offsets in set, start working on it if match: - is_jump_forward = self.is_jump_forward(prev_op[rtarget]) - if (is_jump_forward and prev_op[rtarget] not in self.stmts and - self.restrict_to_parent(self.get_target(prev_op[rtarget]), parent) == rtarget): - if (code[prev_op[prev_op[rtarget]]] == self.opc.JUMP_ABSOLUTE + is_jump_forward = self.is_jump_forward(pre_rtarget) + if (is_jump_forward and pre_rtarget not in self.stmts and + self.restrict_to_parent(self.get_target(pre_rtarget), parent) == rtarget): + if (code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE and self.remove_mid_line_ifs([offset]) and - target == self.get_target(prev_op[prev_op[rtarget]]) and - (prev_op[prev_op[rtarget]] not in self.stmts or - self.get_target(prev_op[prev_op[rtarget]]) > prev_op[prev_op[rtarget]]) and - 1 == len(self.remove_mid_line_ifs(self.rem_or(start, prev_op[prev_op[rtarget]], POP_JUMP_TF, target)))): + target == self.get_target(prev_op[pre_rtarget]) and + (prev_op[pre_rtarget] not in self.stmts or + self.get_target(prev_op[pre_rtarget]) > prev_op[pre_rtarget]) and + 1 == len(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], POP_JUMP_TF, target)))): pass - elif (code[prev_op[prev_op[rtarget]]] == self.opc.RETURN_VALUE + elif (code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE and self.remove_mid_line_ifs([offset]) and - 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[prev_op[rtarget]], + 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], POP_JUMP_TF, target))) | - set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[prev_op[rtarget]], + set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], (self.opc.POP_JUMP_IF_FALSE, self.opc.POP_JUMP_IF_TRUE, self.opc.JUMP_ABSOLUTE), - prev_op[rtarget], True)))))): + pre_rtarget, True)))))): pass else: fix = None @@ -757,7 +779,7 @@ def detect_structure(self, offset, targets): if code[prev_op[next]] == self.opc.POP_JUMP_IF_FALSE: if (code[next] == self.opc.JUMP_FORWARD or target != rtarget - or code[prev_op[prev_op[rtarget]]] not in + or code[prev_op[pre_rtarget]] not in (self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE)): self.fixed_jumps[offset] = prev_op[next] return @@ -770,14 +792,14 @@ def detect_structure(self, offset, targets): if offset in self.ignore_if: return - if (code[prev_op[rtarget]] == self.opc.JUMP_ABSOLUTE and - prev_op[rtarget] in self.stmts and - prev_op[rtarget] != offset and - prev_op[prev_op[rtarget]] != offset and + if (code[pre_rtarget] == self.opc.JUMP_ABSOLUTE and + pre_rtarget in self.stmts and + pre_rtarget != offset and + prev_op[pre_rtarget] != offset and not (code[rtarget] == self.opc.JUMP_ABSOLUTE and code[rtarget+3] == self.opc.POP_BLOCK and - code[prev_op[prev_op[rtarget]]] != self.opc.JUMP_ABSOLUTE)): - rtarget = prev_op[rtarget] + code[prev_op[pre_rtarget]] != self.opc.JUMP_ABSOLUTE)): + rtarget = pre_rtarget # Does the "jump if" jump beyond a jump op? # That is, we have something like: @@ -793,12 +815,11 @@ def detect_structure(self, offset, targets): # There are other contexts we may need to consider # like whether the target is "END_FINALLY" # or if the condition jump is to a forward location - if self.is_jump_forward(prev_op[rtarget]): - rrtarget = prev_op[rtarget] - if_end = self.get_target(rrtarget) + if self.is_jump_forward(pre_rtarget): + if_end = self.get_target(pre_rtarget) # If the jump target is back, we are looping - if (if_end < rrtarget and + if (if_end < pre_rtarget and (code[prev_op[if_end]] == self.opc.SETUP_LOOP)): if (if_end > start): return @@ -807,19 +828,25 @@ def detect_structure(self, offset, targets): self.structs.append({'type': 'if-then', 'start': start, - 'end': prev_op[rtarget]}) - self.not_continue.add(prev_op[rtarget]) + 'end': pre_rtarget}) + self.not_continue.add(pre_rtarget) if rtarget < end and ( code[rtarget] not in (self.opc.END_FINALLY, self.opc.JUMP_ABSOLUTE) and - code[prev_op[rrtarget]] not in (self.opc.POP_EXCEPT, + code[prev_op[pre_rtarget]] not in (self.opc.POP_EXCEPT, self.opc.END_FINALLY)): self.structs.append({'type': 'else', 'start': rtarget, 'end': end}) self.else_start[rtarget] = end - elif code[prev_op[rtarget]] == self.opc.RETURN_VALUE: + elif self.is_jump_back(pre_rtarget): + if_end = rtarget + self.structs.append({'type': 'if-then', + 'start': start, + 'end': pre_rtarget}) + self.not_continue.add(pre_rtarget) + elif code[pre_rtarget] == self.opc.RETURN_VALUE: self.structs.append({'type': 'if-then', 'start': start, 'end': rtarget}) @@ -849,7 +876,7 @@ def detect_structure(self, offset, targets): return pass pass - self.return_end_ifs.add(prev_op[rtarget]) + self.return_end_ifs.add(pre_rtarget) elif op in self.jump_if_pop: target = self.get_target(offset) @@ -888,6 +915,16 @@ def detect_structure(self, offset, targets): pass return + def is_jump_back(self, offset): + """ + Return True if the code at offset is some sort of jump back. + That is, it is ether "JUMP_FORWARD" or an absolute jump that + goes forward. + """ + if self.code[offset] != self.opc.JUMP_ABSOLUTE: + return False + return offset > self.get_target(offset) + def next_except_jump(self, start): """ Return the next jump that was generated by an except SomeException: diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index b094a69a4..09fac8d2d 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -299,7 +299,7 @@ 'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmtl': ( '%|if %c:\n%+%c%-', 0, 1 ), - 'testtrue': ( 'not %p', (0, 22) ), + 'testtrue': ( 'not %p', (0, 22) ), 'ifelsestmt': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ), 'ifelsestmtc': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ), @@ -587,7 +587,9 @@ def customize_for_version(self, is_pypy, version): }) else: TABLE_DIRECT.update({ - 'except_cond3': ( '%|except %c, %c:\n', 1, 6 ), + 'except_cond3': ( '%|except %c, %c:\n', 1, 6 ), + 'testtrue_then': ( 'not %p', (0, 22) ), + }) if 2.4 <= version <= 2.6: TABLE_DIRECT.update({ diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 8c2aaa959..8efc70d7a 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -405,6 +405,7 @@ def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): try: code_obj2 = load_file(src_filename) except SyntaxError, e: + return str(e).replace(src_filename, pyc_filename) return str(e) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) return None From f8544dfbbec0becff6560e472e36f4974941e25f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 31 Dec 2016 10:56:43 -0500 Subject: [PATCH 013/489] 2.7->2.4 conversion --- uncompyle6/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 996fc660b..1215aa5e0 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -131,7 +131,10 @@ def _get_outstream(outfile): junk, outfile = tempfile.mkstemp(suffix=".py", prefix=prefix) # Unbuffer output if possible - buffering = -1 if sys.stdout.isatty() else 0 + if sys.stdout.isatty(): + buffering = -1 + else: + buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) tee = subprocess.Popen(["tee", outfile], stdin=subprocess.PIPE) os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) From 98914941425028a18f3721d525d2b620d56adc3e Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 31 Dec 2016 18:16:23 -0500 Subject: [PATCH 014/489] We are version 2.9.9 --- uncompyle6/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 2165392f2..3723c1be0 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.9.8' +VERSION='2.9.9' From 6ed129bd7a8fac4804d13d05e5a992cd662a538c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 2 Jan 2017 07:15:46 -0500 Subject: [PATCH 015/489] 2.4 verify hacks --- uncompyle6/verify.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 6c0da03b7..739d8e31f 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -351,8 +351,10 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, elif member == 'co_flags': flags1 = code_obj1.co_flags flags2 = code_obj2.co_flags - if is_pypy: + if is_pypy or version == 2.4: # For PYPY for now we don't care about PYPY_SOURCE_IS_UTF8: + # Python 2.4 also sets this flag and I am not sure + # where or why flags2 &= ~0x0100 # PYPY_SOURCE_IS_UTF8 # We also don't care about COROUTINE or GENERATOR for now flags1 &= ~0x000000a0 @@ -361,6 +363,8 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, raise CmpErrorMember(name, 'co_flags', pretty_flags(flags1), pretty_flags(flags2)) + + else: # all other members must be equal if getattr(code_obj1, member) != getattr(code_obj2, member): @@ -404,8 +408,10 @@ def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): return msg try: code_obj2 = load_file(src_filename) - except SyntaxError as e: + except SyntaxError, e: # src_filename can be the first of a group sometimes + if version == 2.4: + print(pyc_filename) return str(e).replace(src_filename, pyc_filename) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) return None From fab4ebb768777b662796d1d4e0270ac159ea4960 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 11 Jan 2017 19:34:28 -0500 Subject: [PATCH 016/489] Merge changes ... * str() in Python 2.4 doesn't detect unicode. * index() doesn't work on tuples * ifelse change --- uncompyle6/parsers/parse3.py | 3 ++- uncompyle6/scanner.py | 5 ++++- uncompyle6/semantics/make_function.py | 2 +- uncompyle6/version.py | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 5ffe02775..841860c57 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -747,7 +747,8 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): elif lhs == 'annotate_tuple': return not isinstance(tokens[first].attr, tuple) elif lhs == 'kwarg': - return not isinstance(tokens[first].attr, str) + return not (isinstance(tokens[first].attr, unicode) or + isinstance(tokens[first].attr, str)) elif lhs == 'while1elsestmt': # if SETUP_LOOP target spans the else part, then this is # not while1else. Also do for whileTrue? diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 40845bf21..2797b3dce 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -224,7 +224,10 @@ def op_size(self, op): for given opcode . """ if op < self.opc.HAVE_ARGUMENT: - return 2 if self.version >= 3.6 else 1 + if self.version >= 3.6: + return 2 + else: + return 1 else: if self.version >= 3.6: return 2 diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 76d956dd1..a0fa0847f 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -149,7 +149,7 @@ def build_param(ast, name, default): self.write(suffix, param) suffix = ', ' if param in annotate_tuple[0].attr: - p = annotate_tuple[0].attr.index(param) + p = [x for x in annotate_tuple[0].attr].index(param) self.write(': ') self.preorder(node[p]) if (line_number != self.line_number): diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 3723c1be0..37bd89e24 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.9.9' +VERSION='2.10.0' From c13e23cdae320ce0ea69aa358f20d1d1ee39f82a Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 11 Jan 2017 21:39:39 -0500 Subject: [PATCH 017/489] Get ready for release 2.9.9 --- NEWS | 14 +++++++++++--- uncompyle6/version.py | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index fa9af9812..10b8ece57 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,14 @@ -uncompyle6 2.9.9 2016-12-16 +uncompyle6 2.9.9 2016-01-11 + +- Remaining Python 3.5 ops handled + (this also means more Python 3.6 ops are handled) +- Python 3.5 and 3.6 async and await handled +- Python 3.0 decompilation improved +- Python 3 annotations fixed +- Better control-flow detection +- Code cleanups and misc bug fixes + +uncompyle6 2.9.8 2016-12-16 - Better control-flow detection - pseudo instruction THEN in 2.x @@ -11,8 +21,6 @@ uncompyle6 2.9.9 2016-12-16 - verifycall fixes for Python <= 2.4 - more Python lint -uncompyle6 2.9.8 2016-12-16 - uncompyle6 2.9.7 2016-12-16 - Start to handle 3.5/3.6 build_map_unpack_with_call diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 37bd89e24..3723c1be0 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.10.0' +VERSION='2.9.9' From 770e988ff8ea036db0b52ec8af902669f1a40b69 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 29 Jan 2017 22:53:12 -0500 Subject: [PATCH 018/489] Changes based on coverage information --- test/Makefile | 5 +++++ test/bytecode_2.5/01_ops.pyc | Bin 0 -> 252 bytes test/simple_source/bug22/01_ops.py | 3 +++ uncompyle6/parsers/parse25.py | 4 +++- uncompyle6/semantics/consts.py | 2 -- uncompyle6/semantics/pysource.py | 3 +++ 6 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 test/bytecode_2.5/01_ops.pyc diff --git a/test/Makefile b/test/Makefile index d31cb7c42..1e3858981 100644 --- a/test/Makefile +++ b/test/Makefile @@ -98,6 +98,11 @@ check-bytecode-2.4: check-bytecode-2.5: $(PYTHON) test_pythonlib.py --bytecode-2.5 +#: Get grammar coverage for Python 2.5 +grammar-coverage-2.5: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 + #: Get grammar coverage for Python 2.6 grammar-coverage-2.6: SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 diff --git a/test/bytecode_2.5/01_ops.pyc b/test/bytecode_2.5/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30badcbb03e374eb407e72725053ee199814fa72 GIT binary patch literal 252 zcmdn|iI+=fOJ77X0~9a;X$K%KP5=@q3=CXR3=FA279)cdl*Png4Ht8UvX~is;4E*r ztPGsx3upO3SiFoWEDXUKtUyaLxj+OXh+qK`AQ$*)fcPaKqEZ7$Fd&FxSs=GKGq)fo zHNH5%v?w`MKdCg`$VlJ7Fh0MaSg)Y6m;>= 2 # INPLACE_RSHIFT y <<= 2 # INPLACE_LSHIFT y //= 1 # INPLACE_TRUE_DIVIDE +y &= 1 # INPLACE_AND +y ^= 1 # INPLACE_XOR + `y` # UNARY_CONVERT - No in Python 3.x diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 195d15dfd..4d17dc9a9 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Rocky Bernstein +# Copyright (c) 2016-2017 Rocky Bernstein """ spark grammar differences over Python2.6 for Python 2.5. """ @@ -20,6 +20,7 @@ def p_misc25(self, args): return_if_stmt ::= ret_expr RETURN_END_IF JUMP_BACK # Python 2.6 uses ROT_TWO instead of the STORE_xxx + # withas is allowed as a "from future" in 2.5 setupwithas ::= DUP_TOP LOAD_ATTR store LOAD_ATTR CALL_FUNCTION_0 setup_finally @@ -27,6 +28,7 @@ def p_misc25(self, args): store ::= STORE_NAME # Python 2.6 omits ths LOAD_FAST DELETE_FAST below + # withas is allowed as a "from future" in 2.5 withasstmt ::= expr setupwithas designator suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM with_cleanup diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 0790fb1b1..46b210379 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -251,8 +251,6 @@ 'except_cond1': ( '%|except %c:\n', 1 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), 'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ), - 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), - 'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3), 'passstmt': ( '%|pass\n', ), 'STORE_FAST': ( '%{pattr}', ), 'kv': ( '%c: %c', 3, 1 ), diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 26d571011..7b74110f7 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -239,6 +239,9 @@ def customize_for_version(self, is_pypy, version): TABLE_DIRECT.update({ 'importmultiple': ( '%|import %c%c\n', 2, 3 ), 'import_cont' : ( ', %c', 2 ), + # With/as is allowed as "from future" thing + 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), + 'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3), }) ######################################## From ea9e3ab3f548ab8a014234834ff5154f329ac279 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 10 Feb 2017 01:00:26 -0500 Subject: [PATCH 019/489] Group coverage Makefile targets --- test/Makefile | 35 ++++++++++++++++++++--------------- test/bytecode_2.4/01_ops.pyc | Bin 0 -> 249 bytes 2 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 test/bytecode_2.4/01_ops.pyc diff --git a/test/Makefile b/test/Makefile index 1e3858981..9c0fc2299 100644 --- a/test/Makefile +++ b/test/Makefile @@ -98,21 +98,6 @@ check-bytecode-2.4: check-bytecode-2.5: $(PYTHON) test_pythonlib.py --bytecode-2.5 -#: Get grammar coverage for Python 2.5 -grammar-coverage-2.5: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 - -#: Get grammar coverage for Python 2.6 -grammar-coverage-2.6: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 - -#: Get grammar coverage for Python 2.7 -grammar-coverage-2.7: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 - #: Check deparsing Python 2.6 check-bytecode-2.6: $(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify @@ -149,6 +134,26 @@ check-bytecode-3.5: check-bytecode-3.6: $(PYTHON) test_pythonlib.py --bytecode-3.6 +#: Get grammar coverage for Python 2.4 +grammar-coverage-2.4: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 + +#: Get grammar coverage for Python 2.5 +grammar-coverage-2.5: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 + +#: Get grammar coverage for Python 2.6 +grammar-coverage-2.6: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 + +#: Get grammar coverage for Python 2.7 +grammar-coverage-2.7: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 + #: short tests for bytecodes only for this version of Python check-native-short: $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --verify $(COMPILE) diff --git a/test/bytecode_2.4/01_ops.pyc b/test/bytecode_2.4/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b579a65c5c976265fd97b7423c13e2743cea8dac GIT binary patch literal 249 zcmd1(#LK0>t1lv%0ScIav;z Date: Wed, 22 Feb 2017 05:30:07 -0500 Subject: [PATCH 020/489] Python 2.5 was missing try else stmt --- test/Makefile | 15 --------------- test/bytecode_2.5/02_try_else.pyc | Bin 559 -> 908 bytes test/simple_source/bug25/02_try_else.py | 17 ++++++++++++++++- uncompyle6/parsers/parse25.py | 17 ++++------------- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/test/Makefile b/test/Makefile index 38619ff66..8c6de51e4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -98,21 +98,6 @@ check-bytecode-2.4: check-bytecode-2.5: $(PYTHON) test_pythonlib.py --bytecode-2.5 -#: Get grammar coverage for Python 2.5 -grammar-coverage-2.5: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 - -#: Get grammar coverage for Python 2.6 -grammar-coverage-2.6: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 - -#: Get grammar coverage for Python 2.7 -grammar-coverage-2.7: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 - #: Check deparsing Python 3.0 check-bytecode-3.0: $(PYTHON) test_pythonlib.py --bytecode-3.0 diff --git a/test/bytecode_2.5/02_try_else.pyc b/test/bytecode_2.5/02_try_else.pyc index 8b7ac30ef0fbc871fd58bd785da892d4db985ae3..139bec0e62e6551c297ebb8f636ad6fcae5a4991 100644 GIT binary patch delta 459 zcmXv~u}T9$5S_WbBxa99MTvrbz%>?H1nd+M1?7+!G1vsmU34X8!|p~AE~F7bunGAH zE3xn=`~iDQYsm*VbBPDQ zu?MH27;QXbG@5)3QQ!)eaS<1=gaNiZD)I?A!XCjs5j{w*A9!%yJpeyNPyja)^co-z z1YjyaAuxN;_Bhzx2F!vY3(n7i^f;UAfQ=MD`7qQHFc#S@lJZ$it<1^&J1MuFr(Pn( zt*Hr(sU)jUra7XJ4Ob*Otk+NWjnT&OC@mc)PLQ~@SB`^cwd1K^O- YCrRfC5~Gk8Tnm_%$KQCA=l^2x2a&)|wg3PC delta 152 zcmeBSU(ceu`4cbKUFEQdWCkc;1kw&bT+9n3QWzLo7#N~}3`T}v4W@}^op!~RK=Gi| zlG36)g+zs%%;FM-{4|C9f|AVqJcYc(+|*))wEQB4l8jV^^vtrH8Tl9m83h=58Mzt#G(c7caZk2p_GSUH7y#K>BfkIu diff --git a/test/simple_source/bug25/02_try_else.py b/test/simple_source/bug25/02_try_else.py index 5c708c31d..f2325ff85 100644 --- a/test/simple_source/bug25/02_try_else.py +++ b/test/simple_source/bug25/02_try_else.py @@ -1,7 +1,6 @@ # Python 2.5 bug # Was turning into tryelse when there in fact is no else. def options(self, section): - """Return a list of option names for the given section name.""" try: opts = self._sections[section].copy() except KeyError: @@ -10,3 +9,19 @@ def options(self, section): if '__name__' in opts: del opts['__name__'] return opts.keys() + +# From python2.5/distutils/command/register.py +def post_to_server(self, urllib2): + try: + result = 5 + except urllib2.HTTPError, e: + result = e.code, e.msg + except urllib2.URLError, e: + result = 500 + else: + if self.show_response: + result = 10 + result = 200 + if self.show_response: + result = 8 + return result diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 4d17dc9a9..8111ff938 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -27,7 +27,10 @@ def p_misc25(self, args): store ::= STORE_FAST store ::= STORE_NAME - # Python 2.6 omits ths LOAD_FAST DELETE_FAST below + tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK + try_middle else_suite COME_FROM + + # Python 2.6 omits the LOAD_FAST DELETE_FAST below # withas is allowed as a "from future" in 2.5 withasstmt ::= expr setupwithas designator suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM @@ -48,18 +51,6 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): tokens, first, last) if invalid: return invalid - lhs = rule[0] - if lhs in ('tryelsestmt', ): - # The end of the else part of try/else come_from has to come - # from an END_FINALLY statement - if tokens[last-1].type.startswith('COME_FROM'): - end_finally_offset = int(tokens[last-1].pattr) - current = first - while current < last: - offset = tokens[current].offset - if offset == end_finally_offset: - return tokens[current].type != 'END_FINALLY' - current += 1 return False From e4a7641927b52bc70f783a36256c684093b403b3 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Feb 2017 05:13:19 -0500 Subject: [PATCH 021/489] Python <= 2.6 grammar fixes --- uncompyle6/parser.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 250827810..6131e63b8 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -28,13 +28,13 @@ class PythonParser(GenericASTBuilder): def __init__(self, AST, start, debug): super(PythonParser, self).__init__(AST, start, debug) - self.collect = frozenset( - ['stmts', 'except_stmts', '_stmts', - 'exprlist', 'kvlist', 'kwargs', 'come_froms', - # Python < 3 - 'print_items', - # PyPy: - 'kvlist_n']) + self.collect = [ + 'stmts', 'except_stmts', '_stmts', + 'exprlist', 'kvlist', 'kwargs', 'come_froms', + # Python < 3 + 'print_items', + # PyPy: + 'kvlist_n'] def add_unique_rule(self, rule, opname, count, customize): """Add rule to grammar, but only if it hasn't been added previously From 7e8f7ba67431725fceec08344934c929a517efc5 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Apr 2017 05:42:44 -0400 Subject: [PATCH 022/489] namedtuple25 -> namedtuple24 --- uncompyle6/scanners/scanner2.py | 2 +- uncompyle6/scanners/scanner3.py | 2 +- uncompyle6/semantics/fragments.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 08fe7f577..26b4794cd 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index c8f62edb6..2c2a4827e 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index e6c62d1b9..443d64ad8 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -82,7 +82,7 @@ from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple From e56ab2dcd54f59c56f011572f0c0c6b26734771b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 6 May 2017 07:17:04 -0400 Subject: [PATCH 023/489] Sync with master --- test/Makefile | 12 ++++++++---- uncompyle6/scanners/scanner2.py | 4 ++-- uncompyle6/scanners/scanner3.py | 2 +- uncompyle6/semantics/fragments.py | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/test/Makefile b/test/Makefile index 8c6de51e4..58ad8e6cf 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,7 +3,7 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea GIT2CL ?= git2cl PYTHON ?= python -PYTHON_VERSION = $(shell $(PYTHON) -V | cut -d ' ' -f 2 | cut -d'.' -f1,2) +PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2) NATIVE_CHECK = check-$(PYTHON_VERSION) # Set COMPILE='--compile' to force compilation before check @@ -20,7 +20,7 @@ check: $(MAKE) check-$$PYTHON_VERSION #: Run working tests from Python 2.6 or 2.7 -check-2.4 check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-2.7-ok +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 @@ -68,7 +68,7 @@ check-bytecode-2: 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-pypy3.2 + --bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-pypy3.2 #: Check deparsing bytecode that works running Python 2 and Python 3 check-bytecode: check-bytecode-3 @@ -148,7 +148,11 @@ grammar-coverage-2.7: #: short tests for bytecodes only for this version of Python check-native-short: - $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --verify $(COMPILE) + $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(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: diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 26b4794cd..9df36c438 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel """ @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple24 import namedtuple + from xdis.namedtuple25 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 699f441d2..5e5059e6b 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple24 import namedtuple + from xdis.namedtuple25 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index f6e38c1f7..c1d8230b3 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -84,7 +84,7 @@ from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG if PYTHON_VERSION < 2.6: - from xdis.namedtuple24 import namedtuple + from xdis.namedtuple25 import namedtuple else: from collections import namedtuple From 5566b9ba6cbf47ad4796f03812998b07efa03f16 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 6 May 2017 07:48:24 -0400 Subject: [PATCH 024/489] Get ready for release 2.9.11 --- ChangeLog | 808 +++++++++++++++++++++++++++++++++--------- NEWS | 6 + uncompyle6/version.py | 2 +- 3 files changed, 655 insertions(+), 161 deletions(-) diff --git a/ChangeLog b/ChangeLog index 83ee07224..32d615afa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,415 @@ +2017-05-06 rocky + + * uncompyle6/version.py: Get ready for release 2.9.11 + +2017-05-06 rocky + + * test/Makefile, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/fragments.py: + Sync with master + +2017-05-06 rocky + + * : commit 4a4782290490187ac2fcaaecd3ca808f933722b2 Author: rocky + Date: Sat May 6 05:25:56 2017 -0400 + +2017-05-05 rocky + + * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ + +2017-05-05 rocky + + * .travis.yml: Try CI testing on Python 3.6 + +2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/semantics/pysource.py: Bang more on BUIlD_MAP_UNPACK there are still bugs. Note: {**{'x': 1}, **{'y': 2}} and {{'x': 1}, **{'y': 2}} generate the same Python 3.5+ bytecode. + +2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + BUILD_MAP_UNPACK'ing of dictionaries in 3.5 + +2017-05-01 rocky + + * uncompyle6/semantics/pysource.py: Remove extra unpack *. Issue #98 + +2017-04-29 R. Bernstein + + * HISTORY.md: Update HISTORY.md + +2017-04-29 rocky + + * test/simple_source/bug35/01_map_unpack.py, + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Handle BUILD_MAP_UNPACK in a build_list + +2017-04-27 rocky + + * uncompyle6/semantics/pysource.py: A hacky way to get + CALL_FUNCTION_EX_KW to work. + +2017-04-26 rocky + + * uncompyle6/semantics/pysource.py: remove debug code + +2017-04-25 rocky + + * test/simple_source/bug36/01_call_function.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner36.py, + uncompyle6/semantics/pysource.py: Python 3.6 CALL_FUNCTION_EX first + attempt + +2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduse scope + of LOAD_ASSERT as expr to 3.4+ + +2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/verify.py: LOAD_ASSERT can also + be an expr This may have the undesirable property that assert statements might + get tagged with equivalant low-level Python code that uses "raise + AssertionError", but so be it. Fixes #103 + +2017-04-22 R. Bernstein + + * HISTORY.md: Update HISTORY.md + +2017-04-22 R. Bernstein + + * HISTORY.md: Update HISTORY.md + +2017-04-22 rocky + + * HISTORY.md: History keeps gettting amended + +2017-04-22 rocky + + * README.rst: Document Python 3.x status + +2017-04-22 rocky + + * test/simple_source/bug35/03_async_await.py, + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: Add + await expr Fixes #111 + +2017-04-22 rocky + + * : Update test + +2017-04-22 rocky + + * test/simple_source/bug33/02_pos_args.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + 3.3+ bug in handling single kwarg after * Towards fixing issue #110 + +2017-04-20 rocky + + * test/simple_source/bug35/02_async_for.py, + uncompyle6/parsers/parse35.py: Add async for with pass statement Fixes #109 + +2017-04-19 rocky + + * test/simple_source/bug35/03_while-if-break.py, + uncompyle6/parsers/parse3.py: 3.5 ifelsestmtl grammar bug. Fixes #108 + +2017-04-18 rocky + + * test/simple_source/bug35/03_async_await.py, + uncompyle6/parsers/parse35.py: Expand await stmt handling Fixes #107 + +2017-04-18 rocky + + * test/simple_source/bug33/01_delete_deref.py, + uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: Add + DELETE_DEREF grammar rule Fixes Issue #106 + +2017-04-17 rocky + + * test/simple_source/bug36/01_extended_arg.py, + test/simple_source/bug36/01_if_file.py: Rename test case to + something more appropriate + +2017-04-17 rocky + + * test/simple_source/bug36/01_if_file.py: Fix botched test case Thanks to Zm908 for pointing this out + +2017-04-16 rocky + + * uncompyle6/parsers/parse3.py: Comment on what's up with last + change + +2017-04-16 rocky + + * test/simple_source/bug22/03_if1.py, + test/simple_source/bug31/02_ifelse_comprehension.py, + uncompyle6/parsers/parse3.py: Python 3.x ifelse in comprehension Fixes Issue #91 + +2017-04-16 rocky + + * : Add 2.7 complex test + +2017-04-15 rocky + + * test/simple_source/bug35/01_map_unpack.py, + uncompyle6/semantics/pysource.py: Correct bug in 3.5+ build_list + with UNPACK + +2017-04-15 R. Bernstein + + * HOW-TO-REPORT-A-BUG.md: Update HOW-TO-REPORT-A-BUG.md + +2017-04-15 R. Bernstein + + * HOW-TO-REPORT-A-BUG.md: Update HOW-TO-REPORT-A-BUG.md + +2017-04-15 rocky + + * test/simple_source/bug36/01_if_file.py, + uncompyle6/parsers/parse36.py: 3.6 generates Wonky EXTENDED_ARG in + expression Fixes Issue #102 + +2017-04-15 rocky + + * HOW-TO-REPORT-A-BUG.md, MANIFEST.in: Add how to report a bug Add test case for ... if 1 else ... + +2017-04-14 rocky + + * test/simple_source/bug35/01_map_unpack.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/semantics/pysource.py: Python 3.5+ BUILD_UNMAP_PACK rules Towards addressing Issue #98 + +2017-04-14 rocky + + * uncompyle6/scanners/scanner3.py: Reduce adding RETURN_END_IF in + 3.5+ The whole control flow determination has to be redone in a less + haphazard way using real flow-control analysis. Hopefully that's on + the way. In the meantime we have this hack. + +2017-04-14 rocky + + * : commit 7e8f7ba67431725fceec08344934c929a517efc5 Author: rocky + Date: Fri Apr 14 05:42:44 2017 -0400 + +2017-04-14 rocky + + * test/simple_source/bug27+/03_if_1_else.py, + test/simple_source/bug27+/03_if_true_else.py: Better names for a + test + +2017-04-13 rocky + + * test/simple_source/bug27+/03_if_true_else.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/semantics/consts.py: Add if1else. Fixes #101 + +2017-04-13 rocky + + * uncompyle6/parsers/parse3.py: In 3.x come_from should include + COME_FROM_EXCEPT + +2017-04-13 rocky + + * uncompyle6/parsers/parse35.py: Towards fixing issue #92 + +2017-04-13 rocky + + * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous + commit. + +2017-04-12 rocky + + * uncompyle6/parsers/parse3.py, + uncompyle6/semantics/make_function.py: annotate args type need to be + expr's not constants + +2017-04-12 rocky + + * uncompyle6/parsers/parse24.py: Handle Python 2.4 "if 1...." + +2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, + uncompyle6/semantics/fragments.py, + uncompyle6/semantics/make_function.py: Bang on 3.x annotations + +2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Towards fixing annotated decorator functions... and annotate functions + +2017-04-10 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, + uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: + grammar typo check_ast: add while1else to list of looping constructs + pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is + different? + +2017-04-10 rocky + + * test/simple_source/stmts/02_while1else.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse35.py: Add more while1else grammar rules Towards addressing issue #93 + +2017-04-10 rocky + + * : commit b9703cf6b41138b717c282fc791c08d807692b07 Author: rocky + Date: Sun Apr 9 06:58:41 2017 -0400 + +2017-04-09 rocky + + * test/simple_source/def/10_kw+pos_args-bug.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Another Python 3.5 FUNCTION_VAR bug Fixes #94 + +2017-04-09 rocky + + * : commit 4199bc7f617e387fb03fc06939cd17366dc15c5e Author: rocky + Date: Sun Apr 9 05:30:45 2017 -0400 + +2017-04-03 rocky + + * : commit 6773a66b99d07e48290a77dbbbe3c71cc39c31ba Author: rocky + Date: Mon Apr 3 06:53:12 2017 -0400 + +2017-03-27 rocky + + * : commit a91cd716670be09d3cef34e1bb36a67f96f91712 Author: rocky + Date: Mon Mar 27 07:08:59 2017 -0400 + +2017-03-19 rocky + + * __pkginfo__.py: Use more-recent xdis + +2017-03-15 rocky + + * HISTORY.md, test/simple_source/bug33/01_if_try_except.py: grammar + typo and add another test + +2017-03-12 rocky + + * uncompyle6/scanners/scanner3.py: Python 3.0 doesn't have + POP_JUMP_IF... + +2017-03-12 rocky + + * README.rst: Note problem in handling pathologically long lists + +2017-03-07 rocky + + * uncompyle6/scanners/scanner3.py: Small cleanup - remove + POP_JUMP_TF + +2017-03-05 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse33.py, uncompyle6/scanners/scanner3.py: More + accurate ranges of try blocks in 3.x + +2017-03-05 rocky + + * test/simple_source/bug33/01_try_except.py: More accurate ranges of + try blocks in 3.x + +2017-03-04 R. Bernstein + + * : Merge pull request #84 from + moagstar/property_based_test_function_call Property based test function call + +2017-03-04 rocky + + * README.rst: README updates for 3.5 and 1.5 + +2017-03-04 rocky + + * test/simple_source/bug32/01_named_and_kwargs.py, + uncompyle6/parsers/parse3.py: Bug found by hypothesis in creating + function calls + +2017-03-04 Daniel Bradburn + + * pytest/test_function_call.py: marked all function call tests as + failing until they pass across all python versions + +2017-03-04 Daniel Bradburn + + * pytest/test_function_call.py: added minimal examples for various + function call opcodes + +2017-03-04 Daniel Bradburn + + * pytest/test_function_call.py: added property based test for + verifying uncompylation of function calls. A number of minimal + examples for the various function call opcodes have been generated + with the majority marked as expected failure until python 3.6 opcode + support is complete. I'm hoping this will make it easier to figure + out what needs to be done to support the new opcodes and changed + semntics for function calls + +2017-03-03 Daniel Bradburn + + * pytest/test_function_call.py: reduced errors when generating + function call instances + +2017-03-03 Daniel Bradburn + + * pytest/test_function_call.py: added test file for function calls + +2017-03-03 Daniel Bradburn + + * .gitignore: added .idea to gitignore + +2017-03-03 Daniel Bradburn + + * .gitignore: added .venv to gitignore + +2017-03-01 rocky + + * : commit 160ec0d9cc5fe347f6e8bdb69515a28c76cfb368 Author: rocky + Date: Wed Mar 1 05:50:31 2017 -0500 + +2017-02-28 rocky + + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + Python 2.6 a == b or c == d == 3 grammar bug + +2017-02-28 rocky + + * : 2.6 a == b or x == y == z bug + +2017-02-28 rocky + + * test/simple_source/bug26/03_double_equals.py, + uncompyle6/semantics/consts.py: Predidence of cmp_list: x == y == z The x, y, z should not have parenthesis around pairs of them (x == + y) or (y == z) + +2017-02-28 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse27.py: Python 2.7 + check jump targets of "and" + +2017-02-25 rocky + + * : commit 1e3ea60055027dfd3f098661ac4f5979c5c48f7e Author: rocky + Date: Sat Feb 25 20:18:03 2017 -0500 + 2017-02-25 rocky - * uncompyle6/version.py: Get ready for release 2.9.10 + * uncompyle6/parser.py: Python <= 2.6 grammar fixes 2017-02-25 rocky - * uncompyle6/parser.py, uncompyle6/parsers/parse26.py: Python 2.6 - parsing bugs .. and some parser list nonterminal cleanup + * : commit 2fbbc728b10f0d3a754165708584bd80d33bc7f9 Author: rocky + Date: Sat Feb 25 04:45:10 2017 -0500 2017-02-24 rocky @@ -19,9 +423,15 @@ uncompyle6/parsers/parse25.py: Python 2.5 wasn't handling tryelse properly -2017-02-20 rocky +2017-02-22 rocky + + * test/Makefile, test/simple_source/bug25/02_try_else.py, + uncompyle6/parsers/parse25.py: Python 2.5 was missing try else stmt + +2017-02-22 rocky - * : New test doesn't --verify correctly. Sigh. + * : commit b043f6bafc9b9ae26e64dc0f1441d7abae894c37 Author: rocky + Date: Mon Feb 20 09:22:01 2017 -0500 2017-02-20 rocky @@ -60,6 +470,10 @@ * test/simple_source/bug22/01_ops.py, test/test_pythonlib.py: Beef up grammar coverage +2017-02-10 rocky + + * test/Makefile: Group coverage Makefile targets + 2017-01-29 rocky * test/Makefile, test/simple_source/bug22/01_ops.py, @@ -67,9 +481,24 @@ uncompyle6/semantics/pysource.py: Changes based on grammar coverage info -2017-01-29 R. Bernstein +2017-01-29 rocky + + * test/Makefile, test/simple_source/bug22/01_ops.py, + uncompyle6/parsers/parse25.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/pysource.py: Changes based on coverage + information + +2017-01-29 rocky + + * : commit 9348411056cbe809e07c4ef341effa17bca90e2f Merge: 3dc766d + e71dd01 Author: R. Bernstein Date: + Sun Jan 29 21:54:45 2017 -0500 + +2017-01-29 rocky - * : Merge pull request #83 from rocky/coverage Coverage + * test/Makefile, test/simple_source/bug22/01_ops.py, + test/test_pyenvlib.py, test/test_pythonlib.py, + uncompyle6/semantics/consts.py: Simplfy getting coverage consts.py: notes on versions use which ops 2017-01-29 rocky @@ -173,6 +602,10 @@ * uncompyle6/__init__.py: sys.recursionlimit is optional, not essential +2017-01-11 rocky + + * NEWS, uncompyle6/version.py: Get ready for release 2.9.9 + 2017-01-11 rocky * : commit b131c20e99514d3a969a51e841d3a823017f1beb Author: rocky @@ -182,9 +615,22 @@ * ChangeLog, NEWS: Get ready for release 2.10.9 +2017-01-11 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, + uncompyle6/semantics/make_function.py, uncompyle6/version.py: Merge + changes ... * str() in Python 2.4 doesn't detect unicode. * index() doesn't work on tuples * ifelse change + +2017-01-11 rocky + + * : commit 7ece296f7638e71fad1117b940f7ffddbe095b1f Merge: 78a5b62 + 5035d54 Author: R. Bernstein Date: + Wed Jan 11 07:10:23 2017 -0500 + 2017-01-11 R. Bernstein - * : Merge pull request #79 from rocky/revert-78-patch-1 Revert "fix bug : not generate all files when use "-ro"" + * uncompyle6/main.py: Revert "fix bug : not generate all files when + use "-ro"" 2017-01-11 R. Bernstein @@ -283,6 +729,16 @@ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: Python 3.5 continue detection bug +2017-01-02 rocky + + * uncompyle6/verify.py: 2.4 verify hacks + +2017-01-02 rocky + + * : commit a7d93e88b4e0dfd6876a7a31bd201a0e40f24bea Merge: 9891494 + 136f42a Author: rocky Date: Mon Jan 2 05:39:13 + 2017 -0500 + 2017-01-01 rocky * uncompyle6/scanners/scanner3.py: add come_from for setup_finally @@ -297,6 +753,14 @@ * README.rst: Note how to verify correctness ... with --verify, --weak-verify and cross checking with pycdc +2016-12-31 rocky + + * uncompyle6/version.py: We are version 2.9.9 + +2016-12-31 rocky + + * uncompyle6/main.py: 2.7->2.4 conversion + 2016-12-31 rocky * ChangeLog, NEWS, uncompyle6/version.py: Get ready for release @@ -306,6 +770,13 @@ * uncompyle6/parsers/parse26.py: 2.x list_if may have a THEN in it +2016-12-31 rocky + + * test/Makefile, uncompyle6/main.py, uncompyle6/parsers/parse26.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py, + uncompyle6/verify.py: Merge master branche Handle 2.2 list_if + 2016-12-31 rocky * uncompyle6/scanners/scanner3.py: Towards fixing a Python 3.3 @@ -317,12 +788,12 @@ 2016-12-29 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: dectect_structure() -> detect_control_flow() 2016-12-29 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie 2016-12-29 rocky @@ -334,10 +805,9 @@ * : Merge pull request #73 from rocky/then-crap Add THEN token to improve Python 2.2-2.6 control flow detection -2016-12-28 rocky +2016-12-29 R. Bernstein - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/tok.py: Misc - bugs + * : Merge pull request #72 from rocky/master THEN psuedo-ops for Python 2.x 2016-12-28 rocky @@ -359,13 +829,12 @@ 2016-12-27 rocky * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: WIP : Add THEN to disambigute from "and" 2016-12-27 rocky - * uncompyle6/scanners/scanner2.py: Make 2.6 and 2.7 ingest more - alike + * : Merge commit '9b1dd0f' into python-2.4 2016-12-26 rocky @@ -385,6 +854,11 @@ * uncompyle6/parsers/parse25.py: fix bug in using python2 AST rules in python 2.5 +2016-12-26 rocky + + * uncompyle6/parsers/parse25.py: Bug in using python2 ast checking + in python 2.5 + 2016-12-26 rocky * : commit f1a947f106b231fb1480ba301b15e3ceaf78c94f Author: rocky @@ -397,15 +871,19 @@ uncompyle6/verify.py: Scanner call fixes. NAME_MODULE removal for <=2.4 -2016-12-24 rocky +2016-12-25 rocky + + * uncompyle6/main.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner21.py, uncompyle6/scanners/scanner22.py, + uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py: Removing + NAME_MODULE, lint and bug fixes scanner*.py: show_asm param is optional verify.py: call correct + scanners main.py, verify.py: Use older Python print statements + +2016-12-25 rocky - * uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, - uncompyle6/scanners/scanner22.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: - Lint + * : commit e3f4beeb74e33d5b404094765cc63040f62a0b41 Author: rocky + Date: Sat Dec 24 07:45:02 2016 -0500 2016-12-24 rocky @@ -421,27 +899,39 @@ * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) 2016-12-18 rocky - * pytest/.gitignore, test/simple_source/bug25/02_try_else.py, - uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: Python - 2.5 mistaken try/else + * : commit c7c0a989829a9a625333665516387c1177c611c2 Author: rocky + Date: Sun Dec 18 00:56:07 2016 -0500 2016-12-17 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: show-asm on python2.5 is optional make scanner2 look a little more like scanner3 +2016-12-17 rocky + + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + show-asm on python2.5 is optional Make scanner2 a little more like scanner3. + +2016-12-17 rocky + + * uncompyle6/parser.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, + uncompyle6/semantics/fragments.py: Python 2.6/2.7 tolerance in + Python 2.4 branch + 2016-12-16 rocky * NEWS: Release 2.9.8 news 2016-12-16 rocky - * __pkginfo__.py, uncompyle6/version.py: Get ready for release 2.9.8 + * : commit 13d5cd1a588b7f4f2c233c436ce6b0b39db9950e Author: rocky + Date: Fri Dec 16 22:42:46 2016 -0500 2016-12-16 rocky @@ -509,19 +999,16 @@ 2016-12-04 rocky - * ChangeLog, NEWS, uncompyle6/main.py, uncompyle6/parser.py, - uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py, - uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, - uncompyle6/scanners/scanner3.py, uncompyle6/scanners/tok.py, - uncompyle6/semantics/make_function.py, - uncompyle6/semantics/pysource.py, uncompyle6/verify.py, - uncompyle6/version.py: Get ready for release 2.9.7 Some of the many lint things. Linting is kind of stupid though. + * ChangeLog: Get ready for release 2.9.7 + +2016-12-04 rocky + + * : commit d22931cb49f0e28a0fbe48a7c1526b1f170a5b52 Author: rocky + Date: Sun Dec 4 07:31:34 2016 -0500 2016-11-28 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: Shorten Python3 grammars with + and * 2016-11-28 rocky @@ -560,7 +1047,7 @@ 2016-11-24 rocky * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: 2.7 grammar bug workaround. Fix docstring bug 2016-11-24 rocky @@ -578,7 +1065,7 @@ 2016-11-24 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: <2.7 "if" detection and dup Python 3 grammar rule 2016-11-24 rocky @@ -685,7 +1172,7 @@ 2016-11-20 rocky * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code @@ -701,7 +1188,7 @@ 2016-11-16 rocky * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, - uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: More AST checking Small fixes in output format 2016-11-15 rocky @@ -721,17 +1208,17 @@ 2016-11-14 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: WIP remove COME_FROMs around ignore_if's 2016-11-14 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: WIP remove COME_FROMs around ignore_if's 2016-11-14 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. 2016-11-13 rocky @@ -767,7 +1254,7 @@ 2016-11-11 rocky * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Revert augassign change but.. Make note of what's going on and add grammar test for bad situations we have in Python 2.6 (and perhaps others) @@ -787,7 +1274,7 @@ 2016-11-10 rocky * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were not. @@ -854,7 +1341,7 @@ 2016-10-30 rocky - * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + * .gitignore, README.rst, test/simple_source/def/03_class_method.py: Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore 2016-10-30 rocky @@ -883,20 +1370,20 @@ * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, - uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: More complete annotate handling Still have a bit of work to do though. 2016-10-28 rocky * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, - uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: Expand annotate return to Python 3.4 2016-10-28 rocky * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, - uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little 2016-10-28 rocky @@ -910,7 +1397,7 @@ * test/simple_source/bug31/04_def_annotate.py, test/simple_source/bug31/04_def_attr.py, - uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: Clean and fix Python 3 annotate arg return 2016-10-26 rocky @@ -985,7 +1472,7 @@ 2016-10-20 moagstar * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: further work on supporting single and multiple fstring decompilation 2016-10-20 rocky @@ -996,7 +1483,7 @@ 2016-10-19 moagstar * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: urther work on fstrings for python 3.6 - there is a new opcode build_string which is used to improve fstring performance, but broke the fstring support in uncompyle @@ -1184,13 +1671,13 @@ 2016-10-05 rocky * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Python 3: "and" doesn't have optional come_from 2016-10-05 rocky * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Python 3: "and" doesn't have optional come_from 2016-10-05 rocky @@ -1220,7 +1707,7 @@ 2016-09-26 rocky * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may need addressing. We want to process COME_FROMs to the same offset to be in *descending* order so we have the larger range or biggest @@ -1305,7 +1792,7 @@ 2016-09-21 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Python 2 & 3 scanner code ever so slightly closer 2016-09-21 rocky @@ -1315,7 +1802,7 @@ 2016-09-18 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: Small changes 2016-09-11 rocky @@ -1326,7 +1813,7 @@ 2016-09-11 rocky * test/bytecode_3.6/fstring.py, - test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: Tidy a bit 2016-09-09 rocky @@ -1340,7 +1827,7 @@ 2016-09-09 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 2016-09-09 rocky @@ -1362,7 +1849,7 @@ 2016-09-08 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.0-3.2 *args processing 2016-09-08 rocky @@ -1398,7 +1885,7 @@ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Python 2.6- try/except control flow detection 2016-09-04 rocky @@ -1473,19 +1960,19 @@ 2016-09-02 rocky * test/simple_source/bug26/06_return_pop.py, - uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning 2016-09-02 rocky * test/simple_source/bug33/02_named_and_kwargs.py, - uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: Fix Python 3.x named param and kwargs bug 2016-09-01 rocky * test/simple_source/bug26/04_while_and_stmt_one_line.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. In Python 2.7+ it's a single op. @@ -1493,7 +1980,7 @@ 2016-09-01 rocky * test/simple_source/bug26/02_except_as.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: Handle Python 2.6 and below "except , " 2016-08-31 rocky @@ -1635,7 +2122,7 @@ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, - uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling 2016-08-11 Omer Katz @@ -1704,7 +2191,7 @@ 2016-07-29 rocky * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. 2016-07-28 Daniel Bradburn @@ -1803,7 +2290,7 @@ 2016-07-27 rocky - * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: Small code clean up 2016-07-26 rocky @@ -1831,7 +2318,7 @@ test/simple_source/bug_pypy27/03_try_return.py, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules 2016-07-25 rocky @@ -1893,7 +2380,7 @@ * README.rst, test/simple_source/stmts/03_if_elif.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little 2016-07-25 rocky @@ -1915,7 +2402,7 @@ test/Makefile, test/test_pythonlib.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy 2016-07-24 Daniel Bradburn @@ -1935,19 +2422,19 @@ 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky @@ -1996,7 +2483,7 @@ 2016-07-17 rocky - * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: Adjust test data for changed disasm output 2016-07-16 rocky @@ -2030,7 +2517,7 @@ 2016-07-14 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we understand better what to do though, we'll go with it. @@ -2101,7 +2588,7 @@ * test/simple_source/bug33/05_store_name.py, test/simple_source/comprehension/05_3x_set_comphension.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.2 & 3.3 handle STORE_NAME better 2016-07-11 rocky @@ -2156,13 +2643,13 @@ 2016-07-10 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Bugs caused by 3.x jump_forward misclasification 2016-07-10 rocky * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification 2016-07-09 rocky @@ -2253,7 +2740,7 @@ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: Python 3 code cleanup 2016-07-08 rocky @@ -2274,7 +2761,7 @@ 2016-07-08 rocky * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: Python 2.4 generator expressions and gen_comp_body 2016-07-08 rocky @@ -2300,12 +2787,12 @@ 2016-07-08 rocky * test/simple_source/stmts/11_return_val.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: 2.5/2.6 RETURN_VALUE bug 2016-07-08 rocky - * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: 2.5/2.6 fn name clash fixes list conprehension problem 2016-07-08 rocky @@ -2347,7 +2834,7 @@ 2016-07-07 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: <2.6 make sure jump back on loops is really "back" 2016-07-07 rocky @@ -2406,12 +2893,12 @@ * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Another 2.6 while stmt. Clean up grammar a little 2016-07-03 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: 2.6 improper tagging of RETURN_END_IF 2016-07-02 rocky @@ -2448,7 +2935,7 @@ 2016-06-30 rocky * test/simple_source/stmts/06_for_break.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else 2016-06-30 rocky @@ -2465,7 +2952,7 @@ 2016-06-30 rocky * test/simple_source/comprehension/05_for_for.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: 2.6.9 list comprehension 2016-06-30 rocky @@ -2507,7 +2994,7 @@ 2016-06-28 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: Weird 2.6.9 list comprehension 2016-06-28 rocky @@ -2524,7 +3011,7 @@ * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: Base 2.5 off of 2.6. Some other small bugs. 2016-06-27 rocky @@ -2534,7 +3021,7 @@ 2016-06-27 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: 2.6 list comprehensions 2016-06-27 rocky @@ -2619,7 +3106,7 @@ 2016-06-22 rocky * test/simple_source/expression/05_yield_from.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: differing ways to do "yield from" in 3.3-3.5 2016-06-22 rocky @@ -2628,7 +3115,7 @@ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option 2016-06-22 rocky @@ -2638,7 +3125,7 @@ 2016-06-22 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: More 3.2 LOAD_CONST removal More python3 custom grammar DRYing 2016-06-22 rocky @@ -2650,7 +3137,7 @@ * test/simple_source/expression/05_lambda.py, test/simple_source/expression/10_lambda.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.2 MAKE_FUNCTION adjustment 2016-06-22 rocky @@ -2669,18 +3156,18 @@ 2016-06-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Bang on Python 3.2 decompiling. 2016-06-20 rocky * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same 2016-06-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: previous 2.7 class decorator bug fixed in 3.x 2016-06-20 rocky @@ -2712,7 +3199,7 @@ * test/simple_source/def/11_mkfunc_closure.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: 3.x make closure kw args handling bug 2016-06-20 rocky @@ -2749,7 +3236,7 @@ * test/simple_source/comprehension/05_set_comprehension.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: 2.7 and 3.x bug in dict comprehensions 2016-06-19 rocky @@ -2767,7 +3254,7 @@ * test/simple_source/looping/08_while_except_bug.py, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3 except clause parsing bug 2016-06-19 rocky @@ -2829,18 +3316,18 @@ * pytest/test_deparse.py, test/simple_source/comprehension/05_set_comprehension.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 2016-06-06 rocky * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: small changes 2016-06-06 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: include offset for starting listcomp 2016-06-03 rocky @@ -2862,7 +3349,7 @@ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, - uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: Limited support for Python 2.3 2016-06-03 rocky @@ -2960,7 +3447,7 @@ 2016-05-29 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: Bang again on Python 2.5 and 2.6 scanners 2016-05-29 rocky @@ -2972,7 +3459,7 @@ 2016-05-29 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. 2016-05-29 rocky @@ -2989,7 +3476,7 @@ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: DRY scanners more 2016-05-28 rocky @@ -3004,7 +3491,7 @@ * test/simple_source/comprehension/06_list_ifnot.py, test/simple_source/comprehension/10-list-ifnot.py, uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: Remove dis3. Fix in 3.x list if not comprehension 2016-05-28 rocky @@ -3015,7 +3502,7 @@ 2016-05-28 rocky * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, - uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: Remove dup 3.x opcodes 2016-05-28 rocky @@ -3025,7 +3512,7 @@ 2016-05-28 rocky * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, - uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: xdis for Python 3 opcodes 2016-05-28 rocky @@ -3127,7 +3614,7 @@ 2016-05-18 rocky * pytest/test_marsh.py, - test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: Handle marshal frozenset 2016-05-18 rocky @@ -3167,14 +3654,14 @@ 2016-05-17 rocky * pytest/test_marsh.py, - test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: Fix marshal bug in handling complex numbers 2016-05-17 rocky * Makefile, test/simple_source/def/09_class_closure.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS 2016-05-16 rocky @@ -3244,7 +3731,7 @@ * test/simple_source/expression/05_lambda.py, test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Fix bug in Python 3 lambda expression handling Some other small cleanup changes 2016-05-15 rocky @@ -3252,7 +3739,7 @@ * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, - uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: pydisassemble disassemble without grammar mangling Some other small cleanups as well 2016-05-15 rocky @@ -3292,7 +3779,7 @@ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs 2016-05-15 rocky @@ -3364,7 +3851,7 @@ 2016-05-12 rocky * uncompyle6/scanners/scanner26.py, - uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: More small changes 2016-05-12 rocky @@ -3381,7 +3868,7 @@ * __pkginfo__.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires sparck 1.2.0) * some optimization in scanner3 @@ -3395,7 +3882,7 @@ uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Redo make_function for *, arg main(*, file='foo') and things like that now work 2016-05-11 rocky @@ -3427,7 +3914,7 @@ 2016-05-09 rocky * test/simple_source/stmts/09_whiletrue_bug.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3 "while True" bug 2016-05-09 rocky @@ -3521,7 +4008,7 @@ * HISTORY.md, test/simple_source/branching/10_if_pass.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections 2016-05-08 rocky @@ -3538,7 +4025,7 @@ * test/simple_source/expression/05_yield_from.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. 2016-05-06 rocky @@ -3603,19 +4090,19 @@ 2016-05-05 rocky * test/simple_source/def/05_abc_class.py, - test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: Python 3.5 abc.py bug distilled 2016-05-05 rocky - * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: Add cross-Python-protable 3.5 dis module 2016-05-04 rocky * test/simple_source/stmts/05_with.py, uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo 2016-05-03 rocky @@ -3625,7 +4112,7 @@ 2016-05-03 rocky * uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: Don't repeat next_except_jump 2016-05-03 rocky @@ -3743,7 +4230,7 @@ * requirements.txt, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: spark -> spark_parser 2016-04-28 rocky @@ -3891,7 +4378,7 @@ 2016-01-02 rocky * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: Make ScannerXX() initialization the same on Python 2.x and 3.x 2016-01-02 rocky @@ -3985,7 +4472,7 @@ 2015-12-31 rocky * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Handle Python 3.3 > dotted class names 2015-12-30 rocky @@ -4008,7 +4495,7 @@ 2015-12-30 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Remove accidental schmutz. Try using pattr on 3.4 to get fn names 2015-12-30 rocky @@ -4055,7 +4542,7 @@ * test/simple_source/exception/25_try_except.py, test/test_pythonlib.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: Towards Python3 getting try/except working more often. 2015-12-29 rocky @@ -4088,7 +4575,7 @@ * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, - uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: scanner3: Python 2.6 compatibility: change set initializations. Get rid of * import opcode_*: only a little of the much-needed larger cleanup Makefile: remove 3.x bytecode checking from Python 2.x for @@ -4107,7 +4594,7 @@ * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Add Python3 marshal codes and start to handle cross-version Python code object types, introducing scan.Code3 @@ -4157,7 +4644,7 @@ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY Python3 scanner code. Some cross version handling fixed. Some Python 3.2 and 3.3 deparse fixes. @@ -4173,7 +4660,7 @@ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY Python3 scanner code. Some cross version handling fixed. Some Python 3.2 and 3.3 deparse fixes. @@ -4237,7 +4724,7 @@ test/simple_source/stmts/15_assert.py, test/simple_source/stmts/15_for_if.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE get jump offsets into jump attributes. Fix up 3.2 scanner paritally and use that in 3.4 for in cross version disassembly. @@ -4321,7 +4808,7 @@ * test/simple_source/simple_stmts/00_import.py, test/simple_source/simple_stmts/00_pass.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Start Python3 class(superclass) handling 2015-12-23 rocky @@ -4355,7 +4842,7 @@ uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Allow comments in grammar rules. Start working on Python3 class (not finished). More test organization. @@ -4439,7 +4926,7 @@ test/simple_source/misc/assign.py, test/simple_source/misc/assign_none_str.py, test/simple_source/simple_stmts/00_assign.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Start Python3 execption handling 2015-12-21 rocky @@ -4585,7 +5072,7 @@ * test/Makefile, test/simple-source/misc/assign_none.py, test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Python 3 decompilation from Python2 2015-12-20 rocky @@ -4603,7 +5090,7 @@ 2015-12-20 rocky * Makefile, README.rst, test/Makefile, test/dis-compare.py, - uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: Go over makefiles to make "make check" work. walker, deparser: use zip_longest @@ -4673,7 +5160,7 @@ test/simple-source/precedence/left.py, test/simple-source/precedence/right.py, test/simple-source/precedence/structure.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: Python 3 bytecode handles opcodes with varargs (better). Decompiling assert works. Add more of the simple tests and their compiled bytecode. @@ -4715,7 +5202,7 @@ 2015-12-18 rocky - * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: disas.py: Do better for finding/turning a .py file into a .pyc file across supported versions of Python. Add for else list comprehension test @@ -4814,7 +5301,7 @@ 2015-12-17 rocky - * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: Python 3.4 correct grammar for some looping constructs 2015-12-17 rocky @@ -4849,14 +5336,14 @@ 2015-12-16 rocky * uncompyle6/deparser.py, uncompyle6/disas.py, - uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: Add LICENSE. Add demo programs and DRY code a little 2015-12-16 rocky * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, - uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: On Python3.4 decompiling Python 3.4 instructions, use its built-in disassembler routines. In contrast to what was here, they most likely work! @@ -4913,7 +5400,7 @@ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Split out marhsal and disassemble code and spell disassemble correctly. Fix some lint issues @@ -4998,7 +5485,7 @@ 2015-12-14 rocky - * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: + * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: uncompyle6/dparser -> uncompyle6/parser 2015-12-14 rocky @@ -5251,7 +5738,7 @@ * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, - uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: Correct MANIFEST->MANIFEST.in more lint 2015-12-13 R. Bernstein @@ -5268,7 +5755,7 @@ uncompyle6/__init__.py, uncompyle6/disas.py, uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, uncompyle6/scanner25.py, uncompyle6/scanner26.py, - uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our own disassembler. Python's will do fine @@ -5369,13 +5856,13 @@ * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, uncompyle6/scanner25.py, uncompyle6/scanner27.py, - uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: Minimal disassemble, ast compile and deparse work on Python 3. Some linting 2015-12-12 rocky - * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: + * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: parser -> dparser so as not to conflict with python3's parser. 2015-12-12 rocky @@ -5394,7 +5881,7 @@ 2015-12-11 rocky - * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: python3 compatibiity and remove some flake8 warnings. 2015-12-11 rocky @@ -5472,7 +5959,7 @@ 2013-07-16 root * uncompyle2/__init__.py, uncompyle2/disas.py, - uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: marshal disassembly improvement 2013-06-20 Mysterie @@ -5557,7 +6044,7 @@ uncompyle2/opcode/opcode_27.py, uncompyle2/parser.py, uncompyle2/scanner.py, uncompyle2/scanner25.py, uncompyle2/scanner26.py, uncompyle2/scanner27.py, - uncompyle2/spark.py, uncompyle2/verify.py, uncompyle2/walker.py: + uncompyle2/spark.py, uncompyle2/verify.py, uncompyle2/walker.py: Cleaning code & patch 2012-09-22 Mysterie @@ -5662,3 +6149,4 @@ 2012-06-05 Mysterie * first commit + diff --git a/NEWS b/NEWS index cc30c15de..9c7ade5f5 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +uncompyle6 2.9.11 2016-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 - Python grammar rule fixes diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 5d5facdb4..566e6123f 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.9.10' +VERSION='2.9.11' From 658c8b4be75127c9fd0b48f6a83d9bc05e73b79f Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 30 May 2017 02:30:56 -0400 Subject: [PATCH 025/489] No decorators in Python < 2.6 --- pytest/test_function_call.py | 175 ----------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 pytest/test_function_call.py diff --git a/pytest/test_function_call.py b/pytest/test_function_call.py deleted file mode 100644 index 936c31ce3..000000000 --- a/pytest/test_function_call.py +++ /dev/null @@ -1,175 +0,0 @@ -# std -import string -# 3rd party -from hypothesis import given, assume, example, settings, strategies as st -import pytest -# uncompyle -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, '', 'single') - except: - assume(False) - return function_call - - -def test_function_no_args(): - validate_uncompyle("fn()") - - -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): - - @given(isolated_function_calls('positional')) - @example("fn(0)") - def test_function_positional_only(expr): - validate_uncompyle(expr) - - @given(isolated_function_calls('keyword')) - @example("fn(a=0)") - def test_function_call_keyword_only(expr): - validate_uncompyle(expr) - - @given(isolated_function_calls('star')) - @example("fn(*items)") - def test_function_call_star_only(expr): - validate_uncompyle(expr) - - @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) From 22e5a4a2835a89feadb16f9a0559fdcca5581a7e Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Jun 2017 05:53:41 -0400 Subject: [PATCH 026/489] Administrivia See if appveyor will handle 2.5 --- __pkginfo__.py | 2 +- appveyor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 4e2d407ad..887406844 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.3.1, < 3.4.0', 'six'] + 'xdis >= 3.3.1, < 3.4.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' diff --git a/appveyor.yml b/appveyor.yml index 04ac8d776..840b5870c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,8 +15,8 @@ environment: # PYTHON_VERSION: "2.7.x" # PYTHON_ARCH: "32" - - PYTHON: "C:\\Python27-x64" - PYTHON_VERSION: "2.7.x" + - PYTHON: "C:\\Python25-x64" + PYTHON_VERSION: "2.5.x" PYTHON_ARCH: "64" # - PYTHON: "C:\\Python26" From 89b42e369659ea7420d0e59039c457601ba99efb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Jun 2017 05:55:21 -0400 Subject: [PATCH 027/489] Nope it (appveyor) doesn't. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 840b5870c..04ac8d776 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,8 +15,8 @@ environment: # PYTHON_VERSION: "2.7.x" # PYTHON_ARCH: "32" - - PYTHON: "C:\\Python25-x64" - PYTHON_VERSION: "2.5.x" + - PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" # - PYTHON: "C:\\Python26" From df8d253f785481d8f6dd4fc90b8c32562701d007 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Jun 2017 06:00:47 -0400 Subject: [PATCH 028/489] 2.4 doesn't do six --- pytest/validate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pytest/validate.py b/pytest/validate.py index f5cc1f7f3..973c71a75 100644 --- a/pytest/validate.py +++ b/pytest/validate.py @@ -6,8 +6,7 @@ import subprocess import tempfile import functools -# compatability -import six +from StringIO import StringIO # uncompyle6 / xdis 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 @@ -123,7 +122,7 @@ def validate_uncompyle(text, mode='exec'): original_text = text deparsed = deparse_code(PYTHON_VERSION, original_code, - compile_mode=mode, out=six.StringIO()) + compile_mode=mode, out=StringIO()) uncompyled_text = deparsed.text uncompyled_code = compile(uncompyled_text, '', 'exec') From 0f489672b9fadef7b76ef6c9afe3d879542d9477 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 18 Jun 2017 16:05:22 -0400 Subject: [PATCH 029/489] More merge fixups from master --- uncompyle6/scanners/scanner2.py | 2 +- uncompyle6/scanners/scanner3.py | 2 +- uncompyle6/semantics/fragments.py | 2 +- uncompyle6/semantics/make_function.py | 121 ++++++++++++++------------ 4 files changed, 67 insertions(+), 60 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 2e3d5b3c6..59cf8f82b 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index ae26df50e..7fb4af3b9 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -23,7 +23,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 50bc41659..f9ffe7068 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -79,7 +79,7 @@ from uncompyle6 import PYTHON_VERSION if PYTHON_VERSION < 2.6: - from xdis.namedtuple25 import namedtuple + from xdis.namedtuple24 import namedtuple else: from collections import namedtuple diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 7460ed46b..bffe8dd81 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -430,34 +430,10 @@ def build_param(ast, name, default): def make_function3(self, node, isLambda, nested=1, codeNode=None): - """Dump function definition, doc string, and function body in - Python version 3.0 and above - """ - - # For Python 3.3, the evaluation stack in MAKE_FUNCTION is: - - # * default argument objects in positional order - # * pairs of name and default argument, with the name just below - # the object on the stack, for keyword-only parameters - # * parameter annotation objects - # * a tuple listing the parameter names for the annotations - # (only if there are ony annotation objects) - # * the code associated with the function (at TOS1) - # * the qualified name of the function (at TOS) + """Dump function definition, doc string, and function body.""" - # For Python 3.0 .. 3.2 the evaluation stack is: - # The function object is defined to have argc default parameters, - # which are found below TOS. - # * first come positional args in the order they are given in the source, - # * next come the keyword args in the order they given in the source, - # * finally is the code associated with the function (at TOS) - # - # Note: There is no qualified name at TOS - - # MAKE_CLOSURE adds an additional closure slot - - # Thank you, Python, for a such a well-thought out system that has - # changed 4 or so times. + # FIXME: call make_function3 if we are self.version >= 3.0 + # and then simplify the below. def build_param(ast, name, default): """build parameters: @@ -477,31 +453,21 @@ def build_param(ast, name, default): # MAKE_FUNCTION_... or MAKE_CLOSURE_... assert node[-1].type.startswith('MAKE_') - - # Python 3.3+ adds a qualified name at TOS (-1) - # moving down the LOAD_LAMBDA instruction - if 3.0 <= self.version <= 3.2: - lambda_index = -2 - elif 3.03 <= self.version: - lambda_index = -3 - else: - lambda_index = None - args_node = node[-1] if isinstance(args_node.attr, tuple): - pos_args, kw_args, annotate_argc = args_node.attr - if self.version <= 3.3 and len(node) > 2 and node[lambda_index] != 'LOAD_LAMBDA': - # args are after kwargs; kwargs are bundled as one node + if self.version <= 3.3 and len(node) > 2 and node[-3] != 'LOAD_LAMBDA': + # positional args are after kwargs defparams = node[1:args_node.attr[0]+1] else: - # args are before kwargs; kwags as bundled as one node + # positional args are before kwargs defparams = node[:args_node.attr[0]] + pos_args, kw_args, annotate_argc = args_node.attr else: if self.version < 3.6: defparams = node[:args_node.attr] else: default, kw, annotate, closure = args_node.attr - # FIXME: start here for Python 3.6 and above: + # FIXME: start here. defparams = [] # if default: # defparams = node[-(2 + kw + annotate + closure)] @@ -511,6 +477,12 @@ def build_param(ast, name, default): kw_args = 0 pass + if 3.0 <= self.version <= 3.2: + lambda_index = -2 + elif 3.03 <= self.version: + lambda_index = -3 + else: + lambda_index = None if lambda_index and isLambda and iscode(node[lambda_index].attr): assert node[lambda_index].type == 'LOAD_LAMBDA' @@ -526,7 +498,7 @@ def build_param(ast, name, default): paramnames = list(code.co_varnames[:argc]) # defaults are for last n parameters, thus reverse - if not 3.0 <= self.version <= 3.1: + if not 3.0 <= self.version <= 3.2: paramnames.reverse(); defparams.reverse() try: @@ -543,27 +515,62 @@ def build_param(ast, name, default): kw_pairs = args_node.attr[1] else: kw_pairs = 0 + indent = self.indent # build parameters - params = [build_param(ast, name, d) for - name, d in zip_longest(paramnames, defparams, fillvalue=None)] - - if not 3.0 <= self.version <= 3.1: + if self.version != 3.2: + tup = [paramnames, defparams] + params = [build_param(ast, name, default) for + name, default in map(lambda *tup:tup, *tup)] params.reverse() # back to correct order - if code_has_star_arg(code): - if self.version > 3.0: - params.append('*%s' % code.co_varnames[argc + kw_pairs]) + if code_has_star_arg(code): + if self.version > 3.0: + params.append('*%s' % code.co_varnames[argc + kw_pairs]) + else: + params.append('*%s' % code.co_varnames[argc]) + argc += 1 + + # dump parameter list (with default values) + if isLambda: + self.write("lambda ", ", ".join(params)) else: - params.append('*%s' % code.co_varnames[argc]) - argc += 1 + self.write("(", ", ".join(params)) + # self.println(indent, '#flags:\t', int(code.co_flags)) - # dump parameter list (with default values) - if isLambda: - self.write("lambda ", ", ".join(params)) else: - self.write("(", ", ".join(params)) - # self.println(indent, '#flags:\t', int(code.co_flags)) + if isLambda: + self.write("lambda ") + else: + self.write("(") + pass + + last_line = self.f.getvalue().split("\n")[-1] + l = len(last_line) + indent = ' ' * l + line_number = self.line_number + + if code_has_star_arg(code): + self.write('*%s' % code.co_varnames[argc + kw_pairs]) + argc += 1 + + i = len(paramnames) - len(defparams) + self.write(", ".join(paramnames[:i])) + if i > 0: + suffix = ', ' + else: + suffix = '' + for n in node: + if n == 'pos_arg': + self.write(suffix) + self.write(paramnames[i] + '=') + i += 1 + self.preorder(n) + if (line_number != self.line_number): + suffix = ",\n" + indent + line_number = self.line_number + else: + suffix = ', ' if kw_args > 0: if not (4 & code.co_flags): From 348afeebbfc8b35b22781df40ac5f7872e7d99c5 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 1 Aug 2017 22:32:43 -0400 Subject: [PATCH 030/489] Python 2.4 compatibility --- pytest/validate.py | 2 -- test/dis-compare.py | 3 +-- test/simple-uncompyle-code-test.py | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pytest/validate.py b/pytest/validate.py index 973c71a75..a25362ac9 100644 --- a/pytest/validate.py +++ b/pytest/validate.py @@ -1,5 +1,3 @@ -# future -from __future__ import print_function # std import os import difflib diff --git a/test/dis-compare.py b/test/dis-compare.py index 86418a084..f60a97c1f 100755 --- a/test/dis-compare.py +++ b/test/dis-compare.py @@ -1,9 +1,8 @@ #!/usr/bin/env python # Mode: -*- python -*- # -# Copyright (c) 2015 by Rocky Bernstein +# Copyright (c) 2015, 2017 by Rocky Bernstein # -from __future__ import print_function import dis, os.path diff --git a/test/simple-uncompyle-code-test.py b/test/simple-uncompyle-code-test.py index 732084e55..1122ed71d 100755 --- a/test/simple-uncompyle-code-test.py +++ b/test/simple-uncompyle-code-test.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -from __future__ import print_function - from uncompyle6 import uncompyle import sys, inspect From e790cb75fd3b097e4554f2881dc21935a93a3a5d Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Aug 2017 06:20:07 -0400 Subject: [PATCH 031/489] Python 2.4 doesn't do six --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 9049f5ec1..f84d9e5d8 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.4.0, < 3.5.0', 'six'] + 'xdis >= 3.5.1, < 3.6.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' From a9635da96a8732ceb319e548ce373aecef5246da Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Aug 2017 06:36:40 -0400 Subject: [PATCH 032/489] in xdis "exception match" is now "exception-match" --- uncompyle6/scanners/scanner3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 2c1ebd3d4..be359f853 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -927,7 +927,7 @@ def detect_control_flow(self, offset, targets): # except block return jump_prev = prev_op[offset] if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP: - if self.opc.cmp_op[code[jump_prev+1]] == 'exception match': + if self.opc.cmp_op[code[jump_prev+1]] == 'exception-match': return if self.version >= 3.5: # Python 3.5 may remove as dead code a JUMP From 8bb01143d8e0e74ac6539d0235cf01d9a515f949 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Aug 2017 08:28:08 -0400 Subject: [PATCH 033/489] Remove six from python 2.4/2.5 --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 9049f5ec1..94dc8555e 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.4.0, < 3.5.0', 'six'] + 'xdis >= 3.4.0, < 3.5.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' From 5b24c20331eac943f90426cd06b5c17bd782e979 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Aug 2017 08:37:50 -0400 Subject: [PATCH 034/489] Bump xdis --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 94dc8555e..f84d9e5d8 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.4.0, < 3.5.0'] + 'xdis >= 3.5.1, < 3.6.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' From ddc348999196401b360ef8ea019f7f3bc9ec9291 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 3 Aug 2017 03:48:57 -0400 Subject: [PATCH 035/489] Python 2.4 comptiability and ... exception match -> exception-match --- pytest/test_deparse.py | 2 +- pytest/test_docstring.py | 2 +- pytest/test_fjt.py | 3 +-- pytest/test_single_compile.py | 34 ++++++++++++++++---------------- pytest/validate.py | 20 ++++++++++++------- uncompyle6/scanners/scanner3.py | 2 +- uncompyle6/scanners/scanner30.py | 2 +- 7 files changed, 35 insertions(+), 30 deletions(-) diff --git a/pytest/test_deparse.py b/pytest/test_deparse.py index 0c883970f..412adfe73 100644 --- a/pytest/test_deparse.py +++ b/pytest/test_deparse.py @@ -29,7 +29,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(PYTHON_VERSION, code) def check_expect(expect, parsed): diff --git a/pytest/test_docstring.py b/pytest/test_docstring.py index b967b6fde..74091876c 100644 --- a/pytest/test_docstring.py +++ b/pytest/test_docstring.py @@ -10,7 +10,7 @@ maxint = sys.maxint from uncompyle6.semantics.helper import print_docstring -class PrintFake(): +class PrintFake: def __init__(self): self.pending_newlines = 0 self.f = StringIO() diff --git a/pytest/test_fjt.py b/pytest/test_fjt.py index 28cb2a7e9..c293cfddd 100644 --- a/pytest/test_fjt.py +++ b/pytest/test_fjt.py @@ -21,9 +21,8 @@ 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) - print(PYTHON_VERSION) if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY: n = scan.setup_code(code) scan.build_lines_data(code, n) diff --git a/pytest/test_single_compile.py b/pytest/test_single_compile.py index 2e381aa57..415c7d80b 100644 --- a/pytest/test_single_compile.py +++ b/pytest/test_single_compile.py @@ -1,19 +1,19 @@ -import pytest -from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code +from uncompyle6 import PYTHON_VERSION, deparse_code -def test_single_mode(): - single_expressions = ( - 'i = 1', - 'i and (j or k)', - 'i += 1', - 'i = j % 4', - 'i = {}', - 'i = []', - 'for i in range(10):\n i\n', - 'for i in range(10):\n for j in range(10):\n i + j\n', - 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' - ) +if PYTHON_VERSION >= 2.5: + def test_single_mode(): + single_expressions = ( + 'i = 1', + 'i and (j or k)', + 'i += 1', + 'i = j % 4', + 'i = {}', + 'i = []', + 'for i in range(10):\n i\n', + 'for i in range(10):\n for j in range(10):\n i + j\n', + 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' + ) - for expr in single_expressions: - code = compile(expr + '\n', '', 'single') - assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n' + for expr in single_expressions: + code = compile(expr + '\n', '', 'single') + assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n' diff --git a/pytest/validate.py b/pytest/validate.py index a25362ac9..5d437cb39 100644 --- a/pytest/validate.py +++ b/pytest/validate.py @@ -3,7 +3,7 @@ import difflib import subprocess import tempfile -import functools + from StringIO import StringIO # uncompyle6 / xdis from uncompyle6 import PYTHON_VERSION, IS_PYPY, deparse_code @@ -11,11 +11,15 @@ from xdis.bytecode import Bytecode from xdis.main import get_opcode opc = get_opcode(PYTHON_VERSION, IS_PYPY) -Bytecode = functools.partial(Bytecode, opc=opc) +try: + import functools + Bytecode = functools.partial(Bytecode, opc=opc) + def _dis_to_text(co): + return Bytecode(co).dis() +except: + pass -def _dis_to_text(co): - return Bytecode(co).dis() def print_diff(original, uncompyled): @@ -39,8 +43,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() @@ -57,8 +64,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): diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 2c1ebd3d4..be359f853 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -927,7 +927,7 @@ def detect_control_flow(self, offset, targets): # except block return jump_prev = prev_op[offset] if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP: - if self.opc.cmp_op[code[jump_prev+1]] == 'exception match': + if self.opc.cmp_op[code[jump_prev+1]] == 'exception-match': return if self.version >= 3.5: # Python 3.5 may remove as dead code a JUMP diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index b5f4e300b..c87034dab 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -293,7 +293,7 @@ def detect_control_flow(self, offset, targets): # except block return jump_prev = prev_op[offset] if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP: - if self.opc.cmp_op[code[jump_prev+1]] == 'exception match': + if self.opc.cmp_op[code[jump_prev+1]] == 'exception-match': return if self.version >= 3.5: # Python 3.5 may remove as dead code a JUMP From dc627d13b8455ded4bf708a596bb466f9df9bf7b Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 9 Aug 2017 21:19:30 -0400 Subject: [PATCH 036/489] Get ready for release 2.11.3 --- ChangeLog | 43 +++++++++++++++++++++++++++++++++++++++++-- NEWS | 9 +++++++++ README.rst | 3 +++ __pkginfo__.py | 2 +- uncompyle6/version.py | 2 +- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6775a627c..d15937188 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,46 @@ +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 - * HOW-TO-REPORT-A-BUG.md, uncompyle6/version.py: Get ready for - release 2.11.2 + * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 2017-07-08 rocky diff --git a/NEWS b/NEWS index 80f594186..e1d418c20 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,12 @@ +uncompyle6 2.11.2 2017-08-09 + +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) diff --git a/README.rst b/README.rst index 63a570032..1cbeb43e0 100644 --- a/README.rst +++ b/README.rst @@ -172,6 +172,9 @@ See Also * 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 `_ +* 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 diff --git a/__pkginfo__.py b/__pkginfo__.py index 453e3c082..a54bf0fff 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.5.1, < 3.6.0', 'six'] + 'xdis == 3.5.1', 'six'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' diff --git a/uncompyle6/version.py b/uncompyle6/version.py index f2462e1e7..632937ca8 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.2' +VERSION='2.11.3' From 45782bbb39bec374bda1fcda14d199667c4b7021 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 9 Aug 2017 21:46:27 -0400 Subject: [PATCH 037/489] Get ready for release 2.11.3 --- ChangeLog | 361 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 201 insertions(+), 160 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74d680105..9ed49afb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,22 @@ 2017-08-09 rocky - * README.rst, __pkginfo__.py, uncompyle6/version.py: Get ready for - release 2.11.3 + * : commit dc627d13b8455ded4bf708a596bb466f9df9bf7b Author: rocky + Date: Wed Aug 9 21:19:30 2017 -0400 + +2017-08-03 rocky + + * pytest/test_deparse.py, pytest/test_docstring.py, + pytest/test_fjt.py, pytest/test_single_compile.py, + pytest/validate.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner30.py: Python 2.4 comptiability and ... exception match -> exception-match + +2017-08-02 rocky + + * __pkginfo__.py: Bump xdis + +2017-08-02 rocky + + * __pkginfo__.py: Remove six from python 2.4/2.5 2017-08-02 rocky @@ -11,6 +26,11 @@ * __pkginfo__.py: Remove six from Python-2.4/2.5 package +2017-08-01 rocky + + * pytest/validate.py, test/dis-compare.py, + test/simple-uncompyle-code-test.py: Python 2.4 compatibility + 2017-07-17 rocky * __pkginfo__.py, uncompyle6/scanners/scanner2.py, @@ -75,10 +95,8 @@ 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 + * : commit 9c072a6a423d8379712296dbcd499c772ba7ef59 Author: rocky + Date: Sun Jun 25 18:44:50 2017 -0400 2017-06-25 rocky @@ -88,7 +106,7 @@ * __pkginfo__.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: Use xdis' instruction offset calculation fns.. next_offset, op_size, has_argument 2017-06-19 rocky @@ -103,8 +121,14 @@ 2017-06-18 rocky - * ChangeLog, NEWS, uncompyle6/version.py: Get ready for release - 2.11.0 + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, + uncompyle6/semantics/fragments.py, + uncompyle6/semantics/make_function.py: More merge fixups from master + +2017-06-18 rocky + + * : commit af10f99776b142c44fb4507033fb3220b5f57910 Author: rocky + Date: Sun Jun 18 15:22:27 2017 -0400 2017-06-13 rocky @@ -169,7 +193,7 @@ 2017-06-06 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated properly. Better grammar structure for Python 3.6 call_function. @@ -181,7 +205,23 @@ regression on one of the test cases 2017-06-05 rocky ->>>>>>> master + + * uncompyle6/semantics/fragments.py: Important fragments bug fix... start, finish that had been adjusted wasn't getting reflected in + final returned deparsed.offsets dictionary. Redo keeping API + compatibility, i.e we still use namedtuple NodeInfo. + +2017-06-04 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh. + +2017-06-03 rocky + + * README.rst, __pkginfo__.py, + test/simple_source/bug35/04_CALL_FUNCTION_VAR_KW.py, + uncompyle6/semantics/fragments.py: Small changes. fragment tag EXEC_STMT + +2017-06-03 rocky * pytest/validate.py: 2.4 doesn't do six @@ -268,7 +308,7 @@ 2017-05-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: More explicit about 3.5 UNMAP_PACK Have to reduce 3.5 bytecode testing for now, code is more solid. 2017-05-19 rocky @@ -301,7 +341,7 @@ 2017-05-19 rocky - * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before needing EXTENDED_ARG has been reduced to 256, but theoretically possible in earlier versions. @@ -331,7 +371,7 @@ 2017-05-16 rocky - * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: Allow LOAD_CONST EXTENDED_ARG 2017-05-15 rocky @@ -369,7 +409,7 @@ 2017-05-13 rocky * README.rst, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: Bang on 3.6 MAKE_FUNCTION a bit more parse3.py, parse36.py: adding return_closure rule tags what's going on with this rule pysource.py: start changing semantic rules to support code changed by new make_function semantics README.rst: typo @@ -412,7 +452,7 @@ * pytest/test_CALL_FUNCTION_KW.sh, pytest/test_function_call.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, - uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: Added support for support for Python 3.6 CALL_FUNCTION_KW 2017-05-08 rocky @@ -479,7 +519,7 @@ 2017-05-06 rocky * test/Makefile, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/fragments.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/fragments.py: Sync with master 2017-05-06 rocky @@ -489,7 +529,7 @@ 2017-05-05 rocky - * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ 2017-05-05 rocky @@ -513,7 +553,7 @@ 2017-05-02 rocky * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, - uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: BUILD_MAP_UNPACK'ing of dictionaries in 3.5 2017-05-01 rocky @@ -527,7 +567,7 @@ 2017-04-29 rocky * test/simple_source/bug35/01_map_unpack.py, - uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: Handle BUILD_MAP_UNPACK in a build_list 2017-04-27 rocky @@ -587,7 +627,7 @@ 2017-04-22 rocky * test/simple_source/bug33/02_pos_args.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: 3.3+ bug in handling single kwarg after * Towards fixing issue #110 2017-04-20 rocky @@ -701,7 +741,7 @@ 2017-04-13 rocky - * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous commit. @@ -724,13 +764,13 @@ 2017-04-11 rocky * test/simple_source/bug31/04_def_annotate.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Towards fixing annotated decorator functions... and annotate functions 2017-04-10 rocky * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, - uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: grammar typo check_ast: add while1else to list of looping constructs pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is @@ -750,7 +790,7 @@ 2017-04-09 rocky * test/simple_source/def/10_kw+pos_args-bug.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Another Python 3.5 FUNCTION_VAR bug Fixes #94 2017-04-09 rocky @@ -861,7 +901,7 @@ 2017-02-28 rocky - * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: Python 2.6 a == b or c == d == 3 grammar bug 2017-02-28 rocky @@ -922,7 +962,7 @@ 2017-02-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: Python 3.x needs more "while 1" grammar rules 2017-02-20 rocky @@ -1071,7 +1111,7 @@ 2017-01-15 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Handle 3.6 BUILD_CONST_KEYMAP 2017-01-15 rocky @@ -1121,7 +1161,7 @@ 2017-01-10 rocky * test/simple_source/bug35/03_double_star_unpack.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Improve BUILD_xxx_UNPACK slightly 2017-01-09 rocky @@ -1140,7 +1180,7 @@ 2017-01-08 rocky - * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: Python 3.0 decompile bugs 2017-01-08 rocky @@ -1171,7 +1211,7 @@ 2017-01-07 rocky * test/simple_source/bug35/03_async_await.py, - uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: Start to add 3.5+ await and async 2017-01-07 rocky @@ -1208,7 +1248,7 @@ 2017-01-02 rocky - * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: Python 3.5 continue detection bug 2017-01-02 rocky @@ -1228,7 +1268,7 @@ 2017-01-01 rocky - * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: Towards fixing Python 3.5 return bugs 2017-01-01 rocky @@ -1270,12 +1310,12 @@ 2016-12-29 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: dectect_structure() -> detect_control_flow() 2016-12-29 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie 2016-12-29 rocky @@ -1311,7 +1351,7 @@ 2016-12-27 rocky * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: WIP : Add THEN to disambigute from "and" 2016-12-27 rocky @@ -1381,7 +1421,7 @@ * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) 2016-12-18 rocky @@ -1391,12 +1431,12 @@ 2016-12-17 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: show-asm on python2.5 is optional make scanner2 look a little more like scanner3 2016-12-17 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: show-asm on python2.5 is optional Make scanner2 a little more like scanner3. 2016-12-17 rocky @@ -1490,7 +1530,7 @@ 2016-11-28 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: Shorten Python3 grammars with + and * 2016-11-28 rocky @@ -1529,7 +1569,7 @@ 2016-11-24 rocky * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: 2.7 grammar bug workaround. Fix docstring bug 2016-11-24 rocky @@ -1547,7 +1587,7 @@ 2016-11-24 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: <2.7 "if" detection and dup Python 3 grammar rule 2016-11-24 rocky @@ -1654,7 +1694,7 @@ 2016-11-20 rocky * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code @@ -1670,7 +1710,7 @@ 2016-11-16 rocky * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, - uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: More AST checking Small fixes in output format 2016-11-15 rocky @@ -1690,17 +1730,17 @@ 2016-11-14 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: WIP remove COME_FROMs around ignore_if's 2016-11-14 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: WIP remove COME_FROMs around ignore_if's 2016-11-14 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. 2016-11-13 rocky @@ -1736,7 +1776,7 @@ 2016-11-11 rocky * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Revert augassign change but.. Make note of what's going on and add grammar test for bad situations we have in Python 2.6 (and perhaps others) @@ -1756,7 +1796,7 @@ 2016-11-10 rocky * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were not. @@ -1823,7 +1863,7 @@ 2016-10-30 rocky - * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + * .gitignore, README.rst, test/simple_source/def/03_class_method.py: Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore 2016-10-30 rocky @@ -1852,20 +1892,20 @@ * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, - uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: More complete annotate handling Still have a bit of work to do though. 2016-10-28 rocky * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, - uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: Expand annotate return to Python 3.4 2016-10-28 rocky * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, - uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little 2016-10-28 rocky @@ -1879,7 +1919,7 @@ * test/simple_source/bug31/04_def_annotate.py, test/simple_source/bug31/04_def_attr.py, - uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: Clean and fix Python 3 annotate arg return 2016-10-26 rocky @@ -1954,7 +1994,7 @@ 2016-10-20 moagstar * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: further work on supporting single and multiple fstring decompilation 2016-10-20 rocky @@ -1965,7 +2005,7 @@ 2016-10-19 moagstar * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, - uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: urther work on fstrings for python 3.6 - there is a new opcode build_string which is used to improve fstring performance, but broke the fstring support in uncompyle @@ -2153,13 +2193,13 @@ 2016-10-05 rocky * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Python 3: "and" doesn't have optional come_from 2016-10-05 rocky * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Python 3: "and" doesn't have optional come_from 2016-10-05 rocky @@ -2189,7 +2229,7 @@ 2016-09-26 rocky * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may need addressing. We want to process COME_FROMs to the same offset to be in *descending* order so we have the larger range or biggest @@ -2274,7 +2314,7 @@ 2016-09-21 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Python 2 & 3 scanner code ever so slightly closer 2016-09-21 rocky @@ -2284,7 +2324,7 @@ 2016-09-18 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: Small changes 2016-09-11 rocky @@ -2295,7 +2335,7 @@ 2016-09-11 rocky * test/bytecode_3.6/fstring.py, - test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: Tidy a bit 2016-09-09 rocky @@ -2309,7 +2349,7 @@ 2016-09-09 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 2016-09-09 rocky @@ -2331,7 +2371,7 @@ 2016-09-08 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.0-3.2 *args processing 2016-09-08 rocky @@ -2367,7 +2407,7 @@ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Python 2.6- try/except control flow detection 2016-09-04 rocky @@ -2442,19 +2482,19 @@ 2016-09-02 rocky * test/simple_source/bug26/06_return_pop.py, - uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning 2016-09-02 rocky * test/simple_source/bug33/02_named_and_kwargs.py, - uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: Fix Python 3.x named param and kwargs bug 2016-09-01 rocky * test/simple_source/bug26/04_while_and_stmt_one_line.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. In Python 2.7+ it's a single op. @@ -2462,7 +2502,7 @@ 2016-09-01 rocky * test/simple_source/bug26/02_except_as.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: Handle Python 2.6 and below "except , " 2016-08-31 rocky @@ -2604,7 +2644,7 @@ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, - uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling 2016-08-11 Omer Katz @@ -2673,7 +2713,7 @@ 2016-07-29 rocky * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. 2016-07-28 Daniel Bradburn @@ -2772,7 +2812,7 @@ 2016-07-27 rocky - * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: Small code clean up 2016-07-26 rocky @@ -2800,7 +2840,7 @@ test/simple_source/bug_pypy27/03_try_return.py, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules 2016-07-25 rocky @@ -2862,7 +2902,7 @@ * README.rst, test/simple_source/stmts/03_if_elif.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little 2016-07-25 rocky @@ -2884,7 +2924,7 @@ test/Makefile, test/test_pythonlib.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy 2016-07-24 Daniel Bradburn @@ -2904,19 +2944,19 @@ 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky * test/simple_source/bug27+/05_for_try_except.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: Another 2.7 'continue' detection bug 2016-07-23 rocky @@ -2965,7 +3005,7 @@ 2016-07-17 rocky - * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: Adjust test data for changed disasm output 2016-07-16 rocky @@ -2999,7 +3039,7 @@ 2016-07-14 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we understand better what to do though, we'll go with it. @@ -3070,7 +3110,7 @@ * test/simple_source/bug33/05_store_name.py, test/simple_source/comprehension/05_3x_set_comphension.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.2 & 3.3 handle STORE_NAME better 2016-07-11 rocky @@ -3125,13 +3165,13 @@ 2016-07-10 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: Bugs caused by 3.x jump_forward misclasification 2016-07-10 rocky * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification 2016-07-09 rocky @@ -3222,7 +3262,7 @@ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: Python 3 code cleanup 2016-07-08 rocky @@ -3243,7 +3283,7 @@ 2016-07-08 rocky * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: Python 2.4 generator expressions and gen_comp_body 2016-07-08 rocky @@ -3269,12 +3309,12 @@ 2016-07-08 rocky * test/simple_source/stmts/11_return_val.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: 2.5/2.6 RETURN_VALUE bug 2016-07-08 rocky - * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: 2.5/2.6 fn name clash fixes list conprehension problem 2016-07-08 rocky @@ -3316,7 +3356,7 @@ 2016-07-07 rocky - * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: <2.6 make sure jump back on loops is really "back" 2016-07-07 rocky @@ -3375,12 +3415,12 @@ * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: Another 2.6 while stmt. Clean up grammar a little 2016-07-03 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: 2.6 improper tagging of RETURN_END_IF 2016-07-02 rocky @@ -3417,7 +3457,7 @@ 2016-06-30 rocky * test/simple_source/stmts/06_for_break.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else 2016-06-30 rocky @@ -3434,7 +3474,7 @@ 2016-06-30 rocky * test/simple_source/comprehension/05_for_for.py, - uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: 2.6.9 list comprehension 2016-06-30 rocky @@ -3476,7 +3516,7 @@ 2016-06-28 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: Weird 2.6.9 list comprehension 2016-06-28 rocky @@ -3493,7 +3533,7 @@ * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: Base 2.5 off of 2.6. Some other small bugs. 2016-06-27 rocky @@ -3503,7 +3543,7 @@ 2016-06-27 rocky - * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: 2.6 list comprehensions 2016-06-27 rocky @@ -3588,7 +3628,7 @@ 2016-06-22 rocky * test/simple_source/expression/05_yield_from.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: differing ways to do "yield from" in 3.3-3.5 2016-06-22 rocky @@ -3597,7 +3637,7 @@ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option 2016-06-22 rocky @@ -3607,7 +3647,7 @@ 2016-06-22 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: More 3.2 LOAD_CONST removal More python3 custom grammar DRYing 2016-06-22 rocky @@ -3619,7 +3659,7 @@ * test/simple_source/expression/05_lambda.py, test/simple_source/expression/10_lambda.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3.2 MAKE_FUNCTION adjustment 2016-06-22 rocky @@ -3638,18 +3678,18 @@ 2016-06-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Bang on Python 3.2 decompiling. 2016-06-20 rocky * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, - uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same 2016-06-20 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: previous 2.7 class decorator bug fixed in 3.x 2016-06-20 rocky @@ -3681,7 +3721,7 @@ * test/simple_source/def/11_mkfunc_closure.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: 3.x make closure kw args handling bug 2016-06-20 rocky @@ -3718,7 +3758,7 @@ * test/simple_source/comprehension/05_set_comprehension.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: 2.7 and 3.x bug in dict comprehensions 2016-06-19 rocky @@ -3736,7 +3776,7 @@ * test/simple_source/looping/08_while_except_bug.py, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3 except clause parsing bug 2016-06-19 rocky @@ -3798,18 +3838,18 @@ * pytest/test_deparse.py, test/simple_source/comprehension/05_set_comprehension.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 2016-06-06 rocky * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: small changes 2016-06-06 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: include offset for starting listcomp 2016-06-03 rocky @@ -3831,7 +3871,7 @@ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, - uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: Limited support for Python 2.3 2016-06-03 rocky @@ -3929,7 +3969,7 @@ 2016-05-29 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: Bang again on Python 2.5 and 2.6 scanners 2016-05-29 rocky @@ -3941,7 +3981,7 @@ 2016-05-29 rocky * uncompyle6/scanners/scanner2.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. 2016-05-29 rocky @@ -3958,7 +3998,7 @@ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: DRY scanners more 2016-05-28 rocky @@ -3973,7 +4013,7 @@ * test/simple_source/comprehension/06_list_ifnot.py, test/simple_source/comprehension/10-list-ifnot.py, uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: Remove dis3. Fix in 3.x list if not comprehension 2016-05-28 rocky @@ -3984,7 +4024,7 @@ 2016-05-28 rocky * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, - uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: Remove dup 3.x opcodes 2016-05-28 rocky @@ -3994,7 +4034,7 @@ 2016-05-28 rocky * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, - uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: xdis for Python 3 opcodes 2016-05-28 rocky @@ -4096,7 +4136,7 @@ 2016-05-18 rocky * pytest/test_marsh.py, - test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: Handle marshal frozenset 2016-05-18 rocky @@ -4136,14 +4176,14 @@ 2016-05-17 rocky * pytest/test_marsh.py, - test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: Fix marshal bug in handling complex numbers 2016-05-17 rocky * Makefile, test/simple_source/def/09_class_closure.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS 2016-05-16 rocky @@ -4213,7 +4253,7 @@ * test/simple_source/expression/05_lambda.py, test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: Fix bug in Python 3 lambda expression handling Some other small cleanup changes 2016-05-15 rocky @@ -4221,7 +4261,7 @@ * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, uncompyle6/parser.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, - uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: pydisassemble disassemble without grammar mangling Some other small cleanups as well 2016-05-15 rocky @@ -4261,7 +4301,7 @@ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs 2016-05-15 rocky @@ -4333,7 +4373,7 @@ 2016-05-12 rocky * uncompyle6/scanners/scanner26.py, - uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: More small changes 2016-05-12 rocky @@ -4350,7 +4390,7 @@ * __pkginfo__.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires sparck 1.2.0) * some optimization in scanner3 @@ -4364,7 +4404,7 @@ uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Redo make_function for *, arg main(*, file='foo') and things like that now work 2016-05-11 rocky @@ -4396,7 +4436,7 @@ 2016-05-09 rocky * test/simple_source/stmts/09_whiletrue_bug.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Python 3 "while True" bug 2016-05-09 rocky @@ -4490,7 +4530,7 @@ * HISTORY.md, test/simple_source/branching/10_if_pass.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections 2016-05-08 rocky @@ -4507,7 +4547,7 @@ * test/simple_source/expression/05_yield_from.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. 2016-05-06 rocky @@ -4572,19 +4612,19 @@ 2016-05-05 rocky * test/simple_source/def/05_abc_class.py, - test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: Python 3.5 abc.py bug distilled 2016-05-05 rocky - * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: Add cross-Python-protable 3.5 dis module 2016-05-04 rocky * test/simple_source/stmts/05_with.py, uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo 2016-05-03 rocky @@ -4594,7 +4634,7 @@ 2016-05-03 rocky * uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: Don't repeat next_except_jump 2016-05-03 rocky @@ -4712,7 +4752,7 @@ * requirements.txt, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: spark -> spark_parser 2016-04-28 rocky @@ -4860,7 +4900,7 @@ 2016-01-02 rocky * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, - uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: Make ScannerXX() initialization the same on Python 2.x and 3.x 2016-01-02 rocky @@ -4954,7 +4994,7 @@ 2015-12-31 rocky * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Handle Python 3.3 > dotted class names 2015-12-30 rocky @@ -4977,7 +5017,7 @@ 2015-12-30 rocky - * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Remove accidental schmutz. Try using pattr on 3.4 to get fn names 2015-12-30 rocky @@ -5024,7 +5064,7 @@ * test/simple_source/exception/25_try_except.py, test/test_pythonlib.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, - uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: Towards Python3 getting try/except working more often. 2015-12-29 rocky @@ -5057,7 +5097,7 @@ * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, - uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: scanner3: Python 2.6 compatibility: change set initializations. Get rid of * import opcode_*: only a little of the much-needed larger cleanup Makefile: remove 3.x bytecode checking from Python 2.x for @@ -5076,7 +5116,7 @@ * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Add Python3 marshal codes and start to handle cross-version Python code object types, introducing scan.Code3 @@ -5126,7 +5166,7 @@ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY Python3 scanner code. Some cross version handling fixed. Some Python 3.2 and 3.3 deparse fixes. @@ -5142,7 +5182,7 @@ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: DRY Python3 scanner code. Some cross version handling fixed. Some Python 3.2 and 3.3 deparse fixes. @@ -5206,7 +5246,7 @@ test/simple_source/stmts/15_assert.py, test/simple_source/stmts/15_for_if.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE get jump offsets into jump attributes. Fix up 3.2 scanner paritally and use that in 3.4 for in cross version disassembly. @@ -5290,7 +5330,7 @@ * test/simple_source/simple_stmts/00_import.py, test/simple_source/simple_stmts/00_pass.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Start Python3 class(superclass) handling 2015-12-23 rocky @@ -5324,7 +5364,7 @@ uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, - uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: Allow comments in grammar rules. Start working on Python3 class (not finished). More test organization. @@ -5408,7 +5448,7 @@ test/simple_source/misc/assign.py, test/simple_source/misc/assign_none_str.py, test/simple_source/simple_stmts/00_assign.py, - uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: Start Python3 execption handling 2015-12-21 rocky @@ -5554,7 +5594,7 @@ * test/Makefile, test/simple-source/misc/assign_none.py, test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Python 3 decompilation from Python2 2015-12-20 rocky @@ -5572,7 +5612,7 @@ 2015-12-20 rocky * Makefile, README.rst, test/Makefile, test/dis-compare.py, - uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: Go over makefiles to make "make check" work. walker, deparser: use zip_longest @@ -5642,7 +5682,7 @@ test/simple-source/precedence/left.py, test/simple-source/precedence/right.py, test/simple-source/precedence/structure.py, - uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: Python 3 bytecode handles opcodes with varargs (better). Decompiling assert works. Add more of the simple tests and their compiled bytecode. @@ -5684,7 +5724,7 @@ 2015-12-18 rocky - * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: disas.py: Do better for finding/turning a .py file into a .pyc file across supported versions of Python. Add for else list comprehension test @@ -5783,7 +5823,7 @@ 2015-12-17 rocky - * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: Python 3.4 correct grammar for some looping constructs 2015-12-17 rocky @@ -5818,14 +5858,14 @@ 2015-12-16 rocky * uncompyle6/deparser.py, uncompyle6/disas.py, - uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: Add LICENSE. Add demo programs and DRY code a little 2015-12-16 rocky * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, - uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: On Python3.4 decompiling Python 3.4 instructions, use its built-in disassembler routines. In contrast to what was here, they most likely work! @@ -5882,7 +5922,7 @@ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, - uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: Split out marhsal and disassemble code and spell disassemble correctly. Fix some lint issues @@ -5967,7 +6007,7 @@ 2015-12-14 rocky - * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: + * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: uncompyle6/dparser -> uncompyle6/parser 2015-12-14 rocky @@ -6220,7 +6260,7 @@ * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, - uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: Correct MANIFEST->MANIFEST.in more lint 2015-12-13 R. Bernstein @@ -6237,7 +6277,7 @@ uncompyle6/__init__.py, uncompyle6/disas.py, uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, uncompyle6/scanner25.py, uncompyle6/scanner26.py, - uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our own disassembler. Python's will do fine @@ -6338,13 +6378,13 @@ * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, uncompyle6/scanner25.py, uncompyle6/scanner27.py, - uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: Minimal disassemble, ast compile and deparse work on Python 3. Some linting 2015-12-12 rocky - * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: + * uncompyle6/dparser.py, uncompyle6/parser.py, uncompyle6/walker.py: parser -> dparser so as not to conflict with python3's parser. 2015-12-12 rocky @@ -6363,7 +6403,7 @@ 2015-12-11 rocky - * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: python3 compatibiity and remove some flake8 warnings. 2015-12-11 rocky @@ -6441,7 +6481,7 @@ 2013-07-16 root * uncompyle2/__init__.py, uncompyle2/disas.py, - uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: marshal disassembly improvement 2013-06-20 Mysterie @@ -6526,7 +6566,7 @@ uncompyle2/opcode/opcode_27.py, uncompyle2/parser.py, uncompyle2/scanner.py, uncompyle2/scanner25.py, uncompyle2/scanner26.py, uncompyle2/scanner27.py, - uncompyle2/spark.py, uncompyle2/verify.py, uncompyle2/walker.py: + uncompyle2/spark.py, uncompyle2/verify.py, uncompyle2/walker.py: Cleaning code & patch 2012-09-22 Mysterie @@ -6631,3 +6671,4 @@ 2012-06-05 Mysterie * first commit + From c38dc61021368f11e95cef70ee77e4a43dba1598 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 9 Aug 2017 22:01:59 -0400 Subject: [PATCH 038/489] xdis "is not" is now "is-not" --- uncompyle6/semantics/consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 6570522b1..9673906e0 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -176,7 +176,7 @@ 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27)), 'conditional_lambda': ( '(%c if %c else %c)', 2, 0, 3), 'return_lambda': ('%c', 0), - 'compare': ( '%p %[-1]{pattr} %p', (0, 19), (1, 19) ), + 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), 'cmp_list': ( '%p %p', (0, 29), (1, 30)), 'cmp_list1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), 'cmp_list2': ( '%[1]{pattr} %p', (0, 19)), From 93f18e24495390c4b642c8a392ffa4cedc2e4954 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 13 Aug 2017 09:23:27 -0400 Subject: [PATCH 039/489] Allow version to be string... in get_python_parser and get_scanner --- ChangeLog | 18 ++++++++++++++++++ README.rst | 2 +- __pkginfo__.py | 2 +- pytest/test_basic.py | 11 +++++++++++ uncompyle6/parser.py | 12 ++++++++++++ uncompyle6/scanner.py | 24 ++++++++++++++++++++++++ 6 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 pytest/test_basic.py diff --git a/ChangeLog b/ChangeLog index 9ed49afb7..a8f4054df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017-08-10 rocky + + * : commit c38dc61021368f11e95cef70ee77e4a43dba1598 Author: rocky + Date: Wed Aug 9 22:01:59 2017 -0400 + +2017-08-09 rocky + + * ChangeLog: Get ready for release 2.11.3 + 2017-08-09 rocky * : commit dc627d13b8455ded4bf708a596bb466f9df9bf7b Author: rocky @@ -26,6 +35,15 @@ * __pkginfo__.py: Remove six from Python-2.4/2.5 package +2017-08-02 rocky + + * uncompyle6/scanners/scanner3.py: in xdis "exception match" is now + "exception-match" + +2017-08-02 rocky + + * __pkginfo__.py: Python 2.4 doesn't do six + 2017-08-01 rocky * pytest/validate.py, test/dis-compare.py, diff --git a/README.rst b/README.rst index 1cbeb43e0..90da8d8b4 100644 --- a/README.rst +++ b/README.rst @@ -176,7 +176,7 @@ See Also * https://github.com/rocky/python-xasm : Cross Python version assembler -.. _trepan: https://pypi.python.org/pypi/trepan +.. _trepan: https://pypi.python.org/pypi/trepan2 .. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md .. _debuggers: https://pypi.python.org/pypi/trepan3k .. _remake: https://bashdb.sf.net/remake diff --git a/__pkginfo__.py b/__pkginfo__.py index 71b2e912a..6c0154b11 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis == 3.5.1, < 3.6.0'] + 'xdis == 3.5.1'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' diff --git a/pytest/test_basic.py b/pytest/test_basic.py new file mode 100644 index 000000000..9517b5100 --- /dev/null +++ b/pytest/test_basic.py @@ -0,0 +1,11 @@ +from uncompyle6.scanner import get_scanner +from uncompyle6.parser import get_python_parser + +def test_get_scanner(): + # See that we can retrieve a scanner using a full version number + assert get_scanner('2.7.13') + + +def test_get_parser(): + # See that we can retrieve a sparser using a full version number + assert get_python_parser('2.7.13') diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index e4c6f6231..1bf1d5cee 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -12,6 +12,9 @@ from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.show import maybe_show_asm +# FIXME: put in xdis +from uncompyle6.scanner import version_str2float + class ParserError(Exception): def __init__(self, token, offset): @@ -609,7 +612,15 @@ def get_python_parser( explanation of the different modes. """ + # If version is a string, turn that into the corresponding float. + if isinstance(version, str): + version = version_str2float(version) + # FIXME: there has to be a better way... + # We could do this as a table lookup, but that would force us + # in import all of the parsers all of the time. Perhaps there is + # a lazy way of doing the import? + if version < 3.0: if version == 1.5: import uncompyle6.parsers.parse15 as parse15 @@ -762,6 +773,7 @@ def python_parser(version, co, out=sys.stdout, showasm=False, if __name__ == '__main__': def parse_test(co): from uncompyle6 import PYTHON_VERSION, IS_PYPY + ast = python_parser('2.7.13', co, showasm=True, is_pypy=True) ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY) print(ast) return diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index eb5fee45c..040c6464d 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -255,7 +255,30 @@ def setTokenClass(self, tokenClass): def parse_fn_counts(argc): return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF) + +# FIXME: put in xdis +from xdis.magics import magics +def version_str2float(version): + if version in magics: + magic = magics[version] + for v, m in list(magics.items()): + if m == magic: + try: + return float(v) + except: + pass + pass + pass + raise RuntimeError("Can't find a valid Python version for version %s" + % version) + return + def get_scanner(version, is_pypy=False, show_asm=None): + + # If version is a string, turn that into the corresponding float. + if isinstance(version, str): + version = version_str2float(version) + # Pick up appropriate scanner if version in PYTHON_VERSIONS: v_str = "%s" % (int(version * 10)) @@ -282,5 +305,6 @@ def get_scanner(version, is_pypy=False, show_asm=None): if __name__ == "__main__": import inspect, uncompyle6 co = inspect.currentframe().f_code + scanner = get_scanner('2.7.13', True) scanner = get_scanner(uncompyle6.PYTHON_VERSION, IS_PYPY, True) tokens, customize = scanner.ingest(co, {}) From a694601264654358de7aacafabc443cded361db3 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 17 Sep 2017 12:03:49 -0400 Subject: [PATCH 040/489] emgine -> template_engine --- uncompyle6/semantics/fragments.py | 8 ++++---- uncompyle6/semantics/pysource.py | 28 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index f9ffe7068..01be58867 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -1474,10 +1474,10 @@ def n_build_list(self, node): self.prec = p self.prune() - def engine(self, entry, startnode): + def template_engine(self, entry, startnode): """The format template interpetation engine. See the comment at the - beginning of this module for the how we interpret format specifications such as - %c, %C, and so on. + beginning of this module for the how we interpret format + specifications such as %c, %C, and so on. """ # print("-----") diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index f4b87c30a..ec6fe6e14 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -26,8 +26,8 @@ of the nonterminal and its children.. The rest of the below describes how table-driven semantic actions work -and gives a list of the format specifiers. The default() and engine() -methods implement most of the below. +and gives a list of the format specifiers. The default() and +template_engine() methods implement most of the below. Step 1 determines a table (T) and a path to a table key (K) from the node type (N) (other nodes are shown as O): @@ -64,8 +64,10 @@ * indicates an argument (A) required. - The '%' may optionally be followed by a number (C) in square brackets, which - makes the engine walk down to N[C] before evaluating the escape code. + The '%' may optionally be followed by a number (C) in square + brackets, which makes the template_engine walk down to N[C] before + evaluating the escape code. + """ import sys @@ -359,7 +361,8 @@ def n_async_call_function(node): node.type == 'call_function' p = self.prec self.prec = 80 - self.engine(('%c(%P)', 0, (1, -4, ', ', 100)), node) + self.template_engine(('%c(%P)', 0, + (1, -4, ', ', 100)), node) self.prec = p self.prune() self.n_async_call_function = n_async_call_function @@ -400,9 +403,11 @@ def n_funcdef(node): is_code = hasattr(code_node, 'attr') and iscode(code_node.attr) if (is_code and (code_node.attr.co_flags & COMPILER_FLAG_BIT['COROUTINE'])): - self.engine(('\n\n%|async def %c\n', -2), node) + self.template_engine(('\n\n%|async def %c\n', + -2), node) else: - self.engine(('\n\n%|def %c\n', -2), node) + self.template_engine(('\n\n%|def %c\n', -2), + node) self.prune() self.n_funcdef = n_funcdef @@ -1759,11 +1764,12 @@ def n_except_cond2(self, node): node[-2][0].type = 'unpack_w_parens' self.default(node) - def engine(self, entry, startnode): + def template_engine(self, entry, startnode): """The format template interpetation engine. See the comment at the - beginning of this module for the how we interpret format specifications such as - %c, %C, and so on. + beginning of this module for the how we interpret format + specifications such as %c, %C, and so on. """ + # self.println("----> ", startnode.type, ', ', entry[0]) fmt = entry[0] arg = 1 @@ -1866,7 +1872,7 @@ def default(self, node): pass if key.type in table: - self.engine(table[key.type], node) + self.template_engine(table[key.type], node) self.prune() def customize(self, customize): From 62ddbe320d39e0c0f49c54f80520bae1cc753e05 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Sep 2017 01:15:37 -0400 Subject: [PATCH 041/489] Start pysource unit test --- pytest/test_pysource.py | 20 ++++ uncompyle6/semantics/pysource.py | 157 ++++++++++++++++++++----------- 2 files changed, 121 insertions(+), 56 deletions(-) create mode 100644 pytest/test_pysource.py diff --git a/pytest/test_pysource.py b/pytest/test_pysource.py new file mode 100644 index 000000000..aacefdf37 --- /dev/null +++ b/pytest/test_pysource.py @@ -0,0 +1,20 @@ +from uncompyle6 import PYTHON3 +from uncompyle6.semantics.consts import ( + NONE, + # RETURN_NONE, PASS, RETURN_LOCALS +) + +if PYTHON3: + from io import StringIO +else: + from StringIO import StringIO + +from uncompyle6.semantics.pysource import SourceWalker as SourceWalker + +def test_template_engine(): + s = StringIO() + sw = SourceWalker(2.7, s, None) + sw.ast = NONE + sw.template_engine(('--%c--', 0), NONE) + print(sw.f.getvalue()) + assert sw.f.getvalue() == '--None--' diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index ec6fe6e14..29230ab46 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -11,64 +11,86 @@ Upper levels of the grammar is a more-or-less conventional grammar for Python. +""" -Semantic action rules for nonterminal symbols can be specified here by -creating a method prefaced with "n_" for that nonterminal. For -example, "n_exec_stmt" handles the semantic actions for the -"exec_smnt" nonterminal symbol. Similarly if a method with the name -of the nonterminal is suffixed with "_exit" it will be called after -all of its children are called. - -Another other way to specify a semantic rule for a nonterminal is via -rule given in one of the tables MAP_R0, MAP_R, or MAP_DIRECT. - -These uses a printf-like syntax to direct substitution from attributes -of the nonterminal and its children.. - -The rest of the below describes how table-driven semantic actions work -and gives a list of the format specifiers. The default() and -template_engine() methods implement most of the below. - - Step 1 determines a table (T) and a path to a - table key (K) from the node type (N) (other nodes are shown as O): - - N N N&K - / | ... \ / | ... \ / | ... \ - O O O O O K O O O - | - K - - MAP_R0 (TABLE_R0) MAP_R (TABLE_R) MAP_DIRECT (TABLE_DIRECT) - - The default is a direct mapping. The key K is then extracted from the - subtree and used to find a table entry T[K], if any. The result is a - format string and arguments (a la printf()) for the formatting engine. - Escapes in the format string are: - - %c evaluate children N[A] recursively* - %C evaluate children N[A[0]]..N[A[1]-1] recursively, separate by A[2]* - %P same as %C but sets operator precedence - %D same as %C but is for left-recursive lists like kwargs which - goes to epsilon at the beginning. Using %C an extra separator - with an epsilon appears at the beginning - %, print ',' if last %C only printed one item. This is mostly for tuples - on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints - other tuples. - %| tab to current indentation level - %+ increase current indentation level - %- decrease current indentation level - %{...} evaluate ... in context of N - %% literal '%' - %p evaluate N setting precedence - - - * indicates an argument (A) required. - - The '%' may optionally be followed by a number (C) in square - brackets, which makes the template_engine walk down to N[C] before - evaluating the escape code. +# The below is a bit long, but still it is somehwat abbreviated. +# See https://github.com/rocky/python-uncompyle6/wiki/Table-driven-semantic-actions. +# for a more complete explanation, nicely marked up and with examples. +# +# +# Semantic action rules for nonterminal symbols can be specified here by +# creating a method prefaced with "n_" for that nonterminal. For +# example, "n_exec_stmt" handles the semantic actions for the +# "exec_stmt" nonterminal symbol. Similarly if a method with the name +# of the nonterminal is suffixed with "_exit" it will be called after +# all of its children are called. +# +# However if this were done for all of the rules, this file would be even longer +# than it is already. +# +# Another more compact way to specify a semantic rule for a nonterminal is via +# rule given in one of the tables MAP_R0, MAP_R, or MAP_DIRECT. +# +# These uses a printf-like syntax to direct substitution from attributes +# of the nonterminal and its children.. +# +# The rest of the below describes how table-driven semantic actions work +# and gives a list of the format specifiers. The default() and +# template_engine() methods implement most of the below. +# +# Step 1 determines a table (T) and a path to a +# table key (K) from the node type (N) (other nodes are shown as O): +# +# N N N&K +# / | ... \ / | ... \ / | ... \ +# O O O O O K O O O +# | +# K +# +# MAP_R0 (TABLE_R0) MAP_R (TABLE_R) MAP_DIRECT (TABLE_DIRECT) +# +# The default is a direct mapping. The key K is then extracted from the +# subtree and used to find a table entry T[K], if any. The result is a +# format string and arguments (a la printf()) for the formatting engine. +# Escapes in the format string are: +# +# %c evaluate the node recursively. Its argument is a single +# integer representing a node index. +# %p like %c but sets the operator precedence. +# Its argument then is a tuple indicating the node +# index and the precidence value, an integer. +# +# %C evaluate children recursively, with sibling children separated by the +# given string. It needs a tuple of 3 items, a starting node, the maximimum +# value of an end node, and a string to be inserted between sibling children +# +# %, Append ',' if last %C only printed one item. This is mostly for tuples +# on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints +# other tuples. The specifier takes no arguments +# +# %P same as %C but sets operator precedence. +# +# %D Same as `%C` this is for left-recursive lists like kwargs where +# goes to epsilon at the beginning. If we were to use `%C` an extra separator +# with an epsilon would appear at the beginning. +# +# %| Insert spaces to the current indentation level. Takes no arguments. +# +# %+ increase current indentation level. Takes no arguments. +# +# %- decrease current indentation level. Takes no arguments. +# +# %{...} evaluate ... in context of N +# +# %% literal '%'. Takes no arguments. +# +# +# The '%' may optionally be followed by a number (C) in square +# brackets, which makes the template_engine walk down to N[C] before +# evaluating the escape code. + +from __future__ import print_function -""" import sys from uncompyle6 import PYTHON3 @@ -124,6 +146,29 @@ def __init__(self, version, out, scanner, showast=False, debug_parser=PARSER_DEFAULT_DEBUG, compile_mode='exec', is_pypy=False, linestarts={}): + """version is the Python version (a float) of the Python dialect + + of both the AST and language we should produce. + + out is IO-like file pointer to where the output should go. It + whould have a getvalue() method. + + scanner is a method to call when we need to scan tokens. Sometimes + in producing output we will run across further tokens that need + to be scaned. + + If showast is True, we print the AST tree. + + compile_mode is is either 'exec' or 'single'. It isthe compile + mode that was used to create the AST and specifies a gramar variant within + a Python version to use. + + is_pypy should be True if the AST was generated for PyPy. + + linestarts is a dictionary of line number to bytecode offset. This + can sometimes assist in determinte which kind of source-code construct + to use when there is ambiguity. + """ GenericASTTraversal.__init__(self, ast=None) self.scanner = scanner params = { From 7725b8e7de924ccdcbb4b247a5db83c76c05799e Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Sep 2017 11:30:50 -0400 Subject: [PATCH 042/489] small fixes... test_pythonlib.py: it is sys.exit not exit pysource.py: restore node type on async_call function --- test/test_pythonlib.py | 6 +++--- uncompyle6/semantics/pysource.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 469139388..a3cdae7a6 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -169,13 +169,13 @@ def file_matches(files, root, basenames, patterns): main(src_dir, target_dir, files, [], do_verify=opts['do_verify']) if failed_files != 0: - exit(2) + sys.exit(2) elif failed_verify != 0: - exit(3) + sys.exit(3) except (KeyboardInterrupt, OSError): print() - exit(1) + sys.exit(1) if test_opts['rmtree']: parent_dir = os.path.dirname(target_dir) print("Everything good, removing %s" % parent_dir) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 29230ab46..c2037f973 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -409,6 +409,7 @@ def n_async_call_function(node): self.template_engine(('%c(%P)', 0, (1, -4, ', ', 100)), node) self.prec = p + node.type == 'async_call_function' self.prune() self.n_async_call_function = n_async_call_function self.n_build_list_unpack = self.n_build_list From ce88a72ea1d05ebd0a7d866afeff8a0d1319ada0 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Sep 2017 17:52:48 -0400 Subject: [PATCH 043/489] Tidy/regularize table entry formatting --- uncompyle6/semantics/consts.py | 209 ++++++++++++++++----------------- 1 file changed, 104 insertions(+), 105 deletions(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 9673906e0..a21945950 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -1,5 +1,5 @@ # Copyright (c) 2017 by Rocky Bernstein -"""Constants used in pysource.py""" +"""Constants and initial table values used in pysource.py and fragments.py""" import re, sys from uncompyle6.parsers.astnode import AST @@ -57,9 +57,7 @@ TABLE_R = { 'STORE_ATTR': ( '%c.%[1]{pattr}', 0), -# 'STORE_SUBSCR': ( '%c[%c]', 0, 1 ), 'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ), -# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ), } TABLE_R0 = { @@ -67,8 +65,9 @@ # 'BUILD_TUPLE': ( '(%C)', (0,-1,', ') ), # 'CALL_FUNCTION': ( '%c(%P)', 0, (1,-1,', ') ), } + TABLE_DIRECT = { - 'BINARY_ADD': ( '+' ,), + 'BINARY_ADD': ( '+' ,), 'BINARY_SUBTRACT': ( '-' ,), 'BINARY_MULTIPLY': ( '*' ,), 'BINARY_DIVIDE': ( '/' ,), @@ -76,13 +75,13 @@ 'BINARY_TRUE_DIVIDE': ( '/' ,), # Not in <= 2.1 'BINARY_FLOOR_DIVIDE': ( '//' ,), 'BINARY_MODULO': ( '%%',), - 'BINARY_POWER': ( '**',), + 'BINARY_POWER': ( '**',), 'BINARY_LSHIFT': ( '<<',), 'BINARY_RSHIFT': ( '>>',), - 'BINARY_AND': ( '&' ,), - 'BINARY_OR': ( '|' ,), - 'BINARY_XOR': ( '^' ,), - 'INPLACE_ADD': ( '+=' ,), + 'BINARY_AND': ( '&' ,), + 'BINARY_OR': ( '|' ,), + 'BINARY_XOR': ( '^' ,), + 'INPLACE_ADD': ( '+=' ,), 'INPLACE_SUBTRACT': ( '-=' ,), 'INPLACE_MULTIPLY': ( '*=' ,), 'INPLACE_MATRIX_MULTIPLY': ( '@=' ,), @@ -93,125 +92,125 @@ 'INPLACE_POWER': ( '**=',), 'INPLACE_LSHIFT': ( '<<=',), 'INPLACE_RSHIFT': ( '>>=',), - 'INPLACE_AND': ( '&=' ,), - 'INPLACE_OR': ( '|=' ,), - 'INPLACE_XOR': ( '^=' ,), - 'binary_expr': ( '%c %c %c', 0, -1, 1 ), + 'INPLACE_AND': ( '&=' ,), + 'INPLACE_OR': ( '|=' ,), + 'INPLACE_XOR': ( '^=' ,), + 'binary_expr': ( '%c %c %c', 0, -1, 1 ), 'UNARY_POSITIVE': ( '+',), 'UNARY_NEGATIVE': ( '-',), - 'UNARY_INVERT': ( '~%c'), - 'unary_expr': ( '%c%c', 1, 0), + 'UNARY_INVERT': ( '~%c'), + 'unary_expr': ( '%c%c', 1, 0), - 'unary_not': ( 'not %c', 0 ), + 'unary_not': ( 'not %c', 0 ), 'unary_convert': ( '`%c`', 0 ), - 'get_iter': ( 'iter(%c)', 0 ), - 'slice0': ( '%c[:]', 0 ), - 'slice1': ( '%c[%p:]', 0, (1, 100) ), - 'slice2': ( '%c[:%p]', 0, (1, 100) ), - 'slice3': ( '%c[%p:%p]', 0, (1, 100), (2, 100) ), - - 'IMPORT_FROM': ( '%{pattr}', ), - 'load_attr': ( '%c.%[1]{pattr}', 0), - 'LOAD_FAST': ( '%{pattr}', ), - 'LOAD_NAME': ( '%{pattr}', ), + 'get_iter': ( 'iter(%c)', 0 ), + 'slice0': ( '%c[:]', 0 ), + 'slice1': ( '%c[%p:]', 0, (1, 100) ), + 'slice2': ( '%c[:%p]', 0, (1, 100) ), + 'slice3': ( '%c[%p:%p]', 0, (1, 100), (2, 100) ), + + 'IMPORT_FROM': ( '%{pattr}', ), + 'load_attr': ( '%c.%[1]{pattr}', 0), + 'LOAD_FAST': ( '%{pattr}', ), + 'LOAD_NAME': ( '%{pattr}', ), 'LOAD_CLASSNAME': ( '%{pattr}', ), - 'LOAD_GLOBAL': ( '%{pattr}', ), - 'LOAD_DEREF': ( '%{pattr}', ), - 'LOAD_LOCALS': ( 'locals()', ), - 'LOAD_ASSERT': ( '%{pattr}', ), + 'LOAD_GLOBAL': ( '%{pattr}', ), + 'LOAD_DEREF': ( '%{pattr}', ), + 'LOAD_LOCALS': ( 'locals()', ), + 'LOAD_ASSERT': ( '%{pattr}', ), # 'LOAD_CONST': ( '%{pattr}', ), # handled by n_LOAD_CONST - 'DELETE_FAST': ( '%|del %{pattr}\n', ), - 'DELETE_NAME': ( '%|del %{pattr}\n', ), + 'DELETE_FAST': ( '%|del %{pattr}\n', ), + 'DELETE_NAME': ( '%|del %{pattr}\n', ), 'DELETE_GLOBAL': ( '%|del %{pattr}\n', ), 'delete_subscr': ( '%|del %c[%c]\n', 0, 1,), 'binary_subscr': ( '%c[%p]', 0, (1, 100)), 'binary_subscr2': ( '%c[%p]', 0, (1, 100)), - 'store_subscr': ( '%c[%c]', 0, 1), - 'STORE_FAST': ( '%{pattr}', ), - 'STORE_NAME': ( '%{pattr}', ), - 'STORE_GLOBAL': ( '%{pattr}', ), - 'STORE_DEREF': ( '%{pattr}', ), - 'unpack': ( '%C%,', (1, maxint, ', ') ), + 'store_subscr': ( '%c[%c]', 0, 1), + 'STORE_FAST': ( '%{pattr}', ), + 'STORE_NAME': ( '%{pattr}', ), + 'STORE_GLOBAL': ( '%{pattr}', ), + 'STORE_DEREF': ( '%{pattr}', ), + 'unpack': ( '%C%,', (1, maxint, ', ') ), # This nonterminal we create on the fly in semantic routines 'unpack_w_parens': ( '(%C%,)', (1, maxint, ', ') ), - 'unpack_list': ( '[%C]', (1, maxint, ', ') ), - 'build_tuple2': ( '%P', (0, -1, ', ', 100) ), + 'unpack_list': ( '[%C]', (1, maxint, ', ') ), + 'build_tuple2': ( '%P', (0, -1, ', ', 100) ), # 'list_compr': ( '[ %c ]', -2), # handled by n_list_compr - 'list_iter': ( '%c', 0), - 'list_for': ( ' for %c in %c%c', 2, 0, 3 ), - 'list_if': ( ' if %c%c', 0, 2 ), + 'list_iter': ( '%c', 0 ), + 'list_for': ( ' for %c in %c%c', 2, 0, 3 ), + 'list_if': ( ' if %c%c', 0, 2 ), 'list_if_not': ( ' if not %p%c', (0, 22), 2 ), - 'lc_body': ( '', ), # ignore when recusing + 'lc_body': ( '', ), # ignore when recusing - 'comp_iter': ( '%c', 0), - 'comp_if': ( ' if %c%c', 0, 2 ), - 'comp_ifnot': ( ' if not %p%c', (0, 22), 2 ), - 'comp_body': ( '', ), # ignore when recusing + 'comp_iter': ( '%c', 0 ), + 'comp_if': ( ' if %c%c', 0, 2 ), + 'comp_ifnot': ( ' if not %p%c', (0, 22), 2 ), + 'comp_body': ( '', ), # ignore when recusing 'set_comp_body': ( '%c', 0 ), 'gen_comp_body': ( '%c', 0 ), 'dict_comp_body': ( '%c:%c', 1, 0 ), - 'assign': ( '%|%c = %p\n', -1, (0, 200) ), + 'assign': ( '%|%c = %p\n', -1, (0, 200) ), # The 2nd parameter should have a = suffix. # There is a rule with a 4th parameter "designator" # which we don't use here. - 'augassign1': ( '%|%c %c %c\n', 0, 2, 1), + 'augassign1': ( '%|%c %c %c\n', 0, 2, 1), - 'augassign2': ( '%|%c.%[2]{pattr} %c %c\n', 0, -3, -4), - 'designList': ( '%c = %c', 0, -1 ), + 'augassign2': ( '%|%c.%[2]{pattr} %c %c\n', 0, -3, -4 ), + 'designList': ( '%c = %c', 0, -1 ), 'and': ( '%c and %c', 0, 2 ), 'ret_and': ( '%c and %c', 0, 2 ), 'and2': ( '%c', 3 ), 'or': ( '%c or %c', 0, 2 ), - 'ret_or': ( '%c or %c', 0, 2 ), - 'conditional': ( '%p if %p else %p', (2, 27), (0, 27), (4, 27)), - 'conditionalTrue': ( '%p if 1 else %p', (0, 27), (2, 27)), - 'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27)), - 'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27)), - 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27)), + 'ret_or': ( '%c or %c', 0, 2 ), + 'conditional': ( '%p if %p else %p', (2, 27), (0, 27), (4, 27) ), + 'conditionalTrue': ( '%p if 1 else %p', (0, 27), (2, 27) ), + 'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27) ), + 'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27) ), + 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27) ), 'conditional_lambda': ( '(%c if %c else %c)', 2, 0, 3), 'return_lambda': ('%c', 0), - 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), - 'cmp_list': ( '%p %p', (0, 29), (1, 30)), - 'cmp_list1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), - 'cmp_list2': ( '%[1]{pattr} %p', (0, 19)), + 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), + 'cmp_list': ( '%p %p', (0, 29), (1, 30)), + 'cmp_list1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), + 'cmp_list2': ( '%[1]{pattr} %p', (0, 19)), # 'classdef': (), # handled by n_classdef() - 'funcdef': ( '\n\n%|def %c\n', -2), # -2 to handle closures + 'funcdef': ( '\n\n%|def %c\n', -2), # -2 to handle closures 'funcdefdeco': ( '\n\n%c', 0), - 'mkfuncdeco': ( '%|@%c\n%c', 0, 1), + 'mkfuncdeco': ( '%|@%c\n%c', 0, 1), 'mkfuncdeco0': ( '%|def %c\n', 0), 'classdefdeco': ( '\n\n%c', 0), 'classdefdeco1': ( '%|@%c\n%c', 0, 1), - 'kwarg': ( '%[0]{pattr}=%c', 1), - 'kwargs': ( '%D', (0, maxint, ', ') ), - - 'assert_expr_or': ( '%c or %c', 0, 2 ), - 'assert_expr_and': ( '%c and %c', 0, 2 ), - 'print_items_stmt': ( '%|print %c%c,\n', 0, 2), # Python 2 only - 'print_items_nl_stmt': ( '%|print %c%c\n', 0, 2), - 'print_item': ( ', %c', 0), - 'print_nl': ( '%|print\n', ), - 'print_to': ( '%|print >> %c, %c,\n', 0, 1 ), - 'print_to_nl': ( '%|print >> %c, %c\n', 0, 1 ), - 'print_nl_to': ( '%|print >> %c\n', 0 ), + 'kwarg': ( '%[0]{pattr}=%c', 1), + 'kwargs': ( '%D', (0, maxint, ', ') ), + + 'assert_expr_or': ( '%c or %c', 0, 2 ), + 'assert_expr_and': ( '%c and %c', 0, 2 ), + 'print_items_stmt': ( '%|print %c%c,\n', 0, 2 ), # Python 2 only + 'print_items_nl_stmt': ( '%|print %c%c\n', 0, 2 ), + 'print_item': ( ', %c', 0), + 'print_nl': ( '%|print\n', ), + 'print_to': ( '%|print >> %c, %c,\n', 0, 1 ), + 'print_to_nl': ( '%|print >> %c, %c\n', 0, 1 ), + 'print_nl_to': ( '%|print >> %c\n', 0 ), 'print_to_items': ( '%C', (0, 2, ', ') ), - 'call_stmt': ( '%|%p\n', (0, 200)), - 'break_stmt': ( '%|break\n', ), + 'call_stmt': ( '%|%p\n', (0, 200)), + 'break_stmt': ( '%|break\n', ), 'continue_stmt': ( '%|continue\n', ), - 'raise_stmt0': ( '%|raise\n', ), - 'raise_stmt1': ( '%|raise %c\n', 0), - 'raise_stmt3': ( '%|raise %c, %c, %c\n', 0, 1, 2), + 'raise_stmt0': ( '%|raise\n', ), + 'raise_stmt1': ( '%|raise %c\n', 0), + 'raise_stmt3': ( '%|raise %c, %c, %c\n', 0, 1, 2), # 'yield': ( 'yield %c', 0), # 'return_stmt': ( '%|return %c\n', 0), - 'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ), + 'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmtl': ( '%|if %c:\n%+%c%-', 0, 1 ), 'testtrue': ( 'not %p', (0, 22) ), @@ -229,37 +228,37 @@ 'elifelsestmtr2': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 3 ), # has COME_FROM 'whileTruestmt': ( '%|while True:\n%+%c%-\n\n', 1 ), - 'whilestmt': ( '%|while %c:\n%+%c%-\n\n', 1, 2 ), - 'while1stmt': ( '%|while 1:\n%+%c%-\n\n', 1 ), - 'while1elsestmt': ( '%|while 1:\n%+%c%-%|else:\n%+%c%-\n\n', 1, -2 ), + 'whilestmt': ( '%|while %c:\n%+%c%-\n\n', 1, 2 ), + 'while1stmt': ( '%|while 1:\n%+%c%-\n\n', 1 ), + 'while1elsestmt': ( '%|while 1:\n%+%c%-%|else:\n%+%c%-\n\n', 1, -2 ), 'whileelsestmt': ( '%|while %c:\n%+%c%-%|else:\n%+%c%-\n\n', 1, 2, -2 ), 'whileelselaststmt': ( '%|while %c:\n%+%c%-%|else:\n%+%c%-', 1, 2, -2 ), - 'forstmt': ( '%|for %c in %c:\n%+%c%-\n\n', 3, 1, 4 ), - 'forelsestmt': ( - '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, 1, 4, -2), + 'forstmt': ( '%|for %c in %c:\n%+%c%-\n\n', 3, 1, 4 ), + 'forelsestmt': ( + '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, 1, 4, -2 ), 'forelselaststmt': ( - '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-', 3, 1, 4, -2), + '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-', 3, 1, 4, -2 ), 'forelselaststmtl': ( - '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, 1, 4, -2), - 'trystmt': ( '%|try:\n%+%c%-%c\n\n', 1, 3 ), - 'tryelsestmt': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-\n\n', 1, 3, 4 ), - 'tryelsestmtc': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-', 1, 3, 4 ), - 'tryelsestmtl': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-', 1, 3, 4 ), - 'tf_trystmt': ( '%c%-%c%+', 1, 3 ), + '%|for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, 1, 4, -2 ), + 'trystmt': ( '%|try:\n%+%c%-%c\n\n', 1, 3 ), + 'tryelsestmt': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-\n\n', 1, 3, 4 ), + 'tryelsestmtc': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-', 1, 3, 4 ), + 'tryelsestmtl': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-', 1, 3, 4 ), + 'tf_trystmt': ( '%c%-%c%+', 1, 3 ), 'tf_tryelsestmt': ( '%c%-%c%|else:\n%+%c', 1, 3, 4 ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ), 'except': ( '%|except:\n%+%c%-', 3 ), - 'except_cond1': ( '%|except %c:\n', 1 ), + 'except_cond1': ( '%|except %c:\n', 1 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), 'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ), - 'passstmt': ( '%|pass\n', ), - 'STORE_FAST': ( '%{pattr}', ), - 'kv': ( '%c: %c', 3, 1 ), - 'kv2': ( '%c: %c', 1, 2 ), - 'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ), - 'importstmt': ( '%|import %c\n', 2), - 'importfrom': ( '%|from %[2]{pattr} import %c\n', 3 ), - 'importstar': ( '%|from %[2]{pattr} import *\n', ), + 'passstmt': ( '%|pass\n', ), + 'STORE_FAST': ( '%{pattr}', ), + 'kv': ( '%c: %c', 3, 1 ), + 'kv2': ( '%c: %c', 1, 2 ), + 'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ), + 'importstmt': ( '%|import %c\n', 2), + 'importfrom': ( '%|from %[2]{pattr} import %c\n', 3 ), + 'importstar': ( '%|from %[2]{pattr} import *\n', ), } @@ -276,7 +275,7 @@ } # Operator precidence -# See https://docs.python.org/3/reference/expressions.html +# See https://docs.python.org/2/reference/expressions.html # or https://docs.python.org/3/reference/expressions.html # for a list. PRECEDENCE = { From 1e858efafd44155ad0ef82fc1b79a5d740c07832 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Sep 2017 19:08:41 -0400 Subject: [PATCH 044/489] Tidy pysource and fragments --- uncompyle6/semantics/fragments.py | 42 +++++++++++++-------------- uncompyle6/semantics/pysource.py | 48 +++++++++++++++---------------- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 01be58867..c2da61b4f 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -8,8 +8,8 @@ and indexes fragments which can be accessed by instruction offset address. -See the comments in pysource for information on the abstract sytax tree -and how semantic actions are written. +See https://github.com/rocky/python-uncompyle6/wiki/Table-driven-semantic-actions. +for a more complete explanation, nicely marked up and with examples. We add some format specifiers here not used in pysource @@ -424,10 +424,10 @@ def n_ifelsestmtr(self, node): self.write(self.indent, 'if ') self.preorder(node[0]) self.println(':') - self.indentMore() + self.indent_more() node[1].parent = node self.preorder(node[1]) - self.indentLess() + self.indent_less() if_ret_at_end = False if len(node[2][0]) >= 3: @@ -446,17 +446,17 @@ def n_ifelsestmtr(self, node): prev_stmt_is_if_ret = False if not past_else and not if_ret_at_end: self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() past_else = True n.parent = node self.preorder(n) if not past_else or if_ret_at_end: self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() node[2][1].parent = node self.preorder(node[2][1]) self.set_pos_info(node, start, len(self.f.getvalue())) - self.indentLess() + self.indent_less() self.prune() def n_elifelsestmtr(self, node): @@ -473,20 +473,20 @@ def n_elifelsestmtr(self, node): node[0].parent = node self.preorder(node[0]) self.println(':') - self.indentMore() + self.indent_more() node[1].parent = node self.preorder(node[1]) - self.indentLess() + self.indent_less() for n in node[2][0]: n[0].type = 'elifstmt' n.parent = node self.preorder(n) self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() node[2][1].parent = node self.preorder(node[2][1]) - self.indentLess() + self.indent_less() self.set_pos_info(node, start, len(self.f.getvalue())) self.prune() @@ -530,7 +530,7 @@ def n_mkfunc(self, node): self.write(func_name) self.set_pos_info(code_node, start, len(self.f.getvalue())) - self.indentMore() + self.indent_more() start = len(self.f.getvalue()) self.make_function(node, isLambda=False, codeNode=code_node) @@ -540,7 +540,7 @@ def n_mkfunc(self, node): self.write('\n\n') else: self.write('\n\n\n') - self.indentLess() + self.indent_less() self.prune() # stop recursing def n_list_compr(self, node): @@ -989,9 +989,9 @@ def n_classdef(self, node): self.println(':') # class body - self.indentMore() + self.indent_more() self.build_class(subclass) - self.indentLess() + self.indent_less() self.currentclass = cclass self.set_pos_info(node, start, len(self.f.getvalue())) @@ -1332,7 +1332,7 @@ def n_mapexpr(self, node): p = self.prec self.prec = 100 - self.indentMore(INDENT_PER_LEVEL) + self.indent_more(INDENT_PER_LEVEL) line_seperator = ',\n' + self.indent sep = INDENT_PER_LEVEL[:-1] start = len(self.f.getvalue()) @@ -1409,7 +1409,7 @@ def n_mapexpr(self, node): n.parent = node self.set_pos_info(n, start, finish) self.set_pos_info(node, start, finish) - self.indentLess(INDENT_PER_LEVEL) + self.indent_less(INDENT_PER_LEVEL) self.prec = p self.prune() @@ -1445,7 +1445,7 @@ def n_build_list(self, node): else: flat_elems.append(elem) - self.indentMore(INDENT_PER_LEVEL) + self.indent_more(INDENT_PER_LEVEL) if len(node) > 3: line_separator = ',\n' + self.indent else: @@ -1470,7 +1470,7 @@ def n_build_list(self, node): n.parent = node.parent self.set_pos_info(n, start, finish) self.set_pos_info(node, start, finish) - self.indentLess(INDENT_PER_LEVEL) + self.indent_less(INDENT_PER_LEVEL) self.prec = p self.prune() @@ -1514,8 +1514,8 @@ def template_engine(self, entry, startnode): self.write('%') self.set_pos_info(node, start, len(self.f.getvalue())) - elif typ == '+': self.indentMore() - elif typ == '-': self.indentLess() + elif typ == '+': self.indent_more() + elif typ == '-': self.indent_less() elif typ == '|': self.write(self.indent) # no longer used, since BUILD_TUPLE_n is pretty printed: elif typ == 'r': recurse_node = True diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index c2037f973..3b21ff7c4 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -89,8 +89,6 @@ # brackets, which makes the template_engine walk down to N[C] before # evaluating the escape code. -from __future__ import print_function - import sys from uncompyle6 import PYTHON3 @@ -351,7 +349,7 @@ def n_mkfunc_annotate(node): # MAKE_FUNCTION .. code = node[-3] - self.indentMore() + self.indent_more() for annotate_last in range(len(node)-1, -1, -1): if node[annotate_last] == 'annotate_tuple': break @@ -371,7 +369,7 @@ def n_mkfunc_annotate(node): self.write('\n\n') else: self.write('\n\n\n') - self.indentLess() + self.indent_less() self.prune() # stop recursing self.n_mkfunc_annotate = n_mkfunc_annotate @@ -551,10 +549,10 @@ def preorder(self, node=None): super(SourceWalker, self).preorder(node) self.set_pos_info(node) - def indentMore(self, indent=TAB): + def indent_more(self, indent=TAB): self.indent += indent - def indentLess(self, indent=TAB): + def indent_less(self, indent=TAB): self.indent = self.indent[:-len(indent)] def traverse(self, node, indent=None, isLambda=False): @@ -872,9 +870,9 @@ def n_ifelsestmtr(self, node): self.write(self.indent, 'if ') self.preorder(node[0]) self.println(':') - self.indentMore() + self.indent_more() self.preorder(node[1]) - self.indentLess() + self.indent_less() if_ret_at_end = False if len(return_stmts_node[0]) >= 3: @@ -893,14 +891,14 @@ def n_ifelsestmtr(self, node): prev_stmt_is_if_ret = False if not past_else and not if_ret_at_end: self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() past_else = True self.preorder(n) if not past_else or if_ret_at_end: self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() self.preorder(return_stmts_node[1]) - self.indentLess() + self.indent_less() self.prune() n_ifelsestmtr2 = n_ifelsestmtr @@ -922,17 +920,17 @@ def n_elifelsestmtr(self, node): self.write(self.indent, 'elif ') self.preorder(node[0]) self.println(':') - self.indentMore() + self.indent_more() self.preorder(node[1]) - self.indentLess() + self.indent_less() for n in return_stmts_node[0]: n[0].type = 'elifstmt' self.preorder(n) self.println(self.indent, 'else:') - self.indentMore() + self.indent_more() self.preorder(return_stmts_node[1]) - self.indentLess() + self.indent_less() self.prune() def n_import_as(self, node): @@ -973,14 +971,14 @@ def n_mkfunc(self, node): func_name = code_node.attr.co_name self.write(func_name) - self.indentMore() + self.indent_more() self.make_function(node, isLambda=False, codeNode=code_node) if len(self.param_stack) > 1: self.write('\n\n') else: self.write('\n\n\n') - self.indentLess() + self.indent_less() self.prune() # stop recursing def make_function(self, node, isLambda, nested=1, @@ -1472,9 +1470,9 @@ def n_classdef(self, node): self.println(':') # class body - self.indentMore() + self.indent_more() self.build_class(subclass_code) - self.indentLess() + self.indent_less() self.currentclass = cclass if len(self.param_stack) > 1: @@ -1545,7 +1543,7 @@ def n_mapexpr(self, node): p = self.prec self.prec = 100 - self.indentMore(INDENT_PER_LEVEL) + self.indent_more(INDENT_PER_LEVEL) sep = INDENT_PER_LEVEL[:-1] self.write('{') line_number = self.line_number @@ -1683,7 +1681,7 @@ def n_mapexpr(self, node): if sep.startswith(",\n"): self.write(sep[1:]) self.write('}') - self.indentLess(INDENT_PER_LEVEL) + self.indent_less(INDENT_PER_LEVEL) self.prec = p self.prune() @@ -1734,7 +1732,7 @@ def n_build_list(self, node): else: flat_elems.append(elem) - self.indentMore(INDENT_PER_LEVEL) + self.indent_more(INDENT_PER_LEVEL) sep = '' for elem in flat_elems: @@ -1759,7 +1757,7 @@ def n_build_list(self, node): if lastnode.attr == 1 and lastnodetype.startswith('BUILD_TUPLE'): self.write(',') self.write(endchar) - self.indentLess(INDENT_PER_LEVEL) + self.indent_less(INDENT_PER_LEVEL) self.prec = p self.prune() @@ -1834,10 +1832,10 @@ def template_engine(self, entry, startnode): if typ == '%': self.write('%') elif typ == '+': self.line_number += 1 - self.indentMore() + self.indent_more() elif typ == '-': self.line_number += 1 - self.indentLess() + self.indent_less() elif typ == '|': self.line_number += 1 self.write(self.indent) From 3447ca0767dcb76d017cc5849c092417ed4e6b1c Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Sep 2017 11:29:17 -0400 Subject: [PATCH 045/489] Unit test for format-specifiers --- pytest/test_pysource.py | 142 +++++++++++++++++++++++++++++- uncompyle6/semantics/consts.py | 2 +- uncompyle6/semantics/fragments.py | 5 +- uncompyle6/semantics/pysource.py | 16 ++-- 4 files changed, 155 insertions(+), 10 deletions(-) diff --git a/pytest/test_pysource.py b/pytest/test_pysource.py index aacefdf37..d7f4e776a 100644 --- a/pytest/test_pysource.py +++ b/pytest/test_pysource.py @@ -1,6 +1,6 @@ from uncompyle6 import PYTHON3 from uncompyle6.semantics.consts import ( - NONE, + escape, NONE, # RETURN_NONE, PASS, RETURN_LOCALS ) @@ -18,3 +18,143 @@ def test_template_engine(): sw.template_engine(('--%c--', 0), NONE) print(sw.f.getvalue()) assert sw.f.getvalue() == '--None--' + # FIXME: and so on... + +from uncompyle6.semantics.consts import ( + TABLE_R, TABLE_DIRECT, + ) + +from uncompyle6.semantics.fragments import ( + TABLE_DIRECT_FRAGMENT, + ) + +def test_tables(): + for t, name, fragment in ( + (TABLE_DIRECT, 'TABLE_DIRECT', False), + (TABLE_R, 'TABLE_R', False), + (TABLE_DIRECT_FRAGMENT, 'TABLE_DIRECT_FRAGMENT', True)): + for k, entry in t.iteritems(): + fmt = entry[0] + arg = 1 + i = 0 + m = escape.search(fmt) + print("%s[%s]" % (name, k)) + while m: + i = m.end() + typ = m.group('type') or '{' + if typ in frozenset(['%', '+', '-', '|', ',', '{']): + # No args + pass + elif typ in frozenset(['c', 'p', 'P', 'C', 'D']): + # One arg - should be int or tuple of int + if typ == 'c': + assert isinstance(entry[arg], int), ( + "%s[%s][%d] type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + elif typ in frozenset(['C', 'D']): + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 3 + for j, x in enumerate(tup[:-1]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[-1], str) or tup[-1] is None, ( + "%s[%s][%d][%d] sep type %s is %s should be an string but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, tup[-1], type(x), entry) + ) + + elif typ == 'P': + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 4 + for j, x in enumerate(tup[:-2]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[-2], str), ( + "%s[%s][%d][%d] sep type %s is '%s' should be an string but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[1], int), ( + "%s[%s][%d][%d] prec type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + + else: + # Should be a tuple which contains only ints + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 2 + for j, x in enumerate(tup): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type '%s' is '%s should be an int but is %s. Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + pass + arg += 1 + elif typ in frozenset(['r']) and fragment: + pass + elif typ == 'b' and fragment: + assert isinstance(entry[arg], int), ( + "%s[%s][%d] type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + arg += 1 + elif typ == 'x' and fragment: + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 2 + assert isinstance(tup[0], int), ( + "%s[%s][%d] source type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert isinstance(tup[1], tuple), ( + "%s[%s][%d] dest type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + for j, x in enumerate(tup[1]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is %s should be an int but is %s. Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + arg += 1 + pass + else: + assert False, ( + "%s[%s][%d] type %s is not known. Full entry: %s" % + (name, k, arg, typ, entry) + ) + m = escape.search(fmt, i) + pass + assert arg == len(entry), ( + "%s[%s] arg %d should be length of entry %d. Full entry: %s" % + (name, k, arg, len(entry), entry)) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index a21945950..b5d496445 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -99,7 +99,7 @@ 'UNARY_POSITIVE': ( '+',), 'UNARY_NEGATIVE': ( '-',), - 'UNARY_INVERT': ( '~%c'), + 'UNARY_INVERT': ( '~'), 'unary_expr': ( '%c%c', 1, 0), 'unary_not': ( 'not %c', 0 ), diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index c2da61b4f..5fc880e4e 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -40,7 +40,8 @@ 2. %b ----- - %b associates the text from the previous start node up to what we have now + %b associates the text from the specified index to what we have now. + it takes an integer argument. For example in: 'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ), @@ -98,7 +99,7 @@ 'list_for': (' for %c%x in %c%c', 2, (2, (1, )), 0, 3 ), 'forstmt': ( '%|for%b %c%x in %c:\n%+%c%-\n\n', 0, 3, (3, (2, )), 1, 4 ), 'forelsestmt': ( - '%|for %c in %c%x:\n%+%c%-%|else:\n%+%c%-\n\n', 3, (3, (2,)), 1, 4, -2), + '%|for %c%x in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, (3, (2,)), 1, 4, -2), 'forelselaststmt': ( '%|for %c%x in %c:\n%+%c%-%|else:\n%+%c%-', 3, (3, (2,)), 1, 4, -2), 'forelselaststmtl': ( diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 3b21ff7c4..61aff5900 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -61,18 +61,22 @@ # index and the precidence value, an integer. # # %C evaluate children recursively, with sibling children separated by the -# given string. It needs a tuple of 3 items, a starting node, the maximimum +# given string. It needs a 3-tuple: a starting node, the maximimum # value of an end node, and a string to be inserted between sibling children # # %, Append ',' if last %C only printed one item. This is mostly for tuples # on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints # other tuples. The specifier takes no arguments # -# %P same as %C but sets operator precedence. +# %P same as %C but sets operator precedence. Its argument is a 4-tuple: +# the node low and high indices, the separator, a string the precidence +# value, an integer. # -# %D Same as `%C` this is for left-recursive lists like kwargs where -# goes to epsilon at the beginning. If we were to use `%C` an extra separator -# with an epsilon would appear at the beginning. +# %D Same as `%C` this is for left-recursive lists like kwargs where goes +# to epsilon at the beginning. It needs a 3-tuple: a starting node, the +# maximimum value of an end node, and a string to be inserted between +# sibling children. If we were to use `%C` an extra separator with an +# epsilon would appear at the beginning. # # %| Insert spaces to the current indentation level. Takes no arguments. # @@ -1940,7 +1944,7 @@ def customize(self, customize): 'CALL_FUNCTION_VAR_KW', 'CALL_FUNCTION_KW'): if v == 0: str = '%c(%C' # '%C' is a dummy here ... - p2 = (0, 0, None) # .. because of this + p2 = (0, 0, None) # .. because of the None in this else: str = '%c(%C, ' p2 = (1, -2, ', ') From 0654aed6c823d0bb20abdc866481ca5950db72f7 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Sep 2017 11:29:17 -0400 Subject: [PATCH 046/489] Get ready for release 2.12.0 --- NEWS | 11 +++ pytest/test_pysource.py | 142 +++++++++++++++++++++++++++++- uncompyle6/scanner.py | 5 +- uncompyle6/scanners/pypy27.py | 6 +- uncompyle6/scanners/pypy35.py | 4 +- uncompyle6/scanners/scanner15.py | 2 +- uncompyle6/scanners/scanner21.py | 4 +- uncompyle6/scanners/scanner22.py | 4 +- uncompyle6/scanners/scanner23.py | 4 +- uncompyle6/scanners/scanner24.py | 4 +- uncompyle6/scanners/scanner25.py | 4 +- uncompyle6/scanners/scanner26.py | 2 +- uncompyle6/scanners/scanner27.py | 2 +- uncompyle6/scanners/scanner30.py | 2 +- uncompyle6/scanners/scanner31.py | 4 +- uncompyle6/scanners/scanner32.py | 2 +- uncompyle6/scanners/scanner33.py | 4 +- uncompyle6/scanners/scanner34.py | 2 +- uncompyle6/scanners/scanner35.py | 2 +- uncompyle6/scanners/scanner36.py | 4 +- uncompyle6/scanners/scanner37.py | 38 ++++++++ uncompyle6/semantics/consts.py | 2 +- uncompyle6/semantics/fragments.py | 5 +- uncompyle6/semantics/pysource.py | 16 ++-- uncompyle6/verify.py | 10 +-- uncompyle6/version.py | 2 +- 26 files changed, 241 insertions(+), 46 deletions(-) create mode 100644 uncompyle6/scanners/scanner37.py diff --git a/NEWS b/NEWS index d81228c60..25859e857 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +uncompyle6 2.12.0 2017-09-25 + +- Use xdis 3.6.0 or greater now +- Small semantic table cleanups +- Python 3.4's terms a little names better +- Slightly more Python 3.7, but still failing a lot + +uncompyle6 2.11.5 2017-08-31 + +- Skeletal support for Python 3.7 + uncompyle6 2.11.4 2017-08-15 * scanner and parser now allow 3-part version string lookups, diff --git a/pytest/test_pysource.py b/pytest/test_pysource.py index aacefdf37..d7f4e776a 100644 --- a/pytest/test_pysource.py +++ b/pytest/test_pysource.py @@ -1,6 +1,6 @@ from uncompyle6 import PYTHON3 from uncompyle6.semantics.consts import ( - NONE, + escape, NONE, # RETURN_NONE, PASS, RETURN_LOCALS ) @@ -18,3 +18,143 @@ def test_template_engine(): sw.template_engine(('--%c--', 0), NONE) print(sw.f.getvalue()) assert sw.f.getvalue() == '--None--' + # FIXME: and so on... + +from uncompyle6.semantics.consts import ( + TABLE_R, TABLE_DIRECT, + ) + +from uncompyle6.semantics.fragments import ( + TABLE_DIRECT_FRAGMENT, + ) + +def test_tables(): + for t, name, fragment in ( + (TABLE_DIRECT, 'TABLE_DIRECT', False), + (TABLE_R, 'TABLE_R', False), + (TABLE_DIRECT_FRAGMENT, 'TABLE_DIRECT_FRAGMENT', True)): + for k, entry in t.iteritems(): + fmt = entry[0] + arg = 1 + i = 0 + m = escape.search(fmt) + print("%s[%s]" % (name, k)) + while m: + i = m.end() + typ = m.group('type') or '{' + if typ in frozenset(['%', '+', '-', '|', ',', '{']): + # No args + pass + elif typ in frozenset(['c', 'p', 'P', 'C', 'D']): + # One arg - should be int or tuple of int + if typ == 'c': + assert isinstance(entry[arg], int), ( + "%s[%s][%d] type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + elif typ in frozenset(['C', 'D']): + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 3 + for j, x in enumerate(tup[:-1]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[-1], str) or tup[-1] is None, ( + "%s[%s][%d][%d] sep type %s is %s should be an string but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, tup[-1], type(x), entry) + ) + + elif typ == 'P': + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is %s should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 4 + for j, x in enumerate(tup[:-2]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[-2], str), ( + "%s[%s][%d][%d] sep type %s is '%s' should be an string but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + assert isinstance(tup[1], int), ( + "%s[%s][%d][%d] prec type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + + else: + # Should be a tuple which contains only ints + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 2 + for j, x in enumerate(tup): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type '%s' is '%s should be an int but is %s. Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + pass + arg += 1 + elif typ in frozenset(['r']) and fragment: + pass + elif typ == 'b' and fragment: + assert isinstance(entry[arg], int), ( + "%s[%s][%d] type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + arg += 1 + elif typ == 'x' and fragment: + tup = entry[arg] + assert isinstance(tup, tuple), ( + "%s[%s][%d] type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert len(tup) == 2 + assert isinstance(tup[0], int), ( + "%s[%s][%d] source type %s is '%s' should be an int but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + assert isinstance(tup[1], tuple), ( + "%s[%s][%d] dest type %s is '%s' should be an tuple but is %s. " + "Full entry: %s" % + (name, k, arg, typ, entry[arg], type(entry[arg]), entry) + ) + for j, x in enumerate(tup[1]): + assert isinstance(x, int), ( + "%s[%s][%d][%d] type %s is %s should be an int but is %s. Full entry: %s" % + (name, k, arg, j, typ, x, type(x), entry) + ) + arg += 1 + pass + else: + assert False, ( + "%s[%s][%d] type %s is not known. Full entry: %s" % + (name, k, arg, typ, entry) + ) + m = escape.search(fmt, i) + pass + assert arg == len(entry), ( + "%s[%s] arg %d should be length of entry %d. Full entry: %s" % + (name, k, arg, len(entry), entry)) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 750c565c9..a92ae837f 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -54,7 +54,7 @@ def __init__(self, version, show_asm=None, is_pypy=False): if version in PYTHON_VERSIONS: if is_pypy: - v_str = "opcode_pypy%s" % (int(version * 10)) + v_str = "opcode_%spypy" % (int(version * 10)) else: v_str = "opcode_%s" % (int(version * 10)) exec("from xdis.opcodes import %s" % v_str) @@ -63,6 +63,7 @@ def __init__(self, version, show_asm=None, is_pypy=False): raise TypeError("%s is not a Python version I know about" % version) self.opname = self.opc.opname + # FIXME: This weird Python2 behavior is not Python3 self.resetTokenClass() @@ -99,7 +100,7 @@ def get_argument(self, pos): def print_bytecode(self): for i in self.op_range(0, len(self.code)): op = self.code[i] - if op in self.JUMP_OPs: + 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/pypy27.py b/uncompyle6/scanners/pypy27.py index 4ecfd628b..ed32de874 100644 --- a/uncompyle6/scanners/pypy27.py +++ b/uncompyle6/scanners/pypy27.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python PyPy 2.7 bytecode scanner/deparser @@ -10,8 +10,8 @@ import uncompyle6.scanners.scanner27 as scan # bytecode verification, verify(), uses JUMP_OPs from here -from xdis.opcodes import opcode_pypy27 -JUMP_OPs = opcode_pypy27.JUMP_OPs +from xdis.opcodes import opcode_27pypy +JUMP_OPS = opcode_27pypy.JUMP_OPS # We base this off of 2.6 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/pypy35.py b/uncompyle6/scanners/pypy35.py index a2c660a9b..2cbca4097 100644 --- a/uncompyle6/scanners/pypy35.py +++ b/uncompyle6/scanners/pypy35.py @@ -8,9 +8,9 @@ import uncompyle6.scanners.scanner35 as scan -# bytecode verification, verify(), uses JUMP_OPs from here +# 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) +JUMP_OPs = opc.JUMP_OPS # We base this off of 3.5 class ScannerPyPy35(scan.Scanner35): diff --git a/uncompyle6/scanners/scanner15.py b/uncompyle6/scanners/scanner15.py index 21d86bda0..867e64f02 100644 --- a/uncompyle6/scanners/scanner15.py +++ b/uncompyle6/scanners/scanner15.py @@ -11,7 +11,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_15 -JUMP_OPs = opcode_15.JUMP_OPs +JUMP_OPS = opcode_15.JUMP_OPS # We base this off of 2.1 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner21.py b/uncompyle6/scanners/scanner21.py index 53a5b405f..271c52db8 100644 --- a/uncompyle6/scanners/scanner21.py +++ b/uncompyle6/scanners/scanner21.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python 2.1 bytecode scanner/deparser @@ -11,7 +11,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_21 -JUMP_OPs = opcode_21.JUMP_OPs +JUMP_OPS = opcode_21.JUMP_OPS # We base this off of 2.2 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner22.py b/uncompyle6/scanners/scanner22.py index d2f8eecd5..c3effbc2e 100644 --- a/uncompyle6/scanners/scanner22.py +++ b/uncompyle6/scanners/scanner22.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python 2.2 bytecode ingester. @@ -11,7 +11,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_22 -JUMP_OPs = opcode_22.JUMP_OPs +JUMP_OPS = opcode_22.JUMP_OPS # We base this off of 2.3 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner23.py b/uncompyle6/scanners/scanner23.py index 688fa1b6b..9919b8317 100644 --- a/uncompyle6/scanners/scanner23.py +++ b/uncompyle6/scanners/scanner23.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python 2.3 bytecode scanner/deparser @@ -10,7 +10,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_23 -JUMP_OPs = opcode_23.JUMP_OPs +JUMP_OPS = opcode_23.JUMP_OPS # We base this off of 2.4 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner24.py b/uncompyle6/scanners/scanner24.py index b994241ed..b7ae220bf 100755 --- a/uncompyle6/scanners/scanner24.py +++ b/uncompyle6/scanners/scanner24.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python 2.4 bytecode scanner/deparser @@ -10,7 +10,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_24 -JUMP_OPs = opcode_24.JUMP_OPs +JUMP_OPS = opcode_24.JUMP_OPS # We base this off of 2.5 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner25.py b/uncompyle6/scanners/scanner25.py index c270d003d..3162388d6 100755 --- a/uncompyle6/scanners/scanner25.py +++ b/uncompyle6/scanners/scanner25.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein """ Python 2.5 bytecode scanner/deparser @@ -11,7 +11,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_25 -JUMP_OPs = opcode_25.JUMP_OPs +JUMP_OPS = opcode_25.JUMP_OPS # We base this off of 2.6 instead of the other way around # because we cleaned things up this way. diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index efe007479..c7297343b 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -19,7 +19,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_26 -JUMP_OPs = opcode_26.JUMP_OPs +JUMP_OPS = opcode_26.JUMP_OPS class Scanner26(scan.Scanner2): def __init__(self, show_asm=False): diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 024253fc1..7046865a6 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -16,7 +16,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_27 -JUMP_OPs = opcode_27.JUMP_OPs +JUMP_OPS = opcode_27.JUMP_OPs class Scanner27(Scanner2): def __init__(self, show_asm=False, is_pypy=False): diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index de0976e54..0b4b7ce35 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -10,7 +10,7 @@ from xdis.opcodes import opcode_30 as opc from xdis.bytecode import op_size -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS JUMP_TF = frozenset([opc.JUMP_IF_FALSE, opc.JUMP_IF_TRUE]) diff --git a/uncompyle6/scanners/scanner31.py b/uncompyle6/scanners/scanner31.py index 15f569188..951962229 100644 --- a/uncompyle6/scanners/scanner31.py +++ b/uncompyle6/scanners/scanner31.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 by Rocky Bernstein +# Copyright (c) 2016-2017 by Rocky Bernstein """ Python 3.1 bytecode scanner/deparser @@ -8,7 +8,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_31 as opc -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS from uncompyle6.scanners.scanner3 import Scanner3 class Scanner31(Scanner3): diff --git a/uncompyle6/scanners/scanner32.py b/uncompyle6/scanners/scanner32.py index b1b2fed80..07a1a28cb 100644 --- a/uncompyle6/scanners/scanner32.py +++ b/uncompyle6/scanners/scanner32.py @@ -11,7 +11,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_32 as opc -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS from uncompyle6.scanners.scanner3 import Scanner3 class Scanner32(Scanner3): diff --git a/uncompyle6/scanners/scanner33.py b/uncompyle6/scanners/scanner33.py index 06268003d..5e99f8554 100644 --- a/uncompyle6/scanners/scanner33.py +++ b/uncompyle6/scanners/scanner33.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016 by Rocky Bernstein +# Copyright (c) 2015-2017 by Rocky Bernstein """ Python 3.3 bytecode scanner/deparser @@ -8,7 +8,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_33 as opc -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS from uncompyle6.scanners.scanner3 import Scanner3 class Scanner33(Scanner3): diff --git a/uncompyle6/scanners/scanner34.py b/uncompyle6/scanners/scanner34.py index 80d14842a..e9de06598 100644 --- a/uncompyle6/scanners/scanner34.py +++ b/uncompyle6/scanners/scanner34.py @@ -12,7 +12,7 @@ from xdis.opcodes import opcode_34 as opc # bytecode verification, verify(), uses JUMP_OPs from here -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS from uncompyle6.scanners.scanner3 import Scanner3 diff --git a/uncompyle6/scanners/scanner35.py b/uncompyle6/scanners/scanner35.py index 2d9265faf..370c56e14 100644 --- a/uncompyle6/scanners/scanner35.py +++ b/uncompyle6/scanners/scanner35.py @@ -13,7 +13,7 @@ # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_35 as opc -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS class Scanner35(Scanner3): diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index dd293d4f2..a9d5bd01f 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -11,9 +11,9 @@ from uncompyle6.scanners.scanner3 import Scanner3 -# bytecode verification, verify(), uses JUMP_OPs from here +# bytecode verification, verify(), uses JUMP_OPS from here from xdis.opcodes import opcode_36 as opc -JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) +JUMP_OPS = opc.JUMP_OPS class Scanner36(Scanner3): diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py new file mode 100644 index 000000000..0e22ba605 --- /dev/null +++ b/uncompyle6/scanners/scanner37.py @@ -0,0 +1,38 @@ +# Copyright (c) 2016-2017 by Rocky Bernstein +""" +Python 3.7 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. +""" + +from __future__ import print_function + +from uncompyle6.scanners.scanner3 import Scanner3 + +# bytecode verification, verify(), uses JUMP_OPs from here +from xdis.opcodes import opcode_36 as opc +JUMP_OPs = opc.JUMP_OPS + +class Scanner37(Scanner3): + + def __init__(self, show_asm=None): + Scanner3.__init__(self, 3.7, show_asm) + return + pass + +if __name__ == "__main__": + from uncompyle6 import PYTHON_VERSION + if PYTHON_VERSION == 3.7: + import inspect + co = inspect.currentframe().f_code + tokens, customize = Scanner37().ingest(co) + for t in tokens: + print(t.format()) + pass + else: + print("Need to be Python 3.7 to demo; I am %s." % + PYTHON_VERSION) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index a21945950..b5d496445 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -99,7 +99,7 @@ 'UNARY_POSITIVE': ( '+',), 'UNARY_NEGATIVE': ( '-',), - 'UNARY_INVERT': ( '~%c'), + 'UNARY_INVERT': ( '~'), 'unary_expr': ( '%c%c', 1, 0), 'unary_not': ( 'not %c', 0 ), diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index c2da61b4f..5fc880e4e 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -40,7 +40,8 @@ 2. %b ----- - %b associates the text from the previous start node up to what we have now + %b associates the text from the specified index to what we have now. + it takes an integer argument. For example in: 'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ), @@ -98,7 +99,7 @@ 'list_for': (' for %c%x in %c%c', 2, (2, (1, )), 0, 3 ), 'forstmt': ( '%|for%b %c%x in %c:\n%+%c%-\n\n', 0, 3, (3, (2, )), 1, 4 ), 'forelsestmt': ( - '%|for %c in %c%x:\n%+%c%-%|else:\n%+%c%-\n\n', 3, (3, (2,)), 1, 4, -2), + '%|for %c%x in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, (3, (2,)), 1, 4, -2), 'forelselaststmt': ( '%|for %c%x in %c:\n%+%c%-%|else:\n%+%c%-', 3, (3, (2,)), 1, 4, -2), 'forelselaststmtl': ( diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 3b21ff7c4..61aff5900 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -61,18 +61,22 @@ # index and the precidence value, an integer. # # %C evaluate children recursively, with sibling children separated by the -# given string. It needs a tuple of 3 items, a starting node, the maximimum +# given string. It needs a 3-tuple: a starting node, the maximimum # value of an end node, and a string to be inserted between sibling children # # %, Append ',' if last %C only printed one item. This is mostly for tuples # on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints # other tuples. The specifier takes no arguments # -# %P same as %C but sets operator precedence. +# %P same as %C but sets operator precedence. Its argument is a 4-tuple: +# the node low and high indices, the separator, a string the precidence +# value, an integer. # -# %D Same as `%C` this is for left-recursive lists like kwargs where -# goes to epsilon at the beginning. If we were to use `%C` an extra separator -# with an epsilon would appear at the beginning. +# %D Same as `%C` this is for left-recursive lists like kwargs where goes +# to epsilon at the beginning. It needs a 3-tuple: a starting node, the +# maximimum value of an end node, and a string to be inserted between +# sibling children. If we were to use `%C` an extra separator with an +# epsilon would appear at the beginning. # # %| Insert spaces to the current indentation level. Takes no arguments. # @@ -1940,7 +1944,7 @@ def customize(self, customize): 'CALL_FUNCTION_VAR_KW', 'CALL_FUNCTION_KW'): if v == 0: str = '%c(%C' # '%C' is a dummy here ... - p2 = (0, 0, None) # .. because of this + p2 = (0, 0, None) # .. because of the None in this else: str = '%c(%C, ' p2 = (1, -2, ', ') diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index cdafcdf10..a353c8e25 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -43,7 +43,7 @@ def code_equal(a, b): 'BINARY_OR': operator.or_, } -JUMP_OPs = None +JUMP_OPS = None # --- exceptions --- @@ -225,8 +225,8 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, import uncompyle6.scanners.scanner36 as scan scanner = scan.Scanner36() - global JUMP_OPs - JUMP_OPs = list(scan.JUMP_OPs) + ['JUMP_BACK'] + global JUMP_OPS + JUMP_OPS = list(scan.JUMP_OPS) + ['JUMP_BACK'] # use changed Token class # We (re)set this here to save exception handling, @@ -331,7 +331,7 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, else: raise CmpErrorCode(name, tokens1[i1].offset, tokens1[i1], tokens2[i2], tokens1, tokens2) - elif tokens1[i1].type in JUMP_OPs and tokens1[i1].pattr != tokens2[i2].pattr: + elif tokens1[i1].type in JUMP_OPS and tokens1[i1].pattr != tokens2[i2].pattr: if tokens1[i1].type == 'JUMP_BACK': dest1 = int(tokens1[i1].pattr) dest2 = int(tokens2[i2].pattr) @@ -398,7 +398,7 @@ def __cmp__(self, o): return 0 if t == 'JUMP_IF_FALSE_OR_POP' and o.type == 'POP_JUMP_IF_FALSE': return 0 - if JUMP_OPs and t in JUMP_OPs: + if JUMP_OPS and t in JUMP_OPS: # ignore offset return t == o.type return (t == o.type) or self.pattr == o.pattr diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 5d5aeedc8..f6cb55671 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.5' +VERSION='2.12.0' From ea75bcf47ea18f3c2cafa08c06ca976506f73d3d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Sep 2017 20:11:53 -0400 Subject: [PATCH 047/489] Require xdis 3.6.0 or greater --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index e06a2bb85..222ba24fc 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -40,7 +40,7 @@ ]} ftp_url = None install_requires = ['spark-parser >= 1.6.1, < 1.7.0', - 'xdis >= 3.5.5, < 3.6.0'] + 'xdis >= 3.6.0, < 3.7.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' modname = 'uncompyle6' From 1a627ba207d75f62c445e35310e8368944019c1a Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Sep 2017 09:53:26 -0400 Subject: [PATCH 048/489] Annotation field can be unicode... When deparsing Python 3.x from Python 2. --- uncompyle6/parsers/parse3.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index bb5d9f4f3..a6fd770ad 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -18,6 +18,7 @@ from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.astnode import AST from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from xdis import PYTHON3 class Python3Parser(PythonParser): @@ -890,8 +891,11 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): elif lhs == 'annotate_tuple': return not isinstance(tokens[first].attr, tuple) elif lhs == 'kwarg': - return not (isinstance(tokens[first].attr, unicode) or - isinstance(tokens[first].attr, str)) + arg = tokens[first].attr + if PYTHON3: + return not isinstance(arg, str) + else: + return not (isinstance(arg, str) or isinstance(arg, unicode)) elif lhs == 'while1elsestmt': # if SETUP_LOOP target spans the else part, then this is # not while1else. Also do for whileTrue? From 2b0fefb95f40837b34171796f87177e05a34a2bb Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 2 Oct 2017 03:12:26 -0400 Subject: [PATCH 049/489] Sync with master --- uncompyle6/parsers/parse2.py | 2 ++ uncompyle6/parsers/parse3.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 8a80a1f42..6f4ab54b2 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -395,6 +395,8 @@ def add_custom_rules(self, tokens, customize): return def reduce_is_invalid(self, rule, ast, tokens, first, last): + if not tokens: + return lhs = rule[0] if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and': return True diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a6fd770ad..a78defe0a 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -885,6 +885,8 @@ def add_custom_rules(self, tokens, customize): return def reduce_is_invalid(self, rule, ast, tokens, first, last): + if not tokens: + return lhs = rule[0] if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and': return True From eee751e22afdfb891b6e4f411634230ea328fb8d Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 3 Oct 2017 05:44:55 -0400 Subject: [PATCH 050/489] Go over table-semantics description yet again --- uncompyle6/semantics/fragments.py | 3 --- uncompyle6/semantics/pysource.py | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 5fc880e4e..6bd613623 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1,6 +1,4 @@ # Copyright (c) 2015-2017 by Rocky Bernstein -# Copyright (c) 2005 by Dan Pascu -# Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock """ @@ -97,7 +95,6 @@ 'importfrom': ( '%|from %[2]{pattr}%x import %c\n', (2, (0, 1)), 3), 'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ), 'list_for': (' for %c%x in %c%c', 2, (2, (1, )), 0, 3 ), - 'forstmt': ( '%|for%b %c%x in %c:\n%+%c%-\n\n', 0, 3, (3, (2, )), 1, 4 ), 'forelsestmt': ( '%|for %c%x in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 3, (3, (2,)), 1, 4, -2), 'forelselaststmt': ( diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 61aff5900..3b1df2c81 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -25,21 +25,28 @@ # of the nonterminal is suffixed with "_exit" it will be called after # all of its children are called. # -# However if this were done for all of the rules, this file would be even longer -# than it is already. +# After a while writing methods this way, you'll find many routines which do similar +# sorts of things, and soon you'll find you want a short notation to +# describe rules and not have to create methods at all. # -# Another more compact way to specify a semantic rule for a nonterminal is via -# rule given in one of the tables MAP_R0, MAP_R, or MAP_DIRECT. +# So another other way to specify a semantic rule for a nonterminal is via +# one of the tables MAP_R0, MAP_R, or MAP_DIRECT where the key is the +# nonterminal name. # -# These uses a printf-like syntax to direct substitution from attributes -# of the nonterminal and its children.. +# These dictionaries use a printf-like syntax to direct substitution +# from attributes of the nonterminal and its children.. # # The rest of the below describes how table-driven semantic actions work # and gives a list of the format specifiers. The default() and # template_engine() methods implement most of the below. # -# Step 1 determines a table (T) and a path to a -# table key (K) from the node type (N) (other nodes are shown as O): +# We allow for a couple of ways to interact with a node in a tree. So +# step 1 after not seeing a custom method for a nonterminal is to +# determine from what point of view tree-wise the rule is applied. +# In the diagram below, "N" is a nonterminal name, and K is the table +# key name; we show where those are with respect to each other in the +# AST tree for N. +# # # N N N&K # / | ... \ / | ... \ / | ... \ @@ -49,7 +56,10 @@ # # MAP_R0 (TABLE_R0) MAP_R (TABLE_R) MAP_DIRECT (TABLE_DIRECT) # -# The default is a direct mapping. The key K is then extracted from the +# The default is a "TABLE_DIRECT" mapping By far, most rules used work this way. +# TABLE_R0 is rarely used. +# +# The key K is then extracted from the # subtree and used to find a table entry T[K], if any. The result is a # format string and arguments (a la printf()) for the formatting engine. # Escapes in the format string are: From b1705e283dcb91b1dec75782ddc823f0ab85a4b0 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 3 Oct 2017 11:54:24 -0400 Subject: [PATCH 051/489] handle newer parser reduction behavior --- uncompyle6/parsers/parse2.py | 4 ++-- uncompyle6/parsers/parse24.py | 2 +- uncompyle6/parsers/parse26.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 6f4ab54b2..cc4fbc375 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -395,8 +395,8 @@ def add_custom_rules(self, tokens, customize): return def reduce_is_invalid(self, rule, ast, tokens, first, last): - if not tokens: - return + if tokens is None: + return False lhs = rule[0] if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and': return True diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index ac8ff71df..6c3006c8b 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -55,7 +55,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python24Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) - if invalid: + if invalid or tokens is None: return invalid # FiXME: this code never gets called... diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index c8561d59b..df7cc42c3 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -258,7 +258,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python26Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) - if invalid: + if invalid or tokens is None: return invalid if rule == ('and', ('expr', 'jmp_false', 'expr', '\\e_come_from_opt')): # Test that jmp_false jumps to the end of "and" From d4f6cec3d0ca3fc9baa2c71d8b741b05fc55ee10 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 5 Oct 2017 11:17:49 -0400 Subject: [PATCH 052/489] Sync with master --- .gitignore | 3 ++- pytest/test_grammar.py | 5 +++-- uncompyle6/parser.py | 7 ++++++- uncompyle6/parsers/parse26.py | 4 +++- uncompyle6/parsers/parse27.py | 4 ++++ uncompyle6/parsers/parse3.py | 7 +++++++ uncompyle6/semantics/consts.py | 11 +++++++++-- uncompyle6/semantics/pysource.py | 8 +++++++- 8 files changed, 41 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d4e5cf9cb..856518e3f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ __pycache__ build /.venv* -/.idea \ No newline at end of file +/.idea +/.hypothesis diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index adccec02c..241d064d3 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -39,13 +39,14 @@ def check_tokens(tokens, opcode_set): s = get_scanner(PYTHON_VERSION, IS_PYPY) ignore_set = set( """ - JUMP_BACK CONTINUE RETURN_END_IF + JUMP_BACK CONTINUE COME_FROM COME_FROM_EXCEPT COME_FROM_EXCEPT_CLAUSE COME_FROM_LOOP COME_FROM_WITH COME_FROM_FINALLY ELSE LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP - LAMBDA_MARKER RETURN_LAST + LAMBDA_MARKER + RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST """.split()) if 2.6 <= PYTHON_VERSION <= 2.7: opcode_set = set(s.opc.opname).union(ignore_set) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 83391a32c..93b181ae0 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -254,8 +254,11 @@ def p_stmt(self, args): stmt ::= return_stmt return_stmt ::= ret_expr RETURN_VALUE + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + return_stmts ::= return_stmt return_stmts ::= _stmts return_stmt + """ pass @@ -530,7 +533,9 @@ def p_expr(self, args): stmt ::= return_lambda stmt ::= conditional_lambda - return_lambda ::= ret_expr RETURN_VALUE LAMBDA_MARKER + return_lambda ::= ret_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER + return_lambda ::= ret_expr RETURN_VALUE_LAMBDA + conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER cmp ::= cmp_list diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index df7cc42c3..79ae264d8 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -247,7 +247,9 @@ def p_misc26(self, args): and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP cmp_list ::= expr cmp_list1 ROT_TWO COME_FROM POP_TOP _come_from - conditional_lambda ::= expr jmp_false_then return_if_stmt return_stmt LAMBDA_MARKER + return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP + conditional_lambda ::= expr jmp_false_then expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index d73928104..614b30dac 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -94,6 +94,10 @@ def p_stmt27(self, args): WITH_CLEANUP END_FINALLY # Common with 2.6 + return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER + while1stmt ::= SETUP_LOOP return_stmts bp_come_from while1stmt ::= SETUP_LOOP return_stmts COME_FROM """ diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a78defe0a..ed5e6c34c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -416,6 +416,13 @@ def p_expr3(self, args): # a JUMP_ABSOLUTE with no COME_FROM conditional ::= expr jmp_false expr jump_absolute_else expr + return_if_lambda ::= RETURN_END_IF_LAMBDA + conditional_lambda ::= expr jmp_false return_stmt_lambda + return_stmt_lambda LAMBDA_MARKER + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER + + expr ::= LOAD_CLASSNAME # Python 3.4+ diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index b5d496445..db0390f19 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -173,8 +173,13 @@ 'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27) ), 'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27) ), 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27) ), - 'conditional_lambda': ( '(%c if %c else %c)', 2, 0, 3), - 'return_lambda': ('%c', 0), + 'conditional_lambda': ( '%c if %c else %c', 2, 0, 4), + + # The semicolon is because Python 3.x can have be dead code as a result of its + # optimization. We don't Python's remove dead code (yet) anymore than Python does. + # So without that we would have "return 2return3" rather than "return 2;return 3" + 'return_lambda': ('return %c;', 0), + 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), 'cmp_list': ( '%p %p', (0, 29), (1, 30)), 'cmp_list1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), @@ -209,6 +214,7 @@ 'raise_stmt3': ( '%|raise %c, %c, %c\n', 0, 1, 2), # 'yield': ( 'yield %c', 0), # 'return_stmt': ( '%|return %c\n', 0), + 'return_if_stmt': ( 'return %c\n', 0), 'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ), @@ -331,6 +337,7 @@ 'ret_or': 26, 'conditional': 28, + 'conditional_lamdba': 28, 'conditionalnot': 28, 'ret_cond': 28, 'ret_cond_not': 28, diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 3b1df2c81..b72596d08 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -658,6 +658,7 @@ def n_return_stmt(self, node): def n_return_if_stmt(self, node): if self.params['isLambda']: + self.write(' return ') self.preorder(node[0]) self.prune() else: @@ -2149,6 +2150,11 @@ def build_ast(self, tokens, customize, isLambda=False, # assert isinstance(tokens[0], Token) if isLambda: + for t in tokens: + if t.type == 'RETURN_END_IF': + t.type = 'RETURN_END_IF_LAMBDA' + elif t.type == 'RETURN_VALUE': + t.type = 'RETURN_VALUE_LAMBDA' tokens.append(Token('LAMBDA_MARKER')) try: ast = python_parser.parse(self.p, tokens, customize) @@ -2165,7 +2171,7 @@ def build_ast(self, tokens, customize, isLambda=False, # than fight (with the grammar to not emit "return None"). if self.hide_internal: if len(tokens) >= 2 and not noneInNames: - if tokens[-1].type == 'RETURN_VALUE': + if tokens[-1].type in ('RETURN_VALUE', 'RETURN_VALUE_LAMBDA'): # Python 3.4's classes can add a "return None" which is # invalid syntax. if tokens[-2].type == 'LOAD_CONST': From 2ea7487ca79f535f8216e3e732443d13ee1f8e9e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 5 Oct 2017 11:19:36 -0400 Subject: [PATCH 053/489] One more test --- test/simple_source/branching/02_ifelse_lambda.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/simple_source/branching/02_ifelse_lambda.py diff --git a/test/simple_source/branching/02_ifelse_lambda.py b/test/simple_source/branching/02_ifelse_lambda.py new file mode 100644 index 000000000..b21fa4f57 --- /dev/null +++ b/test/simple_source/branching/02_ifelse_lambda.py @@ -0,0 +1,5 @@ +# We have to do contortions here because +# lambda's have to be more or less on a line + +f = lambda x: 1 if x<2 else 3 +f(5) From 3892fb533ad2e7f19af384d68ec39b6d450db1a8 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Oct 2017 16:12:02 -0400 Subject: [PATCH 054/489] Misc bugs --- uncompyle6/parsers/parse24.py | 5 +++-- uncompyle6/scanners/scanner3.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 6c3006c8b..cfba72dd0 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -58,10 +58,11 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): if invalid or tokens is None: return invalid - # FiXME: this code never gets called... lhs = rule[0] if lhs == 'nop_stmt': - return not int(tokens[first].pattr) == tokens[last].offset + l = len(tokens) + if 0 <= l < len(tokens): + return not int(tokens[first].pattr) == tokens[last].offset return False diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 47759f803..f2c40424d 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -949,7 +949,7 @@ def detect_control_flow(self, offset, targets): return pass pass - if code[pre_rtarget] == self.opc.RETURN_VALUE and self.version < 3.5: + if code[pre_rtarget] == self.opc.RETURN_VALUE: self.return_end_ifs.add(pre_rtarget) else: self.fixed_jumps[offset] = rtarget @@ -969,7 +969,7 @@ def detect_control_flow(self, offset, targets): if target > next_offset: next_op = code[next_offset] if (self.opc.JUMP_ABSOLUTE == next_op and - END_FINALLY != code[xdis.next_offset(next_op, self.opc, next_offset)]): + self.opc.END_FINALLY != code[xdis.next_offset(next_op, self.opc, next_offset)]): self.fixed_jumps[next_offset] = target self.except_targets[target] = next_offset @@ -992,7 +992,8 @@ def detect_control_flow(self, offset, targets): # misclassified as RETURN_END_IF. Handle that here. # In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF if op == self.opc.RETURN_VALUE: - if (offset+1 < len(code) and code[offset+1] == self.opc.JUMP_ABSOLUTE and + next_offset = xdis.next_offset(op, self.opc, offset) + if (next_offset < len(code) and code[next_offset] == self.opc.JUMP_ABSOLUTE and offset in self.return_end_ifs): self.return_end_ifs.remove(offset) pass From 9e0c65881d8004bae7171f01b48b44b58d5304e3 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Oct 2017 22:50:40 -0400 Subject: [PATCH 055/489] Sync with master --- NEWS | 7 ++ __pkginfo__.py | 2 +- pytest/test_grammar.py | 2 +- uncompyle6/parser.py | 17 ++-- uncompyle6/parsers/parse15.py | 4 +- uncompyle6/parsers/parse2.py | 2 +- uncompyle6/parsers/parse21.py | 4 +- uncompyle6/parsers/parse22.py | 4 +- uncompyle6/parsers/parse23.py | 4 +- uncompyle6/parsers/parse24.py | 2 +- uncompyle6/parsers/parse25.py | 2 +- uncompyle6/parsers/parse26.py | 2 +- uncompyle6/parsers/parse27.py | 5 +- uncompyle6/parsers/parse3.py | 41 ++++----- uncompyle6/parsers/parse32.py | 2 +- uncompyle6/parsers/parse34.py | 2 +- uncompyle6/parsers/parse35.py | 6 +- uncompyle6/parsers/parse36.py | 10 +- uncompyle6/parsers/parse37.py | 2 +- uncompyle6/scanners/scanner22.py | 2 +- uncompyle6/scanners/scanner26.py | 10 +- uncompyle6/scanners/scanner27.py | 4 +- uncompyle6/scanners/scanner3.py | 6 +- uncompyle6/scanners/scanner36.py | 8 +- uncompyle6/scanners/tok.py | 20 ++-- uncompyle6/semantics/check_ast.py | 6 +- uncompyle6/semantics/make_function.py | 22 ++--- uncompyle6/semantics/pysource.py | 128 ++++++++++++++------------ uncompyle6/verify.py | 84 ++++++++--------- uncompyle6/version.py | 2 +- 30 files changed, 215 insertions(+), 197 deletions(-) diff --git a/NEWS b/NEWS index 624d9543b..2c6ae2a8c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,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 + uncompyle6 2.12.0 2017-09-26 - Use xdis 3.6.0 or greater now diff --git a/__pkginfo__.py b/__pkginfo__.py index 222ba24fc..de914c13a 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -39,7 +39,7 @@ 'pydisassemble=uncompyle6.bin.pydisassemble:main', ]} ftp_url = None -install_requires = ['spark-parser >= 1.6.1, < 1.7.0', +install_requires = ['spark-parser >= 1.7.0, < 1.8.0', 'xdis >= 3.6.0, < 3.7.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 241d064d3..b92e163d5 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -11,7 +11,7 @@ def check_tokens(tokens, opcode_set): remain_tokens = set([re.sub('_CONT$','', t) for t in remain_tokens]) remain_tokens = set(remain_tokens) - opcode_set assert remain_tokens == set([]), \ - "Remaining tokens %s\n====\n%s" % (remain_tokens, p.dumpGrammar()) + "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 = p.checkSets() diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 9d7711625..2fe57af5e 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -89,17 +89,14 @@ def cleanup(self): for i in dir(self): setattr(self, i, None) - def debug_reduce(self, rule, tokens, parent, i): + def debug_reduce(self, rule, tokens, parent, last_token_pos): """Customized format and print for our kind of tokens which gets called in debugging grammar reduce rules """ def fix(c): s = str(c) - i = s.find('_') - if i == -1: - return s - else: - return s[:i] + last_token_pos = s.find('_') + return s if last_token_pos == -1 else s[:last_token_pos] prefix = '' if parent and tokens: @@ -111,13 +108,13 @@ def fix(c): if hasattr(p_token, 'offset'): prefix += "%3s" % fix(p_token.offset) if len(rule[1]) > 1: - prefix += '-%-3s ' % fix(tokens[i-1].offset) + prefix += '-%-3s ' % fix(tokens[last_token_pos-1].offset) else: prefix += ' ' else: prefix = ' ' - print("%s%s ::= %s" % (prefix, rule[0], ' '.join(rule[1]))) + print("%s%s ::= %s (%d)" % (prefix, rule[0], ' '.join(rule[1]), last_token_pos)) def error(self, instructions, index): # Find the last line boundary @@ -138,7 +135,7 @@ def error(self, instructions, index): raise ParserError(err_token, err_token.offset) def typestring(self, token): - return token.type + return token.kind def nonterminal(self, nt, args): if nt in self.collect and len(args) > 1: @@ -737,7 +734,7 @@ def get_python_parser( else: p = parse3.Python3ParserSingle(debug_parser) p.version = version - # p.dumpGrammar() # debug + # p.dump_grammar() # debug return p class PythonParserSingle(PythonParser): diff --git a/uncompyle6/parsers/parse15.py b/uncompyle6/parsers/parse15.py index fb2e8b148..b1f51c5a5 100644 --- a/uncompyle6/parsers/parse15.py +++ b/uncompyle6/parsers/parse15.py @@ -29,8 +29,8 @@ class Python15ParserSingle(Python21Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python15Parser() - p.checkGrammar() - p.dumpGrammar() + p.check_grammar() + p.dump_grammar() # local variables: # tab-width: 4 diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index cc4fbc375..0e8f571d2 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -417,4 +417,4 @@ class Python2ParserSingle(Python2Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python2Parser() - p.checkGrammar() + p.check_grammar() diff --git a/uncompyle6/parsers/parse21.py b/uncompyle6/parsers/parse21.py index ed26af82e..7e52626af 100644 --- a/uncompyle6/parsers/parse21.py +++ b/uncompyle6/parsers/parse21.py @@ -33,8 +33,8 @@ class Python21ParserSingle(Python22Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python21Parser() - p.checkGrammar() - p.dumpGrammar() + p.check_grammar() + p.dump_grammar() # local variables: # tab-width: 4 diff --git a/uncompyle6/parsers/parse22.py b/uncompyle6/parsers/parse22.py index 4ea7039ea..ae4ec4c7e 100644 --- a/uncompyle6/parsers/parse22.py +++ b/uncompyle6/parsers/parse22.py @@ -26,8 +26,8 @@ class Python22ParserSingle(Python23Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python22Parser() - p.checkGrammar() - p.dumpGrammar() + p.check_grammar() + p.dump_grammar() # local variables: # tab-width: 4 diff --git a/uncompyle6/parsers/parse23.py b/uncompyle6/parsers/parse23.py index b2072e16e..abbd41c73 100644 --- a/uncompyle6/parsers/parse23.py +++ b/uncompyle6/parsers/parse23.py @@ -67,8 +67,8 @@ class Python23ParserSingle(Python23Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python23Parser() - p.checkGrammar() - p.dumpGrammar() + p.check_grammar() + p.dump_grammar() # local variables: # tab-width: 4 diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index cfba72dd0..e406d11e9 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -72,4 +72,4 @@ class Python24ParserSingle(Python24Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python24Parser() - p.checkGrammar() + p.check_grammar() diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 8111ff938..93dd342bb 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -60,4 +60,4 @@ class Python25ParserSingle(Python26Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python25Parser() - p.checkGrammar() + p.check_grammar() diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 79ae264d8..c68efb8c1 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -276,7 +276,7 @@ class Python26ParserSingle(Python2Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python26Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 2.6: lhs, rhs, tokens, right_recursive = p.checkSets() diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 614b30dac..953ba5acc 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -129,7 +129,7 @@ class Python27ParserSingle(Python27Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python27Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 2.7: lhs, rhs, tokens, right_recursive = p.checkSets() @@ -148,4 +148,5 @@ class Python27ParserSingle(Python27Parser, PythonParserSingle): for t in remain_tokens]) remain_tokens = set(remain_tokens) - opcode_set print(remain_tokens) - # p.dumpGrammar() + p.check_grammar() + p.dump_grammar() diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index ed5e6c34c..a338f6cc5 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -433,7 +433,7 @@ def p_expr3(self, args): @staticmethod def call_fn_name(token): """Customize CALL_FUNCTION to add the number of positional arguments""" - return '%s_%i' % (token.type, token.attr) + return '%s_%i' % (token.kind, token.attr) def custom_build_class_rule(self, opname, i, token, tokens, customize): ''' @@ -449,16 +449,16 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize): # FIXME: I bet this can be simplified # look for next MAKE_FUNCTION for i in range(i+1, len(tokens)): - if tokens[i].type.startswith('MAKE_FUNCTION'): + if tokens[i].kind.startswith('MAKE_FUNCTION'): break - elif tokens[i].type.startswith('MAKE_CLOSURE'): + elif tokens[i].kind.startswith('MAKE_CLOSURE'): break pass assert i < len(tokens), "build_class needs to find MAKE_FUNCTION or MAKE_CLOSURE" - assert tokens[i+1].type == 'LOAD_CONST', \ + assert tokens[i+1].kind == 'LOAD_CONST', \ "build_class expecting CONST after MAKE_FUNCTION/MAKE_CLOSURE" for i in range(i, len(tokens)): - if tokens[i].type == 'CALL_FUNCTION': + if tokens[i].kind == 'CALL_FUNCTION': call_fn_tok = tokens[i] break assert call_fn_tok, "build_class custom rule needs to find CALL_FUNCTION" @@ -499,7 +499,7 @@ def custom_classfunc_rule(self, opname, token, customize): # Yes, this computation based on instruction name is a little bit hoaky. nak = ( len(opname)-len('CALL_FUNCTION') ) // 3 - token.type = self.call_fn_name(token) + token.kind = self.call_fn_name(token) uniq_param = args_kw + args_pos if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR'): # Python 3.5 changes the stack position of *args. KW args come @@ -511,33 +511,33 @@ def custom_classfunc_rule(self, opname, token, customize): kw = '' rule = ('call_function ::= expr expr ' + ('pos_arg ' * args_pos) + - ('kwarg ' * args_kw) + kw + token.type) - self.add_unique_rule(rule, token.type, uniq_param, customize) + ('kwarg ' * args_kw) + kw + token.kind) + self.add_unique_rule(rule, token.kind, uniq_param, customize) if self.version >= 3.6 and opname == 'CALL_FUNCTION_EX_KW': rule = ('call_function36 ::= ' 'expr build_tuple_unpack_with_call build_map_unpack_with_call ' 'CALL_FUNCTION_EX_KW_1') - self.add_unique_rule(rule, token.type, uniq_param, customize) + self.add_unique_rule(rule, token.kind, uniq_param, customize) rule = 'call_function ::= call_function36' else: rule = ('call_function ::= expr ' + ('pos_arg ' * args_pos) + ('kwarg ' * args_kw) + - 'expr ' * nak + token.type) + 'expr ' * nak + token.kind) - self.add_unique_rule(rule, token.type, uniq_param, customize) + self.add_unique_rule(rule, token.kind, uniq_param, customize) if self.version >= 3.5: rule = ('async_call_function ::= expr ' + ('pos_arg ' * args_pos) + ('kwarg ' * args_kw) + - 'expr ' * nak + token.type + + 'expr ' * nak + token.kind + ' GET_AWAITABLE LOAD_CONST YIELD_FROM') - self.add_unique_rule(rule, token.type, uniq_param, customize) - self.add_unique_rule('expr ::= async_call_function', token.type, uniq_param, customize) + self.add_unique_rule(rule, token.kind, uniq_param, customize) + self.add_unique_rule('expr ::= async_call_function', token.kind, uniq_param, customize) rule = ('classdefdeco2 ::= LOAD_BUILD_CLASS mkfunc %s%s_%d' % (('expr ' * (args_pos-1)), opname, args_pos)) - self.add_unique_rule(rule, token.type, uniq_param, customize) + self.add_unique_rule(rule, token.kind, uniq_param, customize) def add_make_function_rule(self, rule, opname, attr, customize): """Python 3.3 added a an addtional LOAD_CONST before MAKE_FUNCTION and @@ -614,7 +614,7 @@ def add_custom_rules(self, tokens, customize): call_function ::= expr CALL_METHOD """ for i, token in enumerate(tokens): - opname = token.type + opname = token.kind opname_base = opname[:opname.rfind('_')] if opname == 'PyPy': @@ -892,8 +892,6 @@ def add_custom_rules(self, tokens, customize): return def reduce_is_invalid(self, rule, ast, tokens, first, last): - if not tokens: - return lhs = rule[0] if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and': return True @@ -913,7 +911,8 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): last += 1 return tokens[first].attr == tokens[last].offset elif lhs == 'while1stmt': - if tokens[last] in ('COME_FROM_LOOP', 'JUMP_BACK'): + if (0 <= last < len(tokens) + and tokens[last] in ('COME_FROM_LOOP', 'JUMP_BACK')): # jump_back should be right afer SETUP_LOOP. Test? last += 1 while last < len(tokens) and isinstance(tokens[last].offset, str): @@ -957,10 +956,10 @@ def info(args): p = Python32Parser() elif arg == '3.0': p = Python30Parser() - p.checkGrammar() + p.check_grammar() if len(sys.argv) > 1 and sys.argv[1] == 'dump': print('-' * 50) - p.dumpGrammar() + p.dump_grammar() if __name__ == '__main__': import sys diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index 598099bc4..8d64346e2 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -42,7 +42,7 @@ def p_32on(self, args): def add_custom_rules(self, tokens, customize): super(Python32Parser, self).add_custom_rules(tokens, customize) for i, token in enumerate(tokens): - opname = token.type + opname = token.kind if opname.startswith('MAKE_FUNCTION_A'): args_pos, args_kw, annotate_args = token.attr # Check that there are 2 annotated params? diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index 080236f62..bd6be275c 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -29,7 +29,7 @@ class Python34ParserSingle(Python34Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python34Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.4: lhs, rhs, tokens, right_recursive = p.checkSets() diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index b8cf37233..12bd5fbd2 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -142,7 +142,7 @@ def p_35on(self, args): def add_custom_rules(self, tokens, customize): super(Python35Parser, self).add_custom_rules(tokens, customize) for i, token in enumerate(tokens): - opname = token.type + opname = token.kind if opname == 'BUILD_MAP_UNPACK_WITH_CALL': nargs = token.attr % 256 map_unpack_n = "map_unpack_%s" % nargs @@ -152,7 +152,7 @@ def add_custom_rules(self, tokens, customize): self.add_unique_rule(rule, opname, token.attr, customize) call_token = tokens[i+1] if self.version == 3.5: - rule = 'call_function ::= expr unmapexpr ' + call_token.type + rule = 'call_function ::= expr unmapexpr ' + call_token.kind self.add_unique_rule(rule, opname, token.attr, customize) pass pass @@ -164,7 +164,7 @@ class Python35ParserSingle(Python35Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python35Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.5: lhs, rhs, tokens, right_recursive = p.checkSets() diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 95f82cc75..7a369997a 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -36,7 +36,7 @@ def p_36misc(self, args): def add_custom_rules(self, tokens, customize): super(Python36Parser, self).add_custom_rules(tokens, customize) for i, token in enumerate(tokens): - opname = token.type + opname = token.kind if opname == 'FORMAT_VALUE': rules_str = """ @@ -64,10 +64,10 @@ def custom_classfunc_rule(self, opname, token, customize): if opname.startswith('CALL_FUNCTION_KW'): values = 'expr ' * token.attr - rule = 'call_function ::= expr kwargs_only_36 {token.type}'.format(**locals()) - self.add_unique_rule(rule, token.type, token.attr, customize) + rule = 'call_function ::= expr kwargs_only_36 {token.kind}'.format(**locals()) + self.add_unique_rule(rule, token.kind, token.attr, customize) rule = 'kwargs_only_36 ::= {values} LOAD_CONST'.format(**locals()) - self.add_unique_rule(rule, token.type, token.attr, customize) + self.add_unique_rule(rule, token.kind, token.attr, customize) else: super(Python36Parser, self).custom_classfunc_rule(opname, token, customize) @@ -78,7 +78,7 @@ class Python36ParserSingle(Python36Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python36Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.6: lhs, rhs, tokens, right_recursive = p.checkSets() diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 35f52eacf..2b04a113a 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -21,7 +21,7 @@ class Python37ParserSingle(Python37Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar p = Python37Parser() - p.checkGrammar() + p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.7: lhs, rhs, tokens, right_recursive = p.checkSets() diff --git a/uncompyle6/scanners/scanner22.py b/uncompyle6/scanners/scanner22.py index c3effbc2e..00060faab 100644 --- a/uncompyle6/scanners/scanner22.py +++ b/uncompyle6/scanners/scanner22.py @@ -30,5 +30,5 @@ def __init__(self, show_asm=False): def ingest22(self, co, classname=None, code_objects={}, show_asm=None): tokens, customize = self.parent_ingest(co, classname, code_objects, show_asm) - tokens = [t for t in tokens if t.type != 'SET_LINENO'] + tokens = [t for t in tokens if t.kind != 'SET_LINENO'] return tokens, customize diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index c7297343b..46838538c 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -217,8 +217,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # FIXME: this is a hack to catch stuff like: # if x: continue # the "continue" is not on a new line. - if len(tokens) and tokens[-1].type == 'JUMP_BACK': - tokens[-1].type = intern('CONTINUE') + if len(tokens) and tokens[-1].kind == 'JUMP_BACK': + tokens[-1].kind = intern('CONTINUE') elif op in self.opc.JABS_OPS: pattr = repr(oparg) @@ -258,18 +258,18 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): and self.code[offset+3] not in (self.opc.END_FINALLY, self.opc.POP_BLOCK)): if ((offset in self.linestartoffsets and - tokens[-1].type == 'JUMP_BACK') + tokens[-1].kind == 'JUMP_BACK') or offset not in self.not_continue): op_name = 'CONTINUE' else: # FIXME: this is a hack to catch stuff like: # if x: continue # the "continue" is not on a new line. - if tokens[-1].type == 'JUMP_BACK': + if tokens[-1].kind == 'JUMP_BACK': # We need 'intern' since we have # already have processed the previous # token. - tokens[-1].type = intern('CONTINUE') + tokens[-1].kind = intern('CONTINUE') elif op == self.opc.LOAD_GLOBAL: if offset in self.load_asserts: diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 7046865a6..bcd93635c 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -92,9 +92,9 @@ def patch_continue(self, tokens, offset, op): # the "continue" is not on a new line. n = len(tokens) if (n > 2 and - tokens[-1].type == 'JUMP_BACK' and + tokens[-1].kind == 'JUMP_BACK' and self.code[offset+3] == self.opc.END_FINALLY): - tokens[-1].type = intern('CONTINUE') + tokens[-1].kind = intern('CONTINUE') pass diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 165f9401e..f99c03c51 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -400,12 +400,12 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # the "continue" is not on a new line. # There are other situations where we don't catch # CONTINUE as well. - if tokens[-1].type == 'JUMP_BACK' and tokens[-1].attr <= argval: - if tokens[-2].type == 'BREAK_LOOP': + if tokens[-1].kind == 'JUMP_BACK' and tokens[-1].attr <= argval: + if tokens[-2].kind == 'BREAK_LOOP': del tokens[-1] else: # intern is used because we are changing the *previous* token - tokens[-1].type = intern('CONTINUE') + tokens[-1].kind = intern('CONTINUE') if last_op_was_break and opname == 'CONTINUE': last_op_was_break = False continue diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index a9d5bd01f..19e6efd4e 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -27,14 +27,14 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # The lowest bit of flags indicates whether the # var-keyword argument is placed at the top of the stack if t.op == self.opc.CALL_FUNCTION_EX and t.attr & 1: - t.type = 'CALL_FUNCTION_EX_KW' + t.kind = 'CALL_FUNCTION_EX_KW' pass elif t.op == self.opc.CALL_FUNCTION_KW: - t.type = 'CALL_FUNCTION_KW_{t.attr}'.format(**locals()) + t.kind = 'CALL_FUNCTION_KW_{t.attr}'.format(**locals()) elif t.op == self.opc.BUILD_TUPLE_UNPACK_WITH_CALL: - t.type = 'BUILD_TUPLE_UNPACK_WITH_CALL_%d' % t.attr + t.kind = 'BUILD_TUPLE_UNPACK_WITH_CALL_%d' % t.attr elif t.op == self.opc.BUILD_MAP_UNPACK_WITH_CALL: - t.type = 'BUILD_MAP_UNPACK_WITH_CALL_%d' % t.attr + t.kind = 'BUILD_MAP_UNPACK_WITH_CALL_%d' % t.attr pass return tokens, customize diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index f21848c06..d750aabc0 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -8,7 +8,7 @@ if PYTHON3: intern = sys.intern -class Token(): +class Token: """ Class representing a byte-code instruction. @@ -21,7 +21,7 @@ class Token(): # pattr = argrepr def __init__(self, opname, attr=None, pattr=None, offset=-1, linestart=None, op=None, has_arg=None, opc=None): - self.type = intern(opname) + self.kind = intern(opname) self.op = op self.has_arg = has_arg self.attr = attr @@ -36,20 +36,20 @@ def __init__(self, opname, attr=None, pattr=None, offset=-1, def __eq__(self, o): """ '==', but it's okay if offsets and linestarts are different""" if isinstance(o, Token): - # Both are tokens: compare type and attr + # Both are tokens: compare kind and attr # It's okay if offsets are different - return (self.type == o.type) and (self.pattr == o.pattr) + return (self.kind == o.kind) and (self.pattr == o.pattr) else: - return self.type == o + return self.kind == o def __repr__(self): - return str(self.type) + return str(self.kind) # def __str__(self): # pattr = self.pattr if self.pattr is not None else '' # prefix = '\n%3d ' % self.linestart if self.linestart else (' ' * 6) # return (prefix + - # ('%9s %-18s %r' % (self.offset, self.type, pattr))) + # ('%9s %-18s %r' % (self.offset, self.kind, pattr))) def __str__(self): return self.format(line_prefix='') @@ -59,7 +59,7 @@ def format(self, line_prefix=''): prefix = '\n%s%4d ' % (line_prefix, self.linestart) else: prefix = ' ' * (6 + len(line_prefix)) - offset_opname = '%6s %-17s' % (self.offset, self.type) + offset_opname = '%6s %-17s' % (self.offset, self.kind) if not self.has_arg: return "%s%s" % (prefix, offset_opname) @@ -83,14 +83,14 @@ def format(self, line_prefix=''): pattr = self.opc.cmp_op[self.attr] # And so on. See xdis/bytecode.py get_instructions_bytes pass - elif re.search('_\d+$', self.type): + elif re.search('_\d+$', self.kind): return "%s%s%s" % (prefix, offset_opname, argstr) else: pattr = '' return "%s%s%s %r" % (prefix, offset_opname, argstr, pattr) def __hash__(self): - return hash(self.type) + return hash(self.kind) def __getitem__(self, i): raise IndexError diff --git a/uncompyle6/semantics/check_ast.py b/uncompyle6/semantics/check_ast.py index efea085db..f2b42bde8 100644 --- a/uncompyle6/semantics/check_ast.py +++ b/uncompyle6/semantics/check_ast.py @@ -9,16 +9,16 @@ """ def checker(ast, in_loop, errors): - in_loop = in_loop or ast.type in ('while1stmt', 'whileTruestmt', + in_loop = in_loop or ast.kind in ('while1stmt', 'whileTruestmt', 'whilestmt', 'whileelsestmt', 'while1elsestmt', 'for_block') - if ast.type in ('augassign1', 'augassign2') and ast[0][0] == 'and': + if ast.kind in ('augassign1', 'augassign2') and ast[0][0] == 'and': text = str(ast) error_text = '\n# improper augmented assigment (e.g. +=, *=, ...):\n#\t' + '\n# '.join(text.split("\n")) + '\n' errors.append(error_text) for node in ast: - if not in_loop and node.type in ('continue_stmt', 'break_stmt'): + if not in_loop and node.kind in ('continue_stmt', 'break_stmt'): text = str(node) error_text = '\n# not in loop:\n#\t' + '\n# '.join(text.split("\n")) errors.append(error_text) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index e62fadb81..c461aa3ae 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -17,7 +17,7 @@ def find_all_globals(node, globs): for n in node: if isinstance(n, AST): globs = find_all_globals(n, globs) - elif n.type in ('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL'): + elif n.kind in ('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL'): globs.add(n.pattr) return globs @@ -26,7 +26,7 @@ def find_globals(node, globs): for n in node: if isinstance(n, AST): globs = find_globals(n, globs) - elif n.type in ('STORE_GLOBAL', 'DELETE_GLOBAL'): + elif n.kind in ('STORE_GLOBAL', 'DELETE_GLOBAL'): globs.add(n.pattr) return globs @@ -36,7 +36,7 @@ def find_none(node): if n not in ('return_stmt', 'return_if_stmt'): if find_none(n): return True - elif n.type == 'LOAD_CONST' and n.pattr is None: + elif n.kind == 'LOAD_CONST' and n.pattr is None: return True return False @@ -64,7 +64,7 @@ def build_param(ast, name, default): return name # MAKE_FUNCTION_... or MAKE_CLOSURE_... - assert node[-1].type.startswith('MAKE_') + assert node[-1].kind.startswith('MAKE_') annotate_tuple = None for annotate_last in range(len(node)-1, -1, -1): @@ -80,7 +80,7 @@ def build_param(ast, name, default): i = -1 j = annotate_last-1 l = -len(node) - while j >= l and node[j].type in ('annotate_arg' 'annotate_tuple'): + while j >= l and node[j].kind in ('annotate_arg' 'annotate_tuple'): annotate_args[annotate_tup[i]] = node[j][0] i -= 1 j -= 1 @@ -106,7 +106,7 @@ def build_param(ast, name, default): lambda_index = None if lambda_index and isLambda and iscode(node[lambda_index].attr): - assert node[lambda_index].type == 'LOAD_LAMBDA' + assert node[lambda_index].kind == 'LOAD_LAMBDA' code = node[lambda_index].attr else: code = codeNode.attr @@ -318,7 +318,7 @@ def build_param(ast, name, default): return name # MAKE_FUNCTION_... or MAKE_CLOSURE_... - assert node[-1].type.startswith('MAKE_') + assert node[-1].kind.startswith('MAKE_') args_node = node[-1] if isinstance(args_node.attr, tuple): @@ -334,7 +334,7 @@ def build_param(ast, name, default): lambda_index = None if lambda_index and isLambda and iscode(node[lambda_index].attr): - assert node[lambda_index].type == 'LOAD_LAMBDA' + assert node[lambda_index].kind == 'LOAD_LAMBDA' code = node[lambda_index].attr else: code = codeNode.attr @@ -450,7 +450,7 @@ def build_param(ast, name, default): return name # MAKE_FUNCTION_... or MAKE_CLOSURE_... - assert node[-1].type.startswith('MAKE_') + assert node[-1].kind.startswith('MAKE_') args_node = node[-1] if isinstance(args_node.attr, tuple): @@ -484,7 +484,7 @@ def build_param(ast, name, default): lambda_index = None if lambda_index and isLambda and iscode(node[lambda_index].attr): - assert node[lambda_index].type == 'LOAD_LAMBDA' + assert node[lambda_index].kind == 'LOAD_LAMBDA' code = node[lambda_index].attr else: code = codeNode.attr @@ -585,7 +585,7 @@ def build_param(ast, name, default): for n in node: if n == 'pos_arg': continue - elif self.version >= 3.4 and not (n.type in ('kwargs', 'kwarg')): + elif self.version >= 3.4 and not (n.kind in ('kwargs', 'kwarg')): continue else: self.preorder(n) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 09428a5dd..c92ac63bd 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -438,13 +438,13 @@ def n_call_function(node): for i in mapping[1:]: key = key[i] pass - if key.type.startswith('CALL_FUNCTION_VAR_KW'): + if key.kind.startswith('CALL_FUNCTION_VAR_KW'): # Python 3.5 changes the stack position of *args. kwargs come # after *args whereas in earlier Pythons, *args is at the end # which simpilfiies things from our perspective. # Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX # We will just swap the order to make it look like earlier Python 3. - entry = table[key.type] + entry = table[key.kind] kwarg_pos = entry[2][1] args_pos = kwarg_pos - 1 # Put last node[args_pos] after subsequent kwargs @@ -645,6 +645,20 @@ def is_return_none(self, node): node == AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')])) + # Python 3.x can have be dead code as a result of its optimization? + # So we'll add a # at the end of the return lambda so the rest is ignored + def n_return_lambda(self, node): + if 1 <= len(node) <= 2: + self.preorder(node[0]) + self.write(' # Avoid dead code: ') + self.prune() + else: + # We can't comment out like above because there may be a trailing ')' + # that needs to be written + assert len(node) == 3 and node[2] == 'LAMBDA_MARKER' + self.preorder(node[0]) + self.prune() + def n_return_stmt(self, node): if self.params['isLambda']: self.preorder(node[0]) @@ -719,12 +733,12 @@ def n_buildslice2(self, node): def n_expr(self, node): p = self.prec - if node[0].type.startswith('binary_expr'): + if node[0].kind.startswith('binary_expr'): n = node[0][-1][0] else: n = node[0] - self.prec = PRECEDENCE.get(n.type, -2) + self.prec = PRECEDENCE.get(n.kind, -2) if n == 'LOAD_CONST' and repr(n.pattr)[0] == '-': self.prec = 6 @@ -807,9 +821,9 @@ def n_LOAD_CONST(self, node): self.prune() def n_delete_subscr(self, node): - if node[-2][0] == 'build_list' and node[-2][0][-1].type.startswith('BUILD_TUPLE'): + if node[-2][0] == 'build_list' and node[-2][0][-1].kind.startswith('BUILD_TUPLE'): if node[-2][0][-1] != 'BUILD_TUPLE_0': - node[-2][0].type = 'build_tuple2' + node[-2][0].kind = 'build_tuple2' self.default(node) n_store_subscr = n_binary_subscr = n_delete_subscr @@ -818,9 +832,9 @@ def n_delete_subscr(self, node): def n_tryfinallystmt(self, node): if len(node[1][0]) == 1 and node[1][0][0] == 'stmt': if node[1][0][0][0] == 'trystmt': - node[1][0][0][0].type = 'tf_trystmt' + node[1][0][0][0].kind = 'tf_trystmt' if node[1][0][0][0] == 'tryelsestmt': - node[1][0][0][0].type = 'tf_tryelsestmt' + node[1][0][0][0].kind = 'tf_tryelsestmt' self.default(node) def n_exec_stmt(self, node): @@ -845,26 +859,26 @@ def n_ifelsestmt(self, node, preprocess=False): if len(n) == 1 == len(n[0]) and n[0] == '_stmts': n = n[0][0][0] - elif n[0].type in ('lastc_stmt', 'lastl_stmt'): + elif n[0].kind in ('lastc_stmt', 'lastl_stmt'): n = n[0][0] else: if not preprocess: self.default(node) return - if n.type in ('ifstmt', 'iflaststmt', 'iflaststmtl'): - node.type = 'ifelifstmt' - n.type = 'elifstmt' - elif n.type in ('ifelsestmtr',): - node.type = 'ifelifstmt' - n.type = 'elifelsestmtr' - elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'): - node.type = 'ifelifstmt' + if n.kind in ('ifstmt', 'iflaststmt', 'iflaststmtl'): + node.kind = 'ifelifstmt' + n.kind = 'elifstmt' + elif n.kind in ('ifelsestmtr',): + node.kind = 'ifelifstmt' + n.kind = 'elifelsestmtr' + elif n.kind in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'): + node.kind = 'ifelifstmt' self.n_ifelsestmt(n, preprocess=True) if n == 'ifelifstmt': - n.type = 'elifelifstmt' - elif n.type in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'): - n.type = 'elifelsestmt' + n.kind = 'elifelifstmt' + elif n.kind in ('ifelsestmt', 'ifelsestmtc', 'ifelsestmtl'): + n.kind = 'elifelsestmt' if not preprocess: self.default(node) @@ -873,7 +887,7 @@ def n_ifelsestmt(self, node, preprocess=False): def n_ifelsestmtr(self, node): if node[2] == 'COME_FROM': return_stmts_node = node[3] - node.type = 'ifelsestmtr2' + node.kind = 'ifelsestmtr2' else: return_stmts_node = node[2] if len(return_stmts_node) != 2: @@ -904,7 +918,7 @@ def n_ifelsestmtr(self, node): for n in return_stmts_node[0]: if (n[0] == 'ifstmt' and n[0][1][0] == 'return_if_stmts'): if prev_stmt_is_if_ret: - n[0].type = 'elifstmt' + n[0].kind = 'elifstmt' prev_stmt_is_if_ret = True else: prev_stmt_is_if_ret = False @@ -924,7 +938,7 @@ def n_ifelsestmtr(self, node): def n_elifelsestmtr(self, node): if node[2] == 'COME_FROM': return_stmts_node = node[3] - node.type = 'elifelsestmtr2' + node.kind = 'elifelsestmtr2' else: return_stmts_node = node[2] @@ -944,7 +958,7 @@ def n_elifelsestmtr(self, node): self.indent_less() for n in return_stmts_node[0]: - n[0].type = 'elifstmt' + n[0].kind = 'elifstmt' self.preorder(n) self.println(self.indent, 'else:') self.indent_more() @@ -954,7 +968,7 @@ def n_elifelsestmtr(self, node): def n_import_as(self, node): store_node = node[-1][-1] - assert store_node.type.startswith('STORE_') + assert store_node.kind.startswith('STORE_') iname = node[0].pattr # import name sname = store_node.pattr # store_name if iname and iname == sname or iname.startswith(sname + '.'): @@ -1074,7 +1088,7 @@ def n_list_compr_pypy27(self, node): """ p = self.prec self.prec = 27 - if node[-1].type == 'list_iter': + if node[-1].kind == 'list_iter': n = node[-1] elif self.is_pypy and node[-1] == 'JUMP_BACK': n = node[-2] @@ -1198,7 +1212,7 @@ def n_setcomp(self, node): self.write('{') if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']: self.comprehension_walk3(node, 1, 0) - elif node[0].type == 'load_closure' and self.version >= 3.0: + elif node[0].kind == 'load_closure' and self.version >= 3.0: self.setcomprehension_walk3(node, collection_index=4) else: self.comprehension_walk(node, iter_index=4) @@ -1265,7 +1279,7 @@ def comprehension_walk3(self, node, iter_index, code_index=-5): # Python 2.7+ starts including set_comp_body # Python 3.5+ starts including setcomp_func - assert n.type in ('lc_body', 'comp_body', 'setcomp_func', 'set_comp_body'), ast + assert n.kind in ('lc_body', 'comp_body', 'setcomp_func', 'set_comp_body'), ast assert designator, "Couldn't find designator in list/set comprehension" self.preorder(n[0]) @@ -1315,7 +1329,7 @@ def listcomprehension_walk2(self, node): n = n[3] elif n in ('list_if', 'list_if_not'): # FIXME: just a guess - if n[0].type == 'expr': + if n[0].kind == 'expr': list_if = n else: list_if = n[1] @@ -1336,7 +1350,7 @@ def listcomprehension_walk2(self, node): def n_listcomp(self, node): self.write('[') - if node[0].type == 'load_closure': + if node[0].kind == 'load_closure': self.listcomprehension_walk2(node) else: self.comprehension_walk3(node, 1, 0) @@ -1373,7 +1387,7 @@ def setcomprehension_walk3(self, node, collection_index): n = n[3] elif n in ('list_if', 'list_if_not', 'comp_if', 'comp_if_not'): # FIXME: just a guess - if n[0].type == 'expr': + if n[0].kind == 'expr': list_if = n else: list_if = n[1] @@ -1525,10 +1539,10 @@ def print_super_classes(self, node): def print_super_classes3(self, node): n = len(node)-1 - if node.type != 'expr': - assert node[n].type.startswith('CALL_FUNCTION') + if node.kind != 'expr': + assert node[n].kind.startswith('CALL_FUNCTION') for i in range(n-2, 0, -1): - if not node[i].type in ['expr', 'LOAD_CLASSNAME']: + if not node[i].kind in ['expr', 'LOAD_CLASSNAME']: break pass @@ -1568,7 +1582,7 @@ def n_mapexpr(self, node): line_number = self.line_number if self.version >= 3.0 and not self.is_pypy: - if node[0].type.startswith('kvlist'): + if node[0].kind.startswith('kvlist'): # Python 3.5+ style key/value list in mapexpr kv_node = node[0] l = list(kv_node) @@ -1591,11 +1605,11 @@ def n_mapexpr(self, node): i += 2 pass pass - elif len(node) > 1 and node[1].type.startswith('kvlist'): + elif len(node) > 1 and node[1].kind.startswith('kvlist'): # Python 3.0..3.4 style key/value list in mapexpr kv_node = node[1] l = list(kv_node) - if len(l) > 0 and l[0].type == 'kv3': + if len(l) > 0 and l[0].kind == 'kv3': # Python 3.2 does this kv_node = node[1][0] l = list(kv_node) @@ -1620,7 +1634,7 @@ def n_mapexpr(self, node): i += 3 pass pass - elif node[-1].type.startswith('BUILD_CONST_KEY_MAP'): + elif node[-1].kind.startswith('BUILD_CONST_KEY_MAP'): # Python 3.6+ style const map keys = node[-2].pattr values = node[:-2] @@ -1645,7 +1659,7 @@ def n_mapexpr(self, node): pass else: # Python 2 style kvlist - assert node[-1].type.startswith('kvlist') + assert node[-1].kind.startswith('kvlist') kv_node = node[-1] # goto kvlist first_time = True @@ -1711,7 +1725,7 @@ def n_build_list(self, node): p = self.prec self.prec = 100 lastnode = node.pop() - lastnodetype = lastnode.type + lastnodetype = lastnode.kind # If this build list is inside a CALL_FUNCTION_VAR, # then the first * has already been printed. @@ -1781,7 +1795,7 @@ def n_build_list(self, node): self.prune() def n_unpack(self, node): - if node[0].type.startswith('UNPACK_EX'): + if node[0].kind.startswith('UNPACK_EX'): # Python 3+ before_count, after_count = node[0].attr for i in range(before_count+1): @@ -1796,8 +1810,8 @@ def n_unpack(self, node): self.prune() return for n in node[1:]: - if n[0].type == 'unpack': - n[0].type = 'unpack_w_parens' + if n[0].kind == 'unpack': + n[0].kind = 'unpack_w_parens' self.default(node) n_unpack_w_parens = n_unpack @@ -1806,25 +1820,25 @@ def n_assign(self, node): # A horrible hack for Python 3.0 .. 3.2 if 3.0 <= self.version <= 3.2 and len(node) == 2: if (node[0][0] == 'LOAD_FAST' and node[0][0].pattr == '__locals__' and - node[1][0].type == 'STORE_LOCALS'): + node[1][0].kind == 'STORE_LOCALS'): self.prune() self.default(node) def n_assign2(self, node): for n in node[-2:]: if n[0] == 'unpack': - n[0].type = 'unpack_w_parens' + n[0].kind = 'unpack_w_parens' self.default(node) def n_assign3(self, node): for n in node[-3:]: if n[0] == 'unpack': - n[0].type = 'unpack_w_parens' + n[0].kind = 'unpack_w_parens' self.default(node) def n_except_cond2(self, node): if node[-2][0] == 'unpack': - node[-2][0].type = 'unpack_w_parens' + node[-2][0].kind = 'unpack_w_parens' self.default(node) def template_engine(self, entry, startnode): @@ -1833,7 +1847,7 @@ def template_engine(self, entry, startnode): specifications such as %c, %C, and so on. """ - # self.println("----> ", startnode.type, ', ', entry[0]) + # self.println("----> ", startnode.kind, ', ', entry[0]) fmt = entry[0] arg = 1 i = 0 @@ -1861,7 +1875,7 @@ def template_engine(self, entry, startnode): # Used mostly on the LHS of an assignment # BUILD_TUPLE_n is pretty printed and may take care of other uses. elif typ == ',': - if (node.type in ('unpack', 'unpack_w_parens') and + if (node.kind in ('unpack', 'unpack_w_parens') and node[0].attr == 1): self.write(',') elif typ == 'c': @@ -1933,8 +1947,8 @@ def default(self, node): key = key[i] pass - if key.type in table: - self.template_engine(table[key.type], node) + if key.kind in table: + self.template_engine(table[key.kind], node) self.prune() def customize(self, customize): @@ -2154,10 +2168,10 @@ def build_ast(self, tokens, customize, isLambda=False, if isLambda: for t in tokens: - if t.type == 'RETURN_END_IF': - t.type = 'RETURN_END_IF_LAMBDA' - elif t.type == 'RETURN_VALUE': - t.type = 'RETURN_VALUE_LAMBDA' + if t.kind == 'RETURN_END_IF': + t.kind = 'RETURN_END_IF_LAMBDA' + elif t.kind == 'RETURN_VALUE': + t.kind = 'RETURN_VALUE_LAMBDA' tokens.append(Token('LAMBDA_MARKER')) try: ast = python_parser.parse(self.p, tokens, customize) @@ -2174,10 +2188,10 @@ def build_ast(self, tokens, customize, isLambda=False, # than fight (with the grammar to not emit "return None"). if self.hide_internal: if len(tokens) >= 2 and not noneInNames: - if tokens[-1].type in ('RETURN_VALUE', 'RETURN_VALUE_LAMBDA'): + if tokens[-1].kind in ('RETURN_VALUE', 'RETURN_VALUE_LAMBDA'): # Python 3.4's classes can add a "return None" which is # invalid syntax. - if tokens[-2].type == 'LOAD_CONST': + if tokens[-2].kind == 'LOAD_CONST': if isTopLevel or tokens[-2].pattr is None: del tokens[-2:] else: diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index a353c8e25..80f02c7d9 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -242,18 +242,18 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, scanner.resetTokenClass() # restore Token class targets1 = dis.findlabels(code_obj1.co_code) - tokens1 = [t for t in tokens1 if t.type != 'COME_FROM'] - tokens2 = [t for t in tokens2 if t.type != 'COME_FROM'] + tokens1 = [t for t in tokens1 if t.kind != 'COME_FROM'] + tokens2 = [t for t in tokens2 if t.kind != 'COME_FROM'] i1 = 0; i2 = 0 offset_map = {}; check_jumps = {} while i1 < len(tokens1): if i2 >= len(tokens2): if len(tokens1) == len(tokens2) + 2 \ - and tokens1[-1].type == 'RETURN_VALUE' \ - and tokens1[-2].type == 'LOAD_CONST' \ + and tokens1[-1].kind == 'RETURN_VALUE' \ + and tokens1[-2].kind == 'LOAD_CONST' \ and tokens1[-2].pattr is None \ - and tokens1[-3].type == 'RETURN_VALUE': + and tokens1[-3].kind == 'RETURN_VALUE': break else: raise CmpErrorCodeLen(name, tokens1, tokens2) @@ -265,13 +265,13 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, raise CmpErrorCode(name, tokens1[idx1].offset, tokens1[idx1], tokens2[idx2], tokens1, tokens2) - if tokens1[i1].type != tokens2[i2].type: - if tokens1[i1].type == 'LOAD_CONST' == tokens2[i2].type: + if tokens1[i1].kind != tokens2[i2].kind: + if tokens1[i1].kind == 'LOAD_CONST' == tokens2[i2].kind: i = 1 - while tokens1[i1+i].type == 'LOAD_CONST': + while tokens1[i1+i].kind == 'LOAD_CONST': i += 1 - if tokens1[i1+i].type.startswith(('BUILD_TUPLE', 'BUILD_LIST')) \ - and i == int(tokens1[i1+i].type.split('_')[-1]): + if tokens1[i1+i].kind.startswith(('BUILD_TUPLE', 'BUILD_LIST')) \ + and i == int(tokens1[i1+i].kind.split('_')[-1]): t = tuple([ elem.pattr for elem in tokens1[i1:i1+i] ]) if t != tokens2[i2].pattr: raise CmpErrorCode(name, tokens1[i1].offset, tokens1[i1], @@ -279,60 +279,60 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, i1 += i + 1 i2 += 1 continue - elif i == 2 and tokens1[i1+i].type == 'ROT_TWO' and tokens2[i2+1].type == 'UNPACK_SEQUENCE_2': + elif i == 2 and tokens1[i1+i].kind == 'ROT_TWO' and tokens2[i2+1].kind == 'UNPACK_SEQUENCE_2': i1 += 3 i2 += 2 continue - elif i == 2 and tokens1[i1+i].type in BIN_OP_FUNCS: - f = BIN_OP_FUNCS[tokens1[i1+i].type] + elif i == 2 and tokens1[i1+i].kind in BIN_OP_FUNCS: + f = BIN_OP_FUNCS[tokens1[i1+i].kind] if f(tokens1[i1].pattr, tokens1[i1+1].pattr) == tokens2[i2].pattr: i1 += 3 i2 += 1 continue - elif tokens1[i1].type == 'UNARY_NOT': - if tokens2[i2].type == 'POP_JUMP_IF_TRUE': - if tokens1[i1+1].type == 'POP_JUMP_IF_FALSE': + elif tokens1[i1].kind == 'UNARY_NOT': + if tokens2[i2].kind == 'POP_JUMP_IF_TRUE': + if tokens1[i1+1].kind == 'POP_JUMP_IF_FALSE': i1 += 2 i2 += 1 continue - elif tokens2[i2].type == 'POP_JUMP_IF_FALSE': - if tokens1[i1+1].type == 'POP_JUMP_IF_TRUE': + elif tokens2[i2].kind == 'POP_JUMP_IF_FALSE': + if tokens1[i1+1].kind == 'POP_JUMP_IF_TRUE': i1 += 2 i2 += 1 continue - elif tokens1[i1].type in ('JUMP_FORWARD', 'JUMP_BACK') \ - and tokens1[i1-1].type == 'RETURN_VALUE' \ - and tokens2[i2-1].type in ('RETURN_VALUE', 'RETURN_END_IF') \ + elif tokens1[i1].kind in ('JUMP_FORWARD', 'JUMP_BACK') \ + and tokens1[i1-1].kind == 'RETURN_VALUE' \ + and tokens2[i2-1].kind in ('RETURN_VALUE', 'RETURN_END_IF') \ and int(tokens1[i1].offset) not in targets1: i1 += 1 continue - elif tokens1[i1].type == 'JUMP_FORWARD' and tokens2[i2].type == 'JUMP_BACK' \ - and tokens1[i1+1].type == 'JUMP_BACK' and tokens2[i2+1].type == 'JUMP_BACK' \ + elif tokens1[i1].kind == 'JUMP_FORWARD' and tokens2[i2].kind == 'JUMP_BACK' \ + and tokens1[i1+1].kind == 'JUMP_BACK' and tokens2[i2+1].kind == 'JUMP_BACK' \ and int(tokens1[i1].pattr) == int(tokens1[i1].offset) + 3: if int(tokens1[i1].pattr) == int(tokens1[i1+1].offset): i1 += 2 i2 += 2 continue - elif tokens1[i1].type == 'LOAD_NAME' and tokens2[i2].type == 'LOAD_CONST' \ + elif tokens1[i1].kind == 'LOAD_NAME' and tokens2[i2].kind == 'LOAD_CONST' \ and tokens1[i1].pattr == 'None' and tokens2[i2].pattr is None: pass - elif tokens1[i1].type == 'LOAD_GLOBAL' and tokens2[i2].type == 'LOAD_NAME' \ + elif tokens1[i1].kind == 'LOAD_GLOBAL' and tokens2[i2].kind == 'LOAD_NAME' \ and tokens1[i1].pattr == tokens2[i2].pattr: pass - elif tokens1[i1].type == 'LOAD_ASSERT' and tokens2[i2].type == 'LOAD_NAME' \ + elif tokens1[i1].kind == 'LOAD_ASSERT' and tokens2[i2].kind == 'LOAD_NAME' \ and tokens1[i1].pattr == tokens2[i2].pattr: pass - elif (tokens1[i1].type == 'RETURN_VALUE' and - tokens2[i2].type == 'RETURN_END_IF'): + elif (tokens1[i1].kind == 'RETURN_VALUE' and + tokens2[i2].kind == 'RETURN_END_IF'): pass - elif (tokens1[i1].type == 'BUILD_TUPLE_0' and + elif (tokens1[i1].kind == 'BUILD_TUPLE_0' and tokens2[i2].pattr == ()): pass else: raise CmpErrorCode(name, tokens1[i1].offset, tokens1[i1], tokens2[i2], tokens1, tokens2) - elif tokens1[i1].type in JUMP_OPS and tokens1[i1].pattr != tokens2[i2].pattr: - if tokens1[i1].type == 'JUMP_BACK': + elif tokens1[i1].kind in JUMP_OPS and tokens1[i1].pattr != tokens2[i2].pattr: + if tokens1[i1].kind == 'JUMP_BACK': dest1 = int(tokens1[i1].pattr) dest2 = int(tokens2[i2].pattr) if offset_map[dest1] != dest2: @@ -387,28 +387,28 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, class Token(scanner.Token): """Token class with changed semantics for 'cmp()'.""" def __cmp__(self, o): - t = self.type # shortcut - if t == 'BUILD_TUPLE_0' and o.type == 'LOAD_CONST' and o.pattr == (): + t = self.kind # shortcut + if t == 'BUILD_TUPLE_0' and o.kind == 'LOAD_CONST' and o.pattr == (): return 0 - if t == 'COME_FROM' == o.type: + if t == 'COME_FROM' == o.kind: return 0 - if t == 'PRINT_ITEM_CONT' and o.type == 'PRINT_ITEM': + if t == 'PRINT_ITEM_CONT' and o.kind == 'PRINT_ITEM': return 0 - if t == 'RETURN_VALUE' and o.type == 'RETURN_END_IF': + if t == 'RETURN_VALUE' and o.kind == 'RETURN_END_IF': return 0 - if t == 'JUMP_IF_FALSE_OR_POP' and o.type == 'POP_JUMP_IF_FALSE': + if t == 'JUMP_IF_FALSE_OR_POP' and o.kind == 'POP_JUMP_IF_FALSE': return 0 if JUMP_OPS and t in JUMP_OPS: # ignore offset - return t == o.type - return (t == o.type) or self.pattr == o.pattr + return t == o.kind + return (t == o.kind) or self.pattr == o.pattr def __repr__(self): - return '%s %s (%s)' % (str(self.type), str(self.attr), + return '%s %s (%s)' % (str(self.kind), str(self.attr), repr(self.pattr)) def __str__(self): - return '%s\t%-17s %r' % (self.offset, self.type, self.pattr) + return '%s\t%-17s %r' % (self.offset, self.kind, self.pattr) def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False): """Compare a .pyc with a source code file.""" @@ -442,4 +442,4 @@ def compare_files(pyc_filename1, pyc_filename2, weak_verify=False): t2 = Token('LOAD_CONST', -421, 'code_object _expandLang', 55) print(repr(t1)) print(repr(t2)) - print(t1.type == t2.type, t1.attr == t2.attr) + print(t1.kind == t2.kind, t1.attr == t2.attr) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index f6cb55671..83bf37400 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.12.0' +VERSION='2.13.0' From 0b198ee8816066245aef84e3282187f18c27aecf Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Oct 2017 23:02:20 -0400 Subject: [PATCH 056/489] Sync with master --- uncompyle6/semantics/fragments.py | 62 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 6bd613623..35ebcba85 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -308,11 +308,11 @@ def n_buildslice2(self, node): def n_expr(self, node): start = len(self.f.getvalue()) p = self.prec - if node[0].type.startswith('binary_expr'): + if node[0].kind.startswith('binary_expr'): n = node[0][-1][0] else: n = node[0] - self.prec = PRECEDENCE.get(n.type, -2) + self.prec = PRECEDENCE.get(n.kind, -2) if n == 'LOAD_CONST' and repr(n.pattr)[0] == '-': n.parent = node self.set_pos_info(n, start, len(self.f.getvalue())) @@ -405,7 +405,7 @@ def n_exec_stmt(self, node): def n_ifelsestmtr(self, node): if node[2] == 'COME_FROM': return_stmts_node = node[3] - node.type = 'ifelsestmtr2' + node.kind = 'ifelsestmtr2' else: return_stmts_node = node[2] if len(return_stmts_node) != 2: @@ -438,7 +438,7 @@ def n_ifelsestmtr(self, node): for n in return_stmts_node[0]: if (n[0] == 'ifstmt' and n[0][1][0] == 'return_if_stmts'): if prev_stmt_is_if_ret: - n[0].type = 'elifstmt' + n[0].kind = 'elifstmt' prev_stmt_is_if_ret = True else: prev_stmt_is_if_ret = False @@ -477,7 +477,7 @@ def n_elifelsestmtr(self, node): self.indent_less() for n in node[2][0]: - n[0].type = 'elifstmt' + n[0].kind = 'elifstmt' n.parent = node self.preorder(n) self.println(self.indent, 'else:') @@ -493,7 +493,7 @@ def n_import_as(self, node): iname = node[0].pattr store_import_node = node[-1][-1] - assert store_import_node.type.startswith('STORE_') + assert store_import_node.kind.startswith('STORE_') sname = store_import_node.pattr self.write(iname) @@ -554,7 +554,7 @@ def n_list_compr(self, node): elif n == 'list_if': n = n[2] elif n == 'list_if_not': n= n[2] assert n == 'lc_body' - if node[0].type.startswith('BUILD_LIST'): + if node[0].kind.startswith('BUILD_LIST'): start = len(self.f.getvalue()) self.set_pos_info(node[0], start, start+1) self.write( '[ ') @@ -687,7 +687,7 @@ def comprehension_walk3(self, node, iter_index, code_index=-5): # Python 2.7+ starts including set_comp_body # Python 3.5+ starts including setcomp_func - assert n.type in ('lc_body', 'comp_body', 'setcomp_func', 'set_comp_body'), ast + assert n.kind in ('lc_body', 'comp_body', 'setcomp_func', 'set_comp_body'), ast assert designator, "Couldn't find designator in list/set comprehension" old_name = self.name @@ -714,7 +714,7 @@ def comprehension_walk3(self, node, iter_index, code_index=-5): self.preorder(if_node) self.prec = p self.name = old_name - if node[-1].type.startswith('CALL_FUNCTION'): + if node[-1].kind.startswith('CALL_FUNCTION'): self.set_pos_info(node[-1], gen_start, len(self.f.getvalue())) def listcomprehension_walk2(self, node): @@ -743,7 +743,7 @@ def listcomprehension_walk2(self, node): n = n[3] elif n in ('list_if', 'list_if_not'): # FIXME: just a guess - if n[0].type == 'expr': + if n[0].kind == 'expr': list_if = n else: list_if = n[1] @@ -789,7 +789,7 @@ def n_setcomp(self, node): start = len(self.f.getvalue()) self.set_pos_info(node[0], start-1, start) self.comprehension_walk3(node, 1, 0) - elif node[0].type == 'load_closure': + elif node[0].kind == 'load_closure': self.setcomprehension_walk3(node, collection_index=4) else: self.comprehension_walk(node, iter_index=4) @@ -808,7 +808,7 @@ def n_setcomp_func(self, node): self.set_pos_info(node[0], start, len(self.f.getvalue())) self.write(': {') start = len(self.f.getvalue()) - assert node[0].type.startswith('BUILD_SET') + assert node[0].kind.startswith('BUILD_SET') self.set_pos_info(node[0], start-1, start) designator = node[3] assert designator == 'designator' @@ -817,7 +817,7 @@ def n_setcomp_func(self, node): fin = len(self.f.getvalue()) self.set_pos_info(designator, start, fin) for_iter_node = node[2] - assert for_iter_node.type == 'FOR_ITER' + assert for_iter_node.kind == 'FOR_ITER' self.set_pos_info(for_iter_node, start, fin) self.write(" for ") self.preorder(designator) @@ -836,7 +836,7 @@ def n_setcomp_func(self, node): def n_listcomp(self, node): self.write('[') - if node[0].type == 'load_closure': + if node[0].kind == 'load_closure': self.listcomprehension_walk2(node) else: if node[0] == 'LOAD_LISTCOMP': @@ -850,7 +850,7 @@ def n__ifstmts_jump_exit(self, node): if len(node) > 1: if (node[0] == 'c_stmts_opt' and node[0][0] == 'passstmt' and - node[1].type.startswith('JUMP_FORWARD')): + node[1].kind.startswith('JUMP_FORWARD')): self.set_pos_info(node[1], node[0][0].start, node[0][0].finish) def setcomprehension_walk3(self, node, collection_index): @@ -881,7 +881,7 @@ def setcomprehension_walk3(self, node, collection_index): n = n[3] elif n in ('list_if', 'list_if_not', 'comp_if', 'comp_if_not'): # FIXME: just a guess - if n[0].type == 'expr': + if n[0].kind == 'expr': list_if = n else: list_if = n[1] @@ -1044,8 +1044,8 @@ def build_ast(self, tokens, customize, isLambda=False, noneInNames=False): # NOTE: this differs from behavior in pysource.py if len(tokens) >= 2 and not noneInNames: - if tokens[-1].type == 'RETURN_VALUE': - if tokens[-2].type != 'LOAD_CONST': + if tokens[-1].kind == 'RETURN_VALUE': + if tokens[-2].kind != 'LOAD_CONST': tokens.append(Token('RETURN_LAST')) if len(tokens) == 0: return @@ -1299,10 +1299,10 @@ def print_super_classes3(self, node): # as a custom rule start = len(self.f.getvalue()) n = len(node)-1 - assert node[n].type.startswith('CALL_FUNCTION') + assert node[n].kind.startswith('CALL_FUNCTION') for i in range(n-2, 0, -1): - if not node[i].type in ['expr', 'LOAD_CLASSNAME']: + if not node[i].kind in ['expr', 'LOAD_CLASSNAME']: break pass @@ -1337,7 +1337,7 @@ def n_mapexpr(self, node): self.write('{') if self.version > 3.0: - if node[0].type.startswith('kvlist'): + if node[0].kind.startswith('kvlist'): # Python 3.5+ style key/value list in mapexpr kv_node = node[0] l = list(kv_node) @@ -1352,11 +1352,11 @@ def n_mapexpr(self, node): i += 2 pass pass - elif node[1].type.startswith('kvlist'): + elif node[1].kind.startswith('kvlist'): # Python 3.0..3.4 style key/value list in mapexpr kv_node = node[1] l = list(kv_node) - if len(l) > 0 and l[0].type == 'kv3': + if len(l) > 0 and l[0].kind == 'kv3': # Python 3.2 does this kv_node = node[1][0] l = list(kv_node) @@ -1379,7 +1379,7 @@ def n_mapexpr(self, node): pass else: # Python 2 style kvlist - assert node[-1].type.startswith('kvlist') + assert node[-1].kind.startswith('kvlist') kv_node = node[-1] # goto kvlist for kv in kv_node: @@ -1418,7 +1418,7 @@ def n_build_list(self, node): p = self.prec self.prec = 100 n = node.pop() - lastnode = n.type + lastnode = n.kind start = len(self.f.getvalue()) if lastnode.startswith('BUILD_LIST'): self.write('['); endchar = ']' @@ -1533,7 +1533,7 @@ def template_engine(self, entry, startnode): # for loops have two positions that correspond to a single text # location. In "for i in ..." there is the initialization "i" code as well # as the iteration code with "i" - match = re.search(r'^for', startnode.type) + match = re.search(r'^for', startnode.kind) if match and entry[arg] == 3: self.set_pos_info(node[0], start, finish) for n in node[2]: @@ -1627,7 +1627,7 @@ def template_engine(self, entry, startnode): # 2. subroutine calls. It the last op is the call and for purposes of printing # we don't need to print anything special there. However it encompases the # entire string of the node fn(...) - match = re.search(r'^call_function', startnode.type) + match = re.search(r'^call_function', startnode.kind) if match: last_node = startnode[-1] # import traceback; traceback.print_stack() @@ -1768,7 +1768,7 @@ def deparse_test(co, is_pypy=IS_PYPY): nodeInfo = walk.offsets[name, offset] node = nodeInfo.node extractInfo = walk.extract_node_info(node) - print("code: %s" % node.type) + print("code: %s" % node.kind) # print extractInfo print(extractInfo.selectedText) print(extractInfo.selectedLine) @@ -1778,7 +1778,7 @@ def deparse_test(co, is_pypy=IS_PYPY): print("Contained in...") print(extractInfo.selectedLine) print(extractInfo.markerLine) - print("code: %s" % p.type) + print("code: %s" % p.kind) print('=' * 40) pass pass @@ -1797,7 +1797,7 @@ def deparse_test_around(offset, name, co, is_pypy=IS_PYPY): nodeInfo = walk.offsets[name, offset] node = nodeInfo.node extractInfo = walk.extract_node_info(node) - print("code: %s" % node.type) + print("code: %s" % node.kind) # print extractInfo print(extractInfo.selectedText) print(extractInfo.selectedLine) @@ -1807,7 +1807,7 @@ def deparse_test_around(offset, name, co, is_pypy=IS_PYPY): print("Contained in...") print(extractInfo.selectedLine) print(extractInfo.markerLine) - print("code: %s" % p.type) + print("code: %s" % p.kind) print('=' * 40) pass pass From 77b93c5f21e101c0c1efa9fdce6fbf3082edd7c4 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Oct 2017 23:04:25 -0400 Subject: [PATCH 057/489] Sync with master --- pytest/test_grammar.py | 2 +- uncompyle6/parsers/parse26.py | 2 +- uncompyle6/parsers/parse27.py | 2 +- uncompyle6/parsers/parse34.py | 2 +- uncompyle6/parsers/parse35.py | 2 +- uncompyle6/parsers/parse36.py | 2 +- uncompyle6/parsers/parse37.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index b92e163d5..fd18b2b0f 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -14,7 +14,7 @@ def check_tokens(tokens, opcode_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 = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() expect_lhs = set(['expr1024', 'pos_arg']) unused_rhs = set(['build_list', 'call_function', 'mkfunc', 'mklambda', diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index c68efb8c1..1f453b523 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -279,7 +279,7 @@ class Python26ParserSingle(Python2Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 2.6: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 953ba5acc..e392da5e4 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -132,7 +132,7 @@ class Python27ParserSingle(Python27Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 2.7: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index bd6be275c..bba5c29d5 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -32,7 +32,7 @@ class Python34ParserSingle(Python34Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.4: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index 12bd5fbd2..52b6e112b 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -167,7 +167,7 @@ class Python35ParserSingle(Python35Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.5: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 7a369997a..87bbd4f81 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -81,7 +81,7 @@ class Python36ParserSingle(Python36Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.6: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 2b04a113a..50cb3a502 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -24,7 +24,7 @@ class Python37ParserSingle(Python37Parser, PythonParserSingle): p.check_grammar() from uncompyle6 import PYTHON_VERSION, IS_PYPY if PYTHON_VERSION == 3.7: - lhs, rhs, tokens, right_recursive = p.checkSets() + lhs, rhs, tokens, right_recursive = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) opcode_set = set(s.opc.opname).union(set( From 9e37495493b75716b4f8fbfbe69cecfe6d582186 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Oct 2017 23:06:22 -0400 Subject: [PATCH 058/489] Sync with master --- pytest/test_grammar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index fd18b2b0f..a2299cca1 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -19,7 +19,8 @@ def check_tokens(tokens, opcode_set): unused_rhs = set(['build_list', 'call_function', 'mkfunc', 'mklambda', 'unpack', 'unpack_list']) - expect_right_recursive = [['designList', ('designator', 'DUP_TOP', 'designList')]] + expect_right_recursive = frozenset([('designList', + ('designator', 'DUP_TOP', 'designList'))]) if PYTHON3: expect_lhs.add('load_genexpr') From e80b36347a70511e22dbde8bc1c533547d5c9791 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 11 Oct 2017 20:43:17 -0400 Subject: [PATCH 059/489] Remove creaping Python 2.6ism --- uncompyle6/parser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 2fe57af5e..6d927d0f4 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -3,7 +3,7 @@ # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock """ -Common uncompyle parser routines. +Common parser routines. """ import sys @@ -96,7 +96,10 @@ def debug_reduce(self, rule, tokens, parent, last_token_pos): def fix(c): s = str(c) last_token_pos = s.find('_') - return s if last_token_pos == -1 else s[:last_token_pos] + if last_token_pos == -1: + return s + else: + return s[:last_token_pos] prefix = '' if parent and tokens: From 5df384bb7150cef194cafe7ac7c2d66d5ae7c945 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 11 Oct 2017 21:16:35 -0400 Subject: [PATCH 060/489] Some admin tools I use --- admin-tools/README.md | 11 +++++ admin-tools/check-newer-versions.sh | 18 ++++++++ admin-tools/check-older-versions.sh | 18 ++++++++ admin-tools/how-to-make-a-release.txt | 59 +++++++++++++++++++++++++++ admin-tools/make-dist-newer.sh | 14 +++++++ admin-tools/make-dist-older.sh | 18 ++++++++ admin-tools/pyenv-newer-versions | 5 +++ admin-tools/pyenv-older-versions | 5 +++ admin-tools/setup-master.sh | 16 ++++++++ admin-tools/setup-python-2.4.sh | 16 ++++++++ 10 files changed, 180 insertions(+) create mode 100644 admin-tools/README.md create mode 100644 admin-tools/check-newer-versions.sh create mode 100644 admin-tools/check-older-versions.sh create mode 100644 admin-tools/how-to-make-a-release.txt create mode 100644 admin-tools/make-dist-newer.sh create mode 100644 admin-tools/make-dist-older.sh create mode 100644 admin-tools/pyenv-newer-versions create mode 100644 admin-tools/pyenv-older-versions create mode 100644 admin-tools/setup-master.sh create mode 100644 admin-tools/setup-python-2.4.sh diff --git a/admin-tools/README.md b/admin-tools/README.md new file mode 100644 index 000000000..0dce281f5 --- /dev/null +++ b/admin-tools/README.md @@ -0,0 +1,11 @@ +Making a release is a somewhat tedious process so I've automated it a little + + +Here are tools that I, rocky, use to check and build a distribution. + +They are customized to my environment: +- I use pyenv to various Python versions installed +- I have git repos for xdis, and spark parser at the same level as uncompyle6 + +There may be other rocky-specific things that need customization. +how-to-make-a-release.txt has overall how I make a release diff --git a/admin-tools/check-newer-versions.sh b/admin-tools/check-newer-versions.sh new file mode 100644 index 000000000..a6d27051f --- /dev/null +++ b/admin-tools/check-newer-versions.sh @@ -0,0 +1,18 @@ +#!/bin/bash +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-newer-versions ; then + exit $? +fi +if ! source ./setup-master.sh ; then + exit $? +fi +cd .. +for version in $PYVERSIONS; do + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check; then + exit $? + fi +done diff --git a/admin-tools/check-older-versions.sh b/admin-tools/check-older-versions.sh new file mode 100644 index 000000000..53a00f6f3 --- /dev/null +++ b/admin-tools/check-older-versions.sh @@ -0,0 +1,18 @@ +#!/bin/bash +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-older-versions ; then + exit $? +fi +if ! source ./setup-python-2.4.sh ; then + exit $? +fi +cd .. +for version in $PYVERSIONS; do + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check ; then + exit $? + fi +done diff --git a/admin-tools/how-to-make-a-release.txt b/admin-tools/how-to-make-a-release.txt new file mode 100644 index 000000000..38e346acb --- /dev/null +++ b/admin-tools/how-to-make-a-release.txt @@ -0,0 +1,59 @@ +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 make-dist/pyenv-versions + + +Test all python versions: + for version in $PYVERSIONS; do pyenv local $version && make clean && python setup.py develop && make check; done + +# Switch to python-2.4 and build that first... + + +---- + +./setup-python-2.4.sh + +rm ChangeLog +git merge master +check uncompyle6/version.py to see it has changed +make ChangeLog + +Update NEWS from master branch + +git commit -m"Get ready for release $VERSION" . + +PYVERSIONS='2.4.6 2.5.6' + +for version in $PYVERSIONS; do pyenv local $version && make clean && python setup.py develop && make check; done + +make-dist-older.sh + +git tag release-python-2.4-$VERSION +git push --tags + +. ./setup-master.sh + +./make-dist-newer.sh + +git tag release-$VERSION + + +twine upload dist/uncompyle6-${VERSION}* diff --git a/admin-tools/make-dist-newer.sh b/admin-tools/make-dist-newer.sh new file mode 100644 index 000000000..4f10e3b1a --- /dev/null +++ b/admin-tools/make-dist-newer.sh @@ -0,0 +1,14 @@ +#!/bin/bash +PACKAGE=uncompyle6 +source $PACKAGE/version.py +. ./setup-master.sh +echo $VERSION +PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 2.7.13 3.4.2 3.5.6' +for pyversion in $PYVERSIONS; do + # Pick out first two numbers + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + python setup.py bdist_egg bdist_wheel + mv -v dist/uncompyle6-$VERSION-{py2.py3,py$first_two}-none-any.whl +done + +python ./setup.py sdist diff --git a/admin-tools/make-dist-older.sh b/admin-tools/make-dist-older.sh new file mode 100644 index 000000000..8300bf954 --- /dev/null +++ b/admin-tools/make-dist-older.sh @@ -0,0 +1,18 @@ +#!/bin/bash +PACKAGE=uncompyle6 +if ! source ./setup-python-2.4.sh ; then + exit $? +fi +source $PACKAGE/version.py +echo $VERSION +PYVERSIONS='2.4.6 2.5.6' +for pyversion in $PYVERSIONS; do + # Pick out first two numbers + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_egg +done +tarball=dist/uncompyle6-$VERSION-tar.gz +if -f $tarball; then + rm dist/uncompyle6-$VERSION-tar.gz +fi diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions new file mode 100644 index 000000000..559670b5d --- /dev/null +++ b/admin-tools/pyenv-newer-versions @@ -0,0 +1,5 @@ +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 pypy-5.0.1 2.7.13 3.4.2' diff --git a/admin-tools/pyenv-older-versions b/admin-tools/pyenv-older-versions new file mode 100644 index 000000000..f5d03e18e --- /dev/null +++ b/admin-tools/pyenv-older-versions @@ -0,0 +1,5 @@ +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='2.4.6 2.5.6' diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh new file mode 100644 index 000000000..84fade5e1 --- /dev/null +++ b/admin-tools/setup-master.sh @@ -0,0 +1,16 @@ +#!/bin/bash +PYTHON_VERSION=3.6.3 + +owd=$(pwd) +bs=${BASH_SOURCE[0]} +if [[ $0 == $bs ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +mydir=$(dirname $bs) +fulldir=$(readlink -f $mydir) +cd $fulldir/.. +(cd ../python-spark && git checkout master && pyenv local $PYTHON_VERSION) && \ + (cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && \ + git checkout master && pyenv local $PYTHON_VERSION +cd $owd diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh new file mode 100644 index 000000000..f4665ab78 --- /dev/null +++ b/admin-tools/setup-python-2.4.sh @@ -0,0 +1,16 @@ +#!/bin/bash +PYTHON_VERSION=2.4.6 + +owd=$(pwd) +bs=${BASH_SOURCE[0]} +if [[ $0 == $bs ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +mydir=$(dirname $bs) +fulldir=$(readlink -f $mydir) +cd $fulldir/.. +(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && \ + (cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && \ + git checkout python-2.4 && pyenv local $PYTHON_VERSION +cd $owd From ca9c227837895e7284309e71781f173faf973b40 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 11 Oct 2017 21:41:51 -0400 Subject: [PATCH 061/489] More administrivia --- admin-tools/check-newer-versions.sh | 10 ++++++++- admin-tools/check-older-versions.sh | 7 ++++++ admin-tools/how-to-make-a-release.txt | 21 ++++-------------- admin-tools/make-dist-newer.sh | 18 ++++++++++++++-- admin-tools/make-dist-older.sh | 31 ++++++++++++++++++++++----- admin-tools/pyenv-newer-versions | 5 +++-- admin-tools/pyenv-older-versions | 1 + uncompyle6/parsers/parse37.py | 1 - uncompyle6/scanners/scanner37.py | 2 -- uncompyle6/version.py | 2 +- 10 files changed, 67 insertions(+), 31 deletions(-) mode change 100644 => 100755 admin-tools/make-dist-newer.sh mode change 100644 => 100755 admin-tools/make-dist-older.sh diff --git a/admin-tools/check-newer-versions.sh b/admin-tools/check-newer-versions.sh index a6d27051f..1c2d18d49 100644 --- a/admin-tools/check-newer-versions.sh +++ b/admin-tools/check-newer-versions.sh @@ -1,4 +1,12 @@ #!/bin/bash +function finish { + cd $owd +} + +# FIXME put some of the below in a common routine +owd=$(pwd) +trap finish EXIT + cd $(dirname ${BASH_SOURCE[0]}) if ! source ./pyenv-newer-versions ; then exit $? @@ -11,7 +19,7 @@ for version in $PYVERSIONS; do if ! pyenv local $version ; then exit $? fi - make clean && python setup.py develop + make clean && pip install -e . if ! make check; then exit $? fi diff --git a/admin-tools/check-older-versions.sh b/admin-tools/check-older-versions.sh index 53a00f6f3..0bfb93fbc 100644 --- a/admin-tools/check-older-versions.sh +++ b/admin-tools/check-older-versions.sh @@ -1,4 +1,10 @@ #!/bin/bash +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + cd $(dirname ${BASH_SOURCE[0]}) if ! source ./pyenv-older-versions ; then exit $? @@ -6,6 +12,7 @@ fi if ! source ./setup-python-2.4.sh ; then exit $? fi + cd .. for version in $PYVERSIONS; do if ! pyenv local $version ; then diff --git a/admin-tools/how-to-make-a-release.txt b/admin-tools/how-to-make-a-release.txt index 38e346acb..70bf3449a 100644 --- a/admin-tools/how-to-make-a-release.txt +++ b/admin-tools/how-to-make-a-release.txt @@ -18,38 +18,25 @@ git push Make sure pyenv is running # Pyenv -source make-dist/pyenv-versions +source admin-tools/check-newer-versions.sh -Test all python versions: - for version in $PYVERSIONS; do pyenv local $version && make clean && python setup.py develop && make check; done - # Switch to python-2.4 and build that first... - - ----- - -./setup-python-2.4.sh +source admin-tools/setup-python-2.4 rm ChangeLog git merge master -check uncompyle6/version.py to see it has changed -make ChangeLog Update NEWS from master branch git commit -m"Get ready for release $VERSION" . -PYVERSIONS='2.4.6 2.5.6' - -for version in $PYVERSIONS; do pyenv local $version && make clean && python setup.py develop && make check; done +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 -git push --tags - -. ./setup-master.sh ./make-dist-newer.sh diff --git a/admin-tools/make-dist-newer.sh b/admin-tools/make-dist-newer.sh old mode 100644 new mode 100755 index 4f10e3b1a..49f4614cc --- a/admin-tools/make-dist-newer.sh +++ b/admin-tools/make-dist-newer.sh @@ -1,12 +1,26 @@ #!/bin/bash PACKAGE=uncompyle6 + +# FIXME put some of the below in a common routine +function finish { + cd $owd +} +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-older-versions ; then + exit $? +fi +if ! source ./setup-master.sh ; then + exit $? +fi + +cd .. source $PACKAGE/version.py -. ./setup-master.sh echo $VERSION -PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 2.7.13 3.4.2 3.5.6' + for pyversion in $PYVERSIONS; do # Pick out first two numbers first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build python setup.py bdist_egg bdist_wheel mv -v dist/uncompyle6-$VERSION-{py2.py3,py$first_two}-none-any.whl done diff --git a/admin-tools/make-dist-older.sh b/admin-tools/make-dist-older.sh old mode 100644 new mode 100755 index 8300bf954..83e72ac77 --- a/admin-tools/make-dist-older.sh +++ b/admin-tools/make-dist-older.sh @@ -1,18 +1,39 @@ #!/bin/bash PACKAGE=uncompyle6 + +# FIXME put some of the below in a common routine +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-older-versions ; then + exit $? +fi if ! source ./setup-python-2.4.sh ; then exit $? fi + +cd .. source $PACKAGE/version.py echo $VERSION -PYVERSIONS='2.4.6 2.5.6' + for pyversion in $PYVERSIONS; do - # Pick out first two numbers - first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + if ! pyenv local $pyversion ; then + exit $? + fi + rm -fr build python setup.py bdist_egg done + +# Pypi can only have one source tarball. +# Tarballs can get created from the above setup, so make sure to remove them since we want +# the tarball from master. + tarball=dist/uncompyle6-$VERSION-tar.gz -if -f $tarball; then - rm dist/uncompyle6-$VERSION-tar.gz +if [[ -f $tarball ]]; then + rm -v dist/uncompyle6-$VERSION-tar.gz fi diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index 559670b5d..8a7bd7a99 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -1,5 +1,6 @@ -if [[ $0 == ${BASH_SOURCE[0]} ]] ; then +# -*- shell-script -*- + if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 pypy-5.0.1 2.7.13 3.4.2' +export PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 2.7.13 3.4.2' diff --git a/admin-tools/pyenv-older-versions b/admin-tools/pyenv-older-versions index f5d03e18e..63e4e2024 100644 --- a/admin-tools/pyenv-older-versions +++ b/admin-tools/pyenv-older-versions @@ -1,3 +1,4 @@ +# -*- shell-script -*- if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 50cb3a502..5d73491b2 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -2,7 +2,6 @@ """ spark grammar differences over Python 3.6 for Python 3.7 """ -from __future__ import print_function from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 0e22ba605..fdb81b52a 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -9,8 +9,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from uncompyle6.scanners.scanner3 import Scanner3 # bytecode verification, verify(), uses JUMP_OPs from here diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 83bf37400..827d6100a 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.13.0' +VERSION='2.13.1' From 05fd992c485ee17aefc1c76688dd2846d49e17fd Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Oct 2017 07:06:19 -0400 Subject: [PATCH 062/489] Update news --- NEWS | 3 --- uncompyle6/parser.py | 4 ---- uncompyle6/scanners/tok.py | 5 ----- uncompyle6/semantics/consts.py | 4 ---- uncompyle6/semantics/make_function.py | 13 ------------- 5 files changed, 29 deletions(-) diff --git a/NEWS b/NEWS index d2ae7b624..24684bb2b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,3 @@ -<<<<<<< HEAD -======= uncompyle6 2.13.2 2017-10-12 - Re-release using a more automated approach @@ -8,7 +6,6 @@ uncompyle6 2.13.1 2017-10-11 - Re-release because Python 2.4 source uploaded rather than 2.6-3.6 ->>>>>>> master uncompyle6 2.13.0 2017-10-10 - Fixes in deparsing lambda expressions diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index f2b630d4c..6d927d0f4 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -96,14 +96,10 @@ def debug_reduce(self, rule, tokens, parent, last_token_pos): def fix(c): s = str(c) last_token_pos = s.find('_') -<<<<<<< HEAD if last_token_pos == -1: return s else: return s[:last_token_pos] -======= - return s if last_token_pos == -1 else s[:last_token_pos] ->>>>>>> master prefix = '' if parent and tokens: diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index ab0c361de..d750aabc0 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -55,15 +55,10 @@ def __str__(self): return self.format(line_prefix='') def format(self, line_prefix=''): -<<<<<<< HEAD if self.linestart: prefix = '\n%s%4d ' % (line_prefix, self.linestart) else: prefix = ' ' * (6 + len(line_prefix)) -======= - prefix = ('\n%s%4d ' % (line_prefix, self.linestart) - if self.linestart else (' ' * (6 + len(line_prefix)))) ->>>>>>> master offset_opname = '%6s %-17s' % (self.offset, self.kind) if not self.has_arg: return "%s%s" % (prefix, offset_opname) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index dc97089bc..e85863afd 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -173,11 +173,7 @@ 'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27) ), 'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27) ), 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27) ), -<<<<<<< HEAD - 'conditional_lambda': ( '(%c if %c else %c)', 2, 0, 3), -======= 'conditional_lambda': ( '%c if %c else %c', 2, 0, 4), ->>>>>>> master 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), 'cmp_list': ( '%p %p', (0, 29), (1, 30)), diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 48a505c1d..c461aa3ae 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -451,19 +451,6 @@ def build_param(ast, name, default): # MAKE_FUNCTION_... or MAKE_CLOSURE_... assert node[-1].kind.startswith('MAKE_') -<<<<<<< HEAD -======= - - - # Python 3.3+ adds a qualified name at TOS (-1) - # moving down the LOAD_LAMBDA instruction - if 3.0 <= self.version <= 3.2: - lambda_index = -2 - elif 3.03 <= self.version: - lambda_index = -3 - else: - lambda_index = None ->>>>>>> master args_node = node[-1] if isinstance(args_node.attr, tuple): From d1a3d42ab87ec4736d9bb2cb77f7d77851ddeb40 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Oct 2017 07:08:58 -0400 Subject: [PATCH 063/489] Sync --- admin-tools/how-to-make-a-release.md | 78 ++++++++++++++++++++++++++++ admin-tools/pyenv-newer-versions | 4 -- admin-tools/update-sources.sh | 3 ++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 admin-tools/how-to-make-a-release.md create mode 100755 admin-tools/update-sources.sh diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md new file mode 100644 index 000000000..a8dd9d06d --- /dev/null +++ b/admin-tools/how-to-make-a-release.md @@ -0,0 +1,78 @@ + +**Table of Contents** + +- [Get latest sources:](#get-latest-sources) +- [Change version in uncompyle6/version.py. Then:](#change-version-in-uncompyle6versionpy-then) +- [Update ChangeLog:](#update-changelog) +- [Update NEWS from ChangeLog. Then:](#update-news-from-changelog-then) +- [Make sure pyenv is running and check newer versions](#make-sure-pyenv-is-running-and-check-newer-versions) +- [Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want.](#switch-to-python-24-sync-that-up-and-build-that-first-since-it-creates-a-tarball-which-we-dont-want) +- [Update NEWS from master branch](#update-news-from-master-branch) +- [Check against all versions](#check-against-all-versions) +- [Make packages and tag](#make-packages-and-tag) +- [Upload single package and look at Rst Formating](#upload-single-package-and-look-at-rst-formating) +- [Upload rest of versions](#upload-rest-of-versions) +- [Push tags:](#push-tags) + + +# Get latest sources: + + $ . ./admin-tool/update-sources.sh + +# Change version in uncompyle6/version.py. Then: + + $ emacs 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. Then: + + $ emacs NEWS + $ make check + $ git commit --amend . + $ git push # get CI testing going early + +# Make sure pyenv is running and check newer versions + + $ pyenv local && source admin-tools/check-newer-versions.sh + +# Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want. + + $ source admin-tools/setup-python-2.4.sh + $ rm ChangeLog + + # $ git merge master ? + +# Update NEWS from master branch + + $ git commit -m"Get ready for release $VERSION" . + +# Check against all versions + + $ source admin-tools/check-older-versions.sh + $ source admin-tools/check-newer-versions.sh + +# Make packages and tag + + $ make-dist-older.sh + $ git tag release-python-2.4-$VERSION + + $ make-dist-newer.sh + $ git tag release-$VERSION + +# Upload single package and look at Rst Formating + + $ twine upload dist/uncompyle6-${VERSION}-py3.3.egg + +# Upload rest of versions + + $ twine upload dist/uncompyle6-${VERSION}* + +# Push tags: + + $ git push --tags diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index daf898774..abee03f4f 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -1,9 +1,5 @@ # -*- shell-script -*- -<<<<<<< HEAD - if [[ $0 == ${BASH_SOURCE[0]} ]] ; then -======= if [[ $0 == ${BASH_SOURCE[0]} ]] ; then ->>>>>>> master echo "This script should be *sourced* rather than run directly through bash" exit 1 fi diff --git a/admin-tools/update-sources.sh b/admin-tools/update-sources.sh new file mode 100755 index 000000000..41ccab52c --- /dev/null +++ b/admin-tools/update-sources.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd $(dirname ${BASH_SOURCE[0]})/.. +git pull From 1f012f7c46680d7758f6d1de04f6521e4601199e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Oct 2017 07:18:11 -0400 Subject: [PATCH 064/489] Merge conflicts --- admin-tools/make-dist-newer.sh | 12 ++---------- admin-tools/make-dist-older.sh | 8 -------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/admin-tools/make-dist-newer.sh b/admin-tools/make-dist-newer.sh index 510e53c78..273d1dd1c 100755 --- a/admin-tools/make-dist-newer.sh +++ b/admin-tools/make-dist-newer.sh @@ -5,16 +5,12 @@ PACKAGE=uncompyle6 function finish { cd $owd } -<<<<<<< HEAD + cd $(dirname ${BASH_SOURCE[0]}) -if ! source ./pyenv-older-versions ; then -======= owd=$(pwd) trap finish EXIT -cd $(dirname ${BASH_SOURCE[0]}) if ! source ./pyenv-newer-versions ; then ->>>>>>> master exit $? fi if ! source ./setup-master.sh ; then @@ -26,17 +22,13 @@ source $PACKAGE/version.py echo $VERSION for pyversion in $PYVERSIONS; do -<<<<<<< HEAD - # Pick out first two numbers -======= if ! pyenv local $pyversion ; then exit $? fi # pip bdist_egg create too-general wheels. So # we narrow that by moving the generated wheel. - # Pick out first two number of version, e.g. 3.5.1 -> 35 ->>>>>>> master + # Pick out first two number of version, e.g. 3.5.1 -> 35 first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel diff --git a/admin-tools/make-dist-older.sh b/admin-tools/make-dist-older.sh index 2d781f075..83e72ac77 100755 --- a/admin-tools/make-dist-older.sh +++ b/admin-tools/make-dist-older.sh @@ -16,12 +16,8 @@ if ! source ./setup-python-2.4.sh ; then exit $? fi -<<<<<<< HEAD cd .. source $PACKAGE/version.py -======= -source ../$PACKAGE/version.py ->>>>>>> master echo $VERSION for pyversion in $PYVERSIONS; do @@ -38,10 +34,6 @@ done # the tarball from master. tarball=dist/uncompyle6-$VERSION-tar.gz -<<<<<<< HEAD if [[ -f $tarball ]]; then -======= -if -f $tarball; then ->>>>>>> master rm -v dist/uncompyle6-$VERSION-tar.gz fi From eafe048c7e9e0008971e88f8eca99db30546aa6a Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Nov 2017 10:12:27 -0500 Subject: [PATCH 065/489] Get ready for release python-2.4-2.13.3 --- uncompyle6/scanners/scanner3.py | 4 +++- uncompyle6/semantics/make_function.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index bd96c2db8..3dc6f396b 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -166,7 +166,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): self.code = array('B', co.co_code) bytecode = Bytecode(co, self.opc) - show_asm = self.show_asm if not show_asm else show_asm + if not show_asm: + show_asm = self.show_asm + # show_asm = 'both' if show_asm in ('both', 'before'): for instr in bytecode.get_instructions(co): diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 67e0560e7..697607684 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -7,7 +7,6 @@ from uncompyle6.scanner import Code from uncompyle6.parsers.astnode import AST from uncompyle6.semantics.parser_error import ParserError -from uncompyle6.parser import ParserError as ParserError2 from uncompyle6.semantics.helper import print_docstring From e0ed187ea614ee094b6a38bc5895d65600cf9ee6 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Nov 2017 10:52:43 -0500 Subject: [PATCH 066/489] 2.4isms... Need print without parens. Handle old-style classes more properly? --- uncompyle6/main.py | 2 +- uncompyle6/parser.py | 5 +++-- uncompyle6/semantics/pysource.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index e6a22f90a..793012589 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -216,7 +216,7 @@ def _get_outstream(outfile): 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)) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 523280bc0..21b9e51a6 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -3,7 +3,7 @@ # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock """ -Common parser routines. +Common uncompyle6 parser routines. """ import sys @@ -37,6 +37,7 @@ def __init__(self, AST, start, debug): 'print_items', # PyPy: 'kvlist_n'] + self.collect = frozenset(nt_list) def ast_first_offset(self, ast): if hasattr(ast, 'offset'): @@ -138,7 +139,7 @@ def error(self, instructions, index): 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) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index abcb8d654..f7bd776de 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1526,7 +1526,7 @@ def print_super_classes(self, node): return n_subclasses = len(node[:-1]) - if n_subclasses > 0 or self.version > 2.1: + if n_subclasses > 0 or self.version > 2.4: # Not an old-style pre-2.2 class self.write('(') @@ -1537,7 +1537,7 @@ def print_super_classes(self, node): self.write(sep, value) sep = line_separator - if n_subclasses > 0 or self.version > 2.1: + if n_subclasses > 0 or self.version > 2.4: # Not an old-style pre-2.2 class self.write(')') From 6055c5e165f5f688298d2b5d602bb0e9fdf9dabb Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Nov 2017 10:58:46 -0500 Subject: [PATCH 067/489] Get ready for release python-2.4- --- ChangeLog | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/ChangeLog b/ChangeLog index 44897aa57..e1b947b39 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,221 @@ +2017-11-13 rocky + + * uncompyle6/main.py, uncompyle6/parser.py, + uncompyle6/semantics/pysource.py: 2.4isms... Need print without parens. Handle old-style classes more properly? + +2017-11-13 rocky + + * uncompyle6/scanners/scanner3.py, + uncompyle6/semantics/make_function.py: Get ready for release + python-2.4-2.13.3 + +2017-11-13 rocky + + * : commit 35e4e034686065609b8b2e55cd37c9a391e16c00 Author: rocky + Date: Mon Nov 13 09:53:10 2017 -0500 + +2017-11-13 rocky + + * ChangeLog, NEWS, uncompyle6/version.py: Get ready for release + 2.13.3 + +2017-11-12 rocky + + * test/Makefile: Back off --verify for --weak-verify + +2017-11-12 rocky + + * test/Makefile: Back off --verify for --weak-verify + +2017-11-12 rocky + + * : Reinstate previously failed tests 2.6, 3.5 and 3.6 decompilation has gotten better + +2017-11-10 rocky + + * __pkginfo__.py: Use newer xdis + +2017-11-09 rocky + + * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Fix bug in return-optimized try stmt + +2017-11-09 rocky + + * HOW-TO-REPORT-A-BUG.md: More detail is needed in bug reporting... sigh. + +2017-11-09 rocky + + * test/simple_source/bug35/04_importlist.py, uncompyle6/parser.py, + uncompyle6/semantics/consts.py: bug in 3.x importlists consts.py: add rule for importlists. imports weren't separated by ', + '. parser.py: Make importlist a list type of node. test/* add test for importlist + +2017-11-08 rocky + + * : commit e9b60ddbf020ee7f14d8d77c6f4a8588d2968377 Author: rocky + Date: Wed Nov 8 23:05:01 2017 -0500 + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: more wordsmithing + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: more wordsmithing + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: more wordsmithing + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: Typo + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: Typo + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: Typo + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: Typo + +2017-11-08 rocky + + * HOW-TO-REPORT-A-BUG.md: Tweak how to report a bug. + +2017-11-08 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse36.py, + uncompyle6/scanners/scanner3.py: Add 3.6+ grammar for except's + ending in RETURN... Not totally out of the maze in 3.6 control flow... There are still + problems with erroneous RETURN_VALUEs becoming RETURN_END_IF, + +2017-11-07 R. Bernstein + + * : Merge pull request #135 from rocky/3.6-instruction-refactor 3.6 instruction refactor + +2017-11-06 rocky + + * uncompyle6/scanners/scanner3.py: Small tweaks to sync up better + with scanner2.py + +2017-11-06 rocky + + * pytest/test_fjt.py: Remove parts of erroneous 2.7 test for now + +2017-11-06 rocky + + * pytest/test_fjt.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner36.py: Fix 3.{3,4} pytest. Remove dup + find_jump_targets + +2017-11-06 rocky + + * Makefile, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner36.py: Move refactored find-jump-targets + from 3.6 to 3.x + +2017-11-06 rocky + + * test/Makefile, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner36.py: Move refactored ingest from 3.6 to + 3.x... We are getting away from working with bytecode in favor of working + with full-fledged structured instructions Up next: find_jump_targets() + +2017-11-06 rocky + + * uncompyle6/parsers/parse36.py: awith custom COME_FROMs ... Now that jump branching has been properly fixed up for EXTENDED_ARG + instructions which are more prevalent with wordcode encoding. + +2017-11-06 rocky + + * : commit 9379922c89573972aa387e4f0b9abcba7358d1a3 Author: rocky + Date: Mon Nov 6 00:38:22 2017 -0500 + +2017-11-06 rocky + + * uncompyle6/scanners/scanner36.py: Revert change that should have + been in a branch + +2017-11-06 rocky + + * uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner36.py: xdis _disassemble->disassemble + +2017-11-04 rocky + + * uncompyle6/semantics/fragments.py, + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py: Add flag to tolerate deparse + errors... and keep going. The fragment parser should ignore errors in nested + function definitions + +2017-11-04 rocky + + * uncompyle6/scanner.py, uncompyle6/semantics/fragments.py: Add + Python 3.6.3 scanner lookup + +2017-11-03 R. Bernstein + + * : Merge pull request #134 from mikemrm/master Corrected python3 import from queue + +2017-10-29 rocky + + * test/simple_source/bug36/10_extended_arg_loop.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6 control flow bug... Much more is needed, but it's a start + +2017-10-29 rocky + + * uncompyle6/verify.py: In verify, JUMP_BACK is the same as + CONTINUE... at least for now. See FIXME in verify + +2017-10-29 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Python 3.6-inspired instruction size cleanup Revise and generalize for Python 3.6+ instructions vs < 3.6 + instuctions. Used more of the generalized methods in xdis and + remove some (but not all) of the magic numbers. This is a lot of changes, but not all of the refactoring needed. + Much crap still remains. Also, there are still bugs in handling 3.6 + bytecodes. + +2017-10-24 rocky + + * Makefile, __pkginfo__.py: Bump uncompyle. Pypy 5.8.0-beta + tolerance + +2017-10-13 rocky + + * test/Makefile, uncompyle6/semantics/consts.py: Tag more semantic + actions with nonterminals + +2017-10-13 rocky + + * uncompyle6/parser.py, uncompyle6/semantics/consts.py: More node + checking in tables + +2017-10-13 rocky + + * pytest/test_pysource.py, uncompyle6/parser.py, + uncompyle6/parsers/parse24.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Start allowing node names in template engine These are now used to assert we have the right node type. Simplify import_from + +2017-10-13 rocky + + * HISTORY.md, uncompyle6/semantics/pysource.py: Small changes + +2017-10-12 rocky + + * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia - generalize shell code + 2017-10-12 rocky * : commit e42e3cc230237a448f48d10f3a6e11c8cda5e9c7 Author: rocky From 524e8c84102c89d2f19e14b6e59916d1f4aba35a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 16 Nov 2017 09:18:26 -0500 Subject: [PATCH 068/489] Python 2.5 "with". isolate 2.5-2.7 grammar better --- test/Makefile | 29 ---------------------------- test/bytecode_2.5/05_with.pyc | Bin 295 -> 421 bytes test/bytecode_2.6/05_with.pyc | Bin 276 -> 387 bytes test/simple_source/stmts/05_with.py | 4 +++- uncompyle6/parsers/parse25.py | 13 +++++++++++++ uncompyle6/parsers/parse26.py | 5 +++++ 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/test/Makefile b/test/Makefile index 822d24927..1443d6bd9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -101,35 +101,6 @@ check-bytecode-2.4: check-bytecode-2.5: $(PYTHON) test_pythonlib.py --bytecode-2.5 -#: Get grammar coverage for Python 2.5 -grammar-coverage-2.5: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 - -#: Get grammar coverage for Python 2.6 -grammar-coverage-2.6: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 - -#: Get grammar coverage for Python 2.7 -grammar-coverage-2.7: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 - -#: Get grammar coverage for Python 3.4 -grammar-coverage-3.4: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-34.cover $(PYTHON) test_pythonlib.py --bytecode-3.4 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-34.cover $(PYTHON) test_pyenvlib.py --3.4.2 - -#: Check deparsing Python 2.6 -check-bytecode-2.6: - $(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify - -#: Check deparsing Python 2.7 -check-bytecode-2.7: - $(PYTHON) test_pythonlib.py --bytecode-2.7 --verify - ->>>>>>> master #: Check deparsing Python 3.0 check-bytecode-3.0: $(PYTHON) test_pythonlib.py --bytecode-3.0 diff --git a/test/bytecode_2.5/05_with.pyc b/test/bytecode_2.5/05_with.pyc index e87be6dadb39c2b8650c1c158d80b603914f6b12..ce3ddcfc93b94ba0d8206fddb93a33e004bd2355 100644 GIT binary patch literal 421 zcmYLE%TB{E5FED&Z7LOU;3IM=h9Wp2#0^eJJS0$}$|{LVqvoY}15Hmz{RO^*3xCEB zz&b>*vc@yJWAEFKO(vFKdKGoMZP2XoI-nktfd&F}JgI(dnVeC8?ZCs`HIs*z7R t+K@C!R`N8asH;dzLm3%)c%tlr2W4aIz-L(z*Qq|YTegWk;R{#niyuO&VG95N delta 181 zcmZ3=yqqaz^Cw;|?biD6WCkc;1JVu+3=G9CKt>7>F*0N`Fyt^YL@_cjrZO?GWHK{E zu`pz^GBh(VM6oec2{ELyF+{U5M6olZvNO1Qgr_huq_QwXvoHik0GYuW%oBSRl>9U} zfaaBO0g3qdw9=B&qSW~KARv#Sgc(Q_R~AovY%Hn)5V8~%)h+<@5Ol4w7WoAfW zVrXV!V98`*V9I1=Xl7uDVq>V%Vn}6Uh-PDmVrNKYXK?ob5=bf-t5_JqQ7)l2MwZUzDGmU8!GCS(1^Tr(2qroS$1znUiX!Uy@o}qCfGD Q0T0MD0Y)`ORz@L407B9?9smFU delta 156 zcmZo>p28G!@e?oCcK3$xWCkc;1JVu+3=G9KKt>7>F*0N`Fyt^YL@_cjrZO?GWHK`_ zWwJ0dGcZK4GE@mMq_Q$Zvob`nF{H9FxO;@BFfjy10Eu7?=83fmN`4ybKyymCfJA(J pT4_mXQEGgA5Rk`E!VDyeD~l&ywqlV3GAFw;8gQ@x83K&5i~y!%8?OKW diff --git a/test/simple_source/stmts/05_with.py b/test/simple_source/stmts/05_with.py index 74706b8f6..6f52fbdb0 100644 --- a/test/simple_source/stmts/05_with.py +++ b/test/simple_source/stmts/05_with.py @@ -1,3 +1,5 @@ from __future__ import with_statement -with (sys) as f: +with open(__file__, 'r') as f: print(f) + with f: + pass diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 93dd342bb..ef3343dba 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -21,8 +21,13 @@ def p_misc25(self, args): # 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 setupwithas ::= DUP_TOP LOAD_ATTR store LOAD_ATTR CALL_FUNCTION_0 setup_finally + # opcode SETUP_WITH + setupwith ::= DUP_TOP LOAD_ATTR STORE_NAME LOAD_ATTR CALL_FUNCTION_0 POP_TOP + withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM with_cleanup store ::= STORE_FAST store ::= STORE_NAME @@ -41,6 +46,14 @@ def p_misc25(self, args): """ def add_custom_rules(self, tokens, customize): + # grammar rules inherited from Python 2.6 + self.remove_rules(""" + 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 + withasstmt ::= expr setupwithas designator suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY + """) super(Python25Parser, self).add_custom_rules(tokens, customize) if self.version == 2.5: self.check_reduce['tryelsestmt'] = 'tokens' diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 4ed3dda90..fc7394ef1 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -251,6 +251,11 @@ def p_misc26(self, args): """ def add_custom_rules(self, tokens, customize): + self.remove_rules(""" + withasstmt ::= expr SETUP_WITH designator suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM_WITH + WITH_CLEANUP END_FINALLY + """) super(Python26Parser, self).add_custom_rules(tokens, customize) self.check_reduce['and'] = 'AST' From f3da5d770d4544ed38442c29764e81f36a511c28 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 22 Nov 2017 06:26:20 -0500 Subject: [PATCH 069/489] Merge hell --- admin-tools/setup-python-2.4.sh | 6 +++--- test/Makefile | 36 +++++---------------------------- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index f4665ab78..5226f9d29 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -10,7 +10,7 @@ fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. -(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && \ - (cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && \ - git checkout python-2.4 && pyenv local $PYTHON_VERSION +(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ + (cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ + git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull cd $owd diff --git a/test/Makefile b/test/Makefile index 8b6db98ac..5dcf3cb56 100644 --- a/test/Makefile +++ b/test/Makefile @@ -102,6 +102,11 @@ check-bytecode-2.4: check-bytecode-2.5: $(PYTHON) test_pythonlib.py --bytecode-2.5 +#: Get grammar coverage for Python 2.4 +grammar-coverage-2.4: + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 + SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 + #: Get grammar coverage for Python 2.5 grammar-coverage-2.5: SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 @@ -117,12 +122,6 @@ grammar-coverage-2.7: SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 -#: Get grammar coverage for Python 3.4 -grammar-coverage-3.4: - rm $(COVER_DIR)/spark-grammar-34.cover || /bin/true - SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-34.cover $(PYTHON) test_pythonlib.py --bytecode-3.4 - SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-34.cover $(PYTHON) test_pyenvlib.py --3.4.2 - #: Check deparsing Python 2.6 check-bytecode-2.6: $(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify @@ -131,7 +130,6 @@ check-bytecode-2.6: check-bytecode-2.7: $(PYTHON) test_pythonlib.py --bytecode-2.7 --verify ->>>>>>> master #: Check deparsing Python 3.0 check-bytecode-3.0: $(PYTHON) test_pythonlib.py --bytecode-3.0 @@ -156,30 +154,6 @@ check-bytecode-3.4: check-bytecode-3.5: $(PYTHON) test_pythonlib.py --bytecode-3.5 -#: Check deparsing Python 3.6 -check-bytecode-3.6: - $(PYTHON) test_pythonlib.py --bytecode-3.6 - -#: Get grammar coverage for Python 2.4 -grammar-coverage-2.4: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 - -#: Get grammar coverage for Python 2.5 -grammar-coverage-2.5: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 - -#: Get grammar coverage for Python 2.6 -grammar-coverage-2.6: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 - -#: Get grammar coverage for Python 2.7 -grammar-coverage-2.7: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 - #: short tests for bytecodes only for this version of Python check-native-short: $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE) From 38f04f0073a1ca29c5e42f9abac66967a4ba000a Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 22 Nov 2017 11:15:39 -0500 Subject: [PATCH 070/489] More complete grammar coverage --- test/bytecode_2.2/01_augmented_assign.pyc | Bin 0 -> 1443 bytes test/bytecode_2.5/01_augmented_assign.pyc | Bin 0 -> 1319 bytes test/bytecode_2.6/01_augmented_assign.pyc | Bin 0 -> 1319 bytes test/bytecode_2.6/02_true_divide.pyc | Bin 238 -> 238 bytes test/bytecode_2.7/01_augmented_assign.pyc | Bin 0 -> 1344 bytes test/bytecode_2.7/02_true_divide.pyc | Bin 238 -> 238 bytes .../stmts/01_augmented_assign.py | 71 ++++++++++++++++++ uncompyle6/parsers/parse2.py | 8 +- uncompyle6/parsers/parse23.py | 1 + uncompyle6/parsers/parse27.py | 3 +- 10 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/bytecode_2.2/01_augmented_assign.pyc create mode 100644 test/bytecode_2.5/01_augmented_assign.pyc create mode 100644 test/bytecode_2.6/01_augmented_assign.pyc create mode 100644 test/bytecode_2.7/01_augmented_assign.pyc create mode 100644 test/simple_source/stmts/01_augmented_assign.py diff --git a/test/bytecode_2.2/01_augmented_assign.pyc b/test/bytecode_2.2/01_augmented_assign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d302fb1f6fe09fa6fad2878fd8cbedac4406b922 GIT binary patch literal 1443 zcmbtU&2HO95dM~=Y>Srd*pA!^L7h#1V8xE4CQaeEFi;d|Z$VJR0SX8(2%22UOeB)w zu4=271(M!+%mefZ`Ye5p9(w5$bY?~Wpx27vVCI`|znz)os`vL=_|Na{VFLOs(W~Ej zfCW-uNKO-W6-po#crWlyz^)?;-KfA@s;Uwjc451==Al!^igH{~)*c_c#^orb`$L z9C}^*iR1dLDQncKjlKHqo@J< z89PDNVCc|e09pV+(hmJu9 zvX9Ht+l+mjKF2VGJ#dUw*hjeByUlon(;W<3usx_%WORffi;K5^il1yBs>v8-9QFrc z18$MA<^ubTu*Y0%K$Qfv7mGbXx{6<^>UG#d*J1#(f{qI5ZPCd*V~|TfVmY;r_qfiw zQ=$R+$7u^E-8KI7{vs2`v+-2rMy20rosIK;IhVbj)Wxhylr%~kS;oewDwm_8lGkh* zJGu_TSLd0&;*(d#m663rnsX&nl@!x*KBv${{-;970K6^2~pXjakomCSOArm@M2Jk%ZP z*40{8#kh*6GKup&BhQqqW_czko6%K7w#>$7(_|B{*=KXWhF-YK>%oWKrHIbOeg*p! zhHf!^_AxW8W-Dz_?j_RQIdZV=_?crsI( z`z6mIRh*BNV`Q4EpS*U#>qYR!1#jHmaapQ7b-<{*LR9D8-eXj=x$9bBp*E@2{@)P3 zZ9+dM>6W+QHARyKv3NGUEwL@y;-0_h?T8)G5!+r%Y>5rgCf*$|_r~58^mv=1)o2s` EFZkggHvj+t literal 0 HcmV?d00001 diff --git a/test/bytecode_2.5/01_augmented_assign.pyc b/test/bytecode_2.5/01_augmented_assign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82a3ddeed2ac6e4a0d0c189e3430f8ffee0e1132 GIT binary patch literal 1319 zcmb7DO>fgc5S_K1wArRfX;nlousso4wSiM93SR?W*H zPl2vcfd?K=@rjJ~A*@#*(Df>db>Kz?a9x60qV{mF-hLiJwCoZMxPE^-@f`ZxC05{i z`*vaj`b|(PpjSb1GGSj*cBUFcAnk}#Bmze?rbLgOVQm4vD?nQ`kSp*5%W1ii1F*}m zr8tfz^iYU8T(4Si19RT(EB1*e(1epti;lmI$Il->38QkDsMIPMM#ku2x}Q%(l1V+# zN{T^|C7jPCujh)rJz=u4h?TI)SdmB8sv;GGtPpdxm>L?+KaI4R=@I2oVMR6&cBF(< zahBwhab;vmZPh;K3mWy2_&BknEEVSytM=kd&X(!1D)@;~Vq|UptlPc1y4sJ6=-UKE zNlsa_kElC$>r#cBsvMLBzP=DT#aR+rou%At;l{XH^CBA-Q6l0feQ3qG5=EJ6+%V7{ zg(V6;g$9Ly!VZO93OHc?yOI744nv!6@sGm~I&$cwL%Abo+aYi3UeG}Vi(tst=p-Mj zaJu7NV-st-|2{hBF?dO9s4DO{JJOp7I&BP=3J*h>#bIchh>y$E>O{ROimY%;BNxwI z9NQX7zDDCxS!x!MV~Qvps$(R;QU~J;r@oj@F5TqP)-e<1xk}|RwY6x-q5tg4ETcsa zzsho~UaTNCA28ItrdMZm#%H(JW@~Jn-3wa5Mr|Xw>#cbW)@Dt%j=EJK?IPY`czZ3@ IsI4Ra7l$ti*8l(j literal 0 HcmV?d00001 diff --git a/test/bytecode_2.6/01_augmented_assign.pyc b/test/bytecode_2.6/01_augmented_assign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd3ad7f3a8480137e4329b7d24db2a58413ada96 GIT binary patch literal 1319 zcmb7DO>fgc5S_K1G})v{X;nlnusso4HGxwp3SRIiOrP!1)|KU82JhIZ$$P-Rf{PE|nD+qk#v?Bfrpr4pN8iKrW~bs)!rR z6^rRgiM)4TR${zj4%{dYt_x6W)E@5D+s|VNYBo`a>-V=4&tb@Iq5;=C zw-Z}1Y=UZlUI)p^gnfzGnW__kv?WfF@GMcE69aaJwR!k14{gyvHsA-A)3POdU~14& z97hudC`28uS1q`KC2#i?`@|Dy!b!J9$KS@|=Z~NGK{1Y0Y?SnaJlEs6m(E0#NIlX@ zicywCoG&G>mx}#;ktanKDq&P^L>d^QvRI6gOf1!6ZkTiaX`=Im9#I-(MkFI)CQ3*Z zCQ&+@mPUD@jp}i}qER1+k25n#VsSn*YClZmVws+*jGrhaCdQ=C`u(e`t6rD|-)1O^ zQp)B%ME#{(pDN^3<*3N;^_kEy&Z5BRB<6VsH^$bQX301UA`u4hLnF?W$ck9whJkh{ ztWj_&)G2rrb}8&pzyZtOjr4DDwfd=t#ZGvLv%h0~^n6 zoSF(sz6R4m8EO`hWwIb1t79awY6%E=c>ehj@t9Xau?X+0E HvWfg(A~Ff~ literal 0 HcmV?d00001 diff --git a/test/bytecode_2.6/02_true_divide.pyc b/test/bytecode_2.6/02_true_divide.pyc index dde95bb8e5268d501eca6dff2c06e7bbfcff39da..e540869a08726ae87bff68a477e44db5645589a3 100644 GIT binary patch delta 15 WcmaFI_>PhN;wN4%zYu|m?9Tx*I0f+l delta 15 XcmaFI_>PhN;wN6N`?|an*`EUdG|vWD diff --git a/test/bytecode_2.7/01_augmented_assign.pyc b/test/bytecode_2.7/01_augmented_assign.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e8f01649a0e3abc6cc69dc8d0aae395ca1c5c05 GIT binary patch literal 1344 zcmb7EO>fgc5S_L2={9X?RYZgY+Y_Nx6A*_`6c7lcRzj*!i-Z&jEZ4hnoF=wwZ)n4j za^gR5;@5HJ2f*8n^HFZZ+VRYLGjC_dcI@9Z=g*Jru21=|g!@aZ?1@Drh`O+hzA_RP zbzyDlS|k}si`t0c9Ue`?r#Hic<&e=bD{6~c$U;*TDS)y~623*gMRh<2c4r#b506A4 z=juq;nKFEp&02|;t0NVhSDR99)ptl0{DnJ$j zVuijzyk=UqNtLNCt5_@4K_c={FKcv7bKDFZ=d?RWJ~Xott905}(=X327{?n2BN-_v zUS(MrM9pNv_xE`gk5gZAB{RhnPbry3ycef@p3Oazo;l9@ewfYj;U!+Gc--TvFS(F@ zJW3|RTqqldN;Vy50VChz? zlxQ|(GcZ)Iwvveu)=?tIejbkcY*Mx)o#HM%RZ9CjRT!!eH&517bxMeMt-$@GjpGj^zo zU_X1qu~hnO@C=fAQ6NtMkkSng2PS(k4bDw)uJpf+mn1S0C;AkN{*Cv)hp0fJGm6D{ zC|~FaXP;n77A{s|4i*1h);imuD%)gt*c#ZaeBH)@OM^13Ul# literal 0 HcmV?d00001 diff --git a/test/bytecode_2.7/02_true_divide.pyc b/test/bytecode_2.7/02_true_divide.pyc index 5ffecbdc270137e4068e7e8fcd7e9226fd93cf59..ee35c2399d0ab881c8d5067b9f1dc8ee9e3f20cc 100644 GIT binary patch delta 15 WcmaFI_>PgC`7g&_U8a9H3cL9 delta 15 WcmaFI_>PgC`7 Date: Fri, 24 Nov 2017 21:48:24 -0500 Subject: [PATCH 071/489] Merge hell --- uncompyle6/semantics/make_function.py | 84 ++++++++++++++++----------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 055551113..58dbfec81 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -360,14 +360,7 @@ def build_param(ast, name, default): self.ERROR = p return -<<<<<<< HEAD - if self.version >= 3.0: - kw_pairs = args_node.attr[1] - else: - kw_pairs = 0 -======= kw_pairs = 0 ->>>>>>> master indent = self.indent # build parameters @@ -451,10 +444,34 @@ def build_param(ast, name, default): def make_function3(self, node, isLambda, nested=1, codeNode=None): - """Dump function definition, doc string, and function body.""" + """Dump function definition, doc string, and function body in + Python version 3.0 and above + """ - # FIXME: call make_function3 if we are self.version >= 3.0 - # and then simplify the below. + # For Python 3.3, the evaluation stack in MAKE_FUNCTION is: + + # * default argument objects in positional order + # * pairs of name and default argument, with the name just below + # the object on the stack, for keyword-only parameters + # * parameter annotation objects + # * a tuple listing the parameter names for the annotations + # (only if there are ony annotation objects) + # * the code associated with the function (at TOS1) + # * the qualified name of the function (at TOS) + + # For Python 3.0 .. 3.2 the evaluation stack is: + # The function object is defined to have argc default parameters, + # which are found below TOS. + # * first come positional args in the order they are given in the source, + # * next come the keyword args in the order they given in the source, + # * finally is the code associated with the function (at TOS) + # + # Note: There is no qualified name at TOS + + # MAKE_CLOSURE adds an additional closure slot + + # Thank you, Python, for a such a well-thought out system that has + # changed 4 or so times. def build_param(ast, name, default): """build parameters: @@ -480,7 +497,7 @@ def build_param(ast, name, default): # positional args are after kwargs defparams = node[1:args_node.attr[0]+1] else: - # positional args are before kwargs + # args are before kwargs; kwags as bundled as one node defparams = node[:args_node.attr[0]] pos_args, kw_args, annotate_argc = args_node.attr else: @@ -488,7 +505,7 @@ def build_param(ast, name, default): defparams = node[:args_node.attr] else: default, kw, annotate, closure = args_node.attr - # FIXME: start here. + # FIXME: start here for Python 3.6 and above: defparams = [] # if default: # defparams = node[-(2 + kw + annotate + closure)] @@ -519,7 +536,7 @@ def build_param(ast, name, default): paramnames = list(code.co_varnames[:argc]) # defaults are for last n parameters, thus reverse - if not 3.0 <= self.version <= 3.2: + if not 3.0 <= self.version <= 3.1: paramnames.reverse(); defparams.reverse() try: @@ -560,31 +577,28 @@ def build_param(ast, name, default): self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) - # dump parameter list (with default values) - if isLambda: - self.write("lambda ", ", ".join(params)) - # If the last statement is None (which is the - # same thing as "return None" in a lambda) and the - # next to last statement is a "yield". Then we want to - # drop the (return) None since that was just put there - # to have something to after the yield finishes. - # FIXME: this is a bit hoaky and not general - if (len(ast) > 1 and - self.traverse(ast[-1]) == 'None' and - self.traverse(ast[-2]).strip().startswith('yield')): - del ast[-1] - # Now pick out the expr part of the last statement - ast_expr = ast[-1] - while ast_expr.kind != 'expr': - ast_expr = ast_expr[0] - ast[-1] = ast_expr - pass else: if isLambda: self.write("lambda ") - else: - self.write("(") - pass + # If the last statement is None (which is the + # same thing as "return None" in a lambda) and the + # next to last statement is a "yield". Then we want to + # drop the (return) None since that was just put there + # to have something to after the yield finishes. + # FIXME: this is a bit hoaky and not general + if (len(ast) > 1 and + self.traverse(ast[-1]) == 'None' and + self.traverse(ast[-2]).strip().startswith('yield')): + del ast[-1] + # Now pick out the expr part of the last statement + ast_expr = ast[-1] + while ast_expr.kind != 'expr': + ast_expr = ast_expr[0] + ast[-1] = ast_expr + pass + else: + self.write("(") + pass last_line = self.f.getvalue().split("\n")[-1] l = len(last_line) From ccd71c857fac76e0aff296ad540fd5364a6ca921 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 24 Nov 2017 22:44:22 -0500 Subject: [PATCH 072/489] Regularze grammar coverage rules --- test/Makefile | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/Makefile b/test/Makefile index 0842bd4e2..ef7ac39cf 100644 --- a/test/Makefile +++ b/test/Makefile @@ -104,27 +104,31 @@ check-bytecode-2.5: #: Get grammar coverage for Python 2.4 grammar-coverage-2.4: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 + -rm $(COVER_DIR)/spark-grammar-24.cover + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 #: Get grammar coverage for Python 2.5 grammar-coverage-2.5: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 + -rm $(COVER_DIR)/spark-grammar-25.cover + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 #: Get grammar coverage for Python 2.6 grammar-coverage-2.6: - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 - SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 + -rm $(COVER_DIR)/spark-grammar-26.cover + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9 #: Get grammar coverage for Python 2.7 grammar-coverage-2.7: + -rm $(COVER_DIR)/spark-grammar-27.cover SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 #: Get grammar coverage for Python 3.2 grammar-coverage-3.2: - rm $(COVER_DIR)/spark-grammar-32.cover || /bin/true + -rm $(COVER_DIR)/spark-grammar-32.cover SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-32.cover $(PYTHON) test_pythonlib.py --bytecode-3.2 SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-32.cover $(PYTHON) test_pyenvlib.py --3.2.6 From 8c0959de425caf50c1d9606b95679a39724d9f8f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Nov 2017 23:11:27 -0500 Subject: [PATCH 073/489] inf and nan tests --- test/bytecode_2.5/01_float.pyc | Bin 0 -> 254 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/bytecode_2.5/01_float.pyc diff --git a/test/bytecode_2.5/01_float.pyc b/test/bytecode_2.5/01_float.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dddd70df3494cb9aad2b89627d08852dba6601aa GIT binary patch literal 254 zcmdn|iI?l+C5fnH1}I9tODc~XXX~Zeu|6r~myXXfYW8yLo?<>V)p=oM5Ja{v|E V Date: Sat, 25 Nov 2017 23:15:07 -0500 Subject: [PATCH 074/489] Merge hell --- uncompyle6/semantics/make_function.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 5885b4636..fc0301c42 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -571,14 +571,14 @@ def build_param(ast, name, default): argc += 1 # dump parameter list (with default values) - if isLambda: + if is_lambda: self.write("lambda ", ", ".join(params)) else: self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) else: - if isLambda: + if is_lambda: self.write("lambda ") # If the last statement is None (which is the # same thing as "return None" in a lambda) and the From 0965e2cc967ab890dc789cdf840ba5a13dcde486 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 26 Nov 2017 01:26:57 -0500 Subject: [PATCH 075/489] Localize kv --- uncompyle6/parser.py | 2 -- uncompyle6/parsers/parse21.py | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index b3120502d..71d074eb9 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -516,12 +516,10 @@ def p_expr(self, args): mapexpr ::= BUILD_MAP kvlist - kvlist ::= kvlist kv kvlist ::= kvlist kv2 kvlist ::= kvlist kv3 kvlist ::= - kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR kv3 ::= expr expr STORE_MAP diff --git a/uncompyle6/parsers/parse21.py b/uncompyle6/parsers/parse21.py index 7e52626af..179c900e8 100644 --- a/uncompyle6/parsers/parse21.py +++ b/uncompyle6/parsers/parse21.py @@ -20,6 +20,9 @@ def p_forstmt21(self, args): forstmt ::= SETUP_LOOP expr _for designator l_stmts_opt _jump_back POP_BLOCK COME_FROM + + kvlist ::= kvlist kv + kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR """ def p_import21(self, args): From 57fe56d72edfaf7bfdd594df63c875e88cc027c7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 26 Nov 2017 01:35:03 -0500 Subject: [PATCH 076/489] localize kv --- uncompyle6/parsers/parse21.py | 3 --- uncompyle6/parsers/parse22.py | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uncompyle6/parsers/parse21.py b/uncompyle6/parsers/parse21.py index 179c900e8..7e52626af 100644 --- a/uncompyle6/parsers/parse21.py +++ b/uncompyle6/parsers/parse21.py @@ -20,9 +20,6 @@ def p_forstmt21(self, args): forstmt ::= SETUP_LOOP expr _for designator l_stmts_opt _jump_back POP_BLOCK COME_FROM - - kvlist ::= kvlist kv - kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR """ def p_import21(self, args): diff --git a/uncompyle6/parsers/parse22.py b/uncompyle6/parsers/parse22.py index ae4ec4c7e..ed0aa2e35 100644 --- a/uncompyle6/parsers/parse22.py +++ b/uncompyle6/parsers/parse22.py @@ -18,6 +18,9 @@ def p_misc22(self, args): COME_FROM POP_TOP COME_FROM list_for ::= expr _for designator list_iter CONTINUE JUMP_FORWARD COME_FROM POP_TOP COME_FROM + + kvlist ::= kvlist kv + kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR ''' class Python22ParserSingle(Python23Parser, PythonParserSingle): From 35aca37557e146d1a7cc29fe006c65e099b0a431 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 26 Nov 2017 06:53:22 -0500 Subject: [PATCH 077/489] Isolate kv, kv2, and kdv3 better --- uncompyle6/parser.py | 6 +----- uncompyle6/parsers/parse22.py | 9 ++++++--- uncompyle6/parsers/parse24.py | 9 +++++++++ uncompyle6/parsers/parse25.py | 4 ++++ uncompyle6/parsers/parse26.py | 2 ++ uncompyle6/parsers/parse27.py | 2 ++ uncompyle6/parsers/parse32.py | 1 + 7 files changed, 25 insertions(+), 8 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index b6fd6cc34..d5e5354e7 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -514,13 +514,9 @@ def p_expr(self, args): mapexpr ::= BUILD_MAP kvlist - kvlist ::= kvlist kv2 - kvlist ::= kvlist kv3 + # Non-null kvlist items are broken out in the indiviual grammars kvlist ::= - kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR - kv3 ::= expr expr STORE_MAP - exprlist ::= exprlist expr exprlist ::= expr diff --git a/uncompyle6/parsers/parse22.py b/uncompyle6/parsers/parse22.py index ed0aa2e35..ffa8aafbb 100644 --- a/uncompyle6/parsers/parse22.py +++ b/uncompyle6/parsers/parse22.py @@ -18,11 +18,14 @@ def p_misc22(self, args): COME_FROM POP_TOP COME_FROM list_for ::= expr _for designator list_iter CONTINUE JUMP_FORWARD COME_FROM POP_TOP COME_FROM - - kvlist ::= kvlist kv - kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR ''' + def add_custom_rules(self, tokens, customize): + super(Python22Parser, self).add_custom_rules(tokens, customize) + self.remove_rules(""" + kvlist ::= kvlist kv2 + """) + class Python22ParserSingle(Python23Parser, PythonParserSingle): pass diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 7fecc1c59..208becf15 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -47,9 +47,18 @@ def p_misc24(self, args): # Python 2.5+ adds POP_TOP at the end gen_comp_body ::= expr YIELD_VALUE + + # Python 2.4 + # Python 2.6, 2.7 and 3.3+ use kv3 + # Python 2.3- use kv + kvlist ::= kvlist kv2 + kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR ''' def add_custom_rules(self, tokens, customize): + self.remove_rules(""" + kvlist ::= kvlist kv3 + """) super(Python24Parser, self).add_custom_rules(tokens, customize) if self.version == 2.4: self.check_reduce['nop_stmt'] = 'tokens' diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 9e0137127..adecc40c5 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -43,6 +43,10 @@ def p_misc25(self, args): with_cleanup ::= LOAD_FAST DELETE_FAST WITH_CLEANUP END_FINALLY with_cleanup ::= LOAD_NAME DELETE_NAME WITH_CLEANUP END_FINALLY + + + kvlist ::= kvlist kv + kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index d8c3d5b08..b972c114d 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -254,6 +254,8 @@ def p_misc26(self, args): return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP conditional_lambda ::= expr jmp_false_then expr return_if_lambda return_stmt_lambda LAMBDA_MARKER + kvlist ::= kvlist kv3 + kv3 ::= expr expr STORE_MAP """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 2142a9657..0bdfdcd80 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -115,6 +115,8 @@ def p_stmt27(self, args): return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM conditional_lambda ::= expr jmp_false expr return_if_lambda return_stmt_lambda LAMBDA_MARKER + kvlist ::= kvlist kv3 + kv3 ::= expr expr STORE_MAP """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index 6b702cf14..455c31a56 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -47,6 +47,7 @@ def p_32to35(self, args): stmt ::= del_deref_stmt del_deref_stmt ::= DELETE_DEREF + kv3 ::= expr expr STORE_MAP """ pass From b0a7452d4827bee6c38a1337bdea38607addf3a0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 26 Nov 2017 15:34:00 -0500 Subject: [PATCH 078/489] 2.7 tryfinally grammar rule removal --- uncompyle6/parsers/parse27.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 0bdfdcd80..e65fb6144 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -123,6 +123,7 @@ def add_custom_rules(self, tokens, customize): self.remove_rules(""" while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK COME_FROM while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suite COME_FROM + tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM suite_stmts_opt END_FINALLY """) super(Python27Parser, self).add_custom_rules(tokens, customize) self.check_reduce['and'] = 'AST' From a9ca30fe34333fd5ce0728a050b32a85e06cdd35 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 12:17:10 -0500 Subject: [PATCH 079/489] Reduce Python 2.5- grammar rules --- __pkginfo__.py | 2 +- test-unit/test_grammar.py | 55 +++++++++++++++++++++++++++++++++++ uncompyle6/parsers/parse2.py | 5 ++-- uncompyle6/parsers/parse25.py | 17 +++++++++-- uncompyle6/parsers/parse26.py | 2 -- 5 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 test-unit/test_grammar.py diff --git a/__pkginfo__.py b/__pkginfo__.py index 28ca02238..2983d59d8 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -39,7 +39,7 @@ 'pydisassemble=uncompyle6.bin.pydisassemble:main', ]} ftp_url = None -install_requires = ['spark-parser >= 1.8.0, < 1.9.0', +install_requires = ['spark-parser >= 1.8.2, < 1.9.0', 'xdis >= 3.6.1, < 3.7.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py new file mode 100644 index 000000000..13b39c362 --- /dev/null +++ b/test-unit/test_grammar.py @@ -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(['build_list', 'call_function', 'mkfunc', + 'mklambda', + 'unpack',]) + + expect_right_recursive = frozenset([('designList', + ('designator', '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() diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index afdf372cb..33c2abf25 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -108,8 +108,9 @@ def p_grammar(self, args): buildclass ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS - stmt ::= classdefdeco - classdefdeco ::= classdefdeco1 designator + # Class decorators starting in 2.6 + stmt ::= classdefdeco + classdefdeco ::= classdefdeco1 designator classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1 classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index adecc40c5..8fc9be6a3 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -50,14 +50,27 @@ def p_misc25(self, args): """ def add_custom_rules(self, tokens, customize): - # grammar rules inherited from Python 2.6 + # Remove grammar rules inherited from Python 2.6 or Python 2 self.remove_rules(""" 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 withasstmt ::= expr setupwithas designator suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY - assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 + assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 + stmt ::= classdefdeco + classdefdeco ::= classdefdeco1 designator + classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1 + classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 + classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS + mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1 + ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond + return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP + return_if_stmts ::= return_if_stmt + return_stmt ::= ret_expr RETURN_END_IF POP_TOP + return_stmt ::= ret_expr RETURN_VALUE POP_TOP + stmt ::= conditional_lambda + setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally """) super(Python25Parser, self).add_custom_rules(tokens, customize) if self.version == 2.5: diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 37e2997c0..e11d1e02c 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -72,8 +72,6 @@ def p_jumps26(self, args): jmp_true ::= JUMP_IF_TRUE POP_TOP jmp_false ::= JUMP_IF_FALSE POP_TOP - jf_pop ::= JUMP_FORWARD POP_TOP - jf_pop ::= JUMP_ABSOLUTE POP_TOP jb_pop ::= JUMP_BACK POP_TOP jb_cont ::= JUMP_BACK From 593304bc43ad5d9508e7f2229996b855e9e17a81 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 12:40:44 -0500 Subject: [PATCH 080/489] Administrivia --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 2983d59d8..af159e8c8 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -39,7 +39,7 @@ 'pydisassemble=uncompyle6.bin.pydisassemble:main', ]} ftp_url = None -install_requires = ['spark-parser >= 1.8.2, < 1.9.0', +install_requires = ['spark-parser >= 1.8.3, < 1.9.0', 'xdis >= 3.6.1, < 3.7.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' From 7553c4aed9cf1058b359dfea746cca6e90727f2d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 12:49:39 -0500 Subject: [PATCH 081/489] Add UNARY_INVERT_OP test --- test/bytecode_2.5/05_dup_top_two.pyc | Bin 0 -> 248 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/bytecode_2.5/05_dup_top_two.pyc diff --git a/test/bytecode_2.5/05_dup_top_two.pyc b/test/bytecode_2.5/05_dup_top_two.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d8ca3998e77cf002489e03c779b79ed81dcd4e2 GIT binary patch literal 248 zcmYLCu?oUK49&HQB8aOl&Yi4_ixd$=aZv{s>2j1d$Z6Xv%~k2*Px)v5faZ$mBk$!U z;gRR7-+OE>rx?EIa9=WM&XRBmxB`SfFCY|v0Lp=J=mNTsI1oE9LIJ7;gPj|2a&Xd=}ab7A&q9<^`xk&%b6h4NtNQlJ|Zha(Gwq@AvBo) literal 0 HcmV?d00001 From 01a27e22b4614ef796ad090f9cb5fe5095f56c6d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 19:39:37 -0500 Subject: [PATCH 082/489] 2.5 grammar reduction and increase coverage --- __pkginfo__.py | 2 +- test/bytecode_2.5/01_inplace_true_divide.pyc | Bin 0 -> 249 bytes test/bytecode_2.5/01_ops.pyc | Bin 252 -> 345 bytes test/bytecode_2.5/06_setif_comprehension.pyc | Bin 0 -> 460 bytes .../bug25/01_inplace_true_divide.py | 4 ++++ uncompyle6/parser.py | 2 +- uncompyle6/parsers/parse25.py | 7 +++++-- 7 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 test/bytecode_2.5/01_inplace_true_divide.pyc create mode 100644 test/bytecode_2.5/06_setif_comprehension.pyc create mode 100644 test/simple_source/bug25/01_inplace_true_divide.py diff --git a/__pkginfo__.py b/__pkginfo__.py index af159e8c8..48a7500d7 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -39,7 +39,7 @@ 'pydisassemble=uncompyle6.bin.pydisassemble:main', ]} ftp_url = None -install_requires = ['spark-parser >= 1.8.3, < 1.9.0', +install_requires = ['spark-parser >= 1.8.4, < 1.9.0', 'xdis >= 3.6.1, < 3.7.0'] license = 'MIT' mailing_list = 'python-debugger@googlegroups.com' diff --git a/test/bytecode_2.5/01_inplace_true_divide.pyc b/test/bytecode_2.5/01_inplace_true_divide.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cffa2df4170eda34072907e87e6b71097095a90 GIT binary patch literal 249 zcmYLDO9}!p3{7W7kU_x%D7YL19TnV(cmfx?b5nF0rP%o}ZAI7K#;r&2MqWS@5ey-H zFE44{Uxf57`v7)8Kv4=f0T=;W0RjWS5N<>wzz9?TJwhskO%l<#ep4iZ zkZba`K5MJXLI*@vNrU?_6)6wi`5L8M69dO54Hn-W(zGGP@h_Kz^?$KLqE_b>P1w@c q8K!%GoX*nmMCzh4y9}kPJxac;a8z9_`$GWCkeU0MZUXTs&c-bd+@pBSQ)^LkbH+3KK&LD?>UfLljVi zks%dGvVj=dP!3I~HZt9A-IL$C(t#0GKGOlF`-nXDiJh#CAeztjc6;F!7X(lo(KuoskO_GK(_uG6Dc5pBd-? delta 104 zcmcb~^oLP;^Cw;|oh^M4$qZ1y1f(5+xHw^=bQE_g0|PH(3JXK92J6HP;yivDj6kUp t5K%etkE*QRSn`EujDqA;;g9$;zJQs8 zqi3~q?9RM-Z$3UxjtBk0eS+`P(|D=Ir|Jkufp<+DvH%<4YU7~yp@-DrCJMAEaq0}V zZx1z|s9TND0Z$Pg1FRj^0R-p*nh2EQkrQ|rEN|-IktA_z5o#fVmbf- literal 0 HcmV?d00001 diff --git a/test/simple_source/bug25/01_inplace_true_divide.py b/test/simple_source/bug25/01_inplace_true_divide.py new file mode 100644 index 000000000..6d7797d2f --- /dev/null +++ b/test/simple_source/bug25/01_inplace_true_divide.py @@ -0,0 +1,4 @@ +# Force INPLACE_TRUE_DIVIDE opcode +from __future__ import division +x = len(__file__) +x /= 2 diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index c69c0ddcf..6c160ec37 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -409,12 +409,12 @@ def p_list_comprehension(self, args): def p_setcomp(self, args): """ - comp_iter ::= comp_if comp_iter ::= comp_for comp_iter ::= comp_body comp_body ::= gen_comp_body gen_comp_body ::= expr YIELD_VALUE POP_TOP + comp_iter ::= comp_if comp_if ::= expr jmp_false comp_iter """ diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 8fc9be6a3..aa1bb6ba1 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -58,19 +58,22 @@ def add_custom_rules(self, tokens, customize): withasstmt ::= expr setupwithas designator suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 - stmt ::= classdefdeco classdefdeco ::= classdefdeco1 designator classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1 classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS + kv3 ::= expr expr STORE_MAP + kvlist ::= kvlist kv3 mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1 ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond + return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP return_if_stmts ::= return_if_stmt return_stmt ::= ret_expr RETURN_END_IF POP_TOP return_stmt ::= ret_expr RETURN_VALUE POP_TOP - stmt ::= conditional_lambda setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally + stmt ::= classdefdeco + stmt ::= conditional_lambda """) super(Python25Parser, self).add_custom_rules(tokens, customize) if self.version == 2.5: From e4110246966ac34fb25260854b5f0baf2dee75e3 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 19:44:47 -0500 Subject: [PATCH 083/489] Merge hell --- test/bytecode_2.5/01_inplace_true_divide.pyc | Bin 249 -> 249 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/bytecode_2.5/01_inplace_true_divide.pyc b/test/bytecode_2.5/01_inplace_true_divide.pyc index 5cffa2df4170eda34072907e87e6b71097095a90..ce7c8daa2300c6cce4e22f1c262889ac98dcdd4d 100644 GIT binary patch delta 14 Wcmey#_>+-s^Cw=e?hO;!J_7(SM+STV delta 14 Wcmey#_>+-s^Cw=e!>cB;eFgwAM+U9{ From 9062f19a97c55947373eddb3979d5b15365469ad Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 21:55:26 -0500 Subject: [PATCH 084/489] 2.4 grammar reduction --- uncompyle6/parsers/parse24.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 208becf15..0eb121a8d 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -33,9 +33,6 @@ def p_misc24(self, args): importmultiple ::= filler LOAD_CONST import_as imports_cont import_cont ::= filler LOAD_CONST import_as - import_as ::= IMPORT_NAME load_attrs designator - load_attrs ::= LOAD_ATTR+ - # Python 2.5+ omits POP_TOP POP_BLOCK while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_TOP POP_BLOCK COME_FROM while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_TOP POP_BLOCK COME_FROM @@ -58,6 +55,10 @@ def p_misc24(self, args): def add_custom_rules(self, tokens, customize): self.remove_rules(""" kvlist ::= kvlist kv3 + while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK COME_FROM + while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK COME_FROM + while1stmt ::= SETUP_LOOP return_stmts COME_FROM + whilestmt ::= SETUP_LOOP testexpr return_stmts POP_BLOCK COME_FROM """) super(Python24Parser, self).add_custom_rules(tokens, customize) if self.version == 2.4: From 2e192f04678c12352812b77a1f273d2e20d2b56a Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 27 Nov 2017 22:16:36 -0500 Subject: [PATCH 085/489] 2.3- import statement fixes --- uncompyle6/parsers/parse23.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uncompyle6/parsers/parse23.py b/uncompyle6/parsers/parse23.py index 3f7e51ad7..f59d3b937 100644 --- a/uncompyle6/parsers/parse23.py +++ b/uncompyle6/parsers/parse23.py @@ -48,6 +48,9 @@ def p_misc23(self, args): expr ::= and2 and2 ::= _jump jmp_false COME_FROM expr COME_FROM + import_as ::= IMPORT_NAME load_attrs designator + load_attrs ::= LOAD_ATTR+ + conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM ''' From fcdc3f67af408cc7186a8963454cbaffa33df4a1 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 28 Nov 2017 09:55:25 -0500 Subject: [PATCH 086/489] Python 2.4 doesn't do "with" --- test/bytecode_2.4/10_del.pyc | Bin 342 -> 488 bytes uncompyle6/parsers/parse24.py | 6 ++++++ 2 files changed, 6 insertions(+) diff --git a/test/bytecode_2.4/10_del.pyc b/test/bytecode_2.4/10_del.pyc index febf095f6222c9c2c7aa2208577f0f37967f816d..371328cb31777ca4d1be695de6bd373e0ba8ee92 100644 GIT binary patch delta 271 zcmcb{^nzI-_Y*JI&Py^;$qZ1y4x}A`xVRliq;OAEC>G&iNMvD1;bdrGV2EO6Na11# z*5I8uL(Qgy5vU{)OeVqggT$Oc`auRI0gYe)DhCPrfl09HR1Jp7Y>WmX%s}C^{CokB zauy)Lz{tQjai3TY6Ob7M;s=2=YOtYj!6qbw$&?_lN|06!R=6TC3#2g!tPv~=d#5|dk(SRGov Date: Tue, 28 Nov 2017 10:01:24 -0500 Subject: [PATCH 087/489] 2.5 test for UNARY_CONVERT --- test/bytecode_2.5/02_unary_convert.pyc | Bin 0 -> 139 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/bytecode_2.5/02_unary_convert.pyc diff --git a/test/bytecode_2.5/02_unary_convert.pyc b/test/bytecode_2.5/02_unary_convert.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f122bb3a7741828ee074de84c5299f81a4f4000 GIT binary patch literal 139 zcmdn|iI;2VC7GyX1}I0^JDor;s)i*GTFU?CVs*F$0&nrtUD$y&bEam{JwaLv-Da}c> KV*=>|Vg>-Vp&Tm! literal 0 HcmV?d00001 From 0b9fca2263d3fbf6ce73aae48c5b098a795a45a0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Dec 2017 09:51:15 -0500 Subject: [PATCH 088/489] Sync with master --- HISTORY.md | 56 +++-- README.rst | 46 ++-- admin-tools/pyenv-all-versions | 19 ++ admin-tools/pyenv-newer-versions | 4 +- admin-tools/pyenv-older-versions | 3 + admin-tools/pyenv-oldest-versions | 9 + pytest/test_grammar.py | 21 +- test/Makefile | 32 ++- test/bytecode_2.1/00_import.pyc | Bin 0 -> 463 bytes test/bytecode_2.1/10_del.pyc | Bin 0 -> 835 bytes test/bytecode_2.2/00_import.pyc | Bin 213 -> 463 bytes test/bytecode_2.3/00_import.pyc | Bin 276 -> 449 bytes test/bytecode_2.4/00_import.pyc | Bin 204 -> 423 bytes test/bytecode_2.5/00_import.pyc | Bin 188 -> 422 bytes test/bytecode_2.6/00_import.pyc | Bin 211 -> 422 bytes test/bytecode_2.6/02_test_exec.pyc | Bin 0 -> 216 bytes test/bytecode_2.7/00_import.pyc | Bin 264 -> 420 bytes test/bytecode_3.0/01_ops.pyc | Bin 0 -> 355 bytes test/bytecode_3.1/00_import.pyc | Bin 0 -> 331 bytes test/bytecode_3.1/01_ops.pyc | Bin 0 -> 355 bytes test/bytecode_3.1/07_forelselast.pyc | Bin 0 -> 537 bytes test/bytecode_3.2/00_import.pyc | Bin 198 -> 331 bytes test/bytecode_3.2/01_delete_deref.pyc | Bin 414 -> 0 bytes test/bytecode_3.2/01_ops.pyc | Bin 0 -> 357 bytes test/bytecode_3.2/07_forelselast.pyc | Bin 0 -> 533 bytes test/bytecode_3.2/10_classdec.pyc | Bin 0 -> 1056 bytes test/bytecode_3.2/10_del.pyc | Bin 0 -> 535 bytes test/bytecode_3.3/00_import.pyc | Bin 202 -> 427 bytes test/bytecode_3.3/01_delete_deref.pyc | Bin 447 -> 0 bytes test/bytecode_3.3/07_forelselast.pyc | Bin 0 -> 562 bytes test/bytecode_3.3/10_del.pyc | Bin 0 -> 851 bytes test/bytecode_3.4/00_import.pyc | Bin 176 -> 354 bytes test/bytecode_3.4/01_delete_deref.pyc | Bin 325 -> 0 bytes test/bytecode_3.4/07_forelselast.pyc | Bin 0 -> 434 bytes test/bytecode_3.4/10_del.pyc | Bin 463 -> 671 bytes test/bytecode_3.5/00_import.pyc | Bin 230 -> 351 bytes test/bytecode_3.5/01_ops.pyc | Bin 0 -> 337 bytes test/bytecode_3.5/07_forelselast.pyc | Bin 0 -> 431 bytes test/bytecode_3.5/10_del.pyc | Bin 463 -> 671 bytes test/bytecode_3.6/00_import.pyc | Bin 212 -> 316 bytes test/bytecode_3.6/03_fn_defaults.pyc | Bin 0 -> 620 bytes test/bytecode_3.6/07_forelselast.pyc | Bin 0 -> 417 bytes test/bytecode_3.6/10_del.pyc | Bin 0 -> 614 bytes test/simple_source/bug22/01_ops.py | 2 +- .../bug26/06_setif_comprehension.py | 2 +- test/simple_source/bug30/01_ops.py | 5 +- test/simple_source/bug31/07_forelselast.py | 22 ++ test/simple_source/bug36/03_fn_defaults.py | 9 + .../comprehension/01_list_comprehension.py | 2 +- .../comprehension/05_list_comprehension.py | 6 +- .../comprehension/06_list_ifnot_and.py | 2 +- test/simple_source/def/01_class.py | 4 +- test/simple_source/def/02_closure.py | 10 +- test/simple_source/def/05_class.py | 8 +- test/simple_source/def/05_closure_bug.py | 6 +- test/simple_source/def/07_closure_bug2.py | 6 +- test/simple_source/def/10_classdec.py | 4 +- test/simple_source/exception/20_try_except.py | 2 +- .../expression/11_multi_genexpr.py | 6 +- test/simple_source/looping/10_for.py | 2 +- test/simple_source/stmts/00_assign.py | 2 +- test/simple_source/stmts/00_import.py | 7 +- test/simple_source/stmts/00_pass.py | 2 +- .../stmts/01_augmented_assign.py | 4 +- test/simple_source/stmts/02_test_exec.py | 13 ++ test/simple_source/stmts/04_withas.py | 2 +- test/simple_source/stmts/10_del.py | 12 + test/test_pyenvlib.py | 2 +- uncompyle6/parser.py | 83 ++++--- uncompyle6/parsers/parse15.py | 12 +- uncompyle6/parsers/parse2.py | 61 ++--- uncompyle6/parsers/parse21.py | 2 +- uncompyle6/parsers/parse23.py | 4 +- uncompyle6/parsers/parse24.py | 10 +- uncompyle6/parsers/parse25.py | 3 + uncompyle6/parsers/parse26.py | 5 +- uncompyle6/parsers/parse27.py | 17 +- uncompyle6/parsers/parse3.py | 209 +++++++++--------- uncompyle6/parsers/parse32.py | 21 +- uncompyle6/parsers/parse33.py | 7 - uncompyle6/parsers/parse35.py | 44 ++-- uncompyle6/parsers/parse36.py | 18 +- uncompyle6/scanners/scanner2.py | 58 +++-- uncompyle6/scanners/scanner26.py | 4 + uncompyle6/semantics/check_ast.py | 2 +- uncompyle6/semantics/consts.py | 40 ++-- uncompyle6/semantics/fragments.py | 36 +-- uncompyle6/semantics/make_function.py | 33 ++- uncompyle6/semantics/pysource.py | 58 ++--- 89 files changed, 622 insertions(+), 437 deletions(-) create mode 100644 admin-tools/pyenv-all-versions create mode 100644 admin-tools/pyenv-oldest-versions create mode 100644 test/bytecode_2.1/00_import.pyc create mode 100644 test/bytecode_2.1/10_del.pyc create mode 100644 test/bytecode_2.6/02_test_exec.pyc create mode 100644 test/bytecode_3.0/01_ops.pyc create mode 100644 test/bytecode_3.1/00_import.pyc create mode 100644 test/bytecode_3.1/01_ops.pyc create mode 100644 test/bytecode_3.1/07_forelselast.pyc delete mode 100644 test/bytecode_3.2/01_delete_deref.pyc create mode 100644 test/bytecode_3.2/01_ops.pyc create mode 100644 test/bytecode_3.2/07_forelselast.pyc create mode 100644 test/bytecode_3.2/10_classdec.pyc create mode 100644 test/bytecode_3.2/10_del.pyc delete mode 100644 test/bytecode_3.3/01_delete_deref.pyc create mode 100644 test/bytecode_3.3/07_forelselast.pyc create mode 100644 test/bytecode_3.3/10_del.pyc delete mode 100644 test/bytecode_3.4/01_delete_deref.pyc create mode 100644 test/bytecode_3.4/07_forelselast.pyc create mode 100644 test/bytecode_3.5/01_ops.pyc create mode 100644 test/bytecode_3.5/07_forelselast.pyc create mode 100644 test/bytecode_3.6/03_fn_defaults.pyc create mode 100644 test/bytecode_3.6/07_forelselast.pyc create mode 100644 test/bytecode_3.6/10_del.pyc create mode 100644 test/simple_source/bug31/07_forelselast.py create mode 100644 test/simple_source/bug36/03_fn_defaults.py create mode 100644 test/simple_source/stmts/02_test_exec.py diff --git a/HISTORY.md b/HISTORY.md index d8871c82d..aec7005bb 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -114,10 +114,18 @@ is done by 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 -reasons. However the main reason is that we need offsets in fragment -deparsing to be exactly the same, and the transformation process can -remove instructions. _Adding_ instructions with psuedo offsets is -however okay. +reasons. Having a grammar per Python version is much cleaner and it +scales indefinitely. That said, we don't have entire copies of the +grammar, but work off of differences from some neighboring version. +And this too I find helpful. Should there be a desire to rebase or +start a new base version to work off of, say for some future Python +version, that can be done by dumping a grammar for a specific version +after it has been loaded incrementally. + +Another problem with pseudo-2.7 bytecode is that that we need offsets +in fragment deparsing to be exactly the same as the bytecode; the +transformation process can remove instructions. _Adding_ instructions +with psuedo offsets is however okay. `Uncompyle6` however owes its existence to the fork of `uncompyle2` by Myst herie (Mysterie) whose first commit picks up at @@ -159,21 +167,37 @@ if the grammar is LR or left recursive. Another approach that doesn't use grammars is to do something like simulate execution symbolically and build expression trees off of -stack results. Control flow in that apprproach still needs to be -handled somewhat ad hoc. The two important projects that work this -way are [unpyc3](https://code.google.com/p/unpyc3/) and most -especially [pycdc](https://github.com/zrax/pycdc) The latter project -is largely by Michael Hansen and Darryl Pogue. If they supported -getting source-code fragments, did a better job in supporting Python -more fully, and had a way I could call it from Python, I'd probably -would have ditched this and used that. The code runs blindingly fast -and spans all versions of Python, although more recently Python 3 -support has been lagging. +stack results. Control flow in that approach still needs to be handled +somewhat ad hoc. The two important projects that work this way are +[unpyc3](https://code.google.com/p/unpyc3/) and most especially +[pycdc](https://github.com/zrax/pycdc) The latter project is largely +by Michael Hansen and Darryl Pogue. If they supported getting +source-code fragments, did a better job in supporting Python more +fully, and had a way I could call it from Python, I'd probably would +have ditched this and used that. The code runs blindingly fast and +spans all versions of Python, although more recently Python 3 support +has been lagging. The code is impressive for its smallness given that +it covers many versions of Python. However, I think it has reached a +scalability issue, same as all the other efforts. For it to handle +Python versions more accurately, I think it will need to have a lot +more code specially which specialize for Python versions. Tests for the project have been, or are being, culled from all of the -projects mentioned. +projects mentioned. Quite a few have been added to improve grammar +coverage and to address the numerous bugs that have been encountered. -For a little bit of the history of changes to the Early-algorithm parser, +If you think, as I am sure will happen in the future, "hey, I can just +write a decompiler from scratch and not have to deal with all all of +the complexity here", think again. What is likely to happen is that +you'll get at best a 90% solution working for a single Python release +that will be obsolete in about a year, and more obsolute each +subsequent year. Writing a decompiler for Python gets harder as it +Python progresses, so writing one for Python 3.7 isn't as easy as it +was for Python 2.2. That said, if you still feel you want to write a +single version decompiler, talk to me. I may have some ideas. + + +For a little bit of the history of changes to the Earley-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 diff --git a/README.rst b/README.rst index ef423c06a..9963e947f 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ uncompyle6 ========== -A native Python cross-version Decompiler and Fragment Decompiler. +A native Python cross-version decompiler and fragment decompiler. The successor to decompyle, uncompyle, and uncompyle2. @@ -17,16 +17,17 @@ source code. It accepts bytecodes from Python version 1.5, and 2.1 to Why this? --------- -Ok, I'll say it: this software is amazing. It is a little more than -just your normal hacky decompiler. Using compiler_ technology, the -programs creates a parse tree of the program from the instructions; -nodes at the upper levels that look like they come from a Python +Ok, I'll say it: this software is amazing. It is more than your +normal hacky decompiler. Using compiler_ technology, the program +creates a parse tree of the program from the instructions; nodes at +the upper levels that look a little like what might come from a Python AST. So we can really classify and understand what's going on in -sections of instructions. +sections of Python bytecode. -So another thing that makes this different from other CPython bytecode -decompilers is the ability to deparse just *fragments* of source code -and give source-code information around a given bytecode offset. +Building on this, another thing that makes this different from other +CPython bytecode decompilers is the ability to deparse just +*fragments* of source code and give source-code information around a +given bytecode offset. I use the tree fragments to deparse fragments of code inside my trepan_ debuggers_. For that, bytecode offsets are recorded and @@ -34,17 +35,22 @@ associated with fragments of the source code. This purpose, although compatible with the original intention, is yet a little bit different. See this_ for more information. -The idea of Python fragment deparsing given an instruction offset can -be used in showing stack traces or any program that wants to show a -location in more detail than just a line number. It can be also used -when source-code information does not exist and there is just bytecode - -There were (and still are) a number of decompyle, uncompyle, uncompyle2, -uncompyle3 forks around. Almost all of them come basically from the -same code base, and (almost?) all of them are no longer actively -maintained. Only one handled Python 3, and even there, only 3.2 or 3.3 -depending on which code is used. This code pulls these together and -moves forward. +Python fragment deparsing given an instruction offset is useful in +showing stack traces and can be encorporated into any program that +wants to show a location in more detail than just a line number at +runtime. This code can be also used when source-code information does +not exist and there is just bytecode. Again, my debuggers make use of +this. + +There were (and still are) a number of decompyle, uncompyle, +uncompyle2, uncompyle3 forks around. Almost all of them come basically +from the same code base, and (almost?) all of them are no longer +actively maintained. One was really good at decompiling Python 1.5-2.3 +or so, another really good at Python 2.7, but that only. Another +handles Python 3.2 only; another patched that and handled only 3.3. +You get the idea. This code pulls all of these forks together and +*moves forward*. There is some serious refactoring and cleanup in this +code base over those old forks. This project has the most complete support for Python 3.3 and above and the best all-around Python support. diff --git a/admin-tools/pyenv-all-versions b/admin-tools/pyenv-all-versions new file mode 100644 index 000000000..6135a635f --- /dev/null +++ b/admin-tools/pyenv-all-versions @@ -0,0 +1,19 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be all pyenv versions we have +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi + +olddir=$(pwd) +mydir=$(dirname ${BASH_SOURCE[0]}) +cd $mydir + +all="" +for file in pyenv-{olde{st,r},newer}-versions ; do + . $mydir/$file + all="$all $PYVERSIONS" +done + +PYVERSIONS="$all" +cd $olddir diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index c08a3ab81..c9f565bdb 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -1,6 +1,8 @@ # -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the master branch. if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.2 3.6.2 2.6.9 3.3.6 2.7.14 3.4.2' +export PYVERSIONS='3.5.3 3.6.3 2.6.9 3.3.6 2.7.14 3.4.2' diff --git a/admin-tools/pyenv-older-versions b/admin-tools/pyenv-older-versions index 63e4e2024..f2e792cbf 100644 --- a/admin-tools/pyenv-older-versions +++ b/admin-tools/pyenv-older-versions @@ -1,4 +1,7 @@ # -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the python-2.4 branch. + if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 diff --git a/admin-tools/pyenv-oldest-versions b/admin-tools/pyenv-oldest-versions new file mode 100644 index 000000000..254fcf855 --- /dev/null +++ b/admin-tools/pyenv-oldest-versions @@ -0,0 +1,9 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be all pyenv the oldest versions we have. +# These are not covered (yet) by uncompyle6, although +# some programs do work here. +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='2.1.3 2.2.3 2.3.7' diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 517a4c2db..138a5d33d 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -17,25 +17,38 @@ def check_tokens(tokens, opcode_set): (lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets() expect_lhs = set(['expr1024', 'pos_arg']) - unused_rhs = set(['build_list', 'call', 'mkfunc', + unused_rhs = set(['list', 'mkfunc', 'mklambda', 'unpack',]) - expect_right_recursive = frozenset([('designList', ('store', 'DUP_TOP', 'designList'))]) if PYTHON3: expect_lhs.add('load_genexpr') + expect_lhs.add('kvlist') + expect_lhs.add('kv3') unused_rhs = unused_rhs.union(set(""" - except_pop_except generator_exp classdefdeco2 listcomp + except_pop_except generator_exp classdefdeco2 + dict """.split())) - if 3.0 <= PYTHON_VERSION: + if PYTHON_VERSION >= 3.0: expect_lhs.add("annotate_arg") expect_lhs.add("annotate_tuple") unused_rhs.add("mkfunc_annotate") + if PYTHON_VERSION != 3.6: + # 3.6 has at least one non-custom call rule + # the others don't + unused_rhs.add('call') + else: + # These are custom rules set in 3.5 + unused_rhs.add('build_map_unpack_with_call') + unused_rhs.add('unmapexpr') + pass pass + pass else: expect_lhs.add('kwarg') + unused_rhs.add('call') assert expect_lhs == set(lhs) assert unused_rhs == set(rhs) diff --git a/test/Makefile b/test/Makefile index 9381c8492..25605a236 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,12 @@ -PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clean_pyc nosetests +PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clean_pyc nosetests \ + check-bytecode-1.5 check-bytecode-1 check-bytecode-2 check-bytecode-3 \ + check-bytecode-2.2 check-byteocde-2.3 check-bytecode-2.4 \ + check-short check-2.6 check-2.7 check-3.0 check-3.1 check-3.2 check-3.3 \ + check-3.4 check-3.5 check-5.6 5.6 5.8 \ + grammar-coverage-2.5 grammar-coverage-2.6 grammarcoverage-2.7 \ + grammar-coverage-3.1 grammar-coverage-3.2 grammarcoverage-3.3 \ + grammar-coverage-3.4 grammar-coverage-3.5 grammarcoverage-3.6 + GIT2CL ?= git2cl PYTHON ?= python @@ -59,8 +67,7 @@ check-disasm: $(PYTHON) dis-compare.py #: Check deparsing bytecode 1.x only -check-bytecode-1: - $(PYTHON) test_pythonlib.py --bytecode-1.5 +check-bytecode-1: check-bytecode-1.5 #: Check deparsing bytecode 2.x only check-bytecode-2: @@ -82,6 +89,10 @@ check-bytecode: check-bytecode-3 --bytecode-pypy2.7 --bytecode-1 +#: Check deparsing bytecode 1.5 only +check-bytecode-1.5: + $(PYTHON) test_pythonlib.py --bytecode-1.5 + #: Check deparsing Python 2.1 check-bytecode-2.1: $(PYTHON) test_pythonlib.py --bytecode-2.1 @@ -130,6 +141,19 @@ grammar-coverage-2.7: SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7 SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13 +#: Get grammar coverage for Python 3.0 +grammar-coverage-3.0: + -rm $(COVER_DIR)/spark-grammar-32.cover + +SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-30.cover $(PYTHON) test_pythonlib.py --bytecode-3.1 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-30.cover $(PYTHON) test_pyenvlib.py --3.0.1 + +#: Get grammar coverage for Python 3.1 +grammar-coverage-3.1: + -rm $(COVER_DIR)/spark-grammar-32.cover + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-31.cover $(PYTHON) test_pythonlib.py --bytecode-3.1 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-31.cover $(PYTHON) test_pyenvlib.py --3.1.5 + #: Get grammar coverage for Python 3.2 grammar-coverage-3.2: -rm $(COVER_DIR)/spark-grammar-32.cover @@ -152,7 +176,7 @@ grammar-coverage-3.4: grammar-coverage-3.5: rm $(COVER_DIR)/spark-grammar-35.cover || /bin/true SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-35.cover $(PYTHON) test_pythonlib.py --bytecode-3.5 - SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-35.cover $(PYTHON) test_pyenvlib.py --3.5.2 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-35.cover $(PYTHON) test_pyenvlib.py --3.5.3 #: Check deparsing Python 2.6 pcheck-bytecode-2.6: diff --git a/test/bytecode_2.1/00_import.pyc b/test/bytecode_2.1/00_import.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3f3da8218fce95c07d8189c19fda777928d43bc GIT binary patch literal 463 zcmZ8cJ5s|i6x=80>m-M@2 z_3qQoYBl?r#NUtix_~Stn?D6w`4mcE3uxgHO2U>*;6%R1nRm#L59e<6PbE-$$@@d4%K38@GK;0IxBca7Y~^~a$wb9Ot& d^Ti^UX?<{6a}4)BDezd#3Efgmca+dn{Q|zbSfKy_ literal 0 HcmV?d00001 diff --git a/test/bytecode_2.1/10_del.pyc b/test/bytecode_2.1/10_del.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41a3f854e4101e68c2ef637881522c853fd628dd GIT binary patch literal 835 zcmbVJ%T5A85UiPDmv8a9a*YMfKX3B@*!)fApQcRnH^l@dCsFd;_*1F%=Zik4iMnR5543lg$2X68BFiN{_HD9^z<;B3Jv(9qu*v5FVsKK!p zqm81b8q%~$85+Yk@k~LBho;${WW)W4r|69oQH6ZWVw;Nr1LP6LON(HSzZ3l(&^-J3gst8(IA}8oB z+Fsy2*go_CZ69U`6XTOmM0iuEXW}soq7m#Eb^?8cJ%Pkym2@P*b3#6hr_I`JPnB;y zSOFwc0ggNznSJh>FXBL)tqgZ%;K?#bYhLn5I$P(OG%u~$JMKw+rtx`nF1>ka_B@a~ z%U*41vMd;`(@mPQ&$0=4;zi=EE|L7WxNQA>#-Bj{wu-PD$#g)ZyWs}<( NO}UvN+V~j-7y(=K7vcZ_ diff --git a/test/bytecode_2.3/00_import.pyc b/test/bytecode_2.3/00_import.pyc index 6f7a4077f52825b0ef18d9b4da4124717075e3c4..5701ad7b80dd1498d014d8d6168cda52d4499ea9 100644 GIT binary patch literal 449 zcmY*U%TB{E5F9&wrVU8+1K>u)A#Kkb;0w5vlP^)57}Yc{bnESwFK{yj9><#O2G^R8NrQVCa_c3 z7~cwIginoj!F}8?gPX%8FgIvakT&Uno!(LEQcI_{#{(p$B-BRvF0D6!yuI|{6+OK0_m*i_t%hf7pwLSW*I|Z8;`8LfN OrYccmb*JWPq5lA9{Zy?0 delta 134 zcmX@eJcUWx`V%i#GspVyWCkc;0@4mZTx>j1+Egi6gBi&7(_jRNumFjI#F7jM4lSt;$-AyWM>2b7f%*2 diff --git a/test/bytecode_2.4/00_import.pyc b/test/bytecode_2.4/00_import.pyc index abf33a9e622e456d5a8a4cf6e3224d093e9600ff..e8693994f02fcd4d4caef5f6e94bbe274b98ca37 100644 GIT binary patch literal 423 zcmXv}OH#uy41IR`OPat8Jpk;;ut?hzzzJ9cR^DXV#7s?-CR2+=*Ibd4Z~`PZct+1p z^3#*t{btF}(*n9dH z2STp1G!+$-ZIJeUOG~aCh=!tWojnoFI3H;;K8>lEw=7xkT~!~hwN(`icg4P_!!G-P zSKj1eRmxsvU^2UujZ1MVV}_jL3iQCtyKZ1t-+!HJyY|$PUvD-QSNk&+!zH*s%jbN` O5UWhh)tyS!O8)_;E=iUE delta 104 zcmZ3^e1=gv_Y*HyNo-?yG6NJa0ci&yE>@fkX)uCBSb#)9Vo3&=R{|2! g(qNvrQkq8tq$vm_5X3w=iqV1>qzSB?laZGZ0G-zk-~a#s diff --git a/test/bytecode_2.5/00_import.pyc b/test/bytecode_2.5/00_import.pyc index c73f03f7e35b1966572c04630c3654e0c00a6a95..fc0377f460343b49044e0b49d2963eb8c57e4ee9 100644 GIT binary patch literal 422 zcmYLFK~BRk5S(?=Qqq(nAt7#XBjS*@cZ7HW2jJvO)FwtXO`53Q9?F#`@fBXe2Vk9~ z!ivW;Ev0J`G}8$zj|70B-eUcdHL0d#omAn3u7 z4`ENBM=+-_5k3h;hDMwfj+~Q#3j5W13BLQ%6LjhD2D>glGmN`)}0kV zG8N!Jz#SYbS!?$!*mbb24Ercg7HwJW7CaVb&D^AUY0Z{-D7vRnztu}0TuO=mEm`(v zOOs`7;4)pMIs1F8TI_g{h=G4_HzJ*_8tHTOewUk>dh{fy@$+ih{(F h46sBANVd4LxP%Ev=NAV7NruS*jE>x3agZPnBLKFN6dV8m diff --git a/test/bytecode_2.6/00_import.pyc b/test/bytecode_2.6/00_import.pyc index da09e5d89fca378f45ac64443d6f279015046724..5425f49f0edcf8d1d545fd938614eba89b8aa68b 100644 GIT binary patch literal 422 zcmYLFK~BRk5S(?=Qqq(nAt7#XBjS*@cZ7HW2jJvO)FwtXO`53Q9?F#$BJmPF0P7?b zRy>{=?~d(!{Y;|o+iRVpA0t^GWx5Z6LO#L<&>dIU5K0BDKz=Xq`n9hLpu=MaK@X06 z2zvrOf;okW@JT2_yerg~U54b3VPn_{^cl7!F5x8^$no}9##2H`U|D RU*KYan9eDpE1J@U`UB66P%!`i delta 88 zcmZ3+e3?=D;wN6NlGw)ZWCkc;0n!dYT&y)wT8ovDAy|WD;w&Xe4Q8NN35Y1JEG}UJ Y()qSRAC2hf#nL00tipmH+?% diff --git a/test/bytecode_2.6/02_test_exec.pyc b/test/bytecode_2.6/02_test_exec.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e92742343dfdfb870c74e07f233b46f6c8d72454 GIT binary patch literal 216 zcmcckiI+=Zn^IIV0~9a=X$K%K)&&wN3=B~W45>f{BLhn)kWOV}Xl6iWrZRy9LV@zZ z8cZN<}ml?>-0V?4D((&9- Ol59YNhf#o$ixB|QAq$QG diff --git a/test/bytecode_3.0/01_ops.pyc b/test/bytecode_3.0/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6988377b9f5ab1b62f10ffcb5d85cfc0e1f066cd GIT binary patch literal 355 zcmY+AO=`n15Jo>qw&R!jCa-lI3n zj4?_hp~w4X1|gI`JZ69TrL6I9CFJjP+%LfZSqWG&foX3Nd8n;>Q}_tB3EfGs&tO|J zy38n;2u8xh*vBZTB4CLL%a26ShloQh@oZAOslp7f(?fdNA!7(e#E=Zdh#7RS)m`pp zLR+(Wu3b8QYaYG9Pbs>?sXf}tHU3=N`Iq0nF6N76)wFKbUVKUu#i=p=XjlAQ?ujrE K+5J{yF%nm0*)M4T literal 0 HcmV?d00001 diff --git a/test/bytecode_3.1/00_import.pyc b/test/bytecode_3.1/00_import.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb446008e3a9f0c7362cb4594c1e8b52e6d9841d GIT binary patch literal 331 zcmYjL$%+Co5UuKVn^wW&oMd1wjR%*z4D$twIHz1h+JG&|q_I*5zr^3Q%5ImCyu2+% z)`Ma8eI1(u-d0!muN>M49AqOn08{e>9D+~4B!HTws{fi+3a0gVfneGX-hopWOiw3m z^Oj64<-jUOK~`Pu-f~+4C5wAC(1QEo9Am7eg)8lU z_GMhXXtNqn{!*1~|eD GKk){*(L5sn literal 0 HcmV?d00001 diff --git a/test/bytecode_3.1/01_ops.pyc b/test/bytecode_3.1/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12d44468135b7d5de5dc2718cae6b84446851841 GIT binary patch literal 355 zcmY+A!D<3A5QhIGyY9Lu^irXq;4!DF^x(mz2tC&7p|`y(bQ45Sc4-LI2k;eq58tpe z%aYoJe0=}R5JGl?VRqBgqQc$kk+12vE5QI+0a!ADNoNwPPP;`}DL!#t@8%AsLDhGw5Ke+uY8C zwr2BOJGcDNJo*Peq38~$=4eY-`|rxmzWn}WKASJfx^d6V*{3v-pK9Ze_LaZOjR=Xz K{%`dt9>gz!l`nk& literal 0 HcmV?d00001 diff --git a/test/bytecode_3.1/07_forelselast.pyc b/test/bytecode_3.1/07_forelselast.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c107bef66e723740a7333aa7d340490f905a3526 GIT binary patch literal 537 zcmb79O-sW-6r9aRQ(B99^CF0#oDps33-Po0^Wf!H4H=7ASJYk^l=Cqgd0Mxh!z}CDg*K!i&Io4sry(qP}&%H^KDoK@X~_324jq#URrn{c|`DD9b|x)ZGF3* zYnQQdIT#J*4!k#@vM7^DlY2^YEJR%=fpql}N+;|O@1zvc)xENaa-POY?~r7%$dz6x zK2~iiX%I!yU&&4So=H)NP^7A%J;5|d%lgOK=aPn+)E;$tGM%N|&xMj9?@rXy$x-+4 z%#VfSDNPLW;$T*)O>%~k2L<;-k!3tA5|P!RcIXDoL4%pB@l|csVe3YVxNX>mY4lcG Y{rSjGod0HO(%|!{h*Zii>L@zNC%W}&{r~^~ literal 0 HcmV?d00001 diff --git a/test/bytecode_3.2/00_import.pyc b/test/bytecode_3.2/00_import.pyc index a9b3648ce45500a868a52ae75e871bfe2d9aae5b..89ca5d6a7d71fd10d47995ff89ade2623439bc33 100644 GIT binary patch literal 331 zcmYjLON+uV5T0p$ZB_8-Ndzy&gO9r``wN6cPq~QHfR$uZoXo*r;@@?~R^5<%e6I}S z2E%N2pO^yvokaMLJo*(l$whDgrsfGa1fPIO05wZh@0(T%ruF)PVA?O!8S)hR$U$AxmIe;^Dhlj0lE?EK7ro7CyAxE+?GJe`dJOM=Ds-R7^_9$O8XbN zBf6nk6V);o1s~w4NGg5h?12Jb3%jJ~BP~~}gSg=u7uAh>Qrh@%VrRc~DN4)9!3CG^9_Cg diff --git a/test/bytecode_3.2/01_delete_deref.pyc b/test/bytecode_3.2/01_delete_deref.pyc deleted file mode 100644 index 151843094164dbbfde10d2ab289809b03c8d4236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 414 zcmd1d;pKX|TR}$DwAjdH_m{Wz%FNCWM=dOI~{CkBE)2nr6fC=1E|R+H$SB`C)EyYKFAaR!;?mq diff --git a/test/bytecode_3.2/01_ops.pyc b/test/bytecode_3.2/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39137bd7a6b504c3cda5d7f861d3d69b354bd53e GIT binary patch literal 357 zcmY+8%ZkD<6o&saZAXj3Y!n7`)?InQg$s)aF1>8rbt8-kB2-!o0et|Uz^xBE=Y$e9 z;e34O=B-Y+m{#$M@{ka`dB}kv-}-jF z7?-tjc^LNR9)fqEb|{lglY2^YCWN`ik@WQvN+*06+({{{zww;!%>wa3weCJ(HpovEZtqJ<)W+EA!F#e9~Y@?NL=srZb*~g-|k1yJPiya@0LM z3o{{8P7|Y|JeXB#gPgHUqcRO+k>_b#PDE}(ZR>Wd!)(?t>=LhAE#kK2TDH|&ZS-e@ VpD6#$)1;y2Q;{g1UYHm<#TUF?YZ?Fm literal 0 HcmV?d00001 diff --git a/test/bytecode_3.2/10_classdec.pyc b/test/bytecode_3.2/10_classdec.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75d9e3bc80db3b53405096a87775e06650ba96fd GIT binary patch literal 1056 zcmb7D!A|2a5FIxy&{6~v5@(J%tYEqCt`IDO3%&G!=*7y~uE;8B5RN5~;MDz0euF#j z*$4_~C2GZ!$;|l8_|2pmZVVoueqI<^SS!#EvHfodEAmfdBI2Mcu^pLrqMpfI$*Jwq zZF}OB%%cg`2_g`OW0}|$8Rx42dQH*6hr&L^_8Sm@1;&GtdxcoKM}`4hd~=VneHY>$ zdQQtIhmfd-44SEYvd|oMA$(b1S5EsT+!(iS-E{xpyEawfy>({q`Yx;^s0i&W2|Nv5!l)WkR9@?4E9Nh8es|1i++wX9i$T`UG8GnFqnvFBZ!;6s=FeYe+Qqm) dMsMG0h}zeF0`l@BG4U%-Bn|!EP;INt{xg4I%6k9+ literal 0 HcmV?d00001 diff --git a/test/bytecode_3.2/10_del.pyc b/test/bytecode_3.2/10_del.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46fec21d3941533d848c96d50583d29c1c53cc15 GIT binary patch literal 535 zcma)%F;BxV5QU%ZCPAeUU0^|iHB$p(r3i_=3!53LHa1nHM5%Byu+txb#E<2j1!^iW z5XGPG&gXZ}%_JY+eO=iKgD+$J$Q3>bcM1!>^|{K)OEuN0`UdA=OM?Ia literal 0 HcmV?d00001 diff --git a/test/bytecode_3.3/00_import.pyc b/test/bytecode_3.3/00_import.pyc index 78fe82064bc63939a2f045431be9e387b4815a4b..0c9e5407c6c3bca178b7a6acc975eaf072771f53 100644 GIT binary patch literal 427 zcmYLEyH3L}6g_s@Qqq(nCN|iJ7}9n}h%e{@lb5JXjGEv)6x$M=`47H|pJC(LNs8rr ze9pNK+uzYL{CT(&zW_3d^Wwx_DD)>mPMbjiqURinq2dr6%;f^7--fCHVls9xi0Q~@ zC@&!9ke84lzL@hrI65;HEKo)$mk?K|{e`dbgf1^Au!|X?b-LY~W3Qa`7_VF+AkZgm z-Lo5guJgncm9$ezII{Jnjo#V?IY(pKBvXZ~jh&GmXgH(>>4qy=+c}+S`d%oRrhec) zIV72N&p3GOc^;F2f3Wu?by2m{ryJX4a;;5e^m?;N$!$85v?o9OscLeogg9}<`(3n w#uw+87A2?Z7nkIg6zdxp!~;e1i%RqgDoZ(l%4~A;Q%ZAE?Z763jOAej0MQI1V*mgE diff --git a/test/bytecode_3.3/01_delete_deref.pyc b/test/bytecode_3.3/01_delete_deref.pyc deleted file mode 100644 index 06a987bbe58a02834ecf507eb9d9787fa5a72cd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 447 zcmb79y9&ZU5S&vB5e31@9}ugkh@FUEkj6?I$>S8^B;t8R3OiA;^9OAGO=m9<#LkeN z+g)aMc3;g_Gj)_s77J0G!$7)>dZiQI_im*W($%%Hh_Wb&m7Zag z#v)UC;P^;2=}3Ywl>S1lQ$LX+7hEK&rai%UloZv)%IA`XiqtMu*=RgTB0m#K@~Ayj zPsfMtgHt~iGD_&jAj|hBg<2;kmr;;MJ{M^k@q8rGD%6&Kj9_AuRVd@ftYyb;;kM?>8^yNq{O8MNc1FX{0Ck<`(ON1 z&TPRV@xZ40c6R!9=FQA!y-`!&=h24%5^Su1>}%Tgi$FIJ0e565=nAxlkwPS31T@g) z!{=`)(bWO_G`S?xM;;;xLpCws7<_TR|Dms<2Z$65C8J1=y;Kx=A2B7bLGR%ih&<>z zbk*6!^KlzCN$i+P!B{dVh6;nn;1l%61jv~aI~@KgoBcPmE!RJ!sGz9q>^pQXOh|W> zkYCWX)wbiwG&KX8o-5AVH$6HLhuf} z(ktqfYu5|#xKhNFe!>rU@yXi-XW>u4TPd6zDAmtPbKz>(Nj`@ko)TDYC!~^jozA$` zNwXwQZLc*f8p6b)uUq%U&UxZvic#bdN`zeN)=We0;N}cN9_^;X*@;8#(5%~C$Rc_% l!JSl9iQSoGI!{fHQ(IQ(OQo735Dj@G8iZ%!K>DKY{Q!vteGdQt literal 0 HcmV?d00001 diff --git a/test/bytecode_3.4/00_import.pyc b/test/bytecode_3.4/00_import.pyc index db26ac849dbbd5ea8a2879598514d5848a0e297d..6174ea0acb495361b997c55bb5d901b7553a3fcc 100644 GIT binary patch literal 354 zcmX|5Jx{|h5WRDf5|Wf6CN|hm7}9n}h+ohJrdy&mF=~SIq1ct^%&+19FnMKSVTXxx zKd|oJJwHF+-FGsMK5nk)2LL`f|Bqnyz^PvuN)7}CKzlAgAv6L=0J=BN-JcFF56D0M zK%n5rM^K*tg&^hv)T$f(%Yr1lyWYl3P-&Z(tA)l*}(G(JQFD#bJ}1pHiBWYR3%JTMROXhYbTKfrGccqvf^-1YwlOf&f(-y_@`LLFX$9#N2I68CAko19G?meBB|{NNSd;M< zVsWjc#Sl_@fJ|#6LwImft6{V)>6;$40Oai&0802gQ z#wwmfJ)4~TV$K7Bfx& diff --git a/test/bytecode_3.4/07_forelselast.pyc b/test/bytecode_3.4/07_forelselast.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3593c8db8768d80f68cc55cc76ad7aba5ce5d81 GIT binary patch literal 434 zcmYjNyH3L}6g_rcRZ9hkg#i{M5LqZMi3K5^Bc)P@7E35f^MHsnZkvB$R2% z!$Z-EUEfzuEr`ZM$xM1O7G~&2!k#tj#oL)@%?j^CoeN8(ibcqs94`0En+a literal 0 HcmV?d00001 diff --git a/test/bytecode_3.4/10_del.pyc b/test/bytecode_3.4/10_del.pyc index 1aa477c0cbeddf6dff66ff723726cbdff89adf5d..269d2be38e09421f3cbe1e17aed76d85908acf10 100644 GIT binary patch delta 337 zcmYjMJxfC|6g@ZTd#!Ea6GZR>1aWDX{sNKyf-W7zZqFB-3PLhjP#3G>R-Bw%{UL4+ z?ym0s2G5NZyyTpmT+X>kKI}`;|8~A>-}k4_0({|LwW&u$dL;$F>@N=2QMVAf2tC{a z(*nUEbh4(U#AHw{-xfEUnldEV=*f*rEnWe;LfWBt1nz-zLEtjD1Fkp-9Aw9hy0vsy z>3DdyN@m-iu4s%o k+@abge#2tr=~PY*^h-(GrLne>ws^B8p1da;rW9BF0PX!M3jhEB delta 128 zcmbQwdY)P19S<*;;CJq*^$ZLQkAWBt*nunuATFK*BvN=LYP5>;G9w-i~wOG5kmj~ diff --git a/test/bytecode_3.5/00_import.pyc b/test/bytecode_3.5/00_import.pyc index 1ced1b8ca1b16eacdc7e07bcbd9918a64b9384e1..9484a59d9a7519f11823a06f0e4f68afaafe7a02 100644 GIT binary patch delta 223 zcmaFHc%MmGjF*?|in@H%PX-2t$3P4ROhA?c5EqwDRCe-ZU`SzP$YEp1VrPirU`XX; zNabQ^W@JcVV8~`-C@KUoKnl1SvUnJ>cp0MjK-^$WmX{#&{4^PFu@oehWB_SKElvK3 z^$MO*+!-Y$1$xOjnW=dtQEX6}3nU0(-(t>5&AY`BAD@<)lNui%#hR#>q?de)G3gc~ lkW5+0P{a*1x`=z?3Vl(KTZ?&s1P`MCBNw9tBR``M69BihGWY-h delta 131 zcmcc5^o&tijF*?InPYu;6axdpV<3hDCLqfJh>M*jDmytdG6ZX~yaY-5X)@koDM&2I z0Md+Fnrye2iz|z7G36H*fpkQ%lw{_nMzMlO!zkwbV#AdTMQlKcBDTrWjQae{KxQ$B L&%-Fd$i)Z%?Hn3J diff --git a/test/bytecode_3.5/01_ops.pyc b/test/bytecode_3.5/01_ops.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9166a5c3c0819882432d636758702156218696d2 GIT binary patch literal 337 zcmWgR<>mS!Eg$uhk%8ec0}@~ZvK@f9cruVk;b4ejU`Pcr7#U=tEG7nPxR^7P#mwLX zXL-YAW#BAdILi;n0veXW%#gyukix`}!pe}&$`Azlq_8stYjVBh0=n!a(A^9#SwI96h+qa0tRMo28T^Vs(wfXgAh{xtsv?k_Cetm( z%3F*TD;bJFW`K!bvc;LX1v#nl#rdU0$*KBDrRl~7`UZya`31##1(mlrY;yBcN^?@} UKmk)M1|--RxlkdqD5C%)0EVwOg8%>k literal 0 HcmV?d00001 diff --git a/test/bytecode_3.5/07_forelselast.pyc b/test/bytecode_3.5/07_forelselast.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f78ccdd93ce0cfd397f581fd694605010c990643 GIT binary patch literal 431 zcmYjNyH3L}6g_rcRjUdR0}QYrf#^ah3@oTZJQjvhsY8n;RMNyj5oz2ysc58hLHrC8 z|C5!!VB#i7s8>G6_Bq%0+TLk4>)F?VIOf1N)`Ir9A|#tcJ`IKsK+u9?&@w!W zHsOYlXrkpSa)#TdXRIt_UF0149?K4LgVZCeY-ASt!}&hU6nL#eUxP754OS)|Ngfe~ zZw`j>?thA`QutqrgHeA@{yUJHY6r8u4yTs(y6U5*L2x5~o`2`aE1!+=<=`Oce1%%zofZ7-pyI^Hy>kqNB zu(!=0$-Fg!kDb}s$IRQ^Z~LD0y3V!j*YV^{fEE5#llq*9A0+RVy~XJ^ss?-;zJmu~ zlED}7t)ywmG47Yk&&B<&rVI%-IC8C0i&wyI5DzF`fG6Ne;JFMQfm;p&2iZ}rZY|vv zX{^5L4tQ3Nj6#RUzWm6I(mWl*xL`AEkq(L2Ai-EOFRH=W?7FUIaX6T6lF9a`OBzE8 jx2X1s->_JDy_Aa+{ZiC+Zmcb(DbDPPBOl3*$)(8F*BL1^ delta 128 zcmbQwdY)NBjF*>7@H=_CNaalBYGzDf z$Yv_?O96>;XYpk5M)9RE1~X`~yaZ|Y(`3BGQjl1Z0i+qVH2EjyDtJb5XOxr_=q2Z5 zrskDIu|a7rkRXJ8i#aDX?-oaVd|GBsYJ7YYYocC~Uh*x*q+5(YGG!%05jW82BJPRP Y^hH5VE9Ln@bQ3{;7aHc4H@Z!U*;4Qgi2SY^Ro|p02k>Dmd*C>8+)~Mw|!@XuFs$V_c@ zUd)#EF}a?dCt3NNQBf{z^E4{gc$oX{Zne{o@iaCMgg8m=&Vrj&O|~j-Q8JJfN<4o}Jy>4= literal 0 HcmV?d00001 diff --git a/test/bytecode_3.6/07_forelselast.pyc b/test/bytecode_3.6/07_forelselast.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3a0a056d42c9ca3a147d5e8a75102713fa6ea81 GIT binary patch literal 417 zcmYjN!AiqG5S`s5+Y)U-1o7ZW6wIYnd$0$Qf_klm9$FV9q{&8uX|~->v4Qj={){L8 zCs+T%lar-~&hp+e^WMx3+iSJl;^&lKP=H_93Cv-D(ECUcMC1!NM05p<&moKG=5Y{Dz8!5TBI>|k}Q_GqVYA~OM@s< zzA5nLLdjf)GUY4|=1E#`$H?EHY~26vTqpBIDts+hDiqz>>a};(y}a>bsYHsC1D$sk zMRgD=5#+)TWtNFBPh?hi>k}j(E}_IW%t)KGY0WNWlv2e|A9}>x=D{7RKecM!&SkVp K#hsZ~kNXE}g;~!4 literal 0 HcmV?d00001 diff --git a/test/bytecode_3.6/10_del.pyc b/test/bytecode_3.6/10_del.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5090326393af024510d8cb3926fd533db0b65330 GIT binary patch literal 614 zcmY*V%}&BV5T4m>OD%s1UW^Al_W~NPKuo-I@m3E6I)#{&lG5r6i{^okxMo5`3CZCA#Cp0 z7wnXP7H|Yy0gqv@V}Kk-IgVpV_eWGW99CFkAmCm&2r>iJNAAyPm`g| zmL^U*b}?Jn&gI3BlC(Wv<$983$I?hFfHrl;!z7s^t|V-W;T4`?g0l0*e=Mi!K`b;m za!VBb#Ml$Ol*S4(;%+6dE)CY0VU8G1Ijk%WN~v{i)b6HPJW6f9J^m3Ew0+)WqAA2a zXD1w`7!`)vhyf$Z7;zmcBcwtfdcS#&agJmHd6Sh(M~8na+UI_EmeDdz`qIwIAV(=3 Rpof8KV8GbInsU&0zX6!mUv~fi literal 0 HcmV?d00001 diff --git a/test/simple_source/bug22/01_ops.py b/test/simple_source/bug22/01_ops.py index 4f97eadd9..18efd99ea 100644 --- a/test/simple_source/bug22/01_ops.py +++ b/test/simple_source/bug22/01_ops.py @@ -12,7 +12,7 @@ `y` # UNARY_CONVERT - No in Python 3.x -# Beef up augassign and STORE_SLICE+3 +# Beef up aug_assign and STORE_SLICE+3 x = [1,2,3,4,5] x[0:1] = 1 x[0:3] += 1, 2, 3 diff --git a/test/simple_source/bug26/06_setif_comprehension.py b/test/simple_source/bug26/06_setif_comprehension.py index dce585aed..9b537ba27 100644 --- a/test/simple_source/bug26/06_setif_comprehension.py +++ b/test/simple_source/bug26/06_setif_comprehension.py @@ -1,7 +1,7 @@ # From 2.6.9 abc.py # For 2.6: -# genexpr_func ::= setup_loop_lf FOR_ITER designator comp_iter JUMP_BACK come_from_pop JUMP_BACK POP_BLOCK COME_FROM +# genexpr_func ::= setup_loop_lf FOR_ITER store comp_iter JUMP_BACK come_from_pop JUMP_BACK POP_BLOCK COME_FROM # This has been a bug in other Pythons after 2.6 were set comprehension {} is used instead of set(). abstracts = set(name diff --git a/test/simple_source/bug30/01_ops.py b/test/simple_source/bug30/01_ops.py index 2c3a4a80f..9dfb189ba 100644 --- a/test/simple_source/bug30/01_ops.py +++ b/test/simple_source/bug30/01_ops.py @@ -1,5 +1,8 @@ # Statements to beef up grammar coverage rules # Force "inplace" ops +# Note this is like simple_source/bug22/01_ops.py +# But we don't ahve the UNARY_CONVERT which dropped +# out around 2.7 y = +10 # UNARY_POSITIVE y /= 1 # INPLACE_DIVIDE y %= 4 # INPLACE_MODULO @@ -10,7 +13,7 @@ y &= 1 # INPLACE_AND y ^= 1 # INPLACE_XOR -# Beef up augassign and STORE_SLICE+3 +# Beef up aug_assign and STORE_SLICE+3 x = [1,2,3,4,5] x[0:1] = 1 x[0:3] += 1, 2, 3 diff --git a/test/simple_source/bug31/07_forelselast.py b/test/simple_source/bug31/07_forelselast.py new file mode 100644 index 000000000..641451968 --- /dev/null +++ b/test/simple_source/bug31/07_forelselast.py @@ -0,0 +1,22 @@ +# From python 3.4 asyncio/base_events.py +# Needs a forelselast grammar rule + +def create_connection(self, infos, f2, laddr_infos, protocol): + for family in infos: + try: + if f2: + for laddr in laddr_infos: + try: + break + except OSError: + protocol = 'foo' + else: + continue + except OSError: + protocol = 'bar' + else: + break + else: + raise + + return protocol diff --git a/test/simple_source/bug36/03_fn_defaults.py b/test/simple_source/bug36/03_fn_defaults.py new file mode 100644 index 000000000..172d61d1b --- /dev/null +++ b/test/simple_source/bug36/03_fn_defaults.py @@ -0,0 +1,9 @@ +# Python 3.6 changes, yet again, the way deafult pairs are handled +def foo1(bar, baz=1): + return 1 +def foo2(bar, baz, qux=1): + return 2 +def foo3(bar, baz=1, qux=2): + return 3 +def foo4(bar, baz, qux=1, quux=2): + return 4 diff --git a/test/simple_source/comprehension/01_list_comprehension.py b/test/simple_source/comprehension/01_list_comprehension.py index b1d33e253..d7baf0509 100644 --- a/test/simple_source/comprehension/01_list_comprehension.py +++ b/test/simple_source/comprehension/01_list_comprehension.py @@ -3,7 +3,7 @@ # Python2 grammar includes: # list_compr ::= BUILD_LIST_0 list_iter # list_iter ::= list_for -# list_for ::= expr _for designator list_iter JUMP_BACK +# list_for ::= expr _for store list_iter JUMP_BACK # list_iter ::= lc_body # lc_body ::= expr LIST_APPEND # diff --git a/test/simple_source/comprehension/05_list_comprehension.py b/test/simple_source/comprehension/05_list_comprehension.py index 8f7884baf..919a90dac 100644 --- a/test/simple_source/comprehension/05_list_comprehension.py +++ b/test/simple_source/comprehension/05_list_comprehension.py @@ -5,7 +5,7 @@ # and ::= expr jmp_false expr \e__come_from # expr ::= list_compr # list_iter ::= list_for -# list_for ::= expr _for designator list_iter JUMP_BACK +# list_for ::= expr _for store list_iter JUMP_BACK # list_iter ::= lc_body # lc_body ::= expr LIST_APPEND @@ -19,9 +19,9 @@ # Python2: # list_compr ::= BUILD_LIST_0 list_iter # list_iter ::= list_for -# list_for ::= expr _for designator list_iter JUMP_BACK +# list_for ::= expr _for store list_iter JUMP_BACK # list_iter ::= list_for -# list_for ::= expr _for designator list_iter JUMP_BACK +# list_for ::= expr _for store list_iter JUMP_BACK # list_iter ::= lc_body # lc_body ::= expr LIST_APPEND # [ i * j for i in range(4) for j in range(7) ] diff --git a/test/simple_source/comprehension/06_list_ifnot_and.py b/test/simple_source/comprehension/06_list_ifnot_and.py index 18f3e2efe..d5d3dcaa2 100644 --- a/test/simple_source/comprehension/06_list_ifnot_and.py +++ b/test/simple_source/comprehension/06_list_ifnot_and.py @@ -6,7 +6,7 @@ # 76 JUMP_ABSOLUTE 17 (to 17) # And getting: -# list_for ::= expr _for designator list_iter JUMP_BACK +# list_for ::= expr _for store list_iter JUMP_BACK # list_iter ::= list_if JUMP_BACK # ^^^^^^^^^ added to 2.6 grammar # list_iter ::= list_for diff --git a/test/simple_source/def/01_class.py b/test/simple_source/def/01_class.py index 95cb27747..555f7f068 100644 --- a/test/simple_source/def/01_class.py +++ b/test/simple_source/def/01_class.py @@ -1,11 +1,11 @@ # Tests: # # For Python3: -# classdef ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST CALL_FUNCTION_2 designator +# classdef ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST CALL_FUNCTION_2 store # mkfunc ::= LOAD_CONST LOAD_CONST MAKE_FUNCTION_0 # For Python2: -# classdef ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS designator +# classdef ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS store # mkfunc ::= LOAD_CONST MAKE_FUNCTION_0 class A: diff --git a/test/simple_source/def/02_closure.py b/test/simple_source/def/02_closure.py index 42a430fb3..021eb545a 100644 --- a/test/simple_source/def/02_closure.py +++ b/test/simple_source/def/02_closure.py @@ -1,15 +1,15 @@ # Tests # Python3: -# funcdef ::= mkfunc designator -# designator ::= STORE_DEREF +# function_def ::= mkfunc store +# store ::= STORE_DEREF # mkfunc ::= load_closure BUILD_TUPLE_1 LOAD_CONST LOAD_CONST MAKE_CLOSURE_0 # load_closure ::= LOAD_CLOSURE # # Python2: -# funcdef ::= mkfunc designator -# designator ::= STORE_DEREF -# mkfunc ::= load_closure LOAD_CONST MAKE_CLOSURE_0 +# function_def ::= mkfunc store +# store ::= STORE_DEREF +# mkfunc ::= load_closure LOAD_CONST MAKE_CLOSURE_0 # load_closure ::= LOAD_CLOSURE diff --git a/test/simple_source/def/05_class.py b/test/simple_source/def/05_class.py index 2ed500e17..8baac7a2b 100644 --- a/test/simple_source/def/05_class.py +++ b/test/simple_source/def/05_class.py @@ -1,12 +1,12 @@ # Tests: # importstmt ::= LOAD_CONST LOAD_CONST import_as -# import_as ::= IMPORT_NAME designator +# import_as ::= IMPORT_NAME store # Since Python 3.3: -# classdef ::= buildclass designator -# designator ::= STORE_NAME +# classdef ::= buildclass store +# store ::= STORE_NAME # buildclass ::= LOAD_BUILD_CLASS mkfunc LOAD_CONST expr CALL_FUNCTION_3 -# mkfunc ::= LOAD_CONST LOAD_CONST MAKE_FUNCTION_0 +# mkfunc ::= LOAD_CONST LOAD_CONST MAKE_FUNCTION_0 import io class BZ2File(io.BufferedIOBase): diff --git a/test/simple_source/def/05_closure_bug.py b/test/simple_source/def/05_closure_bug.py index 2a3b3c0c3..afb36b6a9 100644 --- a/test/simple_source/def/05_closure_bug.py +++ b/test/simple_source/def/05_closure_bug.py @@ -12,9 +12,9 @@ # mkfunc ::= load_closure LOAD_CONST MAKE_CLOSURE_0 # mkfuncdeco0 ::= mkfunc -# mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 -# designator ::= STORE_FAST -# funcdefdeco ::= mkfuncdeco designator +# mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 +# store ::= STORE_FAST +# funcdefdeco ::= mkfuncdeco store # stmt ::= funcdefdeco diff --git a/test/simple_source/def/07_closure_bug2.py b/test/simple_source/def/07_closure_bug2.py index 561defbba..33fd646a7 100644 --- a/test/simple_source/def/07_closure_bug2.py +++ b/test/simple_source/def/07_closure_bug2.py @@ -12,9 +12,9 @@ # mkfunc ::= load_closure LOAD_CONST MAKE_CLOSURE_0 # mkfuncdeco0 ::= mkfunc -# mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 -# designator ::= STORE_FAST -# funcdefdeco ::= mkfuncdeco designator +# mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 +# store ::= STORE_FAST +# funcdefdeco ::= mkfuncdeco store # stmt ::= funcdefdeco from functools import wraps diff --git a/test/simple_source/def/10_classdec.py b/test/simple_source/def/10_classdec.py index 812ed203b..76f581627 100644 --- a/test/simple_source/def/10_classdec.py +++ b/test/simple_source/def/10_classdec.py @@ -5,8 +5,8 @@ # mkfuncdeco0 ::= mkfunc # classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS # classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1 -# designator ::= STORE_NAME -# classdefdeco ::= classdefdeco1 designator +# store ::= STORE_NAME +# classdefdeco ::= classdefdeco1 store def author(*author_names): def author_func(cls): diff --git a/test/simple_source/exception/20_try_except.py b/test/simple_source/exception/20_try_except.py index ce5313c12..8c34653c4 100644 --- a/test/simple_source/exception/20_try_except.py +++ b/test/simple_source/exception/20_try_except.py @@ -1,5 +1,5 @@ # Tests: -# forstmt ::= SETUP_LOOP expr _for designator for_block POP_BLOCK COME_FROM +# forstmt ::= SETUP_LOOP expr _for store for_block POP_BLOCK COME_FROM # for_block ::= l_stmts_opt JUMP_BACK # trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle COME_FROM # try_middle ::= jmp_abs COME_FROM except_stmts END_FINALLY diff --git a/test/simple_source/expression/11_multi_genexpr.py b/test/simple_source/expression/11_multi_genexpr.py index 99d5c2964..124be6dfe 100644 --- a/test/simple_source/expression/11_multi_genexpr.py +++ b/test/simple_source/expression/11_multi_genexpr.py @@ -4,16 +4,16 @@ # get_iter ::= expr GET_ITER # expr ::= get_iter # _for ::= GET_ITER FOR_ITER -# designator ::= STORE_FAST +# store ::= STORE_FAST # expr ::= LOAD_FAST # yield ::= expr YIELD_VALUE # expr ::= yield # gen_comp_body ::= expr YIELD_VALUE POP_TOP # comp_body ::= gen_comp_body # comp_iter ::= comp_body -# comp_for ::= expr _for designator comp_iter JUMP_BACK +# comp_for ::= expr _for store comp_iter JUMP_BACK # comp_iter ::= comp_for -# genexpr_func ::= LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK +# genexpr_func ::= LOAD_FAST FOR_ITER store comp_iter JUMP_BACK def multi_genexpr(blog_posts): diff --git a/test/simple_source/looping/10_for.py b/test/simple_source/looping/10_for.py index 10a560890..eb85f549e 100644 --- a/test/simple_source/looping/10_for.py +++ b/test/simple_source/looping/10_for.py @@ -1,5 +1,5 @@ # Tests: -# forstmt ::= SETUP_LOOP expr _for designator +# forstmt ::= SETUP_LOOP expr _for store # for_block POP_BLOCK COME_FROM for a in [1]: c = 2 diff --git a/test/simple_source/stmts/00_assign.py b/test/simple_source/stmts/00_assign.py index a62aed951..bc46d21ae 100644 --- a/test/simple_source/stmts/00_assign.py +++ b/test/simple_source/stmts/00_assign.py @@ -1,5 +1,5 @@ # Tests: -# assign ::= expr designator +# assign ::= expr store a = 'None' b = None diff --git a/test/simple_source/stmts/00_import.py b/test/simple_source/stmts/00_import.py index de00c4423..33cbb1a36 100644 --- a/test/simple_source/stmts/00_import.py +++ b/test/simple_source/stmts/00_import.py @@ -1,6 +1,9 @@ -# Tests: - +# Tests all the different kinds of imports import sys from os import path from os import * import time as time1, os as os1 +import http.client as httpclient +if len(__file__) == 0: + # a.b.c should force consecutive LOAD_ATTRs + import a.b.c as d diff --git a/test/simple_source/stmts/00_pass.py b/test/simple_source/stmts/00_pass.py index 3deb4538a..557b5bcbe 100644 --- a/test/simple_source/stmts/00_pass.py +++ b/test/simple_source/stmts/00_pass.py @@ -1,3 +1,3 @@ # Tests: -# assign ::= expr designator +# assign ::= expr store pass diff --git a/test/simple_source/stmts/01_augmented_assign.py b/test/simple_source/stmts/01_augmented_assign.py index a91f7279b..5d2798169 100644 --- a/test/simple_source/stmts/01_augmented_assign.py +++ b/test/simple_source/stmts/01_augmented_assign.py @@ -26,11 +26,11 @@ l[1][2][3] *= 3; # Python 2.x -# augassign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0 +# aug_assign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0 l[:] += [9]; # print l # Python 2.x -# augassign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2 +# aug_assign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2 l[:2] += [9]; # print l diff --git a/test/simple_source/stmts/02_test_exec.py b/test/simple_source/stmts/02_test_exec.py new file mode 100644 index 000000000..ed4481550 --- /dev/null +++ b/test/simple_source/stmts/02_test_exec.py @@ -0,0 +1,13 @@ +# exec.py -- source test pattern for exec statement +# +# This simple program is part of the decompyle test suite. +# +# decompyle is a Python byte-code decompiler +# See http://www.goebel-consult.de/decompyle/ for download and +# for further information + +testcode = 'a = 12' + +exec testcode +exec testcode in globals() +exec testcode in globals(), locals() diff --git a/test/simple_source/stmts/04_withas.py b/test/simple_source/stmts/04_withas.py index 3ce7bad5d..a35c01913 100644 --- a/test/simple_source/stmts/04_withas.py +++ b/test/simple_source/stmts/04_withas.py @@ -2,7 +2,7 @@ # Bug in 2.6.9 was handling with as. Added rules # -# withasstmt ::= expr setupwithas designator suite_stmts_opt +# withasstmt ::= expr setupwithas store suite_stmts_opt # POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY # setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 STORE_FAST # SETUP_FINALLY LOAD_FAST DELETE_FAST diff --git a/test/simple_source/stmts/10_del.py b/test/simple_source/stmts/10_del.py index 65d1aa3af..43576bcb0 100644 --- a/test/simple_source/stmts/10_del.py +++ b/test/simple_source/stmts/10_del.py @@ -1,6 +1,9 @@ +# Ensures opcodes DELETE_SUBSCR and DELETE_GLOBAL are covered a = (1, 2, 3) +# DELETE_NAME del a +# DELETE_SUBSCR b = [4, 5, 6] del b[1] del b[:] @@ -14,5 +17,14 @@ e = ('a', 'b') def foo(): + # covers DELETE_GLOBAL global e del e + +def a(): + del z + def b(y): + # covers DELETE_FAST + del y + # LOAD_DEREF + return z diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 6e28741f4..4e52714d3 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -31,7 +31,7 @@ '2.7.10', '2.7.11', '2.7.12', '2.7.13', '2.7.14', '3.0.1', '3.1.5', '3.2.6', '3.3.5', '3.3.6', - '3.4.2', '3.5.1', '3.5.2', '3.6.0', '3.6.3', + '3.4.2', '3.5.3', '3.6.0', '3.6.3', 'native') target_base = '/tmp/py-dis/' diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index ee89088a1..cbbd54e49 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -167,8 +167,8 @@ def __ambiguity(self, children): return GenericASTBuilder.ambiguity(self, children) def resolve(self, list): - if len(list) == 2 and 'funcdef' in list and 'assign' in list: - return 'funcdef' + if len(list) == 2 and 'function_def' in list and 'assign' in list: + return 'function_def' if 'grammar' in list and 'expr' in list: return 'expr' # print >> sys.stderr, 'resolve', str(list) @@ -180,8 +180,7 @@ def resolve(self, list): def p_start(self, args): ''' # The start or goal symbol - stmts ::= stmts sstmt - stmts ::= sstmt + stmts ::= sstmt+ ''' def p_call_stmt(self, args): @@ -267,7 +266,6 @@ def p_stmt(self, args): stmt ::= return_stmt return_stmt ::= ret_expr RETURN_VALUE - return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA # return_stmts are a sequence of statements that ends in a RETURN statement. # In later Python versions with jump optimization, this can cause JUMPs @@ -279,15 +277,15 @@ def p_stmt(self, args): """ pass - def p_funcdef(self, args): + def p_function_def(self, args): ''' - stmt ::= funcdef - funcdef ::= mkfunc store - stmt ::= funcdefdeco - funcdefdeco ::= mkfuncdeco store - mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1 - mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 - mkfuncdeco0 ::= mkfunc + stmt ::= function_def + function_def ::= mkfunc store + stmt ::= funcdefdeco + funcdefdeco ::= mkfuncdeco store + mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1 + mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1 + mkfuncdeco0 ::= mkfunc load_closure ::= load_closure LOAD_CLOSURE load_closure ::= LOAD_CLOSURE ''' @@ -317,17 +315,18 @@ def p_jump(self, args): def p_augmented_assign(self, args): ''' - stmt ::= augassign1 - stmt ::= augassign2 + stmt ::= aug_assign1 + stmt ::= aug_assign2 - # This is odd in that other augassign1's have only 3 slots + # This is odd in that other aug_assign1's have only 3 slots # The store isn't used as that's supposed to be also # indicated in the first expr - augassign1 ::= expr expr inplace_op store - - augassign1 ::= expr expr inplace_op ROT_THREE STORE_SUBSCR - augassign2 ::= expr DUP_TOP LOAD_ATTR expr - inplace_op ROT_TWO STORE_ATTR + aug_assign1 ::= expr expr + inplace_op store + aug_assign1 ::= expr expr + inplace_op ROT_THREE STORE_SUBSCR + aug_assign2 ::= expr DUP_TOP LOAD_ATTR expr + inplace_op ROT_TWO STORE_ATTR inplace_op ::= INPLACE_ADD inplace_op ::= INPLACE_SUBTRACT @@ -376,28 +375,31 @@ def p_forstmt(self, args): def p_import20(self, args): """ - stmt ::= importstmt - stmt ::= importfrom - stmt ::= importstar + stmt ::= import + stmt ::= import_from + stmt ::= import_from_star stmt ::= importmultiple - importlist ::= importlist import_as - importlist ::= import_as - import_as ::= IMPORT_NAME store - import_as ::= IMPORT_FROM store + importlist ::= importlist alias + importlist ::= alias + alias ::= IMPORT_NAME store + alias ::= IMPORT_FROM store + alias ::= IMPORT_NAME load_attrs store - importstmt ::= LOAD_CONST LOAD_CONST import_as - importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME IMPORT_STAR - importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist POP_TOP - importmultiple ::= LOAD_CONST LOAD_CONST import_as imports_cont + import ::= LOAD_CONST LOAD_CONST alias + import_from_star ::= LOAD_CONST LOAD_CONST IMPORT_NAME IMPORT_STAR + import_from ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist POP_TOP + importmultiple ::= LOAD_CONST LOAD_CONST alias imports_cont imports_cont ::= import_cont+ - import_cont ::= LOAD_CONST LOAD_CONST import_as + import_cont ::= LOAD_CONST LOAD_CONST alias + + load_attrs ::= LOAD_ATTR+ """ def p_list_comprehension(self, args): """ - expr ::= list_compr + expr ::= list_comp list_iter ::= list_for list_iter ::= list_if @@ -408,7 +410,7 @@ def p_list_comprehension(self, args): list_if_not ::= expr jmp_true list_iter """ - def p_setcomp(self, args): + def p_set_comp(self, args): """ comp_iter ::= comp_for comp_iter ::= comp_body @@ -429,9 +431,9 @@ def p_expr(self, args): expr ::= LOAD_DEREF expr ::= load_attr expr ::= binary_expr - expr ::= build_list + expr ::= list expr ::= compare - expr ::= mapexpr + expr ::= dict expr ::= and expr ::= or expr ::= unary_expr @@ -482,14 +484,10 @@ def p_expr(self, args): ret_expr_or_cond ::= ret_cond stmt ::= return_lambda - stmt ::= conditional_lambda return_lambda ::= ret_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER return_lambda ::= ret_expr RETURN_VALUE_LAMBDA - # Doesn't seem to be used anymore, but other conditional_lambda's are - # conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER - compare ::= compare_chained compare ::= compare_single compare_single ::= expr expr COMPARE_OP @@ -501,9 +499,6 @@ def p_expr(self, args): # Non-null kvlist items are broken out in the indiviual grammars kvlist ::= - exprlist ::= exprlist expr - exprlist ::= expr - # Positional arguments in make_function pos_arg ::= expr diff --git a/uncompyle6/parsers/parse15.py b/uncompyle6/parsers/parse15.py index b1f51c5a5..7a7183b64 100644 --- a/uncompyle6/parsers/parse15.py +++ b/uncompyle6/parsers/parse15.py @@ -13,14 +13,14 @@ def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG): def p_import15(self, args): """ - importstmt ::= filler IMPORT_NAME STORE_FAST - importstmt ::= filler IMPORT_NAME STORE_NAME + import ::= filler IMPORT_NAME STORE_FAST + import ::= filler IMPORT_NAME STORE_NAME - importfrom ::= filler IMPORT_NAME importlist - importfrom ::= filler filler IMPORT_NAME importlist POP_TOP + import_from ::= filler IMPORT_NAME importlist + import_from ::= filler filler IMPORT_NAME importlist POP_TOP - importlist ::= importlist IMPORT_FROM - importlist ::= IMPORT_FROM + importlist ::= importlist IMPORT_FROM + importlist ::= IMPORT_FROM """ class Python15ParserSingle(Python21Parser, PythonParserSingle): diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 5e3418281..e38b8cf92 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -36,13 +36,6 @@ def p_print2(self, args): print_nl ::= PRINT_NEWLINE """ - def p_stmt2(self, args): - """ - exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT - exec_stmt ::= expr exprlist EXEC_STMT - - """ - def p_print_to(self, args): ''' stmt ::= print_to @@ -65,6 +58,8 @@ def p_grammar(self, args): return_if_stmts ::= _stmts return_if_stmt return_if_stmt ::= ret_expr RETURN_END_IF + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + stmt ::= break_stmt break_stmt ::= BREAK_LOOP @@ -100,7 +95,7 @@ def p_grammar(self, args): kvlist ::= kvlist kv3 kv3 ::= expr expr STORE_MAP - mapexpr ::= BUILD_MAP kvlist + dict ::= BUILD_MAP kvlist classdef ::= buildclass store @@ -198,10 +193,10 @@ def p_slice2(self, args): store ::= expr expr STORE_SLICE+2 store ::= expr expr expr STORE_SLICE+3 - augassign1 ::= expr expr inplace_op ROT_FOUR STORE_SLICE+3 - augassign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+1 - augassign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2 - augassign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0 + aug_assign1 ::= expr expr inplace_op ROT_FOUR STORE_SLICE+3 + aug_assign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+1 + aug_assign1 ::= expr expr inplace_op ROT_THREE STORE_SLICE+2 + aug_assign1 ::= expr expr inplace_op ROT_TWO STORE_SLICE+0 slice0 ::= expr SLICE+0 slice0 ::= expr DUP_TOP SLICE+0 @@ -224,8 +219,8 @@ def add_custom_rules(self, tokens, customize): Special handling for opcodes such as those that take a variable number of arguments -- we add a new rule for each: - build_list ::= {expr}^n BUILD_LIST_n - build_list ::= {expr}^n BUILD_TUPLE_n + list ::= {expr}^n BUILD_LIST_n + list ::= {expr}^n BUILD_TUPLE_n unpack_list ::= UNPACK_LIST {expr}^n unpack ::= UNPACK_TUPLE {expr}^n unpack ::= UNPACK_SEQEUENCE {expr}^n @@ -251,8 +246,8 @@ def add_custom_rules(self, tokens, customize): stmt ::= assign2_pypy assign3_pypy ::= expr expr expr store store store assign2_pypy ::= expr expr store store - list_compr ::= expr BUILD_LIST_FROM_ARG _for store list_iter - JUMP_BACK + list_comp ::= expr BUILD_LIST_FROM_ARG _for store list_iter + JUMP_BACK """, nop_func) for i, token in enumerate(tokens): opname = token.kind @@ -275,7 +270,7 @@ def add_custom_rules(self, tokens, customize): self.add_unique_rule("expr1024 ::=%s" % (' expr32' * 32), opname_base, v, customize) self.seen1024 = True - rule = ('build_list ::= ' + 'expr1024 '*thousands + + rule = ('list ::= ' + 'expr1024 '*thousands + 'expr32 '*thirty32s + 'expr '*(v % 32) + opname) elif opname_base == 'BUILD_MAP': if opname == 'BUILD_MAP_n': @@ -283,7 +278,7 @@ def add_custom_rules(self, tokens, customize): self.add_unique_rules([ 'kvlist_n ::= kvlist_n kv3', 'kvlist_n ::=', - 'mapexpr ::= BUILD_MAP_n kvlist_n', + 'dict ::= BUILD_MAP_n kvlist_n', ], customize) if self.version >= 2.7: self.add_unique_rule( @@ -295,7 +290,7 @@ def add_custom_rules(self, tokens, customize): kvlist_n = "kvlist_%s" % v self.add_unique_rules([ (kvlist_n + " ::=" + ' kv3' * v), - "mapexpr ::= %s %s" % (opname, kvlist_n) + "dict ::= %s %s" % (opname, kvlist_n) ], customize) continue elif opname_base == 'BUILD_SLICE': @@ -337,6 +332,13 @@ def add_custom_rules(self, tokens, customize): # FIXME: remove these conditions if they are not needed. # no longer need to add a rule continue + elif opname == 'EXEC_STMT': + self.addRule(""" + exprlist ::= expr+ + exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT + exec_stmt ::= expr exprlist EXEC_STMT + """, nop_func) + continue elif opname == 'JUMP_IF_NOT_DEBUG': self.add_unique_rules([ 'jmp_true_false ::= POP_JUMP_IF_TRUE', @@ -349,10 +351,15 @@ def add_custom_rules(self, tokens, customize): "LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 COME_FROM", ], customize) continue + elif opname == 'LOAD_LISTCOMP': + self.add_unique_rules([ + "expr ::= listcomp", + ], customize) + continue elif opname == 'LOAD_SETCOMP': self.add_unique_rules([ - "expr ::= setcomp", - "setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1" + "expr ::= set_comp", + "set_comp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1" ], customize) continue elif opname == 'LOOKUP_METHOD': @@ -387,13 +394,13 @@ def add_custom_rules(self, tokens, customize): prev_tok = tokens[i-1] if prev_tok == 'LOAD_DICTCOMP': self.add_unique_rules([ - ('dictcomp ::= %s load_closure LOAD_DICTCOMP %s expr' + ('dict_comp ::= %s load_closure LOAD_DICTCOMP %s expr' ' GET_ITER CALL_FUNCTION_1' % ('expr '*v, opname))], customize) elif prev_tok == 'LOAD_SETCOMP': self.add_unique_rules([ - "expr ::= setcomp", - ('setcomp ::= %s load_closure LOAD_SETCOMP %s expr' + "expr ::= set_comp", + ('set_comp ::= %s load_closure LOAD_SETCOMP %s expr' ' GET_ITER CALL_FUNCTION_1' % ('expr '*v, opname)) ], customize) @@ -428,8 +435,8 @@ def add_custom_rules(self, tokens, customize): raise Exception('unknown customize token %s' % opname) self.add_unique_rule(rule, opname_base, v, customize) pass - self.check_reduce['augassign1'] = 'AST' - self.check_reduce['augassign2'] = 'AST' + self.check_reduce['aug_assign1'] = 'AST' + self.check_reduce['aug_assign2'] = 'AST' self.check_reduce['_stmts'] = 'AST' # Dead code testing... @@ -445,7 +452,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # if lhs == 'while1elsestmt': # from trepan.api import debug; debug() - if lhs in ('augassign1', 'augassign2') and ast[0] and ast[0][0] == 'and': + if lhs in ('aug_assign1', 'aug_assign2') and ast[0] and ast[0][0] == 'and': return True elif lhs == '_stmts': for i, stmt in enumerate(ast): diff --git a/uncompyle6/parsers/parse21.py b/uncompyle6/parsers/parse21.py index 31a13e68e..c2cb8675d 100644 --- a/uncompyle6/parsers/parse21.py +++ b/uncompyle6/parsers/parse21.py @@ -27,7 +27,7 @@ def p_forstmt21(self, args): def p_import21(self, args): ''' - import_as ::= IMPORT_NAME_CONT store + alias ::= IMPORT_NAME_CONT store ''' class Python21ParserSingle(Python22Parser, PythonParserSingle): diff --git a/uncompyle6/parsers/parse23.py b/uncompyle6/parsers/parse23.py index d5a1d0137..56178e920 100644 --- a/uncompyle6/parsers/parse23.py +++ b/uncompyle6/parsers/parse23.py @@ -35,7 +35,7 @@ def p_misc23(self, args): while1stmt ::= _while1test l_stmts_opt JUMP_BACK COME_FROM POP_TOP POP_BLOCK COME_FROM - list_compr ::= BUILD_LIST_0 DUP_TOP LOAD_ATTR store list_iter del_stmt + list_comp ::= BUILD_LIST_0 DUP_TOP LOAD_ATTR store list_iter del_stmt list_for ::= expr _for store list_iter JUMP_BACK come_froms POP_TOP JUMP_BACK lc_body ::= LOAD_NAME expr CALL_FUNCTION_1 POP_TOP @@ -48,7 +48,7 @@ def p_misc23(self, args): expr ::= and2 and2 ::= _jump jmp_false COME_FROM expr COME_FROM - import_as ::= IMPORT_NAME load_attrs store + alias ::= IMPORT_NAME load_attrs store load_attrs ::= LOAD_ATTR+ conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 2d4140bb7..394053010 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -26,12 +26,12 @@ def p_misc24(self, args): # 2.5+ has two LOAD_CONSTs, one for the number '.'s in a relative import # keep positions similar to simplify semantic actions - importstmt ::= filler LOAD_CONST import_as - importfrom ::= filler LOAD_CONST IMPORT_NAME importlist POP_TOP - importstar ::= filler LOAD_CONST IMPORT_NAME IMPORT_STAR + import ::= filler LOAD_CONST alias + import_from ::= filler LOAD_CONST IMPORT_NAME importlist POP_TOP + import_from_star ::= filler LOAD_CONST IMPORT_NAME IMPORT_STAR - importmultiple ::= filler LOAD_CONST import_as imports_cont - import_cont ::= filler LOAD_CONST import_as + importmultiple ::= filler LOAD_CONST alias imports_cont + import_cont ::= filler LOAD_CONST alias # Python 2.5+ omits POP_TOP POP_BLOCK while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_TOP POP_BLOCK COME_FROM diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 49c740547..27525306e 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -71,9 +71,12 @@ def add_custom_rules(self, tokens, customize): return_if_stmts ::= return_if_stmt return_stmt ::= ret_expr RETURN_END_IF POP_TOP return_stmt ::= ret_expr RETURN_VALUE POP_TOP + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally stmt ::= classdefdeco stmt ::= conditional_lambda + conditional_lambda ::= expr jmp_false_then expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER """) super(Python25Parser, self).add_custom_rules(tokens, customize) if self.version == 2.5: diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index a259c1846..ec98e4341 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -195,9 +195,9 @@ def p_comp26(self, args): list_iter ::= list_if JUMP_BACK list_iter ::= list_if JUMP_BACK COME_FROM POP_TOP - list_compr ::= BUILD_LIST_0 DUP_TOP + list_comp ::= BUILD_LIST_0 DUP_TOP store list_iter del_stmt - list_compr ::= BUILD_LIST_0 DUP_TOP + list_comp ::= BUILD_LIST_0 DUP_TOP store list_iter JUMP_BACK del_stmt lc_body ::= LOAD_NAME expr LIST_APPEND lc_body ::= LOAD_FAST expr LIST_APPEND @@ -248,6 +248,7 @@ def p_misc26(self, args): compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP jmp_false compare_chained2 _come_from return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP + stmt ::= conditional_lambda conditional_lambda ::= expr jmp_false_then expr return_if_lambda return_stmt_lambda LAMBDA_MARKER """ diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 7ffcf194f..fbe0471bc 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -14,19 +14,19 @@ def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG): def p_comprehension27(self, args): """ - list_for ::= expr _for store list_iter JUMP_BACK - list_compr ::= BUILD_LIST_0 list_iter - lc_body ::= expr LIST_APPEND + list_for ::= expr _for store list_iter JUMP_BACK + list_comp ::= BUILD_LIST_0 list_iter + lc_body ::= expr LIST_APPEND stmt ::= setcomp_func # Dictionary and set comprehensions were added in Python 2.7 - expr ::= dictcomp - stmt ::= dictcomp_func - dictcomp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER store - comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST + expr ::= dict_comp + dict_comp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 - dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 + stmt ::= dictcomp_func + dictcomp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER store + comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER store comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST @@ -126,6 +126,7 @@ def p_stmt27(self, args): # Common with 2.6 return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM + stmt ::= conditional_lambda conditional_lambda ::= expr jmp_false expr return_if_lambda return_stmt_lambda LAMBDA_MARKER diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a929eddd3..331099325 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -32,9 +32,6 @@ def p_comprehension3(self, args): # Python3 scanner adds LOAD_LISTCOMP. Python3 does list comprehension like # other comprehensions (set, dictionary). - # listcomp is a custom Python3 rule - expr ::= listcomp - # Our "continue" heuristic - in two successive JUMP_BACKS, the first # one may be a continue - sometimes classifies a JUMP_BACK # as a CONTINUE. The two are kind of the same in a comprehension. @@ -69,11 +66,12 @@ def p_comprehension3(self, args): def p_dictcomp3(self, args): """" - expr ::= dictcomp + expr ::= dict_comp stmt ::= dictcomp_func dictcomp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER store comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST - dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 + dict_comp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr + GET_ITER CALL_FUNCTION_1 """ def p_grammar(self, args): @@ -140,7 +138,6 @@ def p_grammar(self, args): testtrue ::= expr jmp_true _ifstmts_jump ::= return_if_stmts - _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM _ifstmts_jump ::= c_stmts_opt COME_FROM iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE @@ -185,7 +182,7 @@ def p_grammar(self, args): # this is nested inside a trystmt tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK LOAD_CONST - come_from_or_finally suite_stmts_opt END_FINALLY + COME_FROM_FINALLY suite_stmts_opt END_FINALLY tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle else_suite come_from_except_clauses @@ -233,7 +230,7 @@ def p_grammar(self, args): except_suite_finalize ::= SETUP_FINALLY c_stmts_opt except_var_finalize END_FINALLY _jump - except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST come_from_or_finally + except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM_FINALLY LOAD_CONST store del_stmt except_suite ::= return_stmts @@ -275,19 +272,16 @@ def p_misc3(self, args): try_middle ::= JUMP_FORWARD COME_FROM_EXCEPT except_stmts END_FINALLY COME_FROM_EXCEPT_CLAUSE - for_block ::= l_stmts_opt opt_come_from_loop JUMP_BACK + for_block ::= l_stmts_opt come_from_loops JUMP_BACK for_block ::= l_stmts iflaststmtl ::= testexpr c_stmts_opt - - expr ::= conditionalTrue - conditionalTrue ::= expr JUMP_FORWARD expr COME_FROM """ def p_def_annotations3(self, args): """ # Annotated functions - stmt ::= funcdef_annotate - funcdef_annotate ::= mkfunc_annotate store + stmt ::= function_def_annotate + function_def_annotate ::= mkfunc_annotate store mkfuncdeco0 ::= mkfunc_annotate @@ -309,17 +303,9 @@ def p_come_from3(self, args): opt_come_from_except ::= come_froms opt_come_from_except ::= come_from_except_clauses - come_froms ::= COME_FROM* - + come_froms ::= COME_FROM* come_from_except_clauses ::= COME_FROM_EXCEPT_CLAUSE+ - - opt_come_from_loop ::= opt_come_from_loop COME_FROM_LOOP - opt_come_from_loop ::= opt_come_from_loop COME_FROM_LOOP - opt_come_from_loop ::= - - come_from_or_finally ::= COME_FROM_FINALLY - come_from_or_finally ::= COME_FROM - + come_from_loops ::= COME_FROM_LOOP* """ def p_jump3(self, args): @@ -354,7 +340,7 @@ def p_stmt3(self, args): def p_loop_stmt3(self, args): """ forstmt ::= SETUP_LOOP expr _for store for_block POP_BLOCK - opt_come_from_loop + come_from_loops forelsestmt ::= SETUP_LOOP expr _for store for_block POP_BLOCK else_suite COME_FROM_LOOP @@ -371,11 +357,6 @@ def p_loop_stmt3(self, args): whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM_LOOP - # The JUMP_ABSOLUTE below comes from escaping an "if" block which surrounds - # the while. This is messy - whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK - JUMP_ABSOLUTE COME_FROM_LOOP - whilestmt ::= SETUP_LOOP testexpr return_stmts POP_BLOCK COME_FROM_LOOP @@ -412,7 +393,7 @@ def p_generator_exp3(self, args): load_genexpr ::= BUILD_TUPLE_1 LOAD_GENEXPR LOAD_CONST # Is there something general going on here? - dictcomp ::= load_closure LOAD_DICTCOMP LOAD_CONST MAKE_CLOSURE_0 expr GET_ITER CALL_FUNCTION_1 + dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST MAKE_CLOSURE_0 expr GET_ITER CALL_FUNCTION_1 ''' def p_expr3(self, args): @@ -423,12 +404,6 @@ def p_expr3(self, args): # a JUMP_FORWARD to another JUMP_FORWARD can get turned into # a JUMP_ABSOLUTE with no COME_FROM conditional ::= expr jmp_false expr jump_absolute_else expr - - return_if_lambda ::= RETURN_END_IF_LAMBDA - conditional_lambda ::= expr jmp_false return_stmt_lambda - return_stmt_lambda LAMBDA_MARKER - conditional_lambda ::= expr jmp_false expr return_if_lambda - return_stmt_lambda LAMBDA_MARKER """ @staticmethod @@ -572,14 +547,14 @@ def add_custom_rules(self, tokens, customize): # Even the below say _list, in the semantic rules we # disambiguate tuples, and sets from lists - build_list ::= {expr}^n BUILD_LIST_n - build_list ::= {expr}^n BUILD_TUPLE_n - build_list ::= {expr}^n BUILD_LIST_UNPACK_n - build_list ::= {expr}^n BUILD_TUPLE_UNPACK_n + list ::= {expr}^n BUILD_LIST_n + list ::= {expr}^n BUILD_TUPLE_n + list ::= {expr}^n BUILD_LIST_UNPACK_n + list ::= {expr}^n BUILD_TUPLE_UNPACK_n # FIXME: - build_list ::= {expr}^n BUILD_SET_n - build_list ::= {expr}^n BUILD_SET_UNPACK_n + list ::= {expr}^n BUILD_SET_n + list ::= {expr}^n BUILD_SET_UNPACK_n should be build_set ::= {expr}^n BUILD_SET_n build_set ::= {expr}^n BUILD_SET_UNPACK_n @@ -594,8 +569,8 @@ def add_custom_rules(self, tokens, customize): # Is there something more general than this? adding pos_arg? # Is there something corresponding using MAKE_CLOSURE? - dictcomp ::= LOAD_DICTCOMP [LOAD_CONST] MAKE_FUNCTION_0 expr - GET_ITER CALL_FUNCTION_1 + dict_comp ::= LOAD_DICTCOMP [LOAD_CONST] MAKE_FUNCTION_0 expr + GET_ITER CALL_FUNCTION_1 generator_exp ::= {pos_arg}^n load_genexpr [LOAD_CONST] MAKE_FUNCTION_n expr GET_ITER CALL_FUNCTION_1 @@ -609,12 +584,12 @@ def add_custom_rules(self, tokens, customize): # Is there something more general than this? adding pos_arg? # Is there something corresponding using MAKE_CLOSURE? For example: - # setcomp ::= {pos_arg}^n LOAD_SETCOMP [LOAD_CONST] MAKE_CLOSURE_n + # set_comp ::= {pos_arg}^n LOAD_SETCOMP [LOAD_CONST] MAKE_CLOSURE_n GET_ITER CALL_FUNCTION_1 - setcomp ::= LOAD_SETCOMP [LOAD_CONST] MAKE_FUNCTION_0 expr + set_comp ::= LOAD_SETCOMP [LOAD_CONST] MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 - setcomp ::= {pos_arg}^n load_closure LOAD_SETCOMP [LOAD_CONST] + set_comp ::= {pos_arg}^n load_closure LOAD_SETCOMP [LOAD_CONST] MAKE_CLOSURE_n expr GET_ITER CALL_FUNCTION_1 mkfunc ::= {pos_arg}^n load_closure [LOAD_CONST] MAKE_FUNCTION_n @@ -626,22 +601,25 @@ def add_custom_rules(self, tokens, customize): load_attr ::= expr LOOKUP_METHOD call ::= expr CALL_METHOD """ + is_pypy = False seen_LOAD_BUILD_CLASS = False - seen_LOAD_DICTCOMP = False - seen_LOAD_LISTCOMP = False - seen_LOAD_SETCOMP = False - seen_classdeco_end = False seen_GET_AWAITABLE_YIELD_FROM = False # Loop over instructions adding custom grammar rules based on # a specific instruction seen. if 'PyPy' in customize: + is_pypy = True self.addRule(""" stmt ::= assign3_pypy stmt ::= assign2_pypy assign3_pypy ::= expr expr expr store store store assign2_pypy ::= expr expr store store + return_if_lambda ::= RETURN_END_IF_LAMBDA + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + stmt ::= conditional_lambda + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER """, nop_func) has_get_iter_call_function1 = False @@ -666,7 +644,7 @@ def add_custom_rules(self, tokens, customize): if opname_base == 'BUILD_CONST_KEY_MAP': # This is in 3.6+ kvlist_n = 'expr ' * (token.attr) - rule = "mapexpr ::= %sLOAD_CONST %s" % (kvlist_n, opname) + rule = "dict ::= %sLOAD_CONST %s" % (kvlist_n, opname) self.add_unique_rule(rule, opname, token.attr, customize) elif opname.startswith('BUILD_LIST_UNPACK'): v = token.attr @@ -689,27 +667,27 @@ def add_custom_rules(self, tokens, customize): self.add_unique_rule(rule, 'kvlist_n', 0, customize) rule = 'kvlist_n ::=' self.add_unique_rule(rule, 'kvlist_n', 1, customize) - rule = "mapexpr ::= BUILD_MAP_n kvlist_n" + rule = "dict ::= BUILD_MAP_n kvlist_n" elif self.version >= 3.5: if opname != 'BUILD_MAP_WITH_CALL': if opname == 'BUILD_MAP_UNPACK': rule = kvlist_n + ' ::= ' + 'expr ' * (token.attr*2) self.add_unique_rule(rule, opname, token.attr, customize) - rule = 'dict ::= ' + 'expr ' * (token.attr*2) + rule = 'dict_entry ::= ' + 'expr ' * (token.attr*2) self.add_unique_rule(rule, opname, token.attr, customize) - rule = 'mapexpr ::= ' + 'dict ' * token.attr + rule = 'dict ::= ' + 'dict_entry ' * token.attr self.add_unique_rule(rule, opname, token.attr, customize) rule = ('unmap_dict ::= ' + - ('mapexpr ' * token.attr) + + ('dict ' * token.attr) + 'BUILD_MAP_UNPACK') else: rule = kvlist_n + ' ::= ' + 'expr ' * (token.attr*2) self.add_unique_rule(rule, opname, token.attr, customize) - rule = "mapexpr ::= %s %s" % (kvlist_n, opname) + rule = "dict ::= %s %s" % (kvlist_n, opname) else: rule = kvlist_n + ' ::= ' + 'expr expr STORE_MAP ' * token.attr self.add_unique_rule(rule, opname, token.attr, customize) - rule = "mapexpr ::= %s %s" % (opname, kvlist_n) + rule = "dict ::= %s %s" % (opname, kvlist_n) self.add_unique_rule(rule, opname, token.attr, customize) elif opname.startswith('BUILD_MAP_UNPACK_WITH_CALL'): v = token.attr @@ -723,7 +701,7 @@ def add_custom_rules(self, tokens, customize): is_LOAD_CLOSURE = False if opname_base == 'BUILD_TUPLE': # If is part of a "load_closure", then it is not part of a - # "build_list". + # "list". is_LOAD_CLOSURE = True for j in range(v): if tokens[i-j-1].kind != 'LOAD_CLOSURE': @@ -733,9 +711,9 @@ def add_custom_rules(self, tokens, customize): rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname)) self.add_unique_rule(rule, opname, token.attr, customize) if not is_LOAD_CLOSURE or v == 0: - rule = ('build_list ::= ' + 'expr1024 ' * int(v//1024) + - 'expr32 ' * int((v//32) % 32) + - 'expr ' * (v % 32) + opname) + rule = ('list ::= ' + 'expr1024 ' * int(v//1024) + + 'expr32 ' * int((v//32) % 32) + + 'expr ' * (v % 32) + opname) self.add_unique_rule(rule, opname, token.attr, customize) continue elif opname_base == 'BUILD_SLICE': @@ -804,21 +782,19 @@ def add_custom_rules(self, tokens, customize): opname, token.attr, customize) continue elif opname == 'LOAD_DICTCOMP': - seen_LOAD_DICTCOMP = True if has_get_iter_call_function1: - rule_pat = ("dictcomp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr " + rule_pat = ("dict_comp ::= LOAD_DICTCOMP %sMAKE_FUNCTION_0 expr " "GET_ITER CALL_FUNCTION_1") self.add_make_function_rule(rule_pat, opname, token.attr, customize) + # listcomp is a custom Python3 rule elif opname == 'LOAD_LISTCOMP': - seen_LOAD_LISTCOMP = True - continue + self.add_unique_rule("expr ::= listcomp", opname, token.attr, customize) elif opname == 'LOAD_SETCOMP': - seen_LOAD_SETCOMP = True # Should this be generalized and put under MAKE_FUNCTION? if has_get_iter_call_function1: - self.add_unique_rule("expr ::= setcomp", + self.add_unique_rule("expr ::= set_comp", opname, token.attr, customize) - rule_pat = ("setcomp ::= LOAD_SETCOMP %sMAKE_FUNCTION_0 expr " + rule_pat = ("set_comp ::= LOAD_SETCOMP %sMAKE_FUNCTION_0 expr " "GET_ITER CALL_FUNCTION_1") self.add_make_function_rule(rule_pat, opname, token.attr, customize) elif opname == 'LOOKUP_METHOD': @@ -831,28 +807,37 @@ def add_custom_rules(self, tokens, customize): # Note: this probably doesn't handle kwargs proprerly args_pos, args_kw, annotate_args = token.attr - rule_pat = ('mklambda ::= %sload_closure LOAD_LAMBDA %%s%s' % - ('pos_arg '* args_pos, opname)) - self.add_make_function_rule(rule_pat, opname, token.attr, customize) + # FIXME: Fold test into add_make_function_rule + j = 1 if self.version < 3.3 else 2 + if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LAMBDA'): + rule_pat = ('mklambda ::= %sload_closure LOAD_LAMBDA %%s%s' % + ('pos_arg '* args_pos, opname)) + self.add_make_function_rule(rule_pat, opname, token.attr, customize) if has_get_iter_call_function1: rule_pat = ("generator_exp ::= %sload_closure load_genexpr %%s%s expr " "GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname)) self.add_make_function_rule(rule_pat, opname, token.attr, customize) - if seen_LOAD_LISTCOMP: - rule_pat = ('listcomp ::= %sload_closure LOAD_LISTCOMP %%s%s expr ' - 'GET_ITER CALL_FUNCTION_1' % ('pos_arg ' * args_pos, opname)) - self.add_make_function_rule(rule_pat, opname, token.attr, customize) - if seen_LOAD_SETCOMP: - rule_pat = ('setcomp ::= %sload_closure LOAD_SETCOMP %%s%s expr ' - 'GET_ITER CALL_FUNCTION_1' % ('pos_arg ' * args_pos, opname)) - self.add_make_function_rule(rule_pat, opname, token.attr, customize) - if seen_LOAD_DICTCOMP: - self.add_unique_rule('dictcomp ::= %sload_closure LOAD_DICTCOMP %s ' - 'expr GET_ITER CALL_FUNCTION_1' % - ('pos_arg '* args_pos, opname), - opname, token.attr, customize) + if has_get_iter_call_function1: + if (is_pypy or (i >= j and tokens[i-j] == 'LOAD_LISTCOMP')): + # In the tokens we saw: + # LOAD_LISTCOMP LOAD_CONST MAKE_FUNCTION (>= 3.3) or + # LOAD_LISTCOMP MAKE_FUNCTION (< 3.3) or + # and have GET_ITER CALL_FUNCTION_1 + # Todo: For Pypy we need to modify this slightly + rule_pat = ('listcomp ::= %sload_closure LOAD_LISTCOMP %%s%s expr ' + 'GET_ITER CALL_FUNCTION_1' % ('pos_arg ' * args_pos, opname)) + self.add_make_function_rule(rule_pat, opname, token.attr, customize) + if (is_pypy or (i >= j and tokens[i-j] == 'LOAD_SETCOMP')): + rule_pat = ('set_comp ::= %sload_closure LOAD_SETCOMP %%s%s expr ' + 'GET_ITER CALL_FUNCTION_1' % ('pos_arg ' * args_pos, opname)) + self.add_make_function_rule(rule_pat, opname, token.attr, customize) + if (is_pypy or (i >= j and tokens[i-j] == 'LOAD_DICTCOMP')): + self.add_unique_rule('dict_comp ::= %sload_closure LOAD_DICTCOMP %s ' + 'expr GET_ITER CALL_FUNCTION_1' % + ('pos_arg '* args_pos, opname), + opname, token.attr, customize) # FIXME: kwarg processing is missing here. # Note order of kwargs and pos args changed between 3.3-3.4 if self.version <= 3.2: @@ -894,15 +879,16 @@ def add_custom_rules(self, tokens, customize): rule_pat = ("generator_exp ::= %sload_closure load_genexpr %%s%s expr " "GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname)) self.add_make_function_rule(rule_pat, opname, token.attr, customize) - - rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' % - (('pos_arg '* args_pos), - ('kwarg '* args_kw), - opname)) - self.add_make_function_rule(rule_pat, opname, token.attr, customize) - if seen_LOAD_LISTCOMP and has_get_iter_call_function1: - rule_pat = ("listcomp ::= %sLOAD_LISTCOMP %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ('expr ' * args_pos, opname)) + if is_pypy or (i >= 2 and tokens[i-2] == 'LOAD_LISTCOMP'): + rule_pat = ("listcomp ::= %sLOAD_LISTCOMP %%s%s expr " + "GET_ITER CALL_FUNCTION_1" % ('expr ' * args_pos, opname)) + self.add_make_function_rule(rule_pat, opname, token.attr, customize) + + if is_pypy or (i >= 2 and tokens[i-2] == 'LOAD_LAMBDA'): + rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' % + (('pos_arg '* args_pos), + ('kwarg '* args_kw), + opname)) self.add_make_function_rule(rule_pat, opname, token.attr, customize) continue if self.version < 3.6: @@ -910,19 +896,28 @@ def add_custom_rules(self, tokens, customize): else: args_pos, args_kw, annotate_args, closure = token.attr + j = 1 if self.version < 3.3 else 2 if has_get_iter_call_function1: rule_pat = ("generator_exp ::= %sload_genexpr %%s%s expr " "GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname)) self.add_make_function_rule(rule_pat, opname, token.attr, customize) - rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' % - (('pos_arg '* args_pos), - ('kwarg '* args_kw), - opname)) - self.add_make_function_rule(rule_pat, opname, token.attr, customize) - - if seen_LOAD_LISTCOMP and has_get_iter_call_function1: - rule_pat = ("listcomp ::= %sLOAD_LISTCOMP %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ('expr ' * args_pos, opname)) + + if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LISTCOMP'): + # In the tokens we saw: + # LOAD_LISTCOMP LOAD_CONST MAKE_FUNCTION (>= 3.3) or + # LOAD_LISTCOMP MAKE_FUNCTION (< 3.3) or + # and have GET_ITER CALL_FUNCTION_1 + # Todo: For Pypy we need to modify this slightly + rule_pat = ("listcomp ::= %sLOAD_LISTCOMP %%s%s expr " + "GET_ITER CALL_FUNCTION_1" % ('expr ' * args_pos, opname)) + self.add_make_function_rule(rule_pat, opname, token.attr, customize) + + # FIXME: Fold test into add_make_function_rule + if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LAMBDA'): + rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' % + (('pos_arg '* args_pos), + ('kwarg '* args_kw), + opname)) self.add_make_function_rule(rule_pat, opname, token.attr, customize) if self.version == 3.3: @@ -978,8 +973,8 @@ def add_custom_rules(self, tokens, customize): self.add_unique_rule(rule, opname, token.attr, customize) elif opname_base == 'UNPACK_LIST': rule = 'unpack_list ::= ' + opname + ' store' * token.attr - self.check_reduce['augassign1'] = 'AST' - self.check_reduce['augassign2'] = 'AST' + self.check_reduce['aug_assign1'] = 'AST' + self.check_reduce['aug_assign2'] = 'AST' self.check_reduce['while1stmt'] = 'noAST' self.check_reduce['annotate_tuple'] = 'noAST' self.check_reduce['kwarg'] = 'noAST' @@ -989,7 +984,7 @@ def add_custom_rules(self, tokens, customize): def reduce_is_invalid(self, rule, ast, tokens, first, last): lhs = rule[0] - if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and': + if lhs in ('aug_assign1', 'aug_assign2') and ast[0][0] == 'and': return True elif lhs == 'annotate_tuple': return not isinstance(tokens[first].attr, tuple) diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index 3f8653b3d..eb8e0f792 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -22,7 +22,6 @@ def p_32to35(self, args): # Python < 3.5 no POP BLOCK whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK COME_FROM_LOOP - whileTruestmt ::= SETUP_LOOP return_stmts COME_FROM_LOOP # Python 3.5+ has jump optimization to remove the redundant # jump_excepts. But in 3.3 we need them added @@ -49,11 +48,9 @@ def p_32to35(self, args): stmt ::= del_deref_stmt del_deref_stmt ::= DELETE_DEREF - list_compr ::= BUILD_LIST_0 list_iter - lc_body ::= expr LIST_APPEND - - kvlist ::= kvlist kv3 - kv3 ::= expr expr STORE_MAP + list_comp ::= BUILD_LIST_0 list_iter + lc_body ::= expr LIST_APPEND + kv3 ::= expr expr STORE_MAP """ pass @@ -65,9 +62,15 @@ def p_32on(self, args): pass def add_custom_rules(self, tokens, customize): - # self.remove_rules(""" - # compare_chained2 ::= expr COMPARE_OP RETURN_VALUE - # """) + self.remove_rules(""" + try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY COME_FROM + try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY COME_FROM_EXCEPT + try_middle ::= JUMP_FORWARD COME_FROM_EXCEPT except_stmts END_FINALLY COME_FROM_EXCEPT_CLAUSE + try_middle ::= jmp_abs COME_FROM except_stmts END_FINALLY + tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle else_suite come_from_except_clauses + whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK NOP COME_FROM_LOOP + whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP COME_FROM_LOOP + """) super(Python32Parser, self).add_custom_rules(tokens, customize) for i, token in enumerate(tokens): opname = token.kind diff --git a/uncompyle6/parsers/parse33.py b/uncompyle6/parsers/parse33.py index 89ba40e12..432eee2dd 100644 --- a/uncompyle6/parsers/parse33.py +++ b/uncompyle6/parsers/parse33.py @@ -17,26 +17,19 @@ def p_33on(self, args): # We do the grammar hackery below for semantics # actions that want c_stmts_opt at index 1 - whileTruestmt ::= SETUP_LOOP l_stmts JUMP_ABSOLUTE - JUMP_BACK COME_FROM_LOOP - # Python 3.5+ has jump optimization to remove the redundant # jump_excepts. But in 3.3 we need them added trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle jump_excepts come_from_except_clauses - mapexpr ::= BUILD_MAP kvlist """ def add_custom_rules(self, tokens, customize): self.remove_rules(""" # 3.3+ adds POP_BLOCKS - whileTruestmt ::= SETUP_LOOP l_stmts JUMP_ABSOLUTE JUMP_BACK COME_FROM_LOOP whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK NOP COME_FROM_LOOP whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP COME_FROM_LOOP - whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK - POP_BLOCK JUMP_ABSOLUTE COME_FROM_LOOP """) super(Python33Parser, self).add_custom_rules(tokens, customize) return diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index da01b862f..c528e8a3b 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -3,7 +3,7 @@ spark grammar differences over Python 3.4 for Python 3.5. """ -from uncompyle6.parser import PythonParserSingle +from uncompyle6.parser import PythonParserSingle, nop_func from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse34 import Python34Parser @@ -32,22 +32,8 @@ def p_35on(self, args): stmt ::= await_stmt await_stmt ::= await_expr POP_TOP - expr ::= unmap_dict - expr ::= unmapexpr - - unmap_dict ::= dictcomp BUILD_MAP_UNPACK - - unmap_dict ::= kv_lists BUILD_MAP_UNPACK - kv_lists ::= kv_list kv_lists - kv_lists ::= kv_list - # Python 3.5+ has WITH_CLEANUP_START/FINISH - withstmt ::= expr - SETUP_WITH exprlist suite_stmts_opt - POP_BLOCK LOAD_CONST COME_FROM_WITH - WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY - withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH @@ -90,7 +76,7 @@ def p_35on(self, args): POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_BLOCK JUMP_ABSOLUTE END_FINALLY COME_FROM for_block POP_BLOCK JUMP_ABSOLUTE - opt_come_from_loop + come_from_loops async_for_stmt ::= SETUP_LOOP expr GET_AITER @@ -102,7 +88,7 @@ def p_35on(self, args): POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_BLOCK JUMP_ABSOLUTE END_FINALLY JUMP_BACK passstmt POP_BLOCK JUMP_ABSOLUTE - opt_come_from_loop + come_from_loops stmt ::= async_forelse_stmt async_forelse_stmt ::= SETUP_LOOP expr @@ -127,7 +113,6 @@ def p_35on(self, args): return_if_stmt ::= ret_expr RETURN_END_IF POP_BLOCK ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec - ifelsestmtc ::= testexpr c_stmts_opt jf_else else_suitec # ifstmt ::= testexpr c_stmts_opt @@ -141,24 +126,37 @@ def p_35on(self, args): def add_custom_rules(self, tokens, customize): self.remove_rules(""" - # FIXME: should this be in 3.3? - whileTruestmt ::= SETUP_LOOP return_stmts COME_FROM_LOOP + yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM + yield_from ::= expr expr YIELD_FROM + withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM_WITH + WITH_CLEANUP END_FINALLY + withasstmt ::= expr SETUP_WITH store suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM_WITH + WITH_CLEANUP END_FINALLY """) super(Python35Parser, self).add_custom_rules(tokens, customize) for i, token in enumerate(tokens): opname = token.kind if opname == 'BUILD_MAP_UNPACK_WITH_CALL': + self.addRule("expr ::= unmapexpr", nop_func) nargs = token.attr % 256 map_unpack_n = "map_unpack_%s" % nargs rule = map_unpack_n + ' ::= ' + 'expr ' * (nargs) - self.add_unique_rule(rule, opname, token.attr, customize) + self.addRule(rule, nop_func) rule = "unmapexpr ::= %s %s" % (map_unpack_n, opname) - self.add_unique_rule(rule, opname, token.attr, customize) + self.addRule(rule, nop_func) call_token = tokens[i+1] if self.version == 3.5: rule = 'call ::= expr unmapexpr ' + call_token.kind - self.add_unique_rule(rule, opname, token.attr, customize) + self.addRule(rule, nop_func) pass + elif opname == 'BUILD_MAP_UNPACK': + self.addRule(""" + expr ::= unmap_dict + unmap_dict ::= dict_comp BUILD_MAP_UNPACK + """, nop_func) + pass return diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 80dcb238c..d135f5ed3 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -17,10 +17,14 @@ def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG): def p_36misc(self, args): """ # 3.6 redoes how return_closure works - return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST + return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST + + stmt ::= conditional_lambda + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + return_if_lambda ::= RETURN_END_IF_LAMBDA - fstring_multi ::= fstring_expr_or_strs BUILD_STRING - fstring_expr_or_strs ::= fstring_expr_or_str+ func_args36 ::= expr BUILD_TUPLE_0 call ::= func_args36 unmapexpr CALL_FUNCTION_EX @@ -91,9 +95,11 @@ def add_custom_rules(self, tokens, customize): fstring_expr_or_str ::= fstring_expr fstring_expr_or_str ::= str - expr ::= fstring_multi - fstring_multi ::= %s BUILD_STRING - %s ::= %sBUILD_STRING + expr ::= fstring_multi + fstring_multi ::= fstring_expr_or_strs BUILD_STRING + fstring_expr_or_strs ::= fstring_expr_or_str+ + fstring_multi ::= %s BUILD_STRING + %s ::= %sBUILD_STRING """ % (fstring_expr_or_str_n, fstring_expr_or_str_n, "fstring_expr_or_str " * v) self.add_unique_doc_rules(rules_str, customize) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 499d0579d..9d366f066 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -254,17 +254,15 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): else: op_name = '%s_%d' % (op_name, oparg) customize[op_name] = oparg - elif self.is_pypy and op_name in ('LOOKUP_METHOD', - 'JUMP_IF_NOT_DEBUG', - 'SETUP_EXCEPT', - 'SETUP_FINALLY'): + elif self.is_pypy and op_name in frozenset( + """LOOKUP_METHOD JUMP_IF_NOT_DEBUG SETUP_EXCEPT SETUP_FINALLY""".split()): # The value in the dict is in special cases in semantic actions, such # as CALL_FUNCTION. The value is not used in these cases, so we put # in arbitrary value 0. customize[op_name] = 0 - elif op == self.opc.CONTINUE_LOOP: - customize[op_name] = 0 - elif op_name == 'LOAD_SETCOMP': + elif op_name in """ + CONTINUE_LOOP EXEC_STMT LOAD_LISTCOMP LOAD_SETCOMP + """.split(): customize[op_name] = 0 elif op == self.opc.JUMP_ABSOLUTE: # Further classify JUMP_ABSOLUTE into backward jumps @@ -1027,33 +1025,45 @@ def find_jump_targets(self, debug): pass pass - # FIXME: All the < 2.7 conditions are is horrible. We need a better way. + # FIXME FIXME FIXME + # All the conditions are horrible, and I am not sure I + # undestand fully what's going l + # WeR REALLY REALLY need a better way to handle control flow + # Expecially for < 2.7 if label is not None and label != -1: - # In Python < 2.7, the POP_TOP in: - # RETURN_VALUE, POP_TOP - # does now start a new statement - # Otherwise, we have want to add a "COME_FROM" - if not (self.version < 2.7 and - code[label] == self.opc.POP_TOP and - code[self.prev[label]] == self.opc.RETURN_VALUE): + if self.version == 2.7: + # FIXME: rocky: I think we need something like this... + if label in self.setup_loops: + source = self.setup_loops[label] + else: + source = offset + targets[label] = targets.get(label, []) + [source] + elif not (code[label] == self.opc.POP_TOP and + code[self.prev[label]] == self.opc.RETURN_VALUE): # In Python < 2.7, don't add a COME_FROM, for: - # JUMP_FORWARD, END_FINALLY + # RETURN_VALUE POP_TOP .. END_FINALLY # or: - # JUMP_FORWARD, POP_TOP, END_FINALLY - if not (self.version < 2.7 and op == self.opc.JUMP_FORWARD - and ((code[offset+3] == self.opc.END_FINALLY) - or (code[offset+3] == self.opc.POP_TOP - and code[offset+4] == self.opc.END_FINALLY))): - + # RETURN_VALUE POP_TOP .. POP_TOP END_FINALLY + skip_come_from = False + if self.version <= 2.5: + skip_come_from = (code[offset+3] == self.opc.END_FINALLY or + (code[offset+3] == self.opc.POP_TOP + and code[offset+4] == self.opc.END_FINALLY)) + else: + skip_come_from = (code[offset+3] == self.opc.END_FINALLY or + (op != self.opc.JUMP_FORWARD + and code[offset+3] == self.opc.POP_TOP + and code[offset+4] == self.opc.END_FINALLY)) + if not skip_come_from: # FIXME: rocky: I think we need something like this... - if offset not in set(self.ignore_if) or self.version == 2.7: + if offset not in set(self.ignore_if): if label in self.setup_loops: source = self.setup_loops[label] else: source = offset targets[label] = targets.get(label, []) + [source] + pass pass - pass pass elif op == self.opc.END_FINALLY and offset in self.fixed_jumps and self.version == 2.7: diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index e774ef196..567e06b15 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -240,6 +240,10 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): customize[op_name] = oparg elif self.version > 2.0 and op == self.opc.CONTINUE_LOOP: customize[op_name] = 0 + elif op_name in """ + CONTINUE_LOOP EXEC_STMT LOAD_LISTCOMP LOAD_SETCOMP + """.split(): + customize[op_name] = 0 elif op == self.opc.JUMP_ABSOLUTE: # Further classify JUMP_ABSOLUTE into backward jumps # which are used in loops, and "CONTINUE" jumps which diff --git a/uncompyle6/semantics/check_ast.py b/uncompyle6/semantics/check_ast.py index 417232d14..16773ac7c 100644 --- a/uncompyle6/semantics/check_ast.py +++ b/uncompyle6/semantics/check_ast.py @@ -14,7 +14,7 @@ def checker(ast, in_loop, errors): in_loop = in_loop or ast.kind in ('while1stmt', 'whileTruestmt', 'whilestmt', 'whileelsestmt', 'while1elsestmt', 'for_block') - if ast.kind in ('augassign1', 'augassign2') and ast[0][0] == 'and': + if ast.kind in ('aug_assign1', 'aug_assign2') and ast[0][0] == 'and': text = str(ast) error_text = '\n# improper augmented assigment (e.g. +=, *=, ...):\n#\t' + '\n# '.join(text.split("\n")) + '\n' errors.append(error_text) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 12a6a542d..93b5587b5 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -156,7 +156,6 @@ 'unpack_list': ( '[%C]', (1, maxint, ', ') ), 'build_tuple2': ( '%P', (0, -1, ', ', 100) ), - # 'list_compr': ( '[ %c ]', -2), # handled by n_list_compr 'list_iter': ( '%c', 0 ), 'list_for': ( ' for %c in %c%c', 2, 0, 3 ), 'list_if': ( ' if %c%c', 0, 2 ), @@ -176,9 +175,9 @@ # The 2nd parameter should have a = suffix. # There is a rule with a 4th parameter "store" # which we don't use here. - 'augassign1': ( '%|%c %c %c\n', 0, 2, 1), + 'aug_assign1': ( '%|%c %c %c\n', 0, 2, 1), - 'augassign2': ( '%|%c.%[2]{pattr} %c %c\n', 0, -3, -4 ), + 'aug_assign2': ( '%|%c.%[2]{pattr} %c %c\n', 0, -3, -4 ), 'designList': ( '%c = %c', 0, -1 ), 'and': ( '%c and %c', 0, 2 ), 'ret_and': ( '%c and %c', 0, 2 ), @@ -197,12 +196,12 @@ 'compare_chained1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), 'compare_chained2': ( '%[1]{pattr} %p', (0, 19)), # 'classdef': (), # handled by n_classdef() - 'funcdef': ( '\n\n%|def %c\n', -2), # -2 to handle closures - 'funcdefdeco': ( '\n\n%c', 0), + 'function_def': ( '\n\n%|def %c\n', -2), # -2 to handle closures + 'funcdefdeco': ( '\n\n%c', 0), 'mkfuncdeco': ( '%|@%c\n%c', 0, 1), - 'mkfuncdeco0': ( '%|def %c\n', 0), - 'classdefdeco': ( '\n\n%c', 0), - 'classdefdeco1': ( '%|@%c\n%c', 0, 1), + 'mkfuncdeco0': ( '%|def %c\n', 0), + 'classdefdeco': ( '\n\n%c', 0), + 'classdefdeco1': ( '%|@%c\n%c', 0, 1), 'kwarg': ( '%[0]{pattr}=%c', 1), 'kwargs': ( '%D', (0, maxint, ', ') ), @@ -271,14 +270,13 @@ 'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ), 'passstmt': ( '%|pass\n', ), 'STORE_FAST': ( '%{pattr}', ), - 'kv': ( '%c: %c', 3, 1 ), - 'kv2': ( '%c: %c', 1, 2 ), - 'mapexpr': ( '{%[1]C}', (0, maxint, ', ') ), - 'importstmt': ( '%|import %c\n', 2), - 'importlist': ( '%C', (0, maxint, ', ') ), - 'importfrom': ( '%|from %[2]{pattr} import %c\n', - (3, 'importlist') ), - 'importstar': ( '%|from %[2]{pattr} import *\n', ), + 'kv': ( '%c: %c', 3, 1 ), + 'kv2': ( '%c: %c', 1, 2 ), + 'import': ( '%|import %c\n', 2), + 'importlist': ( '%C', (0, maxint, ', ') ), + 'import_from': ( '%|from %[2]{pattr} import %c\n', + (3, 'importlist') ), + 'import_from_star': ( '%|from %[2]{pattr} import *\n', ), } @@ -299,12 +297,12 @@ # or https://docs.python.org/3/reference/expressions.html # for a list. PRECEDENCE = { - 'build_list': 0, - 'mapexpr': 0, + 'list': 0, + 'dict': 0, 'unary_convert': 0, - 'dictcomp': 0, - 'setcomp': 0, - 'list_compr': 0, + 'dict_comp': 0, + 'set_comp': 0, + 'list_comp': 0, 'generator_exp': 0, 'load_attr': 2, diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 9fdda4631..5ffa976a6 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -18,7 +18,7 @@ from src to dest. For example in: - 'importstmt': ( '%|import %c%x\n', 2, (2,(0,1)), ), + 'import': ( '%|import %c%x\n', 2, (2,(0,1)), ), node 2 range information, it in %c, is copied to nodes 0 and 1. @@ -91,7 +91,7 @@ 'continue_stmt': ( '%|%rcontinue\n', ), 'passstmt': ( '%|%rpass\n', ), 'raise_stmt0': ( '%|%rraise\n', ), - 'importstmt': ( '%|import %c%x\n', 2, (2, (0, 1)), ), + 'import': ( '%|import %c%x\n', 2, (2, (0, 1)), ), 'importfrom': ( '%|from %[2]{pattr}%x import %c\n', (2, (0, 1)), 3), 'importmultiple': ( '%|import%b %c%c\n', 0, 2, 3 ), 'list_for': (' for %c%x in %c%c', 2, (2, (1, )), 0, 3 ), @@ -194,7 +194,7 @@ def table_r_node(self, node): raise GenericASTTraversalPruningException n_slice0 = n_slice1 = n_slice2 = n_slice3 = n_subscript = table_r_node - n_augassign_1 = n_print_item = exec_stmt = print_to_item = del_stmt = table_r_node + n_aug_assign_1 = n_print_item = exec_stmt = print_to_item = del_stmt = table_r_node n_classdefco1 = n_classdefco2 = except_cond1 = except_cond2 = table_r_node def n_passtmt(self, node): @@ -490,7 +490,7 @@ def n_elifelsestmtr(self, node): self.set_pos_info(node, start, len(self.f.getvalue())) self.prune() - def n_import_as(self, node): + def n_alias(self, node): start = len(self.f.getvalue()) iname = node[0].pattr @@ -543,8 +543,8 @@ def n_mkfunc(self, node): self.indent_less() self.prune() # stop recursing - def n_list_compr(self, node): - """List comprehensions the way they are done in Python 2.""" + def n_list_comp(self, node): + """List comprehensions""" p = self.prec self.prec = 27 n = node[-1] @@ -571,7 +571,7 @@ def comprehension_walk(self, node, iter_index, code_index=-5): self.prec = 27 # FIXME: clean this up - if self.version > 3.0 and node == 'dictcomp': + if self.version > 3.0 and node == 'dict_comp': cn = node[1] elif self.version > 3.0 and node == 'generator_exp': if node[0] == 'load_genexpr': @@ -784,7 +784,7 @@ def n_generator_exp(self, node): self.set_pos_info(node, start, len(self.f.getvalue())) self.prune() - def n_setcomp(self, node): + def n_set_comp(self, node): start = len(self.f.getvalue()) self.write('{') if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']: @@ -799,7 +799,7 @@ def n_setcomp(self, node): self.set_pos_info(node, start, len(self.f.getvalue())) self.prune() - # FIXME: Not sure if below is general. Also, add dictcomp_func. + # FIXME: Not sure if below is general. Also, add dict_comp_func. # 'setcomp_func': ("%|lambda %c: {%c for %c in %c%c}\n", 1, 3, 3, 1, 4) def n_setcomp_func(self, node): setcomp_start = len(self.f.getvalue()) @@ -1324,10 +1324,10 @@ def print_super_classes3(self, node): self.write(')') self.set_pos_info(node, start, len(self.f.getvalue())) - def n_mapexpr(self, node): + def n_dict(self, node): """ - prettyprint a mapexpr - 'mapexpr' is something like k = {'a': 1, 'b': 42 }" + prettyprint a dict + 'dict' is something like k = {'a': 1, 'b': 42 }" """ p = self.prec self.prec = 100 @@ -1340,7 +1340,7 @@ def n_mapexpr(self, node): if self.version > 3.0: if node[0].kind.startswith('kvlist'): - # Python 3.5+ style key/value list in mapexpr + # Python 3.5+ style key/value list in dict kv_node = node[0] l = list(kv_node) i = 0 @@ -1355,7 +1355,7 @@ def n_mapexpr(self, node): pass pass elif node[1].kind.startswith('kvlist'): - # Python 3.0..3.4 style key/value list in mapexpr + # Python 3.0..3.4 style key/value list in dict kv_node = node[1] l = list(kv_node) if len(l) > 0 and l[0].kind == 'kv3': @@ -1413,7 +1413,7 @@ def n_mapexpr(self, node): self.prec = p self.prune() - def n_build_list(self, node): + def n_list(self, node): """ prettyprint a list or tuple """ @@ -1431,7 +1431,7 @@ def n_build_list(self, node): elif lastnode.startswith('ROT_TWO'): self.write('('); endchar = ')' else: - raise RuntimeError('Internal Error: n_build_list expects list or tuple') + raise RuntimeError('Internal Error: n_list expects list or tuple') flat_elems = [] for elem in node: @@ -1844,7 +1844,7 @@ def gcd(a, b): # deparse_test(get_code_for_fn(gcd)) # deparse_test(get_code_for_fn(test)) # deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets)) - # deparse_test(get_code_for_fn(FragmentsWalker.n_build_list)) + # deparse_test(get_code_for_fn(FragmentsWalker.n_list)) print('=' * 30) - deparse_test_around(408, 'n_build_list', get_code_for_fn(FragmentsWalker.n_build_list)) + deparse_test_around(408, 'n_list', get_code_for_fn(FragmentsWalker.n_build_list)) # deparse_test(inspect.currentframe().f_code) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index fc0301c42..53ca14063 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -479,7 +479,10 @@ def build_param(ast, name, default): - handle format tuple parameters """ if default: - value = self.traverse(default, indent='') + if self.version >= 3.6: + value = default + else: + value = self.traverse(default, indent='') maybe_show_ast_param_default(self.showast, name, value) result = '%s=%s' % (name, value) if result[-2:] == '= ': # default was 'LOAD_CONST None' @@ -505,12 +508,17 @@ def build_param(ast, name, default): defparams = node[:args_node.attr] else: default, kw, annotate, closure = args_node.attr - # FIXME: start here for Python 3.6 and above: - defparams = [] - # if default: - # defparams = node[-(2 + kw + annotate + closure)] - # else: - # defparams = [] + if default: + assert node[0] == 'expr', "expecting mkfunc default node to be an expr" + expr_node = node[0] + if (expr_node[0] == 'LOAD_CONST' and + isinstance(expr_node[0].attr, tuple)): + defparams = list(expr_node[0].attr) + elif expr_node[0] == 'list': + defparams = [self.traverse(n, indent='') for n in expr_node[0][:-1]] + else: + defparams = [] + # FIXME: handle kw, annotate and closure kw_args = 0 pass @@ -536,7 +544,7 @@ def build_param(ast, name, default): paramnames = list(code.co_varnames[:argc]) # defaults are for last n parameters, thus reverse - if not 3.0 <= self.version <= 3.1: + if not 3.0 <= self.version <= 3.1 or self.version >= 3.6: paramnames.reverse(); defparams.reverse() try: @@ -557,10 +565,11 @@ def build_param(ast, name, default): indent = self.indent # build parameters - if self.version != 3.2: - tup = [paramnames, defparams] - params = [build_param(ast, name, default) for - name, default in map(lambda *tup:tup, *tup)] + tup = [paramnames, defparams] + params = [build_param(ast, name, default_value) for + name, default_value in map(lambda *tup:tup, *tup)] + + if not 3.0 <= self.version <= 3.1 or self.version >= 3.6: params.reverse() # back to correct order if code_has_star_arg(code): diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 5881984fd..99eaea0dd 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -359,7 +359,7 @@ def customize_for_version(self, is_pypy, version): if version >= 3.0: TABLE_DIRECT.update({ - 'funcdef_annotate': ( '\n\n%|def %c%c\n', -1, 0), + 'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0), 'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ), }) @@ -384,7 +384,7 @@ def n_mkfunc_annotate(node): break # FIXME: the real situation is that when derived from - # funcdef_annotate we the name has been filled in. + # function_def_annotate we the name has been filled in. # But when derived from funcdefdeco it hasn't Would like a better # way to distinquish. if self.f.getvalue()[-4:] == 'def ': @@ -444,7 +444,7 @@ def n_async_call(node): node.kind == 'async_call' self.prune() self.n_async_call = n_async_call - self.n_build_list_unpack = self.n_build_list + self.n_build_list_unpack = self.n_list if version == 3.5: def n_call(node): @@ -472,7 +472,7 @@ def n_call(node): self.default(node) self.n_call = n_call - def n_funcdef(node): + def n_function_def(node): if self.version == 3.6: code_node = node[0][0] else: @@ -487,7 +487,7 @@ def n_funcdef(node): self.template_engine(('\n\n%|def %c\n', -2), node) self.prune() - self.n_funcdef = n_funcdef + self.n_function_def = n_function_def def n_unmapexpr(node): last_n = node[0][-1] @@ -987,7 +987,7 @@ def n_elifelsestmtr(self, node): self.indent_less() self.prune() - def n_import_as(self, node): + def n_alias(self, node): if self.version <= 2.1: if len(node) == 2: store = node[1] @@ -1012,13 +1012,13 @@ def n_import_as(self, node): self.write(iname, ' as ', sname) self.prune() # stop recursing - def n_importfrom(self, node): + def n_import_from(self, node): relative_path_index = 0 if self.version >= 2.5 and node[relative_path_index].pattr > 0: node[2].pattr = '.'*node[relative_path_index].pattr + node[2].pattr self.default(node) - n_importstar = n_importfrom + n_import_from_star = n_import_from def n_mkfunc(self, node): @@ -1058,14 +1058,13 @@ def n_mklambda(self, node): self.make_function(node, is_lambda=True, codeNode=node[-2]) self.prune() # stop recursing - def n_list_compr(self, node): - """List comprehensions the way they are done in Python 2. - """ + def n_list_comp(self, node): + """List comprehensions""" p = self.prec self.prec = 27 if self.version >= 2.7: if self.is_pypy: - self.n_list_compr_pypy27(node) + self.n_list_comp_pypy27(node) return n = node[-1] elif node[-1] == 'del_stmt': @@ -1116,9 +1115,8 @@ def n_list_compr(self, node): self.prec = p self.prune() # stop recursing - def n_list_compr_pypy27(self, node): - """List comprehensions the way they are done in PYPY Python 2.7. - """ + def n_list_comp_pypy27(self, node): + """List comprehensions in PYPY.""" p = self.prec self.prec = 27 if node[-1].kind == 'list_iter': @@ -1166,7 +1164,7 @@ def comprehension_walk(self, node, iter_index, code_index=-5): self.prec = 27 # FIXME: clean this up - if self.version > 3.0 and node == 'dictcomp': + if self.version > 3.0 and node == 'dict_comp': cn = node[1] elif self.version < 2.7 and node == 'generator_exp': if node[0] == 'LOAD_GENEXPR': @@ -1241,7 +1239,7 @@ def n_generator_exp(self, node): self.write(')') self.prune() - def n_setcomp(self, node): + def n_set_comp(self, node): self.write('{') if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']: self.comprehension_walk3(node, 1, 0) @@ -1344,7 +1342,7 @@ def listcomprehension_walk2(self, node): code = Code(node[1].attr, self.scanner, self.currentclass) ast = self.build_ast(code._tokens, code._customize) self.customize(code._customize) - if node == 'setcomp': + if node == 'set_comp': ast = ast[0][0][0] else: ast = ast[0][0][0][0][0] @@ -1390,7 +1388,7 @@ def n_listcomp(self, node): self.write(']') self.prune() - n_dictcomp = n_setcomp + n_dict_comp = n_set_comp def setcomprehension_walk3(self, node, collection_index): """List comprehensions the way they are done in Python3. @@ -1447,6 +1445,8 @@ def n_classdef(self, node): if node == 'classdefdeco2': if self.version >= 3.6: class_name = node[1][1].pattr + elif self.version <= 3.3: + class_name = node[2][0].pattr else: class_name = node[1][2].pattr buildclass = node @@ -1556,7 +1556,7 @@ def n_classdef(self, node): n_classdefdeco2 = n_classdef def print_super_classes(self, node): - if not (node == 'build_list'): + if not (node == 'list'): return n_subclasses = len(node[:-1]) @@ -1605,10 +1605,10 @@ def print_super_classes3(self, node): self.write(')') - def n_mapexpr(self, node): + def n_dict(self, node): """ - prettyprint a mapexpr - 'mapexpr' is something like k = {'a': 1, 'b': 42}" + prettyprint a dict + 'dict' is something like k = {'a': 1, 'b': 42}" We will source-code use line breaks to guide us when to break. """ p = self.prec @@ -1621,7 +1621,7 @@ def n_mapexpr(self, node): if self.version >= 3.0 and not self.is_pypy: if node[0].kind.startswith('kvlist'): - # Python 3.5+ style key/value list in mapexpr + # Python 3.5+ style key/value list in dict kv_node = node[0] l = list(kv_node) i = 0 @@ -1644,7 +1644,7 @@ def n_mapexpr(self, node): pass pass elif len(node) > 1 and node[1].kind.startswith('kvlist'): - # Python 3.0..3.4 style key/value list in mapexpr + # Python 3.0..3.4 style key/value list in dict kv_node = node[1] l = list(kv_node) if len(l) > 0 and l[0].kind == 'kv3': @@ -1756,7 +1756,7 @@ def n_mapexpr(self, node): self.prec = p self.prune() - def n_build_list(self, node): + def n_list(self, node): """ prettyprint a list or tuple """ @@ -1847,7 +1847,7 @@ def n_build_list(self, node): self.prune() return - n_build_set = n_build_list + n_build_set = n_list def n_unpack(self, node): if node[0].kind.startswith('UNPACK_EX'): @@ -2074,9 +2074,9 @@ def customize(self, customize): TABLE_R[k] = entry pass - # handled by n_mapexpr: + # handled by n_dict: # if op == 'BUILD_SLICE': TABLE_R[k] = ('%C' , (0,-1,':')) - # handled by n_build_list: + # handled by n_list: # if op == 'BUILD_LIST': TABLE_R[k] = ('[%C]' , (0,-1,', ')) # elif op == 'BUILD_TUPLE': TABLE_R[k] = ('(%C%,)', (0,-1,', ')) pass From fc0eb876204ed83865129c5abb74db40f1788230 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Dec 2017 10:01:33 -0500 Subject: [PATCH 089/489] Python 2.4 compatability --- uncompyle6/parsers/parse3.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 331099325..70022d7e1 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -808,7 +808,10 @@ def add_custom_rules(self, tokens, customize): args_pos, args_kw, annotate_args = token.attr # FIXME: Fold test into add_make_function_rule - j = 1 if self.version < 3.3 else 2 + if self.version < 3.3: + j = 1 + else: + j = 2 if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LAMBDA'): rule_pat = ('mklambda ::= %sload_closure LOAD_LAMBDA %%s%s' % ('pos_arg '* args_pos, opname)) @@ -896,7 +899,10 @@ def add_custom_rules(self, tokens, customize): else: args_pos, args_kw, annotate_args, closure = token.attr - j = 1 if self.version < 3.3 else 2 + if self.version < 3.3: + j = 1 + else: + j = 2 if has_get_iter_call_function1: rule_pat = ("generator_exp ::= %sload_genexpr %%s%s expr " "GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname)) From 36aba0209335dadf8d9745d3ac34b59960635489 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Dec 2017 14:17:59 -0500 Subject: [PATCH 090/489] Correct Python 2.4 importmultiple rule --- uncompyle6/semantics/pysource.py | 4 ++++ uncompyle6/verify.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 99eaea0dd..892e3a895 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -284,6 +284,10 @@ def customize_for_version(self, is_pypy, version): }) if version <= 2.4: + TABLE_DIRECT.update({ + 'importmultiple': ( '%|import %c%c\n', 2, 3), + 'import_cont' : ( ', %c', 2), + }) if version == 2.3: TABLE_DIRECT.update({ 'if1_stmt': ( '%|if 1\n%+%c%-', 5 ) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 40a8f51f1..480c8962d 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -6,7 +6,8 @@ byte-code verification """ -import dis, operator +import operator +import xdis.std as dis import uncompyle6 import uncompyle6.scanner as scanner From 7b15e54b7dd40da362f5208a9ac8034b7b5a1a1f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Dec 2017 19:11:11 -0500 Subject: [PATCH 091/489] Add "global" in functions that just read --- test/bytecode_2.1/10_del.pyc | Bin 835 -> 907 bytes test/bytecode_2.2/10_del.pyc | Bin 0 -> 911 bytes test/bytecode_2.4/10_del.pyc | Bin 488 -> 772 bytes test/bytecode_2.5/10_del.pyc | Bin 497 -> 823 bytes test/bytecode_2.6/10_del.pyc | Bin 497 -> 823 bytes test/bytecode_2.7/10_del.pyc | Bin 501 -> 823 bytes test/simple_source/stmts/10_del.py | 6 ++++++ test/stdlib/runtests.sh | 8 ++++++++ uncompyle6/parsers/parse2.py | 1 + uncompyle6/parsers/parse27.py | 1 - uncompyle6/semantics/make_function.py | 18 +++++++++++++----- uncompyle6/semantics/pysource.py | 5 ++++- 12 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 test/bytecode_2.2/10_del.pyc diff --git a/test/bytecode_2.1/10_del.pyc b/test/bytecode_2.1/10_del.pyc index 41a3f854e4101e68c2ef637881522c853fd628dd..db47e6a0d051185e71387fd64abf81ef184445e2 100644 GIT binary patch literal 907 zcmbVJ%We}v5UiQ;?)s@15-=bWqrhRsAtpSIh(GWpx8)Gop0O3l!BNH>j6~)FU%)SN z<0q(Y+a!Vuu-Ym0w7RRSYo7n;G{2oZt)}2t@Wk(g#NWaL-oRVT94cmNcuy?g9efQw z!<>18R7YSL@HRChdYRe?7IWru98?aegTNMp)~mD!Pl6pWndTX)8d4X5l)&qBMQJ z%8beoijl52HEh(@p0o~-o**6Jn(;HN3{G#!7AI8pTJh7(9_xQxL2Q@|5XDDloXu_d zi+r*r|0BWLja7f;lD8a9a*YMfKX3B@*!)fApQcRnH^l@dCsFd;_*1F%=Zik4iMnR5543lg$2X68BFiN{_HD9^z<;B3Jv(9qu*v5FVsKK!p zqm81b8q%~$85+Yk@k~LBho;${WW)W4r|69oQH6ZW+`K5PdVl?gD~A6Gbfyspx@=!T52s{0CfeTMwzg3=~yFQVt%l%FIQ7fj`l+ ze?ffRfLMA_w{~Ck^me~~{pQKHX8p_QqjCg31;6-}koa17z#Djru|vsB1#gH2yo0a6 zXP7W=kg5nQ174+?M9)$K!D7N(j)T%6H4)fS;Cb4EukLtBG|5m_kXi_21YV?D8tK@V zY5(`~&D;WIhID|CDH)|2e0CIY7rq8x$JpW`M{2|0z$c(AkUH=Ujk#45XT6);b7};v zfD@<)WCFQBUEup_wVE5BI5KS1*0!{Ek&cj#an1NK76xa($QCXFH;1ax>^v$)N0;%Tfae^S42hGsTgjR}5RPdm>a* s>&|u2TB+X_>Hpb(IPuydb~xaU&E0KNH-&4Ny1mD!X%Ef5-7}5s2d0IR3jhEB literal 0 HcmV?d00001 diff --git a/test/bytecode_2.4/10_del.pyc b/test/bytecode_2.4/10_del.pyc index 371328cb31777ca4d1be695de6bd373e0ba8ee92..95de87ec2fb1df8dfb45e0d5e9a5a475e37fe2b2 100644 GIT binary patch literal 772 zcmZ8eyG{c!5FFdNyATLa@F+l{pt*|hED=cbDUR+a5X2^mln{iE0wk#53-|@TkPjg2 zY#yMTTx z)Q~5dxXf2YXwMKV!4YbNgpd*%grCu9)Dr_0i*FQfXLB=lAt!PHw?Yk}X0WZO)gc!j ze^Bj+yVr`n!9zb>$KlgsC$wTUsAB72|JsNC-otZ6J$J+5rd*M-U}5xCs-3;MA&w0D z3cTrdWKgkH1PR(YV29VW+Qa*xdi#nUMPH~K=5xv!_bkw& p_JV)4P%6O_SMmu^M*EtlHEpB)^!pRP6u& delta 256 zcmX|)u?_)25QhKRy<2e{*PuXhk#P3_ltQ7FINfz(MWs5ej;J^HG zeDlvgGnun`%J}dOgWIE*Z}E!?*Ewf#W$2oT2Z@4aNzejXV(%jt*s%u2wz$DWD|6~3 z5N++abQNbH_n`x<)6m=p=C${t+6+ZfG^s+KXfXrPrAR3H03T~0cK`qY diff --git a/test/bytecode_2.5/10_del.pyc b/test/bytecode_2.5/10_del.pyc index 686422bc022349cf7fddc2cdab7ea81d038fb1a2..4aaf178f6455fb72908c73fe252c69b772158c03 100644 GIT binary patch literal 823 zcmb7ByG{c!5FDR#cMu3r@F+l{pt*|h>;NIrr%1Y^KqNL%q=bv`QGf&$d;!0}AMj^< z0AXi=L_!qAl4ob_eazZ#@3rd7?pEHx_e#Z{$_}prZUH%PF2urB;9_(waszMRfMYRx zu7<9736^sUFJUS6-3+gt97oLT#>gx1k`Elv=*8i$sPFnI@)$nW0+Ma;Y;o)sahbr) z;R(o7xOpYgqJ~zsBtmeaI*dEW#voqO&573sIZ<{vs5&HyvLO<)94p-JJ{P``g32l6tO+Vogk-Kv?ZbI_|kD zj*R*MJnGxXn8H;8(;GTohv7fFC0wOG$~=Eay`QMQn@(_(EjU=adA74Na3ESprp>mkOE{fGNdpuq%bq2vob_6 zF{A?73=Ae93M^ro!Zxv1T%DOAl^LuWEZ)k@V4K3jkjTQ2!pYFWz!1gCkix|ftie0+ zh|;NIrr%1Y^KqNL%q=bv`QGf&$d;!0}5AiE} z0AXi=L_!qAl4ob_eazZ#@3rd7?pEHx_e#Z{$_}prZUH%PF2urB;9_(waszMRfMYRx zu7<9736^sUFJUS6-3+gt97oLT#>gx1k`Elv=*8i$sPFnI@)$nW0+Ma;Y;o)sahbr) z;R(o7xOpYgqJ~zsBtmeaI*dEW#voqO&573sIZ<{vs5&HyvLO<)94p-JJ{P``g32l6tO+Vogk-Kv?ZbI_|kD zj*R*MJnGxXn8H;8(;GTohv7fFC0wOG$~=Eay`QMQn@(_(EjU=goOgNCXuy^CN&jXGikIUtQxJGr6@78@h5a9cr*Y2 delta 235 zcmdna_K{iP;wN6NotI>yk{O_Y9Y{L>adA74Na3ESprp>mkOE{fGNdpuq%bq2vob_6 zF{A?73=Ae93M^ro!Zxv1T%DOAl^LuWEZ)k@V4K3jkjTQ2!pYFWz!1gCkix|ftie0+ zh|ib6bNDyMM^k?FGY|@1z*4~@Q3t- zodpsJQGg}S&f5E!we4H2`qJ3RJNR0u*fZJTRlqGF2QGwIxC&g1u0?L(4IFSHX5ZD& z6)(YRZs8>?#etjSwUgtBncWz91zz%jLmIs}`VsY2KSdtH$67$L4W2Dd+%m2bxCJ}` zc?!3vL|W9)&Q?Td&k!PlB~%D8At6)=?~}=-Cj=#fuN1GRbMx$6cHjeCOKC`H9yS#< z+GpZp24P#=-FoN^?)v^R6vO+DuZMC_hI(V~()s@G-KeCVo1)kd6DSZ?dy-Cju8Sk1 zJ_2KX8yQo$N?>|Z$Llcsd$)zF)UnL-i`0ji>e2rMx7dP%1wJCIjXv`!Snpaq|7T5B z+L9gk9WaTprkQcHA0L-#7shC-Y>sT|mh9XtZoU3SU$LX;TAIj;GiA#D^ha!SJSg0- f?@w7MP-_xdyKGWZu{D!MYr?A0rdf#+Gar8d;O%#3 delta 196 zcmdna_LW(I`7gi1A_^O0!x^tuuZHLS7&BOWd^GTi?=c}*rxC>B(gB1a5A(oFhsF3q;N3=Yw%7y zqBQYCCAR>`9ws2cz%;pvNtKTc$O-~+gBXFt Date: Sun, 3 Dec 2017 05:04:06 -0500 Subject: [PATCH 092/489] Grammar "COME_FROM"_from cleanups ... tryelse constructs in 2.x fixed up _come_from -> _come_froms (COME_FROM*) consolidate come_froms rule into sincle parser.py sync unit/test_grammar.py --- test-unit/test_grammar.py | 4 ++-- uncompyle6/parser.py | 22 ++++++++++++---------- uncompyle6/parsers/parse25.py | 2 +- uncompyle6/parsers/parse26.py | 19 +++++++------------ uncompyle6/parsers/parse27.py | 5 +---- uncompyle6/parsers/parse3.py | 9 ++++----- uncompyle6/parsers/parse30.py | 2 +- uncompyle6/parsers/parse32.py | 2 +- uncompyle6/scanners/scanner2.py | 17 ++++++++++------- 9 files changed, 39 insertions(+), 43 deletions(-) diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index 13b39c362..b063934e0 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -18,12 +18,12 @@ def check_tokens(tokens, opcode_set): (lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets() expect_lhs = set(['expr1024', 'pos_arg']) - unused_rhs = set(['build_list', 'call_function', 'mkfunc', + unused_rhs = set(['list', 'call', 'mkfunc', 'mklambda', 'unpack',]) expect_right_recursive = frozenset([('designList', - ('designator', 'DUP_TOP', 'designList'))]) + ('store', 'DUP_TOP', 'designList'))]) expect_lhs.add('kwarg') self.assertEqual(expect_lhs, set(lhs)) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index ac2ec9ccb..cc785b770 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -31,7 +31,7 @@ def __init__(self, AST, start, debug): # FIXME: customize per python parser version nt_list = [ 'stmts', 'except_stmts', '_stmts', 'load_attrs', - 'exprlist', 'kvlist', 'kwargs', 'come_froms', '_come_from', + 'exprlist', 'kvlist', 'kwargs', 'come_froms', '_come_froms', 'importlist', # Python < 3 'print_items', @@ -304,9 +304,11 @@ def p_jump(self, args): _jump ::= JUMP_FORWARD _jump ::= JUMP_BACK - # Zero or more COME_FROMs - # loops can have this - _come_from ::= COME_FROM* + # Zero or more COME_FROMs - loops can have this + _come_froms ::= COME_FROM* + + # One or more COME_FROMs - joins of tryelse's have this + come_froms ::= COME_FROM+ # Zero or one COME_FROM # And/or expressions have this @@ -358,19 +360,19 @@ def p_forstmt(self, args): """ _for ::= GET_ITER FOR_ITER - for_block ::= l_stmts_opt _come_from JUMP_BACK + for_block ::= l_stmts_opt _come_froms JUMP_BACK forstmt ::= SETUP_LOOP expr _for store - for_block POP_BLOCK _come_from + for_block POP_BLOCK _come_froms forelsestmt ::= SETUP_LOOP expr _for store - for_block POP_BLOCK else_suite _come_from + for_block POP_BLOCK else_suite _come_froms forelselaststmt ::= SETUP_LOOP expr _for store - for_block POP_BLOCK else_suitec _come_from + for_block POP_BLOCK else_suitec _come_froms forelselaststmtl ::= SETUP_LOOP expr _for store - for_block POP_BLOCK else_suitel _come_from + for_block POP_BLOCK else_suitel _come_froms """ def p_import20(self, args): @@ -493,7 +495,7 @@ def p_expr(self, args): compare_single ::= expr expr COMPARE_OP # A compare_chained is two comparisions like x <= y <= z - compare_chained ::= expr compare_chained1 ROT_TWO POP_TOP _come_from + compare_chained ::= expr compare_chained1 ROT_TWO POP_TOP _come_froms compare_chained2 ::= expr COMPARE_OP JUMP_FORWARD # Non-null kvlist items are broken out in the indiviual grammars diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 27525306e..4c0de8d02 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -33,7 +33,7 @@ def p_misc25(self, args): store ::= STORE_NAME tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK - try_middle else_suite COME_FROM + try_middle else_suite come_froms # Python 2.6 omits the LOAD_FAST DELETE_FAST below # withas is allowed as a "from future" in 2.5 diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index f9e93dfda..107fde532 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -47,16 +47,11 @@ def p_try_except26(self, args): except_suite ::= c_stmts_opt JUMP_FORWARD POP_TOP except_suite ::= c_stmts_opt jmp_abs come_from_pop - # Python 3 also has this. - come_froms ::= come_froms COME_FROM - come_froms ::= COME_FROM - # This is what happens after a jump where # we start a new block. For reasons I don't fully # understand, there is also a value on the top of the stack come_from_pop ::= COME_FROM POP_TOP come_froms_pop ::= come_froms POP_TOP - """ # In contrast to Python 2.7, Python 2.6 has a lot of @@ -86,7 +81,7 @@ def p_jumps26(self, args): # COME_FROM_LOOP, but in <= 2.6 we don't distinguish # this - cf_jb_cf_pop ::= _come_from JUMP_BACK come_froms POP_TOP + cf_jb_cf_pop ::= _come_froms JUMP_BACK come_froms POP_TOP bp_come_from ::= POP_BLOCK COME_FROM jb_bp_come_from ::= JUMP_BACK bp_come_from @@ -137,7 +132,7 @@ def p_stmt26(self, args): while1stmt ::= SETUP_LOOP l_stmts JUMP_BACK COME_FROM - whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK _come_from + whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK _come_froms whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop bp_come_from whilestmt ::= SETUP_LOOP testexpr return_stmts POP_BLOCK COME_FROM @@ -179,7 +174,7 @@ def p_stmt26(self, args): jmp_true_then ::= JUMP_IF_TRUE THEN POP_TOP while1stmt ::= SETUP_LOOP return_stmts COME_FROM - for_block ::= return_stmts _come_from + for_block ::= return_stmts _come_froms """ def p_comp26(self, args): @@ -206,7 +201,7 @@ def p_comp26(self, args): comp_body ::= gen_comp_body - for_block ::= l_stmts_opt _come_from POP_TOP JUMP_BACK + for_block ::= l_stmts_opt _come_froms POP_TOP JUMP_BACK # Make sure we keep indices the same as 2.7 setup_loop_lf ::= SETUP_LOOP LOAD_FAST @@ -242,11 +237,11 @@ def p_misc26(self, args): and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP # compare_chained is like x <= y <= z - compare_chained ::= expr compare_chained1 ROT_TWO COME_FROM POP_TOP _come_from + compare_chained ::= expr compare_chained1 ROT_TWO COME_FROM POP_TOP _come_froms compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP - jmp_false compare_chained1 _come_from + jmp_false compare_chained1 _come_froms compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP - jmp_false compare_chained2 _come_from + jmp_false compare_chained2 _come_froms return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP stmt ::= conditional_lambda conditional_lambda ::= expr jmp_false_then expr return_if_lambda diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index d882dbeb7..ec8059ce7 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -61,9 +61,6 @@ def p_try27(self, args): def p_jump27(self, args): """ - come_froms ::= come_froms COME_FROM - come_froms ::= COME_FROM - iflaststmtl ::= testexpr c_stmts_opt _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms @@ -112,7 +109,7 @@ def p_stmt27(self, args): while1stmt ::= SETUP_LOOP return_stmts 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_from + whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_BLOCK else_suite COME_FROM whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 9532a73ac..6ac33e9e6 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -154,10 +154,10 @@ def p_grammar(self, args): ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite opt_come_from_except ifelsestmt ::= testexpr c_stmts_opt jump_forward_else - else_suite _come_from + else_suite _come_froms # ifelsestmt ::= testexpr c_stmts_opt jump_forward_else - # passstmt _come_from + # passstmt _come_froms ifelsestmtc ::= testexpr c_stmts_opt JUMP_ABSOLUTE else_suitec ifelsestmtc ::= testexpr c_stmts_opt jump_absolute_else else_suitec @@ -298,10 +298,9 @@ def p_def_annotations3(self, args): def p_come_from3(self, args): """ opt_come_from_except ::= COME_FROM_EXCEPT - opt_come_from_except ::= come_froms + opt_come_from_except ::= _come_froms opt_come_from_except ::= come_from_except_clauses - come_froms ::= COME_FROM* come_from_except_clauses ::= COME_FROM_EXCEPT_CLAUSE+ come_from_loops ::= COME_FROM_LOOP* """ @@ -332,7 +331,7 @@ def p_stmt3(self, args): return_closure ::= LOAD_CLOSURE RETURN_VALUE RETURN_LAST stmt ::= whileTruestmt - ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite _come_from + ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite _come_froms """ def p_loop_stmt3(self, args): diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index 3f6a52f1a..6d521a232 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -23,7 +23,7 @@ def p_30(self, args): # In many ways Python 3.0 code generation is more like Python 2.6 than # it is 2.7 or 3.1. So we have a number of 2.6ish (and before) rules below - _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms POP_TOP COME_FROM + _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_froms POP_TOP COME_FROM jmp_true ::= JUMP_IF_TRUE POP_TOP jmp_false ::= JUMP_IF_FALSE POP_TOP diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index 25925b549..44b2a3dbc 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -43,7 +43,7 @@ def p_32to35(self, args): # JUMP_FORWARD in some cases, and hence we also don't # see COME_FROM _ifstmts_jump ::= c_stmts_opt - _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_from + _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_froms stmt ::= del_deref_stmt del_deref_stmt ::= DELETE_DEREF diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index bf9c128d1..913a3954a 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -1041,14 +1041,17 @@ def find_jump_targets(self, debug): elif not (code[label] == self.opc.POP_TOP and code[self.prev[label]] == self.opc.RETURN_VALUE): # In Python < 2.7, don't add a COME_FROM, for: - # RETURN_VALUE POP_TOP .. END_FINALLY + # ~RETURN_VALUE POP_TOP .. END_FINALLY # or: - # RETURN_VALUE POP_TOP .. POP_TOP END_FINALLY - skip_come_from = False - if self.version <= 2.6: - skip_come_from = (code[offset+3] == self.opc.END_FINALLY or - (code[offset+3] == self.opc.POP_TOP - and code[offset+4] == self.opc.END_FINALLY)) + # ~RETURN_VALUE POP_TOP .. POP_TOP END_FINALLY + skip_come_from = (code[offset+3] == self.opc.END_FINALLY or + (code[offset+3] == self.opc.POP_TOP + and code[offset+4] == self.opc.END_FINALLY)) + + # The below is for special try/else handling + if skip_come_from and op == self.opc.JUMP_FORWARD: + skip_come_from = False + if not skip_come_from: # FIXME: rocky: I think we need something like this... if offset not in set(self.ignore_if): From 72e2d1a2bf26931009e1c872758595008b0e07fc Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 3 Dec 2017 05:19:20 -0500 Subject: [PATCH 093/489] One more _come_from -> _come_froms --- test/simple_source/looping/12_if_while_bug.py | 6 +++--- uncompyle6/parsers/parse27.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/simple_source/looping/12_if_while_bug.py b/test/simple_source/looping/12_if_while_bug.py index e13ed1a5e..c3f745c48 100644 --- a/test/simple_source/looping/12_if_while_bug.py +++ b/test/simple_source/looping/12_if_while_bug.py @@ -3,11 +3,11 @@ # end of if can come from both finishing loop # and not taking the if. -# whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK \e__come_from +# whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK \e__come_froms # _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD \e__come_from # ifstmt ::= testexpr _ifstmts_jump -# _come_from ::= _come_from COME_FROM -# _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_from +# _come_froms ::= _come_froms COME_FROM +# _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD _come_froms def splitext(p, sep, altsep, extsep): if altsep > extsep: diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index ec8059ce7..3f72e436a 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -97,7 +97,7 @@ def p_stmt27(self, args): # assert condition, expr assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 - for_block ::= return_stmts _come_from + for_block ::= return_stmts _come_froms withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH From 13ab06ecb1d3dab2d0559b5969dc3ba4c6756140 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 3 Dec 2017 06:10:37 -0500 Subject: [PATCH 094/489] Fix bug in 2.6- except_cond3 --- test/bytecode_2.4/02_except_as.pyc | Bin 0 -> 309 bytes test/bytecode_2.5/02_except_as.pyc | Bin 277 -> 291 bytes test/bytecode_2.6/02_except_as.pyc | Bin 277 -> 291 bytes test/bytecode_2.7/02_except_as.pyc | Bin 273 -> 287 bytes test/simple_source/bug26/02_except_as.py | 14 ++++++++++---- test/stdlib/runtests.sh | 4 +--- uncompyle6/semantics/pysource.py | 5 +++++ 7 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 test/bytecode_2.4/02_except_as.pyc diff --git a/test/bytecode_2.4/02_except_as.pyc b/test/bytecode_2.4/02_except_as.pyc new file mode 100644 index 0000000000000000000000000000000000000000..795b6ca80b252308de9dccb3a1b8097e4cfe76e5 GIT binary patch literal 309 zcmYL?zfQw25XQfYU5YG_x)h0}16?vv)PWTi7LXXi05V8XnjWaAiKE0pWG#=$Tkr%u z8zd~^t3@2a0;bMig6CH~$>^0h?wEEo*dfCV1wTWBV{8@L&WUKDHsE7TxPzzVFf zQ>f2Cnn!VPDuebw`V?Hg2s=WZfS%Tbhcpp?uLQ5o-KXR53%5UtZO{HlRMyviQ}IpP zy4I5vipW)D=?|rH$HRY{)3Bcf%PcA#R4~rMb}I1;KNr<)s%Fc1=lZtf#j1Z>UM?<{ bIe(Vi_`K-On;{;$nucK`P-OI}n$U#yya+Sa literal 0 HcmV?d00001 diff --git a/test/bytecode_2.5/02_except_as.pyc b/test/bytecode_2.5/02_except_as.pyc index c2a383f80f2c903ae03204600e7126f8636884bb..cee4913d2dfca87561574a3edb3fe7cb95d8c89c 100644 GIT binary patch delta 187 zcmXYpF$%&!6hvosHwp_vL?YNIXp>`DTi94cRvS&$!Xhb>#!85_MG8+~Y3Xsig(vVQ zIPl+Rm|-63sjlzuz>Yr)m*THL{!*^o2`&~H;D97w!Fb|qQA|PZHJpMI8qh0v4R26u zzDhzz9?f)Y{C*(8S1)$Hc%Gk;1|dtN}8; ygc(Sr<>zNIGBEHlWHJGHnIIuQ4VH`DTi94cRvS&$!Xhb>#!85_MG8+~>1nLJg(vVQ zIPl+Rm|-63sjlzuz>Yr)m*THL{!*^o2`&~H;D97w!Fb|qQA|PZHJpMI8qh0v4R26u zzDhzz9?f)Y{C*(8S1)$Hc%Gk;1|dtN}8; ygc(Sr<>zNIGBEHlWHJGHnIIuQ4VHcTpSK0D!CX^7#N}$7{c@17+6vn8M3(;icA<7 zW0)DDm>8mfBnty$DicF0Geas1LlZMYo;*+)D_B_&17j2$P?iy7L^C5p6C*<&BSScTKfqfpSb>Id=xeC}svmph}>=W=4i4Mut2_hKLjvhF}el$tBD{ uA}v2ZlMzT~GBI!gNsy4A2Ft`&`H9=YgoS{-VxTYsGb0xxFEc+QKO+FiwHST? diff --git a/test/simple_source/bug26/02_except_as.py b/test/simple_source/bug26/02_except_as.py index 1b2e7539d..96077828f 100644 --- a/test/simple_source/bug26/02_except_as.py +++ b/test/simple_source/bug26/02_except_as.py @@ -1,6 +1,9 @@ # From 2.6.9 ConfigParser.py -# Note this can only be compiled in Python 2.x -# +# Note: this can only be compiled in Python 2.x +# Note also name "except_as" is a little bit of +# a misnomer since this is 2.7+ lingo for +# 2.6- syntax which we use here. + # Bug was being able to handle: # except KeyError, e # vs 2.6+. @@ -17,9 +20,12 @@ try: value = "foo" -except RuntimeError: + +# Test ensuring parens around (a, b, c) in +# except_cond2 or except_cond3 +except RuntimeError, (a, b, c): # Test: # raise_stmt3 ::= expr expr expr RAISE_VARARGS_3 - raise 1, 2, 3 + raise a, b, c except KeyError, e: raise RuntimeError('foo') diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index d78129911..577ec67a0 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -12,10 +12,8 @@ typeset -A SKIP_TESTS case $PYVERSION in 2.4) SKIP_TESTS=( [test_binop.py]=1 # need to fix tryelse - [test_bool.py]=1 # need to fix tryelse - [test_call.py]=1 # need to fix tryelse [test_cgi.py]=1 # need to fix tryelse - [test_class.py]=1 # need to fix tryelse + [test_codecs.py]=1 # need to fix tryelse [test_dis.py]=1 # We change line numbers - duh! ) ;; diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 44fdc7101..51b5f693e 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -353,6 +353,7 @@ def customize_for_version(self, is_pypy, version): 'testtrue_then': ( 'not %p', (0, 22) ), }) + if 2.4 <= version <= 2.6: TABLE_DIRECT.update({ 'comp_for': ( ' for %c in %c', 3, 1 ), @@ -1901,6 +1902,10 @@ def n_except_cond2(self, node): node[-2][0].kind = 'unpack_w_parens' self.default(node) + # except_cond3 is only in Python <= 2.6 + n_except_cond3 = n_except_cond2 + + def template_engine(self, entry, startnode): """The format template interpetation engine. See the comment at the beginning of this module for the how we interpret format From 25329d2752976bb092a4deb4c8b884288e1a6b2b Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 3 Dec 2017 11:20:06 -0500 Subject: [PATCH 095/489] Update runtest failures --- test/stdlib/runtests.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 577ec67a0..6f4cab14f 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -14,9 +14,38 @@ case $PYVERSION in SKIP_TESTS=( [test_binop.py]=1 # need to fix tryelse [test_cgi.py]=1 # need to fix tryelse [test_codecs.py]=1 # need to fix tryelse + [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! + [test_extcall.py]=1 # TypeError: saboteur() takes no arguments (1 given) + [test_format.py]=1 # Control flow? + [test_grp.py]=1 # Long test - might work Control flow? + [test_import.py]=1 # Control flow? + [test_long_future.py]=1 # Control flow? + [test_math.py]=1 # Control flow? + [test_pwd.py]=1 # Long test - might work? Control flow? + [test_queue.py]=1 # Control flow? + [test_sax.py]=1 # Control flow? + # [test_threading.py]=1 # Long test - works + [test_types.py]=1 # Control flow? ) ;; + 2.5) + SKIP_TESTS=( + [test_cgi.py]=1 # need to fix tryelse + [test_codecs.py]=1 # need to fix tryelse + [test_decorators.py]=1 # Syntax error decorators? + [test_dis.py]=1 # We change line numbers - duh! + [test_extcall.py]=1 # TypeError: saboteur() takes no arguments (1 given) + [test_format.py]=1 # Control flow? + [test_grp.py]=1 # Long test - might work Control flow? + [test_long_future.py]=1 # Control flow? + [test_math.py]=1 # Control flow? + [test_pwd.py]=1 # Long test - might work? Control flow? + [test_queue.py]=1 # Control flow? + [test_sax.py]=1 # Control flow? + [test_types.py]=1 # Control flow? + ) + ;; 2.6) SKIP_TESTS=( [test_array.py]=1 [test_asyncore.py]=1) ;; From fff0d1c98890d6448f3f523d402500fc23576695 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 3 Dec 2017 20:22:29 -0500 Subject: [PATCH 096/489] Include weird 2.6 bugs in 2.5 --- test/bytecode_2.5/03_weird26.pyc | Bin 0 -> 533 bytes test/simple_source/bug26/03_weird26.py | 2 ++ test/stdlib/runtests.sh | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/bytecode_2.5/03_weird26.pyc diff --git a/test/bytecode_2.5/03_weird26.pyc b/test/bytecode_2.5/03_weird26.pyc new file mode 100644 index 0000000000000000000000000000000000000000..851bcd80193e98b2f634e15d696e3b279a4fd9dd GIT binary patch literal 533 zcma)3!Ab&A6g}@bY8oyIF=!XGmTZ_L$I5Jm&41h2!;46FORUo0S9E%+iLa-h>mQEtG`QHmO_VZ znJA*~?$KLN7SIAY!c-BYvITQ`MOZhn0Y+zdR@m56)FKKCl>?M4y;q9{{T6IIaFf0( zB7fRFmnB?L&jjktOmOs1ysxb$1?M)PvKGC|_C+V%J;Epe*j zo6xM|q+66vM6QHD Date: Mon, 4 Dec 2017 14:18:39 -0500 Subject: [PATCH 097/489] Make 2.4 compatible --- pytest/test_grammar.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 138a5d33d..45a959924 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -57,9 +57,9 @@ def check_tokens(tokens, opcode_set): expect_dup_rhs = frozenset([('COME_FROM',), ('CONTINUE',), ('JUMP_ABSOLUTE',), ('LOAD_CONST',), ('JUMP_BACK',), ('JUMP_FORWARD',)]) - reduced_dup_rhs = {k: dup_rhs[k] for k in dup_rhs if k not in expect_dup_rhs} - for k in reduced_dup_rhs: - print(k, reduced_dup_rhs[k]) + # reduced_dup_rhs = {k: dup_rhs[k] for k in dup_rhs if k not in expect_dup_rhs} + # for k in reduced_dup_rhs: + # print(k, reduced_dup_rhs[k]) # assert not reduced_dup_rhs, reduced_dup_rhs s = get_scanner(PYTHON_VERSION, IS_PYPY) From f07c9c6dcf53bee444e5acd36f42e4d7c5a7933f Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 5 Dec 2017 08:32:31 -0500 Subject: [PATCH 098/489] Merge branch 'master' into python-2.4 --- test/bytecode_2.1/02_def.pyc | Bin 0 -> 950 bytes test/bytecode_2.2/02_def.pyc | Bin 0 -> 950 bytes test/bytecode_2.3/02_def.pyc | Bin 802 -> 963 bytes test/bytecode_2.4/02_def.pyc | Bin 642 -> 754 bytes test/bytecode_2.5/02_def.pyc | Bin 759 -> 893 bytes test/bytecode_2.6/02_def.pyc | Bin 759 -> 893 bytes test/bytecode_2.7/02_def.pyc | Bin 0 -> 893 bytes test/bytecode_3.2/02_def.pyc | Bin 810 -> 945 bytes test/bytecode_3.3/02_def.pyc | Bin 864 -> 1016 bytes test/bytecode_3.4/02_def.pyc | Bin 626 -> 733 bytes test/bytecode_3.5/02_def.pyc | Bin 628 -> 733 bytes test/simple_source/def/02_def.py | 6 ++++++ uncompyle6/parsers/parse26.py | 2 +- uncompyle6/semantics/make_function.py | 3 +-- 14 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 test/bytecode_2.1/02_def.pyc create mode 100644 test/bytecode_2.2/02_def.pyc create mode 100644 test/bytecode_2.7/02_def.pyc diff --git a/test/bytecode_2.1/02_def.pyc b/test/bytecode_2.1/02_def.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51bfe0948516892522823a5098182ac020b865ba GIT binary patch literal 950 zcmcJNJ#WG=5QbmJfrgKUg-+co)S*CN?>}H+saOz=gM|8pFsSWNd12^(?VsrDO9Kk+ zP^30a?tG5#9-r?nKThj!?-!F4d;)&7XQqZt-EaE3+kv-^>>#yQm*>BN^&*G)zFswbFb1;u}?yM#psn{BuAXq Scjz@6+uwgnH^Y|ZsD1)gk)PcF literal 0 HcmV?d00001 diff --git a/test/bytecode_2.2/02_def.pyc b/test/bytecode_2.2/02_def.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccd6f1cb59d84051a44a8a89d551c31244fb6c8a GIT binary patch literal 950 zcmcJN&rZTX5XQgl7AzFY1y9}$7X=D;-++r3!-ZfM65>C?LezuV3kP4;cktV33Q|p! zM7!*4|0XD#h^AJYKT){;!0gT2*VHCi{5{43L zxJ1H=gdtoDrYeaQm?K=ZBNi8wf`+Yo6ic!m_)#$&wrNl@_LT4J{C;sa9oxtCGMjeH zbk^ynW4epQi}gSL+*Oc?R+)ky1%dxTe2L&;)|<%=_B&25EI9KD^GmP@uJ(tpG%8@3 zrl6gu7_RY!qqm|&+Kt%kP=Wn;%M66cSdJ=zYyJ~+kZhTd!y_}H8g`I75$3lC7;?$& zld%U#tTAP_e#j=P)zY>K>abn)dzUv-?s~aPbJx$^!0zRL%GzJo-K$Z~A}a6kA3M%> R=p`H5?|)M_!lve^egGf2pW*-j literal 0 HcmV?d00001 diff --git a/test/bytecode_2.3/02_def.pyc b/test/bytecode_2.3/02_def.pyc index 8480c67f198cf94727442775b50b987a7d50a5c4..ba1a28764adc8e2cbe32728a75330f53ba9b7082 100644 GIT binary patch delta 197 zcmZ3)c9>n-`V%i#ZHHP^G6NJa0ci&yE_R+MZNt;Tz!1gCkiyOotiiD{%8bbztd0>V z55nFcbsRtN_+J+}sgB{3*NKRhQsIakzmx%R^K diff --git a/test/bytecode_2.4/02_def.pyc b/test/bytecode_2.4/02_def.pyc index 1e44dda520b0581f3f664997bbbf4999793cb510..ed8fbab09174c1bf222ae231bf2470b82dde06d0 100644 GIT binary patch delta 179 zcmZo-{lqGr`-zvUwnHr{nE?uzfV2Y;7duasw&7`EV2EO6NMUCP*5KF}b(E0}td4Q= zX-0(vMxd$^79f#bo>HsOk8f-u+2&6ZN k8AN~#2x12j93X-VNI;ZuO?F^1;{)+InK@Z_n1PTD0IA0r0{{R3 delta 94 zcmeyw+QcfI`-zw9eRE}4G6NJa0ci&yF1DH|ZNnU_!M-v1D5IjE1}ji3h!I3Eg9sK7 b!44ugfP@C?NWT>uU! diff --git a/test/bytecode_2.5/02_def.pyc b/test/bytecode_2.5/02_def.pyc index cd98701ca37892b2a4013d8e962efb3fa91f52fe..fcd3d2e78af24895ba121c2deeaa161ee7ecc16a 100644 GIT binary patch delta 138 zcmey)`j<_5^Cw=e+77j-WCkc;0@4mZTivfgy^OA%&eGSc79@lpzxvSRLbJ z872i@Mxd$^79f#bo>Dy7pGjMq6Ua#`%}Y)!DJd!z0T}`^je*fmgKcsjlMGW3=frxW V$v2sV__%<=oXngoJj_7I1^{Jq83q6V delta 81 zcmey%_MKIF^Cw=e+_ysE$qZ1y1f(5+xY%livfgy^OA%&eGSc79@lpzxvSRLbJ z872i@Mxd$^79f#bo>Dy7pGjMq6Ua#`%}Y)!DJd!z0T}`^je*fmgKcsjlMGW3=fryB V$+wsU`M7|>oXngoJj_7I1^{&*86^M! delta 81 zcmey%_MKJw;wN6N_sx}I$qZ1y1f(5+xY%lcAu%F#aJMW~u~Vs{rB$5>7}z@SfB6I4d*nkx zL^Mh6^7`Vt$M!{ioeVxcFH%G0)#LX)n|okqiS|S(3r~bcwntXc-lLQSKfY)sIuPxX z4P|mbwolU};yQJ8j|V91{GaO61d&O?j($0J&M~)KZ&%sOZHk@AhBjLaN8=g4F1PPF zR{AzVzJnysKv&jE!Gs)c-T)6{U18BBYZP~N98Fi~%_)kPePmhpu@x$P1n>FPx(>LQQx?UGndkY= yo$;WgPLhxZnvFEpp=DPR>tl$#1|#a<-zMUm+x5m4tLzTzbpv*>iv457clZtCFodxH literal 0 HcmV?d00001 diff --git a/test/bytecode_3.2/02_def.pyc b/test/bytecode_3.2/02_def.pyc index aab6b55b1888642e55042b25355a9a9128e56085..9677152a6ce1566bbaad6ff6aa5d528c97d6df4e 100644 GIT binary patch delta 266 zcmZ3*wvk;vhliJ|wnHr{nE?qf0oe{fT}e-vddG7 zH9#uBL@CTpX-=R}T4`Q#Vo6C+u?Ua@HOEhbZSqzoHKkG%1qc&RjM3%e0_x;s=49bv H20}Ifc%Lkc delta 189 zcmdnUzKTsghliKzeRE}4G6ND|0fS&&39!AB9C%ln( zlPwqn5Znp`Q*p8;Q#cZr--HijCdhCGMn4VK$$HFcVj3VGf+&UCA|uNIl(EUpPbtkw TwPOUbi$MaM%$zJd%sk8hR1O{e diff --git a/test/bytecode_3.3/02_def.pyc b/test/bytecode_3.3/02_def.pyc index 8d84c270848dc73eb6f1eb5bf35b1f10de2defe0..860db3c9b54f0a2a18b36874a1b7ccb2118d4670 100644 GIT binary patch delta 273 zcmaFB_Jdt{9uF^9ZHHRa4+aK?WFUqEW+2M}h>JrfDtq&%@G!J6FhsF3r0_BXYw%4h zv|*73N>0{iQk-}t2+p4D%NUN}oMw!Jaq3|V#mQHhgt_20F;329QkdM&$STePG%mY5 zrC0+MgKhF_CN(8gQG|J@hE8^7 S7Ubgsn!>}(!@|!Dglqt{s4xKl delta 172 zcmeyt{(wz+9uF@UYfNQW4Fdy1G7!T7Gmzx~#KoQymA#pRHFzf0+OWw21@!bMZ(vlM zcrOTvH#w9s9Ko$eFcl|JZZDtj{rYw~QY-Nwl5r^!0Gk4b9s TS|%kP4xlU#GY<JrfDtq&%@G!J6FhsF3r0_BXYw}Gj zG-j0ExV(vxD;cJNaq>+@Srf)vEZOBL#YK!jVFJZZDtj{rYw}F2HD;F8)8DwUiILe) alXY?*lhow3OiDZ)Kt(*vJS_ao{LBE)@(+6e diff --git a/test/simple_source/def/02_def.py b/test/simple_source/def/02_def.py index 003ad84aa..09f1a0020 100644 --- a/test/simple_source/def/02_def.py +++ b/test/simple_source/def/02_def.py @@ -13,3 +13,9 @@ def x3(a, b, c=5): def x4(a, b=5, **c): pass + +# Had a bug in 2.x where +# we weren't picking up **kwds when +# it was the sole parameter +def funcattrs(**kwds): + return diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 2d40747ce..c7e5ebc7a 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -39,7 +39,7 @@ def p_try_except26(self, args): except_handler tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK - except_handler else_suite COME_FROM + except_handler else_suite come_froms _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index f84562976..4a8cc630a 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -390,8 +390,7 @@ def build_param(ast, name, default): if code_has_star_star_arg(code): if argc > 0: self.write(', ') - if argc + kw_pairs > 0: - self.write('**%s' % code.co_varnames[argc + kw_pairs]) + self.write('**%s' % code.co_varnames[argc + kw_pairs]) if is_lambda: self.write(": ") From 0171e4d89935d8033b31ad2ee192939cbceabe6f Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 5 Dec 2017 18:21:15 -0500 Subject: [PATCH 099/489] remove from exclusion those stdlib test that now work --- test/stdlib/runtests.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 45f511324..045394ffc 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -17,7 +17,6 @@ case $PYVERSION in [test_codecs.py]=1 # need to fix tryelse [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! - [test_extcall.py]=1 # TypeError: saboteur() takes no arguments (1 given) [test_format.py]=1 # Control flow? [test_grp.py]=1 # Long test - might work Control flow? [test_import.py]=1 # Control flow? @@ -36,7 +35,6 @@ case $PYVERSION in [test_codecs.py]=1 # need to fix tryelse [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! - [test_extcall.py]=1 # TypeError: saboteur() takes no arguments (1 given) [test_format.py]=1 # Control flow? [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? From d756548ac3ff797e0d6370d43e3563780d170848 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 5 Dec 2017 22:44:33 -0500 Subject: [PATCH 100/489] Correct 10_del.py syntax --- test/bytecode_2.4/10_del.pyc | Bin 772 -> 782 bytes test/bytecode_2.5/10_del.pyc | Bin 823 -> 836 bytes test/simple_source/stmts/10_del.py | 3 +++ uncompyle6/bin/uncompile.py | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/bytecode_2.4/10_del.pyc b/test/bytecode_2.4/10_del.pyc index 95de87ec2fb1df8dfb45e0d5e9a5a475e37fe2b2..3be5d53bea85fc846f5a9dee1247db70082428c3 100644 GIT binary patch delta 148 zcmZo+>tmD7{lv@lFikxwnE?vefwTh<7q6NqJ&QGifgzD&;+EqQj6fj}b_Pj_0f`hw zhFS)Oq{)*Ra~PE-G0ACzWP?D21`tDtAZCylh${!g#T+0OBO4>bWFICCM$XBlOh!yW TY?GHTIWWpie##`z#Kr^wOa~V9 delta 140 zcmeBUYhjbl{lv>P*-$wunE?vefwTh<7cZG8J!|6bV-ie24kHjdg9OEZL<%EAEdxW{ z=~=893=D}J6So|dWCRLl3(NHJ|Br6BR#cUuJBOBA?3MO?% a&dCdyjF^I0CZA{WV3eCI!7R_j#smN~7Z^MM delta 152 zcmX@Yww+CS^Cw=e$%e{N$qZ1y4x}A`xOmA#=~)wZA7Nyg+`uTtRL3}Z24kz7JV=HG zNH8!nGiiWm4JIHF#0Vl-Cf{c=6bb@~$^daO8;Hfo#yGi-Nu7~n@-il)$#go%)E^3Ork&*7n3xj023P{Co2GU1Qy2t diff --git a/test/simple_source/stmts/10_del.py b/test/simple_source/stmts/10_del.py index 45cf9b5a7..338c41249 100644 --- a/test/simple_source/stmts/10_del.py +++ b/test/simple_source/stmts/10_del.py @@ -25,8 +25,11 @@ def foo(): global e del e +z = {} + def a(): b =1 + global z del z def b(y): global z diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 9636e0da6..b2c417652 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -83,7 +83,7 @@ def main_bin(): opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:', 'help asm grammar linemaps recurse timestamp tree ' 'verify version showgrammar'.split(' ')) - except getopt.GetoptError(e): + except getopt.GetoptError, e: sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e)) sys.exit(-1) From 3c67c7b32c96730183fb127de645c6336d3c90b6 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 10 Dec 2017 18:10:51 -0500 Subject: [PATCH 101/489] Administrivia --- admin-tools/how-to-make-a-release.md | 1 - 1 file changed, 1 deletion(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index 2eec4d6ff..3a316ede1 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -55,7 +55,6 @@ # Check against all versions $ source admin-tools/check-older-versions.sh - $ source admin-tools/check-newer-versions.sh # Make packages and tag From f432f4f6985a982de6797fb5e3d4d06266d6d1d4 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Dec 2017 09:24:59 -0500 Subject: [PATCH 102/489] Update runtest failures --- test/bytecode_2.4/01_triple_compare.pyc | Bin 0 -> 417 bytes test/stdlib/runtests.sh | 9 +++++++++ 2 files changed, 9 insertions(+) create mode 100644 test/bytecode_2.4/01_triple_compare.pyc diff --git a/test/bytecode_2.4/01_triple_compare.pyc b/test/bytecode_2.4/01_triple_compare.pyc new file mode 100644 index 0000000000000000000000000000000000000000..387fb31a84f995755e816f5010d7af3317306076 GIT binary patch literal 417 zcmZvXv2MaJ5QfhQB{UKPGcVw&5HT?ULh8s6HWn)+rZOcYiVaewj(rVYvQNN&1_dEu z={}$DKi_Yc|NZ!qB%7S>E5trW*aATO5p9qN(tW z)VF7~+p407Xf1m%$_2o|_Dh5v0&xAMm#%BcjVl9?i2=!%T?8DpD>M7;3n|VdTR2Xw zDeHq)wmLPr9&JxwlgVhDDAyP+=T%u}jsB>A+yKqWSar@0rcn2>U7ir|MB&(S>^b$! kJa?W8&(D?Q-jw0^pGxfvT-5D#Tz Date: Wed, 13 Dec 2017 10:02:30 -0500 Subject: [PATCH 103/489] Update docs and failed decompiles (for 2.5) --- HOW-TO-REPORT-A-BUG.md | 49 ++++++++++++++++++++++++++--------------- README.rst | 14 +++++++----- test/stdlib/runtests.sh | 2 ++ 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/HOW-TO-REPORT-A-BUG.md b/HOW-TO-REPORT-A-BUG.md index 8cf68d1d2..5e78ee134 100644 --- a/HOW-TO-REPORT-A-BUG.md +++ b/HOW-TO-REPORT-A-BUG.md @@ -10,23 +10,36 @@ decompile everything. Overall, I think this one probably does the best job of *any* Python decompiler that handles such a wide range of versions. -But at any given time, there are maybe dozens of valid Python bytecode -files that I know of that will cause problems. And when I get through -those and all the issues of decompiler bugs that are currently logged, -I could probably easily find dozens more bugs just by doing a -decompile of all the Python bytecode on any one of my -computers. Unless you want to help out by _fixing_ bugs, or are -willing to do work by isolating and narrowing bugs, don't feel you are -doing me a favor by doing scans on your favorite sets of bytecode -files. - -In sum, it is not uncommon that you will find a mistranslation in -decompiling. Furthermore, you may be expected to do some work in order -to have your bug worthy of being considered above other bugs. - -No one is getting paid to work to work on this project, let alone bugs -you may have an interest in. If you require decompiling bytecode -immediately, consider using a decompilation service. +But at any given time, there are a number of valid Python bytecode +files that I know of that will cause problems. See, for example, the +list in +[`test/stdlib/runtests.sh`](https://github.com/rocky/python-uncompyle6/blob/master/test/stdlib/runtests.sh). + +But I understand: you would the bugs _you_ encounter addressed before +all the other known bugs. + +From my standpoint, the good thing about the bugs listed in +`runtests.sh` is that each test case is small and isolated to a single +kind of problem. And I'll tend to fix easier, more isolated cases than +generic "something's wrong" kinds of bugs where I'd have to do a bit +of work to figure out what's up, if not use some sort of mind reading, +make some guesses, and perform some experiments to see if the guesses +are correct. I can't read minds, nor am I into guessing games; I'd +rather devote the effort spent instead towards fixing bugs that are +precisely defined. + +And it often turns out that by just fixing the well-defined and +prescribed cases, the ill-defined amorphous cases as well will get +handled as well. + +In sum, you may need to do some work to have the bug you have found +handled before the hundreds of other bugs, and things I could be +doing. + +No one is getting paid to work to work on this project, let alone the +bugs you may have an interest in. If you require decompiling bytecode +immediately, consider using a decompilation service, listed further +down in this document. ## Is it really a bug? @@ -114,7 +127,7 @@ Also try to narrow the bug. See below. Some kind folks also give the invocation they used and the output which usually includes an error message produced. This is helpful. From this, I can figure out what OS you are running this on -and what version of *uncomplye6* was used. Therefore, if you don't +and what version of *uncomplye6* was used. Therefore, if you _don't_ provide the input command and the output from that, please give: * _uncompyle6_ version used diff --git a/README.rst b/README.rst index df77d3c5a..685f83085 100644 --- a/README.rst +++ b/README.rst @@ -163,10 +163,9 @@ python 2.3-2.4 since a lot of the goodness of early the version of the decompiler from that era has been preserved (and Python compilation in that era was minimal) -Later distributions average about 200 files. There is some work to do -on the lower end Python versions which is more difficult for us to -handle since we don't have a Python interpreter for versions 1.5, 1.6, -and 2.0. +There is some work to do on the lower end Python versions which is +more difficult for us to handle since we don't have a Python +interpreter for versions 1.5, 1.6, and 2.0. In the Python 3 series, Python support is is strongest around 3.4 or 3.3 and drops off as you move further away from those versions. Python @@ -187,7 +186,11 @@ handled. We also don't handle PJOrion_ obfuscated code. For that try: PJOrion Deobfuscator_ to unscramble the bytecode to get valid bytecode before -trying this tool. +trying this tool. This program can't decompile Microsoft Windows EXE +files created by Py2EXE_, although we can probably decompile the code +after you extract the bytecode properly. For situations like this, you +might want to consider a decompilation service like [Crazy +Compilers](http://www.crazy-compilers.com/decompyle/). Handling pathologically long lists of expressions or statements is slow. @@ -219,3 +222,4 @@ See Also :target: https://travis-ci.org/rocky/python-uncompyle6 .. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84 .. _Deobfuscator: https://github.com/extremecoders-re/PjOrion-Deobfuscator +.. _Py2EXE: https://en.wikipedia.org/wiki/Py2exe diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 180082a69..4c00e276b 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -40,8 +40,10 @@ case $PYVERSION in [test_contextlib.py]=1 [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! + [test_exceptions.py]=1 [test_format.py]=1 # Control flow? [test_frozen.py]=1 + [test_functools.py]=1 [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? [test_imp.py]=1 From a37f403410f54711be49be9332178182f0ec44a3 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Dec 2017 17:44:19 -0500 Subject: [PATCH 104/489] Fix runtests.sh --- test/stdlib/runtests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index c36d8b27b..5199494ba 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -6,9 +6,6 @@ FULLVERSION=$(pyenv local) PYVERSION=${FULLVERSION%.*} MINOR=${FULLVERSION##?.?.} -# DECOMPILER=uncompyle2 -DECOMPILER="$fulldir/../../bin/uncompyle6" - typeset -i STOP_ONERROR=1 typeset -A SKIP_TESTS @@ -130,6 +127,9 @@ esac srcdir=$(dirname $me) cd $srcdir fulldir=$(pwd) + +# DECOMPILER=uncompyle2 +DECOMPILER="$fulldir/../../bin/uncompyle6" TESTDIR=/tmp/test${PYVERSION} if [[ -e $TESTDIR ]] ; then rm -fr $TESTDIR From c702ce38029689c58a0f4f9fc46a4f97cd04d789 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Dec 2017 18:06:56 -0500 Subject: [PATCH 105/489] runtests for 2.4 and 2.5 --- test/stdlib/runtests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 5199494ba..64ce55adf 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -55,6 +55,7 @@ case $PYVERSION in [test_sax.py]=1 # Control flow? [test_trace.py]=1 # Line numbers are expected to be different [test_types.py]=1 # Control flow? + [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) ;; 2.6) From 1856e09a0c8faa32970d82fb7bb55218b02e802c Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 Dec 2017 08:45:13 -0500 Subject: [PATCH 106/489] 2.4 tolerance --- uncompyle6/parsers/parse36.py | 4 ++-- uncompyle6/scanners/scanner36.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 6dfc06249..2053c563b 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -128,9 +128,9 @@ def custom_classfunc_rule(self, opname, token, customize, if opname.startswith('CALL_FUNCTION_KW'): self.addRule("expr ::= call_kw", nop_func) values = 'expr ' * token.attr - rule = 'call_kw ::= expr kwargs_36 {token.kind}'.format(**locals()) + rule = 'call_kw ::= expr kwargs_36 %s' % token.kind self.addRule(rule, nop_func) - rule = 'kwargs_36 ::= {values} LOAD_CONST'.format(**locals()) + rule = 'kwargs_36 ::= %s LOAD_CONST' % values self.add_unique_rule(rule, token.kind, token.attr, customize) elif opname == 'CALL_FUNCTION_EX_KW': self.addRule("""expr ::= call_ex_kw diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index f067309c1..d16c97008 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -11,8 +11,6 @@ from uncompyle6.scanners.scanner3 import Scanner3 -import xdis - # bytecode verification, verify(), uses JUMP_OPS from here from xdis.opcodes import opcode_36 as opc JUMP_OPS = opc.JUMP_OPS @@ -32,7 +30,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): t.kind = 'CALL_FUNCTION_EX_KW' pass elif t.op == self.opc.CALL_FUNCTION_KW: - t.kind = 'CALL_FUNCTION_KW_{t.attr}'.format(**locals()) + t.kind = 'CALL_FUNCTION_KW_%s' % t.attr elif t.op == self.opc.BUILD_MAP_UNPACK_WITH_CALL: t.kind = 'BUILD_MAP_UNPACK_WITH_CALL_%d' % t.attr pass From 63050232197aaa0c1087025c51a14cd7244100b4 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 Dec 2017 19:20:57 -0500 Subject: [PATCH 107/489] Handl 2.4- try/finally properly --- test/bytecode_2.4/02_try_except_finally.pyc | Bin 0 -> 245 bytes .../bug22/02_try_except_finally.py | 17 +++++++++++ test/stdlib/runtests.sh | 1 - uncompyle6/semantics/pysource.py | 27 ++++++++++-------- 4 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 test/bytecode_2.4/02_try_except_finally.pyc create mode 100644 test/simple_source/bug22/02_try_except_finally.py diff --git a/test/bytecode_2.4/02_try_except_finally.pyc b/test/bytecode_2.4/02_try_except_finally.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f113093f744323f40f8b79f0fae6db3d83d6c65e GIT binary patch literal 245 zcmXYp!EVAp3`EBXRSKmjQu`4Rt)PSpH+td9Aw7V&L^Ro=Mad>?9Mts6AM*wEA}o3Q zYHw%%!F}e^6$bk!CN7$Gb^puC=0962zG9GBV$qBjV9=1YX zk?#_m%--U)CV|_DdqV2GFZfa5)M{pJ4m^}4X$|XAt*otV as @@ -1029,15 +1041,6 @@ def n_delete_subscr(self, node): n_store_subscr = n_subscript = n_delete_subscr -# 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-', 1, 5 ), - def n_tryfinallystmt(self, node): - if len(node[1][0]) == 1 and node[1][0][0] == 'stmt': - if node[1][0][0][0] == 'try_except': - node[1][0][0][0].kind = 'tf_try_except' - if node[1][0][0][0] == 'tryelsestmt': - node[1][0][0][0].kind = 'tf_tryelsestmt' - self.default(node) - def n_exec_stmt(self, node): """ exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT From e5f06eb5517fe836127bd6860c20a3af7623afb8 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 6 Jan 2018 22:10:05 -0500 Subject: [PATCH 108/489] Fix bug 2.5- in try/else inside ifelsestmt --- test/bytecode_2.4_run/03_try_else.pyc | Bin 0 -> 510 bytes test/bytecode_2.5_run/03_try_else.pyc | Bin 0 -> 536 bytes test/simple_source/bug25/03_try_else.py | 18 ++++++++++++++++++ test/stdlib/runtests.sh | 4 ---- uncompyle6/parsers/parse24.py | 1 - uncompyle6/parsers/parse25.py | 6 ++++++ uncompyle6/scanners/scanner2.py | 2 +- uncompyle6/scanners/scanner26.py | 2 +- uncompyle6/scanners/scanner3.py | 2 +- 9 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 test/bytecode_2.4_run/03_try_else.pyc create mode 100644 test/bytecode_2.5_run/03_try_else.pyc create mode 100644 test/simple_source/bug25/03_try_else.py diff --git a/test/bytecode_2.4_run/03_try_else.pyc b/test/bytecode_2.4_run/03_try_else.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58ce4945418f847eb9a6214f936e0f00c3c0be80 GIT binary patch literal 510 zcmX|8!AiqG5Pg%hRwF4WB6zDpu_r5v7cVMWyj4w$N-sg1MOWKw$!?TFy;RSBtY6^F zR$Q1jvorH%-X`OpINJWc84U4vLiVR@c9$UozJLJ-1jQKOlkgH?QUf`{oIqKKUaP{r zLt+Tns%+ldzy#YQ5c@re*P$v0w#i#2$GeA}q&gMM8G(xr{mAiZk702xn zObp_a)jT5r-Oq^kFY~4@cL0~2zGep}lCH0MeJ!%=IzySi=H@+bjFo#f*>R(3waC>% z^Dl5q94)FW1Sp0sVt4y6DpjW_OySn}I#7kV&~MsmllyE-dJ_+R6yMMia61fEk0&FQ zT2mH7)qX6W4vyOUhp8*3sTx_eH<`K`w`C@E$~yUWc7p*FQzRC|6mnFjRq}EZDRvh- hh3M)GXV$91{R@&OCsOn>JS6fq{$;?4-yw2W;$N2QQ`G?99BGxB2>x!mZEiVFJG=p!ImJ~4aT9W9HdIh{8R5>9k#M zSjBb~%bFaykm%+P1 Date: Sun, 7 Jan 2018 08:36:17 -0500 Subject: [PATCH 109/489] Fix another 2.5- try/else bug (in a loop) --- pytest/testdata/if-2.7.right | 4 ++-- pytest/testdata/ifelse-2.7.right | 4 ++-- test/bytecode_2.4_run/02_try_else_loop.pyc | Bin 0 -> 529 bytes test/bytecode_2.5_run/02_try_else_loop.pyc | Bin 0 -> 582 bytes test/simple_source/bug25/02_try_else_loop.py | 17 +++++++++++++++++ test/stdlib/runtests.sh | 4 ---- uncompyle6/parser.py | 1 + uncompyle6/parsers/parse24.py | 10 ++++++++++ uncompyle6/parsers/parse25.py | 5 +++++ uncompyle6/scanners/tok.py | 10 +++++++--- 10 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 test/bytecode_2.4_run/02_try_else_loop.pyc create mode 100644 test/bytecode_2.5_run/02_try_else_loop.pyc create mode 100644 test/simple_source/bug25/02_try_else_loop.py diff --git a/pytest/testdata/if-2.7.right b/pytest/testdata/if-2.7.right index 61eecf869..c6b7b9345 100644 --- a/pytest/testdata/if-2.7.right +++ b/pytest/testdata/if-2.7.right @@ -7,6 +7,6 @@ 7 6 LOAD_NAME 1 'False' 9 STORE_NAME 2 'b' 12 JUMP_FORWARD 0 'to 15' - 15_0 COME_FROM '12' + 15_0 COME_FROM 12 '12' 15 LOAD_CONST 0 '' - 18 RETURN_VALUE + 18 RETURN_VALUE diff --git a/pytest/testdata/ifelse-2.7.right b/pytest/testdata/ifelse-2.7.right index d6ee0b34b..2f381c643 100644 --- a/pytest/testdata/ifelse-2.7.right +++ b/pytest/testdata/ifelse-2.7.right @@ -10,6 +10,6 @@ 6 15 LOAD_CONST 1 2 18 STORE_NAME 2 'd' - 21_0 COME_FROM '12' + 21_0 COME_FROM 12 '12' 21 LOAD_CONST 2 '' - 24 RETURN_VALUE + 24 RETURN_VALUE diff --git a/test/bytecode_2.4_run/02_try_else_loop.pyc b/test/bytecode_2.4_run/02_try_else_loop.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fcd11b61343dc597fa6c1be81d1685f3e84e8cb2 GIT binary patch literal 529 zcmah`%Sr<=6g`>ggBGj>-{7Jyq_b*E!L^EyWf!ejDag>yq;;g7jL9u@pl+%^;m&XL z3%r?1aU%xq$ssxC27fA(z zatL!)yuWfF{$mVE1X`eM)ZJ%`NOOEoVN+pdXr7CMl8u9}b8`ATDl(uo^kOATt1>uUSsEE9? cw_zPGJJx>DFJ=u{7u^E0>@m)>C<~?SZZbY=?)(S; z%rEdxYU@hG3-`=P=G=2;l8?{T()C`a@8i1|ttZragMb6CKpzmm3&1!-*L7$km0M|v z`ixq?6Fj|v6x;#Nfafp*?o*Gu0?u!zcm|RR48xS%7-kH;a2;8C@lb*+fKi3pU^m7= zR0cETlC|QknFIFc=wtP_QQGOzRl07T4%wzWph<_DSF#|BRqqnpS2Z5+ux@H<5NJ`m zN+NNglvJ*jxmf~Zp)EsUibR$IlcT50!B`7ZCU&Z|P$rP!eA;Hyy@26>&#j0<*DVB- zXe>M}W95s+FdnrI8_kwyRN@J8^Ttv}2T@`wq%}et&zGS#D)x<3_Mhk-09Oi9*g5N(?W6W3yooF?f?J) literal 0 HcmV?d00001 diff --git a/test/simple_source/bug25/02_try_else_loop.py b/test/simple_source/bug25/02_try_else_loop.py new file mode 100644 index 000000000..ab3248f20 --- /dev/null +++ b/test/simple_source/bug25/02_try_else_loop.py @@ -0,0 +1,17 @@ +# From 2.4 test_binop.py bug is missing 'else:' in 2nd try. +def test_constructor(): + for bad in "0", 0.0, 0j, (), [], {}, None: + try: + raise TypeError(bad) + except TypeError: + pass + else: + assert False, "%r didn't raise TypeError" % bad + try: + raise TypeError(bad) + except TypeError: + pass + else: + assert False, "%r didn't raise TypeError" % bad + +test_constructor() diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 10f60c4bf..d268576a6 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -12,7 +12,6 @@ typeset -A SKIP_TESTS case $PYVERSION in 2.4) SKIP_TESTS=( - [test_binop.py]=1 # need to fix tryelse [test_codecs.py]=1 # need to fix tryelse [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! @@ -20,7 +19,6 @@ case $PYVERSION in [test_grp.py]=1 # Long test - might work Control flow? [test_imp.py]=1 # Control flow? [test_import.py]=1 # Control flow? - [test_long_future.py]=1 # Control flow? [test_math.py]=1 # Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? [test_queue.py]=1 # Control flow? @@ -31,7 +29,6 @@ case $PYVERSION in ;; 2.5) SKIP_TESTS=( - [test_binop.py]=1 # need to fix tryelse [test_codecs.py]=1 # need to fix tryelse [test_coercion.py]=1 [test_contextlib.py]=1 @@ -43,7 +40,6 @@ case $PYVERSION in [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? [test_imp.py]=1 - [test_long_future.py]=1 # Control flow? [test_math.py]=1 # Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? [test_queue.py]=1 # Control flow? diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 5b2e474cc..9c3057c85 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -261,6 +261,7 @@ def p_stmt(self, args): c_stmts_opt ::= c_stmts c_stmts_opt ::= pass + # statements inside a loop l_stmts ::= _stmts l_stmts ::= returns l_stmts ::= continues diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index e1ee78f9e..ec2a0a3fc 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -69,6 +69,7 @@ def customize_grammar_rules(self, tokens, customize): super(Python24Parser, self).customize_grammar_rules(tokens, customize) if self.version == 2.4: self.check_reduce['nop_stmt'] = 'tokens' + self.check_reduce['try_except'] = 'tokens' def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python24Parser, @@ -82,6 +83,15 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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 diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 461c713f6..9d7622f34 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -34,8 +34,13 @@ def p_misc25(self, args): store ::= STORE_NAME + # tryelsetmtl doesn't need COME_FROM since the jump might not + # be the the join point at the end of the "try" but instead back to the + # 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 diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index d750aabc0..5becc0914 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -34,14 +34,18 @@ def __init__(self, opname, attr=None, pattr=None, offset=-1, self.opc = opc def __eq__(self, o): - """ '==', but it's okay if offsets and linestarts are different""" + """ '==' on kind and "pattr" attributes. + It is okay if offsets and linestarts are different""" if isinstance(o, Token): - # Both are tokens: compare kind and attr - # It's okay if offsets are different return (self.kind == o.kind) and (self.pattr == o.pattr) else: + # ?? do we need this? return self.kind == o + def __ne__(self, o): + """ '!=', but it's okay if offsets and linestarts are different""" + return not self.__eq__(o) + def __repr__(self): return str(self.kind) From 772d36015ca38529c27eb37c90df36785c56bb41 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 8 Jan 2018 22:18:59 -0500 Subject: [PATCH 110/489] 2.4-compatiblity for next iteration --- uncompyle6/parsers/parse3.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 6fe880583..aed818faa 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2017 Rocky Bernstein +# Copyright (c) 2015-2018 Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -19,6 +19,7 @@ from uncompyle6.parsers.astnode import AST from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from xdis import PYTHON3 +from itertools import islice,chain,repeat class Python3Parser(PythonParser): @@ -1073,7 +1074,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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 From 97604a93dd0079ee21ac1a4136565d9e7b1b98ed Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 9 Jan 2018 00:28:04 -0500 Subject: [PATCH 111/489] Small typo --- admin-tools/how-to-make-a-release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index a91ece751..320fc44e1 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -55,7 +55,7 @@ $ . ./admin-tools/make-dist-older.sh $ git tag release-python-2.4-$VERSION - $ . /admin-tools/make-dist-newer.sh + $ . ./admin-tools/make-dist-newer.sh $ git tag release-$VERSION # Upload single package and look at Rst Formating From 49ef408699a8f10a0155ffe99e2ac7f55d867499 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 9 Jan 2018 08:48:57 -0500 Subject: [PATCH 112/489] Reinstates run tests that now work --- test/stdlib/runtests.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index e457a1d54..48d6ff767 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -12,13 +12,9 @@ typeset -A SKIP_TESTS case $PYVERSION in 2.4) SKIP_TESTS=( - [test_codecs.py]=1 # need to fix tryelse [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! - [test_frozen.py]=1 [test_grp.py]=1 # Long test - might work Control flow? - [test_imp.py]=1 # Control flow? - [test_import.py]=1 # Control flow? [test_math.py]=1 # Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? [test_queue.py]=1 # Control flow? @@ -29,17 +25,13 @@ case $PYVERSION in ;; 2.5) SKIP_TESTS=( - [test_codecs.py]=1 # need to fix tryelse - [test_coercion.py]=1 [test_contextlib.py]=1 [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! [test_exceptions.py]=1 - [test_frozen.py]=1 [test_functools.py]=1 [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? - [test_imp.py]=1 [test_math.py]=1 # Control flow? [test_pdb.py]=1 [test_pwd.py]=1 # Long test - might work? Control flow? From 992a08f5ce6c0a40f2a54b566aff238a15d1e657 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 10 Jan 2018 09:30:15 -0500 Subject: [PATCH 113/489] Check Python version in setup.py ... to make sure we are running a compatible version. --- setup.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/setup.py b/setup.py index 6845d3c7e..831844513 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,20 @@ #!/usr/bin/env python +import sys """Setup script for the 'uncompyle6' distribution.""" +SYS_VERSION = sys.version_info[0:2] +if not ((2, 6) <= SYS_VERSION <= (3, 7)) or ((3, 0) <= SYS_VERSION <= (3, 2)): + mess = "Python Release 2.6 .. 3.7 excluding 3.1 and 3.2 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." % + sys.version[0:3]) + elif SYS_VERSION < (2, 4) or ((3, 0) <= SYS_VERSION <= (3, 2)): + mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s." + % sys.version[0:3]) + print(mess) + raise Exception(mess) + from __pkginfo__ import \ author, author_email, install_requires, \ license, long_description, classifiers, \ From ed7d11525a44478d3142bdd8e0526677e6050660 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 10 Jan 2018 09:48:31 -0500 Subject: [PATCH 114/489] Check Python version in setup.py ... to make the code is compatible. Fixes #146 --- setup.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 831844513..6560eed2b 100755 --- a/setup.py +++ b/setup.py @@ -1,15 +1,15 @@ #!/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)) or ((3, 0) <= SYS_VERSION <= (3, 2)): - mess = "Python Release 2.6 .. 3.7 excluding 3.1 and 3.2 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) or ((3, 0) <= SYS_VERSION <= (3, 2)): + else: mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s." % sys.version[0:3]) print(mess) From 49a71819a1e50d05072a57cef38a2a4290bb7590 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 10 Jan 2018 11:02:54 -0500 Subject: [PATCH 115/489] Correct Python 2.5- decorator parsing --- test/bytecode_2.4/02_decorator.pyc | Bin 0 -> 467 bytes test/bytecode_2.5/02_decorator.pyc | Bin 0 -> 559 bytes test/simple_source/bug25/02_decorator.py | 9 +++++++++ test/stdlib/runtests.sh | 2 -- uncompyle6/parsers/parse25.py | 1 - 5 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 test/bytecode_2.4/02_decorator.pyc create mode 100644 test/bytecode_2.5/02_decorator.pyc create mode 100644 test/simple_source/bug25/02_decorator.py diff --git a/test/bytecode_2.4/02_decorator.pyc b/test/bytecode_2.4/02_decorator.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6dc34ed381508feace89a13e99dbb0a64ff4524 GIT binary patch literal 467 zcmZ8d!A`dj?Wg#B;c!DvInfW%l7SMSD353nUvWu8c#2m%=!FN17;F-A zB7q)-P4lh;1>TQ1xuV*YCUdr_wVAA&?Q}MInr6AtwqAK#k9VKG&$`M~w%8kVaS(ann za1_a)6g^V-l&kFROt}dZ)1g;rbH`V2oX^_z(6(JKx#$KuT!Cc5e?xFJ@BYqhbOimQ BI#d7v literal 0 HcmV?d00001 diff --git a/test/bytecode_2.5/02_decorator.pyc b/test/bytecode_2.5/02_decorator.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4653fe791147e796a4da930b037d35fe16692c3 GIT binary patch literal 559 zcmbVIJ!`{24Ar?GNlH7V^bch5l!QPtg;413!G;c5Ome3bgWU_hJ7`Kfwg0I9tZSD_ zvJ=uR#2{Igp7fsI_s`AM@APS*p?ws+A1K@%B?IsUu%JRop}<6t#b-3q4BW*dFPt|E zSDNG9l}*u+2RfP zii;?L5^gRzgu73L-^u(`@Igv}lrkXMOXaVO!gVRV3;edl6g)f7%>VFug5XQqGd8SB zWa*9GNNh;?qzDp29G2^pjXZ(mn$|ozpSRX9X=_a)48oOO{JSnZ#~LpV%_?g`iSxbl Gz32}Fu4Ezr literal 0 HcmV?d00001 diff --git a/test/simple_source/bug25/02_decorator.py b/test/simple_source/bug25/02_decorator.py new file mode 100644 index 000000000..9a6d88664 --- /dev/null +++ b/test/simple_source/bug25/02_decorator.py @@ -0,0 +1,9 @@ +# From python 2.5 make_decorators.py +# Bug was in not recognizing @memoize which uses grammra rules +# using nonterminals mkfuncdeco and mkfuncdeco0 +def memoize(func): + pass +def test_memoize(self): + @memoize + def double(x): + return x * 2 diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 48d6ff767..7d03f7202 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -12,7 +12,6 @@ typeset -A SKIP_TESTS case $PYVERSION in 2.4) SKIP_TESTS=( - [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! [test_grp.py]=1 # Long test - might work Control flow? [test_math.py]=1 # Control flow? @@ -26,7 +25,6 @@ case $PYVERSION in 2.5) SKIP_TESTS=( [test_contextlib.py]=1 - [test_decorators.py]=1 # Syntax error decorators? [test_dis.py]=1 # We change line numbers - duh! [test_exceptions.py]=1 [test_functools.py]=1 diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index cba2cdce0..afb30ff4b 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -74,7 +74,6 @@ def customize_grammar_rules(self, tokens, customize): classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS kv3 ::= expr expr STORE_MAP kvlist ::= kvlist kv3 - mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1 ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP From c4612b7484d9914b17e8062b09605171a8f5e444 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 12 Jan 2018 09:57:32 -0500 Subject: [PATCH 116/489] Fix ok status on --weak-verify --- uncompyle6/main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 4cf635e94..4d1a17159 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -192,6 +192,10 @@ def _get_outstream(outfile): okay_files += 1 else: print '\n# %s\n\t%s', infile, msg + pass + else: + okay_files += 1 + pass except verify.VerifyCmpError, e: print(e) verify_failed_files += 1 From 4fb379afb43860d56529a0caf1f0c88226ed7912 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 27 Jan 2018 12:26:22 -0500 Subject: [PATCH 117/489] Get ready for release 2.15.0 --- uncompyle6/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 2f0cbf981..5d1865b84 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.14.3' +VERSION='2.15.0' From d0dfdcfcdebe873e627e990b439bac842d796dcf Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 29 Jan 2018 15:41:19 -0500 Subject: [PATCH 118/489] Add Some run tests --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index df7ec163a..5a321cb56 100644 --- a/circle.yml +++ b/circle.yml @@ -11,4 +11,4 @@ dependencies: test: override: - python ./setup.py develop && make check-2.6 - - cd ./test/stdlib && pyenv local 2.5.9 && bash ./runtests.sh 'test_[p-z]*.py' + - cd ./test/stdlib && pyenv local 2.5.9 && bash ./runtests.sh 'test_[f-i]*.py' From 4ce769399fc7c90ddda2ce03517a385dde802f97 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 29 Jan 2018 15:44:34 -0500 Subject: [PATCH 119/489] Correct Python versions in CircleCI tests --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 5a321cb56..9afb77bf4 100644 --- a/circle.yml +++ b/circle.yml @@ -10,5 +10,5 @@ dependencies: - pip install pytest==3.2.5 hypothesis test: override: - - python ./setup.py develop && make check-2.6 - - cd ./test/stdlib && pyenv local 2.5.9 && bash ./runtests.sh 'test_[f-i]*.py' + - python ./setup.py develop && make check-2.7 + - cd ./test/stdlib && pyenv local 2.7.10 && bash ./runtests.sh 'test_[f-i]*.py' From ed3b0e81b9cb627b4b0aab3d4c6ec42be58e6486 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 31 Jan 2018 16:52:43 -0500 Subject: [PATCH 120/489] Remove schmutz from merge --- uncompyle6/bin/uncompile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 001b22aed..6f88f7e38 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -89,7 +89,6 @@ def main_bin(): 'showgrammar'.split(' ')) except getopt.GetoptError(e): sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e)) - print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr) sys.exit(-1) options = {} From 657d5ef024d0c0718ae32c878a5d45e9d731bb26 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 15 Feb 2018 07:33:51 -0500 Subject: [PATCH 121/489] pydisasm fixes --- uncompyle6/bin/pydisassemble.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uncompyle6/bin/pydisassemble.py b/uncompyle6/bin/pydisassemble.py index 8c51498b0..82465755c 100755 --- a/uncompyle6/bin/pydisassemble.py +++ b/uncompyle6/bin/pydisassemble.py @@ -12,8 +12,8 @@ __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 @@ -22,9 +22,9 @@ 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. @@ -32,7 +32,7 @@ -V | --version show version and stop -h | --help show this message -""" % (program, program) +""" % ((program,) * 5) PATTERNS = ('*.pyc', '*.pyo') From d2285f0d618abf40b91d30dbb237ad6f459a3081 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 21 Feb 2018 02:54:40 -0500 Subject: [PATCH 122/489] remove a 2.7 runtest.sh exception --- test/stdlib/runtests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index d74d248c4..4e821221f 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -77,7 +77,6 @@ case $PYVERSION in [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_io.py]=1 # Test takes too long to run [test_ioctl.py]=1 # Test takes too long to run - [test_itertools.py]=1 # Syntax error - look at! [test_memoryio.py]=1 # FIX [test_multiprocessing.py]=1 # On uncompyle2, taks 24 secs [test_pep352.py]=1 # ? From 158a1886fe5d18c0c5d100c74da5772b6b1c7b5e Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 21 Feb 2018 04:13:57 -0500 Subject: [PATCH 123/489] Fix 2.4/2.5 try/else detection bug... in a hacky way --- test/bytecode_2.4_run/03_try_else.pyc | Bin 510 -> 433 bytes test/simple_source/bug25/03_try_else.py | 29 ++++++++++++------------ test/stdlib/runtests.sh | 2 -- uncompyle6/parsers/parse24.py | 10 -------- uncompyle6/parsers/parse25.py | 17 ++++++++++++-- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/bytecode_2.4_run/03_try_else.pyc b/test/bytecode_2.4_run/03_try_else.pyc index 58ce4945418f847eb9a6214f936e0f00c3c0be80..23c616b8eadf8f77c7d5cb895b4e7afde34b0557 100644 GIT binary patch literal 433 zcmYLFJx{|x41G>gpn-x!2PPJ#EVSjTD@cg7Ly(~A5|#FVK=VP)krD|O%E}+$_wbAO z1^6x%ob;Z3_Vd}kLcm5=M@VJF1AK9i6)2p;eH$da2%yxC< z`B99a`o8xLk9vb(O#uSPj#M>MImcP5%`|#f p2;@>%;5)`{Q`@n>7MfJJF4SC&XJh}}L%Wt4>)fnlpKMdR^9$%ZMpys< literal 510 zcmX|8!AiqG5Pg%hRwF4WB6zDpu_r5v7cVMWyj4w$N-sg1MOWKw$!?TFy;RSBtY6^F zR$Q1jvorH%-X`OpINJWc84U4vLiVR@c9$UozJLJ-1jQKOlkgH?QUf`{oIqKKUaP{r zLt+Tns%+ldzy#YQ5c@re*P$v0w#i#2$GeA}q&gMM8G(xr{mAiZk702xn zObp_a)jT5r-Oq^kFY~4@cL0~2zGep}lCH0MeJ!%=IzySi=H@+bjFo#f*>R(3waC>% z^Dl5q94)FW1Sp0sVt4y6DpjW_OySn}I#7kV&~MsmllyE-dJ_+R6yMMia61fEk0&FQ zT2mH7)qX6W4vyOUhp8*3sTx_eH<`K`w`C@E$~yUWc7p*FQzRC|6mnFjRq}EZDRvh- hh3M)GXV$91{R@&OCsOn>JS6fq{$;?4-yw2W;$N2QQ`G Date: Wed, 21 Feb 2018 18:08:27 -0500 Subject: [PATCH 124/489] == -> is --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 14f60ef1b..1f51c2090 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2621,7 +2621,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False, assert iscode(co) - if version == None: + if version is None: version = float(sys.version[0:3]) # store final output stream for case of error From 16b5df4ba4a19df8f9298ccff7911886cdd009ef Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 22 Feb 2018 19:16:41 -0500 Subject: [PATCH 125/489] 2.4 test_types was fixed by prior commit --- test/stdlib/runtests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index c8a3d3353..a04ae0a9d 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -31,7 +31,6 @@ case $PYVERSION in [test_queue.py]=1 # Control flow? [test_sax.py]=1 # Control flow? # [test_threading.py]=1 # Long test - works - [test_types.py]=1 # Control flow? ) ;; 2.5) From b9147b7872859cc85d3d71eb0f41cac404c83a95 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 22 Feb 2018 20:24:21 -0500 Subject: [PATCH 126/489] Distingish 2.4-2.6 try from try/else --- test/bytecode_2.4_run/04_try_else_confuse.pyc | Bin 0 -> 466 bytes .../bug25/04_try_else_confuse.py | 19 ++++++++++++++++++ test/stdlib/runtests.sh | 7 ++----- 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 test/bytecode_2.4_run/04_try_else_confuse.pyc create mode 100644 test/simple_source/bug25/04_try_else_confuse.py diff --git a/test/bytecode_2.4_run/04_try_else_confuse.pyc b/test/bytecode_2.4_run/04_try_else_confuse.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6cbeef34f3a04019a895781811c377d0a9a09e9 GIT binary patch literal 466 zcmZ8eyH3ME5S+Ec%P2u05Tc@?uqX&ZPy+%gq!gh5rNDyZ5?vm)x!YK>lr%ukzw!m_ zIy@xK+S&8Y?B4i1`K(9#_M_9q_X;FmNcaPR9`FuyWJ55(8!!xzuYj2FN}yhVyEqhK z)vm2e5?2!bQ9!!pgt7tA^+N2-f%|k1H4ZS0kkvu5gp+z2fF8<7Wzw=xh5uBvP|biD zVfQYs$q_B9$6Hd6KviUA2F1&Wl^hf!-jv)iF1xmc^)^dyoXZ@qO7+&1)l01I+d8K$ zf%q5rP`2Jq^07&LHg#Roe4Y+Y&YH)k3A-{eV{ejfmiDLK9OWf%iM%k*_Jx|{TqaM< z&Z{H8twU* Date: Thu, 22 Feb 2018 22:23:57 -0500 Subject: [PATCH 127/489] yield before 2.4 may need "None" --- test/bytecode_2.4/02_yield_bug.pyc | Bin 0 -> 231 bytes test/simple_source/bug25/02_yield_bug.py | 7 +++++++ uncompyle6/semantics/pysource.py | 4 ++++ 3 files changed, 11 insertions(+) create mode 100644 test/bytecode_2.4/02_yield_bug.pyc create mode 100644 test/simple_source/bug25/02_yield_bug.py diff --git a/test/bytecode_2.4/02_yield_bug.pyc b/test/bytecode_2.4/02_yield_bug.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5e11c9cc0ebd0dff0de61a1575951a7455feecb GIT binary patch literal 231 zcmd1(#LFer*&mh600oRd+5w1*d4WU<149b~Llls~$Plc-1QbD02jUcSK-7f+)dp*T zbo+tH5*83MKQC1SNHZXa5@jH_I5W2(CpEq}zqBYhRX?dT-N;nmz$m^lGc_kA9>~=z ts4U?Gs)Gx#f;53lWME`rgjf&+at_!k2n!?$wk8PVh!PNC57q{f003*aA%Fk? literal 0 HcmV?d00001 diff --git a/test/simple_source/bug25/02_yield_bug.py b/test/simple_source/bug25/02_yield_bug.py new file mode 100644 index 000000000..bd60872dd --- /dev/null +++ b/test/simple_source/bug25/02_yield_bug.py @@ -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 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 32da230fc..0cd2fdcdf 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -951,6 +951,10 @@ def n_yield(self, node): if node != AST('yield', [NONE, Token('YIELD_VALUE')]): self.write(' ') self.preorder(node[0]) + elif self.version <= 2.4: + # Early versions of Python don't allow a plain "yield" + self.write(' None') + self.prune() # stop recursing # In Python 3.3+ only From e3d8751338fd78b764e393bae382beadb6f58ac4 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 27 Feb 2018 10:41:46 -0500 Subject: [PATCH 128/489] Sync with master + lint --- uncompyle6/main.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 22cb9b0f9..f50d69a18 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -12,11 +12,10 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from __future__ import print_function ->>>>>>> master -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 uncompyle6.disas import check_object_path from uncompyle6.semantics import pysource @@ -267,7 +266,7 @@ def main(in_base, out_base, files, codes, outfile=None, do_verify) if not current_outfile: if not msg: - print '\n# okay decompiling %s' % infile + print('\n# okay decompiling %s' % infile) okay_files += 1 else: verify_failed_files += 1 From 8a842c57d3a0444c3548cb3513e03d2c2505e32e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 1 Mar 2018 18:17:11 -0500 Subject: [PATCH 129/489] Omit empty parens in 2.4 --- uncompyle6/scanners/tok.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 2ae62435b..0a10ec0b1 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -21,7 +21,7 @@ if PYTHON3: intern = sys.intern -class Token(): +class Token: # Python 2.4 can't have empty () """ Class representing a byte-code instruction. From c91b5e1164f7055cb07fa917b34a3f39b742136e Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 7 Mar 2018 07:37:13 -0500 Subject: [PATCH 130/489] Need additional try vs try/else checks --- uncompyle6/parsers/parse26.py | 56 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 09ac34b66..cf0c45f44 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -369,8 +369,9 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # We need to distingush try_except from tryelsestmt and we do that # by making sure that the jump before the except handler jumps to # code somewhere before the end of the construct. - # This AST method is slower, but more correct than what we had - # which is given after this. + # This AST method is slower, but the token-only based approach + # didn't work as it failed with a "try" embedded inside a "try/else" + # since we can't detect COME_FROM boundaries. if ast[3] == 'except_handler': except_handler = ast[3] @@ -382,32 +383,31 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): last_offset = int(tokens[last].offset.split('_')[0]) return else_start >= last_offset - # Before we resorted to using the AST here is the more hacky way we - # did things. This fails with a "try" embedded inside a "try/else" - # since we can't detect COME_FROM boundaries. - # # We need to distinguish try_except from tryelsestmt and we do that - # # by checking the jump before the END_FINALLY - # # If we have: - # # insn - # # POP_TOP - # # END_FINALLY - # # COME_FROM - # # then insn is neither a JUMP_FORWARD nor RETURN_VALUE, - # # or if it is JUMP_FORWARD, then it can't be a JUMP_FORWARD to right after - # # COME_FROM - # if last == len(tokens): - # last -= 1 - # while tokens[last-1] == 'COME_FROM' and tokens[last-2] == 'COME_FROM': - # last -= 1 - # if tokens[last] == 'COME_FROM' and tokens[last-1] == 'COME_FROM': - # last -= 1 - # if (tokens[last] == 'COME_FROM' - # and tokens[last-1] == 'END_FINALLY' - # and tokens[last-2] == 'POP_TOP'): - # # A jump of 2 is a jump around POP_TOP, END_FINALLY which - # # would indicate try/else rather than try - # return (tokens[last-3].kind in frozenset(('JUMP_FORWARD', 'RETURN_VALUE')) - # and (tokens[last-3] != 'JUMP_FORWARD' or tokens[last-3].attr == 2)) + + # The above test apparently isn't good enough, so we have additional + # checks distinguish try_except from tryelsestmt and we do that + # by checking the jump before the END_FINALLY + # If we have: + # insn + # POP_TOP + # END_FINALLY + # COME_FROM + # then insn is neither a JUMP_FORWARD nor RETURN_VALUE, + # or if it is JUMP_FORWARD, then it can't be a JUMP_FORWARD to right after + # COME_FROM + if last == len(tokens): + last -= 1 + while tokens[last-1] == 'COME_FROM' and tokens[last-2] == 'COME_FROM': + last -= 1 + if tokens[last] == 'COME_FROM' and tokens[last-1] == 'COME_FROM': + last -= 1 + if (tokens[last] == 'COME_FROM' + and tokens[last-1] == 'END_FINALLY' + and tokens[last-2] == 'POP_TOP'): + # A jump of 2 is a jump around POP_TOP, END_FINALLY which + # would indicate try/else rather than try + return (tokens[last-3].kind in frozenset(('JUMP_FORWARD', 'RETURN_VALUE')) + and (tokens[last-3] != 'JUMP_FORWARD' or tokens[last-3].attr == 2)) return False From 78898ed187246808e0ce398af49dddd400ed6240 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 21 Mar 2018 19:59:35 -0400 Subject: [PATCH 131/489] Add PYTHON3 import --- uncompyle6/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index a45140b26..e4ab020f1 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -15,7 +15,7 @@ import datetime, os, subprocess, sys -from uncompyle6 import verify, IS_PYPY +from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION from xdis.code import iscode from uncompyle6.disas import check_object_path from uncompyle6.semantics import pysource From 1462a8beb057e359b69f363fcc592f4fbb5bb36a Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 21 Mar 2018 20:43:11 -0400 Subject: [PATCH 132/489] simply since we don't do 3.0 in this branch --- uncompyle6/main.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index e4ab020f1..d2d4e5232 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -15,7 +15,7 @@ import datetime, os, subprocess, sys -from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION +from uncompyle6 import verify, IS_PYPY from xdis.code import iscode from uncompyle6.disas import check_object_path from uncompyle6.semantics import pysource @@ -38,11 +38,7 @@ def _get_outstream(outfile): os.makedirs(dir) except OSError: pass - if PYTHON_VERSION < 3.0: - mode = 'wb' - else: - mode = 'w' - return open(outfile, mode) + return open(outfile, 'wb') def decompile( bytecode_version, co, out=None, showasm=None, showast=False, From a1cdc5e40c0d4ab459da50911775e7b385f51f83 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 26 Mar 2018 08:13:17 -0400 Subject: [PATCH 133/489] Grammar testing --- test/grammar-cover/grammar24.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/grammar-cover/grammar24.sh b/test/grammar-cover/grammar24.sh index 536846bd4..8496935c9 100755 --- a/test/grammar-cover/grammar24.sh +++ b/test/grammar-cover/grammar24.sh @@ -13,8 +13,8 @@ GRAMMAR_TXT=$tmpdir/grammar-${VERS}.txt pyenv local 2.4.6 cd ./test if [[ -r $GRAMMAR_TXT ]]; then - GRAMMAR_SAVE_TXT=${workdir}/grammar-${VERS}-save.txt + GRAMMAR_SAVE_TXT=${tmpdir}/grammar-${VERS}-save.txt cp $GRAMMAR_TXT $GRAMMAR_SAVE_TXT fi make grammar-coverage-2.4 && \ - spark-parser-coverage --path ${workdir}/spark-grammar-${VERS}.cover > $GRAMMAR_TXT + spark-parser-coverage --path ${tmpdir}/spark-grammar-${VERS}.cover > $GRAMMAR_TXT From c48345a5c06ba80ebc870df6efea845e9170b6ca Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 26 Mar 2018 08:14:15 -0400 Subject: [PATCH 134/489] More grammar coverage work --- test/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Makefile b/test/Makefile index 785f76c5f..966818a2b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -118,13 +118,13 @@ check-bytecode-2.5: grammar-coverage-2.4: -rm $(COVER_DIR)/spark-grammar-24.cover SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4 - SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6 --max= 800 #: Get grammar coverage for Python 2.5 grammar-coverage-2.5: -rm $(COVER_DIR)/spark-grammar-25.cover SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5 - SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 + SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6 --max=800 #: Get grammar coverage for Python 2.6 grammar-coverage-2.6: From 19bb16270d4f6f1728d4c1e0c7ded10597e2907c Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 3 Apr 2018 10:56:27 -0400 Subject: [PATCH 135/489] Merge conflicts --- uncompyle6/scanners/scanner2.py | 5 ----- uncompyle6/scanners/scanner3.py | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 8a76ad1e1..cbe59b8b4 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -35,11 +35,6 @@ from uncompyle6 import PYTHON_VERSION -if PYTHON_VERSION < 2.6: - from xdis.namedtuple24 import namedtuple -else: - from collections import namedtuple - from copy import copy from xdis.code import iscode diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 7ecd4952a..a580a17c0 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -173,6 +173,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): cause specific rules for the specific number of arguments they take. """ + if not show_asm: + show_asm = self.show_asm + if not show_asm: show_asm = self.show_asm From 600cee26d96a2941c0508792824858b2f2d8cdf7 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 11 May 2018 10:25:35 -0400 Subject: [PATCH 136/489] Properly resolve a merge conflict --- uncompyle6/parsers/parse26.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index d7731a00c..a2374752b 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -264,10 +264,11 @@ def p_misc26(self, args): dict ::= BUILD_MAP kvlist kvlist ::= kvlist kv3 - expr ::= conditional_not - conditional_not ::= expr jmp_true expr _jump COME_FROM POP_TOP expr COME_FROM + # Note: preserve positions 0 2 and 4 for semantic actions + conditional_not ::= expr jmp_true expr jf_cf_pop expr COME_FROM + conditional ::= expr jmp_false expr jf_cf_pop expr come_from_opt + expr ::= conditional_not - conditional ::= expr jmp_false expr jf_cf_pop expr come_from_opt and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP # compare_chained is like x <= y <= z @@ -322,7 +323,8 @@ def customize_grammar_rules(self, tokens, customize): WITH_CLEANUP END_FINALLY """) super(Python26Parser, self).customize_grammar_rules(tokens, customize) - self.check_reduce['and'] = 'AST' + if self.version >= 2.6: + self.check_reduce['and'] = 'AST' self.check_reduce['assert_expr_and'] = 'AST' self.check_reduce['list_for'] = 'AST' self.check_reduce['try_except'] = 'tokens' @@ -345,14 +347,22 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): return False # For now, we won't let the 2nd 'expr' be a "conditional_not" + # However in < 2.6 where we don't have if/else expression it *can* + # be. if ast[2][0] == 'conditional_not': return True + test_index = last + while tokens[test_index].kind == 'COME_FROM': + test_index += 1 + if tokens[test_index].kind.startswith('JUMP_IF'): + return False + # Test that jmp_false jumps to the end of "and" # or that it jumps to the same place as the end of "and" jmp_false = ast[1][0] jmp_target = jmp_false.offset + jmp_false.attr + 3 - return not (jmp_target == tokens[last].offset or + return not (jmp_target == tokens[test_index].offset or tokens[last].pattr == jmp_false.pattr) elif rule == ( 'list_for', From 7659277c5c3024ac13e36083bc06c6f430f7da4c Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 19 May 2018 12:58:45 -0400 Subject: [PATCH 137/489] Past fix of conditional_not bleed into 2.5... and it shouldn't have --- uncompyle6/parsers/parse26.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index a2374752b..c38e08a04 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -349,7 +349,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # For now, we won't let the 2nd 'expr' be a "conditional_not" # However in < 2.6 where we don't have if/else expression it *can* # be. - if ast[2][0] == 'conditional_not': + if self.version >= 2.6 and ast[2][0] == 'conditional_not': return True test_index = last From b3642094b2258b8c4d7170c0cdb8d86a80e3130c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 11 Jun 2018 11:39:01 -0400 Subject: [PATCH 138/489] Now allow 3.0 --- __pkginfo__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/__pkginfo__.py b/__pkginfo__.py index 3469f754a..71340adc7 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -35,6 +35,7 @@ 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', From f7a8aabdee7aba421309912ef8adbec319878d68 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Jun 2018 13:21:46 -0400 Subject: [PATCH 139/489] Realign make_function3 with master --- uncompyle6/semantics/make_function.py | 86 ++++++++------------------- 1 file changed, 26 insertions(+), 60 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index f85bceed5..5696a43ef 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -627,69 +627,35 @@ def build_param(ast, name, default): params.reverse() # back to correct order - if code_has_star_arg(code): - if self.version > 3.0: - params.append('*%s' % code.co_varnames[argc + kw_pairs]) - else: - params.append('*%s' % code.co_varnames[argc]) - argc += 1 - - # dump parameter list (with default values) - if is_lambda: - self.write("lambda ", ", ".join(params)) + if code_has_star_arg(code): + if self.version > 3.0: + params.append('*%s' % code.co_varnames[argc + kw_pairs]) else: - self.write("(", ", ".join(params)) - # self.println(indent, '#flags:\t', int(code.co_flags)) + params.append('*%s' % code.co_varnames[argc]) + argc += 1 + # dump parameter list (with default values) + if is_lambda: + self.write("lambda ", ", ".join(params)) + # If the last statement is None (which is the + # same thing as "return None" in a lambda) and the + # next to last statement is a "yield". Then we want to + # drop the (return) None since that was just put there + # to have something to after the yield finishes. + # FIXME: this is a bit hoaky and not general + if (len(ast) > 1 and + self.traverse(ast[-1]) == 'None' and + self.traverse(ast[-2]).strip().startswith('yield')): + del ast[-1] + # Now pick out the expr part of the last statement + ast_expr = ast[-1] + while ast_expr.kind != 'expr': + ast_expr = ast_expr[0] + ast[-1] = ast_expr + pass else: - if is_lambda: - self.write("lambda ") - # If the last statement is None (which is the - # same thing as "return None" in a lambda) and the - # next to last statement is a "yield". Then we want to - # drop the (return) None since that was just put there - # to have something to after the yield finishes. - # FIXME: this is a bit hoaky and not general - if (len(ast) > 1 and - self.traverse(ast[-1]) == 'None' and - self.traverse(ast[-2]).strip().startswith('yield')): - del ast[-1] - # Now pick out the expr part of the last statement - ast_expr = ast[-1] - while ast_expr.kind != 'expr': - ast_expr = ast_expr[0] - ast[-1] = ast_expr - pass - else: - self.write("(") - pass - - last_line = self.f.getvalue().split("\n")[-1] - l = len(last_line) - indent = ' ' * l - line_number = self.line_number - - if code_has_star_arg(code): - self.write('*%s' % code.co_varnames[argc + kw_pairs]) - argc += 1 - - i = len(paramnames) - len(defparams) - self.write(", ".join(paramnames[:i])) - if i > 0: - suffix = ', ' - else: - suffix = '' - for n in node: - if n == 'pos_arg': - self.write(suffix) - self.write(paramnames[i] + '=') - i += 1 - self.preorder(n) - if (line_number != self.line_number): - suffix = ",\n" + indent - line_number = self.line_number - else: - suffix = ', ' + self.write("(", ", ".join(params)) + # self.println(indent, '#flags:\t', int(code.co_flags)) ends_in_comma = False if kw_args > 0: From 398981e887951f5f9b36fcf6854328e377a83c75 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 13:17:14 -0400 Subject: [PATCH 140/489] Try CircleCI 2.0 --- .circleci/config.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26a827bca..8fa04f995 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 install 2.7.13 && pyenv local 2.7.13 && pyenv rehash && pip install virtualenv && pip install nose && pip install pep8 && pyenv rehash + command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && pip install virtualenv && pip 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 # Save dependency cache - save_cache: key: v1-dep-{{ .Branch }}-{{ epoch }} @@ -76,7 +74,7 @@ jobs: # 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.13 && bash ./runtests.sh 'test_[p-z]*.py' + - 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 From e934d791700a6240b0589c2ee8d59d8453064139 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 13:27:23 -0400 Subject: [PATCH 141/489] More CircleCI 2.0 config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8fa04f995..cf7159bd8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,7 +73,7 @@ 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: 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 From 86e29eaac8be2d83e0b31c93c995995fee8e712e Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 13:28:39 -0400 Subject: [PATCH 142/489] More CircleCI 2.0 config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cf7159bd8..aebe8c237 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && pip install virtualenv && pip install nose && pyenv rehash + command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && && pip 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 From d3bd73c281bb32852fc17877070c3a704a56a00c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 13:29:28 -0400 Subject: [PATCH 143/489] More CircleCI 2.0 config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index aebe8c237..b9e092a5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && && pip install nose && pyenv rehash + command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && 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 From 12e46504f3b03f4b29fb1071056fed69b25145c2 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 13:33:36 -0400 Subject: [PATCH 144/489] Another CircleCI 2.0 try --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b9e092a5c..eea54bc5f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && install nose && pyenv rehash + command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && pyenv 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 From d420b2864e6480a508e8ae52fcfd34e0f8933674 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 16:40:36 -0400 Subject: [PATCH 145/489] Fix CircleCI testing? --- .circleci/config.yml | 2 +- test/stdlib/runtests.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eea54bc5f..3ce7b92e8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && pyenv install nose && 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 diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 81041c07b..7a6292f4c 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -35,6 +35,7 @@ case $PYVERSION in [test_dis.py]=1 # We change line numbers - duh! [test_grp.py]=1 # Long test - might work Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? + [test_pep247.py]=1 # Long test - might work? Control flow? [test_queue.py]=1 # Control flow? # [test_threading.py]=1 # Long test - works ) @@ -178,7 +179,7 @@ if [[ -e $TESTDIR ]] ; then rm -fr $TESTDIR fi mkdir $TESTDIR || exit $? -cp -r ~/.pyenv/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR +cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR cd $TESTDIR/test export PYTHONPATH=$TESTDIR From 1f8a5dfa06a86a528db576e3833d2d50d11729d9 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Jun 2018 16:53:25 -0400 Subject: [PATCH 146/489] Another CircleCI 2.0 try --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3ce7b92e8..800965bd2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -55,7 +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 -e . + - run: easy_install spark_parser==1.8.5 && easy_install xdis==3.8.4 # Save dependency cache - save_cache: key: v1-dep-{{ .Branch }}-{{ epoch }} From b94d67e99a449516da3a77ef65506272e0f81a3b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Jun 2018 22:36:31 -0400 Subject: [PATCH 147/489] Remove CircleCI 1.1 --- circle.yml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 circle.yml diff --git a/circle.yml b/circle.yml deleted file mode 100644 index cb25f14de..000000000 --- a/circle.yml +++ /dev/null @@ -1,15 +0,0 @@ -machine: - python: - version: 2.7.10 - environment: - COMPILE: --compile - -dependencies: - override: - - pip install --upgrade setuptools - - pip install -e . - - pip install pytest==3.2.5 hypothesis -test: - override: - - python ./setup.py develop && make check-2.7 - - cd ./test/stdlib && pyenv local 2.7.10 && bash ./runtests.sh 'test_[f-i]*.py' From 8246f54831ed13d1877307fbda4766be434dee46 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 26 Jan 2019 18:50:17 -0500 Subject: [PATCH 148/489] Python 2.5. tolerance --- uncompyle6/main.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 83e72e43d..e2c9fe7de 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Rocky Bernstein +# Copyright (C) 2018-2019 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ import datetime, os, subprocess, sys -from uncompyle6 import verify, IS_PYPY +from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION from xdis.code import iscode from xdis.magics import sysinfo2float from uncompyle6.disas import check_object_path @@ -214,10 +214,11 @@ def main(in_base, out_base, files, codes, outfile=None, else: buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) - tee = subprocess.Popen(["tee", current_outfile], - stdin=subprocess.PIPE) - os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) - os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) + if PYTHON_VERSION > 2.5: + tee = subprocess.Popen(["tee", current_outfile], + stdin=subprocess.PIPE) + os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) + os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) else: if filename.endswith('.pyc'): current_outfile = os.path.join(out_base, filename[0:-1]) From ddf73b653c1791230e67f22184111e812b6beb91 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 10 Mar 2019 14:17:59 -0400 Subject: [PATCH 149/489] Use Python 2.7, not 3.7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0871e9fa..d20842f2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ python: matrix: include: - - python: '3.7' + - python: '2.7' dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069) install: From adc7e5242ca5ec619d31d051b1ad850ab19b3cc7 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 10 Apr 2019 12:32:34 -0400 Subject: [PATCH 150/489] More run tests --- test/Makefile | 1 + test/bytecode_2.4/02_slice.pyc | Bin 174 -> 0 bytes test/bytecode_2.4/10_for.pyc | Bin 218 -> 0 bytes test/bytecode_2.4/10_mixed_boolean.pyc | Bin 433 -> 0 bytes test/bytecode_2.4_run/02_slice.pyc | Bin 0 -> 332 bytes test/bytecode_2.4_run/10_for.pyc | Bin 0 -> 313 bytes test/bytecode_2.4_run/10_mixed_boolean.pyc | Bin 0 -> 745 bytes test/bytecode_2.6/02_slice.pyc | Bin 211 -> 0 bytes test/bytecode_2.6/10_del.pyc | Bin 823 -> 828 bytes test/bytecode_2.6/10_for.pyc | Bin 215 -> 0 bytes test/bytecode_2.6/10_mixed_boolean.pyc | Bin 420 -> 0 bytes test/bytecode_2.6_run/02_slice.pyc | Bin 0 -> 329 bytes test/bytecode_2.6_run/10_for.pyc | Bin 0 -> 310 bytes test/bytecode_2.6_run/10_mixed_boolean.pyc | Bin 0 -> 732 bytes test/bytecode_pypy3.2/02_slice.pyc | Bin 192 -> 0 bytes 15 files changed, 1 insertion(+) delete mode 100644 test/bytecode_2.4/02_slice.pyc delete mode 100644 test/bytecode_2.4/10_for.pyc delete mode 100644 test/bytecode_2.4/10_mixed_boolean.pyc create mode 100644 test/bytecode_2.4_run/02_slice.pyc create mode 100644 test/bytecode_2.4_run/10_for.pyc create mode 100644 test/bytecode_2.4_run/10_mixed_boolean.pyc delete mode 100644 test/bytecode_2.6/02_slice.pyc delete mode 100644 test/bytecode_2.6/10_for.pyc delete mode 100644 test/bytecode_2.6/10_mixed_boolean.pyc create mode 100644 test/bytecode_2.6_run/02_slice.pyc create mode 100644 test/bytecode_2.6_run/10_for.pyc create mode 100644 test/bytecode_2.6_run/10_mixed_boolean.pyc delete mode 100644 test/bytecode_pypy3.2/02_slice.pyc diff --git a/test/Makefile b/test/Makefile index 939bbb37e..2dfaee2ee 100644 --- a/test/Makefile +++ b/test/Makefile @@ -148,6 +148,7 @@ check-bytecode-2.3: #: Check deparsing Python 2.4 check-bytecode-2.4: + $(PYTHON) test_pythonlib.py --bytecode-2.4-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-2.4 #: Check deparsing Python 2.5 diff --git a/test/bytecode_2.4/02_slice.pyc b/test/bytecode_2.4/02_slice.pyc deleted file mode 100644 index dcd9f37d6f26558c60e6a35c1ea2f0f26b477892..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmd1(#LJcUqarMs0ScIbv;z^@t%q_@CjW5nGElN(+FV4vXk_JZc WV1`~nWeLa-dk|3!vV)(IgAo9{`x}D* diff --git a/test/bytecode_2.4/10_for.pyc b/test/bytecode_2.4/10_for.pyc deleted file mode 100644 index 0ac4cabcce1edf31dac7c064ce354eaa345e43b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 218 zcmd1(#LJaXUlEqf00m4y+5w1*t${>^I712pLpmdaODqpV6azyFBSRD;Lm?MKc!d;0 zDies`j4r9p5T3%s5Ujxr)St-+B0xs^f%zpMej=DmE@1_-ixTtFQ#C*ef`FJI2qdoo zVu6Vgc_6DeGq)foHNH5%v?w`MKPNxGATuvr-_RgFEx$;wpb~7DJqt)77m(m$U}NNB H;sufbE_xzw diff --git a/test/bytecode_2.4/10_mixed_boolean.pyc b/test/bytecode_2.4/10_mixed_boolean.pyc deleted file mode 100644 index c1c12c5c1b0df0db45960fe3c1cec50c4a95765b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 433 zcmZvXziz@X5XR5Mp%SP}z`_e;;?EPb6Jv)^b;uHhe)2Mt*)nh6^9wDF^l zg7(bU)2_Z=ji+@dzJ|AJ@F~=-rCGR=&U9!nzH?LnyF@u*&yD X4Hk!``SI!BB%PfzhDzqNHy7$3e4RqM diff --git a/test/bytecode_2.4_run/02_slice.pyc b/test/bytecode_2.4_run/02_slice.pyc new file mode 100644 index 0000000000000000000000000000000000000000..280ad2d75e959646346e2928405fb3a91d7373a6 GIT binary patch literal 332 zcmZvWv5EpQ5QhIrT!lri5eo&;GL?!ia9Uhzp`8dKCdi7qOA?D~4}5@ok$X6w;AYmv zMnmSyOy-|IIp15UY5#5Zs8+(~j3fLqEN_BUuo||8LxMHn%FE%J;J8;72Zf_T(Evq- z9|AozgG%$9*KcHOz~+RTMz_+lt;UO|O|UX`{#8Z-CD4MJK>ocjQb)nge@Bt+;sjzlzJ+q HzHZY$qhT_u literal 0 HcmV?d00001 diff --git a/test/bytecode_2.4_run/10_for.pyc b/test/bytecode_2.4_run/10_for.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63501171cd2ee37f18c953d2922fe92b4a9c1170 GIT binary patch literal 313 zcmZvWK}!QM5QX1ltKdS*f(H+RUUPEosmCfPc=FI5gikBjadcv=1Y?|&h@sd^YQiS#rdoLV|V}bLm7#qWB?K%W*`|xl4Iar2H(r)9G;^geU<}ES$Gq^=&dw|xDmK{ zOiLrp#NJ9bc_>1q!`#eJh%&0hMM!#X#+D()A=7_nEb(O9)IRFeqQ<`fvYMRkjgh)8 z)aF5JrRxAC+t(t(=G^8qqSGr*$yVgCB0j=!sa|4bigi`W#Hg(na-k}zQ}Rzr^;U?* s@;X@;?=nv^rAnD@uBs1fe@mX`5))@fjI%k$308kG$9mSr8P@0Q2Z#H1-2eap literal 0 HcmV?d00001 diff --git a/test/bytecode_2.6/02_slice.pyc b/test/bytecode_2.6/02_slice.pyc deleted file mode 100644 index ad08fa8bc852ccd54f897e1eab5054ee30e0e247..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 211 zcmcckiI?k-lvGqQ0~D|UX$K%KwgM6!3@2E$`THs8k^kwl+v73JCIq$Ap1m_I2bvY0H2Z} A#Q*>R diff --git a/test/bytecode_2.6/10_del.pyc b/test/bytecode_2.6/10_del.pyc index e67fcafa83b5dc54148c479d5784df9359011e18..11c06436270ef07ba7fbef19a4345aa2f76c684e 100644 GIT binary patch delta 220 zcmdnawuepn;wN6N^|Lgik{O_Y9Y{L>aq+5&(z94I7#I>cCT{6skp&7(_GFTsoX994 z$q3|turo-V7?4O|WT<6eNMe{gi7^(YRL%sXL||DEAx62$63p^UY)k;sP#pgN delta 199 zcmdnPww+D-;wN6N$%e{N$qZ1y4x}A`xOmA#=~)wZce2R?IePk&Uo*)~PGb~jWSU&Z zD8^LBIC&alEJ9A!Jctpf4y3l21xPS3Gc##`XbmPH0hS8_i9^Id62)+HWrc!30x}>$ iHV})Ejd5}XlR6{Ezh diff --git a/test/bytecode_2.6/10_for.pyc b/test/bytecode_2.6/10_for.pyc deleted file mode 100644 index 557d270cfe9885cc4cd17ae4cb3eafe1f3cb4cdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 215 zcmcckiI*#(z9KA{0SZ`wv;z-mslQ#CT$DM z9R=>5uE$+;J&(J-58lJeCHN=A-$;wla+Aq0V05J@0bXPG*_U|4XeGm2)1r0U!A6YF zxiXdlg1{u6&*80A62nVHd$SDSY`(zh57MGpX`Kh VZEGr9g*#_ymJB1|;;|Pi@e4}4M2i3b diff --git a/test/bytecode_2.6_run/02_slice.pyc b/test/bytecode_2.6_run/02_slice.pyc new file mode 100644 index 0000000000000000000000000000000000000000..faee3c6d21c8afd87062e38e2214dd79ee2d23db GIT binary patch literal 329 zcmZvWF>V4e5JmskY!a;q4Wa-kBIQ=!S{gcpgb=pSqJ>@Arl3XQ09=H-aFv{Z znazq6#Im3LXTHCE`+1L(=5?_~HC}lC=H)L8!;@eXjE1RU6JZY6viLbCSnic#qp(#d zUO_?OM4(?!xAHvh>wjz2f@l6gViKe)B+`z&P+zLw>oR~*9|dxpE*95OqS_k5kv M(lK>ZOdq;QcPXAVFaQ7m literal 0 HcmV?d00001 diff --git a/test/bytecode_2.6_run/10_for.pyc b/test/bytecode_2.6_run/10_for.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c1ddd90b1551fba5c993f3cfae35ea0d1bfc140 GIT binary patch literal 310 zcmZvV!AiqG5QhKR)S`iefCmqPUUM>f@>0Zt1y8+rC=?}x>>5_mY`VL__NwpWyZ9N@dt#3PG~K0+bL5SIuRG4QyN2t10K9ui$puYrd9mBJbl9%?ByqeV3(J19E?o@+y} z3y$5@tW9(stVPI)8`w!j;6@_#4Ya{i4_d{@Uq-x_XED5_efwDs&=tvT@~YNcA7Vl= zdCDuz^~i1IE0)kisD$YW7Sh7T^dhl!riYHP6_1Snz2k^y*T#fcw=E3*1yC5P^q@6Y zrWC73rGzpOmRw(lQ0JNRd5T-Gb9#=cE|;?6nHFnB`AkTza;ue9;=QD^`E|A|KRC+@ rAu67)uH>h&C%st;wyyY{9Y Date: Sun, 14 Apr 2019 07:11:59 -0400 Subject: [PATCH 151/489] 2.4-branch uncompyle6 doesn't support -c --- NEWS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 876076a96..b4027e97a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,6 @@ ========================== * First cut at Python 3.8 (many bug remain) -* Reinstate -c | --compile (compile before disassembly) option * The usual smattering of bug and doc fixes 3.2.6 2019-03-23 Mueller Report From 636257f879e8de37f2892a8d4ed7cb82cc904507 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 23 Apr 2019 13:07:30 -0400 Subject: [PATCH 152/489] Was mssing 2.5 cond3 semantic rule --- uncompyle6/semantics/customize25.py | 2 ++ uncompyle6/semantics/customize26_27.py | 1 - uncompyle6/semantics/pysource.py | 3 --- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/uncompyle6/semantics/customize25.py b/uncompyle6/semantics/customize25.py index 5b1be0ceb..88b6fa505 100644 --- a/uncompyle6/semantics/customize25.py +++ b/uncompyle6/semantics/customize25.py @@ -26,6 +26,8 @@ def customize_for_version25(self, version): # Import style for 2.5+ ######################## TABLE_DIRECT.update({ + 'except_cond3' : ( '%|except %c, %c:\n', + (1, 'expr'), (-2, 'store') ), 'importmultiple': ( '%|import %c%c\n', 2, 3 ), 'import_cont' : ( ', %c', 2 ), # With/as is allowed as "from future" thing in 2.5 diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index b5153245a..f3a91a99d 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -34,7 +34,6 @@ def customize_for_version26_27(self, version): }) else: TABLE_DIRECT.update({ - 'except_cond3': ( '%|except %c, %c:\n', 1, 6 ), 'testtrue_then': ( 'not %p', (0, 22) ), }) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 4b7abe45f..b40993e87 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1813,9 +1813,6 @@ def n_except_cond2(self, node): node[-2][0].kind = 'unpack_w_parens' self.default(node) - # except_cond3 is only in Python <= 2.6 - n_except_cond3 = n_except_cond2 - def template_engine(self, entry, startnode): """The format template interpetation engine. See the comment at the beginning of this module for the how we interpret format From 5475934c0d493126b0b686688056a90af1225a27 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 23 Apr 2019 15:44:05 -0400 Subject: [PATCH 153/489] Fix 2.x delete statements expression confusion --- uncompyle6/parsers/parse2.py | 20 ++++++++++++++++---- uncompyle6/semantics/consts.py | 3 ++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index ead291529..2ebd619fd 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -96,10 +96,6 @@ def p_grammar(self, args): for ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK _come_froms - del_stmt ::= expr DELETE_SLICE+0 - del_stmt ::= expr expr DELETE_SLICE+1 - del_stmt ::= expr expr DELETE_SLICE+2 - del_stmt ::= expr expr expr DELETE_SLICE+3 del_stmt ::= delete_subscr delete_subscr ::= expr expr DELETE_SUBSCR del_stmt ::= expr DELETE_ATTR @@ -372,6 +368,17 @@ def customize_grammar_rules(self, tokens, customize): self.addRule('del_stmt ::= expr DELETE_ATTR', nop_func) custom_seen_ops.add(opname) continue + elif opname.startswith('DELETE_SLICE'): + self.addRule(""" + del_expr ::= expr + del_stmt ::= del_expr DELETE_SLICE+0 + del_stmt ::= del_expr del_expr DELETE_SLICE+1 + del_stmt ::= del_expr del_expr DELETE_SLICE+2 + del_stmt ::= del_expr del_expr del_expr DELETE_SLICE+3 + """, nop_func) + custom_seen_ops.add(opname) + self.check_reduce['del_expr'] = 'AST' + continue elif opname == 'DELETE_DEREF': self.addRule(""" stmt ::= del_deref_stmt @@ -384,6 +391,7 @@ def customize_grammar_rules(self, tokens, customize): del_stmt ::= delete_subscr delete_subscr ::= expr expr DELETE_SUBSCR """, nop_func) + self.check_reduce['delete_subscr'] = 'AST' custom_seen_ops.add(opname) continue elif opname == 'GET_ITER': @@ -539,6 +547,10 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): elif rule == ('or', ('expr', 'jmp_true', 'expr', '\\e_come_from_opt')): expr2 = ast[2] return expr2 == 'expr' and expr2[0] == 'LOAD_ASSERT' + elif lhs in ('delete_subscr', 'del_expr'): + op = ast[0][0] + return op.kind in ('and', 'or') + return False class Python2ParserSingle(Python2Parser, PythonParserSingle): diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 3fcf61117..6183e0608 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -150,7 +150,8 @@ 'DELETE_FAST': ( '%|del %{pattr}\n', ), 'DELETE_NAME': ( '%|del %{pattr}\n', ), 'DELETE_GLOBAL': ( '%|del %{pattr}\n', ), - 'delete_subscr': ( '%|del %c[%c]\n', 0, 1,), + 'delete_subscr': ( '%|del %c[%c]\n', + (0, 'expr'), (1, 'expr') ), 'subscript': ( '%c[%p]', (0, 'expr'), (1, 100) ), From 23b7e6db18c6be190dbd7f80b1b99fbec11e2a47 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 30 Apr 2019 23:09:26 -0400 Subject: [PATCH 154/489] Better 3.6 FORMAT_VALUE handling --- uncompyle6/scanners/scanner36.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/scanners/scanner36.py b/uncompyle6/scanners/scanner36.py index 6a985e591..5e279a7f0 100644 --- a/uncompyle6/scanners/scanner36.py +++ b/uncompyle6/scanners/scanner36.py @@ -37,7 +37,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if (t.attr & 0x4): t.kind = 'FORMAT_VALUE_ATTR' pass ->>>>>>> master elif ( not_pypy36 and t.op == self.opc.BUILD_MAP_UNPACK_WITH_CALL ): t.kind = 'BUILD_MAP_UNPACK_WITH_CALL_%d' % t.attr From da44660a72732ad199d4be96605c9820acb02117 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 3 May 2019 23:22:01 -0400 Subject: [PATCH 155/489] 2.6 doesn't have print_function --- uncompyle6/scanners/scanner37.py | 2 -- uncompyle6/scanners/scanner38.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index d5e095d97..ad86e23af 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,8 +22,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from uncompyle6.scanners.scanner36 import Scanner36 from uncompyle6.scanners.scanner3 import Scanner3 diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index f8fe0ff68..598f8f0a9 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -22,8 +22,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - from uncompyle6.scanners.scanner37 import Scanner37 from uncompyle6.scanners.scanner3 import Scanner3 From 900a0980c1662ec12409a52fb72c97a635499529 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 3 May 2019 23:23:37 -0400 Subject: [PATCH 156/489] Administrivia Add 2.6 back into older dist --- admin-tools/pyenv-older-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/pyenv-older-versions b/admin-tools/pyenv-older-versions index f2e792cbf..38d07ed8c 100644 --- a/admin-tools/pyenv-older-versions +++ b/admin-tools/pyenv-older-versions @@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='2.4.6 2.5.6' +export PYVERSIONS='2.4.6 2.5.6 2.6.9' From 123be56e5df209e95ab31f9b1b5e940a67b9b6c7 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 24 May 2019 10:44:05 -0400 Subject: [PATCH 157/489] Simplify docstrings... main.py: 2.7ism creaped in. --- test/bytecode_2.4_run/00_docstring.pyc | Bin 0 -> 1352 bytes uncompyle6/main.py | 2 +- uncompyle6/semantics/helper.py | 13 +++---------- 3 files changed, 4 insertions(+), 11 deletions(-) create mode 100644 test/bytecode_2.4_run/00_docstring.pyc diff --git a/test/bytecode_2.4_run/00_docstring.pyc b/test/bytecode_2.4_run/00_docstring.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2eb5e8ef5c01d97910b262277e2e9d854da4972b GIT binary patch literal 1352 zcmb_c&5qMR44!EU3q{KbX|GoH&=i$yyC<|#3kV@`Ks^Lbs3^*2rfrt|DdX@fF2IAp z+i~Uzu%}Vm4Mi&u8O5<3`j?yvwoQ?{DiSV_^BuUAs01vbJF_|A47ja_3QXgLKm($EH2NR~%^1 z@S-Ei10hk0&ypS;k&wG1T5iX>owmDc-J<2*e&=u0Cp~B`-}kLXrA?<(h>Xz{!WbqK z81D-zYMF_?Dg^tN6YBY(`#1EoM6Y)5$l~!k)oOWsGS9Q*X zcsqoK&~LnJ*K)h>}#R$!G`>qRvVr 2.7: - replace_str = '\\"""' - else: - replace_str = '\\"\\"\\"' - docstring = docstring.replace(quote, replace_str) + replace_str = '\\"""' else: assert quote == "'''" - if self.version > 2.7: - replace_str = "\\'''" - else: - replace_str = "\\'\\'\\'" - docstring = docstring.replace(quote, replace_str) + replace_str = "\\'''" + docstring = docstring.replace(quote, replace_str) docstring = docstring.replace('\t', '\\\\') lines = docstring.split('\n') From aa21fe0b31f8b187600fb253cad92cc14a81a710 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 8 Jun 2019 18:57:43 -0400 Subject: [PATCH 158/489] Give up on 3.8 in this branch --- test/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/Makefile b/test/Makefile index 670aa74ac..bf8333c51 100644 --- a/test/Makefile +++ b/test/Makefile @@ -71,10 +71,10 @@ check-3.7: check-bytecode $(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify $(COMPILE) -#: Run working tests from Python 3.8 -check-3.8: check-bytecode - $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run - $(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify $(COMPILE) +# #: Run working tests from Python 3.8 +# check-3.8: check-bytecode +# $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run +# $(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify $(COMPILE) # FIXME #: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0 @@ -98,7 +98,7 @@ 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-3.8 \ + --bytecode-3.7 \ --bytecode-pypy3.2 #: Check deparsing on selected bytecode 3.x @@ -277,10 +277,10 @@ check-bytecode-3.7: $(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify -#: Check deparsing Python 3.8 -check-bytecode-3.8: - $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run - $(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify +# #: Check deparsing Python 3.8 +# check-bytecode-3.8: +# $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run +# $(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify #: short tests for bytecodes only for this version of Python check-native-short: From f3b72884c64d54cdd2973bf512a998cdf95f41e6 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 12 Jun 2019 13:09:22 -0400 Subject: [PATCH 159/489] Merge hell? --- uncompyle6/parsers/parse3.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 4cf5c46a1..852c4aaed 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -32,7 +32,6 @@ 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): @@ -1081,11 +1080,11 @@ def customize_grammar_rules(self, tokens, customize): else: # See above comment about use of EXTENDED_ARG rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' % - (('kwargs ' * args_kw), ('pos_arg ' * (args_pos)), + (('pos_arg ' * (args_pos)), ('kwargs ' * args_kw), ('annotate_arg ' * (annotate_args-1)), opname)) self.add_unique_rule(rule, opname, token.attr, customize) rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' % - (('kwargs ' * args_kw), ('pos_arg ' * (args_pos)), + (('pos_arg ' * (args_pos)), ('kwargs ' * args_kw), ('call ' * (annotate_args-1)), opname)) self.addRule(rule, nop_func) elif opname == 'RETURN_VALUE_LAMBDA': @@ -1220,10 +1219,11 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): cfl = last assert tokens[cfl] == 'COME_FROM_LOOP' - if tokens[cfl-1] != 'JUMP_BACK': - cfl_offset = tokens[cfl-1].offset - insn = chain((i for i in self.insts if cfl_offset == i.offset), repeat(None)).next() - if insn and insn.is_jump_target: + for i in range(cfl-1, first, -1): + if tokens[i] != 'POP_BLOCK': + break + if tokens[i].kind not in ('JUMP_BACK', 'RETURN_VALUE'): + if not tokens[i].kind.startswith('COME_FROM'): return True # Check that the SETUP_LOOP jumps to the offset after the From 3983aa1b92c957101ea0aa3dd843396a108161e0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 16 Jun 2019 22:30:05 -0400 Subject: [PATCH 160/489] One more deparse_code removal --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index b0cecd7f9..f9b7e4d8b 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2371,7 +2371,7 @@ def deparse_code2str(code, out=sys.stdout, version=None, """Return the deparsed text for a Python code object. `out` is where any intermediate output for assembly or tree output will be sent. """ - return deparse_code(version, code, out, showasm=debug_opts.get('asm', None), + return code_deparse(code, out, version, showasm=debug_opts.get('asm', None), showast=debug_opts.get('tree', None), showgrammar=debug_opts.get('grammar', None), code_objects=code_objects, compile_mode=compile_mode, is_pypy=is_pypy, walker=walker).text From 72a95e7cce06567a3b57f45aa1c73acc139bb47e Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 17 Jun 2019 02:00:55 -0400 Subject: [PATCH 161/489] Add back in validate. --- pytest/validate.py | 152 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 pytest/validate.py diff --git a/pytest/validate.py b/pytest/validate.py new file mode 100644 index 000000000..84e6e4b2b --- /dev/null +++ b/pytest/validate.py @@ -0,0 +1,152 @@ +# future +from __future__ import print_function +# std +import os +import difflib +import subprocess +import tempfile +import functools +# uncompyle6 / xdis +from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse +# 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() + + +def print_diff(original, uncompyled): + """ + Try and display a pretty html line difference between the original and + uncompyled code and bytecode if elinks and BeautifulSoup are installed + otherwise just show the diff. + + :param original: Text describing the original code object. + :param uncompyled: Text describing the uncompyled code object. + """ + original_lines = original.split('\n') + uncompyled_lines = uncompyled.split('\n') + args = original_lines, uncompyled_lines, 'original', 'uncompyled' + try: + from bs4 import BeautifulSoup + diff = difflib.HtmlDiff().make_file(*args) + diff = BeautifulSoup(diff, "html.parser") + diff.select_one('table[summary="Legends"]').extract() + except ImportError: + print('\nTo display diff highlighting run:\n pip install BeautifulSoup4') + diff = difflib.HtmlDiff().make_table(*args) + + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(str(diff).encode('utf-8')) + + try: + print() + html = subprocess.check_output([ + 'elinks', + '-dump', + '-no-references', + '-dump-color-mode', + '1', + f.name, + ]).decode('utf-8') + print(html) + except: + 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) + + +def are_instructions_equal(i1, i2): + """ + Determine if two instructions are approximately equal, + ignoring certain fields which we allow to differ, namely: + + * code objects are ignore (should probaby be checked) due to address + * line numbers + + :param i1: left instruction to compare + :param i2: right instruction to compare + + :return: True if the two instructions are approximately equal, otherwise False. + """ + result = (1 == 1 + and i1.opname == i2.opname + and i1.opcode == i2.opcode + and i1.arg == i2.arg + # ignore differences due to code objects + # TODO : Better way of ignoring address + and (i1.argval == i2.argval or '', mode) + original_dis = _dis_to_text(original_code) + original_text = text + + deparsed = code_deparse(original_code, + out=six.StringIO(), + version=PYTHON_VERSION, + compile_mode=mode) + uncompyled_text = deparsed.text + uncompyled_code = compile(uncompyled_text, '', 'exec') + + if not are_code_objects_equal(uncompyled_code, original_code): + + uncompyled_dis = _dis_to_text(uncompyled_text) + + def output(text, dis): + width = 60 + return '\n\n'.join([ + ' SOURCE CODE '.center(width, '#'), + text.strip(), + ' BYTECODE '.center(width, '#'), + dis + ]) + + original = output(original_text, original_dis) + uncompyled = output(uncompyled_text, uncompyled_dis) + print_diff(original, uncompyled) + + assert 'original' == 'uncompyled' From 18bb1bc9e3e435392990887c0b1aee5a62ab6092 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 23 Jun 2019 18:15:53 -0400 Subject: [PATCH 162/489] Fix Python 2.xisms --- uncompyle6/main.py | 2 +- uncompyle6/parsers/parse3.py | 4 +++- uncompyle6/scanners/scanner3.py | 2 +- uncompyle6/scanners/tok.py | 6 ++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index b689758a5..08eb45d9f 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -282,7 +282,7 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None, sys.stdout.write("\n") sys.stderr.write("\nLast file: %s " % (infile)) raise - except RuntimeError(e): + except RuntimeError, e: sys.stdout.write("\n%s\n" % str(e)) if str(e).startswith('Unsupported Python'): sys.stdout.write("\n") diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 0b8778a76..9c0a7f11c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -438,7 +438,8 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize): """ # FIXME: I bet this can be simplified # look for next MAKE_FUNCTION - for i in range(i + 1, len(tokens)): + j = i + for i in range(j + 1, len(tokens)): if tokens[i].kind.startswith("MAKE_FUNCTION"): break elif tokens[i].kind.startswith("MAKE_CLOSURE"): @@ -450,6 +451,7 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize): assert ( tokens[i + 1].kind == "LOAD_STR" ), "build_class expecting CONST after MAKE_FUNCTION/MAKE_CLOSURE" + call_fn_tok = None for i in range(i, len(tokens)): if tokens[i].kind.startswith("CALL_FUNCTION"): diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index d39204f44..569941932 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -377,7 +377,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = "" - elif isinstance(const, str): + elif isinstance(const, str) or PYTHON_VERSION < 3.0 and isinstance(const, unicode): opname = "LOAD_STR" else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 309f8d6b8..6e72dda31 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -98,12 +98,14 @@ def format(self, line_prefix=""): prefix = "\n%s%4d " % (line_prefix, self.linestart) else: prefix = (" " * (6 + len(line_prefix))) - ) offset_opname = "%6s %-17s" % (self.offset, self.kind) if not self.has_arg: return "%s%s" % (prefix, offset_opname) - argstr = "%6d " % self.attr if isinstance(self.attr, int) else (" " * 7) + if isinstance(self.attr, int): + argstr = "%6d " % self.attr + else: + argstr = (" " * 7) name = self.kind if self.has_arg: From 82d8e0cd4739ae717891abafd05801f2f0be2702 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Jul 2019 18:36:53 -0400 Subject: [PATCH 163/489] master merge hell --- uncompyle6/semantics/customize3.py | 5 ++++- uncompyle6/semantics/make_function.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 9247b112c..62d32a917 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -266,7 +266,10 @@ def n_call(node): def n_mkfunc_annotate(node): # Handling EXTENDED_ARG before MAKE_FUNCTION ... - i = -1 if node[-2] == "EXTENDED_ARG" else 0 + if node[-2] == "EXTENDED_ARG": + i = -1 + else: + i = 0 if self.version <= 3.2: code = node[-2 + i] diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index a3ffdecb5..3d2d90d77 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2018 by Rocky Bernstein +# Copyright (c) 2015-2019 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # # This program is free software: you can redistribute it and/or modify From 7f7487206af3d2736a442f5960ee1b88659a5ccf Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Jul 2019 18:59:24 -0400 Subject: [PATCH 164/489] Reinstate except_cond{2,3} rules --- uncompyle6/semantics/consts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 214b4e8f5..9e1524dfc 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -409,7 +409,9 @@ 'tf_tryelsestmt': ( '%c%-%c%|else:\n%+%c', 1, 3, 4 ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ), 'except': ( '%|except:\n%+%c%-', 3 ), - 'except_cond1': ( '%|except %c:\n', 1 ), + 'except_cond1': ( '%|except %c:\n', (1, 'expr') ), + 'except_cond2': ( '%|except %c as %c:\n', (1, 'expr'), 5 ), + 'except_cond3': ( '%|except %c as %c:\n', (1, 'expr'), 6 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), # In Python 3.6, this is more complicated in the presence of "returns" From 4f5ad533c3368818eb9e366143357f1d2060d8a9 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Jul 2019 18:59:24 -0400 Subject: [PATCH 165/489] Reinstate except_cond{2,3} rules --- uncompyle6/semantics/consts.py | 4 +++- uncompyle6/semantics/customize.py | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 214b4e8f5..208134fda 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -409,7 +409,9 @@ 'tf_tryelsestmt': ( '%c%-%c%|else:\n%+%c', 1, 3, 4 ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ), 'except': ( '%|except:\n%+%c%-', 3 ), - 'except_cond1': ( '%|except %c:\n', 1 ), + 'except_cond1': ( '%|except %c:\n', (1, 'expr') ), + 'except_cond2': ( '%|except %c as %c:\n', + (1, 'expr'), (5, 'store') ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), # In Python 3.6, this is more complicated in the presence of "returns" diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index 5c18d325f..943b9ead7 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -57,6 +57,10 @@ def customize_for_version(self, is_pypy, version): from uncompyle6.semantics.customize3 import customize_for_version3 customize_for_version3(self, version) else: # < 3.0 + TABLE_DIRECT.update({ + 'except_cond3' : ( '%|except %c, %c:\n', + (1, 'expr'), (-2, 'store') ) + }) if 2.4 <= version <= 2.6: TABLE_DIRECT.update({ 'comp_for': ( ' for %c in %c', 3, 1 ), From e56088b56630b3a60679271365ae9632eae1956b Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Jul 2019 20:04:45 -0400 Subject: [PATCH 166/489] Need parens in unpack in 2.4ish --- uncompyle6/bin/uncompile.py | 2 +- uncompyle6/semantics/pysource.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index a66e22815..ac2181c10 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -88,7 +88,7 @@ def main_bin(): 'fragments verify verify-run version ' 'syntax-verify ' 'showgrammar encoding='.split(' ')) - except getopt.GetoptError(e): + except getopt.GetoptError, e: sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e)) sys.exit(-1) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 2e7dc9a76..72c97642e 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1827,9 +1827,15 @@ def n_unpack(self, node): self.write(', ') self.prune() return + for n in node[1:]: if n[0].kind == 'unpack': n[0].kind = 'unpack_w_parens' + + # In Python 2.4, unpack is used in (a, b, c) of: + # except RuntimeError, (a, b, c): + if self.version < 2.7: + node.kind = 'unpack_w_parens' self.default(node) n_unpack_w_parens = n_unpack From 43b19812449fdc27cc31288a944ddb49a17305c8 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 4 Jul 2019 10:24:08 -0400 Subject: [PATCH 167/489] Except for 2.4 --- uncompyle6/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 08eb45d9f..b689758a5 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -282,7 +282,7 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None, sys.stdout.write("\n") sys.stderr.write("\nLast file: %s " % (infile)) raise - except RuntimeError, e: + except RuntimeError(e): sys.stdout.write("\n%s\n" % str(e)) if str(e).startswith('Unsupported Python'): sys.stdout.write("\n") From fd7caf7f3f95f8b13dce2e948e1c1833300b5bba Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Aug 2019 21:58:57 -0400 Subject: [PATCH 168/489] Tweak runtests so it works on 2.6 --- test/stdlib/runtests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 1be8e7dda..122bc4d4f 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -188,6 +188,7 @@ fi mkdir $TESTDIR || exit $? cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR cd $TESTDIR/test +pyenv local $FULLVERSION export PYTHONPATH=$TESTDIR # Run tests From 2fb9b8f64da4683170b6451b1fcd071505bb4192 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Aug 2019 08:39:04 -0400 Subject: [PATCH 169/489] Remove 2.6.9 form older version. (Is newer?) --- admin-tools/pyenv-older-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/pyenv-older-versions b/admin-tools/pyenv-older-versions index 38d07ed8c..f2e792cbf 100644 --- a/admin-tools/pyenv-older-versions +++ b/admin-tools/pyenv-older-versions @@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='2.4.6 2.5.6 2.6.9' +export PYVERSIONS='2.4.6 2.5.6' From fcc4aff62ce573e6e7a4f6e373489e21724f0984 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Oct 2019 14:10:13 -0400 Subject: [PATCH 170/489] Try to fix up README.RsT --- README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 1e06befd5..b4d339d12 100644 --- a/README.rst +++ b/README.rst @@ -90,9 +90,8 @@ This uses setup.py, so it follows the standard Python routine: :: - pip install -e . # set up to run from source tree - # Or if you want to install instead - python setup.py install # may need sudo + pip install -e . + pip install -r requirements-dev.txt A GNU makefile is also provided so :code:`make install` (possibly as root or sudo) will do the steps above. From 93e26c73260b9a51a85ec6bef8ee06f5ee9f9ccb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 12 Oct 2019 20:08:12 -0400 Subject: [PATCH 171/489] Fragment merge hell --- uncompyle6/semantics/fragments.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 3e8debf8c..7e1f44d41 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1095,9 +1095,6 @@ def n_classdef(self, node): buildclass = node else: buildclass = node[0] -======= - buildclass = node if (node == "classdefdeco2") else node[0] ->>>>>>> master build_list = buildclass[1][0] if hasattr(buildclass[-3][0], "attr"): subclass = buildclass[-3][0].attr From d3acbe26418969c7386244e44212734b5582a734 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 10 Nov 2019 12:16:57 -0500 Subject: [PATCH 172/489] Merge hell --- test/Makefile | 2 +- uncompyle6/parsers/parse36.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Makefile b/test/Makefile index b75e4c9d5..22ada93b4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -100,7 +100,7 @@ check-bytecode-3: --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-pypy3.6 --bytecode-3.8 + --bytecode-pypy3.2 --bytecode-pypy3.6 #: Check deparsing on selected bytecode 3.x check-bytecode-3-short: diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 42fc9ec29..902933419 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -330,14 +330,14 @@ def custom_classfunc_rule(self, opname, token, customize, next_token, is_pypy): self.add_unique_rule(rule, token.kind, uniq_param, customize) self.add_unique_rule('expr ::= async_call', token.kind, uniq_param, customize) - if opname.startswith('CALL_FUNCTION_KW'): + if opname.startswith("CALL_FUNCTION_KW"): if is_pypy: # PYPY doesn't follow CPython 3.6 CALL_FUNCTION_KW conventions super(Python36Parser, self).custom_classfunc_rule(opname, token, customize, next_token, is_pypy) else: self.addRule("expr ::= call_kw36", nop_func) values = 'expr ' * token.attr - rule = "call_kw36 ::= expr {values} LOAD_CONST {opname}".format(**locals()) + rule = "call_kw36 ::= expr %s LOAD_CONST %s" % (values, opname) self.add_unique_rule(rule, token.kind, token.attr, customize) elif opname == 'CALL_FUNCTION_EX_KW': # Note: this doesn't exist in 3.7 and later From ecf6de26a07354a9789849706faf10ca9a51a617 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 18 Nov 2019 18:20:31 -0500 Subject: [PATCH 173/489] Add operator tests --- test/bytecode_2.4_run/15_mixed_expressions.pyc | Bin 0 -> 1254 bytes .../expression/15_mixed_expressions.py | 7 +++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 test/bytecode_2.4_run/15_mixed_expressions.pyc diff --git a/test/bytecode_2.4_run/15_mixed_expressions.pyc b/test/bytecode_2.4_run/15_mixed_expressions.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f70d6095f56e024158ac4360145ed19392c4b466 GIT binary patch literal 1254 zcmZ`&ZEF)j5T4!3OOrG)rfHMdTKb{lf%JOU5>N!INX0i=NkuRqN9pdtwrMWhZc6f1 ze~rJ#AK`cZK%BXpX>z6uH#a-aGtbP_P4Y)zD*TL4)AQGqpa zFRhR9D!fh@97^IoG*beVcrG=X%O;8}q7qNO2A5d~-{73;z7o99XDurj=Q)#`Q*@b0}D|@mtXaRpmyLK zK3iNd)<5s-4085n4zZhicZiNi)M`7f!hZ?W@5y9>KMp_~&w2-hkQ~+Xo-Wo?SpuvB zryW?H(^h#>ptIRUG=_}t2SYQAr0<*gL&u%!u{Nv7xseeK!pA;CQ^CNeubvm zJ7@1sPYjJ_6a%lcmXSg3aTJA-iOcuGb2F7QQA{1%6z|X>Iyo}bey2o+8np458snm; z)%Bn!eH{*?3%M^xgGg%XX5VZ3*J>n%e;d=zU>uh?B1!!oO_>+iRwl=qY@3yt&3D-@ d+qP(5WG#yGGNWA%_f7uKtH)lE)j9E|_AjGb%_IN- literal 0 HcmV?d00001 diff --git a/test/simple_source/expression/15_mixed_expressions.py b/test/simple_source/expression/15_mixed_expressions.py index 0ad66b7ef..6b21e4717 100644 --- a/test/simple_source/expression/15_mixed_expressions.py +++ b/test/simple_source/expression/15_mixed_expressions.py @@ -11,7 +11,10 @@ x = 1e300 assert 0.0 == x * 0 assert x * 1e300 == float("inf") -assert str(float("inf") * 0.0) == "nan" +if PYTHON_VERSION > 2.4: + assert str(float("inf") * 0.0) == "nan" +else: + assert str(float("inf") * 0.0) == "-nan" assert str(float("-inf") * 0.0) == "nan" assert -1e300 * 1e300 == float("-inf") @@ -26,7 +29,7 @@ x = 2 assert 4 / x == 2 -if PYTHON_VERSION >= 2.2: +if PYTHON_VERSION >= 2.19: x = 5 assert x / 2 == 2.5 x = 3 From 8cbdaecfc93b333ec576d996231a4730f47a0b83 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 04:06:34 -0500 Subject: [PATCH 174/489] Merge hell --- test/simple_source/expression/15_mixed_expressions.py | 1 - test/test_pythonlib.py | 4 ++-- uncompyle6/parsers/parse37.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/simple_source/expression/15_mixed_expressions.py b/test/simple_source/expression/15_mixed_expressions.py index 6b21e4717..641b67b7c 100644 --- a/test/simple_source/expression/15_mixed_expressions.py +++ b/test/simple_source/expression/15_mixed_expressions.py @@ -15,7 +15,6 @@ assert str(float("inf") * 0.0) == "nan" else: assert str(float("inf") * 0.0) == "-nan" -assert str(float("-inf") * 0.0) == "nan" assert -1e300 * 1e300 == float("-inf") # Complex (adapted from 02_complex.py) diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 9d054c23a..19fe6eb0b 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -192,8 +192,8 @@ def file_matches(files, root, basenames, patterns): pass print(time.ctime()) - print("Source directory: ", src_dir) - print("Output directory: ", target_dir) + print "Source directory: ", src_dir + print "Output directory: ", target_dir try: _, _, failed_files, failed_verify = main( src_dir, target_dir, files, [], do_verify=opts["do_verify"] diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index cde36dd89..3f348c37d 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -1208,7 +1208,7 @@ def custom_classfunc_rule(self, opname, token, customize, next_token): if opname.startswith("CALL_FUNCTION_KW"): self.addRule("expr ::= call_kw36", nop_func) values = "expr " * token.attr - rule = "call_kw36 ::= expr {values} LOAD_CONST {opname}".format(**locals()) + rule = "call_kw36 ::= expr %s LOAD_CONST %s" % (values, opname) self.add_unique_rule(rule, token.kind, token.attr, customize) elif opname == "CALL_FUNCTION_EX_KW": # Note: this doesn't exist in 3.7 and later From c77d9233f02f3587eca3e8ae1b3a1e6eed7ae51c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 04:27:22 -0500 Subject: [PATCH 175/489] CircleCI/PIP woes with Python 2.4 --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26f411580..7a9182966 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,6 +45,7 @@ jobs: - v2-dependencies- # This is based on your 1.0 configuration file or project settings + - run: easy_install xdis spark-parser - run: pip install -e . - run: pip install -r requirements-dev.txt From 1c943a465a97c5365abc4ff5f7f8327d308f62e1 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 04:27:22 -0500 Subject: [PATCH 176/489] CircleCI/PIP woes with Python 2.4 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26f411580..2b2bf6c6f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,8 +45,8 @@ jobs: - v2-dependencies- # This is based on your 1.0 configuration file or project settings + - run: easy_install xdis spark-parser - run: pip install -e . - - run: pip install -r requirements-dev.txt # Save dependency cache - save_cache: From 827bd32a67f5d618053003bb68e513d94ba6b342 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 05:57:50 -0500 Subject: [PATCH 177/489] was not handling 2.4 "if not"... As the late Danny Gumport used to say: "not"'s can turn you into knots. Also go over 2.4 runtest failures --- .../bytecode_2.4_run/15_mixed_expressions.pyc | Bin 1254 -> 1216 bytes .../expression/15_mixed_expressions.py | 2 +- test/stdlib/runtests.sh | 12 +++++++++--- uncompyle6/semantics/customize.py | 4 +++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/bytecode_2.4_run/15_mixed_expressions.pyc b/test/bytecode_2.4_run/15_mixed_expressions.pyc index f70d6095f56e024158ac4360145ed19392c4b466..7216d13988748ce54740a88e1d49670423c23839 100644 GIT binary patch delta 134 zcmaFHd4N+o_Y*JIe8qRM$qZ1y45S?t7#NCMCrY2#@y(XZ){J6aKv`ZUPDU9PHbx0X QIYwSa4JH-F$sH^f02-hjFaQ7m diff --git a/test/simple_source/expression/15_mixed_expressions.py b/test/simple_source/expression/15_mixed_expressions.py index 641b67b7c..29995f1a7 100644 --- a/test/simple_source/expression/15_mixed_expressions.py +++ b/test/simple_source/expression/15_mixed_expressions.py @@ -11,7 +11,7 @@ x = 1e300 assert 0.0 == x * 0 assert x * 1e300 == float("inf") -if PYTHON_VERSION > 2.4: +if PYTHON_VERSION > 2.41: assert str(float("inf") * 0.0) == "nan" else: assert str(float("inf") * 0.0) == "-nan" diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 62e8db59f..a26a96f79 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -34,10 +34,16 @@ case $PYVERSION in SKIP_TESTS=( [test_dis.py]=1 # We change line numbers - duh! [test_grp.py]=1 # Long test - might work Control flow? - [test_pwd.py]=1 # Long test - might work? Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? + [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else + [test_pwd.py]=1 # Long test - might work? Control flow? + [test_pyexpat.py]=1 # Investigate [test_queue.py]=1 # Control flow? - # [test_threading.py]=1 # Long test - works + [test_re.py]=1 # try confused with try-else again + [test_threading.py]=1 # Line numbers are expected to be different + [test_thread.py]=1 # test takes too long to run: 36 seconds + [test_trace.py]=1 # Long test - works + [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) ;; 2.5) @@ -49,7 +55,7 @@ case $PYVERSION in [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? + [test_re.py]=1 # Possibly try confused with try-else again [test_trace.py]=1 # Line numbers are expected to be different [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index fe3c56884..99b642c49 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -71,6 +71,9 @@ def customize_for_version(self, is_pypy, version): TABLE_DIRECT.update( {"except_cond3": ("%|except %c, %c:\n", (1, "expr"), (-2, "store"))} ) + if version <= 2.6: + TABLE_DIRECT["testtrue_then"] = TABLE_DIRECT["testtrue"] + if 2.4 <= version <= 2.6: TABLE_DIRECT.update({"comp_for": (" for %c in %c", 3, 1)}) else: @@ -134,7 +137,6 @@ def customize_for_version(self, is_pypy, version): } ) if version == 2.4: - def n_iftrue_stmt24(node): self.template_engine(("%c", 0), node) self.default(node) From dfac71e092ca0a2e2b98d015fdcd2817919d0761 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 06:06:20 -0500 Subject: [PATCH 178/489] Exclude one more test for time.. This saves CircleCI 40 seconds in elapsed time --- test/stdlib/runtests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index a26a96f79..756eba863 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -40,6 +40,7 @@ case $PYVERSION in [test_pyexpat.py]=1 # Investigate [test_queue.py]=1 # Control flow? [test_re.py]=1 # try confused with try-else again + [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # Line numbers are expected to be different [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Long test - works From 1c8f885629fe87269dab1446afb480ca1bbafa10 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 06:53:40 -0500 Subject: [PATCH 179/489] 2.5 bugs... Handling "with" Go over 2.5 runtests.sh exclusions --- test/stdlib/runtests.sh | 11 ++++++++++- uncompyle6/main.py | 2 +- uncompyle6/parsers/parse25.py | 12 +++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 756eba863..acb1cb929 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -35,8 +35,8 @@ case $PYVERSION in [test_dis.py]=1 # We change line numbers - duh! [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? - [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else [test_pwd.py]=1 # Long test - might work? Control flow? + [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else [test_pyexpat.py]=1 # Investigate [test_queue.py]=1 # Control flow? [test_re.py]=1 # try confused with try-else again @@ -54,9 +54,17 @@ case $PYVERSION in [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_pep247.py]=1 # "assert xxx or .." not detected properly in check_hash_module() + [test_pep352.py]=1 # try confused with try-else again; in test_inheritance() [test_pwd.py]=1 # Long test - might work? Control flow? + [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else [test_queue.py]=1 # Control flow? [test_re.py]=1 # Possibly try confused with try-else again + [test_struct.py]=1 # "if and" confused for if .. assert and + [test_sys.py]=1 # try confused with try-else again; in test_current_frames() + [test_tarfile.py]=1 # try confused with try-else again; top-level import + [test_threading.py]=1 # Line numbers are expected to be different + [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) @@ -101,6 +109,7 @@ case $PYVERSION in [test_re.py]=1 # Probably Control flow? [test_queue.py]=1 # Control flow? [test_trace.py]=1 # Line numbers are expected to be different + [test_urllib2net.py]=1 # Fails on its own. May need interactive input [test_zipfile64.py]=1 # Skip Long test [test_zlib.py]=1 # Takes too long to run (more than 3 minutes 39 seconds) # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 102d2035a..389decb9c 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -243,7 +243,7 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None, else: buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) - if PYTHON_VERSION > 2.5: + if PYTHON_VERSION > 2.6: tee = subprocess.Popen(["tee", current_outfile], stdin=subprocess.PIPE) os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 07912378f..9f873e13a 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -28,11 +28,17 @@ def p_misc25(self, args): setupwithas ::= DUP_TOP LOAD_ATTR store LOAD_ATTR CALL_FUNCTION_0 setup_finally # opcode SETUP_WITH - setupwith ::= DUP_TOP LOAD_ATTR STORE_NAME LOAD_ATTR CALL_FUNCTION_0 POP_TOP - withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt - POP_BLOCK LOAD_CONST COME_FROM with_cleanup + setupwith ::= DUP_TOP LOAD_ATTR store LOAD_ATTR CALL_FUNCTION_0 POP_TOP + withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM with_cleanup + + # Semantic actions want store to be at index 2 + withasstmt ::= expr setupwithas store suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM with_cleanup + store ::= STORE_NAME + store ::= STORE_FAST # tryelsetmtl doesn't need COME_FROM since the jump might not # be the the join point at the end of the "try" but instead back to the From a73ca4bf186561219d312532fd35768c9a8dc177 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 14:03:52 -0500 Subject: [PATCH 180/489] Start better try/else detection --- test/stdlib/runtests.sh | 3 ++- uncompyle6/parsers/parse2.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index acb1cb929..3e74384c1 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -105,8 +105,9 @@ case $PYVERSION in [test_generators.py]=1 [test_grp.py]=1 # Long test - might work Control flow? [test_opcodes.py]=1 + [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else [test_pwd.py]=1 # Long test - might work? Control flow? - [test_re.py]=1 # Probably Control flow? + [test_re.py]=1 # try confused with try-else again [test_queue.py]=1 # Control flow? [test_trace.py]=1 # Line numbers are expected to be different [test_urllib2net.py]=1 # Fails on its own. May need interactive input diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 1c008a5b2..ffb7e3ade 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -637,6 +637,8 @@ def customize_grammar_rules(self, tokens, customize): self.check_reduce["raise_stmt1"] = "tokens" self.check_reduce["assert_expr_and"] = "AST" + self.check_reduce["tryelsestmt"] = "AST" + self.check_reduce["tryelsestmtl"] = "AST" self.check_reduce["aug_assign2"] = "AST" self.check_reduce["or"] = "AST" # self.check_reduce['_stmts'] = 'AST' @@ -672,6 +674,33 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): elif lhs in ("delete_subscript", "del_expr"): op = ast[0][0] return op.kind in ("and", "or") + elif lhs in ("tryelsestmt", "tryelsetmtl"): + # Check the end of the except handler that there isn't a jump from + # inside the except handler to the end. If that happens + # then this is a "try" with no "else". + except_handler = ast[3] + if except_handler == "except_handler": + + come_from = except_handler[-1] + # We only care about the *first* come_from because that is the + # the innermost one. So if the "tryelse" is invalid (should be a "try") + # ti will be invalid here. + if come_from == "COME_FROM": + first_come_from = except_handler[-1] + else: + assert come_from == "come_froms" + first_come_from = come_from[0] + leading_jump = except_handler[0] + + # We really don't care that this is a jump per-se. But + # we could also check that this jumps to the end of the except if + # desired. + if isinstance(leading_jump, SyntaxTree): + except_handler_first_offset = leading_jump.first_child().off2int() + else: + except_handler_first_offset = leading_jump.off2int() + return first_come_from.attr > except_handler_first_offset + return False From 120bdaedb98a3cfdc9621310631522e1df2bc4a8 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 14:08:02 -0500 Subject: [PATCH 181/489] Bump xdis version --- __pkginfo__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 8c641ddd8..60ec15738 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -58,7 +58,7 @@ ]} ftp_url = None install_requires = ["spark-parser >= 1.8.9, < 1.9.0", - "xdis >= 4.1.3, < 4.2.0"] + "xdis >= 4.2.0, < 4.3.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" From ddaa7ef3374e91e5eb98ec3eb27fd38b5bdcd026 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 9 Dec 2019 16:29:43 -0500 Subject: [PATCH 182/489] Fix 2.x false tryelsestmtl detection... reinstate lots of stdlib tests which are fixed by this change. --- test/stdlib/runtests.sh | 65 ++++++------------------------------ uncompyle6/parsers/parse2.py | 2 +- 2 files changed, 12 insertions(+), 55 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 3e74384c1..a997e3652 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -36,10 +36,8 @@ case $PYVERSION in [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? - [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else - [test_pyexpat.py]=1 # Investigate - [test_queue.py]=1 # Control flow? - [test_re.py]=1 # try confused with try-else again + [test_pyclbr.py]=1 # Investigate + [test_re.py]=1 # Investigate produces a Python syntax error [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # Line numbers are expected to be different [test_thread.py]=1 # test takes too long to run: 36 seconds @@ -49,20 +47,15 @@ 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_pep247.py]=1 # "assert xxx or .." not detected properly in check_hash_module() - [test_pep352.py]=1 # try confused with try-else again; in test_inheritance() + [test_pep352.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? - [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else - [test_queue.py]=1 # Control flow? - [test_re.py]=1 # Possibly try confused with try-else again + [test_pyclbr.py]=1 # Investigate [test_struct.py]=1 # "if and" confused for if .. assert and - [test_sys.py]=1 # try confused with try-else again; in test_current_frames() - [test_tarfile.py]=1 # try confused with try-else again; top-level import [test_threading.py]=1 # Line numbers are expected to be different [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different @@ -71,44 +64,16 @@ case $PYVERSION in ;; 2.6) SKIP_TESTS=( - [test_aepack.py]=1 - [test_aifc.py]=1 - [test_array.py]=1 - [test_audioop.py]=1 - [test_base64.py]=1 - [test_bigmem.py]=1 - [test_binascii.py]=1 - [test_builtin.py]=1 - [test_bytes.py]=1 - [test_class.py]=1 - [test_codeccallbacks.py]=1 - [test_codecencodings_cn.py]=1 - [test_codecencodings_hk.py]=1 - [test_codecencodings_jp.py]=1 - [test_codecencodings_kr.py]=1 - [test_codecencodings_tw.py]=1 - [test_codecencodings_cn.py]=1 - [test_codecmaps_hk.py]=1 - [test_codecmaps_jp.py]=1 - [test_codecmaps_kr.py]=1 - [test_codecmaps_tw.py]=1 - [test_codecs.py]=1 + [test_aepack.py]=1 # Fails on its own + [test_codeccallbacks.py]=1 # Fails on its own [test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't - [test_cookielib.py]=1 - [test_copy.py]=1 - [test_decimal.py]=1 - [test_descr.py]=1 # Problem in pickle.py? [test_exceptions.py]=1 - [test_extcall.py]=1 - [test_float.py]=1 - [test_future4.py]=1 - [test_generators.py]=1 + [test_generators.py]=1 # Investigate [test_grp.py]=1 # Long test - might work Control flow? - [test_opcodes.py]=1 - [test_pyclbr.py]=1 # Bug in checkModule()/ismethod() try confused for try-else + [test_pep352.py]=1 # Investigate + [test_pprint.py]=1 + [test_pyclbr.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? - [test_re.py]=1 # try confused with try-else again - [test_queue.py]=1 # Control flow? [test_trace.py]=1 # Line numbers are expected to be different [test_urllib2net.py]=1 # Fails on its own. May need interactive input [test_zipfile64.py]=1 # Skip Long test @@ -122,8 +87,6 @@ case $PYVERSION in # .pyenv/versions/2.6.9/lib/python2.6/tabnanny.pyc # .pyenv/versions/2.6.9/lib/python2.6/tarfile.pyc - # Not getting set by bach below? - [test_pprint.py]=1 ) if (( batch )) ; then @@ -159,7 +122,7 @@ case $PYVERSION in [test_generators.py]=1 # control flow. uncompyle2 has problem here too [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # test takes to long, works interactively though - [test_hashlib.py]=1 # Investiage + [test_hashlib.py]=1 # Investigate [test_io.py]=1 # Test takes too long to run [test_ioctl.py]=1 # Test takes too long to run [test_long.py]=1 @@ -168,26 +131,20 @@ case $PYVERSION in [test_memoryio.py]=1 # FIX [test_modulefinder.py]=1 # FIX [test_multiprocessing.py]=1 # On uncompyle2, takes 24 secs - [test_pep352.py]=1 # ? [test_posix.py]=1 # Bug in try-else detection inside test_initgroups() # Deal with when we have better flow-control detection [test_pwd.py]=1 # Takes too long [test_pty.py]=1 - [test_queue.py]=1 # Control flow? - [test_re.py]=1 # Probably Control flow? [test_runpy.py]=1 # Long and fails on its own [test_select.py]=1 # Runs okay but takes 11 seconds [test_socket.py]=1 # Runs ok but takes 22 seconds [test_subprocess.py]=1 # Runs ok but takes 22 seconds [test_sys_setprofile.py]=1 [test_sys_settrace.py]=1 # Line numbers are expected to be different - [test_strtod.py]=1 # FIX [test_traceback.py]=1 # Line numbers change - duh. - [test_types.py]=1 # try/else confusions [test_unicode.py]=1 # Too long to run 11 seconds [test_xpickle.py]=1 # Runs ok but takes 72 seconds [test_zipfile64.py]=1 # Runs ok but takes 204 seconds - [test_zipimport.py]=1 # We can't distinguish try from try/else yet ) if (( batch )) ; then # Fails in crontab environment? diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index ffb7e3ade..b7ee65689 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -674,7 +674,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): elif lhs in ("delete_subscript", "del_expr"): op = ast[0][0] return op.kind in ("and", "or") - elif lhs in ("tryelsestmt", "tryelsetmtl"): + elif lhs in ("tryelsestmt", "tryelsestmtl"): # Check the end of the except handler that there isn't a jump from # inside the except handler to the end. If that happens # then this is a "try" with no "else". From ab4a9988672af017ce5e66cd1389eeb4e7b16eea Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 10 Dec 2019 16:13:46 -0500 Subject: [PATCH 183/489] Merge hell --- test/stdlib/runtests.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index b9ebc8877..588d4aa74 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -37,13 +37,10 @@ case $PYVERSION in [test_pep247.py]=1 # Long test - might work? Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate -<<<<<<< HEAD [test_re.py]=1 # Investigate produces a Python syntax error -======= [test_pyexpat.py]=1 # Investigate [test_queue.py]=1 # Control flow? [test_re.py]=1 # try confused with try-else again ->>>>>>> master [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # Line numbers are expected to be different [test_thread.py]=1 # test takes too long to run: 36 seconds @@ -61,15 +58,7 @@ case $PYVERSION in [test_pep352.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate -<<<<<<< HEAD [test_struct.py]=1 # "if and" confused for if .. assert and -======= - [test_queue.py]=1 # Control flow? - [test_re.py]=1 # Possibly try confused with try-else again - [test_struct.py]=1 # "if and" confused for if .. assert and - [test_sys.py]=1 # try confused with try-else again; in test_current_frames() - [test_tarfile.py]=1 # try confused with try-else again; top-level import ->>>>>>> master [test_threading.py]=1 # Line numbers are expected to be different [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different From 1f1a7345980b48cb598ea4dae38d8da6ddc17725 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 Dec 2019 18:11:32 -0500 Subject: [PATCH 184/489] Update runtest.sh tests that fail --- test/stdlib/runtests.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index ed5a99abc..00562fb2c 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -37,12 +37,8 @@ case $PYVERSION in [test_pep247.py]=1 # Long test - might work? Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate - [test_re.py]=1 # Investigate produces a Python syntax error - [test_pyexpat.py]=1 # Investigate - [test_queue.py]=1 # Control flow? - [test_re.py]=1 # try confused with try-else again [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds - [test_threading.py]=1 # Line numbers are expected to be different + [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Long test - works [test_zipfile64.py]=1 # Runs ok but takes 204 seconds @@ -59,7 +55,7 @@ case $PYVERSION in [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate [test_struct.py]=1 # "if and" confused for if .. assert and - [test_threading.py]=1 # Line numbers are expected to be different + [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different [test_zipfile64.py]=1 # Runs ok but takes 204 seconds From de4a15a5b3193e1e5a00e2644cb382d430dfd676 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 Dec 2019 19:48:33 -0500 Subject: [PATCH 185/489] Extend "and" reduction test to Python 2.4 --- uncompyle6/parsers/parse26.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 2d91e9ade..f85d8f45d 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -341,8 +341,7 @@ def customize_grammar_rules(self, tokens, customize): WITH_CLEANUP END_FINALLY """) super(Python26Parser, self).customize_grammar_rules(tokens, customize) - if self.version >= 2.6: - self.check_reduce['and'] = 'AST' + self.check_reduce['and'] = 'AST' self.check_reduce['assert_expr_and'] = 'AST' self.check_reduce['list_for'] = 'AST' self.check_reduce['try_except'] = 'tokens' @@ -380,6 +379,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # or that it jumps to the same place as the end of "and" jmp_false = ast[1][0] jmp_target = jmp_false.offset + jmp_false.attr + 3 + return not (jmp_target == tokens[test_index].offset or tokens[last].pattr == jmp_false.pattr) elif rule == ( From e82a37528de9326e3b52b228dfae684e9c38e19a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 15 Dec 2019 10:54:42 -0500 Subject: [PATCH 186/489] Administrivia: improve setup scripts --- admin-tools/setup-master.sh | 1 + admin-tools/setup-python-2.4.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index e0e5eb20a..4d13c0a63 100644 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -20,3 +20,4 @@ cd $fulldir/.. (cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ git checkout master && pyenv local $PYTHON_VERSION && git pull cd $owd +rm -v */.python-version || true diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 5226f9d29..7f4495da6 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -14,3 +14,4 @@ cd $fulldir/.. (cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull cd $owd +rm -v */.python-version || true From 747ec0d0bce6129fe714a51e19f0cdeb38345fa2 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 23 Dec 2019 11:11:07 -0500 Subject: [PATCH 187/489] "make check-short" now works --- admin-tools/check-older-versions.sh | 3 ++- uncompyle6/util.py | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/admin-tools/check-older-versions.sh b/admin-tools/check-older-versions.sh index 603c79207..3252e3f43 100644 --- a/admin-tools/check-older-versions.sh +++ b/admin-tools/check-older-versions.sh @@ -20,8 +20,9 @@ for version in $PYVERSIONS; do exit $? fi make clean && python setup.py develop - if ! make check ; then + if ! make check-short ; then exit $? fi echo === $version === done +make check diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 12a60175b..a8ec659e6 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -2,11 +2,9 @@ # Until such time it is fixed, we'll do a better. # More could be done here though. -from math import copysign - def is_negative_zero(n): """Returns true if n is -0.0""" - return n == 0.0 and copysign(1, n) == -1 + return n == 0.0 # and copysign(1, n) == -1 def better_repr(v): """Work around Python's unorthogonal and unhelpful repr() for primitive float From 2f9284c3a0f7a13e4f4e4b284d904f886a2d2bad Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 24 Dec 2019 12:50:44 -0500 Subject: [PATCH 188/489] Administrative change --- admin-tools/how-to-make-a-release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index e0cb786f0..dfd460dcd 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -55,7 +55,7 @@ # Make packages and tag $ . ./admin-tools/make-dist-older.sh - $ pyenv local 3.8.0 + $ pyenv local 3.8.1 $ twine check dist/uncompyle6-$VERSION* $ git tag release-python-2.4-$VERSION $ . ./admin-tools/make-dist-newer.sh From 37b7a4b0b6a12ac40cb30b0a4d0fb0e941a7b107 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 5 Jan 2020 18:07:13 -0500 Subject: [PATCH 189/489] Merge hell --- uncompyle6/semantics/helper.py | 17 +++++++++++++++++ uncompyle6/semantics/make_function2.py | 10 +++------- uncompyle6/semantics/make_function36.py | 15 +++++++-------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/uncompyle6/semantics/helper.py b/uncompyle6/semantics/helper.py index 3b048936d..1fbde6497 100644 --- a/uncompyle6/semantics/helper.py +++ b/uncompyle6/semantics/helper.py @@ -5,11 +5,28 @@ from uncompyle6 import PYTHON3 if PYTHON3: + from itertools import zip_longest minint = -sys.maxsize-1 maxint = sys.maxsize else: minint = -sys.maxint-1 maxint = sys.maxint + try: + from itertools import izip_longest as zip_longest + except: + from itertools import (chain, izip, repeat) + def zip_longest(*args, **kwds): + # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- + fillvalue = kwds.get('fillvalue') + def sentinel(counter = ([fillvalue]*(len(args)-1)).pop): + yield counter() # yields the fillvalue, or raises IndexError + fillers = repeat(fillvalue) + iters = [chain(it, sentinel(), fillers) for it in args] + try: + for tup in izip(*iters): + yield tup + except IndexError: + pass read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL')) read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL')) diff --git a/uncompyle6/semantics/make_function2.py b/uncompyle6/semantics/make_function2.py index 10fd0e877..3fd028937 100644 --- a/uncompyle6/semantics/make_function2.py +++ b/uncompyle6/semantics/make_function2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2019 by Rocky Bernstein +# Copyright (c) 2015-2020 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # # This program is free software: you can redistribute it and/or modify @@ -28,13 +28,9 @@ find_all_globals, find_globals_and_nonlocals, find_none, + zip_longest ) -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest - from uncompyle6.show import maybe_show_tree_param_default def make_function2(self, node, is_lambda, nested=1, code_node=None): @@ -104,7 +100,7 @@ def build_param(ast, name, default): is_lambda=is_lambda, noneInNames=("None" in code.co_names), ) - except (ParserError, ParserError2) as p: + except ParserError, p: self.write(str(p)) if not self.tolerate_errors: self.ERROR = p diff --git a/uncompyle6/semantics/make_function36.py b/uncompyle6/semantics/make_function36.py index 97d3baa45..b23e0a127 100644 --- a/uncompyle6/semantics/make_function36.py +++ b/uncompyle6/semantics/make_function36.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019 by Rocky Bernstein +# Copyright (c) 2019-2020 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,13 +27,9 @@ find_all_globals, find_globals_and_nonlocals, find_none, + zip_longest ) -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest - from uncompyle6.show import maybe_show_tree_param_default @@ -213,7 +209,7 @@ def build_param(ast, name, default, annotation=None): is_lambda=is_lambda, noneInNames=("None" in code.co_names), ) - except (ParserError, ParserError2) as p: + except ParserError, p: self.write(str(p)) if not self.tolerate_errors: self.ERROR = p @@ -300,7 +296,10 @@ def build_param(ast, name, default, annotation=None): # optional docstring # LOAD_CONST qualified name, # LOAD_CONST code object - index = -5 if node[-2] == "docstring" else -4 + if node[-2] == "docstring": + index = -5 + else: + index = -4 if fn_bits[-1]: index -= 1 if fn_bits[-2]: From e07e2a498ef81a6b334f40c4d7575bbbc4f38df1 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 5 Jan 2020 21:04:42 -0500 Subject: [PATCH 190/489] 2.x if vs ifelse reduction-rule testing --- test/stdlib/runtests.sh | 2 +- uncompyle6/parsers/parse2.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index e347672a6..6e2a43209 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -32,11 +32,11 @@ typeset -A SKIP_TESTS case $PYVERSION in 2.4) SKIP_TESTS=( + [test_decimal.py]=1 # [test_dis.py]=1 # We change line numbers - duh! [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? - [test_pyclbr.py]=1 # Investigate [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 6089b296f..66be0c71b 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -641,6 +641,7 @@ def customize_grammar_rules(self, tokens, customize): self.check_reduce["tryelsestmtl"] = "AST" self.check_reduce["aug_assign2"] = "AST" self.check_reduce["or"] = "AST" + self.check_reduce["ifstmt"] = "tokens" # self.check_reduce['_stmts'] = 'AST' # Dead code testing... @@ -665,6 +666,14 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): jmp_false = ast[1] jump_target = jmp_false[0].attr return jump_target > tokens[last].off2int() + elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): + for i in range(last-1, last-4, -1): + t = tokens[i] + if t == "JUMP_FORWARD": + return t.attr > tokens[min(last, len(tokens)-1)].off2int() + elif t not in ("POP_TOP", "COME_FROM"): + break + pass 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)) From eefe7bdb6ba90a695b3c5b70956a9f75de0ecbc8 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 5 Jan 2020 21:24:21 -0500 Subject: [PATCH 191/489] runtests.sh update --- test/stdlib/runtests.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 6e2a43209..0b3c2d14b 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -34,6 +34,8 @@ case $PYVERSION in SKIP_TESTS=( [test_decimal.py]=1 # [test_dis.py]=1 # We change line numbers - duh! + [test_generators.py]=1 # Investigate - botched if/elif control flow badly + [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? [test_pwd.py]=1 # Long test - might work? Control flow? @@ -54,7 +56,11 @@ case $PYVERSION in [test_pep352.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate + [test_queue.py]=1 # Control flow? + [test_re.py]=1 # Possibly try confused with try-else again [test_struct.py]=1 # "if and" confused for if .. assert and + [test_sys.py]=1 # try confused with try-else again; in test_current_frames() + [test_tarfile.py]=1 # try confused with try-else again; top-level import [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different @@ -131,6 +137,7 @@ case $PYVERSION in [test_unicode.py]=1 # Too long to run 11 seconds [test_xpickle.py]=1 # Runs ok but takes 72 seconds [test_zipfile64.py]=1 # Runs ok but takes 204 seconds + [test_zipimport.py]=1 # FIXME: improper try from try/else ? ) if (( batch )) ; then # Fails in crontab environment? From 78c4db722a5a70b88d2498990864e127033b2e5b Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Jan 2020 04:42:23 -0500 Subject: [PATCH 192/489] Python 2.4- doesn't have condition expresions --- uncompyle6/parsers/parse21.py | 5 +---- uncompyle6/parsers/parse24.py | 9 ++++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse21.py b/uncompyle6/parsers/parse21.py index 34c5c0d96..07bf5ac75 100644 --- a/uncompyle6/parsers/parse21.py +++ b/uncompyle6/parsers/parse21.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017 Rocky Bernstein +# Copyright (c) 2016-2017, 2020 Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG @@ -19,9 +19,6 @@ def p_forstmt21(self, args): for ::= SETUP_LOOP expr for_iter store l_stmts_opt _jump_back POP_BLOCK COME_FROM - - expr ::= conditional - conditional ::= expr jmp_false expr JUMP_ABSOLUTE expr """ def p_import21(self, args): diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 8d453a961..7795b7aef 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2018 Rocky Bernstein +# Copyright (c) 2016-2018, 2020 Rocky Bernstein """ spark grammar differences over Python2.5 for Python 2.4. """ @@ -56,6 +56,12 @@ def p_misc24(self, args): kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR ''' + def remove_rules_24(self): + self.remove_rules(""" + expr ::= conditional + """) + + def customize_grammar_rules(self, tokens, customize): self.remove_rules(""" gen_comp_body ::= expr YIELD_VALUE POP_TOP @@ -72,6 +78,7 @@ def customize_grammar_rules(self, tokens, customize): stmt ::= withasstmt """) super(Python24Parser, self).customize_grammar_rules(tokens, customize) + self.remove_rules_24() if self.version == 2.4: self.check_reduce['nop_stmt'] = 'tokens' From 9df8dd738433f008a67bb9648b6f5d4fb4d4fa2e Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Jan 2020 23:32:36 -0500 Subject: [PATCH 193/489] Go over 2.5 for reduction rules and tests --- test/stdlib/runtests.sh | 19 ++++++++++++++----- uncompyle6/parsers/parse2.py | 17 +++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 318d97e65..35ef669b8 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -34,7 +34,7 @@ case $PYVERSION in SKIP_TESTS=( [test_decimal.py]=1 # [test_dis.py]=1 # We change line numbers - duh! - [test_generators.py]=1 # Investigate - botched if/elif control flow badly + [test_generators.py]=1 # Investigate [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? @@ -48,37 +48,46 @@ case $PYVERSION in ;; 2.5) SKIP_TESTS=( + [test_coercion.py]=1 + [test_decimal.py]=1 [test_dis.py]=1 # We change line numbers - duh! + [test_generators.py]=1 # Investigate [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_pep247.py]=1 # "assert xxx or .." not detected properly in check_hash_module() [test_pep352.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate [test_queue.py]=1 # Control flow? - [test_re.py]=1 # Possibly try confused with try-else again + [test_socketserver.py]=1 # Too long to run - 42 seconds [test_struct.py]=1 # "if and" confused for if .. assert and - [test_sys.py]=1 # try confused with try-else again; in test_current_frames() - [test_tarfile.py]=1 # try confused with try-else again; top-level import [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different + [test_urllib2net.py]=1 # is interactive? [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) ;; 2.6) SKIP_TESTS=( [test_aepack.py]=1 # Fails on its own + [test_cmath.py]=1 # Investigate: probably fixable like in later versions + [test_coercion.py]=1 [test_codeccallbacks.py]=1 # Fails on its own [test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't + [test_dis.py]=1 # We change line numbers - duh! [test_exceptions.py]=1 + [test_float.py]=1 # Investigate: probably fixable like in later versions + [test_generators.py]=1 # Investigate [test_grp.py]=1 # Long test - might work Control flow? + [test_itertools.py]=1 # complex numbers. Fix as we do in later versions + [test_math.py]=1 # Probably fixable like later versions [test_pep352.py]=1 # Investigate [test_pprint.py]=1 [test_pyclbr.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_trace.py]=1 # Line numbers are expected to be different + [test_types.py]=1 # Probably fixable like later versions [test_urllib2net.py]=1 # Fails on its own. May need interactive input [test_zipfile64.py]=1 # Skip Long test [test_zlib.py]=1 # Takes too long to run (more than 3 minutes 39 seconds) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 2d7d912f4..034b0c551 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -705,12 +705,14 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): pass pass elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): - for i in range(last-1, last-4, -1): - t = tokens[i] - if t == "JUMP_FORWARD": - return t.attr > tokens[min(last, len(tokens)-1)].off2int() - elif t not in ("POP_TOP", "COME_FROM"): - break + # FIXME: move this into 2.7-specific code? + if self.version == 2.7: + for i in range(last-1, last-4, -1): + t = tokens[i] + if t == "JUMP_FORWARD": + return t.attr > tokens[min(last, len(tokens)-1)].off2int() + elif t not in ("POP_TOP", "COME_FROM"): + break pass elif lhs in ("raise_stmt1",): # We will assume 'LOAD_ASSERT' will be handled by an assert grammar rule @@ -734,9 +736,12 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # ti will be invalid here. if come_from == "COME_FROM": first_come_from = except_handler[-1] + elif come_from == "END_FINALLY": + return False else: assert come_from == "come_froms" first_come_from = come_from[0] + leading_jump = except_handler[0] # We really don't care that this is a jump per-se. But From 773bbdab0a37ee2906f922a12e4a588d2c607461 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Jan 2020 04:37:28 -0500 Subject: [PATCH 194/489] Use copysign in 2.6 nuke -0.0 test if < 2.6 --- pytest/test_grammar.py | 3 +++ test/stdlib/runtests.sh | 17 +++++----------- uncompyle6/parsers/parse2.py | 37 ++++++++++++++++++++++++----------- uncompyle6/parsers/parse27.py | 35 ++++++++++----------------------- uncompyle6/util.py | 12 +++++++++--- 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index f20cfacd5..0b6bd7e00 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -42,6 +42,9 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("kvlist") expect_lhs.add("kv3") unused_rhs.add("dict") + else: + # NOTE: this may disappear + expect_lhs.add("except_handler_else") if PYTHON3: expect_lhs.add("load_genexpr") diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 35ef669b8..65f8f1763 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -71,26 +71,16 @@ case $PYVERSION in 2.6) SKIP_TESTS=( [test_aepack.py]=1 # Fails on its own - [test_cmath.py]=1 # Investigate: probably fixable like in later versions - [test_coercion.py]=1 - [test_codeccallbacks.py]=1 # Fails on its own [test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't [test_dis.py]=1 # We change line numbers - duh! - [test_exceptions.py]=1 - [test_float.py]=1 # Investigate: probably fixable like in later versions [test_generators.py]=1 # Investigate [test_grp.py]=1 # Long test - might work Control flow? - [test_itertools.py]=1 # complex numbers. Fix as we do in later versions - [test_math.py]=1 # Probably fixable like later versions [test_pep352.py]=1 # Investigate - [test_pprint.py]=1 [test_pyclbr.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_trace.py]=1 # Line numbers are expected to be different - [test_types.py]=1 # Probably fixable like later versions - [test_urllib2net.py]=1 # Fails on its own. May need interactive input [test_zipfile64.py]=1 # Skip Long test - [test_zlib.py]=1 # Takes too long to run (more than 3 minutes 39 seconds) + [test_zlib.py]=1 # # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc # .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc ) @@ -362,7 +352,10 @@ for file in $files; do # If the fails *before* decompiling, skip it! typeset -i STARTTIME=$(date +%s) - if ! python $file >/dev/null 2>&1 ; then + if [ ! -r $file ]; then + echo "Skipping test $file -- not readable. Does it exist?" + continue + elif ! python $file >/dev/null 2>&1 ; then echo "Skipping test $file -- it fails on its own" continue fi diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 034b0c551..58f35c6ee 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -646,6 +646,7 @@ def customize_grammar_rules(self, tokens, customize): self.addRule(rule, nop_func) pass + self.check_reduce["and"] = "AST" self.check_reduce["except_handler"] = "tokens" self.check_reduce["except_handler_else"] = "tokens" self.check_reduce["raise_stmt1"] = "tokens" @@ -666,10 +667,34 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): return False lhs = rule[0] + if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")): + # If the instruction after the instructions forming the "and" is an "YIELD_VALUE" + # then this is probably an "if" inside a comprehension. + if tokens[last] == "YIELD_VALUE": + # Note: We might also consider testing last+1 being "POP_TOP" + return True + + # Test that jump_false jump somewhere beyond the end of the "and" + # it might not be exactly the end of the "and" because this and can + # be a part of a larger condition. Oddly in 2.7 there doesn't seem to be + # an optimization where the "and" jump_false is back to a loop. + jmp_false = ast[1] + if jmp_false[0] == "POP_JUMP_IF_FALSE": + while (first < last and isinstance(tokens[last].offset, str)): + last -= 1 + if jmp_false[0].attr < tokens[last].offset: + return True + + # Test that jmp_false jumps to the end of "and" + # or that it jumps to the same place as the end of "and" + jmp_false = ast[1][0] + jmp_target = jmp_false.offset + jmp_false.attr + 3 + return not (jmp_target == tokens[last].offset or + tokens[last].pattr == jmp_false.pattr) # Dead code testing... # if lhs == 'while1elsestmt': # from trepan.api import debug; debug() - if ( + elif ( lhs in ("aug_assign1", "aug_assign2") and ast[0] and ast[0][0] in ("and", "or") @@ -704,16 +729,6 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): pass pass pass - elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): - # FIXME: move this into 2.7-specific code? - if self.version == 2.7: - for i in range(last-1, last-4, -1): - t = tokens[i] - if t == "JUMP_FORWARD": - return t.attr > tokens[min(last, len(tokens)-1)].off2int() - elif t not in ("POP_TOP", "COME_FROM"): - break - pass 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)) diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 251d5357a..c2b388b2a 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -239,31 +239,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): if invalid: return invalid - if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")): - # If the instruction after the instructions forming the "and" is an "YIELD_VALUE" - # then this is probably an "if" inside a comprehension. - if tokens[last] == "YIELD_VALUE": - # Note: We might also consider testing last+1 being "POP_TOP" - return True - - # Test that jump_false jump somewhere beyond the end of the "and" - # it might not be exactly the end of the "and" because this and can - # be a part of a larger condition. Oddly in 2.7 there doesn't seem to be - # an optimization where the "and" jump_false is back to a loop. - jmp_false = ast[1] - if jmp_false[0] == "POP_JUMP_IF_FALSE": - while (first < last and isinstance(tokens[last].offset, str)): - last -= 1 - if jmp_false[0].attr < tokens[last].offset: - return True - - # Test that jmp_false jumps to the end of "and" - # or that it jumps to the same place as the end of "and" - jmp_false = ast[1][0] - jmp_target = jmp_false.offset + jmp_false.attr + 3 - return not (jmp_target == tokens[last].offset or - tokens[last].pattr == jmp_false.pattr) - elif rule == ("comp_if", ("expr", "jmp_false", "comp_iter")): + if rule == ("comp_if", ("expr", "jmp_false", "comp_iter")): jmp_false = ast[1] if jmp_false[0] == "POP_JUMP_IF_FALSE": return tokens[first].offset < jmp_false[0].attr < tokens[last].offset @@ -287,6 +263,15 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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 == ("ifstmt", ("testexpr", "_ifstmts_jump")): + for i in range(last-1, last-4, -1): + t = tokens[i] + if t == "JUMP_FORWARD": + return t.attr > tokens[min(last, len(tokens)-1)].off2int() + elif t not in ("POP_TOP", "COME_FROM"): + break + pass + pass elif rule == ("iflaststmtl", ("testexpr", "c_stmts")): testexpr = ast[0] if testexpr[0] in ("testfalse", "testtrue"): diff --git a/uncompyle6/util.py b/uncompyle6/util.py index a8ec659e6..7eca784e0 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -2,9 +2,15 @@ # Until such time it is fixed, we'll do a better. # More could be done here though. -def is_negative_zero(n): - """Returns true if n is -0.0""" - return n == 0.0 # and copysign(1, n) == -1 +try: + from math import copysign + def is_negative_zero(n): + """Returns true if n is -0.0""" + return n == 0.0 and copysign(1, n) == -1 +except: + def is_negative_zero(n): + return False + def better_repr(v): """Work around Python's unorthogonal and unhelpful repr() for primitive float From 5b889bf4f31c13d9c942b8b05e9906ba7f5c633e Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 12 Jan 2020 11:28:37 -0500 Subject: [PATCH 195/489] Fix test_grammar.py for 2.4 --- test-unit/test_grammar.py | 2 +- uncompyle6/parsers/parse2.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index b063934e0..b922c246e 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -17,7 +17,7 @@ def check_tokens(tokens, opcode_set): 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']) + expect_lhs = set(['pos_arg', 'get_iter', 'attribute']) unused_rhs = set(['list', 'call', 'mkfunc', 'mklambda', 'unpack',]) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 575918ef6..70b6d2bac 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -25,8 +25,6 @@ that a later phase can turn into a sequence of ASCII text. """ -from __future__ import print_function - from uncompyle6.parsers.reducecheck import (except_handler_else, tryelsestmt) from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.treenode import SyntaxTree From 4b46a8ffdfcb453f027281a05bc9464cadfdaae2 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Jan 2020 11:41:53 -0500 Subject: [PATCH 196/489] Small fixes --- admin-tools/pyenv-newer-versions | 2 +- admin-tools/setup-python-2.4.sh | 1 + test/stdlib/runtests.sh | 6 +++--- uncompyle6/semantics/pysource.py | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index bf553cc6a..8e8fda120 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.9 3.6.9 2.6.9 3.3.7 2.7.17 3.2.6 3.1.5 3.4.10 3.7.6 3.8.1' +export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.17 3.2.6 3.1.5 3.4.10 3.7.6 3.8.1' diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 7f4495da6..2e1978fbd 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -15,3 +15,4 @@ cd $fulldir/.. git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull cd $owd rm -v */.python-version || true +pyenv local $PYTHON_VERSION diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 57cf40eb9..90565af7c 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -269,9 +269,9 @@ cd $srcdir fulldir=$(pwd) # pyenv version cleaning -for dir in .. ../.. ; do - (cd $dir && [[ -r .python-version ]] && rm -v .python-version ) -done +# for dir in .. ../.. ; do +# (cd $dir && [[ -r .python-version ]] && rm -v .python-version ) +# done # DECOMPILER=uncompyle2 DECOMPILER=${DECOMPILER:-"$fulldir/../../bin/uncompyle6"} diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 62e6a1ff5..ad0f8ba3b 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2092,7 +2092,6 @@ def template_engine(self, entry, startnode): try: self.write(eval(expr, d, d)) except: - from trepan.api import debug; debug() raise m = escape.search(fmt, i) self.write(fmt[i:]) From dc16f03f50632b7dc39985035dfb741befd160bc Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 21 Jan 2020 06:57:04 -0500 Subject: [PATCH 197/489] Split out 2.5 runtest exclusions to its own file --- test/stdlib/2.5-exclude.sh | 41 ++++++++++++++++++++++++++++++++++++++ test/stdlib/runtests.sh | 21 +------------------ 2 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 test/stdlib/2.5-exclude.sh diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh new file mode 100644 index 000000000..c332d373b --- /dev/null +++ b/test/stdlib/2.5-exclude.sh @@ -0,0 +1,41 @@ +SKIP_TESTS=( + [test_coercion.py]=1 + [test_decimal.py]=1 + [test_dis.py]=1 # We change line numbers - duh! + [test_file.py]=1 # test assertion failures + [test_generators.py]=1 # Investigate + [test_grammar.py]=1 # Too many stmts. Handle large stmts + [test_grp.py]=1 # Long test - might work Control flow? + [test_macfs.py]=1 # it fails on its own + [test_macostools.py]=1 # it fails on its own + [test_mailbox.py]=1 + [test_nis.py]=1 # it fails on its own + [test_normalization.py]=1 # it fails on its own + [test_optparse.py]=1 # it fails on its own + [test_ossaudiodev.py]=1 # it fails on its own + [test_pdb.py]=1 # Line-number specific + [test_pep277.py]=1 # it fails on its own + [test_pep352.py]=1 # Investigate + [test_plistlib.py]=1 # it fails on its own + [test_pwd.py]=1 # Long test - might work? Control flow? + [test_pyclbr.py]=1 # Investigate + [test_rgbimg.py]=1 # it fails on its own + [test_queue.py]=1 # Control flow? + [test_scriptpackages.py]=1 # it fails on its own + [test_socketserver.py]=1 # Too long to run - 42 seconds + [test_sqlite.py]=1 # it fails on its own + [test_startfile.py]=1 # it fails on its own + [test_struct.py]=1 # "if and" confused for if .. assert and + [test_sunaudiodev.py]=1 # it fails on its own + [test_support.py]=1 # it fails on its own + [test_tcl.py=1] # it fails on its own + [test_threading.py]=1 # test takes too long to run: 11 seconds + [test_thread.py]=1 # test takes too long to run: 36 seconds + [test_trace.py]=1 # Line numbers are expected to be different + [test_urllib2net.py]=1 # is interactive? + [test_urllibnet.py]=1 # it fails on its own + [test_winreg.py]=1 # it fails on its own + [test_winsound.py[=1 # it fails on its own + [test_zipfile64.py]=1 # Runs ok but takes 204 seconds + [test_zlib]=1 # fails on its own +) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 871e72b2b..9e1b6aa35 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -67,26 +67,7 @@ case $PYVERSION in ) ;; 2.5) - SKIP_TESTS=( - [test_coercion.py]=1 - [test_decimal.py]=1 - [test_dis.py]=1 # We change line numbers - duh! - [test_generators.py]=1 # Investigate - [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_pep352.py]=1 # Investigate - [test_pwd.py]=1 # Long test - might work? Control flow? - [test_pyclbr.py]=1 # Investigate - [test_queue.py]=1 # Control flow? - [test_socketserver.py]=1 # Too long to run - 42 seconds - [test_struct.py]=1 # "if and" confused for if .. assert and - [test_threading.py]=1 # test takes too long to run: 11 seconds - [test_thread.py]=1 # test takes too long to run: 36 seconds - [test_trace.py]=1 # Line numbers are expected to be different - [test_urllib2net.py]=1 # is interactive? - [test_zipfile64.py]=1 # Runs ok but takes 204 seconds - ) + . ./2.5-exclude.sh ;; 2.6) . ./2.6-exclude.sh From afedf43ee1b2705a84dc1f591352ad7297d121a5 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 21 Jan 2020 16:01:19 -0500 Subject: [PATCH 198/489] Add "ifelsestmt" reduce rule checking --- uncompyle6/parsers/parse25.py | 18 ++++++++++++------ uncompyle6/parsers/reducecheck/ifelsestmt.py | 7 ++++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 9f873e13a..1e5c0e614 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2018 Rocky Bernstein +# Copyright (c) 2016-2018, 2020 Rocky Bernstein """ spark grammar differences over Python2.6 for Python 2.5. """ @@ -6,6 +6,7 @@ from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse26 import Python26Parser +from uncompyle6.parsers.reducecheck import (ifelsestmt) class Python25Parser(Python26Parser): def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG): @@ -98,8 +99,9 @@ def customize_grammar_rules(self, tokens, customize): """) 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' + self.check_reduce["try_except"] = "tokens" + self.check_reduce["aug_assign1"] = "AST" + self.check_reduce["ifelsestmt"] = "AST" def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python25Parser, @@ -107,15 +109,19 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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' + if rule == ("aug_assign1", ("expr", "expr", "inplace_op", "store")): + return ast[0][0] == "and" + lhs = rule[0] + n = len(tokens) + if lhs == "ifelsestmt": + return ifelsestmt(self, lhs, n, rule, ast, tokens, first, last) return False class Python25ParserSingle(Python26Parser, PythonParserSingle): pass -if __name__ == '__main__': +if __name__ == "__main__": # Check grammar p = Python25Parser() p.check_grammar() diff --git a/uncompyle6/parsers/reducecheck/ifelsestmt.py b/uncompyle6/parsers/reducecheck/ifelsestmt.py index ca7157822..890ebca0f 100644 --- a/uncompyle6/parsers/reducecheck/ifelsestmt.py +++ b/uncompyle6/parsers/reducecheck/ifelsestmt.py @@ -64,7 +64,6 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last): ), ): return False - # Make sure all of the "come froms" offset at the # end of the "if" come from somewhere inside the "if". # Since the come_froms are ordered so that lowest @@ -115,8 +114,10 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last): jf_cf_pop = ast[2] if jf_cf_pop == "jf_cf_pop" and jf_cf_pop[0] == "JUMP_FORWARD": - int(jf_cf_pop[0].pattr) - if int(jf_cf_pop[0].pattr) < tokens[last-1].off2int(): + jump_forward = jf_cf_pop[0] + endif_target = int(jump_forward.pattr) + last_offset = tokens[min(last, n-1)].off2int() + if endif_target != last_offset: return True # The jump inside "else" check below should be added. From b12893f343ef093350cad8bd42cf7df2956514f9 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 22 Jan 2020 06:25:58 -0500 Subject: [PATCH 199/489] 2.4 compatibility --- uncompyle6/scanners/tok.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 4399f2c49..b615cde7a 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -182,7 +182,10 @@ def off2int(self): # This is an instruction with an extended arg. # For things that compare against offsets, we generally want the # later offset. - return offset_2 if prefer_last else offset_1 + if prefer_last: + return offset_2 + else: + return offset_1 else: # Probably a "COME_FROM"-type offset, where the second number # is just a count, and not really an offset. From f8c437230d92c99c8076e01908c6c5e6a60c2d6c Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 26 Jan 2020 12:03:58 -0500 Subject: [PATCH 200/489] Get ready for release 3.6.3 --- NEWS.md | 27 +++++++++++++++++++++++++++ __pkginfo__.py | 4 ++-- uncompyle6/scanners/tok.py | 10 +++++++--- uncompyle6/version.py | 2 +- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index c53f57d34..c98f35077 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,30 @@ +3.6.3: 2020-1-26 Martin and Susanne +=================================== + +Of late, every release fixes major gaps and embarrassments of the last release.... + +And in some cases, like this one, exposes lacuna and rot. + +I now have [control] flow under control, even if it isn't the most optimal way. + +I now have greatly expanded automated testing. + +On the most recent Python versions I regularly decompile thousands of Python programs that are distributed with Python. when it is possible, I then decompile Python's standard test suite distributed with Python and run the decompiled source code which basically checks itself. This amounts to about 250 test programs per version. This is in addition to the 3 CI testing services which do different things. + +Does this mean the decompiler works perfectly? No. There are still a dozen or so failing programs, although the actual number of bugs is probably smaller though. + +However, in perparation of a more major refactoring of the parser grammar, this release was born. + +In many cases, decompilation is better. But there are some cases where decompilation has gotten worse. For lack of time (and interest) 3.0 bytecode suffered a hit. Possibly some code in the 3.x range did too. In time and with cleaner refactored code, this will come back. + +Commit c90ff51 was a local maxiumum before, I started reworking the grammar to separate productions that were specific to loops versus those that are not in loops. +In the middle of that I added another grammar simplication to remove singleton productions of the form `sstmts-> stmts`. These were always was a bit ugly, and complicated output. + +At any rate if decompilation fails, you can try c90ff51. Or another decompiler. `unpyc37` is pretty good for 3.7. wibiti `uncompyle2` is great for 2.7. `pycdc` is mediocre for Python before 3.5 or so, and not that good for the most recent Python. Geerally these programs will give some sort of answer even if it isn't correct. + +decompyle3 isn't that good for 3.7 and worse for 3.8, but right now it does things no other Python decompiler like `unpyc37` or `pycdc` does. For example, `decompyle3` handles variable annotations. As always, the issue trackers for the various programs will give you a sense for what needs to be done. For now, I've given up on reporting issues in the other decompilers because there are already enough issues reported, and they are just not getting fixed anyway. + + 3.6.2: 2020-1-5 Samish ====================== diff --git a/__pkginfo__.py b/__pkginfo__.py index 1bc46ca64..01dee6d58 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Rocky Bernstein +# Copyright (C) 2018, 2020 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ # Things that change more often go here. copyright = """ -Copyright (C) 2015-2019 Rocky Bernstein . +Copyright (C) 2015-2020 Rocky Bernstein . """ classifiers = ["Development Status :: 5 - Production/Stable", diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 5e8da5292..e0234f620 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -21,8 +21,6 @@ if PYTHON3: intern = sys.intern -class Token: # Python 2.4 can't have empty () - def off2int(offset, prefer_last=True): if isinstance(offset, int): return offset @@ -38,12 +36,18 @@ def off2int(offset, prefer_last=True): # This is an instruction with an extended arg. # For things that compare against offsets, we generally want the # later offset. - return offset_2 if prefer_last else offset_1 + if prefer_last: + return offset_2 + else: + return offset_1 + pass else: # Probably a "COME_FROM"-type offset, where the second number # is just a count, and not really an offset. return offset_1 +class Token: # Python 2.4 can't have empty () + """ Class representing a byte-code instruction. diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 964f78421..c46910ad0 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -12,4 +12,4 @@ # along with this program. If not, see . # This file is suitable for sourcing inside bash as # well as importing into Python -VERSION="3.6.2" # noqa +VERSION="3.6.3" # noqa From 90439c562f4c544b8a1e0fe1502045ed4a4e3b4d Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 4 Feb 2020 20:30:19 -0500 Subject: [PATCH 201/489] Python 2.5 runtests exclusions --- test/stdlib/2.5-exclude.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index c332d373b..007ce8900 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -35,7 +35,11 @@ SKIP_TESTS=( [test_urllib2net.py]=1 # is interactive? [test_urllibnet.py]=1 # it fails on its own [test_winreg.py]=1 # it fails on its own - [test_winsound.py[=1 # it fails on its own + [test_winsound.py]=1 # it fails on its own [test_zipfile64.py]=1 # Runs ok but takes 204 seconds [test_zlib]=1 # fails on its own ) + +if (( batch )) ; then + SKIP_TESTS[test_doctest.py]=1 # Fails on ppc64le +fi From 9cc9bceadfcb66e8f1e9a976b317a51b3b439a14 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 4 Feb 2020 21:51:36 -0500 Subject: [PATCH 202/489] Go over older 2.x exclusions --- test/stdlib/2.4-exclude.sh | 54 ++++++++++++++++++++++++++++++++++++++ test/stdlib/2.5-exclude.sh | 42 ++++++++++++++++++++++++++++- test/stdlib/runtests.sh | 15 +---------- 3 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 test/stdlib/2.4-exclude.sh diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh new file mode 100644 index 000000000..19c37eb3b --- /dev/null +++ b/test/stdlib/2.4-exclude.sh @@ -0,0 +1,54 @@ +SKIP_TESTS=( + [test_aepack.py]=1 # it fails on its own + [test_al.py]=1 # it fails on its own + [test_applesingle.py]=1 # it fails on its own + [test_bsddb185.py]=1 # it fails on its own + [test_bsddb3.py]=1 # it fails on its own + [test_bsddb.py]=1 # it fails on its own + [test_cd.py]=1 # it fails on its own + [test_cl.py]=1 # it fails on its own + [test_codecmaps_cn.py]=1 # it fails on its own + [test_codecmaps_hk.py]=1 # it fails on its own + [test_codecmaps_jp.py]=1 # it fails on its own + [test_codecmaps_kr.py]=1 # it fails on its own + [test_codecmaps_tw.py]=1 # it fails on its own + [test_curses.py]=1 # it fails on its own + [test_dbm.py]=1 # it fails on its own + [test_dl.py]=1 # it fails on its own + [test_gdbm.py]=1 # it fails on its own + [test_gl.py]=1 # it fails on its own + [test_imageop.py]=1 # it fails on its own + [test_imgfile.py]=1 # it fails on its own + [test_linuxaudiodev.py]=1 # it fails on its own + [test_macfs.py]=1 # it fails on its own + [test_macostools.py]=1 # it fails on its own + [test_nis.py]=1 # it fails on its own + [test_normalization.py]=1 # it fails on its own + [test_ossaudiodev.py]=1 # it fails on its own + [test_pep277.py]=1 # it fails on its own + [test_plistlib.py]=1 # it fails on its own + [test_rgbimg.py]=1 # it fails on its own + [test_scriptpackages.py]=1 # it fails on its own + [test_socket_ssl.py]=1 # it fails on its own + [test_sunaudiodev.py]=1 # it fails on its own + [test_support.py]=1 # it fails on its own + [test_tcl.py]=1 # it fails on its own + [test_urllib2net.py]=1 # it fails on its own + [test_urllibnet.py]=1 # it fails on its own + [test_winreg.py]=1 # it fails on its own + [test_winsound.py]=1 # it fails on its own + [test_zlib.py]=1 # it fails on its own + + [test_decimal.py]=1 # + [test_dis.py]=1 # We change line numbers - duh! + [test_generators.py]=1 # Investigate + [test_grammar.py]=1 # Too many stmts. Handle large stmts + [test_grp.py]=1 # Long test - might work Control flow? + [test_pep247.py]=1 # Long test - might work? Control flow? + [test_pwd.py]=1 # Long test - might work? Control flow? + [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds + [test_threading.py]=1 # test takes too long to run: 11 seconds + [test_thread.py]=1 # test takes too long to run: 36 seconds + [test_trace.py]=1 # Long test - works + [test_zipfile64.py]=1 # Runs ok but takes 204 seconds +) diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index 007ce8900..9d9af6a41 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -1,4 +1,44 @@ SKIP_TESTS=( + [test_aepack.py]=1 # it fails on its own + [test_al.py]=1 # it fails on its own + [test_applesingle.py]=1 # it fails on its own + [test_bsddb185.py]=1 # it fails on its own + [test_bsddb3.py]=1 # it fails on its own + [test_bsddb.py]=1 # it fails on its own + [test_cd.py]=1 # it fails on its own + [test_cl.py]=1 # it fails on its own + [test_codecmaps_cn.py]=1 # it fails on its own + [test_codecmaps_hk.py]=1 # it fails on its own + [test_codecmaps_jp.py]=1 # it fails on its own + [test_codecmaps_kr.py]=1 # it fails on its own + [test_codecmaps_tw.py]=1 # it fails on its own + [test_curses.py]=1 # it fails on its own + [test_dbm.py]=1 # it fails on its own + [test_dl.py]=1 # it fails on its own + [test_gdbm.py]=1 # it fails on its own + [test_gl.py]=1 # it fails on its own + [test_imageop.py]=1 # it fails on its own + [test_imgfile.py]=1 # it fails on its own + [test_linuxaudiodev.py]=1 # it fails on its own + [test_macfs.py]=1 # it fails on its own + [test_macostools.py]=1 # it fails on its own + [test_nis.py]=1 # it fails on its own + [test_normalization.py]=1 # it fails on its own + [test_ossaudiodev.py]=1 # it fails on its own + [test_pep277.py]=1 # it fails on its own + [test_plistlib.py]=1 # it fails on its own + [test_rgbimg.py]=1 # it fails on its own + [test_scriptpackages.py]=1 # it fails on its own + [test_sunaudiodev.py]=1 # it fails on its own + [test_support.py]=1 # it fails on its own + [test_tcl.py]=1 # it fails on its own + [test_urllib2net.py]=1 # it fails on its own + [test_urllibnet.py]=1 # it fails on its own + [test_winreg.py]=1 # it fails on its own + [test_winsound.py]=1 # it fails on its own + [test_zlib.py]=1 # it fails on its own + + [test_coercion.py]=1 [test_decimal.py]=1 [test_dis.py]=1 # We change line numbers - duh! @@ -28,7 +68,7 @@ SKIP_TESTS=( [test_struct.py]=1 # "if and" confused for if .. assert and [test_sunaudiodev.py]=1 # it fails on its own [test_support.py]=1 # it fails on its own - [test_tcl.py=1] # it fails on its own + [test_tcl.py]=1 # it fails on its own [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Line numbers are expected to be different diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 65c56cd6f..4f57eae1b 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -51,20 +51,7 @@ function timeout_cmd { typeset -A SKIP_TESTS case $PYVERSION in 2.4) - SKIP_TESTS=( - [test_decimal.py]=1 # - [test_dis.py]=1 # We change line numbers - duh! - [test_generators.py]=1 # Investigate - [test_grammar.py]=1 # Too many stmts. Handle large stmts - [test_grp.py]=1 # Long test - might work Control flow? - [test_pep247.py]=1 # Long test - might work? Control flow? - [test_pwd.py]=1 # Long test - might work? Control flow? - [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds - [test_threading.py]=1 # test takes too long to run: 11 seconds - [test_thread.py]=1 # test takes too long to run: 36 seconds - [test_trace.py]=1 # Long test - works - [test_zipfile64.py]=1 # Runs ok but takes 204 seconds - ) + . ./2.4-exclude.sh ;; 2.5) . ./2.5-exclude.sh From 25b775291544f8651729f3318a5871fb962b3600 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:01:54 -0500 Subject: [PATCH 203/489] CircleCI try 2 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a1466d274..9a6973afc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ jobs: # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ docker: - - image: circleci/jessie + - image: circleci/python:2-jessie steps: # Machine Setup # 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 From 432859d67747ee36edea20dee6e92b6710a5f187 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:04:30 -0500 Subject: [PATCH 204/489] CircleCI try 3 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9a6973afc..0cdd1777c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ jobs: CIRCLE_TEST_REPORTS: /tmp/circleci-test-results COMPILE: --compile PYENV_ROOT: "$HOME/.pyenv" - PATH: "$PYENV_ROOT/bin:$PYENV_ROOT/shims:/usr/bin:/usr/local/bin:/sbin:/usr/sbin" + PATH: "$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ From 1091d32882bea0ff199ad2e66687d960c5759ada Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:09:37 -0500 Subject: [PATCH 205/489] CircleCI try 4 --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0cdd1777c..975f57519 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,8 +10,8 @@ jobs: CIRCLE_ARTIFACTS: /tmp/circleci-artifacts CIRCLE_TEST_REPORTS: /tmp/circleci-test-results COMPILE: --compile - PYENV_ROOT: "$HOME/.pyenv" - PATH: "$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ From 9b41dfd951753c7e42d9b463bf81920e1f11b410 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:14:41 -0500 Subject: [PATCH 206/489] CircleCI try 5 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 975f57519..3daca27f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: - run: curl https://pyenv.run | bash - run: working_directory: ~/rocky/python-uncompyle6 - command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && easy_install nose && pyenv rehash + command: /home/circleci/.pyenv/bin/pyenv install 2.4.6 && /home/circleci/.pyenv/bin/pyenv local 2.4.6 && /home/circleci/.pyenv/bin/pyenv rehash && easy_install nose && /home/circleci/.pyenv/bin/pyenv rehash # Dependencies # This would typically go in either a build or a build-and-test job when using workflows # Restore the dependency cache From 26a7b984aa61672917638a2ddbae6089286adb2d Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:17:09 -0500 Subject: [PATCH 207/489] CircleCI try 6 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3daca27f0..ec8bca382 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: - run: curl https://pyenv.run | bash - run: working_directory: ~/rocky/python-uncompyle6 - command: /home/circleci/.pyenv/bin/pyenv install 2.4.6 && /home/circleci/.pyenv/bin/pyenv local 2.4.6 && /home/circleci/.pyenv/bin/pyenv rehash && easy_install nose && /home/circleci/.pyenv/bin/pyenv rehash + command: sudo /home/circleci/.pyenv/bin/pyenv install 2.4.6 && /home/circleci/.pyenv/bin/pyenv local 2.4.6 && /home/circleci/.pyenv/bin/pyenv rehash && easy_install nose && /home/circleci/.pyenv/bin/pyenv rehash # Dependencies # This would typically go in either a build or a build-and-test job when using workflows # Restore the dependency cache From 3d649e049bef24dc007f2214e75d3f640b98bf56 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:26:55 -0500 Subject: [PATCH 208/489] CircleCI try 7 --- .circleci/config.yml | 9 ++++++--- test/stdlib/3.6-exclude.sh | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ec8bca382..8951125dd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,14 +10,17 @@ jobs: CIRCLE_ARTIFACTS: /tmp/circleci-artifacts CIRCLE_TEST_REPORTS: /tmp/circleci-test-results COMPILE: --compile - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ docker: - image: circleci/python:2-jessie + environment: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" steps: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" # Machine Setup # 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 # The following `checkout` command checks out your code to your working directory. In 1.0 we did this implicitly. In 2.0 you can choose where in the course of a job your code should be checked out. @@ -29,7 +32,7 @@ jobs: - run: curl https://pyenv.run | bash - run: working_directory: ~/rocky/python-uncompyle6 - command: sudo /home/circleci/.pyenv/bin/pyenv install 2.4.6 && /home/circleci/.pyenv/bin/pyenv local 2.4.6 && /home/circleci/.pyenv/bin/pyenv rehash && easy_install nose && /home/circleci/.pyenv/bin/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 diff --git a/test/stdlib/3.6-exclude.sh b/test/stdlib/3.6-exclude.sh index b85ab0ced..82f020cde 100644 --- a/test/stdlib/3.6-exclude.sh +++ b/test/stdlib/3.6-exclude.sh @@ -2,10 +2,12 @@ SKIP_TESTS=( [test_ast.py]=1 # FIXME: Works on c90ff51 [test_binop.py]=1 # FIXME: Works on c90ff51 [test_complex.py]=1 # FIXME: Works on c90ff51 + [test_decorators.py]=1 # FIXME: Works on c90ff51 [test_format.py]=1 # FIXME: Works on c90ff51 [test_ftplib.py]=1 # FIXME: Works on c90ff51 [test_slice.py]=1 # FIXME: Works on c90ff51 [test_sort.py]=1 # FIXME: Works on c90ff51 + [test_strftime.py]=1 # FIXME: Works on c90ff51 [test_timeit.py]=1 # FIXME: Works on c90ff51 [test_os.py]=1 # FIXME: Works on c90ff51 From a29d1e1531f44908b272cf3147169d9f920aeb53 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:28:20 -0500 Subject: [PATCH 209/489] CircleCI try 8 --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8951125dd..fd5a4a016 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,8 +19,6 @@ jobs: PYENV_ROOT: "/home/circleci/.pyenv" PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" steps: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" # Machine Setup # 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 # The following `checkout` command checks out your code to your working directory. In 1.0 we did this implicitly. In 2.0 you can choose where in the course of a job your code should be checked out. From 57bca5102daa182b3f0178471b8b093ff09c4e05 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:32:05 -0500 Subject: [PATCH 210/489] CircleCI try 9 --- .circleci/config.yml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fd5a4a016..9dc8743ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,9 +15,6 @@ jobs: # https://circleci.com/docs/2.0/circleci-images/ docker: - image: circleci/python:2-jessie - environment: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" steps: # Machine Setup # 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 @@ -29,6 +26,9 @@ jobs: - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS - run: curl https://pyenv.run | bash - run: + environment: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: pyenv install 2.4.6 && pyenv local 2.4.6 && pyenv rehash && easy_install nose && pyenv rehash # Dependencies @@ -41,8 +41,12 @@ jobs: - v2-dependencies- # This is based on your 1.0 configuration file or project settings - - run: easy_install xdis spark-parser - - run: pip install -e . + - run: + environment: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" + working_directory: ~/rocky/python-uncompyle6 + command: easy_install xdis spark-parser && pip install -e . # Save dependency cache - save_cache: @@ -60,8 +64,20 @@ 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.4 - - run: cd ./test/stdlib && pyenv local 2.4.6 && bash ./runtests.sh 'test_[p-z]*.py' + - run: + environment: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" + working_directory: ~/rocky/python-uncompyle6 + command: + python ./setup.py develop && make check-2.4 + - run: + environment: + PYENV_ROOT: "/home/circleci/.pyenv" + PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" + working_directory: ~/rocky/python-uncompyle6 + command: + 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 From ef9c34098a4bdf79cf4e35179a7befcf1ee6683c Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:41:30 -0500 Subject: [PATCH 211/489] CircleCI try 10 --- .circleci/config.yml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9dc8743ae..9089b5b1e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,11 +10,10 @@ jobs: CIRCLE_ARTIFACTS: /tmp/circleci-artifacts CIRCLE_TEST_REPORTS: /tmp/circleci-test-results COMPILE: --compile - # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ docker: - - image: circleci/python:2-jessie + - image: circleci/python:2.7 steps: # Machine Setup # 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 @@ -24,13 +23,6 @@ jobs: # In many cases you can simplify this from what is generated here. # 'See docs on artifact collection here https://circleci.com/docs/2.0/artifacts/' - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS - - run: curl https://pyenv.run | bash - - run: - environment: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" - working_directory: ~/rocky/python-uncompyle6 - 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 @@ -42,11 +34,7 @@ jobs: # This is based on your 1.0 configuration file or project settings - run: - environment: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" - working_directory: ~/rocky/python-uncompyle6 - command: easy_install xdis spark-parser && pip install -e . + command: sudo easy_install xdis spark-parser && sudo pip install -e . # Save dependency cache - save_cache: @@ -70,14 +58,14 @@ jobs: PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: - python ./setup.py develop && make check-2.4 + python ./setup.py develop && make check-2.7 - run: environment: PYENV_ROOT: "/home/circleci/.pyenv" PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: - cd ./test/stdlib && pyenv local 2.4.6 && bash ./runtests.sh 'test_[p-z]*.py' + cd ./test/stdlib && 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 From 07290bd44353b63914069fdb4027c59e69516f89 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:42:28 -0500 Subject: [PATCH 212/489] CircleCI try 11 --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9089b5b1e..9ee0e07fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -58,14 +58,14 @@ jobs: PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: - python ./setup.py develop && make check-2.7 + sudo python ./setup.py develop && make check-2.7 - run: environment: PYENV_ROOT: "/home/circleci/.pyenv" PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: - cd ./test/stdlib && bash ./runtests.sh 'test_[p-z]*.py' +&& 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 From 244ab4e3b3dcead4c16ca0a6e250b8041f355d4f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:43:24 -0500 Subject: [PATCH 213/489] CircleCI try 12 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9ee0e07fe..0294bcbde 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -65,7 +65,7 @@ jobs: PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: -&& bash ./runtests.sh 'test_[p-z]*.py' + 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 From cf5c81ab21dffbbe1b51c6e305244849a02fedf0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:44:27 -0500 Subject: [PATCH 214/489] CircleCI try 13 --- .circleci/config.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0294bcbde..1b4c04b2f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,7 +34,7 @@ jobs: # This is based on your 1.0 configuration file or project settings - run: - command: sudo easy_install xdis spark-parser && sudo pip install -e . + command: sudo easy_install xdis spark-parser && sudo pip install -e . && sudo pip install -r requirements-dev.txt # Save dependency cache - save_cache: @@ -53,16 +53,10 @@ jobs: # 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: - environment: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: sudo python ./setup.py develop && make check-2.7 - run: - environment: - PYENV_ROOT: "/home/circleci/.pyenv" - PATH: "/home/circleci/bin:/home/circleci/shims:/home/circleci/.pyenv/bin:/home/circleci/.local/bin:/usr/local/bin:/usr/bin:/bin" working_directory: ~/rocky/python-uncompyle6 command: bash ./runtests.sh 'test_[p-z]*.py' From 846020bf5ab1ba2d67ff85a60eb47e0c1dc71fd6 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:46:21 -0500 Subject: [PATCH 215/489] CircleCI try 14 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b4c04b2f..d332c5d2a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ jobs: command: sudo python ./setup.py develop && make check-2.7 - run: - working_directory: ~/rocky/python-uncompyle6 + working_directory: ~/rocky/python-uncompyle6/test command: bash ./runtests.sh 'test_[p-z]*.py' # Teardown From ae9f83c1915a2e70adb1e084ba5e92ce2e05421e Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 10:49:58 -0500 Subject: [PATCH 216/489] CircleCI try 15 --- .circleci/config.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d332c5d2a..83f1f38a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,6 @@ version: 2 jobs: build: - working_directory: ~/rocky/python-uncompyle6 parallelism: 1 shell: /bin/bash --login # CircleCI 2.0 does not support environment variables that refer to each other the same way as 1.0 did. @@ -52,14 +51,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: - working_directory: ~/rocky/python-uncompyle6 - command: - sudo python ./setup.py develop && make check-2.7 - - run: - working_directory: ~/rocky/python-uncompyle6/test - command: - bash ./runtests.sh 'test_[p-z]*.py' + - run: sudo python ./setup.py develop && make check-2.7 + - run: cd test/stdlib && 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 From da119a31f71cdb6ae427513bdd914e59dd38e84a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Feb 2020 12:41:52 -0500 Subject: [PATCH 217/489] Update README.rst --- README.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index c82b5f88b..a9b332617 100644 --- a/README.rst +++ b/README.rst @@ -139,9 +139,16 @@ Python syntax changes, you should use this option if the bytecode is the right bytecode for the Python interpreter that will be checking the syntax. -You can also cross compare the results with another python decompiler -like pycdc_ . Since they work differently, bugs here often aren't in -that, and vice versa. +You can also cross compare the results with either another version of +`uncompyle6` since there are are sometimes regressions in decompiling +specific bytecode as the overall quality improves. + +For Python 3.7 and above, the code in decompyle3_ is generally +better. + +Or try specific another python decompiler like uncompyle2_, unpyc37_, +or pycdc_. Since the later two work differently, bugs here often +aren't in that, and vice versa. There is an interesting class of these programs that is readily available give stronger verification: those programs that when run @@ -240,7 +247,9 @@ See Also .. _debuggers: https://pypi.python.org/pypi/trepan3k .. _remake: https://bashdb.sf.net/remake .. _pycdc: https://github.com/zrax/pycdc -.. _decompile3: https://github.com/rocky/python-decompile3 +.. _decompyle3: https://github.com/rocky/python-decompile3 +.. _uncompyle2: https://github.com/wibiti/uncompyle2 +.. _unpyc37: https://github.com/andrew-tavera/unpyc37 .. _this: https://github.com/rocky/python-uncompyle6/wiki/Deparsing-technology-and-its-use-in-exact-location-reporting .. |buildstatus| image:: https://travis-ci.org/rocky/python-uncompyle6.svg :target: https://travis-ci.org/rocky/python-uncompyle6 .. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:uncompyle6.svg :target: https://repology.org/project/python:uncompyle6/versions From 74848140c523a8e15a7edd94ee1dfd743192938b Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 10 Feb 2020 18:36:10 -0500 Subject: [PATCH 218/489] Script typo --- test/stdlib/run-and-email.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stdlib/run-and-email.sh b/test/stdlib/run-and-email.sh index 6ae5e7b0d..3f7f37246 100755 --- a/test/stdlib/run-and-email.sh +++ b/test/stdlib/run-and-email.sh @@ -21,7 +21,7 @@ if [[ $0 != $bs ]] ; then fi mydir=$(dirname $bs) -chdir $mydir +cd $mydir branch=$(cat ../../.git/HEAD | cut -d'/' -f 3) if [[ $branch == 'python-2.4' ]]; then From 9f4458db9a70ff20b9552dac75d9c6a86eaa9142 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 13 Feb 2020 21:04:26 -0500 Subject: [PATCH 219/489] better batch testing for older Pythons --- test/run-and-email.sh | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/test/run-and-email.sh b/test/run-and-email.sh index b97d5dc65..fb7a79434 100755 --- a/test/run-and-email.sh +++ b/test/run-and-email.sh @@ -14,20 +14,32 @@ function displaytime { printf '%d seconds\n' $S } -. ../admin-tools/pyenv-newer-versions +bs=${BASH_SOURCE[0]} +if [[ $0 != $bs ]] ; then + echo "This script should not be *sourced* but run through bash" + exit 1 +fi + +mydir=$(dirname $bs) +cd $mydir + +. ../admin-tools/pyenv-older-versions +MAIN="test_pyenvlib.py" USER=${USER:-rocky} EMAIL=${EMAIL:-rb@dustyfeet.com} +SUBJECT_PREFIX="${MAIN} for" MAX_TESTS=${MAX_TESTS:-800} export BATCH=1 typeset -i RUN_STARTTIME=$(date +%s) # PYVERSIONS="3.5.6" -actual_versions="" +MAILBODY=/tmp/${MAIN}-mailbody-$$.txt +# for VERSION in 2.4.6 2.5.9 ; do for VERSION in $PYVERSIONS ; do typeset -i rc=0 - LOGFILE=/tmp/pyenvlib-$VERSION-$$.log + LOGFILE=/tmp/${MAIN}-$VERSION-$$.log case "$VERSION" in 3.7.6 | 3.8.1 | 3.1.5 | 3.0.1 ) @@ -48,6 +60,12 @@ for VERSION in $PYVERSIONS ; do 3.6.10 ) MAX_TESTS=1300 # about 2139 exist ;; + 2.4.6 ) + MAX_TESTS=600 + ;; + 2.5.6 ) + MAX_TESTS=600 + ;; 2.6.9 ) MAX_TESTS=1300 ;; @@ -58,13 +76,14 @@ for VERSION in $PYVERSIONS ; do actual_versions="$actual_versions $VERSION" - if ! pyenv local $VERSION ; then + if ! pyenv local $VERSION; then rc=1 + mailbody_line="pyenv local $VERSION not installed" else echo Python Version $(pyenv local) > $LOGFILE echo "" >> $LOGFILE typeset -i ALL_FILES_STARTTIME=$(date +%s) - cmd="python ./test_pyenvlib.py --max ${MAX_TESTS} --syntax-verify --$VERSION" + cmd="python ./${MAIN} --max ${MAX_TESTS} --syntax-verify --$VERSION" echo "$cmd" >>$LOGFILE 2>&1 $cmd >>$LOGFILE 2>&1 rc=$? @@ -77,19 +96,23 @@ for VERSION in $PYVERSIONS ; do displaytime $time_diff >> $LOGFILE fi + SUBJECT_PREFIX="pyenv weak verify (max $MAX_TESTS) for" if ((rc == 0)); then - actual_versions="$actual_versions ok;" + mailbody_line="Python $VERSION ok; ran in $time_diff" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost else + mailbody_line="Python $VERSION failed; ran in $time_diff" actual_versions="$actual_versions failed;" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${USER}@localhost tail -v $LOGFILE | mail -s "$HOST $SUBJECT_PREFIX $VERSION not ok" ${EMAIL} fi + echo $mailbody_line >> $MAILBODY rm .python-version done typeset -i RUN_ENDTIME=$(date +%s) (( time_diff = RUN_ENDTIME - RUN_STARTTIME)) elapsed_time=$(displaytime $time_diff) -echo "Run complete $elapsed_time for versions $actual_versions" | mail -s "$HOST pyenv weak verify in $elapsed_time" ${EMAIL} +echo "Run complete in $elapsed_time" >> $MAILBODY +cat $MAILBODY | mail -s "$HOST $MAIN weak verify in $elapsed_time" ${EMAIL} From 108c6ecfe36b753307312795754d55f8b4bb4892 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Feb 2020 08:41:52 -0500 Subject: [PATCH 220/489] Small tweak in mailbody line --- test/run-and-email.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-and-email.sh b/test/run-and-email.sh index fb7a79434..022c8f3df 100755 --- a/test/run-and-email.sh +++ b/test/run-and-email.sh @@ -99,7 +99,7 @@ for VERSION in $PYVERSIONS ; do SUBJECT_PREFIX="pyenv weak verify (max $MAX_TESTS) for" if ((rc == 0)); then - mailbody_line="Python $VERSION ok; ran in $time_diff" + mailbody_line="Python $VERSION ok; ran in $time_diff seconds" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost else mailbody_line="Python $VERSION failed; ran in $time_diff" From a37ae1be0d5634dba78be53416e578626d58be54 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Feb 2020 10:45:06 -0500 Subject: [PATCH 221/489] Fix parsing bug in 2.3 and 2.4 from sre.py --- test/bytecode_2.3/08_while1_if_continue.pyc | Bin 0 -> 637 bytes test/bytecode_2.4/08_while1_if_continue.pyc | Bin 305 -> 491 bytes test/bytecode_2.6/08_while1_if_continue.pyc | Bin 336 -> 545 bytes test/bytecode_2.7/08_while1_if_continue.pyc | Bin 333 -> 542 bytes .../looping/08_while1_if_continue.py | 10 ++++++++++ uncompyle6/parsers/parse23.py | 15 +++++++++++++-- uncompyle6/parsers/parse24.py | 17 +++++++++++++++-- 7 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 test/bytecode_2.3/08_while1_if_continue.pyc diff --git a/test/bytecode_2.3/08_while1_if_continue.pyc b/test/bytecode_2.3/08_while1_if_continue.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd3d766b1859fe789a776f33fa90a5b673c9e373 GIT binary patch literal 637 zcmbu6Jx;?w5QX132?0YWP((uoG=?HS9TG*5kSHUh6i5`TjJ<}HjMvUOB1lw-dvO^~ zzzLYyU@Albws!oyv-3RP`1GR}zQ0}EB>1|BpJ%+>E{7C&1+H0;7lbsxENXEok%P@T zmx2+8^|rjusfidV7s6yM0E%%2*jQm|I(#;%+!PQIGdrJXR)Ci7jeVEcBp!^1gE&r@1M# zaJVh8qZYa(_hyht3$o;+9&F5FdF;Us7>tSfpk?20bU>HY9@A7U&dO?LKz0r)u?5{%_MvqtD@hNV)p0R3-QDc JU4HvU_zC$`d^7+6 literal 0 HcmV?d00001 diff --git a/test/bytecode_2.4/08_while1_if_continue.pyc b/test/bytecode_2.4/08_while1_if_continue.pyc index 96166f79c051300b07588af521f80428631f773b..00c1a58c6398be9c32afdfe72d88b6bf1292b51e 100644 GIT binary patch delta 268 zcmdnU^qSc$_Y*JIll^XS$qZ1y2&5f=xL6EGq%bhFFfc>`8H`{CBSQ)kL$C((MBR(^ z$t*wxAPmys48+CCK%zp1p@xwmpO=BLf|ntn5J-m?GBYqXF))CraG-&~8caZSewiR` z8X%$sL?mf|i~=(ggTPESAip@jv?w{XgcZarNi0d#05TZBM3586loF7l_=3cu;#6KB ntC$Z+FfcL$F*}&#V)6sq76cSx2;u+|$lS>SjIwMXV>r10WU?c2 delta 81 zcmaFOypc&a_Y*JIcK3$xWCkc;1kw&bT+9n3QWzLo7#N~}3`T}v4W@}^7lr&ZKq`Wm QfdrH_`2?dZ3y{kI0B$r4(*OVf diff --git a/test/bytecode_2.6/08_while1_if_continue.pyc b/test/bytecode_2.6/08_while1_if_continue.pyc index 5c87045d056ad07b0641eee0c45d8269acdf0aef..fbe8975330ba71e272c669da20602d94b27d9880 100644 GIT binary patch delta 233 zcmcb>w2;N@;wN6NC;Q#vk{O_Y5lA}#aj_VXNMT@TVPJ>?G8n-OMurq7hF}fmiMj{U zl39QXKp3RM8HkJJfkcG_Lk%NCJ~snn1vf)LAumHAGXrB21Be0|7OVkM?56=F7&Jh7 zOF;ZYFqu@s24olKmlh?bmau}DC5a`e6DQaifyCnr5{rscc|pQlK!SmhnUNicIhg!3 bn1I|MFu@LFfz6&c!D+HRBQG0Bl#>epPWK}O delta 71 zcmZ3;a)C+r;wN6N?d}cX$qZ1y2&5f=xR@76q%bhFFfc>`8H^0U8cY+-4siHsfK&uA NO+LaH&H`jH000QD45^rM`7`8H`{CBSQ)kL$C((MBTk< z$t*wxAPmys48+CqK%zo|p@xy6NQ9w+n<1c(hatR>nW2e+0Z4`e4GY!)DfZI<5)2w3 zy(J)iBA84nVFR*@^Gl18Q%hJu%#y^C)QP=zMj-L{g2bZYR9=uU7m#3JWM*UoVh$!h c4JIHr2u!d8Szxm#_Bu_rVdP~4iE?rQ0PRmA+W-In delta 71 zcmbQoa+XP#`7 Date: Fri, 14 Feb 2020 22:47:48 -0500 Subject: [PATCH 222/489] Correct a comment --- uncompyle6/parsers/parse24.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 47ca4c806..ffb10f648 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -42,6 +42,8 @@ def p_misc24(self, args): POP_TOP POP_BLOCK COME_FROM while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_TOP POP_BLOCK + while1stmt ::= SETUP_LOOP l_stmts COME_FROM JUMP_BACK + POP_TOP POP_BLOCK COME_FROM # Python 2.4 # The following has no "JUMP_BACK" after l_stmts because @@ -49,11 +51,6 @@ def p_misc24(self, args): while1stmt ::= SETUP_LOOP l_stmts POP_TOP POP_BLOCK - # The following has a "COME_FROM" at the end which comes from - # a "break" inside "l_stmts". - while1stmt ::= SETUP_LOOP l_stmts COME_FROM JUMP_BACK - POP_TOP POP_BLOCK COME_FROM - # Python 2.5+: # call_stmt ::= expr POP_TOP # expr ::= yield From d4381ef73ff5cd9f240425ad914c62bf5f820123 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 15 Feb 2020 05:04:42 -0500 Subject: [PATCH 223/489] More bugs found via sre_parse.py decompilation --- test/bytecode_2.3/08_while1_if_continue.pyc | Bin 637 -> 1294 bytes test/bytecode_2.4/08_while1_if_continue.pyc | Bin 491 -> 960 bytes test/bytecode_2.6/08_while1_if_continue.pyc | Bin 545 -> 1061 bytes .../looping/08_while1_if_continue.py | 29 +++++++++++++++++- uncompyle6/parsers/parse23.py | 2 ++ uncompyle6/parsers/parse24.py | 2 ++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/test/bytecode_2.3/08_while1_if_continue.pyc b/test/bytecode_2.3/08_while1_if_continue.pyc index fd3d766b1859fe789a776f33fa90a5b673c9e373..4fc32a63b37bbb072770930bc2330eef75e49a99 100644 GIT binary patch literal 1294 zcmb`G+lmuG5QeK}a@Zs)iyK5x5fxr~+<&$vag|*xLqv>cX1i*c@4dmZ6aI5OXScT)feH|ffhT2AP`}dY;i?auIa80DWiD;{i0JD~S zdx7tf1wY&$6&%X2uVr#C6~j}{Z{TSNMo-P%R_m6x0utT=8b-E^$`=Am8fb0z;3Va- zY#AKuB3)j~#@l7n|3EUhkK_A@wnEZcs3sr!65+8fAC-2r$7yS1YkJ_F{ul=}(TN&PHeRH-kd*T>t<8 delta 116 zcmeC<`paTw{fU?B$$q!EWCkc;1kw&bTr378QWzLo7#N~}3`Q`6ks*bNAy|WXqsMYa wM&8LE7{!$RG?+lDIe7UZ06i`iXaE2J diff --git a/test/bytecode_2.4/08_while1_if_continue.pyc b/test/bytecode_2.4/08_while1_if_continue.pyc index 00c1a58c6398be9c32afdfe72d88b6bf1292b51e..4023f31eb3d4fe73e499854d1f7c19a3170e77e0 100644 GIT binary patch literal 960 zcmaKq&uZI15XNWa*oy7AG$n)*d}#wgrNwCzD7mH3LvAK02SX1PjwB}wj%0Z^RDtAD z`e5xV^$GfYyZ%FyQkxxpyE{8Ozn!`H-Ru1NdGbcg zX*U=mpHA#1M3PMOG*6O<`!R+vKX2>+%IKRJ987sTPxHfRSH2A`|TdDc$}`a)^cc zOe~)Km4EVGVm5lbrlkM{ChhO*Ql{<07)5 e<1P)m&TmlpwUx``CnNbOcMVf&ciWro=YIg^J9kR} delta 116 zcmX@W{+ih=_Y*JIll^XS$qZ1y2&5f=xL6EGq%bhFFfc>`8H`{CBSQ)kL$C((Mvr(# rOnbp}qf}C6cX>kuF diff --git a/test/bytecode_2.6/08_while1_if_continue.pyc b/test/bytecode_2.6/08_while1_if_continue.pyc index fbe8975330ba71e272c669da20602d94b27d9880..79f4253640aa1630c42befccc66ffc23992bd256 100644 GIT binary patch literal 1061 zcmb`G&u-H|5XNWh{I?2KRaF%N^@5N=RSRtoNT3SD0Zvin-Z)?ddqY=p?KrzpjnrNc z4+f9GtMCNOH%?mMNJ+Hg$!2GEe&39L{9GG-|MvDnM#~S&^OY@X#WWA-lBn7s_VVZx*CEySiAyGy^ru)cqQ+|dK-@H) z+QOu1yVF4`Q%q41sd0PQvgb27?f?}*cE(P|gf{>o4}vU^y*~in$wu>iz2r V^76dO7lk{=;wN6NC;Q#vk{O_Y5lA}#aj_VXNMT@TVPJ>?G8n-OMurq7hF}fmjUIW7 u8oVG?TtI?>k(rSlh&h=2G?;+gATYrWWNCn8C+9KRP3B?|WCICvasdFO$`8;0 diff --git a/test/simple_source/looping/08_while1_if_continue.py b/test/simple_source/looping/08_while1_if_continue.py index eba6ead7b..de4dd7582 100644 --- a/test/simple_source/looping/08_while1_if_continue.py +++ b/test/simple_source/looping/08_while1_if_continue.py @@ -9,7 +9,8 @@ def readline (self): return # From 2.4.6 sre.py -# Bug in 2.4 and 2.3 was parsing the nested "while 1" with a "break" in it +# Bug has to do with "break" not being recognized +# and is a JUMP_FORWARD. def _parse(a, b, source, state): while 1: if b: @@ -17,3 +18,29 @@ def _parse(a, b, source, state): break else: raise + +def _parse2(source, state): + while 1: + if a: + if b: + while 1: + this = 1 + break + continue + + while 1: + if b: + break + + x = 3 + +# Bug was in 2.3 decompilation +def _parse3(source, state): + while 1: + if a: + if b: + x = 1 + while 1: + if a: + break + raise diff --git a/uncompyle6/parsers/parse23.py b/uncompyle6/parsers/parse23.py index a9f3b5c23..2411cd581 100644 --- a/uncompyle6/parsers/parse23.py +++ b/uncompyle6/parsers/parse23.py @@ -45,6 +45,8 @@ def p_misc23(self, args): # a "break" inside "l_stmts". while1stmt ::= _while1test l_stmts COME_FROM JUMP_BACK POP_TOP POP_BLOCK COME_FROM + while1stmt ::= _while1test l_stmts JUMP_BACK + POP_TOP POP_BLOCK list_comp ::= BUILD_LIST_0 DUP_TOP LOAD_ATTR store list_iter del_stmt list_for ::= expr for_iter store list_iter JUMP_BACK come_froms POP_TOP JUMP_BACK diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index ffb10f648..09b9afee4 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -45,6 +45,8 @@ def p_misc24(self, args): while1stmt ::= SETUP_LOOP l_stmts COME_FROM JUMP_BACK POP_TOP POP_BLOCK COME_FROM + continue ::= JUMP_BACK JUMP_ABSOLUTE + # Python 2.4 # The following has no "JUMP_BACK" after l_stmts because # l_stmts ends in a "break", "return", or "continue" From 2a040bee5fdf83b7dda010ecd510feaeb2b69720 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 16 Feb 2020 11:04:58 -0500 Subject: [PATCH 224/489] Tweak to run-and-email message --- test/run-and-email.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run-and-email.sh b/test/run-and-email.sh index 915f4da4b..362b88e09 100755 --- a/test/run-and-email.sh +++ b/test/run-and-email.sh @@ -122,5 +122,5 @@ done typeset -i RUN_ENDTIME=$(date +%s) (( time_diff = RUN_ENDTIME - RUN_STARTTIME)) elapsed_time=$(displaytime $time_diff) -echo "Run complete in $elapsed_time" >> $MAILBODY +echo "Run complete in $elapsed_time seconds" >> $MAILBODY cat $MAILBODY | mail -s "$HOST $MAIN weak verify in $elapsed_time" ${EMAIL} From 3d2fc7a5e6544428ecc6c4a47d91ea47859420de Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 16 Feb 2020 11:59:21 -0500 Subject: [PATCH 225/489] run-and-email message tweak --- test/run-and-email.sh | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/test/run-and-email.sh b/test/run-and-email.sh index 362b88e09..c053c9179 100755 --- a/test/run-and-email.sh +++ b/test/run-and-email.sh @@ -36,11 +36,7 @@ typeset -i RUN_STARTTIME=$(date +%s) # PYVERSIONS="3.5.6" MAILBODY=/tmp/${MAIN}-mailbody-$$.txt -<<<<<<< HEAD # for VERSION in 2.4.6 2.5.9 ; do -======= -# for VERSION in 3.3.7 ; do ->>>>>>> master for VERSION in $PYVERSIONS ; do typeset -i rc=0 LOGFILE=/tmp/${MAIN}-$VERSION-$$.log @@ -103,14 +99,10 @@ for VERSION in $PYVERSIONS ; do SUBJECT_PREFIX="pyenv weak verify (max $MAX_TESTS) for" if ((rc == 0)); then -<<<<<<< HEAD mailbody_line="Python $VERSION ok; ran in $time_diff seconds" -======= - mailbody_line="Python $VERSION ok; ran in $time_diff" ->>>>>>> master tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost else - mailbody_line="Python $VERSION failed; ran in $time_diff" + mailbody_line="Python $VERSION failed; ran in $time_diff seconds" actual_versions="$actual_versions failed;" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${USER}@localhost tail -v $LOGFILE | mail -s "$HOST $SUBJECT_PREFIX $VERSION not ok" ${EMAIL} @@ -122,5 +114,5 @@ done typeset -i RUN_ENDTIME=$(date +%s) (( time_diff = RUN_ENDTIME - RUN_STARTTIME)) elapsed_time=$(displaytime $time_diff) -echo "Run complete in $elapsed_time seconds" >> $MAILBODY +echo "Run complete in $elapsed_time" >> $MAILBODY cat $MAILBODY | mail -s "$HOST $MAIN weak verify in $elapsed_time" ${EMAIL} From 283db0faea2ee729b34ef97ce430b3091b882953 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 16 Feb 2020 19:35:17 -0500 Subject: [PATCH 226/489] run-and-email.sh tweak --- test/run-and-email.sh | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/test/run-and-email.sh b/test/run-and-email.sh index c053c9179..4d04233a5 100755 --- a/test/run-and-email.sh +++ b/test/run-and-email.sh @@ -23,12 +23,20 @@ fi mydir=$(dirname $bs) cd $mydir -. ../admin-tools/pyenv-older-versions -MAIN="test_pyenvlib.py" +branch=$(cat ../.git/HEAD | cut -d'/' -f 3) +if [[ $branch == 'python-2.4' ]]; then + . ../admin-tools/pyenv-older-versions +elif [[ $branch == 'master' ]]; then + . ../admin-tools/pyenv-newer-versions +else + echo &1>2 "Error git branch should either be 'master' or 'python-2.4'; got: '$branch'" + exit 1 +fi +MAIN="test_pyenvlib.py" USER=${USER:-rocky} EMAIL=${EMAIL:-rb@dustyfeet.com} -SUBJECT_PREFIX="${MAIN} for" +WHAT="uncompyle6 2.4 ${MAIN} for" MAX_TESTS=${MAX_TESTS:-800} export BATCH=1 @@ -79,6 +87,7 @@ for VERSION in $PYVERSIONS ; do if ! pyenv local $VERSION; then rc=1 mailbody_line="pyenv local $VERSION not installed" + echo $mailbody_line >> $MAILBODY else echo Python Version $(pyenv local) > $LOGFILE echo "" >> $LOGFILE @@ -93,17 +102,16 @@ for VERSION in $PYVERSIONS ; do typeset -i ALL_FILES_ENDTIME=$(date +%s) (( time_diff = ALL_FILES_ENDTIME - ALL_FILES_STARTTIME)) - displaytime $time_diff >> $LOGFILE + tiem_str=$(displaytime $time_diff >> $LOGFILE) + echo ${time_str}. >> $LOGFILE fi - - SUBJECT_PREFIX="pyenv weak verify (max $MAX_TESTS) for" + SUBJECT_PREFIX="$WHAT (max $MAX_TESTS) for" if ((rc == 0)); then - mailbody_line="Python $VERSION ok; ran in $time_diff seconds" + mailbody_line="Python $VERSION ok; ran in ${time_str}" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost else - mailbody_line="Python $VERSION failed; ran in $time_diff seconds" - actual_versions="$actual_versions failed;" + mailbody_line="Python $VERSION failed; ran in ${time_str}" tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${USER}@localhost tail -v $LOGFILE | mail -s "$HOST $SUBJECT_PREFIX $VERSION not ok" ${EMAIL} fi @@ -114,5 +122,5 @@ done typeset -i RUN_ENDTIME=$(date +%s) (( time_diff = RUN_ENDTIME - RUN_STARTTIME)) elapsed_time=$(displaytime $time_diff) -echo "Run complete in $elapsed_time" >> $MAILBODY -cat $MAILBODY | mail -s "$HOST $MAIN weak verify in $elapsed_time" ${EMAIL} +echo "${WHAT} complete in ${elapsed_time}." >> $MAILBODY +cat $MAILBODY | mail -s "$HOST $MAIN weak verify in ${elapsed_time}." ${EMAIL} From 57109ed066ee0e6bb0203809ac656569b280820a Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 31 Mar 2020 10:27:08 -0400 Subject: [PATCH 227/489] Conversion from 2.7+ --- uncompyle6/scanners/tok.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 75fda8a1e..781edf757 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -125,17 +125,15 @@ def __str__(self): def format(self, line_prefix="", token_num=None): if token_num is not None: - prefix = ( - "\n(%03d)%s L.%4d " % (token_num, line_prefix, self.linestart) - if self.linestart - else ("(%03d)%s" % (token_num, " " * (9 + len(line_prefix)))) - ) + if self.linestart: + prefix = "\n(%03d)%s L.%4d " % (token_num, line_prefix, self.linestart) + else: + prefix = "(%03d)%s" % (token_num, " " * (9 + len(line_prefix))) else: - prefix = ( - "\n%s L.%4d " % (line_prefix, self.linestart) - if self.linestart - else (" " * (9 + len(line_prefix))) - ) + if self.linestart: + prefix = "\n%s L.%4d " % (line_prefix, self.linestart) + else: + prefix = " " * (9 + len(line_prefix)) offset_opname = "%8s %-17s" % (self.offset, self.kind) if not self.has_arg: From 486f10be6cdf0a3be07dc99eb0392a514e2c5e84 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 16 Apr 2020 14:00:48 -0400 Subject: [PATCH 228/489] grammar normalization for "or" rule... tracks what's been going on in master. --- uncompyle6/parsers/parse2.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index d6dfa3b3a..b69381942 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -194,8 +194,9 @@ def p_expr2(self, args): expr ::= slice3 expr ::= unary_convert - and ::= expr jmp_false expr come_from_opt - or ::= expr jmp_true expr come_from_opt + expr_jit ::= expr jmp_true + and ::= expr jmp_false expr come_from_opt + or ::= expr_jit expr come_from_opt unary_convert ::= expr UNARY_CONVERT @@ -712,7 +713,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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)) - elif rule == ("or", ("expr", "jmp_true", "expr", "\\e_come_from_opt")): + elif rule == ("or", ("expr_jit", "expr", "\\e_come_from_opt")): expr2 = ast[2] return expr2 == "expr" and expr2[0] == "LOAD_ASSERT" elif lhs in ("delete_subscript", "del_expr"): From b29a008cb3be67be17741bd63655563ec15e6128 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 16 Apr 2020 16:24:40 -0400 Subject: [PATCH 229/489] 2.7 or reduce check rule --- ..._listcomp.pyc => 01_ifelse_listcomp.pyc-notyet} | Bin uncompyle6/parsers/parse27.py | 9 ++++++--- uncompyle6/parsers/reducecheck/or_check.py | 13 +++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) rename test/bytecode_2.7_run/{01_ifelse_listcomp.pyc => 01_ifelse_listcomp.pyc-notyet} (100%) diff --git a/test/bytecode_2.7_run/01_ifelse_listcomp.pyc b/test/bytecode_2.7_run/01_ifelse_listcomp.pyc-notyet similarity index 100% rename from test/bytecode_2.7_run/01_ifelse_listcomp.pyc rename to test/bytecode_2.7_run/01_ifelse_listcomp.pyc-notyet diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index ff2fcd0a3..4f30edf3c 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -7,6 +7,7 @@ from uncompyle6.parser import PythonParserSingle, nop_func from uncompyle6.parsers.parse2 import Python2Parser from uncompyle6.parsers.reducecheck import ( + or_check, ifelsestmt, tryelsestmt, ) @@ -101,8 +102,9 @@ def p_jump27(self, args): ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond - or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM - and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM + expr_jitop ::= expr JUMP_IF_TRUE_OR_POP + or ::= expr_jitop expr COME_FROM + and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM # compare_chained{1,2} is used exclusively in chained_compare compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP JUMP_IF_FALSE_OR_POP @@ -229,6 +231,7 @@ def customize_grammar_rules(self, tokens, customize): # FIXME: Put more in this table self.reduce_check_table = { # "ifelsestmt": ifelsestmt, + "or": or_check, "tryelsestmt": tryelsestmt, "tryelsestmtl": tryelsestmt, } @@ -239,7 +242,7 @@ def customize_grammar_rules(self, tokens, customize): self.check_reduce["except_handler"] = "tokens" self.check_reduce["except_handler_else"] = "tokens" - # self.check_reduce["or"] = "AST" + self.check_reduce["or"] = "AST" self.check_reduce["raise_stmt1"] = "AST" self.check_reduce["iflaststmtl"] = "AST" self.check_reduce["ifelsestmt"] = "AST" diff --git a/uncompyle6/parsers/reducecheck/or_check.py b/uncompyle6/parsers/reducecheck/or_check.py index 2a35adf3f..5e0c7d856 100644 --- a/uncompyle6/parsers/reducecheck/or_check.py +++ b/uncompyle6/parsers/reducecheck/or_check.py @@ -2,7 +2,10 @@ ASSERT_OPS = frozenset(["LOAD_ASSERT", "RAISE_VARARGS_1"]) def or_check(self, lhs, n, rule, ast, tokens, first, last): - if rule == ("or", ("expr_jt", "expr")): + rhs = rule[1] + if rhs in (("expr_jt", "expr"), + ("expr_jitop", "expr", "COME_FROM"), + ("expr_jit", "expr", "\\e_come_from_opt")): if tokens[last] in ASSERT_OPS or tokens[last-1] in ASSERT_OPS: return True @@ -18,7 +21,13 @@ def or_check(self, lhs, n, rule, ast, tokens, first, last): return True first_offset = tokens[first].off2int() - jmp_true_target = ast[0][1][0].attr + expr_jt = ast[0] + if expr_jt == "expr_jitop": + jump_true = expr_jt[1] + else: + jump_true = expr_jt[1][0] + + jmp_true_target = jump_true.attr jmp_true_target < first_offset if jmp_true_target < first_offset: From 6116eb64d1e3b53184274f73c2b60496072d761b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 19 May 2020 01:25:38 -0400 Subject: [PATCH 230/489] Bump version --- admin-tools/how-to-make-a-release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index ee3098583..b7f68d87d 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -55,7 +55,7 @@ # Make packages and tag $ . ./admin-tools/make-dist-older.sh - $ pyenv local 3.8.2 + $ pyenv local 3.8.3 $ twine check dist/uncompyle6-$VERSION* $ git tag release-python-2.4-$VERSION $ twine check dist/uncompyle6-$VERSION* From 1bfa4228d6e68af8b50f79fa08fe2d54bf79ca78 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 19 May 2020 01:27:54 -0400 Subject: [PATCH 231/489] Administrivia --- admin-tools/how-to-make-a-release.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index b7f68d87d..1e718a68d 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -59,9 +59,7 @@ $ twine check dist/uncompyle6-$VERSION* $ git tag release-python-2.4-$VERSION $ twine check dist/uncompyle6-$VERSION* - $ git tag release-python-2.4-$VERSION $ . ./admin-tools/make-dist-newer.sh - $ twine check dist/uncompyle6-$VERSION* # Upload single package and look at Rst Formating From 8ce921c5b7d36d24e0c6f7d249e2bb8be5708725 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 27 Jun 2020 11:21:34 -0400 Subject: [PATCH 232/489] Last commit fixed test_pep352 test --- test/stdlib/2.5-exclude.sh | 1 - test/stdlib/2.6-exclude.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index 6eeaea8a4..e2f2b2e2b 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -55,7 +55,6 @@ SKIP_TESTS=( [test_ossaudiodev.py]=1 # it fails on its own [test_pdb.py]=1 # Line-number specific [test_pep277.py]=1 # it fails on its own - [test_pep352.py]=1 # Investigate [test_plistlib.py]=1 # it fails on its own [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index 9de894ef5..cd766d665 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -60,7 +60,6 @@ SKIP_TESTS=( [test_ossaudiodev.py]=1 # it fails on its own [test_pep277.py]=1 # it fails on its own - [test_pep352.py]=1 # Investigate [test_pyclbr.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_py3kwarn.py]=1 # it fails on its own From 8de663ff520f4af8e7ef19ef5dff208ef9f95eea Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 5 Jul 2020 21:20:15 -0400 Subject: [PATCH 233/489] A test unexplicably got fixed somewhere previously --- test/stdlib/2.5-exclude.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index e2f2b2e2b..dc08ccb1a 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -59,7 +59,6 @@ SKIP_TESTS=( [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate [test_rgbimg.py]=1 # it fails on its own - [test_queue.py]=1 # Control flow? [test_scriptpackages.py]=1 # it fails on its own [test_socketserver.py]=1 # Too long to run - 42 seconds [test_sqlite.py]=1 # it fails on its own From 3dc6c31ae549d1fd42af1eee3cf9f5561c3b4d13 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 5 Jul 2020 22:11:37 -0400 Subject: [PATCH 234/489] Fix bug in detecting 2.7 except-handler ranges --- test/stdlib/2.7-exclude.sh | 1 - uncompyle6/parsers/parse26.py | 8 ++++++++ uncompyle6/parsers/parse27.py | 2 ++ uncompyle6/parsers/reducecheck/__init__.py | 1 + uncompyle6/parsers/reducecheck/except_handler.py | 12 ++++++++++++ 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 uncompyle6/parsers/reducecheck/except_handler.py diff --git a/test/stdlib/2.7-exclude.sh b/test/stdlib/2.7-exclude.sh index e189743f9..296cd679a 100644 --- a/test/stdlib/2.7-exclude.sh +++ b/test/stdlib/2.7-exclude.sh @@ -19,7 +19,6 @@ SKIP_TESTS=( [test_modulefinder.py]=1 # FIX [test_multiprocessing.py]=1 # On uncompyle2, takes 24 secs [test_poll.py]=1 # test takes too long to run: 11 seconds - [test_pwd.py]=1 # Takes too long [test_regrtest.py]=1 # [test_runpy.py]=1 # Long and fails on its own [test_select.py]=1 # Runs okay but takes 11 seconds diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 51941c222..abacd8bc0 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -6,6 +6,9 @@ from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse2 import Python2Parser +from uncompyle6.parsers.reducecheck import ( + except_handler, +) class Python26Parser(Python2Parser): @@ -345,6 +348,11 @@ def customize_grammar_rules(self, tokens, customize): WITH_CLEANUP END_FINALLY """) super(Python26Parser, self).customize_grammar_rules(tokens, customize) + self.reduce_check_table = { + "except_handler": except_handler, + } + + self.check_reduce['and'] = 'AST' self.check_reduce['assert_expr_and'] = 'AST' self.check_reduce["ifstmt"] = "tokens" diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 97c3411a5..7f76efe43 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -9,6 +9,7 @@ from uncompyle6.parsers.reducecheck import ( or_check, tryelsestmt, + except_handler, ) class Python27Parser(Python2Parser): @@ -230,6 +231,7 @@ def customize_grammar_rules(self, tokens, customize): # FIXME: Put more in this table self.reduce_check_table = { # "ifelsestmt": ifelsestmt, + "except_handler": except_handler, "or": or_check, "tryelsestmt": tryelsestmt, "tryelsestmtl": tryelsestmt, diff --git a/uncompyle6/parsers/reducecheck/__init__.py b/uncompyle6/parsers/reducecheck/__init__.py index 0ab057ae9..e7eafa3fb 100644 --- a/uncompyle6/parsers/reducecheck/__init__.py +++ b/uncompyle6/parsers/reducecheck/__init__.py @@ -1,4 +1,5 @@ from uncompyle6.parsers.reducecheck.and_check import * +from uncompyle6.parsers.reducecheck.except_handler import * from uncompyle6.parsers.reducecheck.except_handler_else import * from uncompyle6.parsers.reducecheck.ifelsestmt import * from uncompyle6.parsers.reducecheck.iflaststmt import * diff --git a/uncompyle6/parsers/reducecheck/except_handler.py b/uncompyle6/parsers/reducecheck/except_handler.py new file mode 100644 index 000000000..367a970a9 --- /dev/null +++ b/uncompyle6/parsers/reducecheck/except_handler.py @@ -0,0 +1,12 @@ +# Copyright (c) 2020 Rocky Bernstein + +def except_handler(self, lhs, n, rule, ast, tokens, first, last): + end_token = tokens[last-1] + # for t in range(first, last): + # print(tokens[t]) + # print("=" * 30) + + # Make sure come froms all come from within "except_handler". + if end_token != "COME_FROM": + return False + return end_token.attr < tokens[first].offset From d822017520f8235302d311a1a3b726d1b452a600 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Jul 2020 10:04:08 -0400 Subject: [PATCH 235/489] Add try/else reduction rule --- README.rst | 62 +++++++++++++------ test-unit/test_grammar.py | 3 +- test/stdlib/2.6-exclude.sh | 2 - uncompyle6/parsers/parse2.py | 2 +- uncompyle6/parsers/parse26.py | 40 +++++++++--- .../parsers/reducecheck/except_handler.py | 5 ++ uncompyle6/parsers/reducecheck/tryelsestmt.py | 9 +++ 7 files changed, 91 insertions(+), 32 deletions(-) diff --git a/README.rst b/README.rst index 8e6f2a32e..e1c6fd50d 100644 --- a/README.rst +++ b/README.rst @@ -68,10 +68,9 @@ are syntactically correct by running the Python interpreter for that bytecode version. Finally, in cases where the program has a test for itself, we can run the check on the decompiled code. -We are serious about testing, and use automated processes to find -bugs. In the issue trackers for other decompilers, you will find a -number of bugs we've found along the way. Very few to none of them are -fixed in the other decompilers. +We use an automated processes to find bugs. In the issue trackers for +other decompilers, you will find a number of bugs we've found along +the way. Very few to none of them are fixed in the other decompilers. Requirements ------------ @@ -171,11 +170,7 @@ All of the Python decompilers that I have looked at have problems decompiling Python's control flow. In some cases we can detect an erroneous decompilation and report that. -Python support is strongest in Python 2 for 2.7 and drops off as you -get further away from that. Support is also probably pretty good for -python 2.3-2.4 since a lot of the goodness of early the version of the -decompiler from that era has been preserved (and Python compilation in -that era was minimal) +Python support is pretty good for Python 2 There is some work to do on the lower end Python versions which is more difficult for us to handle since we don't have a Python @@ -214,17 +209,42 @@ which use their own magic and encrypt bytecode. With the exception of the Dropbox's old Python 2.5 interpreter this kind of thing is not handled. -We also don't handle PJOrion_ obfuscated code. For that try: PJOrion -Deobfuscator_ to unscramble the bytecode to get valid bytecode before -trying this tool. This program can't decompile Microsoft Windows EXE -files created by Py2EXE_, although we can probably decompile the code -after you extract the bytecode properly. For situations like this, you -might want to consider a decompilation service like `Crazy Compilers -`_. Handling -pathologically long lists of expressions or statements is slow. - - -There is lots to do, so please dig in and help. +We also don't handle PJOrion_ or otherwise obfuscated code. For +PJOrion try: PJOrion Deobfuscator_ to unscramble the bytecode to get +valid bytecode before trying this tool. This program can't decompile +Microsoft Windows EXE files created by Py2EXE_, although we can +probably decompile the code after you extract the bytecode +properly. Handling pathologically long lists of expressions or +statements is slow. We don't handle Cython_ or MicroPython_ which don't use bytecode. + +There are numerous bugs in decompilation. And that's true for every +other CPython decompiler I have encountered, even the ones that +claimed to be "perfect" on some particular version like 2.4. + +As Python progresses decompilation also gets harder because the +compilation is more sophisticated and the language itself is more +sophisticated. I suspect that attempts there will be fewer ad-hoc +attempts like unpyc37_ (which is based on a 3.3 decompiler) simply +because it is harder to do so. The good news, at least from my +standpoint, is that I think I understand what's needed to address the +problems in a more robust way. But right now until such time as +project is better funded, I do not intend to make any serious effort +to support Python versions 3.8 or 3.9, including bugs that might come +in. I imagine at some point I may be interested in it. + +You can easily find bugs by running the tests against the standard +test suite that Python uses to check itself. At any given time, there are +dozens of known problems that are pretty well isolated and that could +be solved if one were to put in the time to do so. The problem is that +there aren't that many people who have been working on bug fixing. + +Some of the bugs in 3.7 and 3.8 are simply a matter of back-porting +the fixes in decmopyle3. + +You may run across a bug, that you want to report. Please do so. But +be aware that it might not get my attention for a while. If you +sponsor or support the project in some way, I'll prioritize your +issues above the queue of other things I might be doing instead. See Also -------- @@ -241,6 +261,8 @@ See Also * https://github.com/zrax/pycdc : The README for this C++ code says it aims to support all versions of Python. It is best for Python versions around 2.7 and 3.3 when the code was initially developed. Accuracy for current versions of Python3 and early versions of Python is lacking. Without major effort, it is unlikely it can be made to support current Python 3. See its `issue tracker `_ for details. Currently lightly maintained. +.. _Cython: https://en.wikipedia.org/wiki/Cython +.. _MicroPython: https://micropotyon.org .. _trepan: https://pypi.python.org/pypi/trepan2g .. _compiler: https://pypi.python.org/pypi/spark_parser .. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index b922c246e..57f929894 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -44,7 +44,8 @@ def check_tokens(tokens, opcode_set): print(k, reduced_dup_rhs[k]) # assert not reduced_dup_rhs, reduced_dup_rhs - def test_dup_rule(self): + # FIXME: Something got borked here + def no_test_dup_rule(self): import inspect python_parser(PYTHON_VERSION, inspect.currentframe().f_code, is_pypy=IS_PYPY, diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index cd766d665..298623268 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -7,7 +7,6 @@ SKIP_TESTS=( # assert 0 # shouldn't reach here. [test_shutil.py]=1 - [test___all__.py]=1 # it fails on its own [test___all__.py]=1 # it fails on its own [test_aepack.py]=1 # Fails on its own @@ -61,7 +60,6 @@ SKIP_TESTS=( [test_pep277.py]=1 # it fails on its own [test_pyclbr.py]=1 # Investigate - [test_pwd.py]=1 # Long test - might work? Control flow? [test_py3kwarn.py]=1 # it fails on its own [test_scriptpackages.py]=1 # it fails on its own diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 1a986d39c..76eadfa7c 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -713,7 +713,7 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): 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)) - elif rule == ("or", ("expr_jit", "expr", "\\e_come_from_opt")): + elif rule == ("or", ("expr", "jmp_true", "expr", "\\e_come_from_opt")): expr2 = ast[2] return expr2 == "expr" and expr2[0] == "LOAD_ASSERT" elif lhs in ("delete_subscript", "del_expr"): diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index abacd8bc0..938e3b18d 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2019 Rocky Bernstein +# Copyright (c) 2017-2020 Rocky Bernstein """ spark grammar differences over Python2 for Python 2.6. """ @@ -6,9 +6,7 @@ from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse2 import Python2Parser -from uncompyle6.parsers.reducecheck import ( - except_handler, -) +from uncompyle6.parsers.reducecheck import (except_handler, tryelsestmt) class Python26Parser(Python2Parser): @@ -27,7 +25,11 @@ def p_try_except26(self, args): except_handler ::= JUMP_FORWARD COME_FROM except_stmts come_froms_pop END_FINALLY come_froms - except_handler ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY + except_handler ::= JUMP_FORWARD COME_FROM except_stmts + END_FINALLY + + except_handler ::= JUMP_FORWARD COME_FROM except_stmts + POP_TOP END_FINALLY come_froms except_handler ::= jmp_abs COME_FROM except_stmts @@ -36,6 +38,7 @@ def p_try_except26(self, args): except_handler ::= jmp_abs COME_FROM except_stmts END_FINALLY JUMP_FORWARD + # Sometimes we don't put in COME_FROM to the next statement # like we do in 2.7. Perhaps we should? try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK @@ -350,21 +353,28 @@ def customize_grammar_rules(self, tokens, customize): super(Python26Parser, self).customize_grammar_rules(tokens, customize) self.reduce_check_table = { "except_handler": except_handler, + "tryelsestmt": tryelsestmt, + "tryelsestmtl": tryelsestmt, } self.check_reduce['and'] = 'AST' self.check_reduce['assert_expr_and'] = 'AST' + self.check_reduce["except_handler"] = "tokens" self.check_reduce["ifstmt"] = "tokens" self.check_reduce["ifelsestmt"] = "AST" + self.check_reduce["forelselaststmtl"] = "tokens" + self.check_reduce["forelsestmt"] = "tokens" self.check_reduce['list_for'] = 'AST' self.check_reduce['try_except'] = 'tokens' self.check_reduce['tryelsestmt'] = 'AST' + self.check_reduce['tryelsestmtl'] = 'AST' def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python26Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) + lhs = rule[0] if invalid or tokens is None: return invalid if rule in ( @@ -397,6 +407,16 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): return not (jmp_target == tokens[test_index].offset or tokens[last].pattr == jmp_false.pattr) + elif lhs in ("forelselaststmtl", "forelsestmt"): + # print("XXX", first, last) + # for t in range(first, last): + # print(tokens[t]) + # print("=" * 30) + # FIXME: Figure out why this doesn't work on + # bytecode-1.4/anydbm.pyc + if self.version == 1.4: + return False + return tokens[last-1].off2int() > tokens[first].attr elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): for i in range(last-1, last-4, -1): t = tokens[i] @@ -413,7 +433,11 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): # The JUMP_ABSOLUTE has to be to the last POP_TOP or this is invalid ja_attr = ast[4].attr return tokens[last].offset != ja_attr - elif rule[0] == 'try_except': + elif lhs == 'try_except': + # FIXME: Figure out why this doesn't work on + # bytecode-1.4/anydbm.pyc + if self.version == 1.4: + return False # We need to distingush try_except from tryelsestmt and we do that # by checking the jump before the END_FINALLY # If we have: @@ -430,12 +454,12 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): last -= 1 if (tokens[last] == 'COME_FROM' and tokens[last-1] == 'END_FINALLY' - and tokens[last-2] == 'POP_TOP'): + and tokens[last-2] == 'POP_TOP'): # A jump of 2 is a jump around POP_TOP, END_FINALLY which # would indicate try/else rather than try return (tokens[last-3].kind not in frozenset(('JUMP_FORWARD', 'RETURN_VALUE')) or (tokens[last-3] == 'JUMP_FORWARD' and tokens[last-3].attr != 2)) - elif rule[0] == 'tryelsestmt': + elif lhs == 'tryelsestmt': # We need to distingush try_except from tryelsestmt and we do that # by making sure that the jump before the except handler jumps to diff --git a/uncompyle6/parsers/reducecheck/except_handler.py b/uncompyle6/parsers/reducecheck/except_handler.py index 367a970a9..05b447e3e 100644 --- a/uncompyle6/parsers/reducecheck/except_handler.py +++ b/uncompyle6/parsers/reducecheck/except_handler.py @@ -6,6 +6,11 @@ def except_handler(self, lhs, n, rule, ast, tokens, first, last): # print(tokens[t]) # print("=" * 30) + # FIXME: Figure out why this doesn't work on + # bytecode-1.4/anydbm.pyc + if self.version != 1.4: + return False + # Make sure come froms all come from within "except_handler". if end_token != "COME_FROM": return False diff --git a/uncompyle6/parsers/reducecheck/tryelsestmt.py b/uncompyle6/parsers/reducecheck/tryelsestmt.py index 7af38f37d..4e53746fa 100644 --- a/uncompyle6/parsers/reducecheck/tryelsestmt.py +++ b/uncompyle6/parsers/reducecheck/tryelsestmt.py @@ -6,7 +6,13 @@ def tryelsestmt(self, lhs, n, rule, ast, tokens, first, last): # Check the end of the except handler that there isn't a jump from # inside the except handler to the end. If that happens # then this is a "try" with no "else". + + # for t in range(first, last): + # print(tokens[t]) + # print("=" * 30) + except_handler = ast[3] + if except_handler == "except_handler_else": except_handler = except_handler[0] if except_handler == "except_handler": @@ -32,5 +38,8 @@ def tryelsestmt(self, lhs, n, rule, ast, tokens, first, last): except_handler_first_offset = leading_jump.first_child().off2int() else: except_handler_first_offset = leading_jump.off2int() + + if first_come_from.attr < tokens[first].offset: + return True return first_come_from.attr > except_handler_first_offset return False From b49033d584a6b13603a19b64a580b7b6e52c3fe6 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Jul 2020 10:26:35 -0400 Subject: [PATCH 236/489] test_pwd.py now works --- test/stdlib/2.4-exclude.sh | 1 - test/stdlib/2.5-exclude.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh index 771342227..a28d2cc68 100644 --- a/test/stdlib/2.4-exclude.sh +++ b/test/stdlib/2.4-exclude.sh @@ -45,7 +45,6 @@ SKIP_TESTS=( [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? - [test_pwd.py]=1 # Long test - might work? Control flow? [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index dc08ccb1a..783e50c78 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -56,7 +56,6 @@ SKIP_TESTS=( [test_pdb.py]=1 # Line-number specific [test_pep277.py]=1 # it fails on its own [test_plistlib.py]=1 # it fails on its own - [test_pwd.py]=1 # Long test - might work? Control flow? [test_pyclbr.py]=1 # Investigate [test_rgbimg.py]=1 # it fails on its own [test_scriptpackages.py]=1 # it fails on its own From c2e3ff0f43de803501042092421c4b2569fc593a Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Jul 2020 14:15:08 -0400 Subject: [PATCH 237/489] Set bug-report expectations. --- .github/ISSUE_TEMPLATE/bug-report.md | 10 +---- HOW-TO-REPORT-A-BUG.md | 57 +++++++--------------------- 2 files changed, 15 insertions(+), 52 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 413d6a233..48ebef5f3 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -4,7 +4,8 @@ about: Tell us about uncompyle6 bugs --- - ## Description diff --git a/HOW-TO-REPORT-A-BUG.md b/HOW-TO-REPORT-A-BUG.md index 6f23f1c63..7fa9b3b8c 100644 --- a/HOW-TO-REPORT-A-BUG.md +++ b/HOW-TO-REPORT-A-BUG.md @@ -30,31 +30,9 @@ files that I know of that will cause problems. See, for example, the list in [`test/stdlib/runtests.sh`](https://github.com/rocky/python-uncompyle6/blob/master/test/stdlib/runtests.sh). -But I understand: you would the bugs _you_ encounter addressed before -all the other known bugs. - -From my standpoint, the good thing about the bugs listed in -`runtests.sh` is that each test case is small and isolated to a single -kind of problem. And I'll tend to fix easier, more isolated cases than -generic "something's wrong" kinds of bugs where I'd have to do a bit -of work to figure out what's up, if not use some sort of mind reading, -make some guesses, and perform some experiments to see if the guesses -are correct. I can't read minds, nor am I into guessing games; I'd -rather devote the effort spent instead towards fixing bugs that are -precisely defined. - -And it often turns out that by just fixing the well-defined and -prescribed cases, the ill-defined amorphous cases as well will get -handled as well. - -In sum, you may need to do some work to have the bug you have found -handled before the hundreds of other bugs, and other things I could be -doing. - -No one is getting paid to work to work on this project, let alone the -bugs you may have an interest in. If you require decompiling bytecode -immediately, consider using a decompilation service, listed further -down in this document. +There are far more bug reporters than there are bug fixers. + +Unless you are a sponsor of this project, it may take a while, maybe a week or so, before the bug report is noticed, let alone acted upon. Things eventually get fixed, but it may take years. # Is it really a bug? @@ -189,7 +167,7 @@ disassemble Python bytecode. And as Richard Feynman once said, "What one fool can learn, so can another." If this is too difficult, or too time consuming, or not of interest to -you, then perhaps what require is a decompilation service. [Crazy +you, then you might consider sponsoring the project. [Crazy Compilers](http://www.crazy-compilers.com/decompyle/) offers a byte-code decompiler service for versions of Python up to 2.6. (If there are others around let me know and I'll list them here.) @@ -217,10 +195,7 @@ likely the problem will be fixed and fixed sooner. # Karma I realize that following the instructions given herein puts a bit of -burden on the bug reporter. In my opinion, this is justified as -attempts to balance somewhat the burden and effort needed to fix the -bug and the attempts to balance number of would-be bug reporters with -the number of bug fixers. Better bug reporters are more likely to move +burden on the bug reporter. This is justified as attempts to balance somewhat the burden and effort needed to fix the bug and the attempts to balance number of would-be bug reporters with the number of bug fixers. Better bug reporters are more likely to move in the category of bug fixers. The barrier to reporting a big is pretty small: all you really need is @@ -228,22 +203,14 @@ a github account, and the ability to type something after clicking some buttons. So the reality is that many people just don't bother to read these instructions, let alone follow it to any simulacrum. -And the reality is also that bugs sometimes get fixed even though -these instructions are not followed. +That said, bugs sometimes get fixed even though these instructions are not followed. + +I may take into consideration is the bug reporter's karma. -So one factors I may take into consideration is the bug reporter's karma. +* Have you demonstrably contributed to open source? I may look at your github profile to see what contributions you have made, how popular those contributions are, or how popular you are. +* How appreciative are you? Have you starred this project that you are seeking help from? Have you starred _any_ github project? And the above two kind of feed into ... +* Attitude. Some people feel that they are doing me and the world a great favor by just pointing out that there is a problem whose solution would greatly benefit them. (This might account partially those that have this attitude often don't read or follow instructions such as those given here.) -* Have you demonstrably contributed to open source? I may look at your - github profile to see what contributions you have made, how popular - those contributions are, or how popular you are. -* How appreciative are you? Have you starred this project that you are - seeking help from? Have you starred _any_ github project? And the above - two kind of feed into ... -* Attitude. Some people feel that they are doing me and the world a - great favor by just pointing out that there is a problem whose solution - would greatly benefit them. Perhaps this is why they feel that - instructions are not to be followed by them, nor any need for - showing evidence gratitude when help is offered them. # Confidentiality of Bug Reports @@ -255,6 +222,8 @@ remains would not be an issue. However feel free to remove any comments, and modify variable names or constants in the source code. +If there is some legitimate reason to keep confidentiality, you can contact me by email to explain the extenuating circumstances. However I tend to discard without reading anonymous email. + # Ethics I do not condone using this program for unethical or illegal purposes. From 844144f90adcc66427cfdc9c90c9be031fd7eedb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Jul 2020 13:12:42 -0400 Subject: [PATCH 238/489] Get ready for release 3.7.3 --- NEWS.md | 12 ++++++++++++ admin-tools/how-to-make-a-release.md | 4 ++-- admin-tools/pyenv-newer-versions | 2 +- uncompyle6/version.py | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4b5dcfc77..7752f9189 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,15 @@ +3.7.3: 2020-7-25 +================ + +Mostly small miscellaneous bug fixes + +* `__doc__ = DocDescr()` from `test_descr.py` was getting confused as a docstring. +* detect 2.7 exchandler range better +* Add for .. else reduction checks on 2.6 and before +* Add reduce check for 2.7 augmented assign +* Add VERSION in a pydoc-friendly way + + 3.7.2: 2020-6-27 ================ diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index c9ed644d4..91532cdbd 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -39,7 +39,7 @@ # Make sure pyenv is running and check newer versions - $ pyenv local && source admin-tools/check-newer-versions.sh + $ admin-tools/check-newer-versions.sh # Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want. @@ -62,7 +62,7 @@ # Check package on github - $ mkdir /tmp/gittest; pushd /tmp/gittest + $ [[ ! -d /tmp/gittest ]] && mkdir /tmp/gittest; pushd /tmp/gittest $ pyenv local 3.7.5 $ pip install -e git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6 $ uncompyle6 --help diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index 59583f750..5b31d293c 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.7 3.8.3' +export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.7 3.8.4' diff --git a/uncompyle6/version.py b/uncompyle6/version.py index c8a669e8c..b43d84bef 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -12,4 +12,4 @@ # along with this program. If not, see . # This file is suitable for sourcing inside POSIX shell as # well as importing into Python -VERSION="3.7.2" # noqa +VERSION="3.7.3" # noqa From fae5525514fd31aaa436566407dd0e0dfedd7336 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Jul 2020 15:42:31 -0400 Subject: [PATCH 239/489] Administrivia --- admin-tools/how-to-make-a-release.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/admin-tools/how-to-make-a-release.md b/admin-tools/how-to-make-a-release.md index 2966c5b44..6420821c5 100644 --- a/admin-tools/how-to-make-a-release.md +++ b/admin-tools/how-to-make-a-release.md @@ -59,11 +59,12 @@ $ twine check dist/uncompyle6-$VERSION* $ ./admin-tools/make-dist-newer.sh $ twine check dist/uncompyle6-$VERSION* + $ git tag release-python-2.4-$VERSION # Check package on github $ [[ ! -d /tmp/gittest ]] && mkdir /tmp/gittest; pushd /tmp/gittest - $ pyenv local 3.7.5 + $ pyenv local 3.8.3 $ pip install -e git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6 $ uncompyle6 --help $ pip uninstall uncompyle6 @@ -93,3 +94,7 @@ Todo: turn this into a script in `admin-tools` $ git push --tags $ git pull --tags + +# Move dist files to uploaded + + $ mv -v dist/uncompyle6-${VERSION}* dist/uploaded From 732e3331b8c791cd8cd7c15e4bb1205f53a68657 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Sep 2020 05:41:49 -0400 Subject: [PATCH 240/489] Get ready for release 3.7.4 --- NEWS.md | 11 +++++ __pkginfo__.py | 80 +++++++++++++++++--------------- admin-tools/pyenv-newer-versions | 2 +- uncompyle6/show.py | 9 ++-- uncompyle6/util.py | 2 + uncompyle6/version.py | 2 +- 6 files changed, 64 insertions(+), 42 deletions(-) diff --git a/NEWS.md b/NEWS.md index 7752f9189..375a0d71a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,14 @@ +3.7.4: 2020-8-05 +================ + +* Fragment parsing was borked. This means deparsing in trepan2/trepan3k was broken +* 3.7+: narrow precedence for call tatement +* del_stmt -> delete to better match Python AST +* 3.8+ Add another `forelsestmt` (found only in a loop) +* 3.8+ Add precedence on walrus operator +* More files blackened +* bump min xdis version + 3.7.3: 2020-7-25 ================ diff --git a/__pkginfo__.py b/__pkginfo__.py index ff206581b..c425c768b 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -33,65 +33,71 @@ # 3.4 | pip | 19.1.1 | # Things that change more often go here. -copyright = """ +copyright = """ Copyright (C) 2015-2020 Rocky Bernstein . """ -classifiers = ["Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2.4", - "Programming Language :: Python :: 2.5", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.0", - "Programming Language :: Python :: 3.1", - "Programming Language :: Python :: 3.2", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Topic :: Software Development :: Debuggers", - "Topic :: Software Development :: Libraries :: Python Modules", - ] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2.4", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.0", + "Programming Language :: Python :: 3.1", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Topic :: Software Development :: Debuggers", + "Topic :: Software Development :: Libraries :: Python Modules", +] # The rest in alphabetic order -author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others" -author_email = "rb@dustyfeet.com" -entry_points = { +author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others" +author_email = "rb@dustyfeet.com" +entry_points = { "console_scripts": [ "uncompyle6=uncompyle6.bin.uncompile:main_bin", "pydisassemble=uncompyle6.bin.pydisassemble:main", - ]} -ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.0", - "xdis >= 4.7.0, <5.1.0"] - -license = "GPL3" -mailing_list = "python-debugger@googlegroups.com" -modname = "uncompyle6" -py_modules = None -short_desc = "Python cross-version byte-code decompiler" -web = "https://github.com/rocky/python-uncompyle6/" + ] +} +ftp_url = None +install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 5.0.4, <5.1.0"] + +license = "GPL3" +mailing_list = "python-debugger@googlegroups.com" +modname = "uncompyle6" +py_modules = None +short_desc = "Python cross-version byte-code decompiler" +web = "https://github.com/rocky/python-uncompyle6/" # tracebacks in zip files are funky and not debuggable zip_safe = True import os.path + + def get_srcdir(): filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__))) return os.path.realpath(filename) + srcdir = get_srcdir() + def read(*rnames): return open(os.path.join(srcdir, *rnames)).read() + # Get info from files; set: long_description and VERSION -long_description = ( read("README.rst") + "\n" ) +long_description = read("README.rst") + "\n" exec(read("uncompyle6/version.py")) diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions index 89924a551..d1dba9537 100644 --- a/admin-tools/pyenv-newer-versions +++ b/admin-tools/pyenv-newer-versions @@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.5.9 3.6.11 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.8 3.8.5' +export PYVERSIONS='3.5.9 3.6.12 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.9 3.8.5' diff --git a/uncompyle6/show.py b/uncompyle6/show.py index 13aca7337..25acdc5c2 100644 --- a/uncompyle6/show.py +++ b/uncompyle6/show.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Rocky Bernstein +# Copyright (C) 2018, 2020 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -47,8 +47,11 @@ def maybe_show_tree(walker, ast): stream = walker.showast else: stream = sys.stdout - if (isinstance(walker.showast, dict) and walker.showast.get("Full", False) - and hasattr(walker, "str_with_template")): + if ( + isinstance(walker.showast, dict) + and walker.showast.get("Full", False) + and hasattr(walker, "str_with_template") + ): walker.str_with_template(ast) else: stream.write(str(ast)) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 3a6c55612..aeec12eda 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -5,10 +5,12 @@ from math import copysign from uncompyle6 import PYTHON_VERSION + def is_negative_zero(n): """Returns true if n is -0.0""" return n == 0.0 and copysign(1, n) == -1 + def better_repr(v, version): """Work around Python's unorthogonal and unhelpful repr() for primitive float and complex.""" diff --git a/uncompyle6/version.py b/uncompyle6/version.py index b43d84bef..060dfaaf3 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -12,4 +12,4 @@ # along with this program. If not, see . # This file is suitable for sourcing inside POSIX shell as # well as importing into Python -VERSION="3.7.3" # noqa +VERSION="3.7.4" # noqa From a0cb9c5d6a715e507bee39cfcb644d84b52e905b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 31 Oct 2020 11:37:58 -0400 Subject: [PATCH 241/489] merge hell --- uncompyle6/main.py | 3 +-- uncompyle6/util.py | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index d76948103..0f0323433 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -102,8 +102,7 @@ def write(s): __version__, co_pypy_str, bytecode_version, - " (%s)" % str(magic_int) if magic_int else "", - run_pypy_str, + " (%s)" % m, run_pypy_str, "\n# ".join(sys_version_lines), ) ) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 3c9a3420e..d9f9c2725 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -13,11 +13,6 @@ def is_negative_zero(n): from uncompyle6 import PYTHON_VERSION -def is_negative_zero(n): - """Returns true if n is -0.0""" - return n == 0.0 and copysign(1, n) == -1 - - def better_repr(v, version): """Work around Python's unorthogonal and unhelpful repr() for primitive float and complex.""" From 3684b383108b77e4b75b67d62feb69bc62d6a25e Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 15 Jun 2021 22:50:36 -0400 Subject: [PATCH 242/489] One more test --- test/bytecode_2.4_run/01_lambda_call.pyc | Bin 0 -> 298 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/bytecode_2.4_run/01_lambda_call.pyc diff --git a/test/bytecode_2.4_run/01_lambda_call.pyc b/test/bytecode_2.4_run/01_lambda_call.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a680c699a999444c9b96cedf171bd9ee80b7ff95 GIT binary patch literal 298 zcmYLF!D<3A6r8sfS_-vaA?(F!J&SEAUIp#V%bMM!va;(gNd$$ST7Ry;)4QziMXP}~ znK#Ls3@QH}?x&x>iwx%#@&3x?x(piF0|xjZ%n62|Nw|)%icsHze1vZT=@vfX8=lCB z;lJL+N7OIyv8a=PUg$Q^88gHe@ExWuFYCf2uG-kl^wQ08FzEH4lR}lLR!OFc;;G*G zJH9zQX`_}*iAjEFnkJWa5(|0(mAdev@@?+koHN$v)p~4gWltd_<2A%g;)RKqU@Twq FNJp#AG6( Date: Thu, 21 Oct 2021 16:12:39 -0400 Subject: [PATCH 243/489] Break out code for 3.3-3.5 versions --- .github/workflows/osx.yml | 6 +++--- .github/workflows/ubuntu.yml | 6 +++--- .github/workflows/windows.yml | 6 +++--- admin-tools/pyenv-3.3-3.5-versions | 9 +++++++++ admin-tools/setup-python-3.3.sh | 15 +++++++++++++++ setup.py | 4 ++-- 6 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 admin-tools/pyenv-3.3-3.5-versions create mode 100755 admin-tools/setup-python-3.3.sh diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 79faa7c66..89bab85f4 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -2,9 +2,9 @@ name: uncompyle6 (osx) on: push: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] pull_request: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: [3.7, 3.8] + python-version: [3.3, 3.4, 3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index e071eb0a4..202091ba0 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -2,16 +2,16 @@ name: uncompyle6 (ubuntu) on: push: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] pull_request: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.3, 3.4, 3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index abfecf748..26ab2b379 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,9 +2,9 @@ name: uncompyle6 (windows) on: push: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] pull_request: - branches: [ master ] + branches: [ python-3.3-to-3.5 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [windows] - python-version: [3.7, 3.8] + python-version: [3.3, 3.4, 3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/admin-tools/pyenv-3.3-3.5-versions b/admin-tools/pyenv-3.3-3.5-versions new file mode 100644 index 000000000..3b030b8ae --- /dev/null +++ b/admin-tools/pyenv-3.3-3.5-versions @@ -0,0 +1,9 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the python-2.4 branch. + +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS=' 3.3.7 3.4.10 3.5.10 ' diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh new file mode 100755 index 000000000..5af28261b --- /dev/null +++ b/admin-tools/setup-python-3.3.sh @@ -0,0 +1,15 @@ +#!/bin/bash +PYTHON_VERSION=3.3.7 +pyenv local $PYTHON_VERSION + +owd=$(pwd) +bs=${BASH_SOURCE[0]} + +mydir=$(dirname $bs) +fulldir=$(readlink -f $mydir) +cd $fulldir/.. +(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh) +cd $owd +rm -v */.python-version || true + +git checkout python-3.3-to-3.5 && git pull && pyenv local $PYTHON_VERSION diff --git a/setup.py b/setup.py index 1d1da4afd..e67870730 100755 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ """Setup script for the 'uncompyle6' distribution.""" SYS_VERSION = sys.version_info[0:2] -if not ((2, 6) <= SYS_VERSION <= (3, 9)): - mess = "Python Release 2.6 .. 3.9 are supported in this code branch." +if not ((3, 3) <= SYS_VERSION <= (3, 5)): + mess = "Python Release 3.3 .. 3.9 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." From ddbfc168c5806144a538b7f288b300fed25d4cee Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Oct 2021 16:14:26 -0400 Subject: [PATCH 244/489] CI testing 3.5, 3.6 Workflows doesn't go back before 3.5. It is okay to use 3.6 in testing the 3.3-3.5 branch --- .github/workflows/osx.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 89bab85f4..6abccb6db 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: [3.3, 3.4, 3.5] + python-version: [3.5, 3.6] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 202091ba0..8d24bcd0a 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.3, 3.4, 3.5] + python-version: [3.5, 3.6] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 26ab2b379..0b2e1937b 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [windows] - python-version: [3.3, 3.4, 3.5] + python-version: [3.5, 3.6] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 4d84a723f4fa5b3dae4a76bf6fc4045953de43f2 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Oct 2021 16:16:46 -0400 Subject: [PATCH 245/489] Use right xdis branch --- .github/workflows/osx.yml | 4 ++-- .github/workflows/ubuntu.yml | 4 ++-- .github/workflows/windows.yml | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 6abccb6db..4a0772d17 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: [3.5, 3.6] + python-version: [3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -23,7 +23,7 @@ jobs: run: | python -m pip install --upgrade pip # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 8d24bcd0a..f22f5849b 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5, 3.6] + python-version: [3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,7 +22,7 @@ jobs: run: | python -m pip install --upgrade pip # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0b2e1937b..9a29a5d61 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [windows] - python-version: [3.5, 3.6] + python-version: [3.5] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,8 +22,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 From 37f953c35360d08f678626fc61c43322a3355c1e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Oct 2021 16:28:41 -0400 Subject: [PATCH 246/489] More version twiddling --- uncompyle6/semantics/make_function3.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/uncompyle6/semantics/make_function3.py b/uncompyle6/semantics/make_function3.py index 39603b5f5..a7ae5f3b2 100644 --- a/uncompyle6/semantics/make_function3.py +++ b/uncompyle6/semantics/make_function3.py @@ -19,7 +19,6 @@ from xdis import iscode, code_has_star_arg, code_has_star_star_arg, CO_GENERATOR from uncompyle6.scanner import Code from uncompyle6.parsers.treenode import SyntaxTree -from uncompyle6 import PYTHON3 from uncompyle6.semantics.parser_error import ParserError from uncompyle6.parser import ParserError as ParserError2 from uncompyle6.semantics.helper import ( @@ -29,11 +28,6 @@ find_none, ) -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest - from uncompyle6.show import maybe_show_tree_param_default # FIXME: DRY the below code... @@ -90,12 +84,9 @@ def build_param(ast, name, default): # positional args are before kwargs defparams = node[: args_node.attr[0]] pos_args, kw_args, annotate_argc = args_node.attr - if "return" in annotate_args.keys(): - annotate_argc = len(annotate_args) - 1 else: defparams = node[: args_node.attr] kw_args = 0 - annotate_argc = 0 pass annotate_dict = {} @@ -104,9 +95,9 @@ def build_param(ast, name, default): n = self.traverse(annotate_args[name], indent="") annotate_dict[name] = n - if 3.0 <= self.version <= 3.2: + if 3.0 <= self.version < (3, 3): lambda_index = -2 - elif 3.03 <= self.version: + elif self.version < (3, 4): lambda_index = -3 else: lambda_index = None @@ -142,7 +133,6 @@ def build_param(ast, name, default): self.ERROR = p return - kw_pairs = args_node.attr[1] indent = self.indent if is_lambda: From cfb5c442e2e7ba7e142dea8743eb563d900af3df Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Oct 2021 16:33:42 -0400 Subject: [PATCH 247/489] Version twiddling --- uncompyle6/semantics/make_function3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/make_function3.py b/uncompyle6/semantics/make_function3.py index a7ae5f3b2..d749cf0b1 100644 --- a/uncompyle6/semantics/make_function3.py +++ b/uncompyle6/semantics/make_function3.py @@ -95,7 +95,7 @@ def build_param(ast, name, default): n = self.traverse(annotate_args[name], indent="") annotate_dict[name] = n - if 3.0 <= self.version < (3, 3): + if (3, 0) <= self.version < (3, 3): lambda_index = -2 elif self.version < (3, 4): lambda_index = -3 From ada786e08ce616cf462943dbbea67cbf06a74500 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 21 Oct 2021 16:38:12 -0400 Subject: [PATCH 248/489] Administrivia --- admin-tools/setup-master.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index d5fa64517..0bf2a0e23 100755 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -20,4 +20,4 @@ cd $fulldir/.. (cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ git checkout master && pyenv local $PYTHON_VERSION && git pull cd $owd -rm -v */.python-version || true +rm -v */.python-version >/dev/null 2>&1 || true From 01859ce8207cdce7d5b49cdaae1eaa1869f2d777 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 07:51:15 -0400 Subject: [PATCH 249/489] Don not upgrade pip on older pythons --- .github/workflows/osx.yml | 7 ++----- .github/workflows/windows.yml | 6 ++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 4a0772d17..7145a3307 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -21,11 +21,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis - pip install -e . - pip install -r requirements-dev.txt + pip install --disable-version-check -e . + pip install --disable-version-check -r requirements-dev.txt - name: Test uncompyle6 run: | make check diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9a29a5d61..7f9b8ccf7 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -21,10 +21,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis - pip install -e . - pip install -r requirements-dev.txt + pip install --disable-version-check -e . + pip install --disable-version-check -r requirements-dev.txt - name: Test uncompyle6 run: | make check From ce58ed74344c630c78abdc2e75d288bd4477bb77 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 07:57:38 -0400 Subject: [PATCH 250/489] CircleCI testing --- .circleci/config.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 319810c7f..c16363618 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,7 +13,7 @@ jobs: # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ docker: - - image: circleci/python:3.6.9 + - image: circleci/python:3.5 steps: # Machine Setup # 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 @@ -38,7 +38,6 @@ jobs: - run: command: | # Use pip to install dependengcies - pip install --user --upgrade setuptools pip install --user -e . pip install --user -r requirements-dev.txt @@ -58,8 +57,7 @@ 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: sudo python ./setup.py develop && make check-3.6 - - run: cd ./test/stdlib && bash ./runtests.sh 'test_[p-z]*.py' + - run: sudo python ./setup.py develop && make check # 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 From 52262dc38a32912ff53d50568cfa04227915495e Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 08:27:47 -0400 Subject: [PATCH 251/489] Merge hell --- .github/workflows/osx.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 0a31d9e15..7145a3307 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -12,11 +12,7 @@ jobs: strategy: matrix: os: [macOS] -<<<<<<< HEAD python-version: [3.5] -======= - python-version: [3.6, 3.7, 3.8] ->>>>>>> master steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From fad50891750a4b0675b21091fdd41efa8768208f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 08:33:39 -0400 Subject: [PATCH 252/489] Administrivia --- admin-tools/setup-python-2.4.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 7f4495da6..a64bad0b0 100755 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -11,7 +11,6 @@ mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. (cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ - (cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull cd $owd rm -v */.python-version || true From 1509bc4828d64ee8483ab72074fc5a11bff1da64 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 08:35:00 -0400 Subject: [PATCH 253/489] Administrivia --- admin-tools/setup-python-3.3.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 admin-tools/setup-python-3.3.sh diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh new file mode 100644 index 000000000..5af28261b --- /dev/null +++ b/admin-tools/setup-python-3.3.sh @@ -0,0 +1,15 @@ +#!/bin/bash +PYTHON_VERSION=3.3.7 +pyenv local $PYTHON_VERSION + +owd=$(pwd) +bs=${BASH_SOURCE[0]} + +mydir=$(dirname $bs) +fulldir=$(readlink -f $mydir) +cd $fulldir/.. +(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh) +cd $owd +rm -v */.python-version || true + +git checkout python-3.3-to-3.5 && git pull && pyenv local $PYTHON_VERSION From cef32036016fbee6c1be0e443531534e408c82e7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 08:46:05 -0400 Subject: [PATCH 254/489] merge hell --- pytest/test_fjt.py | 1 - uncompyle6/scanner.py | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/pytest/test_fjt.py b/pytest/test_fjt.py index 2d1b05e36..356c1b221 100644 --- a/pytest/test_fjt.py +++ b/pytest/test_fjt.py @@ -23,7 +23,6 @@ def test_if_in_for(): code = bug.func_code scan = get_scanner(PYTHON_VERSION_TRIPLE) if (2, 7) <= PYTHON_VERSION_TRIPLE < (3, 1) and not IS_PYPY: ->>>>>>> python-3.3-to-3.5 scan.build_instructions(code) fjt = scan.find_jump_targets(False) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 75f8d3031..6efc658ca 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -24,16 +24,12 @@ from array import array import sys -<<<<<<< HEAD -from uncompyle6 import PYTHON3, IS_PYPY, PYTHON_VERSION -======= ->>>>>>> python-3.3-to-3.5 from uncompyle6.scanners.tok import Token -from xdis.version_info import PYTHON3, IS_PYPY, version_tuple_to_str +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, PYTHON3, version_tuple_to_str import xdis from xdis import Bytecode, canonic_python_version, code2num, instruction_size, extended_arg_val, next_offset -if PYTHON_VERSION < 2.6: +if PYTHON_VERSION_TRIPLE < (2, 6): from xdis.namedtuple24 import namedtuple else: from collections import namedtuple From d75bf1c32a9b5d84589b91cf4f9bf1c4444e2287 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 08:56:33 -0400 Subject: [PATCH 255/489] Admnistrivia --- .circleci/config.yml | 3 +++ admin-tools/setup-python-2.4.sh | 1 + 2 files changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c94b8b26..e46eb89f2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,7 @@ version: 2 +filters: + branches: + only: python-2.4 jobs: build: parallelism: 1 diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index f2ca2c2fc..4ca2901d4 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -11,6 +11,7 @@ mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. (cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ + (cd ../python-xdis && . ./admint-tools/setup-python-2.4.sh) && \ git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull cd $owd rm -v */.python-version || true From b8e9ce8a7a31b4ed9248efe94d55c0b25434baef Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 09:06:14 -0400 Subject: [PATCH 256/489] CircleCI testing --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e46eb89f2..ea652aaa2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,7 +35,10 @@ jobs: - v2-dependencies- - run: - command: sudo easy_install xdis spark-parser && sudo pip install -e . && sudo pip install -r requirements-dev.txt + command: | # Use pip to install dependengcies + sudo easy_install click==7.1.2 + sudo pip install -e . + sudo pip install -r requirements-dev.txt # Save dependency cache - save_cache: From 8a9a4ca6cc9c63f88ce660f1d2d202ed80b7699a Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 09:12:45 -0400 Subject: [PATCH 257/489] CircleCI testing --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ea652aaa2..f85061eaf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,6 +37,8 @@ jobs: - run: command: | # Use pip to install dependengcies sudo easy_install click==7.1.2 + # Until next release use github xdis + sudo pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis sudo pip install -e . sudo pip install -r requirements-dev.txt From 536d45deb11189657bed6892eaa5d61f5d86b4da Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 10:01:53 -0400 Subject: [PATCH 258/489] Another version bug --- pytest/test_single_compile.py | 5 +++-- uncompyle6/semantics/pysource.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pytest/test_single_compile.py b/pytest/test_single_compile.py index cc5bdb572..3302fb926 100644 --- a/pytest/test_single_compile.py +++ b/pytest/test_single_compile.py @@ -1,6 +1,7 @@ -from uncompyle6 import PYTHON_VERSION, code_deparse +from uncompyle6 import code_deparse +from xdis.version_info import PYTHON_VERSION_TRIPLE -if PYTHON_VERSION > 2.6: +if PYTHON_VERSION_TRIPLE >= (2, 7): def test_single_mode(): single_expressions = ( 'i = 1', diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 6627bb617..75498832c 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -135,7 +135,8 @@ IS_PYPY = "__pypy__" in sys.builtin_module_names PYTHON3 = sys.version_info >= (3, 0) -from xdis import iscode, COMPILER_FLAG_BIT, sysinfo2float +from xdis import iscode, COMPILER_FLAG_BIT +from xdis.version_info import PYTHON_VERSION_TRIPLE from uncompyle6.parser import get_python_parser from uncompyle6.parsers.treenode import SyntaxTree @@ -2568,7 +2569,7 @@ def code_deparse( assert iscode(co) if version is None: - version = sysinfo2float() + version = PYTHON_VERSION_TRIPLE # store final output stream for case of error scanner = get_scanner(version, is_pypy=is_pypy) From 79d5790e3f0b71ceaf7d86594cf55665fb8c0cdb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 23 Oct 2021 16:06:02 -0400 Subject: [PATCH 259/489] Workflows CI adjusment --- .github/workflows/osx.yml | 6 ++++-- .github/workflows/windows.yml | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 7145a3307..7dac2d778 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -21,8 +21,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - pip install --disable-version-check -e . - pip install --disable-version-check -r requirements-dev.txt + # Until the next xdis release + pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + pip install -e . + pip install -r requirements-dev.txt - name: Test uncompyle6 run: | make check diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 42d60845c..e975548e4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -21,6 +21,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | + # Until the next xdis release + pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 From 91fa73bf01f7b48d271d114253f3dce77fc8be82 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 24 Oct 2021 00:53:38 -0400 Subject: [PATCH 260/489] Try CI on 2.4 branch --- .github/workflows/osx.yml | 8 ++++---- .github/workflows/ubuntu.yml | 8 ++++---- .github/workflows/windows.yml | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 7dac2d778..375f6dc1f 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -2,9 +2,9 @@ name: uncompyle6 (osx) on: push: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] pull_request: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: [3.5] + python-version: [2.7] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index f22f5849b..a6ab34c47 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -2,16 +2,16 @@ name: uncompyle6 (ubuntu) on: push: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] pull_request: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5] + python-version: [2.7] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,7 +22,7 @@ jobs: run: | python -m pip install --upgrade pip # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e975548e4..e19aca529 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,9 +2,9 @@ name: uncompyle6 (windows) on: push: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] pull_request: - branches: [ python-3.3-to-3.5 ] + branches: [ python-2.4 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [windows] - python-version: [3.5] + python-version: [2.7] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 From 482dbb5c82be1b8de12f76a0065206d6ebd818ed Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Oct 2021 09:04:12 -0400 Subject: [PATCH 261/489] Modernize and sync with decompyle3 better --- uncompyle6/main.py | 47 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 17fbf6886..1d9703f19 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -12,7 +12,8 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from __future__ import print_function + +from typing import Any, Tuple import datetime, py_compile, os, subprocess, sys, tempfile from uncompyle6 import verify @@ -31,8 +32,7 @@ from xdis.load import load_module - -def _get_outstream(outfile): +def _get_outstream(outfile: str) -> Any: dir = os.path.dirname(outfile) failed_file = outfile + "_failed" if os.path.exists(failed_file): @@ -41,14 +41,11 @@ def _get_outstream(outfile): os.makedirs(dir) except OSError: pass - if PYTHON_VERSION_TRIPLE < (3, 0): - return open(outfile, mode="wb") - else: - return open(outfile, mode="w", encoding="utf-8") + return open(outfile, mode="w", encoding="utf-8") def decompile( - bytecode_version, + bytecode_version: str, co, out=None, showasm=None, @@ -62,7 +59,7 @@ def decompile( magic_int=None, mapstream=None, do_fragments=False, -): +) -> Any: """ ingests and deparses a given code block 'co' @@ -81,7 +78,7 @@ def write(s): s += "\n" real_out.write(s) - assert iscode(co) + assert iscode(co), f"""{co} is not smell like code""" co_pypy_str = "PyPy " if is_pypy else "" run_pypy_str = "PyPy " if IS_PYPY else "" @@ -100,13 +97,8 @@ def write(s): "\n# ".join(sys_version_lines), ) ) - if PYTHON_VERSION_TRIPLE < (3, 0) and bytecode_version >= (3, 0): - write( - '# Warning: this version of Python has problems handling the Python 3 "byte" type in constants properly.\n' - ) - if co.co_filename: - write("# Embedded file name: %s" % co.co_filename,) + write("# Embedded file name: %s" % co.co_filename) if timestamp: write("# Compiled at: %s" % datetime.datetime.fromtimestamp(timestamp)) if source_size: @@ -148,7 +140,7 @@ def write(s): raise pysource.SourceWalkerError(str(e)) -def compile_file(source_path): +def compile_file(source_path: str) -> str: if source_path.endswith(".py"): basename = source_path[:-3] else: @@ -173,7 +165,7 @@ def decompile_file( source_encoding=None, mapstream=None, do_fragments=False, -): +) -> Any: """ decompile Python byte-code file (.pyc). Return objects to all of the deparsed objects found in `filename`. @@ -229,10 +221,10 @@ def decompile_file( # FIXME: combine into an options parameter def main( - in_base, - out_base, - compiled_files, - source_files, + in_base: str, + out_base: str, + compiled_files: list, + source_files: list, outfile=None, showasm=None, showast=False, @@ -242,7 +234,7 @@ def main( raise_on_error=False, do_linemaps=False, do_fragments=False, -): +) -> Tuple[int, int, int, int]: """ in_base base directory for input files out_base base directory for output files (ignored when @@ -287,13 +279,8 @@ def main( # 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 - ) - else: - t = tempfile.NamedTemporaryFile( - mode="w+b", suffix=".py", prefix=prefix + t = tempfile.NamedTemporaryFile( + mode="w+b", buffering=buffering, suffix=".py", prefix=prefix ) current_outfile = t.name sys.stdout = os.fdopen(sys.stdout.fileno(), "w", buffering) From 8076c60eee231e79feb1e792fe5a4f32f9dc8b42 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 04:29:55 -0400 Subject: [PATCH 262/489] Remove float2str --- uncompyle6/parser.py | 2 +- uncompyle6/scanners/scanner3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index cb9be20fb..3acddc2af 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -21,7 +21,7 @@ import sys -from xdis import iscode, py_str2float +from xdis import iscode from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.show import maybe_show_asm diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index affe35c8e..b34500442 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -387,7 +387,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = "" - elif isinstance(const, str) or xdis.PYTHON_VERSION <= 2.7 and isinstance(const, unicode): + elif isinstance(const, str) or PYTHON_VERSION <= 2.7 and isinstance(const, unicode): opname = "LOAD_STR" else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): From 5c2af699251e6de9cbd75667b4860e3e9da44be1 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 06:08:17 -0400 Subject: [PATCH 263/489] Loosen check to allow running from 2.4-3.10 We still only can *decompile* 2.4-3.8 --- uncompyle6/bin/uncompile.py | 4 ++-- uncompyle6/parser.py | 1 - uncompyle6/scanner.py | 19 ++++++++++++++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 6266ecd94..2c21a011c 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -74,9 +74,9 @@ 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), (3, 8) + (3, 7), (3, 8), (3, 9), (3, 10) )): - print('Error: %s requires Python 2.6-3.8' % program, + print('Error: %s requires Python 2.4-3.10' % program, file=sys.stderr) sys.exit(-1) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index c35febad8..0254e57af 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -23,7 +23,6 @@ import sys -from xdis import iscode, py_str2float from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.show import maybe_show_asm diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index d11adbfa0..ba9374a6c 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -28,7 +28,14 @@ from uncompyle6.scanners.tok import Token from xdis.version_info import IS_PYPY, PYTHON3, version_tuple_to_str import xdis -from xdis import Bytecode, canonic_python_version, code2num, instruction_size, extended_arg_val, next_offset +from xdis import ( + Bytecode, + canonic_python_version, + code2num, + instruction_size, + extended_arg_val, + next_offset, +) # The byte code versions we support. # Note: these all have to be tuples of 2 ints @@ -111,7 +118,10 @@ def __init__(self, version, show_asm=None, is_pypy=False): exec("from xdis.opcodes import %s" % v_str) exec("self.opc = %s" % v_str) else: - raise TypeError("%s is not a Python version I know about" % version_tuple_to_str(version)) + raise TypeError( + "%s is not a Python version I know about" + % version_tuple_to_str(version) + ) self.opname = self.opc.opname @@ -566,7 +576,10 @@ def get_scanner(version, is_pypy=False, show_asm=None): "scan.Scanner%s(show_asm=show_asm)" % v_str, locals(), globals() ) else: - raise RuntimeError("Unsupported Python version %s" % version) + raise RuntimeError( + "Unsupported Python version, %s, for decompilation" + % version_tuple_to_str(version) + ) return scanner From 5390e3b838cd5b85a2ccd721920c54008e4b3f3b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 06:42:23 -0400 Subject: [PATCH 264/489] Merge hell --- uncompyle6/bin/uncompile.py | 4 +--- uncompyle6/main.py | 14 +++++++------- uncompyle6/parser.py | 4 ++-- uncompyle6/scanner.py | 2 +- uncompyle6/scanners/tok.py | 3 ++- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index aa65d6a5b..eaba97a08 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -75,9 +75,7 @@ def main_bin(): (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10) )): - print('Error: %s requires Python 2.4-3.10' % program, - file=sys.stderr) ->>>>>>> python-3.3-to-3.5 + print('Error: %s requires Python 2.4-3.10' % program) sys.exit(-1) do_verify = recurse_dirs = False diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 5adde6113..f5c813548 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -30,7 +30,7 @@ from xdis.load import load_module -def _get_outstream(outfile: str): +def _get_outstream(outfile): dir = os.path.dirname(outfile) failed_file = outfile + "_failed" if os.path.exists(failed_file): @@ -42,7 +42,7 @@ def _get_outstream(outfile: str): return open(outfile, 'wb') def decompile( - bytecode_version: str, + bytecode_version, co, out=None, showasm=None, @@ -155,7 +155,7 @@ def write(s): raise pysource.SourceWalkerError(str(e)) -def compile_file(source_path: str) -> str: +def compile_file(source_path): if source_path.endswith(".py"): basename = source_path[:-3] else: @@ -236,10 +236,10 @@ def decompile_file( # FIXME: combine into an options parameter def main( - in_base: str, - out_base: str, - compiled_files: list, - source_files: list, + in_base, + out_base, + compiled_files, + source_files, outfile=None, showasm=None, showast=False, diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 12b0a00dc..6f2c1cafe 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -891,9 +891,9 @@ def python_parser( if __name__ == "__main__": def parse_test(co): - from uncompyle6 import PYTHON_VERSION, IS_PYPY + from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY - ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY) + ast = python_parser(PYTHON_VERSION_TRIPLE[:2], co, showasm=True, is_pypy=IS_PYPY) print(ast) return parse_test(parse_test.func_code) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 2e742a7bc..896146019 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -593,5 +593,5 @@ def get_scanner(version, is_pypy=False, show_asm=None): co = inspect.currentframe().f_code # scanner = get_scanner('2.7.13', True) # scanner = get_scanner(sys.version[:5], False) - scanner = get_scanner(uncompyle6.PYTHON_VERSION, IS_PYPY, True) + scanner = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY, True) tokens, customize = scanner.ingest(co, {}, show_asm="after") diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index c922f5bd5..3d13c9f81 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -88,7 +88,8 @@ def __init__( if opc is None: try: from xdis.std import _std_api - except KeyError as e: + except KeyError: + e = sys.exec_info()[1] print("I don't know about Python version %s yet." % e) try: version_tuple = tuple(int(i) for i in str(e)[1:-1].split(".")) From 39d79217cae3cf71462f368acc278fe46d250577 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 06:47:35 -0400 Subject: [PATCH 265/489] Merge hell --- uncompyle6/main.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index d314622d5..254f8ac17 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -31,7 +31,7 @@ from xdis.load import load_module -def _get_outstream(outfile: str): +def _get_outstream(outfile): dir = os.path.dirname(outfile) failed_file = outfile + "_failed" if os.path.exists(failed_file): @@ -44,7 +44,7 @@ def _get_outstream(outfile: str): def decompile( - bytecode_version: str, + bytecode_version, co, out=None, showasm=None, @@ -139,7 +139,7 @@ def write(s): raise pysource.SourceWalkerError(str(e)) -def compile_file(source_path: str) -> str: +def compile_file(source_path): if source_path.endswith(".py"): basename = source_path[:-3] else: @@ -220,10 +220,10 @@ def decompile_file( # FIXME: combine into an options parameter def main( - in_base: str, - out_base: str, - compiled_files: list, - source_files: list, + in_base, + out_base, + compiled_files, + source_files, outfile=None, showasm=None, showast=False, From 000c06009310ce3b83acae10dfcfa72f9db69699 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 06:49:49 -0400 Subject: [PATCH 266/489] One more PYTHON_VERSION_TRIPLE conversion --- uncompyle6/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index f5c813548..02a8b5857 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -298,7 +298,7 @@ def main( else: buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) - if PYTHON_VERSION > 2.6: + if PYTHON_VERSION_TRIPLE > (2, 6): tee = subprocess.Popen(["tee", current_outfile], stdin=subprocess.PIPE) os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) From 25cd759dbe39523d152e07eb6ad9d792e8c05cb0 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Oct 2021 18:39:07 -0400 Subject: [PATCH 267/489] Packaging adminstrivia --- admin-tools/make-dist-older.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/admin-tools/make-dist-older.sh b/admin-tools/make-dist-older.sh index aee0ce921..0e4189599 100755 --- a/admin-tools/make-dist-older.sh +++ b/admin-tools/make-dist-older.sh @@ -18,7 +18,7 @@ fi cd .. source $PACKAGE/version.py -echo $VERSION +echo $__version__ for pyversion in $PYVERSIONS; do if ! pyenv local $pyversion ; then @@ -29,11 +29,15 @@ for pyversion in $PYVERSIONS; do python setup.py bdist_egg done +pyenv local 2.7.18 +python setup.py bdist_wheel +mv -v dist/${PACKAGE}-$__version__-py2{.py3,}-none-any.whl + # Pypi can only have one source tarball. # Tarballs can get created from the above setup, so make sure to remove them since we want # the tarball from master. -tarball=dist/${PACKAGE}-$VERSION-tar.gz +tarball=dist/${PACKAGE}-${__version_}_-tar.gz if [[ -f $tarball ]]; then - rm -v dist/${PACKAGE}-$VERSION-tar.gz + rm -v dist/${PACKAGE}-${__version__}-tar.gz fi From c8c6f1a63d76c812c301ab8cc5da017354f2767c Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 29 Oct 2021 22:27:53 -0400 Subject: [PATCH 268/489] Merge hell --- uncompyle6/scanner.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 8287b8022..45f79d958 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -111,7 +111,9 @@ def __init__(self, version, show_asm=None, is_pypy=False): self.is_pypy = is_pypy if version[:2] in PYTHON_VERSIONS: - v_str = f"""opcode_{version_tuple_to_str(version, start=0, end=2, delimiter="")}""" + v_str = "opcode_%s" % version_tuple_to_str( + version, start=0, end=2, delimiter="" + ) if is_pypy: v_str += "pypy" exec("from xdis.opcodes import %s" % v_str) From e50cd1e07dffec228bbc5a87dc4439f8dad499f8 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 30 Oct 2021 06:00:10 -0400 Subject: [PATCH 269/489] Fix off-by-one in setup's 3.6 range comparison --- setup.py | 2 +- uncompyle6/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a0ec64717..6b4a4dc06 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ """Setup script for the 'uncompyle6' distribution.""" SYS_VERSION = sys.version_info[0:2] -if not ((3, 3) <= SYS_VERSION <= (3, 5)): +if not ((3, 3) <= SYS_VERSION < (3, 6)): mess = "Python Release 3.3 .. 3.5 are supported in this code branch." if (2, 4) <= SYS_VERSION <= (2, 7): mess += ( diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 138213a19..fed5a211a 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.8.0" # noqa +__version__="3.8.1.dev0" # noqa From 0742f0b83f718935cd529d52f537fa92484a8acc Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Nov 2021 01:56:41 -0400 Subject: [PATCH 270/489] Specialize for Python 3.3-3.5 --- pytest/test_deparse.py | 8 +++----- pytest/test_pysource.py-notyet | 12 +++--------- uncompyle6/parsers/treenode.py | 5 ++--- uncompyle6/scanners/scanner2.py | 27 ++------------------------- uncompyle6/scanners/scanner26.py | 14 +------------- uncompyle6/scanners/scanner3.py | 20 +++++++------------- 6 files changed, 18 insertions(+), 68 deletions(-) diff --git a/pytest/test_deparse.py b/pytest/test_deparse.py index 50f02affa..074a87af0 100644 --- a/pytest/test_deparse.py +++ b/pytest/test_deparse.py @@ -1,5 +1,5 @@ from uncompyle6.semantics.fragments import code_deparse as deparse -from xdis.version_info import PYTHON_VERSION, PYTHON3 +from xdis.version_info import PYTHON_VERSION_TRIPLE def map_stmts(x, y): x = [] @@ -29,8 +29,8 @@ def list_comp(): [y for y in range(3)] def get_parsed_for_fn(fn): - code = fn.__code__ if PYTHON3 else fn.func_code - return deparse(code, version=PYTHON_VERSION) + code = fn.__code__ + return deparse(code, version=PYTHON_VERSION_TRIPLE) def check_expect(expect, parsed, fn_name): debug = False @@ -316,5 +316,3 @@ def test_stuff(): . """.split("\n") parsed = get_parsed_for_fn(for_range_stmt) - if not PYTHON3: - check_expect(expect, parsed, 'range_stmt') diff --git a/pytest/test_pysource.py-notyet b/pytest/test_pysource.py-notyet index cdb9ef06f..08ec9645e 100644 --- a/pytest/test_pysource.py-notyet +++ b/pytest/test_pysource.py-notyet @@ -5,15 +5,9 @@ from uncompyle6.semantics.consts import ( # RETURN_NONE, PASS, RETURN_LOCALS ) -from xdis.version_info import PYTHON3 -if PYTHON3: - from io import StringIO - def iteritems(d): - return d.items() -else: - from StringIO import StringIO - def iteritems(d): - return d.iteritems() +from io import StringIO +def iteritems(d): + return d.items() from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str) diff --git a/uncompyle6/parsers/treenode.py b/uncompyle6/parsers/treenode.py index 4fff2c312..ba175af64 100644 --- a/uncompyle6/parsers/treenode.py +++ b/uncompyle6/parsers/treenode.py @@ -1,10 +1,9 @@ import sys -from xdis.version_info import PYTHON3 from uncompyle6.scanners.tok import NoneToken from spark_parser.ast import AST as spark_AST -if PYTHON3: - intern = sys.intern + +intern = sys.intern class SyntaxTree(spark_AST): diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index fccbf6774..0ac2e7c01 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -40,10 +40,7 @@ from xdis import code2num, iscode, op_has_argument, instruction_size from xdis.bytecode import _get_const_info -from xdis.version_info import PYTHON3 - -if PYTHON3: - from sys import intern +from sys import intern from uncompyle6.scanner import Scanner, Token @@ -147,10 +144,7 @@ def extended_arg_val(arg): In Python2 this always the operand value shifted 16 bits since the operand is always 2 bytes. In Python 3.6+ this changes to one byte. """ - if PYTHON3: - return arg << 16 - else: - return arg << long(16) + return arg << 16 @staticmethod def unmangle_name(name, classname): @@ -1428,20 +1422,3 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): instr_offsets = filtered filtered = [] return instr_offsets - - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - - if 2.0 <= PYTHON_VERSION < 3.0: - import inspect - - co = inspect.currentframe().f_code - from uncompyle6 import PYTHON_VERSION - - tokens, customize = Scanner2(PYTHON_VERSION).ingest(co) - for t in tokens: - print(t) - else: - print("Need to be Python 2.x to demo; I am %s." % PYTHON_VERSION) - pass diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 25b683f6c..b0d88d438 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -23,9 +23,7 @@ """ import sys -from xdis.version_info import PYTHON3 -if PYTHON3: - intern = sys.intern +intern = sys.intern import uncompyle6.scanners.scanner2 as scan from uncompyle6.scanner import L65536 @@ -282,13 +280,3 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): print(t.format(line_prefix="")) print() return tokens, customize - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - if PYTHON_VERSION == 2.6: - import inspect - co = inspect.currentframe().f_code - tokens, customize = Scanner26(show_asm=True).ingest(co) - else: - print("Need to be Python 2.6 to demo; I am %s." % - PYTHON_VERSION) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index cc5745e56..c9f09c0a8 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -47,10 +47,8 @@ from uncompyle6.scanner import Scanner import sys -from xdis.version_info import PYTHON3 -if PYTHON3: - intern = sys.intern +intern = sys.intern globals().update(op3.opmap) @@ -379,7 +377,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = "" - elif isinstance(const, str) or xdis.PYTHON_VERSION <= 2.7 and isinstance(const, unicode): + elif isinstance(const, str): opname = "LOAD_STR" else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): @@ -1297,14 +1295,10 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): if __name__ == "__main__": from xdis.version_info import PYTHON_VERSION_TRIPLE - if PYTHON_VERSION_TRIPLE >= (3, 2): - import inspect + import inspect - co = inspect.currentframe().f_code + co = inspect.currentframe().f_code - tokens, customize = Scanner3(PYTHON_VERSION_TRIPLE).ingest(co) - for t in tokens: - print(t) - else: - print("Need to be Python 3.2 or greater to demo; I am %s." % sys.version) - pass + tokens, customize = Scanner3(PYTHON_VERSION_TRIPLE).ingest(co) + for t in tokens: + print(t) From 343f0f781a47028ee3373ead4bc0dc49ccbd3ad5 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Nov 2021 02:07:02 -0400 Subject: [PATCH 271/489] Python 2.4 specialization --- uncompyle6/parsers/treenode.py | 3 --- uncompyle6/scanners/scanner2.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/uncompyle6/parsers/treenode.py b/uncompyle6/parsers/treenode.py index d362785b8..c09b0574a 100644 --- a/uncompyle6/parsers/treenode.py +++ b/uncompyle6/parsers/treenode.py @@ -3,9 +3,6 @@ from spark_parser.ast import AST as spark_AST -intern = sys.intern - - class SyntaxTree(spark_AST): def __init__(self, *args, **kwargs): spark_AST.__init__(self, *args, **kwargs) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 5eeafdbb3..d385a2fc2 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -140,7 +140,7 @@ def extended_arg_val(arg): In Python2 this always the operand value shifted 16 bits since the operand is always 2 bytes. In Python 3.6+ this changes to one byte. """ - return arg << 16 + return arg << long(16) @staticmethod def unmangle_name(name, classname): From 6bb2605bed8adba10525f2359b4d34add752f0cd Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Nov 2021 03:11:06 -0400 Subject: [PATCH 272/489] Remove PYTHON3 --- pytest/test_grammar.py | 30 +----------------------------- pytest/test_pysource.py-notyet | 1 - test-unit/test_grammar.py | 6 +++--- test/test_pyenvlib.py | 4 ---- 4 files changed, 4 insertions(+), 37 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index fbb6aa2fa..feb485c5b 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -53,35 +53,7 @@ def check_tokens(tokens, opcode_set): # NOTE: this may disappear expect_lhs.add("except_handler_else") - expect_lhs.add("load_genexpr") - - unused_rhs = unused_rhs.union( - set( - """ - except_pop_except generator_exp - """.split() - ) - ) - if PYTHON_VERSION_TRIPLE < (3, 7): - expect_lhs.add("annotate_arg") - expect_lhs.add("annotate_tuple") - unused_rhs.add("mkfunc_annotate") - - unused_rhs.add("dict_comp") - unused_rhs.add("classdefdeco1") - unused_rhs.add("tryelsestmtl") - if PYTHON_VERSION_TRIPLE >= (3, 5): - expect_right_recursive.add( - (("l_stmts", ("lastl_stmt", "come_froms", "l_stmts"))) - ) - pass - pass - - # FIXME - if PYTHON_VERSION_TRIPLE < (3, 8): - assert expect_lhs == set(lhs) - assert unused_rhs == set(rhs) - + expect_lhs.add("kwarg") assert expect_right_recursive == right_recursive expect_dup_rhs = frozenset( diff --git a/pytest/test_pysource.py-notyet b/pytest/test_pysource.py-notyet index dff5915ae..0b9734b8b 100644 --- a/pytest/test_pysource.py-notyet +++ b/pytest/test_pysource.py-notyet @@ -5,7 +5,6 @@ from uncompyle6.semantics.consts import ( # RETURN_NONE, PASS, RETURN_LOCALS ) -from xdis.version_info import PYTHON3 from StringIO import StringIO from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str) diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index 57f929894..683d0bccb 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -1,7 +1,7 @@ import re import unittest -from uncompyle6 import PYTHON_VERSION, IS_PYPY # , PYTHON_VERSION from uncompyle6.parser import get_python_parser, python_parser +from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY class TestGrammar(unittest.TestCase): def test_grammar(self): @@ -14,7 +14,7 @@ def check_tokens(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) + p = get_python_parser(PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY) (lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets() expect_lhs = set(['pos_arg', 'get_iter', 'attribute']) @@ -47,7 +47,7 @@ def check_tokens(tokens, opcode_set): # FIXME: Something got borked here def no_test_dup_rule(self): import inspect - python_parser(PYTHON_VERSION, inspect.currentframe().f_code, + python_parser(PYTHON_VERSION_TRIPLE, inspect.currentframe().f_code, is_pypy=IS_PYPY, parser_debug={ 'dups': True, 'transition': False, 'reduce': False, diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index cd1e315ba..3f1ef4f31 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -20,7 +20,6 @@ test_pyenvlib --mylib --verify # decompile verify 'mylib' """ -from uncompyle6 import main, PYTHON3 import os, time, re, shutil, sys from fnmatch import fnmatch @@ -81,9 +80,6 @@ else: if vers == "native": short_vers = os.path.basename(sys.path[-1]) - from xdis import PYTHON_VERSION - if PYTHON_VERSION > 3.0: - PYC = "*.cpython-%d.pyc" % int(PYTHON_VERSION * 10) test_options[vers] = (sys.path[-1], PYC, short_vers) else: short_vers = vers[:3] From f72070e6d016c483b8bc306ef97f955c69e3dd36 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 7 Nov 2021 10:21:56 -0500 Subject: [PATCH 273/489] Administrivia - workflows CI --- .github/workflows/osx.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 7dac2d778..4e40cb211 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + # pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index f22f5849b..54aa85bec 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -22,7 +22,7 @@ jobs: run: | python -m pip install --upgrade pip # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + # pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e975548e4..0b43aaac9 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis + # pip install git+git://github.com/rocky/python-xdis.git@python-3.3-to-3.5#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 From c4baec28deb180ee1c2c28c90a4db6df7e135f61 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 24 Nov 2021 15:38:28 -0500 Subject: [PATCH 274/489] No fstrings here --- uncompyle6/semantics/customize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index fc9bb5e0d..ae8580d62 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -68,7 +68,7 @@ def n_call_kw_pypy37(node): if line_number != self.line_number: sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1] pass - self.write(f"{sep}{value}") + self.write("%s%s" (sep, value)) sep = ", " assert n >= len(kwargs_names) @@ -83,7 +83,7 @@ def n_call_kw_pypy37(node): sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1] pass self.write(sep) - self.write("%s=%s" % (kw_keys_tuple[i], value)) + self.write("%s=%s" % (kwargs_names[i], value)) sep = ", " pass From 7a98ac990d7338c619496eece9f0dc1507957a3a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 25 Nov 2021 04:05:49 -0500 Subject: [PATCH 275/489] sys.exc typo --- uncompyle6/scanners/tok.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index c98a2fdb8..51d048125 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -86,7 +86,7 @@ def __init__( try: from xdis.std import _std_api except KeyError: - e = sys.exec_info()[1] + e = sys.exc_info()[1] print("I don't know about Python version %s yet." % e) try: version_tuple = tuple(int(i) for i in str(e)[1:-1].split(".")) From 0a781164c377113584d31d2327304a23cb8e3e2a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Nov 2021 05:24:59 -0500 Subject: [PATCH 276/489] Python 2.4 tolerance --- uncompyle6/parsers/reducecheck/and_not_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/reducecheck/and_not_check.py b/uncompyle6/parsers/reducecheck/and_not_check.py index a246e6302..c9fd42372 100644 --- a/uncompyle6/parsers/reducecheck/and_not_check.py +++ b/uncompyle6/parsers/reducecheck/and_not_check.py @@ -1,9 +1,9 @@ -# Copyright (c) 2020 Rocky Bernstein +# Copyright (c) 2020-2021 Rocky Bernstein def and_not_check( self, lhs, n, rule, ast, tokens, first, last -) -> bool: +): jmp = ast[1] if jmp.kind.startswith("jmp_"): if last == n: From bba9c577d15398a8d23ee8c1705e15d8699159c3 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Nov 2021 06:09:17 -0500 Subject: [PATCH 277/489] Administrivia --- admin-tools/setup-master.sh | 14 +++++++++++--- admin-tools/setup-python-2.4.sh | 16 +++++++++++----- admin-tools/setup-python-3.3.sh | 22 +++++++++++++++++++++- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index 834345227..3dc4ac9a8 100755 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -1,6 +1,15 @@ #!/bin/bash PYTHON_VERSION=3.7.12 +function checkout_version { + local repo=$1 + version=${2:-master} + echo Checking out $version on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + # FIXME put some of the below in a common routine function finish { cd $owd @@ -16,8 +25,7 @@ fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. -(cd ../python-spark && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ - (cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ - git checkout master && pyenv local $PYTHON_VERSION && git pull +(cd $fulldir/.. && checkout_version python-spark && checkout_version python-xdis && + checkout_version python_uncompyle6) cd $owd rm -v */.python-version >/dev/null 2>&1 || true diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 3ed58d7e6..249e8947e 100755 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -1,6 +1,15 @@ #!/bin/bash PYTHON_VERSION=2.4.6 +function checkout_version { + local repo=$1 + version=${2:-python-2.4} + echo Checking out $version.4 on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + owd=$(pwd) bs=${BASH_SOURCE[0]} if [[ $0 == $bs ]] ; then @@ -9,10 +18,7 @@ if [[ $0 == $bs ]] ; then fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) -cd $fulldir/.. -(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ - (cd ../python-xdis && . ./admin-tools/setup-python-2.4.sh) && \ - git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull +(cd $fulldir/.. && checkout_version python-spark && checkout_version python-xdis python-2.4-to-2.7 && + checkout_version python_uncompyle6) cd $owd rm -v */.python-version || true -pyenv local $PYTHON_VERSION diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index 5af28261b..4e244df34 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -2,13 +2,33 @@ PYTHON_VERSION=3.3.7 pyenv local $PYTHON_VERSION +# FIXME put some of the below in a common routine +function checkout_version { + local repo=$1 + version=${2:-python-3.3-to-3.5} + echo Checking out $version on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + +function finish { + cd $owd +} + +export PATH=$HOME/.pyenv/bin/pyenv:$PATH owd=$(pwd) bs=${BASH_SOURCE[0]} +if [[ $0 == $bs ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. -(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh) +(cd $fulldir/.. && checkout_version python-spark master && checkout_version python-xdis && + checkout_version python-uncompyle6) cd $owd rm -v */.python-version || true From 9caceed00111f23160cd300761333ac48c5e9d90 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Nov 2021 06:09:17 -0500 Subject: [PATCH 278/489] Administrivia --- admin-tools/setup-master.sh | 14 +++++++++++--- admin-tools/setup-python-2.4.sh | 16 +++++++++++----- admin-tools/setup-python-3.3.sh | 22 +++++++++++++++++++++- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index 834345227..377a0a764 100755 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -1,6 +1,15 @@ #!/bin/bash PYTHON_VERSION=3.7.12 +function checkout_version { + local repo=$1 + version=${2:-master} + echo Checking out $version on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + # FIXME put some of the below in a common routine function finish { cd $owd @@ -16,8 +25,7 @@ fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. -(cd ../python-spark && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ - (cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \ - git checkout master && pyenv local $PYTHON_VERSION && git pull +(cd $fulldir/.. && checkout_version python-spark && checkout_version python-xdis && + checkout_version python-uncompyle6) cd $owd rm -v */.python-version >/dev/null 2>&1 || true diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 3ed58d7e6..249e8947e 100755 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -1,6 +1,15 @@ #!/bin/bash PYTHON_VERSION=2.4.6 +function checkout_version { + local repo=$1 + version=${2:-python-2.4} + echo Checking out $version.4 on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + owd=$(pwd) bs=${BASH_SOURCE[0]} if [[ $0 == $bs ]] ; then @@ -9,10 +18,7 @@ if [[ $0 == $bs ]] ; then fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) -cd $fulldir/.. -(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \ - (cd ../python-xdis && . ./admin-tools/setup-python-2.4.sh) && \ - git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull +(cd $fulldir/.. && checkout_version python-spark && checkout_version python-xdis python-2.4-to-2.7 && + checkout_version python_uncompyle6) cd $owd rm -v */.python-version || true -pyenv local $PYTHON_VERSION diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index 5af28261b..4e244df34 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -2,13 +2,33 @@ PYTHON_VERSION=3.3.7 pyenv local $PYTHON_VERSION +# FIXME put some of the below in a common routine +function checkout_version { + local repo=$1 + version=${2:-python-3.3-to-3.5} + echo Checking out $version on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + +function finish { + cd $owd +} + +export PATH=$HOME/.pyenv/bin/pyenv:$PATH owd=$(pwd) bs=${BASH_SOURCE[0]} +if [[ $0 == $bs ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. -(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh) +(cd $fulldir/.. && checkout_version python-spark master && checkout_version python-xdis && + checkout_version python-uncompyle6) cd $owd rm -v */.python-version || true From f06bd69858fddc3e2d8d652171553ced8ade4c31 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 23 Dec 2021 16:44:53 -0500 Subject: [PATCH 279/489] Sync with master --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 63c4d85ae..4a128f41c 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1259,7 +1259,7 @@ def comprehension_walk_newer(self, node, iter_index, code_index=-5): have_not = False - # Iterate to find the innermost store + # Iterate to find the inner-most "store". # We'll come back to the list iteration below. while n in ("list_iter", "list_afor", "list_afor2", "comp_iter"): From 040ed20b59918eb491de9233d6519e571c4ee004 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 23 Dec 2021 16:47:46 -0500 Subject: [PATCH 280/489] Sync with master --- uncompyle6/semantics/pysource.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 4a128f41c..ff8176388 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1332,6 +1332,7 @@ def comprehension_walk_newer(self, node, iter_index, code_index=-5): in_node_index = -3 self.write(" for ") + if comp_store: self.preorder(comp_store) else: @@ -1399,7 +1400,7 @@ def setcomprehension_walk3(self, node, collection_index): list_if = None assert n == "comp_iter" - # find inner-most node + # Find inner-most node. while n == "comp_iter": n = n[0] # recurse one step # FIXME: adjust for set comprehension From 5d0dc5fffdd515e8bbd73a749bcb052b61b2dc08 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 23 Dec 2021 16:58:06 -0500 Subject: [PATCH 281/489] Remove 2.7+ism --- uncompyle6/semantics/make_function36.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/make_function36.py b/uncompyle6/semantics/make_function36.py index 562f59001..719170526 100644 --- a/uncompyle6/semantics/make_function36.py +++ b/uncompyle6/semantics/make_function36.py @@ -147,7 +147,7 @@ def build_param(ast, name, default, annotation=None): code = code_node.attr assert iscode(code) - debug_opts = self.debug_opts["asm"] if self.debug_opts else None + debug_opts = self.debug_opts.get("asm", None) scanner_code = Code(code, self.scanner, self.currentclass, debug_opts) # add defaults values to parameter names From 164168e7f455099b4efde2908dca57eb45fcc22c Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 23 Dec 2021 22:24:45 -0500 Subject: [PATCH 282/489] unmap_dict -> dict_unmap ... This matches Python's AST (Dict) better. Variations or specializations of an AST name, e.g. "unmap" should come at the end, not the beginning. --- uncompyle6/parsers/parse3.py | 6 +++--- uncompyle6/parsers/parse35.py | 4 ++-- uncompyle6/parsers/parse37base.py | 10 +++++----- uncompyle6/semantics/customize35.py | 2 +- uncompyle6/semantics/customize36.py | 2 +- uncompyle6/semantics/customize37.py | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index bac6ae8e3..75e7b4eb2 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -775,7 +775,7 @@ def customize_grammar_rules(self, tokens, customize): # FIXME: Use the attr # so this doesn't run into exponential parsing time. if opname.startswith("BUILD_MAP_UNPACK"): - # FIXME: start here. The LHS should be unmap_dict, not dict. + # FIXME: start here. The LHS should be dict_unmap, not dict. # FIXME: really we need a combination of dict_entry-like things. # It just so happens the most common case is not to mix # dictionary comphensions with dictionary, elements @@ -786,8 +786,8 @@ def customize_grammar_rules(self, tokens, customize): ) self.addRule(rule, nop_func) rule = """ - expr ::= unmap_dict - unmap_dict ::= %s%s + expr ::= dict_unmap + dict_unmap ::= %s%s """ % ( "expr " * token.attr, opname, diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index 4ca8d2c73..edfc4f925 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -201,8 +201,8 @@ def customize_grammar_rules(self, tokens, customize): self.addRule(rules_str, nop_func) elif opname == 'BUILD_MAP_UNPACK': self.addRule(""" - expr ::= unmap_dict - unmap_dict ::= dict_comp BUILD_MAP_UNPACK + expr ::= dict_unmap + dict_unmap ::= dict_comp BUILD_MAP_UNPACK """, nop_func) elif opname == 'SETUP_WITH': diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 5d45b33ed..75ffb34f8 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -336,8 +336,8 @@ def customize_grammar_rules(self, tokens, customize): if opname == "BUILD_MAP_UNPACK": self.addRule( """ - expr ::= unmap_dict - unmap_dict ::= dict_comp BUILD_MAP_UNPACK + expr ::= dict_unmap + dict_unmap ::= dict_comp BUILD_MAP_UNPACK """, nop_func, ) @@ -367,7 +367,7 @@ def customize_grammar_rules(self, tokens, customize): # FIXME: Use the attr # so this doesn't run into exponential parsing time. if opname.startswith("BUILD_MAP_UNPACK"): - # FIXME: start here. The LHS should be unmap_dict, not dict. + # FIXME: start here. The LHS should be dict_unmap, not dict. # FIXME: really we need a combination of dict_entry-like things. # It just so happens the most common case is not to mix # dictionary comphensions with dictionary, elements @@ -375,8 +375,8 @@ def customize_grammar_rules(self, tokens, customize): rule = "dict ::= %s%s" % ("dict_comp " * token.attr, opname) self.addRule(rule, nop_func) rule = """ - expr ::= unmap_dict - unmap_dict ::= %s%s + expr ::= dict_unmap + dict_unmap ::= %s%s """ % ( "expr " * token.attr, opname, diff --git a/uncompyle6/semantics/customize35.py b/uncompyle6/semantics/customize35.py index 04c13affb..02709b8ef 100644 --- a/uncompyle6/semantics/customize35.py +++ b/uncompyle6/semantics/customize35.py @@ -51,7 +51,7 @@ def customize_for_version35(self, version): (2, "store"), 3, ), - "unmap_dict": ("{**%C}", (0, -1, ", **")), + "dict_unmap": ("{**%C}", (0, -1, ", **")), # "unmapexpr": ( "{**%c}", 0), # done by n_unmapexpr } ) diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index e8741144f..1d2798dc6 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -44,7 +44,7 @@ def customize_for_version36(self, version): PRECEDENCE["call_ex_kw2"] = 1 PRECEDENCE["call_ex_kw3"] = 1 PRECEDENCE["call_ex_kw4"] = 1 - PRECEDENCE["unmap_dict"] = 0 + PRECEDENCE["dict_unmap"] = 0 PRECEDENCE["formatted_value1"] = 100 TABLE_DIRECT.update( diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index 91d25032d..58b12012e 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -38,7 +38,7 @@ def customize_for_version37(self, version): PRECEDENCE["formatted_value1"] = 100 PRECEDENCE["if_exp_37a"] = 28 PRECEDENCE["if_exp_37b"] = 28 - PRECEDENCE["unmap_dict"] = 0 + PRECEDENCE["dict_unmap"] = 0 TABLE_DIRECT.update( { @@ -161,7 +161,7 @@ def customize_for_version37(self, version): "testfalsel": ("not %c", (0, "expr")), "try_except36": ("%|try:\n%+%c%-%c\n\n", 1, -2), "tryfinally36": ("%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", (1, "returns"), 3), - "unmap_dict": ("{**%C}", (0, -1, ", **")), + "dict_unmap": ("{**%C}", (0, -1, ", **")), "unpack_list": ("*%c", (0, "list")), "yield_from": ("yield from %c", (0, "expr")), } From a93bec73cf57a0d05b1d6ac8bd1f6fc8c649896b Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Jan 2022 08:04:33 -0500 Subject: [PATCH 283/489] merge hell --- uncompyle6/main.py | 15 ++++++++++----- uncompyle6/semantics/pysource.py | 13 ++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index da04659dd..3bc89f9de 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import datetime, py_compile, os, subprocess, sys, tempfile +import datetime, py_compile, os, sys from xdis import iscode from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str @@ -58,6 +58,7 @@ def decompile( magic_int=None, mapstream=None, do_fragments=False, + compile_mode="exec", ): """ ingests and deparses a given code block 'co' @@ -331,7 +332,7 @@ def main( tot_files += 1 except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e: sys.stdout.write("\n") - sys.stderr.write(f"\n# file {infile}\n# {e}\n") + sys.stderr.write("\n# file %s\n# %s\n" % (infile, e)) failed_files += 1 tot_files += 1 except KeyboardInterrupt: @@ -339,10 +340,10 @@ def main( outstream.close() os.remove(outfile) sys.stdout.write("\n") - sys.stderr.write(f"\nLast file: {infile} ") + sys.stderr.write("\nLast file: %s " % (infile)) raise except RuntimeError as e: - sys.stdout.write(f"\n{str(e)}\n") + sys.stdout.write("\n%s\n" % str(e)) if str(e).startswith("Unsupported Python"): sys.stdout.write("\n") sys.stderr.write( @@ -432,5 +433,9 @@ def status_msg(do_verify, tot_files, okay_files, failed_files, verify_failed_fil return "\n# Successfully decompiled file" pass pass - mess = f"decompiled {tot_files} files: {okay_files} okay, {failed_files} failed" + mess = "decompiled %i files: %i okay, %i failed" % ( + tot_files, + okay_files, + failed_files, + ) return mess diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 50c3d3b3b..6547dc570 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1201,7 +1201,7 @@ def n_set_comp(self, node): n_dict_comp = n_set_comp - def comprehension_walk_newer(self, node, iter_index: int, code_index: int = -5): + def comprehension_walk_newer(self, node, iter_index, code_index=-5): """Non-closure-based comprehensions the way they are done in Python3 and some Python 2.7. Note: there are also other set comprehensions. """ @@ -2095,10 +2095,10 @@ def template_engine(self, entry, startnode): node[index] except IndexError: raise RuntimeError( - f""" - Expanding '{node.kind}' in template '{entry}[{arg}]': - {index} is invalid; has only {len(node)} entries """ + Expanding '%s' in template '%s[%s]': + %s is invalid; has only %d entries + """ % (node.kind, entry, arg, index, len(node)) ) self.preorder(node[index]) @@ -2657,7 +2657,10 @@ def code_deparse( if expected_start: assert ( deparsed.ast == expected_start - ), f"Should have parsed grammar start to '{expected_start}'; got: {deparsed.ast.kind}" + ), ( + "Should have parsed grammar start to '%s'; got: %s" % + (expected_start, deparsed.ast.kind) + ) # save memory del tokens From 05f743ed140f113449ae777e82995ccdf746b53d Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Jan 2022 08:09:02 -0500 Subject: [PATCH 284/489] Merge hell --- uncompyle6/main.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 02a8b5857..c1f457781 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -56,6 +56,7 @@ def decompile( magic_int=None, mapstream=None, do_fragments=False, + compile_mode="exec", ): """ ingests and deparses a given code block 'co' @@ -133,6 +134,7 @@ def write(s): debug_opts, code_objects=code_objects, is_pypy=is_pypy, + compile_mode=compile_mode, ) header_count = 3 + len(sys_version_lines) linemap = [ @@ -146,7 +148,12 @@ def write(s): else: deparse_fn = code_deparse deparsed = deparse_fn( - co, out, bytecode_version, debug_opts=debug_opts, is_pypy=is_pypy + co, + out, + bytecode_version, + debug_opts=debug_opts, + is_pypy=is_pypy, + compile_mode=compile_mode, ) pass return deparsed From 209f19c1dadd3f9e3317b8fb9a8cd0777a62194f Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Mar 2022 04:51:22 -0500 Subject: [PATCH 285/489] Some variable name changes... and sync with master --- uncompyle6/scanners/scanner3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index e0f72f1f7..d8f4fd44b 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -397,7 +397,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): elif flags == 9: opname = "MAKE_FUNCTION_CLOSURE_POS" else: - opname = f"MAKE_FUNCTION_{flags}" + opname = "MAKE_FUNCTION_%d" % (flags) attr = [] for flag in self.MAKE_FUNCTION_FLAGS: bit = flags & 1 From 2efe2b5b47f896700c301e4e2efc7b191631a2d2 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Mar 2022 05:07:31 -0500 Subject: [PATCH 286/489] WIP --- test/simple_source/bug36/02_genexpr.py | 2 +- test/simple_source/bug36/05_36lambda.py | 4 +- uncompyle6/bin/uncompile.py | 3 +- uncompyle6/main.py | 44 ++-- uncompyle6/parsers/parse36.py | 6 +- uncompyle6/parsers/parse37.py | 6 +- uncompyle6/parsers/parse37base.py | 21 +- uncompyle6/parsers/parse38.py | 5 + uncompyle6/scanners/scanner3.py | 8 +- uncompyle6/semantics/aligner.py | 6 +- uncompyle6/semantics/consts.py | 35 ++- uncompyle6/semantics/customize3.py | 8 +- uncompyle6/semantics/customize36.py | 2 +- uncompyle6/semantics/fragments.py | 43 +--- uncompyle6/semantics/pysource.py | 284 +++++++++++++++++------- uncompyle6/show.py | 2 +- uncompyle6/version.py | 2 +- 17 files changed, 316 insertions(+), 165 deletions(-) diff --git a/test/simple_source/bug36/02_genexpr.py b/test/simple_source/bug36/02_genexpr.py index 9ea0dea8f..755108dca 100644 --- a/test/simple_source/bug36/02_genexpr.py +++ b/test/simple_source/bug36/02_genexpr.py @@ -1,5 +1,5 @@ # Python 3.6, uses rule: # genexpr ::= load_closure load_genexpr LOAD_CONST -# MAKE_FUNCTION_8 expr GET_ITER CALL_FUNCTION_1 +# MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 def __sub__(self, other): # SList()-other return self.__class__(i for i in self if i not in other) diff --git a/test/simple_source/bug36/05_36lambda.py b/test/simple_source/bug36/05_36lambda.py index 3ed67f749..29bc037a0 100644 --- a/test/simple_source/bug36/05_36lambda.py +++ b/test/simple_source/bug36/05_36lambda.py @@ -4,8 +4,8 @@ def __init__(self, msg = None, digestmod = None): self.digest_cons = lambda d='': digestmod.new(d) # From Python 3.6 functools.py -# Bug was handling lambda for MAKE_FUNCTION_8 (closure) -# vs to MAKE_FUNCTION_9 (pos_args + closure) +# Bug was handling lambda for MAKE_FUNCTION_CLOSURE (closure) +# vs to MAKE_FUNCTION_CLOSURE_POS (pos_args + closure) def bug(): def register(cls, func=None): return lambda f: register(cls, f) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 291066f2e..bde477000 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -133,7 +133,8 @@ def main_bin(): elif opt in ('--tree+', '-T'): if 'showast' not in options: options['showast'] = {} - options['showast']['Full'] = True + options['showast']['after'] = True + options['showast']['before'] = True options['do_verify'] = None elif opt in ('--grammar', '-g'): options['showgrammar'] = True diff --git a/uncompyle6/main.py b/uncompyle6/main.py index c1f457781..9fd31f3d6 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2021 Rocky Bernstein +# Copyright (C) 2018-2022 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str from uncompyle6.disas import check_object_path from uncompyle6.semantics import pysource +from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG from uncompyle6.parser import ParserError from uncompyle6.version import __version__ @@ -42,9 +43,9 @@ def _get_outstream(outfile): return open(outfile, 'wb') def decompile( - bytecode_version, co, - out=None, + bytecode_version = PYTHON_VERSION_TRIPLE, + out=sys.stdout, showasm=None, showast={}, timestamp=None, @@ -98,7 +99,7 @@ def write(s): write("# -*- coding: %s -*-" % source_encoding) write( "# uncompyle6 version %s\n" - "# %sPython bytecode %s%s\n# Decompiled from: %sPython %s" + "# %sPython bytecode version base %s%s\n# Decompiled from: %sPython %s" % ( __version__, co_pypy_str, @@ -107,10 +108,6 @@ def write(s): "\n# ".join(sys_version_lines), ) ) - if bytecode_version >= 3.0: - write( - "# Warning: this version of Python has problems handling the Python 3 byte type in constants properly.\n" - ) if co.co_filename: write("# Embedded file name: %s" % co.co_filename) if timestamp: @@ -120,7 +117,17 @@ def write(s): real_out.write("# Size of source mod 2**32: %d bytes\n" % source_size) - debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar} + # maybe a second -a will do before as well + if showasm: + asm = "after" + else: + asm = None + + grammar = dict(PARSER_DEFAULT_DEBUG) + if showgrammar: + grammar["reduce"] = True + + debug_opts = {"asm": asm, "tree": showast, "grammar": grammar} try: if mapstream: @@ -128,10 +135,12 @@ def write(s): mapstream = _get_outstream(mapstream) deparsed = deparse_code_with_map( + bytecode_version, co, out, - bytecode_version, - debug_opts, + showasm, + showast, + showgrammar, code_objects=code_objects, is_pypy=is_pypy, compile_mode=compile_mode, @@ -182,7 +191,7 @@ def decompile_file( filename, outstream=None, showasm=None, - showast=False, + showast={}, showgrammar=False, source_encoding=None, mapstream=None, @@ -201,11 +210,11 @@ def decompile_file( if isinstance(co, list): deparsed = [] - for con in co: + for bytecode in co: deparsed.append( decompile( + bytecode, version, - con, outstream, showasm, showast, @@ -215,14 +224,14 @@ def decompile_file( code_objects=code_objects, is_pypy=is_pypy, magic_int=magic_int, + mapstream=mapstream, ), - mapstream=mapstream, ) else: deparsed = [ decompile( - version, co, + version, outstream, showasm, showast, @@ -235,6 +244,7 @@ def decompile_file( magic_int=magic_int, mapstream=mapstream, do_fragments=do_fragments, + compile_mode="exec", ) ] co = None @@ -249,7 +259,7 @@ def main( source_files, outfile=None, showasm=None, - showast=False, + showast={}, do_verify=False, showgrammar=False, source_encoding=None, diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index fb6d034e7..604d9fca2 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -219,19 +219,19 @@ def customize_grammar_rules(self, tokens, customize): formatted_value2 ::= expr expr FORMAT_VALUE_ATTR """ self.add_unique_doc_rules(rules_str, customize) - elif opname == 'MAKE_FUNCTION_8': + elif opname == 'MAKE_FUNCTION_CLOSURE': if 'LOAD_DICTCOMP' in self.seen_ops: # Is there something general going on here? rule = """ dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) elif 'LOAD_SETCOMP' in self.seen_ops: rule = """ set_comp ::= load_closure LOAD_SETCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index bf5a65651..57942e30f 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -1204,19 +1204,19 @@ def customize_grammar_rules(self, tokens, customize): formatted_value2 ::= expr expr FORMAT_VALUE_ATTR """ self.add_unique_doc_rules(rules_str, customize) - elif opname == "MAKE_FUNCTION_8": + elif opname == "MAKE_FUNCTION_CLOSURE": if "LOAD_DICTCOMP" in self.seen_ops: # Is there something general going on here? rule = """ dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) elif "LOAD_SETCOMP" in self.seen_ops: rule = """ set_comp ::= load_closure LOAD_SETCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index de54f05a1..ba51790e6 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -584,6 +584,21 @@ def customize_grammar_rules(self, tokens, customize): """ self.add_unique_doc_rules(rules_str, customize) + elif opname == "GET_ANEXT": + self.addRule( + """ + func_async_prefix ::= _come_froms SETUP_FINALLY GET_ANEXT LOAD_CONST YIELD_FROM POP_BLOCK + func_async_middle ::= JUMP_FORWARD COME_FROM_EXCEPT + DUP_TOP LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE + list_afor2 ::= func_async_prefix + store list_iter + JUMP_BACK COME_FROM_FINALLY + END_ASYNC_FOR + """, + nop_func, + ) + custom_ops_processed.add(opname) + elif opname == "FORMAT_VALUE_ATTR": rules_str = """ expr ::= formatted_value2 @@ -932,19 +947,19 @@ def customize_grammar_rules(self, tokens, customize): ) self.add_unique_rule(rule, opname, token.attr, customize) - elif opname == "MAKE_FUNCTION_8": + elif opname == "MAKE_FUNCTION_CLOSURE": if "LOAD_DICTCOMP" in self.seen_ops: # Is there something general going on here? rule = """ dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) elif "LOAD_SETCOMP" in self.seen_ops: rule = """ set_comp ::= load_closure LOAD_SETCOMP LOAD_STR - MAKE_FUNCTION_8 expr + MAKE_FUNCTION_CLOSURE expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) diff --git a/uncompyle6/parsers/parse38.py b/uncompyle6/parsers/parse38.py index 3549ca614..01183d7ac 100644 --- a/uncompyle6/parsers/parse38.py +++ b/uncompyle6/parsers/parse38.py @@ -74,6 +74,11 @@ def p_38misc(self, args): COME_FROM_FINALLY END_ASYNC_FOR + genexpr_func_async ::= LOAD_FAST func_async_prefix + store comp_iter + JUMP_BACK COME_FROM_FINALLY + END_ASYNC_FOR + # FIXME: come froms after the else_suite or END_ASYNC_FOR distinguish which of # for / forelse is used. Add come froms and check of add up control-flow detection phase. async_forelse_stmt38 ::= expr diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index cf0909a8d..c82396aab 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -397,7 +397,13 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if self.version >= (3, 6): # 3.6+ doesn't have MAKE_CLOSURE, so opname == 'MAKE_FUNCTION' flags = argval - opname = "MAKE_FUNCTION_%d" % (flags) + # FIXME: generalize this + if flags == 8: + opname = "MAKE_FUNCTION_CLOSURE" + elif flags == 9: + opname = "MAKE_FUNCTION_CLOSURE_POS" + else: + opname = "MAKE_FUNCTION_%d" % (flags) attr = [] for flag in self.MAKE_FUNCTION_FLAGS: bit = flags & 1 diff --git a/uncompyle6/semantics/aligner.py b/uncompyle6/semantics/aligner.py index c452e93de..1cc68a565 100644 --- a/uncompyle6/semantics/aligner.py +++ b/uncompyle6/semantics/aligner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 by Rocky Bernstein +# Copyright (c) 2018, 2022 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -141,8 +141,8 @@ def code_deparse_align(co, out=sys.stderr, version=None, is_pypy=None, debug_parser=debug_parser, compile_mode=compile_mode, is_pypy = is_pypy) - isTopLevel = co.co_name == '' - deparsed.ast = deparsed.build_ast(tokens, customize, co, isTopLevel=isTopLevel) + is_top_level_module = co.co_name == '' + deparsed.ast = deparsed.build_ast(tokens, customize, co, is_top_level_module=is_top_level_module) assert deparsed.ast == 'stmts', 'Should have parsed grammar start' diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index c22360532..197bec888 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2021 by Rocky Bernstein +# Copyright (c) 2017-2022 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -44,6 +44,9 @@ # say to 100, to make sure we avoid additional prenthesis in # call((.. op ..)). +NO_PARENTHESIS_EVER = 100 + +# fmt: off PRECEDENCE = { "named_expr": 40, # := "yield": 38, # Needs to be below named_expr @@ -168,11 +171,14 @@ "DELETE_ATTR": ("%|del %c.%[-1]{pattr}\n", 0), } -TABLE_R0 = { - # "BUILD_LIST": ( "[%C]", (0,-1,", ") ), - # "BUILD_TUPLE": ( "(%C)", (0,-1,", ") ), - # "CALL_FUNCTION": ( "%c(%P)", 0, (1,-1,", ") ), -} +# I'll leave this in for historical interest. +# TABLE_R0 it was like TABLE_R but the key was the *child* of the last child, +# or a grandchild of the node that this is considered. +# TABLE_R0 = { +# "BUILD_LIST": ( "[%C]", (0,-1,", ") ), +# "BUILD_TUPLE": ( "(%C)", (0,-1,", ") ), +# "CALL_FUNCTION": ( "%c(%P)", 0, (1,-1,", ") ), +# } TABLE_DIRECT = { "BINARY_ADD": ("+",), @@ -236,8 +242,19 @@ (0, "expr", PRECEDENCE["subscript"]), (1, "expr"), ), - "subscript": ("%p[%c]", (0, "expr", PRECEDENCE["subscript"]), (1, "expr")), - "subscript2": ("%p[%c]", (0, "expr", PRECEDENCE["subscript"]), (1, "expr")), + + "subscript": ( + "%p[%p]", + (0, "expr", PRECEDENCE["subscript"]), + (1, "expr", NO_PARENTHESIS_EVER) + ), + + "subscript2": ( + "%p[%p]", + (0, "expr", PRECEDENCE["subscript"]), + (1, "expr", NO_PARENTHESIS_EVER) + ), + "store_subscript": ("%p[%c]", (0, "expr", PRECEDENCE["subscript"]), (1, "expr")), "STORE_FAST": ("%{pattr}",), "STORE_NAME": ("%{pattr}",), @@ -427,7 +444,6 @@ MAP_DIRECT = (TABLE_DIRECT,) -MAP_R0 = (TABLE_R0, -1, 0) MAP_R = (TABLE_R, -1) MAP = { @@ -435,7 +451,6 @@ "call": MAP_R, "delete": MAP_R, "store": MAP_R, - "exprlist": MAP_R0, } ASSIGN_TUPLE_PARAM = lambda param_name: SyntaxTree( diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index beccb2e82..07be2a365 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -154,6 +154,7 @@ def listcomp_closure3(node): # recurse one step n = n[0] + # FIXME: adjust for set comprehension if n == "list_for": stores.append(n[2]) n = n[3] @@ -168,13 +169,12 @@ def listcomp_closure3(node): c = c[0] collections.append(c) pass - elif n in ("list_if", "list_if_not"): - # FIXME: just a guess + elif n in ("list_if", "list_if_not", "list_if_or_not"): if n[0].kind == "expr": list_ifs.append(n) else: list_ifs.append([1]) - n = n[2] + n = n[-2] if n[-1] == "come_from_opt" else n[-1] pass elif n == "list_if37": list_ifs.append(n) @@ -184,7 +184,7 @@ def listcomp_closure3(node): collections.append(n[0][0]) n = n[1] stores.append(n[1][0]) - n = n[3] + n = n[2] if n[2].kind == "list_iter" else n[3] pass assert n == "lc_body", ast diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 1074fca82..9df98ad19 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -338,7 +338,7 @@ def call_ex_kw4(node): kwargs = kwargs[0] call_function_ex = node[-1] assert call_function_ex == "CALL_FUNCTION_EX_KW" or ( - self.version >= 3.6 and call_function_ex == "CALL_FUNCTION_EX" + self.version >= (3, 6) and call_function_ex == "CALL_FUNCTION_EX" ) # FIXME: decide if the below test be on kwargs == 'dict' if ( diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 5d484cae3..d21665083 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2019, 2021 by Rocky Bernstein +# Copyright (c) 2015-2019, 2021-2022 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -64,6 +64,7 @@ # FIXME: DRY code with pysource import re +from StringIO import StringIO from uncompyle6.semantics import pysource from uncompyle6 import parser @@ -75,7 +76,7 @@ from uncompyle6.parsers.treenode import SyntaxTree -from uncompyle6.semantics.pysource import ParserError, StringIO +from uncompyle6.semantics.pysource import ParserError from xdis import iscode from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE @@ -628,32 +629,6 @@ def n_mkfunc(self, node): self.indent_less() self.prune() # stop recursing - def n_list_comp(self, node): - """List comprehensions""" - p = self.prec - self.prec = 27 - n = node[-1] - assert n == "list_iter" - # find innermost node - while n == "list_iter": - n = n[0] # recurse one step - if n == "list_for": - n = n[3] - elif n == "list_if": - n = n[2] - elif n == "list_if_not": - n = n[2] - assert n == "lc_body" - if node[0].kind.startswith("BUILD_LIST"): - start = len(self.f.getvalue()) - self.set_pos_info(node[0], start, start + 1) - self.write("[ ") - self.preorder(n[0]) # lc_body - self.preorder(node[-1]) # for/if parts - self.write(" ]") - self.prec = p - self.prune() # stop recursing - def comprehension_walk(self, node, iter_index, code_index=-5): p = self.prec self.prec = 27 @@ -946,7 +921,7 @@ def n_set_comp(self, node): self.set_pos_info(node[0], start - 1, start) self.comprehension_walk3(node, 1, 0) elif node[0].kind == "load_closure": - self.setcomprehension_walk3(node, collection_index=4) + self.closure_walk(node, collection_index=4) else: self.comprehension_walk(node, iter_index=4) self.write("}") @@ -1011,7 +986,7 @@ def n__ifstmts_jump_exit(self, node): ): self.set_pos_info(node[1], node[0][0].start, node[0][0].finish) - def setcomprehension_walk3(self, node, collection_index): + def closure_walk(self, node, collection_index): """Set comprehensions the way they are done in Python3. They're more other comprehensions, e.g. set comprehensions See if we can combine code. @@ -1185,7 +1160,7 @@ def build_ast( code, is_lambda=False, noneInNames=False, - isTopLevel=False, + is_top_level_module=False, ): # FIXME: DRY with pysource.py @@ -1227,7 +1202,7 @@ def build_ast( # Python 3.4's classes can add a "return None" which is # invalid syntax. if tokens[-2].kind == "LOAD_CONST": - if isTopLevel or tokens[-2].pattr is None: + if is_top_level_module or tokens[-2].pattr is None: del tokens[-2:] else: tokens.append(Token("RETURN_LAST")) @@ -2102,8 +2077,8 @@ def code_deparse( is_pypy=is_pypy, ) - isTopLevel = co.co_name == "" - deparsed.ast = deparsed.build_ast(tokens, customize, co, isTopLevel=isTopLevel) + is_top_level_module = co.co_name == "" + deparsed.ast = deparsed.build_ast(tokens, customize, co, is_top_level_module=is_top_level_module) assert deparsed.ast == "stmts", "Should have parsed grammar start" diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 75e43eebc..bc4e9b989 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -43,7 +43,7 @@ # describe rules and not have to create methods at all. # # So another other way to specify a semantic rule for a nonterminal is via -# one of the tables MAP_R0, MAP_R, or MAP_DIRECT where the key is the +# either tables MAP_R, or MAP_DIRECT where the key is the # nonterminal name. # # These dictionaries use a printf-like syntax to direct substitution @@ -63,15 +63,14 @@ # parse tree for N. # # -# N&K N N -# / | ... \ / | ... \ / | ... \ -# O O O O O K O O O -# | -# K -# TABLE_DIRECT TABLE_R TABLE_R0 +# N&K N +# / | ... \ / | ... \ +# O O O O O K +# +# +# TABLE_DIRECT TABLE_R # # The default table is TABLE_DIRECT mapping By far, most rules used work this way. -# TABLE_R0 is rarely used. # # The key K is then extracted from the subtree and used to find one # of the tables, T listed above. The result after applying T[K] is @@ -139,7 +138,7 @@ from uncompyle6.parser import get_python_parser from uncompyle6.parsers.treenode import SyntaxTree -from spark_parser import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from spark_parser import GenericASTTraversal from uncompyle6.scanner import Code, get_scanner import uncompyle6.parser as python_parser from uncompyle6.semantics.check_ast import checker @@ -185,6 +184,25 @@ DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False} +def unicode(x): return x +from StringIO import StringIO + +PARSER_DEFAULT_DEBUG = { + "rules": False, + "transition": False, + "reduce": False, + "errorstack": "full", + "context": True, + "dups": False, +} + +TREE_DEFAULT_DEBUG = {"before": False, "after": False} + +DEFAULT_DEBUG_OPTS = { + "asm": False, + "tree": TREE_DEFAULT_DEBUG, + "grammar": dict(PARSER_DEFAULT_DEBUG), +} class SourceWalkerError(Exception): def __init__(self, errmsg): @@ -202,7 +220,7 @@ def __init__( version, out, scanner, - showast=False, + showast=TREE_DEFAULT_DEBUG, debug_parser=PARSER_DEFAULT_DEBUG, compile_mode="exec", is_pypy=IS_PYPY, @@ -225,9 +243,9 @@ def __init__( mode that was used to create the Syntax Tree and specifies a gramar variant within a Python version to use. - `is_pypy' should be True if the Syntax Tree was generated for PyPy. + `is_pypy` should be True if the Syntax Tree was generated for PyPy. - `linestarts' is a dictionary of line number to bytecode offset. This + `linestarts` is a dictionary of line number to bytecode offset. This can sometimes assist in determinte which kind of source-code construct to use when there is ambiguity. @@ -244,9 +262,10 @@ def __init__( is_pypy=is_pypy, ) - self.treeTransform = TreeTransform( - version=version, show_ast=showast, is_pypy=is_pypy - ) + # Initialize p_lambda on demand + self.p_lambda = None + + self.treeTransform = TreeTransform(version=self.version, show_ast=showast) self.debug_parser = dict(debug_parser) self.showast = showast self.params = params @@ -286,25 +305,28 @@ def __init__( # An example is: # __module__ = __name__ self.hide_internal = True - self.compile_mode = "exec" + self.compile_mode = compile_mode self.name = None self.version = version self.is_pypy = is_pypy customize_for_version(self, is_pypy, version) - return - def maybe_show_tree(self, ast): - if self.showast and self.treeTransform.showast: + def maybe_show_tree(self, ast, phase): + if self.showast.get("before", False): self.println( """ ---- end before transform +""" + ) + if self.showast.get("after", False): + self.println( + """ ---- begin after transform """ - + " " + + " " ) - - if isinstance(self.showast, dict) and self.showast.get: + if self.showast.get(phase, False): maybe_show_tree(self, ast) def str_with_template(self, ast): @@ -586,8 +608,10 @@ def n_expr(self, node): self.prec = 6 # print("XXX", n.kind, p, "<", self.prec) + # print(self.f.getvalue()) if p < self.prec: + # print(f"PREC {p}, {node[0].kind}") self.write("(") self.preorder(node[0]) self.write(")") @@ -1111,8 +1135,8 @@ def comprehension_walk(self, node, iter_index, code_index=-5): ast = ast[0] n = ast[iter_index] - assert n == "comp_iter", n + assert n == "comp_iter", n.kind # Find the comprehension body. It is the inner-most # node that is not list_.. . while n == "comp_iter": # list_iter @@ -1154,10 +1178,24 @@ def n_generator_exp(self, node): code_index = -6 if self.version > (3, 6): # Python 3.7+ adds optional "come_froms" at node[0] - iter_index = 4 + if node[0].kind in ("load_closure", "load_genexpr") and self.version >= (3, 8): + is_lambda = self.is_lambda + if node[0].kind == "load_genexpr": + self.is_lambda = False + self.closure_walk(node, collection_index=4) + self.is_lambda = is_lambda + else: + code_index = -6 + if self.version < (3, 8): + iter_index = 4 + else: + iter_index = 3 + self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) + pass + pass else: code_index = -5 - self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) + self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) self.write(")") self.prune() @@ -1168,7 +1206,7 @@ def n_set_comp(self, node): if node[0] in ["LOAD_SETCOMP", "LOAD_DICTCOMP"]: self.comprehension_walk_newer(node, 1, 0) elif node[0].kind == "load_closure" and self.version >= (3, 0): - self.setcomprehension_walk3(node, collection_index=4) + self.closure_walk(node, collection_index=4) else: self.comprehension_walk(node, iter_index=4) self.write("}") @@ -1180,15 +1218,19 @@ def comprehension_walk_newer(self, node, iter_index, code_index=-5): """Non-closure-based comprehensions the way they are done in Python3 and some Python 2.7. Note: there are also other set comprehensions. """ + # FIXME: DRY with listcomp_closure3 p = self.prec self.prec = 27 code_obj = node[code_index].attr assert iscode(code_obj), node[code_index] + self.debug_opts["asm"] code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"]) - ast = self.build_ast(code._tokens, code._customize, code) + ast = self.build_ast( + code._tokens, code._customize, code, is_lambda=self.is_lambda + ) self.customize(code._customize) # skip over: sstmt, stmt, return, return_expr @@ -1336,7 +1378,6 @@ def comprehension_walk_newer(self, node, iter_index, code_index=-5): else: self.preorder(store) - # FIXME this is all merely approximate self.write(" in ") self.preorder(node[in_node_index]) @@ -1356,6 +1397,7 @@ def comprehension_walk_newer(self, node, iter_index, code_index=-5): self.write(" if ") if have_not: self.write("not ") + pass self.prec = 27 self.preorder(if_node) pass @@ -1375,32 +1417,86 @@ def n_listcomp(self, node): self.write("]") self.prune() - def setcomprehension_walk3(self, node, collection_index): - """Set comprehensions the way they are done in Python3. - They're more other comprehensions, e.g. set comprehensions - See if we can combine code. + def get_comprehension_function(self, node, code_index): + """ + Build the body of a comprehension function and then + find the comprehension node buried in the tree which may + be surrounded with start-like symbols or dominiators,. """ - p = self.prec self.prec = 27 + code_node = node[code_index] + if code_node == "load_genexpr": + code_node = code_node[0] + + code_obj = code_node.attr + assert iscode(code_obj), code_node + + code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"]) + + # FIXME: is there a way we can avoid this? + # The problem is that in filterint top-level list comprehensions we can + # encounter comprehensions of other kinds, and lambdas + if self.compile_mode in ("listcomp",): # add other comprehensions to this list + p_save = self.p + self.p = get_python_parser( + self.version, compile_mode="exec", is_pypy=self.is_pypy, + ) + tree = self.build_ast( + code._tokens, code._customize, code, is_lambda=self.is_lambda + ) + self.p = p_save + else: + tree = self.build_ast( + code._tokens, code._customize, code, is_lambda=self.is_lambda + ) - code = Code(node[1].attr, self.scanner, self.currentclass) - ast = self.build_ast(code._tokens, code._customize, code) self.customize(code._customize) + # skip over: sstmt, stmt, return, return_expr + # and other singleton derivations + if tree == "lambda_start": + if tree[0] in ("dom_start", "dom_start_opt"): + tree = tree[1] + + while len(tree) == 1 or ( + tree in ("stmt", "sstmt", "return", "return_expr", "return_expr_lambda") + ): + self.prec = 100 + tree = tree[0] + return tree + + def closure_walk(self, node, collection_index): + """Dictionary and comprehensions using closure the way they are done in Python3. + """ + p = self.prec + self.prec = 27 + + if node[0] == "load_genexpr": + code_index = 0 + else: + code_index = 1 + tree = self.get_comprehension_function(node, code_index=code_index) + # Remove single reductions as in ("stmts", "sstmt"): - while len(ast) == 1: - ast = ast[0] + while len(tree) == 1: + tree = tree[0] - store = ast[3] + store = tree[3] collection = node[collection_index] - n = ast[4] + if tree == "genexpr_func_async": + iter_index = 3 + else: + iter_index = 4 + + n = tree[iter_index] list_if = None assert n == "comp_iter" # Find inner-most node. while n == "comp_iter": n = n[0] # recurse one step + # FIXME: adjust for set comprehension if n == "list_for": store = n[2] @@ -1419,7 +1515,7 @@ def setcomprehension_walk3(self, node, collection_index): pass pass - assert n == "comp_body", ast + assert n == "comp_body", tree self.preorder(n[0]) self.write(" for ") @@ -1813,6 +1909,7 @@ def n_dict(self, node): self.kv_map(node[-1], sep, line_number, indent) pass + pass if sep.startswith(",\n"): self.write(sep[1:]) if node[0] != "dict_entry": @@ -1874,6 +1971,7 @@ def n_list(self, node): self.write("(") endchar = ")" else: + # from trepan.api import debug; debug() raise TypeError( "Internal Error: n_build_list expects list, tuple, set, or unpack" ) @@ -2044,23 +2142,22 @@ def template_engine(self, entry, startnode): index = entry[arg] if isinstance(index, tuple): if isinstance(index[1], str): + # if node[index[0]] != index[1]: + # from trepan.api import debug; debug() assert node[index[0]] == index[1], ( "at %s[%d], expected '%s' node; got '%s'" - % (node.kind, arg, index[1], node[index[0]].kind) + % (node.kind, arg, index[1], node[index[0]].kind,) ) else: assert node[index[0]] in index[1], ( "at %s[%d], expected to be in '%s' node; got '%s'" - % (node.kind, arg, index[1], node[index[0]].kind) + % (node.kind, arg, index[1], node[index[0]].kind,) ) index = index[0] - assert isinstance( - index, int - ), "at %s[%d], %s should be int or tuple" % ( - node.kind, - arg, - type(index), + assert isinstance(index, int), ( + "at %s[%d], %s should be int or tuple" + % (node.kind, arg, type(index),) ) try: @@ -2082,10 +2179,17 @@ def template_engine(self, entry, startnode): assert isinstance(tup, tuple) if len(tup) == 3: (index, nonterm_name, self.prec) = tup - assert node[index] == nonterm_name, ( - "at %s[%d], expected '%s' node; got '%s'" - % (node.kind, arg, nonterm_name, node[index].kind) - ) + if isinstance(tup[1], str): + assert node[index] == nonterm_name, ( + "at %s[%d], expected '%s' node; got '%s'" + % (node.kind, arg, nonterm_name, node[index].kind,) + ) + else: + assert node[tup[0]] in tup[1], ( + "at %s[%d], expected to be in '%s' node; got '%s'" + % (node.kind, arg, index[1], node[index[0]].kind,) + ) + else: assert len(tup) == 2 (index, self.prec) = entry[arg] @@ -2416,10 +2520,10 @@ def build_class(self, code): # print stmt[-1] - # Add "global" declaration statements at the top globals, nonlocals = find_globals_and_nonlocals( ast, set(), set(), code, self.version ) + # Add "global" declaration statements at the top # of the function for g in sorted(globals): self.println(indent, "global ", g) @@ -2458,11 +2562,8 @@ def gen_source( self.println(self.indent, "pass") else: self.customize(customize) - if is_lambda: - self.write(self.traverse(ast, is_lambda=is_lambda)) - else: - self.text = self.traverse(ast, is_lambda=is_lambda) - self.println(self.text) + self.text = self.traverse(ast, is_lambda=is_lambda) + self.println(self.text) self.name = old_name self.return_none = rn @@ -2473,7 +2574,7 @@ def build_ast( code, is_lambda=False, noneInNames=False, - isTopLevel=False, + is_top_level_module=False, ): # FIXME: DRY with fragments.py @@ -2500,10 +2601,10 @@ def build_ast( raise ParserError(e, tokens, self.p.debug["reduce"]) except AssertionError, e: raise ParserError(e, tokens, self.p.debug["reduce"]) - transform_ast = self.treeTransform.transform(ast, code) - self.maybe_show_tree(ast) + transform_tree = self.treeTransform.transform(ast, code) + self.maybe_show_tree(ast, phase="after") del ast # Save memory - return transform_ast + return transform_tree # The bytecode for the end of the main routine has a # "return None". However you can't issue a "return" statement in @@ -2515,7 +2616,7 @@ def build_ast( # Python 3.4's classes can add a "return None" which is # invalid syntax. if tokens[-2].kind == "LOAD_CONST": - if isTopLevel or tokens[-2].pattr is None: + if is_top_level_module or tokens[-2].pattr is None: del tokens[-2:] else: tokens.append(Token("RETURN_LAST")) @@ -2540,12 +2641,12 @@ def build_ast( checker(ast, False, self.ast_errors) self.customize(customize) - transform_ast = self.treeTransform.transform(ast, code) + transform_tree = self.treeTransform.transform(ast, code) - self.maybe_show_tree(ast) + self.maybe_show_tree(ast, phase="before") del ast # Save memory - return transform_ast + return transform_tree @classmethod def _get_mapping(cls, node): @@ -2573,16 +2674,13 @@ def code_deparse( version = PYTHON_VERSION_TRIPLE # store final output stream for case of error - scanner = get_scanner(version, is_pypy=is_pypy) + scanner = get_scanner(version, is_pypy=is_pypy, show_asm=debug_opts["asm"]) tokens, customize = scanner.ingest( co, code_objects=code_objects, show_asm=debug_opts["asm"] ) - debug_parser = dict(PARSER_DEFAULT_DEBUG) - if debug_opts.get("grammar", None): - debug_parser["reduce"] = debug_opts["grammar"] - debug_parser["errorstack"] = "full" + debug_parser = debug_opts.get("grammar", dict(PARSER_DEFAULT_DEBUG)) # Build Syntax Tree from disassembly. linestarts = dict(scanner.opc.findlinestarts(co)) @@ -2590,27 +2688,49 @@ def code_deparse( version, out, scanner, - showast=debug_opts.get("ast", None), + showast=debug_opts.get("tree", TREE_DEFAULT_DEBUG), debug_parser=debug_parser, compile_mode=compile_mode, is_pypy=is_pypy, linestarts=linestarts, ) - isTopLevel = co.co_name == "" + is_top_level_module = co.co_name == "" if compile_mode == "eval": deparsed.hide_internal = False - deparsed.ast = deparsed.build_ast(tokens, customize, co, isTopLevel=isTopLevel) + deparsed.compile_mode = compile_mode + deparsed.ast = deparsed.build_ast( + tokens, + customize, + co, + is_lambda=(compile_mode == "lambda"), + is_top_level_module=is_top_level_module, + ) #### XXX workaround for profiling if deparsed.ast is None: return None - if compile_mode != "eval": - assert deparsed.ast == "stmts", "Should have parsed grammar start" + # FIXME use a lookup table here. + if compile_mode == "lambda": + expected_start = "lambda_start" + elif compile_mode == "eval": + expected_start = "expr_start" + elif compile_mode == "expr": + expected_start = "expr_start" + elif compile_mode == "exec": + expected_start = "stmts" + elif compile_mode == "single": + expected_start = "single_start" else: - assert deparsed.ast == "eval_expr", "Should have parsed grammar start" - + expected_start = None + if expected_start: + assert ( + deparsed.ast == expected_start + ), ( + "Should have parsed grammar start to '%s'; got: %s" % + (expected_start, deparsed.ast.kind) + ) # save memory del tokens @@ -2652,7 +2772,11 @@ def code_deparse( # What we've been waiting for: Generate source from Syntax Tree! deparsed.gen_source( - deparsed.ast, name=co.co_name, customize=customize, debug_opts=debug_opts + deparsed.ast, + name=co.co_name, + customize=customize, + is_lambda=compile_mode == "lambda", + debug_opts=debug_opts, ) for g in sorted(deparsed.mod_globs): @@ -2660,7 +2784,7 @@ def code_deparse( if deparsed.ast_errors: deparsed.write("# NOTE: have internal decompilation grammar errors.\n") - deparsed.write("# Use -t option to show full context.") + deparsed.write("# Use -T option to show full context.") for err in deparsed.ast_errors: deparsed.write(err) raise SourceWalkerError("Deparsing hit an internal grammar-rule bug") diff --git a/uncompyle6/show.py b/uncompyle6/show.py index bf5e40326..8115ca004 100644 --- a/uncompyle6/show.py +++ b/uncompyle6/show.py @@ -52,7 +52,7 @@ def maybe_show_tree(walker, ast): stream = sys.stdout if ( isinstance(walker.showast, dict) - and walker.showast.get("Full", False) + and walker.showast.get("after", False) and hasattr(walker, "str_with_template") ): walker.str_with_template(ast) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index fed5a211a..44c88a7dc 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.8.1.dev0" # noqa +__version__="3.9.0a1" # noqa From f89a3e8fa18dbe0e4f57cbbb90e2603b8596ad11 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Mar 2022 05:12:44 -0500 Subject: [PATCH 287/489] Remove some 3.6ish type annotations --- uncompyle6/main.py | 4 ++-- uncompyle6/parsers/reducecheck/and_not_check.py | 2 +- uncompyle6/semantics/fragments.py | 2 +- uncompyle6/semantics/pysource.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 3bc89f9de..25da29c14 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -45,7 +45,7 @@ def _get_outstream(outfile): def decompile( co, - bytecode_version: str = PYTHON_VERSION_TRIPLE, + bytecode_version = PYTHON_VERSION_TRIPLE, out=sys.stdout, showasm=None, showast={}, @@ -171,7 +171,7 @@ def compile_file(source_path): def decompile_file( - filename: str, + filename, outstream=None, showasm=None, showast={}, diff --git a/uncompyle6/parsers/reducecheck/and_not_check.py b/uncompyle6/parsers/reducecheck/and_not_check.py index a246e6302..dbdef0296 100644 --- a/uncompyle6/parsers/reducecheck/and_not_check.py +++ b/uncompyle6/parsers/reducecheck/and_not_check.py @@ -3,7 +3,7 @@ def and_not_check( self, lhs, n, rule, ast, tokens, first, last -) -> bool: +): jmp = ast[1] if jmp.kind.startswith("jmp_"): if last == n: diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index dc4e8e47b..00eee644f 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -2276,7 +2276,7 @@ def deparsed_find(tup, deparsed, code): # def test(): # import os, sys -# def get_dups(li: list) -> set: +# def get_dups(li: list): # dups = {} # for item in li: # dups[item] = dups.get(item, -1) + 1 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index bfcb357ce..6cdfcee0e 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1414,7 +1414,7 @@ def n_listcomp(self, node): self.write("]") self.prune() - def get_comprehension_function(self, node, code_index: int): + def get_comprehension_function(self, node, code_index): """ Build the body of a comprehension function and then find the comprehension node buried in the tree which may From c5bc21bf6a767b91c934432f0cd3465169f8fafb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Mar 2022 03:53:44 -0500 Subject: [PATCH 288/489] Correct some 2.6 bugs in chained compare ... and other bugs * main.py: was botching a version triple test * parse2{5,6}.py: Add 2.6 try/except end position checking via COME_FROM offsets * parse26.py: adjust grammar rule for chained-compare2 such as in try-except --- uncompyle6/main.py | 2 +- uncompyle6/parsers/parse25.py | 2 +- uncompyle6/parsers/parse26.py | 7 +++++-- uncompyle6/parsers/reducecheck/tryexcept.py | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 9fd31f3d6..7b45f5fdd 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -315,7 +315,7 @@ def main( else: buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) - if PYTHON_VERSION_TRIPLE > (2, 6): + if PYTHON_VERSION_TRIPLE >= (2, 7): tee = subprocess.Popen(["tee", current_outfile], stdin=subprocess.PIPE) os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 0c6a79649..cf687f292 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -98,7 +98,7 @@ def customize_grammar_rules(self, tokens, customize): """) super(Python25Parser, self).customize_grammar_rules(tokens, customize) if self.version[:2] == (2, 5): - self.check_reduce["try_except"] = "tokens" + self.check_reduce["try_except"] = "AST" self.check_reduce["aug_assign1"] = "AST" self.check_reduce["ifelsestmt"] = "AST" diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 30a2f788a..06821f41d 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -6,7 +6,7 @@ from uncompyle6.parser import PythonParserSingle from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse2 import Python2Parser -from uncompyle6.parsers.reducecheck import (except_handler, tryelsestmt) +from uncompyle6.parsers.reducecheck import (except_handler, tryexcept, tryelsestmt) class Python26Parser(Python2Parser): @@ -318,6 +318,8 @@ def p_misc26(self, args): return_lambda ::= RETURN_VALUE_LAMBDA compare_chained2 ::= expr COMPARE_OP return_expr_lambda + compare_chained2 ::= expr COMPARE_OP RETURN_END_IF_LAMBDA + compare_chained2 ::= expr COMPARE_OP RETURN_END_IF COME_FROM return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP stmt ::= if_exp_lambda @@ -354,6 +356,7 @@ def customize_grammar_rules(self, tokens, customize): self.reduce_check_table = { "except_handler": except_handler, "tryelsestmt": tryelsestmt, + "try_except": tryexcept, "tryelsestmtl": tryelsestmt, } @@ -366,7 +369,7 @@ def customize_grammar_rules(self, tokens, customize): self.check_reduce["forelselaststmtl"] = "tokens" self.check_reduce["forelsestmt"] = "tokens" self.check_reduce['list_for'] = 'AST' - self.check_reduce['try_except'] = 'tokens' + self.check_reduce['try_except'] = 'AST' self.check_reduce['tryelsestmt'] = 'AST' self.check_reduce['tryelsestmtl'] = 'AST' diff --git a/uncompyle6/parsers/reducecheck/tryexcept.py b/uncompyle6/parsers/reducecheck/tryexcept.py index 33b07d67b..ffad50619 100644 --- a/uncompyle6/parsers/reducecheck/tryexcept.py +++ b/uncompyle6/parsers/reducecheck/tryexcept.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Rocky Bernstein +# Copyright (c) 2020, 2022 Rocky Bernstein def tryexcept(self, lhs, n, rule, ast, tokens, first, last): come_from_except = ast[-1] @@ -13,12 +13,24 @@ def tryexcept(self, lhs, n, rule, ast, tokens, first, last): ), ): if come_from_except[0] == "COME_FROM": - # There should be at last two COME_FROMs, one from an + # There should be at least two COME_FROMs, one from an # exception handler and one from the try. Otherwise # we have a try/else. return True pass + elif rule == ( + "try_except", + ( + "SETUP_EXCEPT", + "suite_stmts_opt", + "POP_BLOCK", + "except_handler", + "COME_FROM", + ), + ): + return come_from_except.attr < tokens[first].offset + elif rule == ( 'try_except', ( From 27583856cbc8bb136cd351b688555276c87e0144 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Mar 2022 10:23:25 -0500 Subject: [PATCH 289/489] Remove 3.x "... if ... else" from this branch --- uncompyle6/semantics/customize3.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 07be2a365..c1962e263 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -174,7 +174,10 @@ def listcomp_closure3(node): list_ifs.append(n) else: list_ifs.append([1]) - n = n[-2] if n[-1] == "come_from_opt" else n[-1] + if n[-1] == "come_from_opt": + n = n[-2] + else: + n = n[-1] pass elif n == "list_if37": list_ifs.append(n) @@ -184,7 +187,10 @@ def listcomp_closure3(node): collections.append(n[0][0]) n = n[1] stores.append(n[1][0]) - n = n[2] if n[2].kind == "list_iter" else n[3] + if n[2].kind == "list_iter": + n = n[2] + else: + n = n[3] pass assert n == "lc_body", ast From 48fc42d182bdc0cf76cadd829095381a22bd16d3 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 31 Mar 2022 06:48:09 -0400 Subject: [PATCH 290/489] Remove workflows testing... It no longer works on 2.7 --- .github/workflows/osx.yml | 30 ------------------------------ .github/workflows/ubuntu.yml | 30 ------------------------------ .github/workflows/windows.yml | 30 ------------------------------ 3 files changed, 90 deletions(-) delete mode 100644 .github/workflows/osx.yml delete mode 100644 .github/workflows/ubuntu.yml delete mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml deleted file mode 100644 index 6d444c56d..000000000 --- a/.github/workflows/osx.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: uncompyle6 (osx) - -on: - push: - branches: [ python-2.4 ] - pull_request: - branches: [ python-2.4 ] - -jobs: - build: - runs-on: macos-latest - strategy: - matrix: - os: [macOS] - python-version: [2.7] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - # Until the next xdis release - # pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis - pip install -e . - pip install -r requirements-dev.txt - - name: Test uncompyle6 - run: | - make check diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml deleted file mode 100644 index e24655881..000000000 --- a/.github/workflows/ubuntu.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: uncompyle6 (ubuntu) - -on: - push: - branches: [ python-2.4 ] - pull_request: - branches: [ python-2.4 ] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [2.7] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - # Until the next xdis release - # pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis - pip install -e . - pip install -r requirements-dev.txt - - name: Test uncompyle6 - run: | - make check diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index c9058e242..000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: uncompyle6 (windows) - -on: - push: - branches: [ python-2.4 ] - pull_request: - branches: [ python-2.4 ] - -jobs: - build: - runs-on: macos-latest - strategy: - matrix: - os: [windows] - python-version: [2.7] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - # Until the next xdis release - # pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis - pip install -e . - pip install -r requirements-dev.txt - - name: Test uncompyle6 - run: | - make check From 3c2ed93b342edc613fa0e8beb4e2dc2b2ce3183e Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 15 Apr 2022 08:57:55 -0400 Subject: [PATCH 291/489] Python 2.4 seems broken --- .github/ISSUE_TEMPLATE/bug-report.md | 26 +++- HOW-TO-REPORT-A-BUG.md | 2 + admin-tools/pyenv-newest-versions | 2 +- pytest/test_single_compile.py | 5 +- test/Makefile | 66 ++++---- test/add-test.py | 2 +- test/bytecode_3.1_run/10_complex.pyc | Bin 2009 -> 2774 bytes test/bytecode_3.3_run/10_complex.pyc | Bin 2152 -> 2345 bytes test/bytecode_3.5_run/10_complex.pyc | Bin 1635 -> 1687 bytes ...oc_assign.pyc-notyet => 03_doc_assign.pyc} | Bin test/bytecode_3.6_run/10_fstring.pyc | Bin 2888 -> 1526 bytes test/bytecode_3.7_run/10_complex.pyc | Bin 1915 -> 1530 bytes test/bytecode_3.7_run/10_fstring.pyc | Bin 2877 -> 1520 bytes test/bytecode_3.8_run/02_named_expr.pyc | Bin 0 -> 174 bytes test/bytecode_3.8_run/10_fstring.pyc | Bin 2933 -> 1534 bytes test/simple_source/bug31/10_complex.py | 6 +- test/simple_source/bug36/10_fstring.py | 91 ++++++----- test/simple_source/bug38/02_named_expr.py | 14 ++ uncompyle6/parsers/parse37.py | 8 + uncompyle6/parsers/parse37base.py | 2 +- uncompyle6/scanners/pypy37.py | 4 +- uncompyle6/scanners/scanner37.py | 5 +- uncompyle6/semantics/consts.py | 117 +++++++------- uncompyle6/semantics/customize37.py | 145 +++++++++++++++--- uncompyle6/semantics/customize38.py | 4 - uncompyle6/semantics/pysource.py | 20 ++- 26 files changed, 343 insertions(+), 176 deletions(-) rename test/bytecode_3.6_run/{03_doc_assign.pyc-notyet => 03_doc_assign.pyc} (100%) create mode 100644 test/bytecode_3.8_run/02_named_expr.pyc create mode 100644 test/simple_source/bug38/02_named_expr.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 79379cbf1..cec076b49 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -28,6 +28,8 @@ someone to do, especially when you are the primary beneficiary of the work, or the task is complex, long, or tedious. If your code is over 30 lines long, it fits into this category. + +See also https://github.com/rocky/python-uncomp[yle6/blob/master/HOW-TO-REPORT-A-BUG.md ? --> + ## How to Reproduce @@ -73,6 +75,16 @@ can add that too. --> +## Output Given + + + + ## Expected behavior @@ -84,12 +96,20 @@ can add that too. Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` -- Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct Cpython or Pypy binary. +- Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. - OS and Version: [e.g. Ubuntu bionic] --> -## Additional Environment or Context +## Workarounds + + + +## Priority + + + +## Additional Context Ax By C- D- - fillvalue = kwds.get('fillvalue') - def sentinel(counter = ([fillvalue]*(len(args)-1)).pop): - yield counter() # yields the fillvalue, or raises IndexError + fillvalue = kwds.get("fillvalue") + + def sentinel(counter=([fillvalue] * (len(args) - 1)).pop): + yield counter() # yields the fillvalue, or raises IndexError + fillers = repeat(fillvalue) iters = [chain(it, sentinel(), fillers) for it in args] try: @@ -36,11 +39,13 @@ def sentinel(counter = ([fillvalue]*(len(args)-1)).pop): except IndexError: pass -read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL')) -read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL')) + +read_write_global_ops = frozenset(("STORE_GLOBAL", "DELETE_GLOBAL", "LOAD_GLOBAL")) +read_global_ops = frozenset(("STORE_GLOBAL", "DELETE_GLOBAL")) # NOTE: we also need to check that the variable name is a free variable, not a cell variable. -nonglobal_ops = frozenset(('STORE_DEREF', 'DELETE_DEREF')) +nonglobal_ops = frozenset(("STORE_DEREF", "DELETE_DEREF")) + def escape_string(s, quotes=('"', "'", '"""', "'''")): quote = None @@ -53,12 +58,11 @@ def escape_string(s, quotes=('"', "'", '"""', "'''")): quote = '"""' s = s.replace('"""', '\\"""') - for (orig, replace) in (('\t', '\\t'), - ('\n', '\\n'), - ('\r', '\\r')): + for (orig, replace) in (("\t", "\\t"), ("\n", "\\n"), ("\r", "\\r")): s = s.replace(orig, replace) return "%s%s%s" % (quote, s, quote) + # FIXME: this and find_globals could be paramaterized with one of the # above global ops def find_all_globals(node, globs): @@ -70,6 +74,7 @@ def find_all_globals(node, globs): globs.add(n.pattr) return globs + # def find_globals(node, globs, global_ops=mkfunc_globals): # """Find globals in this statement.""" # for n in node: @@ -84,6 +89,7 @@ def find_all_globals(node, globs): # globs.add(n.pattr) # return globs + def find_code_node(node, start): for i in range(-start, len(node) + 1): if node[-i].kind == "LOAD_CODE": @@ -99,28 +105,33 @@ def find_globals_and_nonlocals(node, globs, nonlocals, code, version): either 'global' or 'nonlocal' statements added.""" for n in node: if isinstance(n, SyntaxTree): - globs, nonlocals = find_globals_and_nonlocals(n, globs, nonlocals, - code, version) + globs, nonlocals = find_globals_and_nonlocals( + n, globs, nonlocals, code, version + ) elif n.kind in read_global_ops: globs.add(n.pattr) - elif (version >= (3, 0) - and n.kind in nonglobal_ops - and n.pattr in code.co_freevars - and n.pattr != code.co_name - and code.co_name != ''): + elif ( + version >= (3, 0) + and n.kind in nonglobal_ops + and n.pattr in code.co_freevars + and n.pattr != code.co_name + and code.co_name != "" + ): nonlocals.add(n.pattr) return globs, nonlocals + def find_none(node): for n in node: if isinstance(n, SyntaxTree): - if n not in ('return_stmt', 'return_if_stmt'): + if n not in ("return_stmt", "return_if_stmt"): if find_none(n): return True - elif n.kind == 'LOAD_CONST' and n.pattr is None: + elif n.kind == "LOAD_CONST" and n.pattr is None: return True return False + def flatten_list(node): """ List of expressions may be nested in groups of 32 and 1024 @@ -128,14 +139,14 @@ def flatten_list(node): """ flat_elems = [] for elem in node: - if elem == 'expr1024': + if elem == "expr1024": for subelem in elem: - assert subelem == 'expr32' + assert subelem == "expr32" for subsubelem in subelem: flat_elems.append(subsubelem) - elif elem == 'expr32': + elif elem == "expr32": for subelem in elem: - assert subelem == 'expr' + assert subelem == "expr" flat_elems.append(subelem) else: flat_elems.append(elem) @@ -143,6 +154,7 @@ def flatten_list(node): pass return flat_elems + # Note: this is only used in Python > 3.0 # Should move this somewhere more specific? def gen_function_parens_adjust(mapping_key, node): @@ -151,19 +163,20 @@ def gen_function_parens_adjust(mapping_key, node): 'call_generator' and the caller will do the default action on that. Otherwise we do nothing. """ - if mapping_key.kind != 'CALL_FUNCTION_1': + if mapping_key.kind != "CALL_FUNCTION_1": return args_node = node[-2] - if args_node == 'pos_arg': - assert args_node[0] == 'expr' + if args_node == "pos_arg": + assert args_node[0] == "expr" n = args_node[0][0] - if n == 'generator_exp': - node.kind = 'call_generator' + if n == "generator_exp": + node.kind = "call_generator" pass return -def is_lambda_mode(compile_mode: str) -> bool: + +def is_lambda_mode(compile_mode): return compile_mode in ("dictcomp", "genexpr", "lambda", "listcomp", "setcomp") @@ -176,36 +189,39 @@ def print_docstring(self, indent, docstring): self.write(indent) if not isinstance(docstring, str): # Must be unicode in Python2 - self.write('u') + self.write("u") docstring = repr(docstring.expandtabs())[2:-1] else: docstring = repr(docstring.expandtabs())[1:-1] - for (orig, replace) in (('\\\\', '\t'), - ('\\r\\n', '\n'), - ('\\n', '\n'), - ('\\r', '\n'), - ('\\"', '"'), - ("\\'", "'")): + for (orig, replace) in ( + ("\\\\", "\t"), + ("\\r\\n", "\n"), + ("\\n", "\n"), + ("\\r", "\n"), + ('\\"', '"'), + ("\\'", "'"), + ): docstring = docstring.replace(orig, replace) # Do a raw string if there are backslashes but no other escaped characters: # also check some edge cases - if ('\t' in docstring - and '\\' not in docstring + if ( + "\t" in docstring + and "\\" not in docstring and len(docstring) >= 2 - and docstring[-1] != '\t' - and (docstring[-1] != '"' - or docstring[-2] == '\t')): - self.write('r') # raw string + and docstring[-1] != "\t" + and (docstring[-1] != '"' or docstring[-2] == "\t") + ): + self.write("r") # raw string # Restore backslashes unescaped since raw - docstring = docstring.replace('\t', '\\') + docstring = docstring.replace("\t", "\\") else: # Escape the last character if it is the same as the # triple quote character. quote1 = quote[-1] if len(docstring) and docstring[-1] == quote1: - docstring = docstring[:-1] + '\\' + quote1 + docstring = docstring[:-1] + "\\" + quote1 # Escape triple quote when needed if quote == '"""': @@ -215,9 +231,9 @@ def print_docstring(self, indent, docstring): replace_str = "\\'''" docstring = docstring.replace(quote, replace_str) - docstring = docstring.replace('\t', '\\\\') + docstring = docstring.replace("\t", "\\\\") - lines = docstring.split('\n') + lines = docstring.split("\n") self.write(quote) if len(lines) == 0: @@ -228,14 +244,15 @@ def print_docstring(self, indent, docstring): self.println(lines[0]) for line in lines[1:-1]: if line: - self.println( line ) + self.println(line) else: - self.println( "\n\n" ) + self.println("\n\n") pass pass self.println(lines[-1], quote) return True + def strip_quotes(s): if s.startswith("'''") and s.endswith("'''"): s = s[3:-3] @@ -249,7 +266,6 @@ def strip_quotes(s): return s - # if __name__ == '__main__': # from io import StringIO # class PrintFake(): From 484ded7635ef9f8168929117211e96de7da46b7b Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Apr 2022 08:30:44 -0400 Subject: [PATCH 295/489] Python 2.4 compliance --- uncompyle6/semantics/n_actions.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 9506c21d7..c2f273b12 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -394,7 +394,10 @@ def n_generator_exp(self, node): self.is_lambda = is_lambda else: code_index = -6 - iter_index = 4 if self.version < (3, 8) else 3 + if self.version < (3, 8): + iter_index = 4 + else: + iter_index = 3 self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) pass pass From 0f525c142dc42305fab5670aff0a8a6155610c89 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Apr 2022 07:53:36 -0400 Subject: [PATCH 296/489] Python 3.3 tolerance --- uncompyle6/scanner.py | 6 +++--- uncompyle6/scanners/scanner37.py | 5 ++--- uncompyle6/scanners/scanner37base.py | 22 ++++++++++------------ uncompyle6/semantics/n_actions.py | 4 ++-- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index c546ba17a..bb1114e98 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, 2018-2021 by Rocky Bernstein +# Copyright (c) 2016, 2018-2022 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -168,7 +168,7 @@ def bound_collection( opname="COLLECTION_START", attr=collection_enum, pattr=collection_type, - offset=f"{start_offset}_0", + offset="%s_0" % start_offset, has_arg=True, opc=self.opc, has_extended_arg=False, @@ -189,7 +189,7 @@ def bound_collection( ) new_tokens.append( Token( - opname=f"BUILD_{collection_type}", + opname="BUILD_%s" % collection_type, attr=t.attr, pattr=t.pattr, offset=t.offset, diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 7ccfc91cf..4cd0df597 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,7 +22,6 @@ scanner routine for Python 3. """ -from typing import Tuple from uncompyle6.scanners.scanner37base import Scanner37Base # bytecode verification, verify(), uses JUMP_OPs from here @@ -44,7 +43,7 @@ def __init__(self, show_asm=None, is_pypy: bool=False): def ingest( self, co, classname=None, code_objects={}, show_asm=None - ) -> Tuple[list, dict]: + ): """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing @@ -78,7 +77,7 @@ def ingest( else t.kind.split("_")[1] ) new_tokens = self.bound_collection( - tokens, new_tokens, t, i, f"CONST_{collection_type}" + tokens, new_tokens, t, i, "CONST_%s" % collection_type ) continue diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 238006ed2..64445f784 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -29,8 +29,6 @@ Finally we save token information. """ -from typing import Any, Dict, List, Set - from xdis import iscode, instruction_size, Instruction from xdis.bytecode import _get_const_info @@ -534,17 +532,17 @@ def find_jump_targets(self, debug: str) -> dict: self.structs = [{"type": "root", "start": 0, "end": n - 1}] # All loop entry points - self.loops: List[int] = [] + self.loops = [] # Map fixed jumps to their real destination - self.fixed_jumps: Dict[int, int] = {} + self.fixed_jumps = {} self.except_targets = {} - self.ignore_if: Set[int] = set() + self.ignore_if = set() self.build_statement_indices() # Containers filled by detect_control_flow() - self.not_continue: Set[int] = set() - self.return_end_ifs: Set[int] = set() + self.not_continue = set() + self.return_end_ifs = set() self.setup_loop_targets = {} # target given setup_loop offset self.setup_loops = {} # setup_loop offset given target @@ -683,7 +681,7 @@ def build_statement_indices(self): slist += [codelen] * (codelen - len(slist)) def detect_control_flow( - self, offset: int, targets: Dict[Any, Any], inst_index: int + self, offset, targets, inst_index ): """ Detect type of block structures and their boundaries to fix optimized jumps @@ -695,9 +693,9 @@ def detect_control_flow( op = inst.opcode # Detect parent structure - parent: Dict[str, Any] = self.structs[0] - start: int = parent["start"] - end: int = parent["end"] + parent = self.structs[0] + start = parent["start"] + end = parent["end"] # Pick inner-most parent for our offset for struct in self.structs: @@ -941,5 +939,5 @@ def next_except_jump(self, start): for t in tokens: print(t) else: - print(f"Need to be Python 3.7 to demo; I am version {version_tuple_to_str()}.") + print("Need to be Python 3.7 to demo; I am version %s." % version_tuple_to_str()) pass diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index d108b742e..835bf232a 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -221,7 +221,7 @@ def n_const_list(self, node): else: # from trepan.api import debug; debug() raise TypeError( - f"Internal Error: n_const_list expects dict, list set, or set; got {lastnodetype}" + "Internal Error: n_const_list expects dict, list set, or set; got %s" % lastnodetype ) self.indent_more(INDENT_PER_LEVEL) @@ -240,7 +240,7 @@ def n_const_list(self, node): else: if sep != "": sep += " " - self.write(f"{sep} {repr(keys[i])}: {value}") + self.write("%s %s: %s" % (sep, repr(keys[i]), value)) sep = "," else: for elem in flat_elems: From d8d8ed60d7b0da2953bf21a4e2c7933b6527aae5 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 25 Apr 2022 07:56:41 -0400 Subject: [PATCH 297/489] Python 3.3 tolerance --- uncompyle6/parsers/parse37base.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 96c24c716..93083588d 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -321,18 +321,18 @@ def customize_grammar_rules(self, tokens, customize): elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): if opname == "BUILD_CONST_DICT": - rule = f""" + rule = """ add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts {opname} + const_list ::= COLLECTION_START add_consts %s dict ::= const_list expr ::= dict - """ + """ % opname else: - rule = f""" + rule = """ add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts {opname} + const_list ::= COLLECTION_START add_consts %s expr ::= const_list - """ + """ % opname self.addRule(rule, nop_func) elif opname_base == "BUILD_CONST_KEY_MAP": From 2d6f31df9753e40bd048c8130df61693f73ef954 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Apr 2022 02:34:00 -0400 Subject: [PATCH 298/489] Use attr insead of pattrr for non-strings --- test/bytecode_3.6_run/05_long_literals.pyc | Bin 0 -> 15723 bytes uncompyle6/scanners/scanner3.py | 14 ++++++++------ uncompyle6/semantics/n_actions.py | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 test/bytecode_3.6_run/05_long_literals.pyc diff --git a/test/bytecode_3.6_run/05_long_literals.pyc b/test/bytecode_3.6_run/05_long_literals.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e73e3a0f4426315e51741977f063c686bec74413 GIT binary patch literal 15723 zcmeI%XOvY{o`&&zDMEn+$vFusC_>fQyONSY1Qbva)B;4{7CBi32xbr^iWmS%0tSL4 zvw|XEA}B~u&{Be8LcyHlybsj=ub!SSJ+r1i%q*Jq{OWqpz1z~4<5E|uREhc1`}bXX zQ7m>O_7DI2IUb9()Nkiyo*s)0h-JqTCw>e_3ZG8?_9;(&2mZId12f|T8vWn=yK7)J z|G%^2Ij4S{`VRaXz5^$haq91`Q{RDq$9G_6eBjAncjJjdiKIl~M3F?%M6pEjf@J-w z7EcsUlvq$GJC+lh8BhGK{!o9aztrC|3ngMIt_rCnRag~KMO87Ctct4=>NHhSl~Scu z8FjiUtIDbJs)DMhDyhnQdOj!@+wWGs|=N?vefzN0@YMCQ_WQi)l#)mtyLSFO>uL*1=rs(aME>OOV9nx$r|IqCs5SItxN)dICpJ*XC`#cGLq zNIk3`QID#nYMENDR;b6+O0`O@R%_H+^|*RMJ*l2jPpfCtv+6nZyjrK$s~6OZYJ+-7 zZB(1oX7#dqMZKzCQ?IKnYOC6&wyQVPn`(#Jsoqk%)NZv$?Nx89cho+$U%ji|Q~BzB z^?^E|4yr@yu=-Gaq>iYM)hFsx^_luy9aUebFV!)1Tz#d!R^O;^)pzQ9^@I9R{iJ?Y zzo=i;Z|ZmThx$|frT(6or2Qvp|4G_^lJ>7(KU5J_R25Uns<I_v+)mLY#v((wDfoiDEQRk{g>O9q0 zHBl)lRYl4vuhLYy%21gqOP#MSP)$`c)m*huEmbSkTD4Ja)rG2^x=6KG9aKkkvARTc zQk_*7b*Z{cU9P&SD^xetU0tcJQdg^N)kF1Ez0@_Tx4KsKQGHcEl~6gVzZ#$hszGY7 z8lr}(VQRP6fRIbWXqts|MMqRJQs&VQDb)&jT-K=g=x2oIJcr`)Yt|qEG)SYUQ znyjX%scM>Px<}os?o;=xS!%YLqaILm)jTy{El>;9gKCjltd^*U)Whl# z^{85^mZ{}xg?db_RIAi#wMMN~kEMzu+8 zRxhhp)T`<>^}5=kwyJGvyLv;tsdlKH>MgZP?N)o#UiG$mN9|Ml)w}9Fm9O4cAE*QB zpgN=us}I#j>WKPSeWE^9pQ+E)QT2uTQXNyr)mQ3ky~BT*8DH>IcA=bjB37CAz24S| z(@y+zKuP_RK&cb|EKoX8CUJVAY@%GEe4;|4Vxm%_a-vG2YNA@AdZI?6W};T2cA`$A zt~MA?{JNlSb|HQJt!u2oH%YPBQT>~Q*wI3u--;bA3dNu}oCYOD!{q#U-~4#L{CG}& zd_aDDV19gXetbxN(cGL-qjQHJEzIvzD3{Z6PaIT)KQb9gKq)8x0DpZ5&Py=d0EvOB3pe~#N^`JhS31`9C&;T03IdCpCg7cs;G=UUIg$NvY zNP~39fK14O^Wg$$3eBK7w1Ae-3R*)OXbTrYJJ7%5i5+bZ9iSsz43|JB=nP%pQn(B* zhpuo1bc612C0qqpLpJn)p3n=ff!=T}^nt$64-$|A{b2wMgh4PEhQLr52E$3H^I$t3)~8~!FZSex5GrZ1MY-LFd3%6RG0?S;Vzf~cf(A$ z2kwRY;C`3|vtbTA0CQm;%!dWA5FUg@uo#xWL+~&>0*}H{SO&{s1v~~TVHK=~HLw;Q zhbQ1kcnY3|XW&_Q4xWc~upVB37hwau1RG%!Y=)QN6?he1gV$jTY=v#G9o~R9VF&Dl zw_q3ShCQ$s-iCKzAMA&B;XTNQ_u&IL00-d^9EK0!BRB#d!zb`5dR%C2le4hI1A2(2G9`B zfpeh|oCl4e38X+OMBu!p1+;`#&>Gr6TeuL~!9~y>IzUIb z7%qWM&>6bGrEnQs4qf32=my>4O1KKHhHU5oJ)sv|1HIu|=mUMBA0!|L`ojPi2!miS z41u9A42Hu97zx(_uf#!lFbYP)7`PtB!Z^4AZiJiQX1E1zh1*~}On}>ABHRIY!X%gs zQ(!7ggXwS=%z(RLCfoz}!hLW*%!1i42OfaAFc0R#0$2zS!Xj7K-t3y;GS@FYA1Ps20tEIbF#!#Y?GFTjhi0bYWQun9K9%kT=k3a`QI zum!flHrNhtz?-lGcEVe*3wFaE*b8sNJFpM-!@KYv$0UUsXa0m{=hwu>`fsf%6 z_!K^a&*3P10bjx~I1XRI*YFK|3*W)_@B{n^KZypAUvx~Lp`&wB3%*7LUtPghU+^`p z;A?up*NlR%nFU|7@{653CnbDH4IiTL!G#Y#d`Jr)(!+<0@F6pN2q#D3<(vlIJ-k*E%;---Qn#HZ+B?0;rFvUG}-XX?$Bt%GrL2xEqJEghEH~fmK&bg z9olYqW_M`4;hEi`{T4jafWs%dLlX|q><*1MJhMAA7{+0G-|d1O0}Z0C`)@0IO5vYkh^^T>7{+0G-|d1O0}Z0C{fJkp!_1tencbncb$DiX=zSfY*&TXg7d*3_N4E1wFYWNNc86Zu;hEi`7k7AOcj(m}p4lC? z^GI*+f}gdWM|yvUXLg6);Nh9wp?7$AW_RcIS&V~li5YB;fp%I)1jiCvoKq^Gwz(X3OLk46*7Mu?kKvQT2 z&7lRfgjUcR+CW>l5Zb{-&>lKKN4OX+flkmFy1=Dy8C(us;R@&m-Qh~O3a*B1=m9;U z7hD6q;acbeeW4#DAP4%x02l~^U@#1Up)d@F!w47&*Fi4i!6+CFW8iui3*+DhxDjrG zo8cC?6>fv^Fad6diEszp36o$lOo6E|4W`3gFaz#}nQ#x>3-`hOFbihG9C!fc!aSG{ z3t%BU2#a7bEP;pMVR!@{g{80zmct5o3|7J_SPg4nEj$iSz?1M4JPpslv+x`|59?q( zyZ|r426zcJ!Y0@ZFT*SFD!c}-!xq>I+h9Aq0dK+%*a>gJF4zrwU@yE4@4!CT5AVWz zkPq*}2XFum!XY>eAHqj)1U`mO;8XYvK8K_51$+s|;5d8*U&A->Eqn*x!w>Ky`~*M4 zFYqh;2EW4}@F)BQe?u%T;!p^ZpfD7HqEHNy#i{>5tM5S?--vX`fK14O^Wg$$3eBK7 zw1Ae-3R*)OXbTrYJGcniLkH*x7sDmc2|7a;xD+mf%b_b=0o|ZGTnSgf)sPK6peOW# zYoIq=3w@w3^n(QCKz|qj17Q#hh9NK%hQV+c0VCl$$b~!@1*2gMTn}Sm9NYjm!cA~9 z+yb}4Z7?1t!0j**?tnXC5=@3EFcqf3bhry~M}VGXQ>$KeTh5}tym;Td=qo`dIM9ju2J z;6>N~FTqCG1e@Vycm-aC*Wh*70$X7lY=<}CP1pfD;Vsw&yI~LPg}31y*a!RJU3d@j z;eGf34!}V;1c%{6_y~@`$M6Y!3ZKE}a1_3PFX0#*hp*sk_y)d(@8Em*0e*y^;Ahb= zDL+0oKi;R{KeXnp&_6Kg@dh2BZfCgN$Wjy z#P9*VhYlK*liO!#UgMGD@{^km8<7}2G^cqn{koc0vPdjexJZeT72^NXAJvNg^B-BI zXyK%Pe)g~b_J2L^zwyT=7mEMmkL02yiWQ0%KK0|&ci_}_;Q#%1pmd3%|7rdI_$$G` J_PIpTe*j|O2WbER literal 0 HcmV?d00001 diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index cb540823e..047a380ef 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -376,11 +376,13 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None for i, inst in enumerate(self.insts): opname = inst.opname + argval = inst.argval + pattr = inst.argrepr t = Token( opname=opname, - attr=inst.argval, - pattr=inst.argrepr, + attr=argval, + pattr=pattr, offset=inst.offset, linestart=inst.starts_line, op=inst.opcode, @@ -431,8 +433,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None j = xdis.next_offset(op, self.opc, jump_offset) come_from_opname = self.opname_for_offset(j) - if opname.startswith("SETUP_"): - come_from_type = opname[len("SETUP_") :] + if come_from_opname.startswith("SETUP_"): + come_from_type = come_from_opname[len("SETUP_") :] come_from_name = "COME_FROM_%s" % come_from_type pass elif inst.offset in self.except_targets: @@ -465,8 +467,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None pass - pattr = inst.argrepr - if op in self.opc.CONST_OPS: const = argval if iscode(const): @@ -640,6 +640,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None last_op_was_break = opname == "BREAK_LOOP" t.kind = opname + t.attr = argval + t.pattr = pattr new_tokens.append(t) pass diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index b6a9b822f..30cb0fe07 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -227,7 +227,7 @@ def n_const_list(self, node): self.indent_more(INDENT_PER_LEVEL) sep = "" if is_dict: - keys = flat_elems[-1].pattr + keys = flat_elems[-1].attr assert isinstance(keys, tuple) assert len(keys) == len(flat_elems) - 1 for i, elem in enumerate(flat_elems[:-1]): From 3471d11dd5595af0737fc60dc27b94ae56c14293 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Apr 2022 02:45:31 -0400 Subject: [PATCH 299/489] Merge in literal speedups --- uncompyle6/parsers/parse3.py | 12 ++++++------ uncompyle6/scanners/scanner3.py | 12 +++++------- uncompyle6/scanners/scanner37.py | 9 ++------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 039a51dbc..54302ff35 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -816,18 +816,18 @@ def customize_grammar_rules(self, tokens, customize): elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): if opname == "BUILD_CONST_DICT": - rule = f""" + rule = """ add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts {opname} + const_list ::= COLLECTION_START add_consts %s dict ::= const_list expr ::= dict - """ + """ % opname else: - rule = f""" + rule = """ add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts {opname} + const_list ::= COLLECTION_START add_consts %s expr ::= const_list - """ + """ % opname self.addRule(rule, nop_func) elif opname_base in ( diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 30244a5dd..f58835edd 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -35,8 +35,6 @@ from __future__ import print_function -from typing import Optional, Tuple - from xdis import iscode, instruction_size, Instruction from xdis.bytecode import _get_const_info @@ -209,7 +207,7 @@ def __init__(self, version, show_asm=None, is_pypy=False): def bound_collection_from_inst( self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int, collection_type: str - ) -> Optional[list]: + ): count = t.attr assert isinstance(count, int) @@ -248,7 +246,7 @@ def bound_collection_from_inst( opname="COLLECTION_START", attr=collection_enum, pattr=collection_type, - offset=f"{start_offset}_0", + offset= "%s_0" % start_offset, linestart=False, has_arg=True, has_extended_arg=False, @@ -270,7 +268,7 @@ def bound_collection_from_inst( ) new_tokens.append( Token( - opname=f"BUILD_{collection_type}", + opname="BUILD_%s" % collection_type, attr=t.attr, pattr=t.pattr, offset=t.offset, @@ -283,7 +281,7 @@ def bound_collection_from_inst( return new_tokens def ingest(self, co, classname=None, code_objects={}, show_asm=None - ) -> Tuple[list, dict]: + ): """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing @@ -403,7 +401,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None else opname.split("_")[1] ) try_tokens = self.bound_collection_from_inst( - self.insts, new_tokens, inst, t, i, f"CONST_{collection_type}" + self.insts, new_tokens, inst, t, i, "CONST_%s" % collection_type ) if try_tokens is not None: new_tokens = try_tokens diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index bafc5c702..1ac26bb73 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,13 +22,8 @@ scanner routine for Python 3. """ -<<<<<<< HEAD -======= -from typing import Tuple - from uncompyle6.scanner import CONST_COLLECTIONS from uncompyle6.scanners.tok import Token ->>>>>>> long-collection-python3 from uncompyle6.scanners.scanner37base import Scanner37Base # bytecode verification, verify(), uses JUMP_OPs from here @@ -86,7 +81,7 @@ def bound_collection_from_tokens( opname="COLLECTION_START", attr=collection_enum, pattr=collection_type, - offset=f"{start_offset}_0", + offset="%s_0" % start_offset, linestart=False, has_arg=True, has_extended_arg=False, @@ -108,7 +103,7 @@ def bound_collection_from_tokens( ) new_tokens.append( Token( - opname=f"BUILD_{collection_type}", + opname="BUILD_%s" % collection_type, attr=t.attr, pattr=t.pattr, offset=t.offset, From a2780bc1c26757c24e1f3932521c41dcc2988b46 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Apr 2022 02:50:44 -0400 Subject: [PATCH 300/489] 2.4 tolerance --- uncompyle6/scanners/scanner3.py | 11 +++++------ uncompyle6/scanners/scanner37.py | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index d2ebf0b6e..d3c3b3975 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -209,7 +209,7 @@ def __init__(self, version, show_asm=None, is_pypy=False): return def bound_collection_from_inst( - self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int, collection_type: str + self, insts, next_tokens, inst, t, i, collection_type ): count = t.attr assert isinstance(count, int) @@ -401,11 +401,10 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None "BUILD_LIST", "BUILD_SET", ): - collection_type = ( - "DICT" - if opname.startswith("BUILD_CONST_KEY_MAP") - else opname.split("_")[1] - ) + if opname.startswith("BUILD_CONST_KEY_MAP"): + collection_type = "DICT" + else: + collection_type = opname.split("_")[1] try_tokens = self.bound_collection_from_inst( self.insts, new_tokens, inst, t, i, "CONST_%s" % collection_type ) diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 8830527f1..4edbc7686 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -41,8 +41,8 @@ def __init__(self, show_asm=None, is_pypy=False): pass def bound_collection_from_tokens( - self, tokens: list, next_tokens: list, t: Token, i: int, collection_type: str - ) -> list: + self, tokens, next_tokens, t, i, collection_type + ): count = t.attr assert isinstance(count, int) From c8b94cf48f8af5900e4c003a0677ac65a118b95e Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 27 Apr 2022 05:06:14 -0400 Subject: [PATCH 301/489] Small tewaks --- uncompyle6/main.py | 5 ----- uncompyle6/scanners/scanner3.py | 4 +--- uncompyle6/scanners/scanner37.py | 4 ++-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index d1dff348e..49174fa53 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -315,11 +315,6 @@ def main( else: buffering = 0 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) - if PYTHON_VERSION_TRIPLE >= (2, 7): - tee = subprocess.Popen(["tee", current_outfile], - stdin=subprocess.PIPE) - os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) - os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) else: if filename.endswith(".pyc"): current_outfile = os.path.join(out_base, filename[0:-1]) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index f051c79cf..37808465e 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -212,7 +212,7 @@ def bound_collection_from_inst( self, insts, next_tokens, inst, t, i, collection_type ): """ - Try to a sequence of instruction that ends with a BUILD_xxx into a sequence that can + Try to a replace sequence of instruction that ends with a BUILD_xxx with a sequence that can be parsed much faster, but inserting the token boundary at the beginning of the sequence. """ count = t.attr @@ -376,8 +376,6 @@ def bound_map_from_inst( ) return new_tokens - - def ingest(self, co, classname=None, code_objects={}, show_asm=None ): """ diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 35491e505..925215f56 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -74,8 +74,8 @@ def bound_collection_from_tokens( collection_enum = CONST_COLLECTIONS.index(collection_type) - # If we go there all instructions before tokens[i] are LOAD_CONST and we can replace - # add a boundary marker and change LOAD_CONST to something else + # If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace + # add a boundary marker and change LOAD_CONST to something else. new_tokens = next_tokens[:-count] start_offset = tokens[collection_start].offset new_tokens.append( From 5220aa3b65217efea1131e6b9fd73c34571e30f0 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 27 Apr 2022 05:15:33 -0400 Subject: [PATCH 302/489] WIP - deal with BUILD_LIST --- uncompyle6/scanners/scanner2.py | 109 +++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 0a962b205..e2fcfebf0 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -134,6 +134,96 @@ def __init__(self, version, show_asm=None, is_pypy=False): ] ) + def bound_collection_from_tokens( + self, tokens, t, i, c, collection_type): + """ + Try to a replace sequence of instruction that ends with a BUILD_LIST with a sequence that can + be parsed much faster, but inserting the token boundary at the beginning of the sequence. + """ + count = t.attr + assert isinstance(count, int) + if count > i: + return None + + # For small lists don't bother + if count < 5: + return None + + collection_start = i - (count * 2) + assert (count * 2) <= i + + for j in range(collection_start, i, 2): + try: + tokens[j] + except: + from trepan.api import debug; debug() + if tokens[j].opname not in ( + "LOAD_CONST", + ): + return None + if tokens[j+1].opname not in ( + "LOAD_CONST", + ): + return None + + collection_start = i - (2 * count) + collection_enum = CONST_COLLECTIONS.index("CONST_MAP") + + # If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace + # add a boundary marker and change LOAD_CONST to something else + new_tokens = tokens[:-(2*count)] + start_offset = tokens[collection_start].offset + new_tokens.append( + Token( + opname="COLLECTION_START", + attr=collection_enum, + pattr="CONST_MAP", + offset="%s_0" % start_offset, + linestart=False, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + ) + ) + for j in range(collection_start, i, 2): + new_tokens.append( + Token( + opname="ADD_KEY", + attr=tokens[j].argval, + pattr=tokens[j].argrepr, + offset=tokens[j].offset, + linestart=tokens[j].starts_line, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + ) + ) + new_tokens.append( + Token( + opname="ADD_VALUE", + attr=tokens[j+1].argval, + pattr=tokens[j+1].argrepr, + offset=tokens[j+1].offset, + linestart=tokens[j+1].starts_line, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + ) + ) + new_tokens.append( + Token( + opname=collection_type, + attr=t.attr, + pattr=t.pattr, + offset=t.offset, + linestart=t.linestart, + has_arg=t.has_arg, + has_extended_arg=False, + opc=t.opc, + ) + ) + return new_tokens + @staticmethod def extended_arg_val(arg): """Return integer value of an EXTENDED_ARG operand. @@ -209,7 +299,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): print(instr.disassemble()) # list of tokens/instructions - tokens = [] + new_tokens = [] # "customize" is in the process of going away here customize = {} @@ -286,7 +376,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if come_from_type not in ("LOOP", "EXCEPT"): come_from_name = "COME_FROM_%s" % come_from_type pass - tokens.append( + new_tokens.append( Token( come_from_name, jump_offset, @@ -310,6 +400,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if op == self.opc.EXTENDED_ARG: extended_arg += self.extended_arg_val(oparg) continue + ### + # Start here: look for BUILD_LIST + ### if op in self.opc.CONST_OPS: const = co.co_consts[oparg] if iscode(const): @@ -344,12 +437,12 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): elif op in self.opc.JREL_OPS: # use instead: hasattr(self, 'patch_continue'): ? if self.version[:2] == (2, 7): - self.patch_continue(tokens, offset, op) + self.patch_continue(new_tokens, offset, op) pattr = repr(offset + 3 + oparg) elif op in self.opc.JABS_OPS: # use instead: hasattr(self, 'patch_continue'): ? if self.version[:2] == (2, 7): - self.patch_continue(tokens, offset, op) + self.patch_continue(new_tokens, offset, op) pattr = repr(oparg) elif op in self.opc.LOCAL_OPS: pattr = varnames[oparg] @@ -430,13 +523,13 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): linestart = self.linestarts.get(offset, None) if offset not in replace: - tokens.append( + new_tokens.append( Token( op_name, oparg, pattr, offset, linestart, op, has_arg, self.opc ) ) else: - tokens.append( + new_tokens.append( Token( replace[offset], oparg, @@ -452,10 +545,10 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): pass if show_asm in ("both", "after"): - for t in tokens: + for t in new_tokens: print(t.format(line_prefix="")) print() - return tokens, customize + return new_tokens, customize def build_statement_indices(self): code = self.code From fa62724f14e1cfada3ea60926f226011ea5e7a78 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 27 Apr 2022 09:23:38 -0400 Subject: [PATCH 303/489] Handle BUILD_{LIST,SET} more efficiently --- test/bytecode_2.7_run/05_long_literals.pyc | Bin 0 -> 20487 bytes uncompyle6/parsers/parse2.py | 8 ++ uncompyle6/parsers/parse3.py | 35 ++++--- uncompyle6/scanner.py | 10 +- uncompyle6/scanners/scanner2.py | 112 ++++----------------- uncompyle6/scanners/scanner26.py | 26 ++++- uncompyle6/scanners/scanner37.py | 87 +--------------- 7 files changed, 79 insertions(+), 199 deletions(-) create mode 100644 test/bytecode_2.7_run/05_long_literals.pyc diff --git a/test/bytecode_2.7_run/05_long_literals.pyc b/test/bytecode_2.7_run/05_long_literals.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2e2a5bd7aeb19c7725e9591e22c763877bc8709 GIT binary patch literal 20487 zcmeI3b(B7rHTQB4xn`e-G-TfXM+IhpWT z8F^OC^ff=W{&TCBM3r^cym-wD`#S%4!3_^KyaOBFfq&;aFsDzM6#pOHZ0S~aeBDQZ z(~p9pTffdVL)QG*zw=l9zyD{=ovxpU`UyFA^+)Jpzvg|bs~@3D{XafJr`L-rH~hWf z9oX;={I9+P_5-k0{eS)eSgId<01jRIWB;qa{Du#Z4e!8)cVO=7J*pUbGy~*d)U1{kZ0ycFt z258}E9MICy1fZ3pNx)`~rU0!SO$FLGng+CWv^B7~qiun9jFu>6qsC4uZu$!Y#fH{sn1LivV0$@j90rMPv1I%~y9Z==y z2VjAtpMZsqegPIa`VCm@=nr6bM}Gm;j-s-ZY8;gVwT>LH#8Dk!siS(p9*!CS%N#WV zmOE+!?CEGDV1=V*z+R4;1A9Aa0qopnt%b=pS$v`Ujki{sHHpf55ru zA8;P}2b_=o0T(zT;6n5dxCs3NE=K==OVB^yQuGhF4E+NxNB@8;&_Ccx^bfcS{R6H> z|A1@IKj2#Q54aBf1FlE^fE&<1;70ThxC#9OZbturThKq?R`d_J4gCXdNB@93&_Cc# z^bfcT{R8es|A2eYKj2>U54aEg1MWxvfCtb&;6d~ccnJLi9!CFwN6NB@8?&_Ccy^bhz7{R6&6|A24MKj2&R5BLuKD^KZr^bhy} z{R4hP|A3#+Kj3Hd5BLTB1AaySfZxzR;CJ*7_yhd|{zU(PztBJ6Z}bm{JhcVNJhcPL zJ#_#wo;m@}Qy0K{>IT&D)B~vNsTWYsQy-wdr+z>KPZdBzPchKQQx0hCDFvE%DgsSC z4FERsGzi$((-5GUr(wV*o<;!8J&gi3^)v=(;b|Pu($fT>m8VI-W}c=1tvyWz+IX4< zwDq(#u(_vgfp(s@2ikj@4s`Ie6VTDqE=r5nhkXIR0(wRGzaMJiGd!T z<^w%FEdY9XS_Jg=v^&tpQw`A9(-NScr#*oFo|Xd@o>l-^PkRHgr+tCM)BZrt(<&hE z=|CX$bTClxbSO~tbU0A*bR;mq)6u{{Psaj-JRJ`V_H-gJ#M8;ZP*0}z(`N$0;4>g4~+J7Auz_%#lTokmjdHFT@H-*bR{ss)78L4PuBvIJY5e=_H-jK z#na8e7M^Yerh2*^*wWLTz%);H16z5z7ued<{lGS!9t5`a^f0iUr$>S9Jv|QW;OR+V zx~Hds9X&k@?BwZrU}sM+0=sy68JOYeRbW?7uLCnZy$Q_n^foZt)4Kq9dLO9t^dYdD zr;mX-o<0TUdioq-PhSG_Jbew!_w+4L<>`B1fu|pVg`R!}7J2#=SnTO{V0TY{0@a@W z25LN&Ww8Ev$^c6|d0?rhy1*Wu>I2I>H3XJ>Y7Fe@sVT6+)5gGFo;CsY_OvOmkEfQv zzMeJ%_Vd&R*x%FUz)DZ;fmNP50ta~N3>@gGD{zpf?!dvGdIE=d>J1#~sV{Jtr~bg< zp0dCZo)X|lPkG=dPX*v;PbJ_OPXmEtJq-qq^E4DV-qUd41WzM@6FrRvPVzJsIN8&9 z;1o|2fm1zA22S&|1#r5jErByUZ3Ud^X&c}yPul@!d)fgw$J36$xt?|g&hs<_I3N83 zEZq82tk-LH~eD(Ldla^bfck{R6H*|9~seKj13#54alr1Fk{;fNRk| z;5zgVxE}ojZb1Kl8__@DCiD-u8T|upLH~eT(Ldle^bfcl{R8em|A0HuKj1F(54aos z1MWfpfP2wD;6C&ZxF7uk9zg$q2hl&^A@mP;82tktLH~e9(LdlZ^bdF({R5sr|9~ga zKj10!4|p2=1D-+ufM?M^;5qaUcpm)&UO@kV7tuf9CG-z?8T|uZLH~eP(Ldld^bdF) z{R7@W|A05qKj1C&4|p5>1KvUZfOpY9;63yYcpv=(K0yC~579s1BlHjW82tl2LH~eH z(Ldlb^bhzP{R6&0|9~&izf3y4pR>z8Dc(>d=R2QHDPJa0>uKqYQnmA|3iLkhaEG7)WL4Ya8j%hq<&JzG@%o(1-C< zhCYm^oq*1f4t-rC9s0UQI`s97bm;3H>Co3V(xI<^q(fge(xESjbm+@RI`kDH9r{X< z4t)b79r^}GI`j>Vbm$u%>CiVa(xGp3q(k4>NQb`hkq&(mBN_Vs%XbL>?33k0e9b#_ zRNK|>5dDjzJ*CyNH0_E0oxu(P7>P2&^XD;Y~hc%T|yY-ztw{rG;UO1;C<0m4< zwakb!5^`CyR=%9YSo{OPKxfF^54+uq(2Zo}=g94FO@ZeBnc}OT? z9vX^-hlL`?!$Xnh5ur$VWGD(eDilQ?9f}f<2}GfS$A%)y<3bVh_)sJ~Arv{D7>Ybk z3PsA3Ls8%-3q^sq4@Hr8 z2t|o;Tg!UgFIDi4p~&)1p@@0sP$axdC~`a_6nWk?6e-UPMS*99qR6vDQDWSK6V=Lk zu;%l=f-8;5@@~e&Jja-X=Ngk^StHkf8t*WO=bM zG4F0n!qvv)xWjLGrd#^iY) zV^ZGNm;&!-Op*6Dro<~lgC%U0Feooh^%&od_G^NmUP0%LM~p)q;B z$e5HbHm1Or7*pg+jVbYEp}|sjxiMM3!kCz^G$!GzjLGrU#^m`LV^Y4>m;zsCOp&iQ zro=ad28-T}#$@>>V`9G9n1pXJCdaoLljqxvN%?kT3Veq#MZVLR65kaXEPr(<|Bl{I)R(zhg{}-!&%B?-`Tw`^FUb17nK(p)n=?C^T3HKQ<=I zpBNMKr^Y1wnK3#3+?YInVNA+j8dKn}j4ATh#+3M*&|n?>)|f1RXH3lB8kevyU<`A^u}bljxjOUH74PD#^kuZF?nuaOv(+7DR3iWirmBo`HpV2})|eb` zZcLur8Iy8*V+!2Cm?C#Hro^2>gLSa8F6E z_co@qZeUBW1ojQSom6DGpD{7_Hzwf&XHKxGhj4ASXV@f70?n1rVoljALn$@5fWQr^;-0#7rh$Xgjx z;;lo2C2$*Kvb?P^F>hx~!rL2@;~k92Gj7pa@314urM#mt1>VV+BJXTWiFXMNmcSXt zWO-L(VxDPC!n2IY@oZ!AjQ^+A`oA-lz)E8Zyqhsao?}dj=Y|GLpj;VQ?~^3W@;qZ= zo^MRTRmS9afiZbrXiUnBj4AM9V~V`HF(s}J4VJ(fW3nvQZ`S*#D8#(Pn1q)aljA*% z$@4N}QeJLMf%i0~$SaH~@m`_961cZ9S>DH(nD;d%;r)!s@&3l-d8IKauQH~<2N+Z2 z1C1&1L7~ACc(5^9KE#-q4>cy?!;H!C;l||o2xC${(wG7tWlWKeHm1bK1SW@d@K|HA ze4H^cA8$;;Cm56C6OGC9NyemnvM~id#h4&^Lm@HpoOw89Blkj!Mp%-)l^X?+Xpq!TXKL@&m@i{Gc%jKV(df zA2ue>j~J8kqsA2YF=LASxG^PuA~aYBpEM@RPZ<;Q)5awHj4?TW)|fm$XH3e^8&lvH zj4ASq#+3M_&|n>W*_bT9Voc1h8k6vA#^m^QWAgllF)6=kOo87rrpRv_Q{s0*gLUv- zW3v37F)_byOu`=+lj9GK$@53Xr2Mfl1^&dCB7bU3i9ZVs*1^w>$?_M*#Qdc(34diw zj=wf0&)*o6^0&qm_&Z~Y{Jk+H{vj}Vtb;!qljWa`iKq0ahqIPx_-`}~-;1V|OJpRR zgqNrzQ5VrezRU7+tM8+cpVOOO^hOrFbw+QR(K}Z3o*BJCMQ@qWn`QJi6utFCZ#U6f zO!T%Ay_H07AJJPz^fnQ_HAHU*(OW?Dwhz74LvQcUTRQYM4!w0lZ`a@s@(Xp8=p@lu zqKiaViEa|zC3;Bol;|bVTcVFdUx|Ja{Us_SvJ$aGB9W8GOQaG7iK0YFVt~Xzi9r&B zC5A{0l^7;5Tw;X8NQqGrqb0^jjFlKCF#3G5s61z)OOVmizN-U9BDzS&eGKu99drGX3*h^w>iG3vYmDo>We~Fb6 zt0WGPI8fpsiGw8$kvLT1Fp0w@j*vJ~;wXuuC619eR^m8`<0VdzI8ovxiIXKxkvLW2 zG>OwC&X71$;w*`?CC-sJSK>U0^Cd2jxKQFEiHjvJk+@XiGKtG2u8_D=;wp)&C9aXU zR^mE|>m_cGxKZLJiJK*Ek+@ajHi_FM?vS`s;x381CGL^9SK>a2`z0Qbcu?XYiH9W~ zk$6<%F^R_|o{)G_;wg!zC7zLZR^mB{=Otc{cv0ddiI*i_k$6?&HHp_H-jH}x;w_1{ zCEk&ESK>X1_a#1%_)y{_iH{{dk@!^NGl|b7zL5A*;wy=-CBBjPR^mH}?N>CF)7kmuMi-P@<7UV~Hjb zO(iyx*jS>O#3mBWB{r34A<w3XOgqMby0i4GDSB|1rTmgpkURic|j zcZnVnJtcZc^p@x&(O06MM1P42iL68{kx1ku@)D^;L82&8k{BQ{P-2k8V2L3TLnVeu z43`)oF;Zfb#At~z5@RLCNsO16ATd#5lEh?*DH2;qOqJMDLRK$5RMK-KJv!3UB0V6| zGa)?&(vu%O?9uZbJ<`!r96h+vvl=~~(GwXxgwb;sJ!;X@6+KYVGZZ~G(UTHA9MSU- zJp$2F4?XD6vkg7Y&=U+jw9s=3J(|$d2t9z%GY36p(31r{OwjWKJu=W!0zDYevj83c zb>i0{U*~!q<#l@3fn8^G9m{nR*Wp{|Z5^?7s@6eTXJ;LkbwbvmSm$6JeRbN^0as^Q z9bK_(BVPn1sxG|D$qed_x`%w*B!oY>UAHlTX)^9>jqu-X|)-QDVjR`;;FZPlHsZccSSs#{Rqb?Qb__m;Yy)E%U5 z8g-wjTSMIq^3PJ7Ul2VS;}cHrfSoae7R{b9qZTq+R+~XqRW7V;ARmA=ys)Nr=EB*P zwN5nG)Ydk^gW)wbmDRPpXyNGU>P6N1l$ljk%9_ereW97SZ5yw@WO3E%=gzNOUbF5_ z<{JHO^~{BHDtq9^qIFTz2Vd6k0z7X<&7vjMvn%^oE?Zn(SyO{Qu75>-M%AK)b7oX= zZDsY$s+xX_m+KkepaqL)Nmb>La(Qwe{K<8EowDw(sc%)*u}-_P|LI>{GR?}md;9Dz znJ$?+8EgOhU;p!0{a2pf#bwIs27fikw97OvZ}*>k_){Cc+VBo+cnAK!yaNp~**clB OhQa5+zy8nGAoCx6cu&g! literal 0 HcmV?d00001 diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index adffd0233..989646fc0 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -310,6 +310,14 @@ def customize_grammar_rules(self, tokens, customize): opname_base = opname[: opname.rfind("_")] + if opname in ("BUILD_CONST_LIST", "BUILD_CONST_SET"): + rule = """ + add_consts ::= ADD_VALUE* + const_list ::= COLLECTION_START add_consts %s + expr ::= const_list + """ % opname + self.addRule(rule, nop_func) + # The order of opname listed is roughly sorted below if opname_base in ("BUILD_LIST", "BUILD_SET", "BUILD_TUPLE"): # We do this complicated test to speed up parsing of diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 00ef60c85..027941962 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -750,18 +750,37 @@ def customize_grammar_rules(self, tokens, customize): kvlist_n = "expr " * (token.attr) rule = "dict ::= %sLOAD_CONST %s" % (kvlist_n, opname) self.addRule(rule, nop_func) + + elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): + if opname == "BUILD_CONST_DICT": + rule = """ + add_consts ::= ADD_VALUE* + const_list ::= COLLECTION_START add_consts %s + dict ::= const_list + expr ::= dict + """ % opname + else: + rule = """ + add_consts ::= ADD_VALUE* + const_list ::= COLLECTION_START add_consts %s + expr ::= const_list + """ % opname + self.addRule(rule, nop_func) + elif opname.startswith("BUILD_DICT_OLDER"): rule = """dict ::= COLLECTION_START key_value_pairs BUILD_DICT_OLDER key_value_pairs ::= key_value_pair+ key_value_pair ::= ADD_KEY ADD_VALUE """ self.addRule(rule, nop_func) + elif opname.startswith("BUILD_LIST_UNPACK"): v = token.attr rule = "build_list_unpack ::= %s%s" % ("expr " * v, opname) self.addRule(rule, nop_func) rule = "expr ::= build_list_unpack" self.addRule(rule, nop_func) + elif opname_base in ("BUILD_MAP", "BUILD_MAP_UNPACK"): kvlist_n = "kvlist_%s" % token.attr if opname == "BUILD_MAP_n": @@ -822,22 +841,6 @@ def customize_grammar_rules(self, tokens, customize): rule = "starred ::= %s %s" % ("expr " * v, opname) self.addRule(rule, nop_func) - elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): - if opname == "BUILD_CONST_DICT": - rule = """ - add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts %s - dict ::= const_list - expr ::= dict - """ % opname - else: - rule = """ - add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts %s - expr ::= const_list - """ % opname - self.addRule(rule, nop_func) - elif opname_base in ( "BUILD_LIST", "BUILD_SET", diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index fb6f05685..f98397124 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -128,8 +128,8 @@ def __init__(self, version, show_asm=None, is_pypy=False): # FIXME: This weird Python2 behavior is not Python3 self.resetTokenClass() - def bound_collection( - self, tokens, next_tokens, t, i, collection_type + def bound_collection_from_tokens( + self, tokens, t, i, collection_type ): count = t.attr assert isinstance(count, int) @@ -145,7 +145,7 @@ def bound_collection( # For small lists don't bother if count < 5: - return next_tokens + [t] + return None collection_start = i - count @@ -156,13 +156,13 @@ def bound_collection( "LOAD_GLOBAL", "LOAD_NAME", ): - return next_tokens + [t] + return None collection_enum = CONST_COLLECTIONS.index(collection_type) # If we go there all instructions before tokens[i] are LOAD_CONST and we can replace # add a boundary marker and change LOAD_CONST to something else - new_tokens = next_tokens[:-count] + new_tokens = tokens[:-count] start_offset = tokens[collection_start].offset new_tokens.append( Token( diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index e2fcfebf0..441fc5c3c 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -134,96 +134,6 @@ def __init__(self, version, show_asm=None, is_pypy=False): ] ) - def bound_collection_from_tokens( - self, tokens, t, i, c, collection_type): - """ - Try to a replace sequence of instruction that ends with a BUILD_LIST with a sequence that can - be parsed much faster, but inserting the token boundary at the beginning of the sequence. - """ - count = t.attr - assert isinstance(count, int) - if count > i: - return None - - # For small lists don't bother - if count < 5: - return None - - collection_start = i - (count * 2) - assert (count * 2) <= i - - for j in range(collection_start, i, 2): - try: - tokens[j] - except: - from trepan.api import debug; debug() - if tokens[j].opname not in ( - "LOAD_CONST", - ): - return None - if tokens[j+1].opname not in ( - "LOAD_CONST", - ): - return None - - collection_start = i - (2 * count) - collection_enum = CONST_COLLECTIONS.index("CONST_MAP") - - # If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace - # add a boundary marker and change LOAD_CONST to something else - new_tokens = tokens[:-(2*count)] - start_offset = tokens[collection_start].offset - new_tokens.append( - Token( - opname="COLLECTION_START", - attr=collection_enum, - pattr="CONST_MAP", - offset="%s_0" % start_offset, - linestart=False, - has_arg=True, - has_extended_arg=False, - opc=self.opc, - ) - ) - for j in range(collection_start, i, 2): - new_tokens.append( - Token( - opname="ADD_KEY", - attr=tokens[j].argval, - pattr=tokens[j].argrepr, - offset=tokens[j].offset, - linestart=tokens[j].starts_line, - has_arg=True, - has_extended_arg=False, - opc=self.opc, - ) - ) - new_tokens.append( - Token( - opname="ADD_VALUE", - attr=tokens[j+1].argval, - pattr=tokens[j+1].argrepr, - offset=tokens[j+1].offset, - linestart=tokens[j+1].starts_line, - has_arg=True, - has_extended_arg=False, - opc=self.opc, - ) - ) - new_tokens.append( - Token( - opname=collection_type, - attr=t.attr, - pattr=t.pattr, - offset=t.offset, - linestart=t.linestart, - has_arg=t.has_arg, - has_extended_arg=False, - opc=t.opc, - ) - ) - return new_tokens - @staticmethod def extended_arg_val(arg): """Return integer value of an EXTENDED_ARG operand. @@ -287,7 +197,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST cause specific rules for the specific number of arguments they take. """ - if not show_asm: show_asm = self.show_asm @@ -400,9 +309,24 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if op == self.opc.EXTENDED_ARG: extended_arg += self.extended_arg_val(oparg) continue - ### - # Start here: look for BUILD_LIST - ### + + # Note: name used to match on rather than op since + # BUILD_SET isn't in earlier Pythons. + if op_name in ( + "BUILD_LIST", + "BUILD_SET", + ): + t = Token( + op_name, oparg, pattr, offset, self.linestarts.get(offset, None), op, has_arg, self.opc + ) + collection_type = op_name.split("_")[1] + next_tokens = self.bound_collection_from_tokens( + new_tokens, t, len(new_tokens), "CONST_%s" % collection_type + ) + if next_tokens is not None: + new_tokens = next_tokens + continue + if op in self.opc.CONST_OPS: const = co.co_consts[oparg] if iscode(const): diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 79123edc9..2cd873e3b 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -121,7 +121,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): i = self.next_stmt[i] extended_arg = 0 + i = -1 for offset in self.op_range(0, codelen): + i += 1 op = self.code[offset] op_name = self.opname[op] oparg = None; pattr = None @@ -154,8 +156,28 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): oparg = self.get_argument(offset) + extended_arg extended_arg = 0 if op == self.opc.EXTENDED_ARG: - extended_arg = oparg * L65536 - continue + extended_arg += self.extended_arg_val(oparg) + continue + + + # Note: name used to match on rather than op since + # BUILD_SET isn't in earlier Pythons. + if op_name in ( + "BUILD_LIST", + "BUILD_SET", + ): + t = Token( + op_name, oparg, pattr, offset, self.linestarts.get(offset, None), op, has_arg, self.opc + ) + + collection_type = op_name.split("_")[1] + next_tokens = self.bound_collection_from_tokens( + tokens, t, i, "CONST_%s" % collection_type + ) + if next_tokens is not None: + tokens = next_tokens + continue + if op in self.opc.CONST_OPS: const = co.co_consts[oparg] # We can't use inspect.iscode() because we may be diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 925215f56..42bb70525 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,8 +22,6 @@ scanner routine for Python 3. """ -from uncompyle6.scanner import CONST_COLLECTIONS -from uncompyle6.scanners.tok import Token from uncompyle6.scanners.scanner37base import Scanner37Base # bytecode verification, verify(), uses JUMP_OPs from here @@ -40,83 +38,6 @@ def __init__(self, show_asm=None, is_pypy=False): pass - def bound_collection_from_tokens( - self, tokens, next_tokens, t, i, collection_type - ): - count = t.attr - assert isinstance(count, int) - - assert count <= i - - if collection_type == "CONST_DICT": - # constant dictonaries work via BUILD_CONST_KEY_MAP and - # handle the values() like sets and lists. - # However the keys() are an LOAD_CONST of the keys. - # adjust offset to account for this - count += 1 - - # For small lists don't bother - if count < 5: - return next_tokens + [t] - - collection_start = i - count - - for j in range(collection_start, i): - if tokens[j].kind not in ( - "LOAD_CODE", - "LOAD_CONST", - "LOAD_FAST", - "LOAD_GLOBAL", - "LOAD_NAME", - "LOAD_STR", - ): - return next_tokens + [t] - - collection_enum = CONST_COLLECTIONS.index(collection_type) - - # If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace - # add a boundary marker and change LOAD_CONST to something else. - new_tokens = next_tokens[:-count] - start_offset = tokens[collection_start].offset - new_tokens.append( - Token( - opname="COLLECTION_START", - attr=collection_enum, - pattr=collection_type, - offset="%s_0" % start_offset, - linestart=False, - has_arg=True, - has_extended_arg=False, - opc=self.opc, - ) - ) - for j in range(collection_start, i): - new_tokens.append( - Token( - opname="ADD_VALUE", - attr=tokens[j].attr, - pattr=tokens[j].pattr, - offset=tokens[j].offset, - linestart=tokens[j].linestart, - has_arg=True, - has_extended_arg=False, - opc=self.opc, - ) - ) - new_tokens.append( - Token( - opname="BUILD_%s" % collection_type, - attr=t.attr, - pattr=t.pattr, - offset=t.offset, - linestart=t.linestart, - has_arg=t.has_arg, - has_extended_arg=False, - opc=t.opc, - ) - ) - return new_tokens - def ingest( self, co, classname=None, code_objects={}, show_asm=None ): @@ -151,10 +72,12 @@ def ingest( collection_type = "DICT" else: collection_type = t.kind.split("_")[1] - new_tokens = self.bound_collection( - tokens, new_tokens, t, i, "CONST_%s" % collection_type + next_tokens = self.bound_collection_from_tokens( + new_tokens, t, i, "CONST_%s" % collection_type ) - continue + if next_tokens is not None: + new_tokens = next_tokens + continue # The lowest bit of flags indicates whether the # var-keyword argument is placed at the top of the stack From b8856993d2ba661b1565d96f419c785750324aaf Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 09:40:53 -0400 Subject: [PATCH 304/489] merge from master --- uncompyle6/parsers/parse14.py | 2 +- uncompyle6/scanner.py | 10 ++--- uncompyle6/scanners/scanner2.py | 13 ++++++ uncompyle6/scanners/scanner26.py | 68 ++++++++++++++++++-------------- uncompyle6/scanners/scanner37.py | 2 +- uncompyle6/scanners/scanner38.py | 13 +++--- 6 files changed, 65 insertions(+), 43 deletions(-) diff --git a/uncompyle6/parsers/parse14.py b/uncompyle6/parsers/parse14.py index 2064e6095..b74e280d1 100644 --- a/uncompyle6/parsers/parse14.py +++ b/uncompyle6/parsers/parse14.py @@ -64,7 +64,7 @@ def customize_grammar_rules(self, tokens, customize): if opname_base == "UNPACK_VARARG": if token.attr > 1: - self.addRule(f"star_args ::= RESERVE_FAST {opname} args_store", nop_func) + self.addRule("star_args ::= RESERVE_FAST %s args_store" % opname, nop_func) def reduce_is_invalid(self, rule, ast, tokens, first, last): diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 524e30fe8..cf6693f7a 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -127,8 +127,8 @@ def __init__(self, version, show_asm=None, is_pypy=False): # FIXME: This weird Python2 behavior is not Python3 self.resetTokenClass() - def bound_collection( - self, tokens: list, next_tokens: list, t: Token, i: int, collection_type: str + def bound_collection_from_tokens( + self, tokens, t, i, collection_type ): count = t.attr assert isinstance(count, int) @@ -144,7 +144,7 @@ def bound_collection( # For small lists don't bother if count < 5: - return next_tokens + [t] + return None collection_start = i - count @@ -155,13 +155,13 @@ def bound_collection( "LOAD_GLOBAL", "LOAD_NAME", ): - return next_tokens + [t] + return None collection_enum = CONST_COLLECTIONS.index(collection_type) # If we go there all instructions before tokens[i] are LOAD_CONST and we can replace # add a boundary marker and change LOAD_CONST to something else - new_tokens = next_tokens[:-count] + new_tokens = tokens[:-count] start_offset = tokens[collection_start].offset new_tokens.append( Token( diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index db213bab1..fb9e0b845 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -200,6 +200,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST cause specific rules for the specific number of arguments they take. """ + if not show_asm: show_asm = self.show_asm @@ -1441,3 +1442,15 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): instr_offsets = filtered filtered = [] return instr_offsets + + +if __name__ == "__main__": + import inspect + from xdis.version_info import PYTHON_VERSION_TRIPLE + + co = inspect.currentframe().f_code + + tokens, customize = Scanner2(PYTHON_VERSION_TRIPLE).ingest(co) + for t in tokens: + print(t) + pass diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index a1067fbd3..f0d46f900 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -26,6 +26,7 @@ import uncompyle6.scanners.scanner2 as scan # bytecode verification, verify(), uses JUMP_OPs from here +from xdis import iscode from xdis.opcodes import opcode_26 from xdis.bytecode import _get_const_info @@ -72,7 +73,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): bytecode = self.build_instructions(co) # show_asm = 'after' - if show_asm in ('both', 'before'): + if show_asm in ("both", "before"): for instr in bytecode.get_instructions(co): print(instr.disassemble()) @@ -81,7 +82,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): customize = {} if self.is_pypy: - customize['PyPy'] = 1 + customize["PyPy"] = 0 codelen = len(self.code) @@ -93,6 +94,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() for i in self.op_range(0, codelen): + # We need to detect the difference between: # raise AssertionError # and @@ -115,9 +117,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # Distinguish "print ..." from "print ...," if self.code[last_stmt] == self.opc.PRINT_ITEM: if self.code[i] == self.opc.PRINT_ITEM: - replace[i] = 'PRINT_ITEM_CONT' + replace[i] = "PRINT_ITEM_CONT" elif self.code[i] == self.opc.PRINT_NEWLINE: - replace[i] = 'PRINT_NEWLINE_CONT' + replace[i] = "PRINT_NEWLINE_CONT" last_stmt = i i = self.next_stmt[i] @@ -181,29 +183,25 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): 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 - # one that this was byte-compiled on. So the code - # types may mismatch. - if hasattr(const, 'co_name'): + if iscode(const): oparg = const - if const.co_name == '': - assert op_name == 'LOAD_CONST' - op_name = 'LOAD_LAMBDA' + if const.co_name == "": + assert op_name == "LOAD_CONST" + op_name = "LOAD_LAMBDA" elif const.co_name == self.genexpr_name: - op_name = 'LOAD_GENEXPR' - elif const.co_name == '': - op_name = 'LOAD_DICTCOMP' - elif const.co_name == '': - op_name = 'LOAD_SETCOMP' + op_name = "LOAD_GENEXPR" + elif const.co_name == "": + op_name = "LOAD_DICTCOMP" + elif const.co_name == "": + op_name = "LOAD_SETCOMP" else: op_name = "LOAD_CODE" - # verify uses 'pattr' for comparison, since 'attr' + # verify() uses 'pattr' for comparison, since 'attr' # now holds Code(const) and thus can not be used # for comparison (todo: think about changing this) - # pattr = 'code_object @ 0x%x %s->%s' % \ + # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) - pattr = '' + pattr = "" else: if oparg < len(co.co_consts): argval, _ = _get_const_info(oparg, co.co_consts) @@ -235,6 +233,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): pattr = self.opc.cmp_op[oparg] elif op in self.opc.FREE_OPS: pattr = free[oparg] + if op in self.varargs_ops: # CE - Hack for >= 2.5 # Now all values loaded via LOAD_CLOSURE are packed into @@ -285,25 +284,36 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): elif op == self.opc.LOAD_GLOBAL: if offset in self.load_asserts: - op_name = 'LOAD_ASSERT' + op_name = "LOAD_ASSERT" elif op == self.opc.RETURN_VALUE: if offset in self.return_end_ifs: - op_name = 'RETURN_END_IF' + op_name = "RETURN_END_IF" linestart = self.linestarts.get(offset, None) if offset not in replace: - tokens.append(Token( - op_name, oparg, pattr, offset, linestart, op, - has_arg, self.opc)) + tokens.append( + Token( + op_name, oparg, pattr, offset, linestart, op, has_arg, self.opc + ) + ) else: - tokens.append(Token( - replace[offset], oparg, pattr, offset, linestart, op, - has_arg, self.opc)) + tokens.append( + Token( + replace[offset], + oparg, + pattr, + offset, + linestart, + op, + has_arg, + self.opc, + ) + ) pass pass - if show_asm in ('both', 'after'): + if show_asm in ("both", "after"): for t in tokens: print(t.format(line_prefix="")) print() diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index d081fc074..5e1270d81 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -156,7 +156,7 @@ def ingest( if t.kind.startswith("BUILD_CONST_KEY_MAP") else t.kind.split("_")[1] ) - new_tokens = self.bound_collection( + new_tokens = self.bound_collection_from_tokens( tokens, new_tokens, t, i, "CONST_%s" % collection_type ) continue diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index 765daf2b4..492a86831 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -22,8 +22,6 @@ scanner routine for Python 3.7 and up. """ -from typing import Dict, Tuple - from uncompyle6.scanners.tok import off2int from uncompyle6.scanners.scanner37 import Scanner37 from uncompyle6.scanners.scanner37base import Scanner37Base @@ -45,7 +43,7 @@ def __init__(self, show_asm=None, debug="", is_pypy=False): def ingest( self, co, classname=None, code_objects={}, show_asm=None - ) -> Tuple[list, dict]: + ) -> tuple: """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing @@ -73,7 +71,7 @@ def ingest( # The value is where the loop ends. In current Python, # JUMP_BACKS are always to loops. And blocks are ordered so that the # JUMP_BACK with the highest offset will be where the range ends. - jump_back_targets: Dict[int, int] = {} + jump_back_targets = {} for token in tokens: if token.kind == "JUMP_BACK": jump_back_targets[token.attr] = token.offset @@ -92,7 +90,7 @@ def ingest( if offset == next_end: loop_ends.pop() if self.debug: - print(f"{' ' * len(loop_ends)}remove loop offset {offset}") + print("%sremove loop offset %s" % (" " * len(loop_ends), offset)) pass next_end = ( loop_ends[-1] @@ -106,7 +104,8 @@ def ingest( next_end = off2int(jump_back_targets[offset], prefer_last=False) if self.debug: print( - f"{' ' * len(loop_ends)}adding loop offset {offset} ending at {next_end}" + "%sadding loop offset %s ending at %s" + % (" " * len(loop_ends), offset, next_end) ) loop_ends.append(next_end) @@ -165,4 +164,4 @@ def ingest( print(t.format()) pass else: - print(f"Need to be Python 3.8 to demo; I am version {version_tuple_to_str()}.") + print("Need to be Python 3.8 to demo; I am version %s." % version_tuple_to_str()) From 5f48a8bf2f8386686fe653488769ef1748e25547 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 14:38:03 -0400 Subject: [PATCH 305/489] python-3.3-3.5 merge --- pytest/test_grammar.py | 2 +- ...pyc => 03_async_from_coroutine.pyc-notyet} | Bin ....pyc => 02_async_for_generator.pyc-notyet} | Bin ...pyc => 03_async_from_coroutine.pyc-notyet} | Bin uncompyle6/disas.py | 1 - uncompyle6/parsers/parse26.py | 6 ++--- uncompyle6/parsers/parse27.py | 4 +-- uncompyle6/parsers/parse30.py | 4 +-- uncompyle6/parsers/parse31.py | 4 +-- uncompyle6/parsers/parse34.py | 4 +-- uncompyle6/parsers/parse35.py | 4 +-- uncompyle6/parsers/parse36.py | 6 ++--- uncompyle6/parsers/parse37.py | 6 ++--- uncompyle6/parsers/parse38.py | 4 +-- uncompyle6/scanners/scanner31.py | 1 - uncompyle6/scanners/scanner37.py | 25 ++++++++++++++---- uncompyle6/scanners/scanner37base.py | 2 +- uncompyle6/scanners/scanner38.py | 2 +- uncompyle6/semantics/gencomp.py | 15 ++++++++--- uncompyle6/semantics/make_function1.py | 4 +-- 20 files changed, 58 insertions(+), 36 deletions(-) rename test/bytecode_3.6/{03_async_from_coroutine.pyc => 03_async_from_coroutine.pyc-notyet} (100%) rename test/bytecode_3.7/{02_async_for_generator.pyc => 02_async_for_generator.pyc-notyet} (100%) rename test/bytecode_3.7/{03_async_from_coroutine.pyc => 03_async_from_coroutine.pyc-notyet} (100%) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index b0f587a5e..ae80a8e0b 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -54,6 +54,7 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("except_handler_else") expect_lhs.add("kwarg") +<<<<<<< HEAD expect_lhs.add("load_genexpr") unused_rhs = unused_rhs.union( @@ -88,7 +89,6 @@ def check_tokens(tokens, opcode_set): assert expect_lhs == set(lhs) assert unused_rhs == set(rhs) ->>>>>>> python-3.3-to-3.5 assert expect_right_recursive == right_recursive expect_dup_rhs = frozenset( diff --git a/test/bytecode_3.6/03_async_from_coroutine.pyc b/test/bytecode_3.6/03_async_from_coroutine.pyc-notyet similarity index 100% rename from test/bytecode_3.6/03_async_from_coroutine.pyc rename to test/bytecode_3.6/03_async_from_coroutine.pyc-notyet diff --git a/test/bytecode_3.7/02_async_for_generator.pyc b/test/bytecode_3.7/02_async_for_generator.pyc-notyet similarity index 100% rename from test/bytecode_3.7/02_async_for_generator.pyc rename to test/bytecode_3.7/02_async_for_generator.pyc-notyet diff --git a/test/bytecode_3.7/03_async_from_coroutine.pyc b/test/bytecode_3.7/03_async_from_coroutine.pyc-notyet similarity index 100% rename from test/bytecode_3.7/03_async_from_coroutine.pyc rename to test/bytecode_3.7/03_async_from_coroutine.pyc-notyet diff --git a/uncompyle6/disas.py b/uncompyle6/disas.py index 46f591235..b36c755f7 100644 --- a/uncompyle6/disas.py +++ b/uncompyle6/disas.py @@ -70,7 +70,6 @@ def disco_loop(disasm, queue, real_out): "\n# %s %s\n" % (co.co_name, co.co_filename) ) - print( tokens, customize = disasm(co) for t in tokens: if iscode(t.pattr): diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 87397911a..27c71eccd 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -523,11 +523,11 @@ class Python26ParserSingle(Python2Parser, PythonParserSingle): # Check grammar p = Python26Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 2.6: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (2, 6): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner - s = get_scanner(PYTHON_VERSION, IS_PYPY) + s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY) opcode_set = set(s.opc.opname).union(set( """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index b4d534d0e..472f3b720 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -361,8 +361,8 @@ class Python27ParserSingle(Python27Parser, PythonParserSingle): # Check grammar p = Python27Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 2.7: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (2, 7): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index 86e6b59bc..b38e96ccc 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -352,8 +352,8 @@ class Python30ParserSingle(Python30Parser, PythonParserSingle): p = Python30Parser() p.remove_rules_30() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 3.0: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (3, 0): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse31.py b/uncompyle6/parsers/parse31.py index 8fc37244f..615933aa8 100644 --- a/uncompyle6/parsers/parse31.py +++ b/uncompyle6/parsers/parse31.py @@ -55,8 +55,8 @@ class Python31ParserSingle(Python31Parser, PythonParserSingle): p = Python31Parser() p.remove_rules_31() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 3.1: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (3, 1): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index 8eff26dd6..2154dc204 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -70,8 +70,8 @@ class Python34ParserSingle(Python34Parser, PythonParserSingle): # Check grammar p = Python34Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 3.4: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE == (3, 4): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index dc989b822..c61eebce8 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -272,8 +272,8 @@ class Python35ParserSingle(Python35Parser, PythonParserSingle): # Check grammar p = Python35Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 3.5: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (3, 5): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index bceabe448..832e020a6 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -376,7 +376,7 @@ def customize_grammar_rules(self, tokens, customize): elif opname == "GET_AITER": self.add_unique_doc_rules("get_aiter ::= expr GET_AITER", customize) - if not {"MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"} in self.seen_ops: + if not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) in self.seen_ops: self.addRule( """ expr ::= dict_comp_async @@ -672,8 +672,8 @@ class Python36ParserSingle(Python36Parser, PythonParserSingle): # Check grammar p = Python36Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY - if PYTHON_VERSION == 3.6: + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY + if PYTHON_VERSION_TRIPLE[:2] == (3, 6): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner s = get_scanner(PYTHON_VERSION, IS_PYPY) diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 7d68c12c3..2f51f8ffc 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -1337,7 +1337,7 @@ def customize_grammar_rules(self, tokens, customize): elif opname == "GET_AITER": self.add_unique_doc_rules("get_aiter ::= expr GET_AITER", customize) - if not {"MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"} in self.seen_ops: + if not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) in self.seen_ops: self.addRule( """ expr ::= dict_comp_async @@ -1738,9 +1738,9 @@ class Python37ParserSingle(Python37Parser, PythonParserSingle): # FIXME: DRY this with other parseXX.py routines p = Python37Parser() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY - if PYTHON_VERSION == 3.7: + if PYTHON_VERSION_TRIPLE[:2] == (3, 7): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner diff --git a/uncompyle6/parsers/parse38.py b/uncompyle6/parsers/parse38.py index 1169c9282..776279543 100644 --- a/uncompyle6/parsers/parse38.py +++ b/uncompyle6/parsers/parse38.py @@ -344,9 +344,9 @@ class Python38ParserSingle(Python38Parser, PythonParserSingle): p = Python38Parser() p.remove_rules_38() p.check_grammar() - from uncompyle6 import PYTHON_VERSION, IS_PYPY + from xdis import PYTHON_VERSION_TRIPLE, IS_PYPY - if PYTHON_VERSION == 3.8: + if PYTHON_VERSION_TRIPLE[:2] == (3, 8): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner diff --git a/uncompyle6/scanners/scanner31.py b/uncompyle6/scanners/scanner31.py index 94ff7b223..4600803a6 100644 --- a/uncompyle6/scanners/scanner31.py +++ b/uncompyle6/scanners/scanner31.py @@ -31,4 +31,3 @@ def __init__(self, show_asm=None, is_pypy=False): pass else: print("Need to be Python 3.1 to demo; I am version %s." % version_tuple_to_str()) -[< diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 6f18d606c..ccc7534f0 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,12 +22,18 @@ scanner routine for Python 3. """ +<<<<<<< HEAD <<<<<<< HEAD ======= from uncompyle6.scanner import CONST_COLLECTIONS from uncompyle6.scanners.tok import Token >>>>>>> python-3.3-to-3.5 +======= +from uncompyle6.scanner import CONST_COLLECTIONS +from uncompyle6.scanners.tok import Token + +>>>>>>> python-2.4-nogood-merge from uncompyle6.scanners.scanner37base import Scanner37Base # bytecode verification, verify(), uses JUMP_OPs from here @@ -38,6 +44,7 @@ class Scanner37(Scanner37Base): +<<<<<<< HEAD <<<<<<< HEAD def __init__(self, show_asm=None, is_pypy=False): Scanner37Base.__init__(self, (3, 7), show_asm) @@ -47,15 +54,23 @@ def __init__(self, show_asm=None, debug="", is_pypy=False): Scanner37Base.__init__(self, (3, 7), show_asm, debug, is_pypy) self.debug = debug >>>>>>> python-3.3-to-3.5 +======= + def __init__(self, show_asm=None, debug="", is_pypy=False): + Scanner37Base.__init__(self, (3, 7), show_asm, debug, is_pypy) + self.debug = debug +>>>>>>> python-2.4-nogood-merge return pass <<<<<<< HEAD +<<<<<<< HEAD +======= ======= +>>>>>>> python-2.4-nogood-merge def bound_collection_from_tokens( - self, tokens: list, next_tokens: list, t: Token, i: int, collection_type: str - ) -> list: + self, tokens, next_tokens, t, i, collection_type + ): count = t.attr assert isinstance(count, int) @@ -130,7 +145,10 @@ def bound_collection_from_tokens( ) return new_tokens +<<<<<<< HEAD >>>>>>> python-3.3-to-3.5 +======= +>>>>>>> python-2.4-nogood-merge def ingest( self, co, classname=None, code_objects={}, show_asm=None ): @@ -167,9 +185,6 @@ def ingest( collection_type = "DICT" else: collection_type = t.kind.split("_")[1] - next_tokens = self.bound_collection_from_tokens( - new_tokens, t, i, "CONST_%s" % collection_type - ) new_tokens = self.bound_collection_from_tokens( tokens, new_tokens, t, i, "CONST_%s" % collection_type ) diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 59c50c546..6c8d69ae8 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -46,7 +46,7 @@ class Scanner37Base(Scanner): - def __init__(self, version: tuple, show_asm=None, debug="", is_pypy=False): + def __init__(self, version, show_asm=None, debug="", is_pypy=False): super(Scanner37Base, self).__init__(version, show_asm, is_pypy) self.debug = debug self.is_pypy = is_pypy diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index 2d211f686..23909804a 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -43,7 +43,7 @@ def __init__(self, show_asm=None, debug="", is_pypy=False): def ingest( self, co, classname=None, code_objects={}, show_asm=None - ) -> tuple: + ): """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 052dd7d5d..3385f8dca 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -269,7 +269,10 @@ def comprehension_walk_newer( assert list_afor2 == "list_afor2" store = list_afor2[1] assert store == "store" - n = list_afor2[3] if list_afor2[3] == "list_iter" else list_afor2[2] + if list_afor2[3] == "list_iter": + n = list_afor2[3] + else: + n = list_afor2[2] else: # ??? pass @@ -629,7 +632,10 @@ def listcomp_closure3(self, node): list_ifs.append(n) else: list_ifs.append([1]) - n = n[-2] if n[-1] == "come_from_opt" else n[-1] + if n[-1] == "come_from_opt": + n = n[-2] + else: + n = n[-1] pass elif n == "list_if37": list_ifs.append(n) @@ -639,7 +645,10 @@ def listcomp_closure3(self, node): collections.append(n[0][0]) n = n[1] stores.append(n[1][0]) - n = n[2] if n[2].kind == "list_iter" else n[3] + if n[2].kind: + n = n[2] + else: + n = n[3] pass assert n == "lc_body", tree diff --git a/uncompyle6/semantics/make_function1.py b/uncompyle6/semantics/make_function1.py index b61245240..ac076a096 100644 --- a/uncompyle6/semantics/make_function1.py +++ b/uncompyle6/semantics/make_function1.py @@ -34,7 +34,7 @@ def make_function1(self, node, is_lambda, nested=1, code_node=None): This code is specialied for Python 2. """ - def build_param(tree, param_names: list) -> tuple: + def build_param(tree, param_names): """build parameters: - handle defaults - handle format tuple parameters @@ -93,7 +93,7 @@ def build_param(tree, param_names: list) -> tuple: is_lambda=is_lambda, noneInNames=("None" in code.co_names), ) - except (ParserError, ParserError2) as p: + except (ParserError(p), ParserError2(p)): self.write(str(p)) if not self.tolerate_errors: self.ERROR = p From a040439f48e8f72649997fcfedd973a3e2d6875b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 16:51:28 -0400 Subject: [PATCH 306/489] bug in formatting slice2 nonterminal --- uncompyle6/semantics/consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 8e9334c33..b738426d5 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -255,7 +255,7 @@ (1, NO_PARENTHESIS_EVER) ), - "slice2": ( "[%c:%p]", + "slice2": ( "%c[:%p]", (0, "expr"), (1, NO_PARENTHESIS_EVER) ), From b8cc1be32b34a8c8511f62f4d0dea26327bf832f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 16:57:23 -0400 Subject: [PATCH 307/489] Remove diff merge schmutz --- pytest/test_grammar.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index ae80a8e0b..ed4b2c65d 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -54,7 +54,6 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("except_handler_else") expect_lhs.add("kwarg") -<<<<<<< HEAD expect_lhs.add("load_genexpr") unused_rhs = unused_rhs.union( From 550273d11771d68471b934ce6f73ee8ba5332fc1 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 17:04:41 -0400 Subject: [PATCH 308/489] test_grammar corrections for Python < 3.0 --- pytest/test_grammar.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index ed4b2c65d..a8f11b403 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -54,23 +54,25 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("except_handler_else") expect_lhs.add("kwarg") - expect_lhs.add("load_genexpr") - - unused_rhs = unused_rhs.union( - set( - """ - except_pop_except generator_exp - """.split() + if PYTHON_VERSION_TRIPLE >= (3, 0): + expect_lhs.add("load_genexpr") + + unused_rhs = unused_rhs.union( + set( + """ + except_pop_except generator_exp + """.split() + ) ) - ) - if PYTHON_VERSION_TRIPLE < (3, 7): - expect_lhs.add("annotate_arg") - expect_lhs.add("annotate_tuple") - unused_rhs.add("mkfunc_annotate") - - unused_rhs.add("dict_comp") - unused_rhs.add("classdefdeco1") - unused_rhs.add("tryelsestmtl") + if PYTHON_VERSION_TRIPLE < (3, 7): + expect_lhs.add("annotate_arg") + expect_lhs.add("annotate_tuple") + unused_rhs.add("mkfunc_annotate") + + unused_rhs.add("dict_comp") + unused_rhs.add("classdefdeco1") + unused_rhs.add("tryelsestmtl") + if PYTHON_VERSION_TRIPLE >= (3, 5): expect_right_recursive.add( (("l_stmts", ("lastl_stmt", "come_froms", "l_stmts"))) From 4b9b3f27f975dbc28a6158a9c32218d0d789507f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 17:08:51 -0400 Subject: [PATCH 309/489] Remove failed merge chevron remnants --- uncompyle6/scanners/scanner37.py | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index ccc7534f0..59d59049b 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,18 +22,9 @@ scanner routine for Python 3. """ -<<<<<<< HEAD -<<<<<<< HEAD -======= from uncompyle6.scanner import CONST_COLLECTIONS from uncompyle6.scanners.tok import Token ->>>>>>> python-3.3-to-3.5 -======= -from uncompyle6.scanner import CONST_COLLECTIONS -from uncompyle6.scanners.tok import Token - ->>>>>>> python-2.4-nogood-merge from uncompyle6.scanners.scanner37base import Scanner37Base # bytecode verification, verify(), uses JUMP_OPs from here @@ -44,30 +35,13 @@ class Scanner37(Scanner37Base): -<<<<<<< HEAD -<<<<<<< HEAD - def __init__(self, show_asm=None, is_pypy=False): - Scanner37Base.__init__(self, (3, 7), show_asm) - self.is_pypy = is_pypy -======= - def __init__(self, show_asm=None, debug="", is_pypy=False): - Scanner37Base.__init__(self, (3, 7), show_asm, debug, is_pypy) - self.debug = debug ->>>>>>> python-3.3-to-3.5 -======= def __init__(self, show_asm=None, debug="", is_pypy=False): Scanner37Base.__init__(self, (3, 7), show_asm, debug, is_pypy) self.debug = debug ->>>>>>> python-2.4-nogood-merge return pass -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= ->>>>>>> python-2.4-nogood-merge def bound_collection_from_tokens( self, tokens, next_tokens, t, i, collection_type ): @@ -145,10 +119,6 @@ def bound_collection_from_tokens( ) return new_tokens -<<<<<<< HEAD ->>>>>>> python-3.3-to-3.5 -======= ->>>>>>> python-2.4-nogood-merge def ingest( self, co, classname=None, code_objects={}, show_asm=None ): From 540f6197457bbbb17f28251c9dd2ec703534a30d Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 17:37:12 -0400 Subject: [PATCH 310/489] Bugs with 1.0 bytecode and 2.x relative "." import --- uncompyle6/scanner.py | 2 ++ uncompyle6/scanners/scanner2.py | 6 ++++-- uncompyle6/scanners/scanner26.py | 3 +-- uncompyle6/semantics/customize26_27.py | 15 +++++++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 1c4ef5f2e..373913ac6 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -230,6 +230,8 @@ def build_lines_data(self, code_obj): # Locally we use list for more convenient iteration using indices linestarts = list(self.opc.findlinestarts(code_obj)) self.linestarts = dict(linestarts) + if not self.linestarts: + return [] # 'List-map' which shows line number of current op and offset of # first op on following line, given offset of op as index diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 441fc5c3c..b219cfd77 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -518,7 +518,7 @@ def build_statement_indices(self): for s in stmt_list: if code[s] == self.opc.JUMP_ABSOLUTE and s not in pass_stmts: target = self.get_target(s) - if target > s or self.lines[last_stmt].l_no == self.lines[s].l_no: + if target > s or (self.lines and self.lines[last_stmt].l_no == self.lines[s].l_no): stmts.remove(s) continue j = self.prev[s] @@ -619,6 +619,7 @@ def detect_control_flow(self, offset, op, extended_arg): parent = self.structs[0] start = parent["start"] end = parent["end"] + next_line_byte = end # Pick inner-most parent for our offset for struct in self.structs: @@ -647,7 +648,8 @@ def detect_control_flow(self, offset, op, extended_arg): if setup_target != loop_end_offset: self.fixed_jumps[offset] = loop_end_offset - (line_no, next_line_byte) = self.lines[offset] + if self.lines: + (line_no, next_line_byte) = self.lines[offset] # jump_back_offset is the instruction after the SETUP_LOOP # where we iterate back to. diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 0d683ec38..2fc2f2264 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -22,7 +22,6 @@ use in deparsing. """ -import sys import uncompyle6.scanners.scanner2 as scan # bytecode verification, verify(), uses JUMP_OPs from here @@ -111,7 +110,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): i = self.next_stmt[last_stmt] replace = {} while i < codelen - 1: - if self.lines[last_stmt].next > i: + if self.lines and self.lines[last_stmt].next > i: # Distinguish "print ..." from "print ...," if self.code[last_stmt] == self.opc.PRINT_ITEM: if self.code[i] == self.opc.PRINT_ITEM: diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index ee50bb217..2e503c219 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -30,10 +30,10 @@ def customize_for_version26_27(self, version): ######################################## if version > (2, 6): TABLE_DIRECT.update({ - 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), + "except_cond2": ( "%|except %c as %c:\n", 1, 5 ), # When a generator is a single parameter of a function, # it doesn't need the surrounding parenethesis. - 'call_generator': ('%c%P', 0, (1, -1, ', ', 100)), + "call_generator": ('%c%P', 0, (1, -1, ', ', 100)), }) else: TABLE_DIRECT.update({ @@ -60,3 +60,14 @@ def n_call(node): self.default(node) self.n_call = n_call + + def n_import_from(node): + import_name = node[2] + if import_name == "IMPORT_NAME" and import_name.pattr == "": + fmt = "%|from . import %c\n" + self.template_engine( + (fmt, (3, "importlist")), node + ) + self.prune() + self.default(node) + self.n_import_from = n_import_from From c504bb24915720ff3d025f9b743104ae5e612949 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 19:25:26 -0400 Subject: [PATCH 311/489] 2.5-2.7 relative import fixes --- test/bytecode_2.5/01_rel_import.pyc | Bin 0 -> 254 bytes test/bytecode_2.6/01_rel_import.pyc | Bin 0 -> 254 bytes test/bytecode_2.7/01_rel_import.pyc | Bin 169 -> 254 bytes test/simple_source/stmts/01_rel_import.py | 2 ++ uncompyle6/semantics/consts.py | 13 +++++++++++-- uncompyle6/semantics/customize25.py | 6 ++++++ uncompyle6/semantics/customize26_27.py | 9 ++------- 7 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 test/bytecode_2.5/01_rel_import.pyc create mode 100644 test/bytecode_2.6/01_rel_import.pyc diff --git a/test/bytecode_2.5/01_rel_import.pyc b/test/bytecode_2.5/01_rel_import.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eff91378110247832659e5d8b683fe5aa1fe2cfe GIT binary patch literal 254 zcmX|(!485j42HWgj4?6cAvkanO+0uo#wYNAH!eijG=!0nbsY5MJNaflf!#1H>(~D6 z-+sR9ReE^W4g6nB`AmU(f~3!&1JDdg22660QP3PpK4}461X@5TNXKx^7PQzhLgwN8 z!P-1VZ28=asJa_78N8@(uS@2gjsl8+usscJ5q5n$n}I2n*!F`~6`IjDDo58l%(uJB bDqYdUShpFTxFqATH*(bK(~D6 z-+sR9ReE^W4g6nB`AmU(f~3!&1JDdg22660QP3PpK4}461X@5TNXKx^7PQzhLgwN8 z!P-1VZ28=asJa_78N8@(uS@2gjsl8+usscJ5q5n$n}I2n*!F`~6`IjDDo58l%(uJB bDqYdUShpFTZb`;tZ{(=e$sa;NNLa#t4K^v3 literal 0 HcmV?d00001 diff --git a/test/bytecode_2.7/01_rel_import.pyc b/test/bytecode_2.7/01_rel_import.pyc index 46c146daab02d1d9fb5d434f56862be67c236fc9..8e516b37d9f7e119bca0fb21d232b8d1c44e3ec5 100644 GIT binary patch literal 254 zcmYL>O$x#=5QQf{6%m9UqKmAof(sWSp1?)jbyJ!)N+BU7Nf)~E&R)PtDjG6h=1txk z_Fk`w!%KGXJrv(Fmfs_KyaY6WAy5+_J%yenO`)c<=AaoE4mC%e!Bs3UI1q%02pK}! z`{akXdY&=tZr1*VY@ZhqodFA~gp`g>*}5ua<5>LQ3vB&hMy(oeC)cUc2NQg`-8D|> a27jyzoAD8rXgnI*Pgmyscgk%2LVi6K~n87Ps- h2qZK>L 0: + node[2].pattr = ("." * node[0].pattr) + node[2].pattr + self.default(node) + self.n_import_from = n_import_from diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index 2e503c219..191966147 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -62,12 +62,7 @@ def n_call(node): self.n_call = n_call def n_import_from(node): - import_name = node[2] - if import_name == "IMPORT_NAME" and import_name.pattr == "": - fmt = "%|from . import %c\n" - self.template_engine( - (fmt, (3, "importlist")), node - ) - self.prune() + if node[0].pattr > 0: + node[2].pattr = ("." * node[0].pattr) + node[2].pattr self.default(node) self.n_import_from = n_import_from From d89153f910a8f47d9c9cb75b85fa321e3f9fdbbd Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 09:51:50 -0400 Subject: [PATCH 312/489] semi-black scanner26.py From 8f0943753739fc98a4b975d4698d0725d7ca62ac Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 16:54:50 -0400 Subject: [PATCH 313/489] Correct 2.x formatting "slice2" nonterminal --- uncompyle6/semantics/consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index d711b7da4..d094febf3 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -256,7 +256,7 @@ (1, NO_PARENTHESIS_EVER) ), - "slice2": ( "[%c:%p]", + "slice2": ( "%c[:%p]", (0, "expr"), (1, NO_PARENTHESIS_EVER) ), From 5c6c6c663d32aa3d3e02b6de1316606def378915 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 17:42:30 -0400 Subject: [PATCH 314/489] Bugs in 2.x relative import '.' and 1.x bytecode --- uncompyle6/scanner.py | 2 ++ uncompyle6/scanners/scanner2.py | 6 ++++-- uncompyle6/scanners/scanner26.py | 2 +- uncompyle6/semantics/customize26_27.py | 15 +++++++++++++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index cf6693f7a..be3ce28ed 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -229,6 +229,8 @@ def build_lines_data(self, code_obj): # Locally we use list for more convenient iteration using indices linestarts = list(self.opc.findlinestarts(code_obj)) self.linestarts = dict(linestarts) + if not self.linestarts: + return [] # 'List-map' which shows line number of current op and offset of # first op on following line, given offset of op as index diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index fb9e0b845..3ec6e1135 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -522,7 +522,7 @@ def build_statement_indices(self): for s in stmt_list: if code[s] == self.opc.JUMP_ABSOLUTE and s not in pass_stmts: target = self.get_target(s) - if target > s or self.lines[last_stmt].l_no == self.lines[s].l_no: + if target > s or (self.lines and self.lines[last_stmt].l_no == self.lines[s].l_no): stmts.remove(s) continue j = self.prev[s] @@ -623,6 +623,7 @@ def detect_control_flow(self, offset, op, extended_arg): parent = self.structs[0] start = parent["start"] end = parent["end"] + next_line_byte = end # Pick inner-most parent for our offset for struct in self.structs: @@ -651,7 +652,8 @@ def detect_control_flow(self, offset, op, extended_arg): if setup_target != loop_end_offset: self.fixed_jumps[offset] = loop_end_offset - (line_no, next_line_byte) = self.lines[offset] + if self.lines: + (line_no, next_line_byte) = self.lines[offset] # jump_back_offset is the instruction after the SETUP_LOOP # where we iterate back to. diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index f0d46f900..9c77476c9 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -113,7 +113,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): i = self.next_stmt[last_stmt] replace = {} while i < codelen - 1: - if self.lines[last_stmt].next > i: + if self.lines and self.lines[last_stmt].next > i: # Distinguish "print ..." from "print ...," if self.code[last_stmt] == self.opc.PRINT_ITEM: if self.code[i] == self.opc.PRINT_ITEM: diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index ee50bb217..2e503c219 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -30,10 +30,10 @@ def customize_for_version26_27(self, version): ######################################## if version > (2, 6): TABLE_DIRECT.update({ - 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), + "except_cond2": ( "%|except %c as %c:\n", 1, 5 ), # When a generator is a single parameter of a function, # it doesn't need the surrounding parenethesis. - 'call_generator': ('%c%P', 0, (1, -1, ', ', 100)), + "call_generator": ('%c%P', 0, (1, -1, ', ', 100)), }) else: TABLE_DIRECT.update({ @@ -60,3 +60,14 @@ def n_call(node): self.default(node) self.n_call = n_call + + def n_import_from(node): + import_name = node[2] + if import_name == "IMPORT_NAME" and import_name.pattr == "": + fmt = "%|from . import %c\n" + self.template_engine( + (fmt, (3, "importlist")), node + ) + self.prune() + self.default(node) + self.n_import_from = n_import_from From 4096d310e493d20de971d0e97a6a4c9d2ed7155b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 19:28:23 -0400 Subject: [PATCH 315/489] Correct 2.5-7 relative import formatting --- test/bytecode_2.5/01_rel_import.pyc | Bin 0 -> 254 bytes test/bytecode_2.6/01_rel_import.pyc | Bin 0 -> 254 bytes test/bytecode_2.7/01_rel_import.pyc | Bin 169 -> 254 bytes test/simple_source/stmts/01_rel_import.py | 2 ++ uncompyle6/semantics/consts.py | 13 +++++++++++-- uncompyle6/semantics/customize25.py | 6 ++++++ uncompyle6/semantics/customize26_27.py | 9 ++------- 7 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 test/bytecode_2.5/01_rel_import.pyc create mode 100644 test/bytecode_2.6/01_rel_import.pyc diff --git a/test/bytecode_2.5/01_rel_import.pyc b/test/bytecode_2.5/01_rel_import.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eff91378110247832659e5d8b683fe5aa1fe2cfe GIT binary patch literal 254 zcmX|(!485j42HWgj4?6cAvkanO+0uo#wYNAH!eijG=!0nbsY5MJNaflf!#1H>(~D6 z-+sR9ReE^W4g6nB`AmU(f~3!&1JDdg22660QP3PpK4}461X@5TNXKx^7PQzhLgwN8 z!P-1VZ28=asJa_78N8@(uS@2gjsl8+usscJ5q5n$n}I2n*!F`~6`IjDDo58l%(uJB bDqYdUShpFTxFqATH*(bK(~D6 z-+sR9ReE^W4g6nB`AmU(f~3!&1JDdg22660QP3PpK4}461X@5TNXKx^7PQzhLgwN8 z!P-1VZ28=asJa_78N8@(uS@2gjsl8+usscJ5q5n$n}I2n*!F`~6`IjDDo58l%(uJB bDqYdUShpFTZb`;tZ{(=e$sa;NNLa#t4K^v3 literal 0 HcmV?d00001 diff --git a/test/bytecode_2.7/01_rel_import.pyc b/test/bytecode_2.7/01_rel_import.pyc index 46c146daab02d1d9fb5d434f56862be67c236fc9..8e516b37d9f7e119bca0fb21d232b8d1c44e3ec5 100644 GIT binary patch literal 254 zcmYL>O$x#=5QQf{6%m9UqKmAof(sWSp1?)jbyJ!)N+BU7Nf)~E&R)PtDjG6h=1txk z_Fk`w!%KGXJrv(Fmfs_KyaY6WAy5+_J%yenO`)c<=AaoE4mC%e!Bs3UI1q%02pK}! z`{akXdY&=tZr1*VY@ZhqodFA~gp`g>*}5ua<5>LQ3vB&hMy(oeC)cUc2NQg`-8D|> a27jyzoAD8rXgnI*Pgmyscgk%2LVi6K~n87Ps- h2qZK>L 0: + node[2].pattr = ("." * node[0].pattr) + node[2].pattr + self.default(node) + self.n_import_from = n_import_from diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index 2e503c219..191966147 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -62,12 +62,7 @@ def n_call(node): self.n_call = n_call def n_import_from(node): - import_name = node[2] - if import_name == "IMPORT_NAME" and import_name.pattr == "": - fmt = "%|from . import %c\n" - self.template_engine( - (fmt, (3, "importlist")), node - ) - self.prune() + if node[0].pattr > 0: + node[2].pattr = ("." * node[0].pattr) + node[2].pattr self.default(node) self.n_import_from = n_import_from From 14fe8c5356e1cc8190a4b7dd60f984f6150632db Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 May 2022 20:25:33 -0400 Subject: [PATCH 316/489] some lambda's can't have \n + grammar cleanup --- pytest/test_grammar.py | 5 +---- test/stdlib/2.4-exclude.sh | 2 +- test/stdlib/2.5-exclude.sh | 2 +- test/stdlib/2.7-exclude.sh | 1 - uncompyle6/parsers/parse26.py | 5 ----- uncompyle6/semantics/pysource.py | 6 +----- 6 files changed, 4 insertions(+), 17 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index a8f11b403..8cb5a5c84 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -46,10 +46,7 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("kv3") unused_rhs.add("dict") else: - # NOTE: this may disappear - expect_lhs.add("except_handler_else") - - if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] != (2, 7): + if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] not in ((2, 7), (2, 6)): # NOTE: this may disappear expect_lhs.add("except_handler_else") diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh index a28d2cc68..664f6da59 100644 --- a/test/stdlib/2.4-exclude.sh +++ b/test/stdlib/2.4-exclude.sh @@ -42,7 +42,7 @@ SKIP_TESTS=( [test_decimal.py]=1 # [test_dis.py]=1 # We change line numbers - duh! [test_generators.py]=1 # Investigate - [test_grammar.py]=1 # Too many stmts. Handle large stmts + # [test_grammar.py]=1 # fails on its own - no module tests.test_support [test_grp.py]=1 # Long test - might work Control flow? [test_pep247.py]=1 # Long test - might work? Control flow? [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index 783e50c78..1b0d1afa6 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -44,7 +44,7 @@ SKIP_TESTS=( [test_dis.py]=1 # We change line numbers - duh! [test_file.py]=1 # test assertion failures [test_generators.py]=1 # Investigate - [test_grammar.py]=1 # Too many stmts. Handle large stmts + # [test_grammar.py]=1 # fails on its own - no module tests.test_support [test_grp.py]=1 # Long test - might work Control flow? [test_macfs.py]=1 # it fails on its own [test_macostools.py]=1 # it fails on its own diff --git a/test/stdlib/2.7-exclude.sh b/test/stdlib/2.7-exclude.sh index 296cd679a..629286a1f 100644 --- a/test/stdlib/2.7-exclude.sh +++ b/test/stdlib/2.7-exclude.sh @@ -9,7 +9,6 @@ SKIP_TESTS=( [test_doctest.py]=1 # Fails on its own [test_exceptions.py]=1 [test_format.py]=1 # Control flow "and" vs nested "if" - [test_grammar.py]=1 # Too many stmts. Handle large stmts [test_grp.py]=1 # test takes to long, works interactively though [test_io.py]=1 # Test takes too long to run [test_ioctl.py]=1 # Test takes too long to run diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 27c71eccd..ff52a41c1 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -312,11 +312,6 @@ def p_misc26(self, args): compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP jmp_false_then compare_chained2 _come_froms - return_lambda ::= RETURN_VALUE - return_lambda ::= RETURN_END_IF - return_lambda ::= RETURN_END_IF_LAMBDA - return_lambda ::= RETURN_VALUE_LAMBDA - compare_chained2 ::= expr COMPARE_OP return_expr_lambda compare_chained2 ::= expr COMPARE_OP RETURN_END_IF_LAMBDA compare_chained2 ::= expr COMPARE_OP RETURN_END_IF COME_FROM diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index ac648b91c..f5114b1e4 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1180,11 +1180,7 @@ def gen_source( # Adding a "\n" after "lambda x: x" will give an error message: # SyntaxError: f-string expression part cannot include a backslash # So avoid that. - if self.in_format_string and is_lambda: - printfn = self.write - else: - printfn = self.println - printfn(self.text) + self.write(self.text) self.name = old_name self.return_none = rn From 175821f9d5fdf9fa8c1e6ce94934b3e75592ed8b Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 8 Jun 2022 13:53:49 -0400 Subject: [PATCH 317/489] Remove erroneously checked-in files --- .../parsers/reducecheck/ifelsestmt.py-notyet | 219 --- uncompyle6/scanners/scanner3.py-notyet | 1318 ----------------- uncompyle6/scanners/scanner30.py-try | 454 ------ 3 files changed, 1991 deletions(-) delete mode 100644 uncompyle6/parsers/reducecheck/ifelsestmt.py-notyet delete mode 100644 uncompyle6/scanners/scanner3.py-notyet delete mode 100644 uncompyle6/scanners/scanner30.py-try diff --git a/uncompyle6/parsers/reducecheck/ifelsestmt.py-notyet b/uncompyle6/parsers/reducecheck/ifelsestmt.py-notyet deleted file mode 100644 index 204278700..000000000 --- a/uncompyle6/parsers/reducecheck/ifelsestmt.py-notyet +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright (c) 2020 Rocky Bernstein - -from uncompyle6.scanners.tok import Token - -IFELSE_STMT_RULES = frozenset( - [ - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "jump_forward_else", - "else_suite", - "_come_froms", - ), - ), - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "jump_forward_else", - "else_suite", - "\\e__come_froms", - ), - ), - ( - "ifelsestmtl", - ( - "testexpr", - "c_stmts_opt", - "jump_forward_else", - "else_suitec", - ), - ), - ( - "ifelsestmtc", - ( - "testexpr", - "c_stmts_opt", - "jump_forward_else", - "else_suitec", - "\\e__come_froms", - ), - ), - ( - "ifelsestmtc", - ( - "testexpr", - "c_stmts_opt", - "jump_absolute_else", - "else_suitec", - ), - ), - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "jf_cfs", - "else_suite", - "\\e_opt_come_from_except", - ), - ), - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "JUMP_FORWARD", - "else_suite", - "come_froms", - ), - ), - ( - "ifelsestmt", - ("testexpr", "c_stmts", "come_froms", "else_suite", "come_froms",), - ), - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "jf_cfs", - "else_suite", - "opt_come_from_except", - ), - ), - ( - "ifelsestmt", - ( - "testexpr", - "c_stmts_opt", - "jf_cf_pop", - "else_suite", - ), - ), - ]) - -def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last): - - if (last + 1) < n and tokens[last + 1] == "COME_FROM_LOOP" and lhs != "ifelsestmtc": - # ifelsestmt jumped outside of loop. No good. - return True - - if not (rule[1][0] == "testexpr_then") and rule not in IFELSE_STMT_RULES: - # print("XXX", rule) - return False - - # Avoid if/else where the "then" is a "raise_stmt1" for an - # assert statemetn. Parse this as an "assert" instead. - stmts = ast[1] - if stmts in ("c_stmts",) and len(stmts) == 1: - raise_stmt1 = stmts[0] - if ( - raise_stmt1 == "raise_stmt1" and - raise_stmt1[0] in ("LOAD_ASSERT",) - ): - return True - - # Make sure all of the "come froms" offset at the - # end of the "if" come from somewhere inside the "if". - # Since the come_froms are ordered so that lowest - # offset COME_FROM is last, it is sufficient to test - # just the last one. - if len(ast) == 5: - end_come_froms = ast[-1] - if end_come_froms.kind != "else_suite" and self.version >= 3.0: - if end_come_froms == "opt_come_from_except" and len(end_come_froms) > 0: - end_come_froms = end_come_froms[0] - if not isinstance(end_come_froms, Token): - if len(end_come_froms): - return tokens[first].offset > end_come_froms[-1].attr - elif tokens[first].offset > end_come_froms.attr: - return True - - # FIXME: There is weirdness in the grammar we need to work around. - # we need to clean up the grammar. - if self.version < 3.0: - last_token = ast[-1] - else: - last_token = tokens[last] - if last_token == "COME_FROM" and tokens[first].offset > last_token.attr: - if self.version < 3.0 and self.insts[self.offset2inst_index[last_token.attr]].opname != "SETUP_LOOP": - return True - - testexpr = ast[0] - - if rule[1][0] == "testexpr_then": - from trepan.api import debug; debug() - - if_condition = testexpr[0] - # Check that the condition portion of the "if" - # jumps to the "else" part. - if if_condition in ("testtrue", "testfalse", "testfalse_then"): - - else_suite = ast[3] - assert else_suite.kind.startswith("else_suite") - - if len(if_condition) > 1 and if_condition[1].kind.startswith("jmp_"): - if last == n: - last -= 1 - jmp = if_condition[1] - if self.version > 2.6: - jmp_target = jmp[0].attr - else: - jmp_target = int(jmp[0].pattr) - - - # Below we check that jmp_target is jumping to a feasible - # location. It should be to the transition after the "then" - # block and to the beginning of the "else" block. - # However the "if/else" is inside a loop the false test can be - # back to the loop. - - # FIXME: the below logic for jf_cfs could probably be - # simplified. - jump_else_end = ast[2] - if jump_else_end == "filler": - jump_else_end = ast[3] - if jump_else_end == "jf_cf_pop": - jump_else_end = jump_else_end[0] - - jump_to_jump = False - if jump_else_end == "JUMP_FORWARD": - jump_to_jump = True - endif_target = int(jump_else_end.pattr) - last_offset = tokens[last].off2int() - if endif_target != last_offset: - return True - last_offset = tokens[last].off2int(prefer_last=False) - if jmp_target == last_offset: - # jmp_target should be jumping to the end of the if/then/else - # but is it jumping to the beginning of the "else" - return True - if ( - jump_else_end in ("jf_cfs", "jump_forward_else") - and jump_else_end[0] == "JUMP_FORWARD" - ): - # If the "else" jump jumps before the end of the the "if .. else end", then this - # is not this kind of "ifelsestmt". - jump_else_forward = jump_else_end[0] - jump_else_forward_target = jump_else_forward.attr - if jump_else_forward_target < last_offset: - return True - pass - if ( - jump_else_end in ("jb_elsec", "jb_elsel", "jf_cfs", "jb_cfs") - and jump_else_end[-1] == "COME_FROM" - ): - if jump_else_end[-1].off2int() != jmp_target: - return True - - if tokens[first].off2int() > jmp_target: - return True - - return (jmp_target > last_offset) and tokens[last] != "JUMP_FORWARD" - - return False diff --git a/uncompyle6/scanners/scanner3.py-notyet b/uncompyle6/scanners/scanner3.py-notyet deleted file mode 100644 index b066302dc..000000000 --- a/uncompyle6/scanners/scanner3.py-notyet +++ /dev/null @@ -1,1318 +0,0 @@ -# Copyright (c) 2015-2019 by Rocky Bernstein -# Copyright (c) 2005 by Dan Pascu -# Copyright (c) 2000-2002 by hartmut Goebel -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -""" -Python 3 Generic bytecode scanner/deparser - -This overlaps various Python3's dis module, but it can be run from -Python versions other than the version running this code. Notably, -run from Python version 2. - -Also we *modify* the instruction sequence to assist deparsing code. -For example: - - we add "COME_FROM" instructions to help in figuring out - conditional branching and looping. - - LOAD_CONSTs are classified further into the type of thing - they load: - lambda's, genexpr's, {dict,set,list} comprehension's, - - PARAMETER counts appended {CALL,MAKE}_FUNCTION, BUILD_{TUPLE,SET,SLICE} - -Finally we save token information. -""" - -from __future__ import print_function - -from xdis import iscode -from xdis.bytecode import instruction_size, _get_const_info - -from uncompyle6.scanner import Token, parse_fn_counts -import xdis - -# Get all the opcodes into globals -import xdis.opcodes.opcode_33 as op3 - -from uncompyle6.scanner import Scanner - -import sys -from uncompyle6 import PYTHON3 - -if PYTHON3: - intern = sys.intern - -globals().update(op3.opmap) - - -class Scanner3(Scanner): - def __init__(self, version, show_asm=None, is_pypy=False): - super(Scanner3, self).__init__(version, show_asm, is_pypy) - - # Create opcode classification sets - # Note: super initilization above initializes self.opc - - # For ops that start SETUP_ ... we will add COME_FROM with these names - # at the their targets. - # Some blocks and END_ statements. And they can start - # a new statement - if self.version < 3.8: - setup_ops = [ - self.opc.SETUP_LOOP, - self.opc.SETUP_EXCEPT, - self.opc.SETUP_FINALLY, - ] - self.setup_ops_no_loop = frozenset(setup_ops) - frozenset( - [self.opc.SETUP_LOOP] - ) - else: - setup_ops = [self.opc.SETUP_FINALLY] - self.setup_ops_no_loop = frozenset(setup_ops) - - if self.version >= 3.2: - setup_ops.append(self.opc.SETUP_WITH) - self.setup_ops = frozenset(setup_ops) - - if self.version == 3.0: - self.pop_jump_tf = frozenset( - [self.opc.JUMP_IF_FALSE, self.opc.JUMP_IF_TRUE] - ) - self.not_continue_follow = ("END_FINALLY", "POP_BLOCK", "POP_TOP") - else: - self.pop_jump_tf = frozenset([self.opc.PJIF, self.opc.PJIT]) - self.not_continue_follow = ("END_FINALLY", "POP_BLOCK") - - # Opcodes that can start a statement. - statement_opcodes = [ - self.opc.POP_BLOCK, - self.opc.STORE_FAST, - self.opc.DELETE_FAST, - self.opc.STORE_DEREF, - self.opc.STORE_GLOBAL, - self.opc.DELETE_GLOBAL, - self.opc.STORE_NAME, - self.opc.DELETE_NAME, - self.opc.STORE_ATTR, - self.opc.DELETE_ATTR, - self.opc.STORE_SUBSCR, - self.opc.POP_TOP, - self.opc.DELETE_SUBSCR, - self.opc.END_FINALLY, - self.opc.RETURN_VALUE, - self.opc.RAISE_VARARGS, - self.opc.PRINT_EXPR, - self.opc.JUMP_ABSOLUTE, - ] - - if self.version < 3.8: - statement_opcodes += [self.opc.BREAK_LOOP, self.opc.CONTINUE_LOOP] - - self.statement_opcodes = frozenset(statement_opcodes) | self.setup_ops_no_loop - - # Opcodes that can start a "store" non-terminal. - # FIXME: JUMP_ABSOLUTE is weird. What's up with that? - self.designator_ops = frozenset( - [ - self.opc.STORE_FAST, - self.opc.STORE_NAME, - self.opc.STORE_GLOBAL, - self.opc.STORE_DEREF, - self.opc.STORE_ATTR, - self.opc.STORE_SUBSCR, - self.opc.UNPACK_SEQUENCE, - self.opc.JUMP_ABSOLUTE, - self.opc.UNPACK_EX, - ] - ) - - if self.version > 3.0: - self.jump_if_pop = frozenset( - [self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP] - ) - - self.pop_jump_if_pop = frozenset( - [ - self.opc.JUMP_IF_FALSE_OR_POP, - self.opc.JUMP_IF_TRUE_OR_POP, - self.opc.POP_JUMP_IF_TRUE, - self.opc.POP_JUMP_IF_FALSE, - ] - ) - # Not really a set, but still clasification-like - self.statement_opcode_sequences = [ - (self.opc.POP_JUMP_IF_FALSE, self.opc.JUMP_FORWARD), - (self.opc.POP_JUMP_IF_FALSE, self.opc.JUMP_ABSOLUTE), - (self.opc.POP_JUMP_IF_TRUE, self.opc.JUMP_FORWARD), - (self.opc.POP_JUMP_IF_TRUE, self.opc.JUMP_ABSOLUTE), - ] - - else: - self.jump_if_pop = frozenset([]) - self.pop_jump_if_pop = frozenset([]) - # Not really a set, but still clasification-like - self.statement_opcode_sequences = [ - (self.opc.JUMP_FORWARD,), - (self.opc.JUMP_ABSOLUTE,), - (self.opc.JUMP_FORWARD,), - (self.opc.JUMP_ABSOLUTE,), - ] - - # FIXME: remove this and use instead info from xdis. - # Opcodes that take a variable number of arguments - # (expr's) - varargs_ops = set( - [ - self.opc.BUILD_LIST, - self.opc.BUILD_TUPLE, - self.opc.BUILD_SET, - self.opc.BUILD_SLICE, - self.opc.BUILD_MAP, - self.opc.UNPACK_SEQUENCE, - self.opc.RAISE_VARARGS, - ] - ) - - if is_pypy or self.version >= 3.7: - varargs_ops.add(self.opc.CALL_METHOD) - if self.version >= 3.5: - varargs_ops |= set( - [ - self.opc.BUILD_SET_UNPACK, - self.opc.BUILD_MAP_UNPACK, # we will handle this later - self.opc.BUILD_LIST_UNPACK, - self.opc.BUILD_TUPLE_UNPACK, - ] - ) - if self.version >= 3.6: - varargs_ops.add(self.opc.BUILD_CONST_KEY_MAP) - # Below is in bit order, "default = bit 0, closure = bit 3 - self.MAKE_FUNCTION_FLAGS = tuple( - """ - default keyword-only annotation closure""".split() - ) - - self.varargs_ops = frozenset(varargs_ops) - # FIXME: remove the above in favor of: - # self.varargs_ops = frozenset(self.opc.hasvargs) - return - - def ingest(self, co, classname=None, code_objects={}, show_asm=None): - """ - Pick out tokens from an uncompyle6 code object, and transform them, - returning a list of uncompyle6 Token's. - - The transformations are made to assist the deparsing grammar. - Specificially: - - various types of LOAD_CONST's are categorized in terms of what they load - - COME_FROM instructions are added to assist parsing control structures - - MAKE_FUNCTION and FUNCTION_CALLS append the number of positional arguments - - some EXTENDED_ARGS instructions are removed - - Also, when we encounter certain tokens, we add them to a set which will cause custom - grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST - cause specific rules for the specific number of arguments they take. - """ - - if not show_asm: - show_asm = self.show_asm - - bytecode = self.build_instructions(co) - - # show_asm = 'both' - if show_asm in ("both", "before"): - for instr in bytecode.get_instructions(co): - print(instr.disassemble()) - - # list of tokens/instructions - tokens = [] - - # "customize" is in the process of going away here - customize = {} - - if self.is_pypy: - customize["PyPy"] = 0 - - # Scan for assertions. Later we will - # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'. - # 'LOAD_ASSERT' is used in assert statements. - self.load_asserts = set() - - n = len(self.insts) - for i, inst in enumerate(self.insts): - - # We need to detect the difference between: - # raise AssertionError - # and - # assert ... - # If we have a JUMP_FORWARD after the - # RAISE_VARARGS then we have a "raise" statement - # else we have an "assert" statement. - if self.version == 3.0: - # Like 2.6, 3.0 doesn't have POP_JUMP_IF... so we have - # to go through more machinations - assert_can_follow = inst.opname == "POP_TOP" and i + 1 < n - if assert_can_follow: - prev_inst = self.insts[i - 1] - assert_can_follow = ( - prev_inst.opname in ("JUMP_IF_TRUE", "JUMP_IF_FALSE") - and i + 1 < n ) - jump_if_inst = prev_inst - else: - assert_can_follow = ( - inst.opname in ("POP_JUMP_IF_TRUE", "POP_JUMP_IF_FALSE") - and i + 1 < n - ) - jump_if_inst = inst - if assert_can_follow: - next_inst = self.insts[i + 1] - if ( - next_inst.opname == "LOAD_GLOBAL" - and next_inst.argval == "AssertionError" - and jump_if_inst.argval - ): - raise_idx = self.offset2inst_index[self.prev_op[jump_if_inst.argval]] - raise_inst = self.insts[raise_idx] - if raise_inst.opname.startswith("RAISE_VARARGS"): - self.load_asserts.add(next_inst.offset) - pass - pass - - # Get jump targets - # Format: {target offset: [jump offsets]} - jump_targets = self.find_jump_targets(show_asm) - # print("XXX2", jump_targets) - - last_op_was_break = False - - for i, inst in enumerate(self.insts): - - argval = inst.argval - op = inst.opcode - - if inst.opname == "EXTENDED_ARG": - # FIXME: The EXTENDED_ARG is used to signal annotation - # parameters - if i + 1 < n and self.insts[i + 1].opcode != self.opc.MAKE_FUNCTION: - continue - - if inst.offset in jump_targets: - jump_idx = 0 - # We want to process COME_FROMs to the same offset to be in *descending* - # offset order so we have the larger range or biggest instruction interval - # last. (I think they are sorted in increasing order, but for safety - # we sort them). That way, specific COME_FROM tags will match up - # properly. For example, a "loop" with an "if" nested in it should have the - # "loop" tag last so the grammar rule matches that properly. - for jump_offset in sorted(jump_targets[inst.offset], reverse=True): - come_from_name = "COME_FROM" - opname = self.opname_for_offset(jump_offset) - if opname == "EXTENDED_ARG": - j = xdis.next_offset(op, self.opc, jump_offset) - opname = self.opname_for_offset(j) - - if opname.startswith("SETUP_"): - come_from_type = opname[len("SETUP_") :] - come_from_name = "COME_FROM_%s" % come_from_type - pass - elif inst.offset in self.except_targets: - come_from_name = "COME_FROM_EXCEPT_CLAUSE" - tokens.append( - Token( - come_from_name, - jump_offset, - repr(jump_offset), - offset="%s_%s" % (inst.offset, jump_idx), - has_arg=True, - opc=self.opc, - ) - ) - jump_idx += 1 - pass - pass - elif inst.offset in self.else_start: - end_offset = self.else_start[inst.offset] - tokens.append( - Token( - "ELSE", - None, - repr(end_offset), - offset="%s" % (inst.offset), - has_arg=True, - opc=self.opc, - ) - ) - - pass - - pattr = inst.argrepr - opname = inst.opname - - if op in self.opc.CONST_OPS: - const = argval - if iscode(const): - if const.co_name == "": - assert opname == "LOAD_CONST" - opname = "LOAD_LAMBDA" - elif const.co_name == "": - opname = "LOAD_GENEXPR" - elif const.co_name == "": - opname = "LOAD_DICTCOMP" - elif const.co_name == "": - opname = "LOAD_SETCOMP" - elif const.co_name == "": - opname = "LOAD_LISTCOMP" - else: - opname = "LOAD_CODE" - # verify() uses 'pattr' for comparison, since 'attr' - # now holds Code(const) and thus can not be used - # for comparison (todo: think about changing this) - # pattr = 'code_object @ 0x%x %s->%s' %\ - # (id(const), const.co_filename, const.co_name) - pattr = "" - elif isinstance(const, str): - opname = "LOAD_STR" - else: - if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): - argval, _ = _get_const_info(inst.arg, co.co_consts) - # Why don't we use _ above for "pattr" rather than "const"? - # This *is* a little hoaky, but we have to coordinate with - # other parts like n_LOAD_CONST in pysource.py for example. - pattr = const - pass - elif opname in ("MAKE_FUNCTION", "MAKE_CLOSURE"): - if self.version >= 3.6: - # 3.6+ doesn't have MAKE_CLOSURE, so opname == 'MAKE_FUNCTION' - flags = argval - opname = "MAKE_FUNCTION_%d" % (flags) - attr = [] - for flag in self.MAKE_FUNCTION_FLAGS: - bit = flags & 1 - attr.append(bit) - flags >>= 1 - attr = attr[:4] # remove last value: attr[5] == False - else: - pos_args, name_pair_args, annotate_args = parse_fn_counts( - inst.argval - ) - pattr = "%d positional, %d keyword only, %d annotated" % ( - pos_args, - name_pair_args, - annotate_args, - ) - if name_pair_args > 0: - # FIXME: this should probably be K_ - opname = "%s_N%d" % (opname, name_pair_args) - pass - if annotate_args > 0: - opname = "%s_A_%d" % (opname, annotate_args) - pass - opname = "%s_%d" % (opname, pos_args) - attr = (pos_args, name_pair_args, annotate_args) - tokens.append( - Token( - opname=opname, - attr=attr, - pattr=pattr, - offset=inst.offset, - linestart=inst.starts_line, - op=op, - has_arg=inst.has_arg, - opc=self.opc, - ) - ) - continue - elif op in self.varargs_ops: - pos_args = argval - if self.is_pypy and not pos_args and opname == "BUILD_MAP": - opname = "BUILD_MAP_n" - else: - opname = "%s_%d" % (opname, pos_args) - - elif self.is_pypy and opname in ("JUMP_IF_NOT_DEBUG", "CALL_FUNCTION"): - if opname == "JUMP_IF_NOT_DEBUG": - # The value in the dict is in special cases in semantic actions, such - # as JUMP_IF_NOT_DEBUG. The value is not used in these cases, so we put - # in arbitrary value 0. - customize[opname] = 0 - elif self.version >= 3.6 and argval > 255: - opname = "CALL_FUNCTION_KW" - pass - - elif opname == "UNPACK_EX": - # FIXME: try with scanner and parser by - # changing argval - before_args = argval & 0xFF - after_args = (argval >> 8) & 0xFF - pattr = "%d before vararg, %d after" % (before_args, after_args) - argval = (before_args, after_args) - opname = "%s_%d+%d" % (opname, before_args, after_args) - - elif op == self.opc.JUMP_ABSOLUTE: - # Further classify JUMP_ABSOLUTE into backward jumps - # which are used in loops, and "CONTINUE" jumps which - # may appear in a "continue" statement. The loop-type - # and continue-type jumps will help us classify loop - # boundaries The continue-type jumps help us get - # "continue" statements with would otherwise be turned - # into a "pass" statement because JUMPs are sometimes - # ignored in rules as just boundary overhead. In - # comprehensions we might sometimes classify JUMP_BACK - # as CONTINUE, but that's okay since we add a grammar - # rule for that. - pattr = argval - target = self.get_target(inst.offset) - if target <= inst.offset: - next_opname = self.insts[i + 1].opname - - # 'Continue's include jumps to loops that are not - # and the end of a block which follow with POP_BLOCK and COME_FROM_LOOP. - # If the JUMP_ABSOLUTE is to a FOR_ITER and it is followed by another JUMP_FORWARD - # then we'll take it as a "continue". - is_continue = ( - self.insts[self.offset2inst_index[target]].opname == "FOR_ITER" - and self.insts[i + 1].opname == "JUMP_FORWARD" - ) - - if (self.version == 3.0 and self.insts[i + 1].opname == "JUMP_FORWARD" - and not is_continue): - target_prev = self.offset2inst_index[self.prev_op[target]] - is_continue = ( - self.insts[target_prev].opname == "SETUP_LOOP") - - if is_continue or ( - inst.offset in self.stmts - and ( - inst.starts_line - and next_opname not in self.not_continue_follow - ) - ): - opname = "CONTINUE" - else: - opname = "JUMP_BACK" - # FIXME: this is a hack to catch stuff like: - # if x: continue - # the "continue" is not on a new line. - # There are other situations where we don't catch - # CONTINUE as well. - if tokens[-1].kind == "JUMP_BACK" and tokens[-1].attr <= argval: - if tokens[-2].kind == "BREAK_LOOP": - del tokens[-1] - else: - # intern is used because we are changing the *previous* token - tokens[-1].kind = intern("CONTINUE") - if last_op_was_break and opname == "CONTINUE": - last_op_was_break = False - continue - - # FIXME: go over for Python 3.6+. This is sometimes wrong - elif op == self.opc.RETURN_VALUE: - if inst.offset in self.return_end_ifs: - opname = "RETURN_END_IF" - - elif inst.offset in self.load_asserts: - opname = "LOAD_ASSERT" - - last_op_was_break = opname == "BREAK_LOOP" - tokens.append( - Token( - opname=opname, - attr=argval, - pattr=pattr, - offset=inst.offset, - linestart=inst.starts_line, - op=op, - has_arg=inst.has_arg, - opc=self.opc, - ) - ) - pass - - if show_asm in ("both", "after"): - for t in tokens: - print(t.format(line_prefix="L.")) - print() - return tokens, customize - - def find_jump_targets(self, debug): - """ - Detect all offsets in a byte code which are jump targets - where we might insert a COME_FROM instruction. - - Return the list of offsets. - - Return the list of offsets. An instruction can be jumped - to in from multiple instructions. - """ - code = self.code - n = len(code) - self.structs = [{"type": "root", "start": 0, "end": n - 1}] - - # All loop entry points - self.loops = [] - - # Map fixed jumps to their real destination - self.fixed_jumps = {} - self.except_targets = {} - self.ignore_if = set() - self.build_statement_indices() - self.else_start = {} - - # Containers filled by detect_control_flow() - self.not_continue = set() - self.return_end_ifs = set() - self.setup_loop_targets = {} # target given setup_loop offset - self.setup_loops = {} # setup_loop offset given target - - targets = {} - for i, inst in enumerate(self.insts): - offset = inst.offset - op = inst.opcode - - if offset == 6 and inst.opname == "SETUP_LOOP": - from trepan.api import debug; debug() - - # FIXME: this code is going to get removed. - # Determine structures and fix jumps in Python versions - # since 2.3 - self.detect_control_flow(offset, targets, i) - - if inst.has_arg: - label = self.fixed_jumps.get(offset) - oparg = inst.arg - if self.version >= 3.6 and self.code[offset] == self.opc.EXTENDED_ARG: - j = xdis.next_offset(op, self.opc, offset) - next_offset = xdis.next_offset(op, self.opc, j) - else: - next_offset = xdis.next_offset(op, self.opc, offset) - - if label is None: - if op in self.opc.hasjrel and op != self.opc.FOR_ITER: - label = next_offset + oparg - elif op in self.opc.hasjabs: - if op in self.jump_if_pop: - if oparg > offset: - label = oparg - - if label is not None and label != -1 and self.version > 3.3: - targets[label] = targets.get(label, []) + [offset] - elif op == self.opc.END_FINALLY and offset in self.fixed_jumps: - label = self.fixed_jumps[offset] - targets[label] = targets.get(label, []) + [offset] - pass - - pass # for loop - - # DEBUG: - if debug in ("both", "after"): - import pprint as pp - - pp.pprint(self.structs) - - return targets - - def build_statement_indices(self): - code = self.code - start = 0 - end = codelen = len(code) - - # Compose preliminary list of indices with statements, - # using plain statement opcodes - prelim = self.inst_matches(start, end, self.statement_opcodes) - - # Initialize final container with statements with - # preliminary data - stmts = self.stmts = set(prelim) - - # Same for opcode sequences - pass_stmts = set() - for sequence in self.statement_opcode_sequences: - for i in self.op_range(start, end - (len(sequence) + 1)): - match = True - for elem in sequence: - if elem != code[i]: - match = False - break - i += instruction_size(code[i], self.opc) - - if match is True: - i = self.prev_op[i] - stmts.add(i) - pass_stmts.add(i) - - # Initialize statement list with the full data we've gathered so far - if pass_stmts: - stmt_offset_list = list(stmts) - stmt_offset_list.sort() - else: - stmt_offset_list = prelim - # 'List-map' which contains offset of start of - # next statement, when op offset is passed as index - self.next_stmt = slist = [] - last_stmt_offset = -1 - i = 0 - # Go through all statement offsets - for stmt_offset in stmt_offset_list: - # Process absolute jumps, but do not remove 'pass' statements - # from the set - if ( - code[stmt_offset] == self.opc.JUMP_ABSOLUTE - and stmt_offset not in pass_stmts - ): - # If absolute jump occurs in forward direction or it takes off from the - # same line as previous statement, this is not a statement - # FIXME: 0 isn't always correct - target = self.get_target(stmt_offset) - if ( - target > stmt_offset - or self.lines[last_stmt_offset].l_no == self.lines[stmt_offset].l_no - ): - stmts.remove(stmt_offset) - continue - # Rewing ops till we encounter non-JUMP_ABSOLUTE one - j = self.prev_op[stmt_offset] - while code[j] == self.opc.JUMP_ABSOLUTE: - j = self.prev_op[j] - # If we got here, then it's list comprehension which - # is not a statement too - if code[j] == self.opc.LIST_APPEND: - stmts.remove(stmt_offset) - continue - # Exclude ROT_TWO + POP_TOP - elif ( - code[stmt_offset] == self.opc.POP_TOP - and code[self.prev_op[stmt_offset]] == self.opc.ROT_TWO - ): - stmts.remove(stmt_offset) - continue - # Exclude FOR_ITER + designators - elif code[stmt_offset] in self.designator_ops: - j = self.prev_op[stmt_offset] - while code[j] in self.designator_ops: - j = self.prev_op[j] - if code[j] == self.opc.FOR_ITER: - stmts.remove(stmt_offset) - continue - # Add to list another list with offset of current statement, - # equal to length of previous statement - slist += [stmt_offset] * (stmt_offset - i) - last_stmt_offset = stmt_offset - i = stmt_offset - # Finish filling the list for last statement - slist += [codelen] * (codelen - len(slist)) - - def detect_control_flow(self, offset, targets, inst_index): - """ - Detect type of block structures and their boundaries to fix optimized jumps - in python2.3+ - """ - - code = self.code - inst = self.insts[inst_index] - op = inst.opcode - - # Detect parent structure - parent = self.structs[0] - start = parent["start"] - end = parent["end"] - - # Pick inner-most parent for our offset - for struct in self.structs: - current_start = struct["start"] - current_end = struct["end"] - if (current_start <= offset < current_end) and ( - current_start >= start and current_end <= end - ): - start = current_start - end = current_end - parent = struct - - if self.version < 3.8 and op == self.opc.SETUP_LOOP: - # We categorize loop types: 'for', 'while', 'while 1' with - # possibly suffixes '-loop' and '-else' - # Try to find the jump_back instruction of the loop. - # It could be a return instruction. - - start += inst.inst_size - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.setup_loops[target] = offset - - if target != end: - self.fixed_jumps[offset] = end - - (line_no, next_line_byte) = self.lines[offset] - jump_back = self.last_instr( - start, end, self.opc.JUMP_ABSOLUTE, next_line_byte, False - ) - - if jump_back: - jump_forward_offset = xdis.next_offset( - code[jump_back], self.opc, jump_back - ) - else: - jump_forward_offset = None - - return_val_offset1 = self.prev[self.prev[end]] - - if ( - jump_back - and jump_back != self.prev_op[end] - and self.is_jump_forward(jump_forward_offset) - ): - if code[self.prev_op[end]] == self.opc.RETURN_VALUE or ( - code[self.prev_op[end]] == self.opc.POP_BLOCK - and code[return_val_offset1] == self.opc.RETURN_VALUE - ): - jump_back = None - if not jump_back: - # loop suite ends in return - jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE) - if not jump_back: - return - - jb_inst = self.get_inst(jump_back) - jump_back = self.next_offset(jb_inst.opcode, jump_back) - - if_offset = None - if code[self.prev_op[next_line_byte]] not in self.pop_jump_tf: - if_offset = self.prev[next_line_byte] - if if_offset: - loop_type = "while" - self.ignore_if.add(if_offset) - else: - loop_type = "for" - target = next_line_byte - end = xdis.next_offset(code[jump_back], self.opc, jump_back) - else: - if self.get_target(jump_back) >= next_line_byte: - jump_back = self.last_instr( - start, end, self.opc.JUMP_ABSOLUTE, start, False - ) - - jb_inst = self.get_inst(jump_back) - - jb_next_offset = self.next_offset(jb_inst.opcode, jump_back) - if end > jb_next_offset and self.is_jump_forward(end): - if self.is_jump_forward(jb_next_offset): - if self.get_target(jb_next_offset) == self.get_target(end): - self.fixed_jumps[offset] = jb_next_offset - end = jb_next_offset - elif target < offset: - self.fixed_jumps[offset] = jb_next_offset - end = jb_next_offset - - target = self.get_target(jump_back) - - if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER): - loop_type = "for" - else: - loop_type = "while" - test = self.prev_op[next_line_byte] - - if test == offset: - loop_type = "while 1" - 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): - jump_back = test_target - self.not_continue.add(jump_back) - self.loops.append(target) - self.structs.append( - {"type": loop_type + "-loop", "start": target, "end": jump_back} - ) - after_jump_offset = xdis.next_offset(code[jump_back], self.opc, jump_back) - if after_jump_offset != end: - self.structs.append( - { - "type": loop_type + "-else", - "start": after_jump_offset, - "end": end, - } - ) - elif op in self.pop_jump_tf: - target = inst.argval - if self.version == 3.3: - self.fixed_jumps[offset] = target - return - - start = offset + inst.inst_size - rtarget = self.restrict_to_parent(target, parent) - prev_op = self.prev_op - - # Do not let jump to go out of parent struct bounds - if target != rtarget and parent["type"] == "and/or": - self.fixed_jumps[offset] = rtarget - return - - # Does this jump to right after another conditional jump that is - # not myself? If so, it's part of a larger conditional. - # rocky: if we have a conditional jump to the next instruction, then - # possibly I am "skipping over" a "pass" or null statement. - pretarget = self.get_inst(prev_op[target]) - - if ( - pretarget.opcode in self.pop_jump_if_pop - and (target > offset) - and pretarget.offset != offset - ): - - # FIXME: hack upon hack... - # In some cases the pretarget can be a jump to the next instruction - # and these aren't and/or's either. We limit to 3.5+ since we experienced there - # but it might be earlier versions, or might be a general principle. - if self.version < 3.5 or pretarget.argval != target: - # FIXME: this is not accurate The commented out below - # is what it should be. However grammar rules right now - # assume the incorrect offsets. - # self.fixed_jumps[offset] = target - self.fixed_jumps[offset] = pretarget.offset - self.structs.append( - {"type": "and/or", "start": start, "end": pretarget.offset} - ) - return - - # The opcode *two* instructions before the target jump offset is important - # in making a determination of what we have. Save that. - pre_rtarget = prev_op[rtarget] - - # Is it an "and" inside an "if" or "while" block - if op == self.opc.POP_JUMP_IF_FALSE: - - # Search for another POP_JUMP_IF_FALSE targetting the same op, - # in current statement, starting from current offset, and filter - # everything inside inner 'or' jumps and midline ifs - match = self.rem_or( - start, self.next_stmt[offset], self.opc.POP_JUMP_IF_FALSE, target - ) - - # If we still have any offsets in set, start working on it - if match: - is_jump_forward = self.is_jump_forward(pre_rtarget) - if ( - is_jump_forward - and pre_rtarget not in self.stmts - and self.restrict_to_parent( - self.get_target(pre_rtarget), parent - ) - == rtarget - ): - if ( - code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE - and self.remove_mid_line_ifs([offset]) - and target == self.get_target(prev_op[pre_rtarget]) - and ( - prev_op[pre_rtarget] not in self.stmts - or self.get_target(prev_op[pre_rtarget]) - > prev_op[pre_rtarget] - ) - and 1 - == len( - self.remove_mid_line_ifs( - self.rem_or( - start, - prev_op[pre_rtarget], - self.pop_jump_tf, - target, - ) - ) - ) - ): - pass - elif ( - code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE - and self.remove_mid_line_ifs([offset]) - and 1 - == ( - len( - set( - self.remove_mid_line_ifs( - self.rem_or( - start, - prev_op[pre_rtarget], - self.pop_jump_tf, - target, - ) - ) - ) - | set( - self.remove_mid_line_ifs( - self.rem_or( - start, - prev_op[pre_rtarget], - ( - self.opc.POP_JUMP_IF_FALSE, - self.opc.POP_JUMP_IF_TRUE, - self.opc.JUMP_ABSOLUTE, - ), - pre_rtarget, - True, - ) - ) - ) - ) - ) - ): - pass - else: - fix = None - jump_ifs = self.inst_matches( - start, - self.next_stmt[offset], - self.opc.POP_JUMP_IF_FALSE, - ) - last_jump_good = True - for j in jump_ifs: - if target == self.get_target(j): - # FIXME: remove magic number - if self.lines[j].next == j + 3 and last_jump_good: - fix = j - break - else: - last_jump_good = False - self.fixed_jumps[offset] = fix or match[-1] - return - else: - if self.version < 3.6: - # FIXME: this is putting in COME_FROMs in the wrong place. - # Fix up grammar so we don't need to do this. - # See cf_for_iter use in parser36.py - self.fixed_jumps[offset] = match[-1] - elif target > offset: - # Right now we only add COME_FROMs in forward (not loop) jumps - self.fixed_jumps[offset] = target - return - # op == POP_JUMP_IF_TRUE - else: - next = self.next_stmt[offset] - if prev_op[next] == offset: - pass - elif self.is_jump_forward(next) and target == self.get_target(next): - if code[prev_op[next]] == self.opc.POP_JUMP_IF_FALSE: - if ( - code[next] == self.opc.JUMP_FORWARD - or target != rtarget - or code[prev_op[pre_rtarget]] - not in (self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE) - ): - self.fixed_jumps[offset] = prev_op[next] - return - elif ( - code[next] == self.opc.JUMP_ABSOLUTE - and self.is_jump_forward(target) - and self.get_target(target) == self.get_target(next) - ): - self.fixed_jumps[offset] = prev_op[next] - return - - # Don't add a struct for a while test, it's already taken care of - if offset in self.ignore_if: - return - - rtarget_is_ja = code[pre_rtarget] == self.opc.JUMP_ABSOLUTE - if ( - rtarget_is_ja - and pre_rtarget in self.stmts - and pre_rtarget != offset - and prev_op[pre_rtarget] != offset - and not ( - code[rtarget] == self.opc.JUMP_ABSOLUTE - and code[rtarget + 3] == self.opc.POP_BLOCK - and code[prev_op[pre_rtarget]] != self.opc.JUMP_ABSOLUTE - ) - ): - rtarget = pre_rtarget - - # Does the "jump if" jump beyond a jump op? - # That is, we have something like: - # POP_JUMP_IF_FALSE HERE - # ... - # JUMP_FORWARD - # HERE: - # - # If so, this can be block inside an "if" statement - # or a conditional assignment like: - # x = 1 if x else 2 - # - # For 3.5, in addition the JUMP_FORWARD above we could have - # JUMP_BACK or CONTINUE - # - # There are other situations we may need to consider, like - # if the condition jump is to a forward location. - # Also the existence of a jump to the instruction after "END_FINALLY" - # will distinguish "try/else" from "try". - if self.version < 3.8: - rtarget_break = (self.opc.RETURN_VALUE, self.opc.BREAK_LOOP) - else: - rtarget_break = (self.opc.RETURN_VALUE,) - - if self.is_jump_forward(pre_rtarget) or ( - rtarget_is_ja and self.version >= 3.5 - ): - if_end = self.get_target(pre_rtarget) - - # If the jump target is back, we are looping - if ( - if_end < pre_rtarget - and self.version < 3.8 - and (code[prev_op[if_end]] == self.opc.SETUP_LOOP) - ): - if if_end > start: - return - - end = self.restrict_to_parent(if_end, parent) - - self.structs.append( - {"type": "if-then", "start": start, "end": pre_rtarget} - ) - - # FIXME: add this - # self.fixed_jumps[offset] = rtarget - self.not_continue.add(pre_rtarget) - - if rtarget < end and ( - code[rtarget] not in (self.opc.END_FINALLY, self.opc.JUMP_ABSOLUTE) - and code[prev_op[pre_rtarget]] - not in (self.opc.POP_EXCEPT, self.opc.END_FINALLY) - ): - self.structs.append({"type": "else", "start": rtarget, "end": end}) - self.else_start[rtarget] = end - elif self.is_jump_back(pre_rtarget, 0): - if_end = rtarget - self.structs.append( - {"type": "if-then", "start": start, "end": pre_rtarget} - ) - self.not_continue.add(pre_rtarget) - elif code[pre_rtarget] in rtarget_break: - self.structs.append({"type": "if-then", "start": start, "end": rtarget}) - # It is important to distingish if this return is inside some sort - # except block return - jump_prev = prev_op[offset] - if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP: - if self.opc.cmp_op[code[jump_prev + 1]] == "exception-match": - return - if self.version >= 3.5: - # Python 3.5 may remove as dead code a JUMP - # instruction after a RETURN_VALUE. So we check - # based on seeing SETUP_EXCEPT various places. - if self.version < 3.6 and code[rtarget] == self.opc.SETUP_EXCEPT: - return - # Check that next instruction after pops and jump is - # not from SETUP_EXCEPT - next_op = rtarget - if code[next_op] == self.opc.POP_BLOCK: - next_op += instruction_size(self.code[next_op], self.opc) - if code[next_op] == self.opc.JUMP_ABSOLUTE: - next_op += instruction_size(self.code[next_op], self.opc) - if next_op in targets: - for try_op in targets[next_op]: - come_from_op = code[try_op] - if ( - self.version < 3.8 - and come_from_op == self.opc.SETUP_EXCEPT - ): - return - pass - pass - - if self.version >= 3.4: - self.fixed_jumps[offset] = rtarget - - if code[pre_rtarget] == self.opc.RETURN_VALUE: - # If we are at some sort of POP_JUMP_IF and the instruction before was - # COMPARE_OP exception-match, then pre_rtarget is not an end_if - if not ( - inst_index > 0 - and self.insts[inst_index - 1].argval == "exception-match" - ): - self.return_end_ifs.add(pre_rtarget) - else: - self.fixed_jumps[offset] = rtarget - self.not_continue.add(pre_rtarget) - else: - - # FIXME: this is very convoluted and based on rather hacky - # empirical evidence. It should go a way when - # we have better control-flow analysis - normal_jump = self.version >= 3.6 - if self.version == 3.5: - j = self.offset2inst_index[target] - if j + 2 < len(self.insts) and self.insts[j + 2].is_jump_target: - normal_jump = self.insts[j + 1].opname == "POP_BLOCK" - - if normal_jump: - # For now, we'll only tag forward jump. - if target > offset: - self.fixed_jumps[offset] = target - pass - else: - # FIXME: This is probably a bug in < 3.5 and we should - # instead use the above code. But until we smoke things - # out we'll stick with it. - if rtarget > offset: - self.fixed_jumps[offset] = rtarget - - elif self.version < 3.8 and op == self.opc.SETUP_EXCEPT: - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.fixed_jumps[offset] = end - elif op == self.opc.POP_EXCEPT: - next_offset = xdis.next_offset(op, self.opc, offset) - target = self.get_target(next_offset) - if target > next_offset: - next_op = code[next_offset] - if ( - self.opc.JUMP_ABSOLUTE == next_op - and self.opc.END_FINALLY - != code[xdis.next_offset(next_op, self.opc, next_offset)] - ): - self.fixed_jumps[next_offset] = target - self.except_targets[target] = next_offset - - elif op == self.opc.SETUP_FINALLY: - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.fixed_jumps[offset] = end - elif op in self.jump_if_pop: - target = self.get_target(offset) - if target > offset: - unop_target = self.last_instr( - offset, target, self.opc.JUMP_FORWARD, target - ) - if unop_target and code[unop_target + 3] != self.opc.ROT_TWO: - self.fixed_jumps[offset] = unop_target - else: - self.fixed_jumps[offset] = self.restrict_to_parent(target, parent) - pass - pass - elif self.version >= 3.5: - # 3.5+ has Jump optimization which too often causes RETURN_VALUE to get - # misclassified as RETURN_END_IF. Handle that here. - # In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF - if op == self.opc.RETURN_VALUE: - next_offset = xdis.next_offset(op, self.opc, offset) - if next_offset < len(code) and ( - code[next_offset] == self.opc.JUMP_ABSOLUTE - and offset in self.return_end_ifs - ): - self.return_end_ifs.remove(offset) - pass - pass - elif op == self.opc.JUMP_FORWARD: - # If we have: - # JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x: - # then RETURN_VALUE is not RETURN_END_IF - rtarget = self.get_target(offset) - rtarget_prev = self.prev[rtarget] - if ( - code[rtarget_prev] == self.opc.RETURN_VALUE - and rtarget_prev in self.return_end_ifs - ): - i = rtarget_prev - while i != offset: - if code[i] in [op3.JUMP_FORWARD, op3.JUMP_ABSOLUTE]: - return - i = self.prev[i] - self.return_end_ifs.remove(rtarget_prev) - pass - return - - def is_jump_back(self, offset, extended_arg): - """ - Return True if the code at offset is some sort of jump back. - That is, it is ether "JUMP_FORWARD" or an absolute jump that - goes forward. - """ - if self.code[offset] != self.opc.JUMP_ABSOLUTE: - return False - return offset > self.get_target(offset, extended_arg) - - def next_except_jump(self, start): - """ - Return the next jump that was generated by an except SomeException: - construct in a try...except...else clause or None if not found. - """ - - if self.code[start] == self.opc.DUP_TOP: - except_match = self.first_instr( - start, len(self.code), self.opc.POP_JUMP_IF_FALSE - ) - if except_match: - jmp = self.prev_op[self.get_target(except_match)] - self.ignore_if.add(except_match) - self.not_continue.add(jmp) - return jmp - - count_END_FINALLY = 0 - count_SETUP_ = 0 - for i in self.op_range(start, len(self.code)): - op = self.code[i] - if op == self.opc.END_FINALLY: - if count_END_FINALLY == count_SETUP_: - assert self.code[self.prev_op[i]] in frozenset( - [ - self.opc.JUMP_ABSOLUTE, - self.opc.JUMP_FORWARD, - self.opc.RETURN_VALUE, - ] - ) - self.not_continue.add(self.prev_op[i]) - return self.prev_op[i] - count_END_FINALLY += 1 - elif op in self.setup_opts_no_loop: - count_SETUP_ += 1 - - def rem_or(self, start, end, instr, target=None, include_beyond_target=False): - """ - Find offsets of all requested between and , - optionally ing specified offset, and return list found - offsets which are not within any POP_JUMP_IF_TRUE jumps. - """ - assert start >= 0 and end <= len(self.code) and start <= end - - # Find all offsets of requested instructions - instr_offsets = self.inst_matches( - start, end, instr, target, include_beyond_target - ) - # Get all POP_JUMP_IF_TRUE (or) offsets - if self.version == 3.0: - jump_true_op = self.opc.JUMP_IF_TRUE - else: - jump_true_op = self.opc.POP_JUMP_IF_TRUE - pjit_offsets = self.inst_matches(start, end, jump_true_op) - filtered = [] - for pjit_offset in pjit_offsets: - pjit_tgt = self.get_target(pjit_offset) - 3 - for instr_offset in instr_offsets: - if instr_offset <= pjit_offset or instr_offset >= pjit_tgt: - filtered.append(instr_offset) - instr_offsets = filtered - filtered = [] - return instr_offsets - - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - - if PYTHON_VERSION >= 3.2: - import inspect - - co = inspect.currentframe().f_code - from uncompyle6 import PYTHON_VERSION - - tokens, customize = Scanner3(PYTHON_VERSION).ingest(co) - for t in tokens: - print(t) - else: - print("Need to be Python 3.2 or greater to demo; I am %s." % PYTHON_VERSION) - pass diff --git a/uncompyle6/scanners/scanner30.py-try b/uncompyle6/scanners/scanner30.py-try deleted file mode 100644 index 6c65aabd5..000000000 --- a/uncompyle6/scanners/scanner30.py-try +++ /dev/null @@ -1,454 +0,0 @@ -# Copyright (c) 2016, 2017 by Rocky Bernstein -""" -Python 3.0 bytecode scanner/deparser - -This sets up opcodes Python's 3.0 and calls a generalized -scanner routine for Python 3. -""" - -from __future__ import print_function - -# bytecode verification, verify(), uses JUMP_OPs from here -from xdis.opcodes import opcode_30 as opc -from xdis.bytecode import instruction_size, next_offset -import xdis - -JUMP_TF = frozenset([opc.JUMP_IF_FALSE, opc.JUMP_IF_TRUE]) - -from uncompyle6.scanners.scanner3 import Scanner3 -class Scanner30(Scanner3): - - def __init__(self, show_asm=None, is_pypy=False): - Scanner3.__init__(self, 3.0, show_asm, is_pypy) - self.thens = {} # JUMP_IF's that separate the 'then' part of an 'if' - return - pass - - def detect_control_flow(self, offset, targets, inst_index): - """ - Detect structures and their boundaries to fix optimized jumps - Python 3.0 is more like Python 2.6 than it is Python 3.x. - So we have a special routine here. - """ - - code = self.code - op = code[offset] - - # Detect parent structure - parent = self.structs[0] - start = parent['start'] - end = parent['end'] - - # Pick inner-most parent for our offset - for struct in self.structs: - current_start = struct['start'] - current_end = struct['end'] - if ((current_start <= offset < current_end) - and (current_start >= start and current_end <= end)): - start = current_start - end = current_end - parent = struct - - if op == self.opc.SETUP_LOOP: - # We categorize loop types: 'for', 'while', 'while 1' with - # possibly suffixes '-loop' and '-else' - # Try to find the jump_back instruction of the loop. - # It could be a return instruction. - - start += instruction_size(op, self.opc) - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.setup_loop_targets[offset] = target - self.setup_loops[target] = offset - - if target != end: - self.fixed_jumps[offset] = end - - (line_no, next_line_byte) = self.lines[offset] - jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, - next_line_byte, False) - - if jump_back: - jump_forward_offset = next_offset(code[jump_back], self.opc, jump_back) - else: - jump_forward_offset = None - - return_val_offset1 = self.prev[self.prev[end]] - - if (jump_back and jump_back != self.prev_op[end] - and self.is_jump_forward(jump_forward_offset)): - if (code[self.prev_op[end]] == self.opc.RETURN_VALUE or - (code[self.prev_op[end]] == self.opc.POP_BLOCK - and code[return_val_offset1] == self.opc.RETURN_VALUE)): - jump_back = None - if not jump_back: - # loop suite ends in return - jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE) - if not jump_back: - return - - jump_back += 2 - if_offset = None - if code[self.prev_op[next_line_byte]] not in JUMP_TF: - if_offset = self.prev[next_line_byte] - if if_offset: - loop_type = 'while' - self.ignore_if.add(if_offset) - else: - loop_type = 'for' - target = next_line_byte - end = jump_back + 3 - else: - if self.get_target(jump_back, 0) >= next_line_byte: - jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, start, False) - if end > jump_back+4 and self.is_jump_forward(end): - if self.is_jump_forward(jump_back+4): - if self.get_target(jump_back+4) == self.get_target(end): - self.fixed_jumps[offset] = jump_back+4 - end = jump_back+4 - elif target < offset: - self.fixed_jumps[offset] = jump_back+4 - end = jump_back+4 - - target = self.get_target(jump_back, 0) - - if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER): - loop_type = 'for' - else: - loop_type = 'while' - test = self.prev_op[next_line_byte] - - if test == offset: - loop_type = 'while 1' - 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): - jump_back = test_target - self.not_continue.add(jump_back) - self.loops.append(target) - self.structs.append({'type': loop_type + '-loop', - 'start': target, - 'end': jump_back}) - after_jump_offset = xdis.next_offset(code[jump_back], self.opc, jump_back) - if after_jump_offset != end: - self.structs.append({'type': loop_type + '-else', - 'start': after_jump_offset, - 'end': end}) - elif op in self.pop_jump_tf: - start = offset + instruction_size(op, self.opc) - target = self.get_target(offset) - rtarget = self.restrict_to_parent(target, parent) - prev_op = self.prev_op - - # Do not let jump to go out of parent struct bounds - if target != rtarget and parent['type'] == 'and/or': - self.fixed_jumps[offset] = rtarget - return - - # Does this jump to right after another conditional jump that is - # not myself? If so, it's part of a larger conditional. - # rocky: if we have a conditional jump to the next instruction, then - # possibly I am "skipping over" a "pass" or null statement. - - if ((code[prev_op[target]] in self.pop_jump_if_pop) and - (target > offset) and prev_op[target] != offset): - self.fixed_jumps[offset] = prev_op[target] - self.structs.append({'type': 'and/or', - 'start': start, - 'end': prev_op[target]}) - return - - # The op offset just before the target jump offset is important - # in making a determination of what we have. Save that. - pre_rtarget = prev_op[rtarget] - - # Is it an "and" inside an "if" or "while" block - if op == opc.JUMP_IF_FALSE: - - # Search for another JUMP_IF_FALSE targetting the same op, - # in current statement, starting from current offset, and filter - # everything inside inner 'or' jumps and midline ifs - match = self.rem_or(start, self.next_stmt[offset], - opc.JUMP_IF_FALSE, target) - - # If we still have any offsets in set, start working on it - if match: - is_jump_forward = self.is_jump_forward(pre_rtarget) - if (is_jump_forward and pre_rtarget not in self.stmts and - self.restrict_to_parent(self.get_target(pre_rtarget), parent) == rtarget): - if (code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE - and self.remove_mid_line_ifs([offset]) and - target == self.get_target(prev_op[pre_rtarget]) and - (prev_op[pre_rtarget] not in self.stmts or - self.get_target(prev_op[pre_rtarget]) > prev_op[pre_rtarget]) and - 1 == len(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], JUMP_TF, target)))): - pass - elif (code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE - and self.remove_mid_line_ifs([offset]) and - 1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], - JUMP_TF, target))) | - set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], - (opc.JUMP_IF_FALSE, - opc.JUMP_IF_TRUE, - opc.JUMP_ABSOLUTE), - pre_rtarget, True)))))): - pass - else: - fix = None - jump_ifs = self.inst_matches(start, self.next_stmt[offset], - opc.JUMP_IF_FALSE) - last_jump_good = True - for j in jump_ifs: - if target == self.get_target(j): - # FIXME: remove magic number - if self.lines[j].next == j + 3 and last_jump_good: - fix = j - break - else: - last_jump_good = False - self.fixed_jumps[offset] = fix or match[-1] - return - else: - self.fixed_jumps[offset] = match[-1] - return - # op == JUMP_IF_TRUE - else: - next = self.next_stmt[offset] - if prev_op[next] == offset: - pass - elif self.is_jump_forward(next) and target == self.get_target(next): - if code[prev_op[next]] == opc.JUMP_IF_FALSE: - if (code[next] == self.opc.JUMP_FORWARD - or target != rtarget - or code[prev_op[pre_rtarget]] not in - (self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE)): - self.fixed_jumps[offset] = prev_op[next] - return - elif (code[next] == self.opc.JUMP_ABSOLUTE and self.is_jump_forward(target) and - self.get_target(target) == self.get_target(next)): - self.fixed_jumps[offset] = prev_op[next] - return - - # Don't add a struct for a while test, it's already taken care of - if offset in self.ignore_if: - return - - if (code[pre_rtarget] == self.opc.JUMP_ABSOLUTE and - pre_rtarget in self.stmts and - pre_rtarget != offset and - prev_op[pre_rtarget] != offset and - not (code[rtarget] == self.opc.JUMP_ABSOLUTE and - code[rtarget+3] == self.opc.POP_BLOCK and - code[prev_op[pre_rtarget]] != self.opc.JUMP_ABSOLUTE)): - rtarget = pre_rtarget - - # Does the "jump if" jump beyond a jump op? - # That is, we have something like: - # JUMP_IF_FALSE HERE - # ... - # JUMP_FORWARD - # HERE: - # - # If so, this can be block inside an "if" statement - # or a conditional assignment like: - # x = 1 if x else 2 - # - # There are other contexts we may need to consider - # like whether the target is "END_FINALLY" - # or if the condition jump is to a forward location - if self.is_jump_forward(pre_rtarget): - if_end = self.get_target(pre_rtarget, 0) - - # If the jump target is back, we are looping - if (if_end < pre_rtarget and - (code[prev_op[if_end]] == self.opc.SETUP_LOOP)): - if (if_end > start): - return - - end = self.restrict_to_parent(if_end, parent) - - if_then_maybe = None - from trepan.api import debug; debug() - - if self.version == 3.0: - # Take the JUMP_IF target. In an "if/then", it will be - # a POP_TOP instruction and the instruction before it - # will be a JUMP_FORWARD to just after the POP_TOP. - # For example: - # Good: - # 3 JUMP_IF_FALSE 33 'to 39' - # .. - # 36 JUMP_FORWARD 1 'to 40' - # 39 POP_TOP - # 40 ... - # example: - - # BAD (is an "and"): - # 28 JUMP_IF_FALSE 4 'to 35' - # ... - # 32 JUMP_ABSOLUTE 40 'to 40' # should be 36 or there should - # # be a COME_FROM at the pop top - # # before 40 to 35 - # 35 POP_TOP - # 36 ... - # 39 POP_TOP - # 39_0 COME_FROM 3 - # 40 ... - - jump_if_offset = offset - if self.opname_for_offset(jump_if_offset).startswith('JUMP_IF'): - jump_if_target = code[jump_if_offset+1] - if self.opname_for_offset(jump_if_target + jump_if_offset + 3) == 'POP_TOP': - jump_inst = jump_if_target + jump_if_offset - jump_offset = code[jump_inst+1] - jump_op = self.opname_for_offset(jump_inst) - if (jump_op == 'JUMP_FORWARD' and jump_offset == 1): - self.structs.append({'type': 'if-then', - 'start': start-3, - 'end': pre_rtarget}) - self.thens[start] = end - elif jump_op == 'JUMP_ABSOLUTE': - if_then_maybe = {'type': 'if-then', - 'start': start-3, - 'end': pre_rtarget} - - self.structs.append({'type': 'if-then', - 'start': start, - 'end': pre_rtarget}) - self.not_continue.add(pre_rtarget) - - if rtarget < end: - # We have an "else" block of some kind. - # Is it associated with "if_then_maybe" seen above? - # These will be linked in this funny way: - - # 198 JUMP_IF_FALSE 18 'to 219' - # 201 POP_TOP - # ... - # 216 JUMP_ABSOLUTE 256 'to 256' - # 219 POP_TOP - # ... - # 252 JUMP_FORWARD 1 'to 256' - # 255 POP_TOP - # 256 - if if_then_maybe and jump_op == 'JUMP_ABSOLUTE': - jump_target = self.get_target(jump_inst, code[jump_inst]) - if self.opname_for_offset(end) == 'JUMP_FORWARD': - end_target = self.get_target(end, code[end]) - if jump_target == end_target: - self.structs.append(if_then_maybe) - self.thens[start] = end - - self.structs.append({'type': 'else', - 'start': rtarget, - 'end': end}) - - elif self.is_jump_back(pre_rtarget, 0): - if_end = rtarget - self.structs.append({'type': 'if-then', - 'start': start, - 'end': pre_rtarget}) - self.not_continue.add(pre_rtarget) - elif code[pre_rtarget] in (self.opc.RETURN_VALUE, - self.opc.BREAK_LOOP): - self.structs.append({'type': 'if-then', - 'start': start, - 'end': rtarget}) - # It is important to distingish if this return is inside some sort - # except block return - jump_prev = prev_op[offset] - if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP: - if self.opc.cmp_op[code[jump_prev+1]] == 'exception-match': - return - if self.version >= 3.5: - # Python 3.5 may remove as dead code a JUMP - # instruction after a RETURN_VALUE. So we check - # based on seeing SETUP_EXCEPT various places. - if code[rtarget] == self.opc.SETUP_EXCEPT: - return - # Check that next instruction after pops and jump is - # not from SETUP_EXCEPT - next_op = rtarget - if code[next_op] == self.opc.POP_BLOCK: - next_op += instruction_size(self.code[next_op], self.opc) - if code[next_op] == self.opc.JUMP_ABSOLUTE: - next_op += instruction_size(self.code[next_op], self.opc) - if next_op in targets: - for try_op in targets[next_op]: - come_from_op = code[try_op] - if come_from_op == self.opc.SETUP_EXCEPT: - return - pass - pass - if code[pre_rtarget] == self.opc.RETURN_VALUE: - if self.version == 3.0: - next_op = rtarget - if code[next_op] == self.opc.POP_TOP: - next_op = rtarget - next_op += instruction_size(self.code[next_op], self.opc) - if code[next_op] == self.opc.POP_BLOCK: - return - self.return_end_ifs.add(pre_rtarget) - else: - self.fixed_jumps[offset] = rtarget - self.not_continue.add(pre_rtarget) - - - elif op == self.opc.SETUP_EXCEPT: - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.fixed_jumps[offset] = end - elif op == self.opc.SETUP_FINALLY: - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - self.fixed_jumps[offset] = end - elif op in self.jump_if_pop: - target = self.get_target(offset) - if target > offset: - unop_target = self.last_instr(offset, target, self.opc.JUMP_FORWARD, target) - if unop_target and code[unop_target+3] != self.opc.ROT_TWO: - self.fixed_jumps[offset] = unop_target - else: - self.fixed_jumps[offset] = self.restrict_to_parent(target, parent) - pass - pass - elif self.version >= 3.5: - # 3.5+ has Jump optimization which too often causes RETURN_VALUE to get - # misclassified as RETURN_END_IF. Handle that here. - # In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF - if op == self.opc.RETURN_VALUE: - if (offset+1 < len(code) and code[offset+1] == self.opc.JUMP_ABSOLUTE and - offset in self.return_end_ifs): - self.return_end_ifs.remove(offset) - pass - pass - elif op == self.opc.JUMP_FORWARD: - # If we have: - # JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x: - # then RETURN_VALUE is not RETURN_END_IF - rtarget = self.get_target(offset) - rtarget_prev = self.prev[rtarget] - if (code[rtarget_prev] == self.opc.RETURN_VALUE and - rtarget_prev in self.return_end_ifs): - i = rtarget_prev - while i != offset: - if code[i] in [opc.JUMP_FORWARD, opc.JUMP_ABSOLUTE]: - return - i = self.prev[i] - self.return_end_ifs.remove(rtarget_prev) - pass - return - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - if PYTHON_VERSION == 3.0: - import inspect - co = inspect.currentframe().f_code - tokens, customize = Scanner30().ingest(co) - for t in tokens: - print(t) - pass - else: - print("Need to be Python 3.0 to demo; I am %s." % - PYTHON_VERSION) From 32114b5550c851faf7e330e1fa728371af81ee8d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 4 Jul 2022 07:32:49 -0400 Subject: [PATCH 318/489] Python 2.4 tolerance --- test/test_pythonlib.py | 8 ++++++-- uncompyle6/semantics/customize38.py | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 462b509ab..25c31441e 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -31,11 +31,15 @@ from fnmatch import fnmatch from uncompyle6.main import main -from xdis.version_info import PYTHON_VERSION +from xdis.version_info import PYTHON_VERSION, PYTHON_VERSION_TRIPLE def get_srcdir(): - filename = os.path.normcase(os.path.dirname(__file__)) + if PYTHON_VERSION_TRIPLE < (2, 5): + def five(): return 5 + filename = five.func_code.co_filename + else: + filename = os.path.normcase(os.path.dirname(__file__)) return os.path.realpath(filename) diff --git a/uncompyle6/semantics/customize38.py b/uncompyle6/semantics/customize38.py index 0e6e5e70e..6a069aefd 100644 --- a/uncompyle6/semantics/customize38.py +++ b/uncompyle6/semantics/customize38.py @@ -252,7 +252,10 @@ def n_list_afor(node): # list_afor ::= get_iter list_afor self.comprehension_walk_newer(node, 0) else: - list_iter_index = 2 if node[2] == "list_iter" else 3 + if node[2] == "list_iter": + list_iter_index = 2 + else: + list_iter_index = 3 self.template_engine( ( " async for %[1]{%c} in %c%[1]{%c}", From d03a4235df2df444685f105cde5db6731eb4eede Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 7 Jul 2022 01:58:40 -0400 Subject: [PATCH 319/489] pre 3.6 tolerance --- uncompyle6/semantics/customize38.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/customize38.py b/uncompyle6/semantics/customize38.py index 02ae50896..4c6c17f38 100644 --- a/uncompyle6/semantics/customize38.py +++ b/uncompyle6/semantics/customize38.py @@ -322,7 +322,7 @@ def n_formatted_value_debug(node): f_conversion = self.traverse(formatted_value, indent="") # Remove leaving "f" and quotes conversion = strip_quotes(f_conversion[1:]) - f_str = "f%s" % escape_string(f"{value_equal}{conversion}" + post_str) + f_str = "f%s" % escape_string(("%s%s" % (value_equal, conversion)) + post_str) self.write(f_str) self.in_format_string = old_in_format_string From 930d03ab07d07b766099b0b0a92d1d01198ab548 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 7 Jul 2022 02:10:26 -0400 Subject: [PATCH 320/489] 3.5- tolerance --- uncompyle6/parsers/reducecheck/iflaststmt.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uncompyle6/parsers/reducecheck/iflaststmt.py b/uncompyle6/parsers/reducecheck/iflaststmt.py index 3fc778d31..29349cd18 100644 --- a/uncompyle6/parsers/reducecheck/iflaststmt.py +++ b/uncompyle6/parsers/reducecheck/iflaststmt.py @@ -13,9 +13,7 @@ # along with this program. If not, see . -def iflaststmt( - self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int -) -> bool: +def iflaststmt(self, lhs, n, rule, tree, tokens, first, last): testexpr = tree[0] if testexpr[0] in ("testtrue", "testfalse"): From 507a75461684c22916a4d14131756506e7d19f63 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 7 Jul 2022 02:22:16 -0400 Subject: [PATCH 321/489] 2.4 tolerance --- test/simple_source/bug14/lambda.py | 17 +++++++++++++++++ .../parsers/reducecheck/joined_str_check.py | 4 +--- 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 test/simple_source/bug14/lambda.py diff --git a/test/simple_source/bug14/lambda.py b/test/simple_source/bug14/lambda.py new file mode 100644 index 000000000..f5c9ce36f --- /dev/null +++ b/test/simple_source/bug14/lambda.py @@ -0,0 +1,17 @@ +palette = map(lambda a:(a, + a, + a) +, range(256)) +palette = map(lambda (r, g, b,):((chr(r) + chr(g)) + chr(b)) +, palette) +palette = map(lambda r:r +, palette) +palette = lambda (r, g, b,):r + +palette = lambda (r):r + +palette = lambda r:r + +palette = (lambda (r):r +, + palette) diff --git a/uncompyle6/parsers/reducecheck/joined_str_check.py b/uncompyle6/parsers/reducecheck/joined_str_check.py index 96ddc7b96..d045ae399 100644 --- a/uncompyle6/parsers/reducecheck/joined_str_check.py +++ b/uncompyle6/parsers/reducecheck/joined_str_check.py @@ -13,9 +13,7 @@ # along with this program. If not, see . -def joined_str_ok( - self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int -) -> bool: +def joined_str_ok(self, lhs, n, rule, tree, tokens, first, last): # In Python 3.8, there is a new "=" specifier. # See https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging # We detect this here inside joined_str by looking for an From 4789ae0d94bf10c0fc7dd250c3ff9e39957ba03d Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 23 Aug 2022 08:10:07 -0400 Subject: [PATCH 322/489] 2.6 runtest adjustments FOr some tests PYTHON needs to be set to pytest --- test/stdlib/2.6-exclude.sh | 5 +---- test/stdlib/runtests.sh | 7 +++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index 298623268..5653f32f6 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -7,9 +7,7 @@ SKIP_TESTS=( # assert 0 # shouldn't reach here. [test_shutil.py]=1 - [test___all__.py]=1 # it fails on its own [test___all__.py]=1 # it fails on its own - [test_aepack.py]=1 # Fails on its own [test_aepack.py]=1 # it fails on its own [test_al.py]=1 # it fails on its own [test_anydbm.py]=1 # it fails on its own @@ -59,7 +57,7 @@ SKIP_TESTS=( [test_ossaudiodev.py]=1 # it fails on its own [test_pep277.py]=1 # it fails on its own - [test_pyclbr.py]=1 # Investigate + [test_pyclbr.py]=1 # it fails on its own [test_py3kwarn.py]=1 # it fails on its own [test_scriptpackages.py]=1 # it fails on its own @@ -85,7 +83,6 @@ SKIP_TESTS=( [test_zipimport_support.py]=1 [test_zipfile64.py]=1 # Skip Long test - [test_zlib.py]=1 # # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc # .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc ) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 1b3e579df..018913099 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -1,6 +1,9 @@ #!/bin/bash me=${BASH_SOURCE[0]} +# Note: for 2.6 sometimes we need to set PYTHON=pytest +PYTHON=${PYTHON:-python} + typeset -i BATCH=${BATCH:-0} if (( ! BATCH )) ; then isatty=$(/usr/bin/tty 2>/dev/null) @@ -191,7 +194,7 @@ for file in $files; do if [ ! -r $file ]; then echo "Skipping test $file -- not readable. Does it exist?" continue - elif ! python $file >/dev/null 2>&1 ; then + elif ! $PYTHON $file >/dev/null 2>&1 ; then echo "Skipping test $file -- it fails on its own" continue fi @@ -214,7 +217,7 @@ for file in $files; do rc=$? if (( rc == 0 )) ; then echo ========== $(date +%X) Running $file =========== - timeout_cmd python $file + timeout_cmd $PYTHON $file rc=$? else echo ======= Skipping $file due to compile/decompile errors ======== From 55368c8b295e12a320487b1c766b7f699fe47912 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 23 Aug 2022 21:50:37 -0400 Subject: [PATCH 323/489] Reduce 2.6 excluded tests --- test/stdlib/2.6-exclude.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index d9fe398fa..2ec213f87 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -35,14 +35,14 @@ SKIP_TESTS=( [test_file.py]=1 # it fails on its own [test_future5.py]=1 # it fails on its own - # [test_generators.py]=1 # Investigate + # [test_generators.py]=1 # works but use PYTHON=pytest [test_gl.py]=1 # it fails on its own - [test_grp.py]=1 # Long test - might work Control flow? + # [test_grp.py]=1 # works but use PYTHON=pytest [test_imageop.py]=1 # it fails on its own [test_imaplib.py]=1 # it fails on its own [test_imgfile.py]=1 # it fails on its own - [test_ioctl.py]=1 # it fails on its own + # [test_ioctl.py]=1 # works but use PYTHON=pytest [test_kqueue.py]=1 # it fails on its own @@ -52,7 +52,7 @@ SKIP_TESTS=( [test_macostools.py]=1 # it fails on its own [test_mailbox.py]=1 # FIXME: release 3.6.2 may have worked - [test_normalization.py]=1 # it fails on its own + # [test_normalization.py]=1 # it fails on its own [test_ossaudiodev.py]=1 # it fails on its own From 83bf64553569574f44a97332ed023518a60dab8a Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 16 Sep 2022 16:18:54 -0400 Subject: [PATCH 324/489] Python 2.4 tolerance --- requirements.txt | 4 ---- uncompyle6/parsers/parse2.py | 1 - 2 files changed, 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 40a868989..f5c6f7054 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,5 @@ # Pick up stuff from setup.py -hypothesis==2.0.0 pytest -e . -Click~=7.0 xdis>=6.0.4 -configobj~=5.0.6 -setuptools~=65.3.0 diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 84fb78785..d6f191c1f 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -25,7 +25,6 @@ that a later phase can turn into a sequence of ASCII text. """ -from __future__ import print_function from uncompyle6.parsers.reducecheck import (except_handler_else, ifelsestmt, tryelsestmt) from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.treenode import SyntaxTree From eaa063a15f80cb0c18ff3787cf1e48671536492f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 18 Sep 2022 21:05:40 -0400 Subject: [PATCH 325/489] Deal with 2.x EXTENDED_ARGS on JUMP_ABSOLUTE in scanner2's "continue" detection --- uncompyle6/scanners/scanner2.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index b219cfd77..a3709ab7b 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -38,7 +38,6 @@ from xdis import code2num, iscode, op_has_argument, instruction_size from xdis.bytecode import _get_const_info from uncompyle6.scanner import Scanner, Token -from uncompyle6.scanner import Scanner, Token class Scanner2(Scanner): @@ -414,7 +413,16 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # either to a FOR_ITER or the instruction after a SETUP_LOOP # and it is followed by another JUMP_FORWARD # then we'll take it as a "continue". - j = self.offset2inst_index[offset] + j = self.offset2inst_index.get(offset) + + # EXTENDED_ARG doesn't appear in instructions, + # but is instead the next opcode folded into it, and has the offset + # of the EXTENDED_ARG. Therefor in self.offset2nist_index we'll find + # the instruction at the previous EXTENDED_ARG offset which is 3 + # bytes back. + if j is None and offset > self.opc.ARG_MAX_VALUE: + j = self.offset2inst_index[offset-3] + target_index = self.offset2inst_index[target] is_continue = ( self.insts[target_index - 1].opname == "SETUP_LOOP" From 6aa0725baeb3b9d082530d835dc42d3c508a9cbc Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 20 Sep 2022 17:33:38 -0400 Subject: [PATCH 326/489] Sync with master --- uncompyle6/semantics/gencomp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index c62956a68..3ed4ee74e 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -106,7 +106,7 @@ def comprehension_walk( self, node, iter_index, - code_index = -5, + code_index=-5, ): p = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 From 68c646f1bb3c4ee3fa2278ae1050a6583bbe5cf5 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Sep 2022 02:50:53 -0400 Subject: [PATCH 327/489] Remove type annotations --- uncompyle6/parsers/reducecheck/and_check.py | 4 +--- uncompyle6/parsers/reducecheck/for_block_check.py | 2 +- uncompyle6/parsers/reducecheck/joined_str_check.py | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/uncompyle6/parsers/reducecheck/and_check.py b/uncompyle6/parsers/reducecheck/and_check.py index afffbcb33..809fdb932 100644 --- a/uncompyle6/parsers/reducecheck/and_check.py +++ b/uncompyle6/parsers/reducecheck/and_check.py @@ -5,9 +5,7 @@ -def and_invalid( - self, lhs: str, n: int, rule, ast, tokens: list, first: int, last: int - ) -> bool: +def and_invalid( self, lhs, n, rule, ast, tokens, first, last): jmp = ast[1] if jmp.kind.startswith("jmp_"): if last == n: diff --git a/uncompyle6/parsers/reducecheck/for_block_check.py b/uncompyle6/parsers/reducecheck/for_block_check.py index cf9a22a58..83fdadac4 100644 --- a/uncompyle6/parsers/reducecheck/for_block_check.py +++ b/uncompyle6/parsers/reducecheck/for_block_check.py @@ -3,7 +3,7 @@ from uncompyle6.scanners.tok import Token -def for_block_invalid(self, lhs, n, rule, tree, tokens, first: int, last: int) -> bool: +def for_block_invalid(self, lhs, n, rule, tree, tokens, first, last): # print("XXX", first, last) # for t in range(first, last): diff --git a/uncompyle6/parsers/reducecheck/joined_str_check.py b/uncompyle6/parsers/reducecheck/joined_str_check.py index c6f67441b..821fab6c9 100644 --- a/uncompyle6/parsers/reducecheck/joined_str_check.py +++ b/uncompyle6/parsers/reducecheck/joined_str_check.py @@ -13,9 +13,7 @@ # along with this program. If not, see . -def joined_str_invalid( - self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int -) -> bool: +def joined_str_invalid(self, lhs, n, rule, tree, tokens, first, last): # In Python 3.8, there is a new "=" specifier. # See https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging # We detect this here inside joined_str by looking for an From 61784c4f43a85e2d4218b4257efd64683239ea26 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Sep 2022 03:42:56 -0400 Subject: [PATCH 328/489] remove test in 2.4: no builtin "all()" --- test/bytecode_2.4_run/05_long_literals24.pyc | Bin 18560 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/bytecode_2.4_run/05_long_literals24.pyc diff --git a/test/bytecode_2.4_run/05_long_literals24.pyc b/test/bytecode_2.4_run/05_long_literals24.pyc deleted file mode 100644 index 383aa905381a99298960dd7429d9d0aab4d06460..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18560 zcmeI)caRj-yT^n&N=6t zbHc3L?$v$Zy!Tgi>sH;W`;SVE@8>(yJKWVocH*toy+re_~$O>xeZVD@9^(4@b5G5|MCosTgg^00RQ2ubMA{myZ`w`Vf&7z z@!uc+J_G+g1OKnj!2iWp^LS(0p?$T?`&HYagF(mEp_74c9p*FW+&XkIn7?)CYOp}- zu%N+0t;50wiqMfi~e)I&f)pWn|L$U{imb5Rky4j!(!EG%E!~a!s68dZRlQ|w+%fEmLPgokFxEW zC96l;hNTRaCYGrldfPR<40;oNs^_BZnq{l!qYZrx`Vq?+EKjUp(4QD!FpyZ$U?pOZ z!C+#DK?4yP#6)6{5}84b$PMa5VX!i>iovSHY6hzlLk-p-h8e6$tYxq^G2CDsVqJsv zi1iINAT~7Eh}hU*1hI+1ro?6jn-g0YY)Ncour;xb!M4P92HO)m80<*wWUw2 zl)-3Xi~)#7gR#UogYkqIOduv2Od=*5Od+NkOe1zRXd;>oT8QZeyAit^%phhO>_O~l zuotnn!9K*k2Ky2F8yrB)GB}Vp$lze&5Q9UB!we25jxacqILhE?;uwQtiQ^28Cr&Up zkvPfVWa1QqQ;E|IPAASVIFmTb;B4X?gL8@V49+JmFu0Jo$lzk)5`#;L%M30jt}wWg zxXR#a;u?c%iR%omCvGsfk+{j=X5touTZ!8YZYS6QwKtvWXkyxZeW>F(@i#kzQtW2z8u`02e#p=XRi#3R0 z7Hbk~S*%SAw^)Z**J3?leTxl<4J|ezHntc+Y+|t~v6;o@#1ASaEwP=& z_QVbrI}$rt>`aWb*o7EnF`5`-0iw}jEHTbvJRuenh=~@Hh{+aHh^ZFSh+Qq3h-Qlx zV!Fj{#O@X|h?y395PMqeMeJ>{53#Sse#HJ32N1I?4kQk;IG8xZ;!xr+i^GW{ERH0O zvN)PJ#^PAwIE&+n6D&?7PO>r;xvoXi8CzDB+jxpn>fefT;e>7^N9;AE+j6p zxR|)a;!@%=i_3{CEUqN3vbdVK#^PGyI*aRx8!T=lZnC(UxW(dD;x>!hi90OrB<`}f zo4Ci~UgAEB`-ulE9wZ*Jc$j#^;!)x;i^qv4ES@BuvUr+!#^PDxIg96s7c5>RUb1+Z zc*WvX;x&uci8n0XB;K-kn|R0KUE)29_lXZIJ|sS}_?Y;_;#1-?i_eKKEWRYZviO?# z#^PJzJB#m$A1r<(W?TG3{A}?H@vFse#P1e=5Pw?yMa;1fw3J&7e9mLisRScd53(3|Mv zuq@Hnp&zlF!}7!m4*iJ%4g-l59abU+ISeL-I5ZHELrf$NDUmtUh}@x06b>sBt2nGm ztmd#fG1OrVVwl64#99t(6T=BMdhyAv}UW)gci>`Cn9us5-f!@k6R4*L@aILsmrbU27O z*x?Z3P=~{a!yS$wj&wMRINISD;#h~{h~phjAWn2Ri8$He6yj8e(}>d@&LGZoIEy&j z;T+;zhx3T@9WEd)bhwDP*x?f5Qisck%N?#Du5`GHxZ2?w;#!C6i0d70AZ~QHiMZL} z7UEWi+lbp8?jY`TxQn>k;U3~%hx>^89UdSaba;q(*x?c4QHRHf#~q#^o^*JMc-r9^ z;#r61i02(%AYOEMiFn!J72;Kg*NE30-XPv|c#C-3;T_^#hxds09X=pFbohw)*x?i6 zQ-{xp&mF!XzI6DC_}bwc;#-IBi0>VKAbxb1P5k8WGx3YVuf%T-zY~8r{7L-fFo!T6 z*0(K2&chS!JlYc-JUSAcJmw=hdvqb@_vlJ2;ISaFkjKKrA|8tp-8>c}7We2*^zc}M z=;^T}v6RQs#4;Yeh~6H3h-E$c68$`uBbN7Af#~lsfEehpBC(RkAY!n`5Td~&B4Uq( zNIf#5=8+S1kAhg)V-;dmkJX6PJ%$o%cnl-f^jM2n+haJfj>o#hdLHW&8+dF;Y~-;q zF~VaLVpEUJh|N8=Ahz__irCs?8)93J?TGC?b|7~2*ooNLV2yC8l}oN;G*i6D=OoiQPPQCuVreB=+#wli15+Z(<*heTn@% z_9qVTm_;1uaS(B^$05X_9)}T!dmKR=>2VZsw8t^Tu^z_}$9tSWoak{9ak9rL#Hk*q z5vO~cL7eGv7IC)6ImEdh=Mm?7TtHmtaS?H`$0fw29+wf9dt52VctwZ}EYwI0_I z*L&PR+~{!=akIxQ#H}8;5x0BXLEPza7jd`8J;c2p_YwDdJU~3?@euK_$0Nj}9*+@^ zdptor>G2ftw8t~VvmVb8&wIQ;yy)=~@v_G&#H${!5wCl^LA>el7V);nJH)#l?-B2N zd_a8Y@e%Q{$0x+69-k4PdwfBB>G2iuwZ}Kaw;taS-+TN({OB?JA8g;H^#dhcjC5(+ z^_lI%PlvSb?v(p89r>nnv9_(A#oP9oy8pfB(+)kVeVJO+ zwW@uSY8YPanN-8N)qY7etY7VwRKteVK1sQe_TQh2(<=TH4Krg7KT_>4?`kD!;s1vVaQ}y7;3U+7;;%F40TyM z42292Lf#0U7&6%~3^my(47qF^hPsRhLm`_4q23^yh9Q#8 z!Vt^mVMt_)Fr>0&7&6%^3^mz047qF*hPrGUhC;RrLeU`QheYT3+Akv6Aq=tX7=}c4 z3PUP8har=ZVW`P2VaR1v80s=Q426uTLiPIp&+C1IlpkpgN+gY{#4=WuM8>I-%6L^W zsTRz6@2e&gRLNzcDs`EpN+FZO5;e#aRU(E`$Dv8{pN-DRi zlF4nV)Z}(ma=Am5y4kD>C6aqoiRE5Z61h*6RPI+LlLu6($%Cro@{lTZ zd03S~9tld^&>)Yh63Jt##PYZ*i9Df7Do?7C$y2J-bW?+o~k;jw-3V zt4b#CsZx{oRmtT8RqFDgDusL$mU12ZSd~aVQ6-j7RY~MCRZ{s}l}x@+r6ymhlFL`B z)a7ec3i&212lE@FLr1GOGnaozDCO@f?%g?IR)^7g zMABE4So*1w$a1Qrvb-vpte{Fw`m2)509EQTP?bVf3`)|_F!vj_q#=?)>greqtCGkN zRZ?kCC6h>%n#8K)lBiObRFy)qu#`(+O_fM;Rbr{Dl1QOSDl4m!$ttSUWK~siSxuF? ztgcESL&H)oforG|$uL!7SyPon)>0*vwN=SvxGFVSN0nUGRi!TLsZz-LVJVlu4OEF_ zLseqgNR>o3Rwb1Ys${Z>DmB?um0UJcr7oMRQpgrzDVM-4Rf%LPRbts%l|;5tC6#Se z$z(fKYEu5Koq7JSBS~}FL6y4fs7fI_g{52qcUC2mk*dV9iz)?f|L~@ZTv0SW5BA2L=%B8Aga+xYMxm=Z8u27{eSE^FTRbeUD!K+n?s86*232Zuqbj-Fq)J_GR;7?z!cwk-x2h7!ZK}j_yDEv?p-L)us*=fFs?_9e zRdTsUmAc%kN+I`!rCbN^S0$1MREgz5RT6nfl~f*9C6h-~smY_No~ZTdLIMZB+_+CoJVU_^v9Eyr)Vm@2ir?2dbpetq)JUb zRwb8DRH@6Ssuc2BSju(qb5$bwLX}v)R3(wGR7vG)RWkWTm7093N-p22QkU;lDddNs zWaT>eqbiZiRwb67$}*z={M8??bSy7Mj>Ob4BS*HB)y!z|<>jQtDJ`AL|4Oq=X>J)c zWlUpByDCd_OUnY~Fs!+`v8hF-P8r_RG_|SqkWrH+wVq&9>xWjF%i4(6gC;i4Y%c$w zI^}&$pEjv+?nhdh`&ak0d3#r0%vW8^Deu33nf|_L8C*`yGPyivWb@SNO=B8|G|rgT z)Y#ly-tCZvY~-Y=Q^t*)BrT0iqb4=S>ELNITkn5pc`DO9p}gqOzJnduZo&3FZNK(& pO!e Date: Fri, 30 Sep 2022 19:47:23 -0400 Subject: [PATCH 329/489] Go over 2.7 stdlib exclusions --- test/stdlib/2.7-exclude.sh | 23 ++++++++++++++++------- test/stdlib/runtests.sh | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/test/stdlib/2.7-exclude.sh b/test/stdlib/2.7-exclude.sh index 629286a1f..16a055477 100644 --- a/test/stdlib/2.7-exclude.sh +++ b/test/stdlib/2.7-exclude.sh @@ -1,34 +1,43 @@ SKIP_TESTS=( - [test_cgi.py]=1 # FIXME: Works on c90ff51 + # raise ValueError("str arguments must be keys in sys.modules") + # ValueError: str arguments must be keys in sys.modules + [test_collections.py]=1 + [test_asyncore.py]=1 + [test_bdb.py]=1 + [test_bisect.py]=1 [test_bsddb3.py]=1 # test takes too long to run: 110 seconds + [test_coercion.py]=1 # Code introspects on co_consts in a non-decompilable way [test_compile.py]=1 # Code introspects on co_consts in a non-decompilable way + [test_complex.py]=1 [test_curses.py]=1 # Possibly fails on its own but not detected [test_cmd_line.py]=1 # Takes too long, maybe hangs, or looking for interactive input? + [test_datetime.py]=1 + [test_decimal.py]=1 + [test_deque.py]=1 + [test_descr.py]=1 + [test_dictcomps.py]=1 [test_dis.py]=1 # We change line numbers - duh! [test_doctest.py]=1 # Fails on its own - [test_exceptions.py]=1 + [test_doctest2.py]=1 # Fails on its own + [test_format.py]=1 # Control flow "and" vs nested "if" + [test_float.py]=1 [test_grp.py]=1 # test takes to long, works interactively though [test_io.py]=1 # Test takes too long to run [test_ioctl.py]=1 # Test takes too long to run [test_lib2to3.py]=1 # test takes too long to run: 28 seconds - [test_math.py]=1 [test_memoryio.py]=1 # FIX - [test_modulefinder.py]=1 # FIX [test_multiprocessing.py]=1 # On uncompyle2, takes 24 secs [test_poll.py]=1 # test takes too long to run: 11 seconds [test_regrtest.py]=1 # [test_runpy.py]=1 # Long and fails on its own - [test_select.py]=1 # Runs okay but takes 11 seconds [test_socket.py]=1 # Runs ok but takes 22 seconds [test_ssl.py]=1 # [test_subprocess.py]=1 # Runs ok but takes 22 seconds [test_sys_settrace.py]=1 # Line numbers are expected to be different - [test_tokenize.py]=1 # test takes too long to run: 19 seconds [test_traceback.py]=1 # Line numbers change - duh. - [test_unicode.py]=1 # Too long to run 11 seconds [test_xpickle.py]=1 # Runs ok but takes 72 seconds [test_zipfile64.py]=1 # Runs ok but takes 204 seconds [test_zipimport.py]=1 # diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index b0c74644a..e1cceec58 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -234,7 +234,7 @@ for file in $files; do $fulldir/compile-file.py $file && \ mv $file{,.orig} && \ echo ========== $(date +%X) Decompiling $file =========== - $DECOMPILER $OPTS $decompiled_file > $file + $DECOMPILER $OPTS $decompiled_file > $file 2>/dev/null rc=$? if (( rc == 0 )) ; then echo ========== $(date +%X) Running $file =========== From e596fb09173722cfa2266dd04350ca83b416f9ea Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 3 Nov 2022 16:20:52 -0400 Subject: [PATCH 330/489] Allow running from 3.0 --- ....1-3.2-versions => pyenv-3.0-3.3-versions} | 2 +- admin-tools/setup-python-3.0.sh | 35 +++++++++++++++++++ setup.py | 9 +++-- 3 files changed, 43 insertions(+), 3 deletions(-) rename admin-tools/{pyenv-3.1-3.2-versions => pyenv-3.0-3.3-versions} (86%) create mode 100644 admin-tools/setup-python-3.0.sh diff --git a/admin-tools/pyenv-3.1-3.2-versions b/admin-tools/pyenv-3.0-3.3-versions similarity index 86% rename from admin-tools/pyenv-3.1-3.2-versions rename to admin-tools/pyenv-3.0-3.3-versions index 334a2631c..df84c5bf8 100644 --- a/admin-tools/pyenv-3.1-3.2-versions +++ b/admin-tools/pyenv-3.0-3.3-versions @@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then echo "This script should be *sourced* rather than run directly through bash" exit 1 fi -export PYVERSIONS='3.1.5 3.2.6' +export PYVERSIONS='3.0.1 3.1.5 3.2.6' diff --git a/admin-tools/setup-python-3.0.sh b/admin-tools/setup-python-3.0.sh new file mode 100644 index 000000000..27282d53b --- /dev/null +++ b/admin-tools/setup-python-3.0.sh @@ -0,0 +1,35 @@ +#!/bin/bash +PYTHON_VERSION=3.0.1 +pyenv local $PYTHON_VERSION + +# FIXME put some of the below in a common routine +function checkout_version { + local repo=$1 + version=${2:-python-3.0-to-3.2} + echo Checking out $version on $repo ... + (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ + git pull + return $? +} + +function finish { + cd $owd +} + +export PATH=$HOME/.pyenv/bin/pyenv:$PATH +owd=$(pwd) +bs=${BASH_SOURCE[0]} +if [[ $0 == $bs ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi + +mydir=$(dirname $bs) +fulldir=$(readlink -f $mydir) +cd $fulldir/.. +(cd $fulldir/.. && checkout_version python-spark master && checkout_version python-xdis && + checkout_version python-uncompyle6) +cd $owd +rm -v */.python-version || true + +git checkout python-3.0-to-3.2 && git pull && pyenv local $PYTHON_VERSION diff --git a/setup.py b/setup.py index fe030010c..c2f8753ef 100755 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ """Setup script for the 'uncompyle6' distribution.""" SYS_VERSION = sys.version_info[0:2] -if not ((3, 3) <= SYS_VERSION < (3, 6)): - mess = "Python Release 3.3 .. 3.5 are supported in this code branch." +if not ((3, 0) <= SYS_VERSION < (3, 3)): + mess = "Python Release 3.0 .. 3.2 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." @@ -17,6 +17,11 @@ "\nFor your Python, version %s, use the master code/branch." % sys.version[0:3] ) + if (3, 3) >= SYS_VERSION < (3, 6): + mess += ( + "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." + % sys.version[0:3] + ) elif SYS_VERSION < (2, 4): mess += ( "\nThis package is not supported for Python version %s." % sys.version[0:3] From 2a393a408b47ab68e29afd699a1629559e17a1b1 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Nov 2022 00:36:22 -0400 Subject: [PATCH 331/489] Handle 3.0 list comprehensions properly --- uncompyle6/parsers/parse30.py | 7 ++++++- uncompyle6/semantics/gencomp.py | 21 ++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index 79ecbe738..bf8815bfe 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -85,6 +85,11 @@ def p_30(self, args): LOAD_FAST FOR_ITER store comp_iter JUMP_BACK _come_froms POP_TOP JUMP_BACK + list_for ::= DUP_TOP STORE_FAST + expr_or_arg + FOR_ITER + store list_iter jb_or_c + set_comp ::= set_comp_header LOAD_FAST FOR_ITER store comp_iter JUMP_BACK @@ -219,7 +224,7 @@ def remove_rules_30(self): # lc_body ::= LOAD_NAME expr LIST_APPEND # lc_body ::= expr LIST_APPEND # list_comp ::= BUILD_LIST_0 list_iter - # list_for ::= expr FOR_ITER store list_iter jb_or_c + list_for ::= expr FOR_ITER store list_iter jb_or_c # list_if ::= expr jmp_false list_iter # list_if ::= expr jmp_false_then list_iter # list_if_not ::= expr jmp_true list_iter diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index b4a7517e3..f9b862931 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -388,7 +388,7 @@ def comprehension_walk_newer( while n in ("list_iter", "list_afor", "list_afor2", "comp_iter"): # iterate one nesting deeper - if self.version == 3.0 and len(n) == 3: + if self.version == (3, 0) and len(n) == 3: assert n[0] == "expr" and n[1] == "expr" n = n[1] elif n == "list_afor": @@ -401,11 +401,17 @@ def comprehension_walk_newer( n = n[0] if n in ("list_for", "comp_for"): - if n[2] == "store" and not store: - store = n[2] + n_index = 3 + if ((n[2] == "store") + or (self.version == (3, 0) and n[4] == "store") and not store): + if self.version == (3, 0): + store = n[4] + n_index = 5 + else: + store = n[2] if not comp_store: comp_store = store - n = n[3] + n = n[n_index] elif n in ( "list_if", "list_if_not", @@ -452,7 +458,11 @@ def comprehension_walk_newer( self.write(": ") self.preorder(n[1]) else: - self.preorder(n[0]) + if self.version == (3, 0): + body = n[1] + else: + body = n[0] + self.preorder(body) if node == "list_comp_async": self.write(" async") @@ -464,6 +474,7 @@ def comprehension_walk_newer( if comp_store: self.preorder(comp_store) + comp_store = None else: self.preorder(store) From dd20a3841258bb57e5664d89a96e1966928babe4 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Nov 2022 00:57:24 -0400 Subject: [PATCH 332/489] Sync with python-3.3-3.5 branch --- uncompyle6/semantics/gencomp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index a42c37f66..20c85db7c 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -408,7 +408,6 @@ def comprehension_walk_newer( or (self.version == (3, 0) and n[4] == "store") and not store ): ->>>>>>> python-3.3-to-3.5 if self.version == (3, 0): store = n[4] n_index = 5 From 69c5954815b8a7e519e906e6edbb553380cd11cb Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Nov 2022 01:00:20 -0400 Subject: [PATCH 333/489] Sync with python-3.0-3.2 branch --- uncompyle6/semantics/gencomp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index ffc3306b3..8d73ae8fd 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -25,6 +25,7 @@ from uncompyle6.semantics.helper import is_lambda_mode from uncompyle6.scanners.tok import Token + class ComprehensionMixin(object): """ These functions hand nonterminal common actions that occur From 9923a4c7753c262c7675b38f98b82260358cacc1 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Nov 2022 02:02:34 -0400 Subject: [PATCH 334/489] More 3.0 lambda comphension fixes --- uncompyle6/parsers/parse30.py | 5 +++++ uncompyle6/semantics/gencomp.py | 18 +++++++++++++++--- uncompyle6/semantics/n_actions.py | 6 +++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index bf8815bfe..93a47ebd5 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -102,6 +102,11 @@ def p_30(self, args): LOAD_FAST FOR_ITER store dict_comp_iter JUMP_BACK _come_froms POP_TOP JUMP_BACK + dict_comp_func ::= BUILD_MAP_0 + DUP_TOP STORE_FAST + LOAD_ARG FOR_ITER store + dict_comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST + stmt ::= try_except30 try_except30 ::= SETUP_EXCEPT suite_stmts_opt _come_froms pt_bp diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 20c85db7c..94c6d548f 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -267,6 +267,7 @@ def comprehension_walk_newer( is_30_dict_comp = False store = None + if node == "list_comp_async": # We have two different kinds of grammar rules: # list_comp_async ::= LOAD_LISTCOMP LOAD_STR MAKE_FUNCTION_0 expr ... @@ -593,7 +594,7 @@ def listcomp_closure3(self, node): collections = [node[-3]] list_ifs = [] - if self.version[:2] == (3, 0) and n != "list_iter": + if self.version[:2] == (3, 0) and n.kind != "list_iter": # FIXME 3.0 is a snowflake here. We need # special code for this. Not sure if this is totally # correct. @@ -636,7 +637,12 @@ def listcomp_closure3(self, node): # FIXME: adjust for set comprehension if n == "list_for": stores.append(n[2]) - n = n[3] + if self.version[:2] == (3, 0): + body_index = 5 + else: + body_index = 3 + + n = n[body_index] if n[0] == "list_for": # Dog-paddle down largely singleton reductions # to find the collection (expr) @@ -668,7 +674,11 @@ def listcomp_closure3(self, node): assert n == "lc_body", tree - self.preorder(n[0]) + if self.version[:2] == (3, 0): + body_index = 1 + else: + body_index = 0 + self.preorder(n[body_index]) # FIXME: add indentation around "for"'s and "in"'s n_colls = len(collections) @@ -682,6 +692,8 @@ def listcomp_closure3(self, node): self.write(" async") pass self.write(" for ") + if self.version[:2] == (3, 0): + store = token self.preorder(store) self.write(" in ") self.preorder(collections[i]) diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 9b11bc5e6..c82c8c6d3 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -1085,7 +1085,11 @@ def n_return_if_stmt(self, node): def n_set_comp(self, node): self.write("{") if node[0] in ["LOAD_SETCOMP", "LOAD_DICTCOMP"]: - self.comprehension_walk_newer(node, 1, 0) + if self.version == (3, 0): + iter_index = 6 + else: + iter_index = 1 + self.comprehension_walk_newer(node, iter_index=iter_index, code_index=0) elif node[0].kind == "load_closure" and self.version >= (3, 0): self.closure_walk(node, collection_index=4) else: From e03274c78c5b7a61e8a04d11cf965bbcfbb58249 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Nov 2022 00:25:32 -0400 Subject: [PATCH 335/489] Fix another 3.0 list comprehension parse --- uncompyle6/parsers/parse30.py | 12 +++++++----- uncompyle6/semantics/gencomp.py | 5 ++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index 93a47ebd5..13fdb280d 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -115,11 +115,13 @@ def p_30(self, args): # From Python 2.6 - list_iter ::= list_if JUMP_BACK - list_iter ::= list_if JUMP_BACK _come_froms POP_TOP - lc_body ::= LOAD_NAME expr LIST_APPEND - lc_body ::= LOAD_FAST expr LIST_APPEND - list_if ::= expr jmp_false_then list_iter + lc_body ::= LOAD_FAST expr LIST_APPEND + lc_body ::= LOAD_NAME expr LIST_APPEND + list_if ::= expr jmp_false_then list_iter + list_if_not ::= expr jmp_true list_iter JUMP_BACK come_froms POP_TOP + list_iter ::= list_if JUMP_BACK + list_iter ::= list_if JUMP_BACK _come_froms POP_TOP + ############# dict_comp_iter ::= expr expr ROT_TWO expr STORE_SUBSCR diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 94c6d548f..1fc434127 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -659,7 +659,10 @@ def listcomp_closure3(self, node): list_ifs.append(n) else: list_ifs.append([1]) - n = n[-2] if n[-1] == "come_from_opt" else n[-1] + if self.version[:2] == (3, 0) and n[2] == "list_iter": + n = n[2] + else: + n = n[-2] if n[-1] == "come_from_opt" else n[-1] pass elif n == "list_if37": list_ifs.append(n) From 555fbe81daa6b4be2781efe0a88cf5b8ad1ec107 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Nov 2022 00:37:07 -0400 Subject: [PATCH 336/489] Tidy else if -> elif --- uncompyle6/semantics/gencomp.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 715bfb40c..b409f0338 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -672,11 +672,10 @@ def listcomp_closure3(self, node): list_ifs.append([1]) if self.version[:2] == (3, 0) and n[2] == "list_iter": n = n[2] - else - if n[-1] == "come_from_opt": - n = n[-2] - else: - n = n[-1] + elif n[-1] == "come_from_opt": + n = n[-2] + else: + n = n[-1] pass elif n == "list_if37": list_ifs.append(n) From a941326a306f941a92bdc8b642f60999c81fd802 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 5 Nov 2022 10:13:21 -0400 Subject: [PATCH 337/489] Add generator expression Python 3.0 .. 3.2 --- uncompyle6/parsers/parse32.py | 6 ++++++ uncompyle6/parsers/parse37.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse32.py b/uncompyle6/parsers/parse32.py index be2629854..29fbccf2c 100644 --- a/uncompyle6/parsers/parse32.py +++ b/uncompyle6/parsers/parse32.py @@ -15,6 +15,12 @@ def p_30to33(self, args): store_locals ::= LOAD_FAST STORE_LOCALS """ + + def p_gen_comp(self, args): + """ + genexpr_func ::= LOAD_ARG FOR_ITER store comp_iter JUMP_BACK + """ + def p_32to35(self, args): """ if_exp ::= expr jmp_false expr jump_forward_else expr COME_FROM diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 80d9c6dd3..e038f1d9a 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -403,7 +403,7 @@ def p_list_comprehension(self, args): list_if_not ::= expr jmp_true list_iter """ - def p_set_comp(self, args): + def p_gen_comp(self, args): """ comp_iter ::= comp_for comp_body ::= gen_comp_body From 6ba779b915b42335f8f8a146799e5b624180118b Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 22 Dec 2022 22:47:14 -0500 Subject: [PATCH 338/489] Get ready for release 3.9.0 --- NEWS.md | 24 +++++++++++++++++++++++- admin-tools/pyenv-newest-versions | 2 +- uncompyle6/version.py | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5125ccf76..9f33e2955 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,26 @@ -3.8.0: 2020-10-29 +3.9.0: 2022-12-22 +================= + +* deparse generator expressions for Python 3.0 .. 3.2 +* Python 3.0 list comprehension. +* Fix Issues #310, #344, #377, #391, #409, #414 +* Limited support for 3.8+ f-string "=" specifier +* Correct 2.5-7 relative import formatting +* Miscellaneous bug fixing +* remove \n in lambda +* Python 2.6 gramar cleanup +* Correct some Python 2.6 chain compare decompilation +* Ensure no parenthesis subscript slices +* Correct 2.x formatting "slice2" nonterminal +* Correct 3.7 imports +* Improve "async for" parsing +* Handle BUILD_MAP opcode +* match Python AT better +* Correct 3.7 positional args +* PyPy 3.7 and PyPy 3.8 support +* Miscellaneous linting, isorting, blacking + +3.8.0: 2021-10-29 ================= * Better handling of invalid bytecode magic diff --git a/admin-tools/pyenv-newest-versions b/admin-tools/pyenv-newest-versions index 4350d1bc0..f332631e4 100644 --- a/admin-tools/pyenv-newest-versions +++ b/admin-tools/pyenv-newest-versions @@ -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.6.15 pypy3.6-7.3.1 3.7.16 pypy-3.7-3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.14' +export PYVERSIONS='3.6.15 pypy3.6-7.3.1 3.7.16 pypy-3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.16' diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 44c88a7dc..e6a3e3c77 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.0a1" # noqa +__version__="3.9.0" # noqa From 3ea0d67be9cdffa737547c408c98fba444424054 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 22 Dec 2022 23:33:49 -0500 Subject: [PATCH 339/489] Add check program for Python 3.3-3.5 --- admin-tools/check-3.3-3.5-versions.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 admin-tools/check-3.3-3.5-versions.sh diff --git a/admin-tools/check-3.3-3.5-versions.sh b/admin-tools/check-3.3-3.5-versions.sh new file mode 100755 index 000000000..5b451577f --- /dev/null +++ b/admin-tools/check-3.3-3.5-versions.sh @@ -0,0 +1,27 @@ +#!/bin/bash +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-3.3-3.5-versions ; then + exit $? +fi +if ! source ./setup-python-3.3.sh ; then + exit $? +fi + +cd .. +for version in $PYVERSIONS; do + echo --- $version --- + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check ; then + exit $? + fi + echo === $version === +done From aa1e6a7567cb084658f206cf0da60978d907966b Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 22 Dec 2022 23:46:08 -0500 Subject: [PATCH 340/489] Old egg build tolerance --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index fb12051b1..829295fa5 100644 --- a/README.rst +++ b/README.rst @@ -103,16 +103,16 @@ Installation You can install from PyPI using the name ``uncompyle6``:: - pip install uncompyle6 + $ pip install uncompyle6 To install from source code, this project uses setup.py, so it follows the standard Python routine:: - $ pip install -e . # set up to run from source tree + $ pip install -e . # set up to run from source tree or:: - $ python setup.py install # may need sudo + $ python setup.py install # may need sudo A GNU Makefile is also provided so :code:`make install` (possibly as root or sudo) will do the steps above. From 26b60f6fb899f70f6ee7339c2ba6247d91ca98ed Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 Jan 2023 09:42:16 -0500 Subject: [PATCH 341/489] Handle Python 3.4 MAKE_CLOSURE fns ... Is done just like Python 3.3 --- test/bytecode_3.3_run/02_make_closure.pyc | Bin 0 -> 850 bytes test/bytecode_3.4_run/02_make_closure.pyc | Bin 0 -> 580 bytes test/simple_source/bug34/02_make_closure.py | 18 ++++++++++++++++++ uncompyle6/parsers/parse3.py | 16 ++++++++-------- 4 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 test/bytecode_3.3_run/02_make_closure.pyc create mode 100644 test/bytecode_3.4_run/02_make_closure.pyc create mode 100644 test/simple_source/bug34/02_make_closure.py diff --git a/test/bytecode_3.3_run/02_make_closure.pyc b/test/bytecode_3.3_run/02_make_closure.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0200d741f3315c22bb36499439d9c54743e07e0a GIT binary patch literal 850 zcmb7CO;5r=5S?uc0)b%S#iJ+Fg8_pcjWIFClU(4$WmC3`skRim9is_1j3%D^1^yE+ z{xWB_5UuHjh0f0G$9r#P_Osn-9ejPOcLAW_&v41VpwAqU2>~Vm*P(#WfftG$SUE5e zplQX0ux3MYJQ(?Px)9aKD8jUZXI^#aGXpY9fGbUybepUL+6CniMmo`%}C?09nqv8?vwwoKD~`v+n4qI zd5~z*-=gDECTWPoEU|6F2Mpr%zO7rH*>t998kg9MYzl}tRYAN-ry|X5GOXzF4hb{d x$X%!E32dr792c*I8y8d_R`j$QkfOq(_6!CpBw?U8rbO8=C0hxq*@+I6! z=n60tQIJK!m5{}7qH7;9m84|9t2SeLmB9;DNF+2Tye5 zmyePQbC4IVvgXvdQcJHgbLB-Z zj&*xChyOKTKEQHnkUX7zQEVI8w|&}L042ZHJx5{ zw!PEY+`=KvPRGLV?eUG}r)ZG5Isu3!(V*{k_1_iSKU3%$Pc%w~2GKVWhecLV7xXQ} z%PPrd8Rbgrqh3+up@D6Zb^t9bce9HO{6Y(4j!8=fKiuf_SS!n!5c1-BE-+ 0: rule = ( "mkfunc_annotate ::= %s%s%sannotate_tuple load_closure LOAD_CODE LOAD_STR %s" @@ -1196,7 +1196,7 @@ def customize_grammar_rules(self, tokens, customize): opname, ) - elif self.version >= (3, 4): + elif self.version >= (3, 5): if not self.is_pypy: load_op = "LOAD_STR" else: From 5102e5f6e01d33416efb856ef455882694c54b34 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 14 Jan 2023 10:02:01 -0500 Subject: [PATCH 342/489] Merge hell --- test/bytecode_3.3_run/02_make_closure.pyc | Bin 850 -> 1005 bytes test/bytecode_3.4_run/02_make_closure.pyc | Bin 580 -> 722 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/bytecode_3.3_run/02_make_closure.pyc b/test/bytecode_3.3_run/02_make_closure.pyc index 0200d741f3315c22bb36499439d9c54743e07e0a..0828c6cb8020d4ff21ce11758064a83270af1072 100644 GIT binary patch delta 292 zcmcb__LjYV9uF_qg#Cw-yBHZ5k{OTyGmz~7#Kna`B87n=3P>_CL@_eBr!X<3Ff+6O z`OFN>Obk&>45>g77KRiyFqefPm4zXT6(o|)#8B+aP{PL0#0VB-2dM!GM!*CefJzxb z27^R%p`t0Q48a=gKx<3ofJ8_}X0bv+QGR++Vy*&^S)7`arkk9Rnw*`Pm#(-myn;!L z1EdzDAwE7OKRG_W6zCa-#K{wxL?*vw;#VvM`6VT_tdtK(I~EtG7L{b?=eZUYHt>L<$2#6p&{W6h8JWcj1x5MkMTxlzKxT1jPMU6VMrv|)W?s7D#*nRyhU~Z4 z8Go-M9xl9ZxtPH`LY#VoOW#nTnVh3t0VgeGk7%L{vXOiP*0~rS**cgR5 G_?ZEwPZW0m From 8479e66adddd68cc39dc76020e2645eca10ef7c9 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 01:22:39 -0500 Subject: [PATCH 343/489] Annotate arg parsing --- uncompyle6/scanner.py | 25 ++++++++++++++++---- uncompyle6/scanners/scanner3.py | 41 ++++++++++++++++----------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 7955496d3..da94d6b1a 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, 2018-2022 by Rocky Bernstein +# Copyright (c) 2016, 2018-2023 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -32,8 +32,8 @@ Bytecode, canonic_python_version, code2num, - instruction_size, extended_arg_val, + instruction_size, next_offset, ) @@ -600,8 +600,25 @@ def setTokenClass(self, tokenClass): return self.Token -def parse_fn_counts(argc): - return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF) +# TODO: after the next xdis release, use from there instead. +def parse_fn_counts_30_35(argc): + """ + In Python 3.0 to 3.5 MAKE_CLOSURE and MAKE_FUNCTION encode + arguments counts of positional, default + named, and annotation + arguments a particular kind of encoding where each of + the entry a a packe byted value of the lower 24 bits + of ``argc``. The high bits of argc may have come from + an EXTENDED_ARG instruction. Here, we unpack the values + from the ``argc`` int and return a triple of the + positional args, named_args, and annotation args. + """ + annotate_count = (argc >> 16) & 0x7FFF + # For some reason that I don't understand, annotate_args is off by one + # when there is an EXENDED_ARG instruction from what is documented in + # https://docs.python.org/3.4/library/dis.html#opcode-MAKE_CLOSURE + if annotate_count > 1: + annotate_count -= 1 + return ((argc & 0xFF), (argc >> 8) & 0xFF, annotate_count) def get_scanner(version, is_pypy=False, show_asm=None): diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 8d3b91a01..1868ada98 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2019, 2021-2022 by Rocky Bernstein +# Copyright (c) 2015-2019, 2021-2023 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # @@ -39,7 +39,7 @@ from xdis.bytecode import _get_const_info from uncompyle6.scanners.tok import Token -from uncompyle6.scanner import parse_fn_counts +from uncompyle6.scanner import parse_fn_counts_30_35 import xdis # Get all the opcodes into globals @@ -621,32 +621,31 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None flags >>= 1 attr = attr[:4] # remove last value: attr[5] == False else: - pos_args, name_pair_args, annotate_args = parse_fn_counts( + pos_args, name_pair_args, annotate_args = parse_fn_counts_30_35( inst.argval - ) + ) - correct_annotate_args = annotate_args - if opname in ("MAKE_CLOSURE", "MAKE_FUNCTION") and ((3, 4) <= self.version < (3, 6)) and annotate_args > 0: - # For some reason that I don't understand, annotate_args is off by one - # when there is an EXENDED_ARG instruction from what is documented in - # https://docs.python.org/3.4/library/dis.html#opcode-MAKE_CLOSURE - # However in parsing rule, we have already adjusted for the one-fewer annotate arg - correct_annotate_args -= 1 - - pattr = "%d positional, %d keyword only, %d annotated" % ( - pos_args, - name_pair_args, - correct_annotate_args, + pattr = "%s positional, %s keyword only, %s annotated" % ( + pos_args, name_pair_args, annotate_args ) - if name_pair_args > 0: + + if name_pair_args > 0 and annotate_args > 0: # FIXME: this should probably be K_ - opname = "%s_N%d" % (opname, name_pair_args) + opname += "_N%s_A%s" % (name_pair_args, annotate_args) pass - if annotate_args > 0: - opname = "%s_A_%d" % (opname, annotate_args) + elif annotate_args > 0: + opname += "_A_%s" % annotate_args pass - opname = "%s_%d" % (opname, pos_args) + elif name_pair_args > 0: + opname += "_N_%s" % name_pair_args + pass + else: + # Rule customization mathics, MAKE_FUNCTION_... + # so make sure to add the "_" + opname += "_0" + attr = (pos_args, name_pair_args, annotate_args) + new_tokens.append( Token( opname=opname, From ee7fda286966f40000d494c05a7742d076b0a7a0 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 08:56:34 -0500 Subject: [PATCH 344/489] Remove a CircleCI test for 3.0-3.2... until we can find an image that might run this --- .circleci/config.yml | 76 -------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8e02f9755..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,76 +0,0 @@ -version: 2 -filters: - branches: - only: python-3.3-to-3.5 -jobs: - build: - working_directory: ~/rocky/python-uncompyle6 - parallelism: 1 - shell: /bin/bash --login - # CircleCI 2.0 does not support environment variables that refer to each other the same way as 1.0 did. - # If any of these refer to each other, rewrite them so that they don't or see https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables . - environment: - CIRCLE_ARTIFACTS: /tmp/circleci-artifacts - CIRCLE_TEST_REPORTS: /tmp/circleci-test-results - COMPILE: --compile - # To see the list of pre-built images that CircleCI provides for most common languages see - # https://circleci.com/docs/2.0/circleci-images/ - docker: - - image: circleci/python:3.5 - steps: - # Machine Setup - # 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 - # The following `checkout` command checks out your code to your working directory. In 1.0 we did this implicitly. In 2.0 you can choose where in the course of a job your code should be checked out. - - checkout - # Prepare for artifact and test results collection equivalent to how it was done on 1.0. - # In many cases you can simplify this from what is generated here. - # 'See docs on artifact collection here https://circleci.com/docs/2.0/artifacts/' - - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS - # This is based on your 1.0 configuration file or project settings - - run: - working_directory: ~/rocky/python-uncompyle6 - command: pip install --user virtualenv && pip install --user nose && pip install --user pep8 - # Dependencies - # This would typically go in either a build or a build-and-test job when using workflows - # Restore the dependency cache - - restore_cache: - keys: - - v2-dependencies-{{ .Branch }}- - # fallback to using the latest cache if no exact match is found - - v2-dependencies- - - - run: - command: | # Use pip to install dependengcies - pip install --user --upgrade setuptools - # Until the next release - pip install git+https://github.com/rocky/python-xdis@python-3.3-to-3.5#egg=xdis - pip install --user -e . - pip install --user -r requirements-dev.txt - - # Save dependency cache - - save_cache: - key: v2-dependencies-{{ .Branch }}-{{ epoch }} - paths: - # This is a broad list of cache paths to include many possible development environments - # You can probably delete some of these entries - - vendor/bundle - - ~/virtualenvs - - ~/.m2 - - ~/.ivy2 - - ~/.bundle - - ~/.cache/bower - - # 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: sudo python ./setup.py develop && make check - # 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 - - store_test_results: - path: /tmp/circleci-test-results - # Save artifacts - - store_artifacts: - path: /tmp/circleci-artifacts - - store_artifacts: - path: /tmp/circleci-test-results From 2580e20469cf31fcdaa3a5a203737beae774b6d3 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 09:14:15 -0500 Subject: [PATCH 345/489] Update 2.4 CircleCI branch --- .circleci/config.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 358789e48..aa6eb6f2d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,11 +36,15 @@ jobs: - run: command: | # Use pip to install dependengcies + # Install the version of click that works with Python 2.7. + # DO this before upgrading setuptool sudo easy_install click==7.1.2 - # Until next release use github xdis - sudo pip install git+https://github.com/rocky/python-xdis@python-2.34to-2.7#egg=xdis - sudo pip install -e . - sudo pip install -r requirements-dev.txt + # Install a version of xdis that works for this code + pip install --user git+https://github.com/rocky/python-xdis@python-2.4/#egg=xdis + # Install a version of spark-parser that works for this code + pip install git+https://github.com/rocky/spark-parser@python-2.4/#egg=spark-parser + pip install --user -e . + pip install --user -r requirements-dev.txt # Save dependency cache - save_cache: @@ -58,7 +62,7 @@ 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: sudo python ./setup.py develop && make check-2.7 + - run: make check-2.7 - run: cd test/stdlib && 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 From 1345e6fc24ae6f52109a7e56b7e28e0a05ffc6a4 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 09:42:14 -0500 Subject: [PATCH 346/489] Fixup runtests for CIRCLECI --- test/stdlib/runtests.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index e1cceec58..48cc22e93 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -27,7 +27,11 @@ function displaytime { } # Python version setup -FULLVERSION=$(pyenv local) +if [[ "$CIRCLECI" == "true" ]]; then + FULLVERSION=$(pyenv local) +else + FULLVERSION=$(pyenv local) +fi PYVERSION=${FULLVERSION%.*} if [[ $PYVERSION =~ 'pypy' ]] ; then From 078d306acab5ab3f0c95c9a2fe3dd487f8fc506d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 10:15:18 -0500 Subject: [PATCH 347/489] Try for special CircleCI runtests --- .circleci/config.yml | 2 +- test/stdlib/runtests-circleci.sh | 149 +++++++++++++++++++++++++++++++ test/stdlib/runtests.sh | 10 +-- 3 files changed, 155 insertions(+), 6 deletions(-) create mode 100755 test/stdlib/runtests-circleci.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index aa6eb6f2d..979c54d5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,7 +63,7 @@ jobs: # 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: make check-2.7 - - run: cd test/stdlib && bash ./runtests.sh 'test_[p-z]*.py' + - run: cd test/stdlib && bash -x ./runtests-circleci.sh # 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 diff --git a/test/stdlib/runtests-circleci.sh b/test/stdlib/runtests-circleci.sh new file mode 100755 index 000000000..de2b5cd78 --- /dev/null +++ b/test/stdlib/runtests-circleci.sh @@ -0,0 +1,149 @@ +#!/bin/bash +me=${BASH_SOURCE[0]} + +# Note: for 2.6 sometimes we need to set PYTHON=pytest +PYTHON=${PYTHON:-python} + +typeset -i BATCH=${BATCH:-0} +if (( ! BATCH )) ; then + isatty=$(/usr/bin/tty 2>/dev/null) + if [[ -n $isatty ]] && [[ "$isatty" != 'not a tty' ]] ; then + BATCH=0 + fi +fi + + +function displaytime { + local T=$1 + local D=$((T/60/60/24)) + local H=$((T/60/60%24)) + local M=$((T/60%60)) + local S=$((T%60)) + (( D > 0 )) && printf '%d days ' $D + (( H > 0 )) && printf '%d hours ' $H + (( M > 0 )) && printf '%d minutes ' $M + (( D > 0 || H > 0 || M > 0 )) && printf 'and ' + printf '%d seconds\n' $S +} + +FULLVERSION=2.7.18 +IS_PYPY=0 +MINOR=${FULLVERSION##?.?.} + +STOP_ONERROR=${STOP_ONERROR:-1} + +typeset -i timeout=15 + +function timeout_cmd { + + ( + $@ & + child=$! + trap -- "" SIGTERM + ( + sleep "$timeout" + if ps -p $child >/dev/null ; then + echo "" + echo >&1 "**Killing ${2}; takes more than $timeout seconds to run" + kill -TERM ${child} + fi + ) & + wait "$child" + ) +} + +. ./2.7-exclude.sh + +# Test directory setup +srcdir=$(dirname $me) +cd $srcdir +fulldir=$(pwd) + +# DECOMPILER=uncompyle2 +DECOMPILER=${DECOMPILER:-"$fulldir/../../bin/uncompyle6"} +OPTS=${OPTS:-""} +TESTDIR=/tmp/test2.7 +if [[ -e $TESTDIR ]] ; then + rm -fr $TESTDIR +fi + +mkdir $TESTDIR || exit $? +(cd /usr/local/lib/python2.7/site-packages && cp */test*.pyc $TESTDIR) +(cd /usr/local/lib/python2.7/site-packages && cp */*/test*.pyc $TESTDIR) +cd $TESTDIR +export PATH=/usr/local/bin/python:${PATH} + +DONT_SKIP_TESTS=${DONT_SKIP_TESTS:-0} + +# Run tests +typeset -i i=0 +typeset -i allerrs=0 +if [[ -n $1 ]] ; then + files=$@ + typeset -a files_ary=( $(echo $@) ) + if (( ${#files_ary[@]} == 1 || DONT_SKIP_TESTS == 1 )) ; then + SKIP_TESTS=() + fi +elif [[ "$CIRCLECI" == "true" ]] ; then + files=$(echo test_*.pyc) +else + files=$(echo test_*.py) +fi + +typeset -i ALL_FILES_STARTTIME=$(date +%s) +typeset -i skipped=0 + +NOT_INVERTED_TESTS=${NOT_INVERTED_TESTS:-1} + +for file in $files; do + # If the fails *before* decompiling, skip it! + typeset -i STARTTIME=$(date +%s) + if [ ! -r $file ]; then + echo "Skipping test $file -- not readable. Does it exist?" + continue + elif ! $PYTHON $file >/dev/null 2>&1 ; then + echo "Skipping test $file -- it fails on its own" + continue + fi + typeset -i ENDTIME=$(date +%s) + typeset -i time_diff + (( time_diff = ENDTIME - STARTTIME)) + if (( time_diff > timeout )) ; then + echo "Skipping test $file -- test takes too long to run: $time_diff seconds" + continue + fi + + ((i++)) + # (( i > 40 )) && break + short_name=$(basename $file .py) + if ((IS_PYPY)); then + decompiled_file=$short_name-${MAJOR}.${MINOR}.pyc + else + decompiled_file=$short_name-${PYVERSION}.pyc + fi + $fulldir/compile-file.py $file && \ + mv $file{,.orig} && \ + echo ========== $(date +%X) Decompiling $file =========== + $DECOMPILER $OPTS $decompiled_file > $file 2>/dev/null + rc=$? + if (( rc == 0 )) ; then + echo ========== $(date +%X) Running $file =========== + timeout_cmd $PYTHON $file + rc=$? + else + echo ======= Skipping $file due to compile/decompile errors ======== + fi + (( rc != 0 && allerrs++ )) + if (( STOP_ONERROR && rc )) ; then + echo "** Ran $i tests before failure. Skipped $skipped test for known failures. **" + exit $allerrs + fi +done +typeset -i ALL_FILES_ENDTIME=$(date +%s) + +(( time_diff = ALL_FILES_ENDTIME - ALL_FILES_STARTTIME)) + +printf "Ran $i unit-test files, $allerrs errors; Elapsed time: " +displaytime $time_diff +echo "Skipped $skipped test for known failures." +exit $allerrs diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 48cc22e93..8e1520136 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -19,10 +19,10 @@ function displaytime { local H=$((T/60/60%24)) local M=$((T/60%60)) local S=$((T%60)) - (( $D > 0 )) && printf '%d days ' $D - (( $H > 0 )) && printf '%d hours ' $H - (( $M > 0 )) && printf '%d minutes ' $M - (( $D > 0 || $H > 0 || $M > 0 )) && printf 'and ' + (( D > 0 )) && printf '%d days ' $D + (( H > 0 )) && printf '%d hours ' $H + (( M > 0 )) && printf '%d minutes ' $M + (( D > 0 || H > 0 || M > 0 )) && printf 'and ' printf '%d seconds\n' $S } @@ -222,7 +222,7 @@ for file in $files; do typeset -i ENDTIME=$(date +%s) typeset -i time_diff (( time_diff = ENDTIME - STARTTIME)) - if (( time_diff > $timeout )) ; then + if (( time_diff > timeout )) ; then echo "Skipping test $file -- test takes too long to run: $time_diff seconds" continue fi From b50ca11709413e59fbcdf206e74ba95f6cb035b5 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 10:35:42 -0500 Subject: [PATCH 348/489] Disable runtests-circleci for now --- test/stdlib/runtests-circleci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/stdlib/runtests-circleci.sh b/test/stdlib/runtests-circleci.sh index de2b5cd78..a3172ad6f 100755 --- a/test/stdlib/runtests-circleci.sh +++ b/test/stdlib/runtests-circleci.sh @@ -1,4 +1,6 @@ #!/bin/bash +echo "This needs work" +exit 0 me=${BASH_SOURCE[0]} # Note: for 2.6 sometimes we need to set PYTHON=pytest From c4e7e99185124ac172f9fd4387c0a06c928b0f1c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 16 Jan 2023 11:42:50 -0500 Subject: [PATCH 349/489] Remove runtests testing for now --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 979c54d5c..05452bb54 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,7 +63,7 @@ jobs: # 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: make check-2.7 - - run: cd test/stdlib && bash -x ./runtests-circleci.sh + # - run: cd test/stdlib && bash -x ./runtests-circleci.sh # 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 From 5a2e5cf6bb8f361edce675b38beb1a4fc382befa Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Mar 2023 02:27:59 -0400 Subject: [PATCH 350/489] Merge branch 'master' into python-3.3-to-3.5 --- uncompyle6/parsers/parse37base.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index ac95e3f0e..2553bf821 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -1261,11 +1261,6 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): except Exception: import sys, traceback - print( - f"Exception in {fn.__name__} {sys.exc_info()[1]}\n" - + f"rule: {rule2str(rule)}\n" - + f"offsets {tokens[first].offset} .. {tokens[last].offset}" - ) print(traceback.print_tb(sys.exc_info()[2], -1)) raise ParserError(tokens[last], tokens[last].off2int(), self.debug["rules"]) From be855a30012d2ce488ddfb67960b3c8826295dce Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Mar 2023 02:35:59 -0400 Subject: [PATCH 351/489] Renstate some code --- uncompyle6/parsers/parse37base.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 2553bf821..226e2e7fc 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -1261,6 +1261,18 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): except Exception: import sys, traceback + print( + ("Exception in %s %s\n" + + "rule: %s\n" + + "offsets %s .. %s") + % ( + fn.__name__, + sys.exc_info()[1], + rule2str(rule), + tokens[first].offset, + tokens[last].offset, + ) + ) print(traceback.print_tb(sys.exc_info()[2], -1)) raise ParserError(tokens[last], tokens[last].off2int(), self.debug["rules"]) From 078c1ffd16e735bd0b5c3b4c4931c1134bd0b5a6 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 25 Mar 2023 02:45:42 -0400 Subject: [PATCH 352/489] merge stuff --- test/test_pythonlib.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 6c4dbc473..bfe8de6ac 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -27,8 +27,6 @@ test_pythonlib.py --mylib --verify # decompile verify 'mylib' """ -from __future__ import print_function - import getopt import os import py_compile From 0b06b6943a424a9ea0c0057db0a19b144846d055 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 8 Apr 2023 22:09:34 -0400 Subject: [PATCH 353/489] Go over stdlib test for 2.{6,7} --- test/stdlib/2.6-exclude.sh | 2 +- test/stdlib/2.7-exclude.sh | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index 2ec213f87..657c6cf97 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -81,7 +81,7 @@ SKIP_TESTS=( [test_winreg.py]=1 # it fails on its own [test_winsound.py]=1 # it fails on its own - [test_zipimport_support.py]=1 + [test_zipimport_support.py]=1 # expected test to raise ImportError [test_zipfile64.py]=1 # Skip Long test # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc # .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc diff --git a/test/stdlib/2.7-exclude.sh b/test/stdlib/2.7-exclude.sh index 16a055477..89890d1c5 100644 --- a/test/stdlib/2.7-exclude.sh +++ b/test/stdlib/2.7-exclude.sh @@ -22,25 +22,20 @@ SKIP_TESTS=( [test_doctest2.py]=1 # Fails on its own [test_format.py]=1 # Control flow "and" vs nested "if" - [test_float.py]=1 - [test_grp.py]=1 # test takes to long, works interactively though [test_io.py]=1 # Test takes too long to run - [test_ioctl.py]=1 # Test takes too long to run - [test_lib2to3.py]=1 # test takes too long to run: 28 seconds [test_memoryio.py]=1 # FIX [test_multiprocessing.py]=1 # On uncompyle2, takes 24 secs - [test_poll.py]=1 # test takes too long to run: 11 seconds [test_regrtest.py]=1 # [test_runpy.py]=1 # Long and fails on its own [test_socket.py]=1 # Runs ok but takes 22 seconds - [test_ssl.py]=1 # + [test_ssl.py]=1 # Fails on its own [test_subprocess.py]=1 # Runs ok but takes 22 seconds [test_sys_settrace.py]=1 # Line numbers are expected to be different [test_traceback.py]=1 # Line numbers change - duh. [test_xpickle.py]=1 # Runs ok but takes 72 seconds [test_zipfile64.py]=1 # Runs ok but takes 204 seconds - [test_zipimport.py]=1 # + [test_zipimport.py]=1 # expected test to raise ImportError ) # 334 unit-test files in about 15 minutes From b7ad271aa2965c92eb218142506b26bf70834579 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 17 Apr 2023 23:09:21 -0400 Subject: [PATCH 354/489] Revert 3.6ish type annotation --- uncompyle6/scanners/tok.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 113275609..ace74a02e 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -19,7 +19,6 @@ import sys intern = sys.intern -from typing import Union def off2int(offset, prefer_last=True): @@ -61,7 +60,7 @@ def __init__( opname, attr=None, pattr=None, - offset:Union[int, str]=-1, + offset=-1, linestart=None, op=None, has_arg=None, From d0714edfe60b53d166356a53a03d01c8c56edc51 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 17 Apr 2023 23:33:33 -0400 Subject: [PATCH 355/489] Update 2.{4,5} stdlib excludes --- test/stdlib/2.4-exclude.sh | 2 -- test/stdlib/2.5-exclude.sh | 1 - 2 files changed, 3 deletions(-) diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh index 664f6da59..99e11f9e9 100644 --- a/test/stdlib/2.4-exclude.sh +++ b/test/stdlib/2.4-exclude.sh @@ -44,11 +44,9 @@ SKIP_TESTS=( [test_generators.py]=1 # Investigate # [test_grammar.py]=1 # fails on its own - no module tests.test_support [test_grp.py]=1 # Long test - might work Control flow? - [test_pep247.py]=1 # Long test - might work? Control flow? [test_socketserver.py]=1 # -- test takes too long to run: 40 seconds [test_threading.py]=1 # test takes too long to run: 11 seconds [test_thread.py]=1 # test takes too long to run: 36 seconds [test_trace.py]=1 # Long test - works - [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) # About 243 files, 0 in 19 minutes diff --git a/test/stdlib/2.5-exclude.sh b/test/stdlib/2.5-exclude.sh index 1b0d1afa6..5dc11c569 100644 --- a/test/stdlib/2.5-exclude.sh +++ b/test/stdlib/2.5-exclude.sh @@ -25,7 +25,6 @@ SKIP_TESTS=( [test_nis.py]=1 # it fails on its own [test_normalization.py]=1 # it fails on its own [test_ossaudiodev.py]=1 # it fails on its own - [test_pep277.py]=1 # it fails on its own [test_plistlib.py]=1 # it fails on its own [test_rgbimg.py]=1 # it fails on its own [test_scriptpackages.py]=1 # it fails on its own From 4bd6e609dda8a56ace6df0321a04f795990e6e28 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Jun 2023 02:05:55 -0400 Subject: [PATCH 356/489] formatting --- uncompyle6/bin/uncompile.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index d3039fe9d..64416f65b 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -11,8 +11,6 @@ import sys import time -from xdis.version_info import version_tuple_to_str - program = "uncompyle6" __doc__ = """ @@ -80,16 +78,29 @@ 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), (3, 8), (3, 9), (3, 10) - )): - print('Error: %s requires Python 2.4-3.10' % program, - file=sys.stderr) + 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), + (3, 8), + (3, 9), + (3, 10), + (3, 11), + ) + ): + print("Error: %s requires Python 2.4-3.11" % program, file=sys.stderr) sys.exit(-1) - do_verify = recurse_dirs = False + recurse_dirs = False numproc = 0 outfile = "-" out_base = None From aae7777d92c986aa73a9bcc6d01171e485201c22 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Jun 2023 02:28:23 -0400 Subject: [PATCH 357/489] Merge conflicts --- uncompyle6/bin/uncompile.py | 2 ++ uncompyle6/main.py | 5 ++++- uncompyle6/parser.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index c471189fd..50714edd2 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -82,6 +82,8 @@ def main_bin(): if not ( sys.version_info[0:2] in ( + (2, 4), + (2, 5), (2, 6), (2, 7), (3, 0), diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 1a6a83253..72a825502 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -23,9 +23,12 @@ from xdis.load import load_module from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str +from uncompyle6 import verify from uncompyle6.code_fns import check_object_path from uncompyle6.parser import ParserError -from uncompyle6 import verify +from uncompyle6.semantics import pysource +from uncompyle6.semantics.fragments import code_deparse as code_deparse_fragments +from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG, code_deparse from uncompyle6.version import __version__ # from uncompyle6.linenumbers import line_number_mapping diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 1bf7cb08a..39997f0c8 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -268,7 +268,7 @@ def __ambiguity(self, children): print(children) return GenericASTBuilder.ambiguity(self, children) - def resolve(self, rule: list): + def resolve(self, rule): if len(rule) == 2 and "function_def" in rule and "assign" in rule: return "function_def" if "grammar" in rule and "expr" in rule: From 47f0d5cd69524ceb8f90c268742d760e83daca89 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Jun 2023 16:00:54 -0400 Subject: [PATCH 358/489] Merge with master --- admin-tools/setup-master.sh | 2 +- uncompyle6/parsers/parse33.py | 2 +- uncompyle6/parsers/parse34.py | 2 ++ uncompyle6/parsers/parse36.py | 3 --- uncompyle6/scanners/scanner3.py | 18 +++++++++++------- uncompyle6/semantics/gencomp.py | 8 +++++--- uncompyle6/semantics/n_actions.py | 30 ++++++++++++++++++++---------- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index 9e00863c6..181f857e6 100755 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -1,5 +1,5 @@ #!/bin/bash -PYTHON_VERSION=3.7.16 +PYTHON_VERSION=3.8.17 function checkout_version { local repo=$1 diff --git a/uncompyle6/parsers/parse33.py b/uncompyle6/parsers/parse33.py index 2a4a4ef2a..55432e72b 100644 --- a/uncompyle6/parsers/parse33.py +++ b/uncompyle6/parsers/parse33.py @@ -15,12 +15,12 @@ def p_33on(self, args): # Python 3.3+ adds yield from. expr ::= yield_from yield_from ::= expr expr YIELD_FROM + stmt ::= genexpr_func """ def customize_grammar_rules(self, tokens, customize): self.remove_rules(""" # 3.3+ adds POP_BLOCKS - genexpr_func ::= LOAD_ARG FOR_ITER store comp_iter JUMP_BACK whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP COME_FROM_LOOP whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK NOP COME_FROM_LOOP """) diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index 0ff381fb0..39b04082a 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -52,6 +52,8 @@ def p_misc34(self, args): yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM _ifstmts_jump ::= c_stmts_opt JUMP_ABSOLUTE JUMP_FORWARD COME_FROM + + genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK """ def customize_grammar_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 36d65c3c0..fd79035fc 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -191,9 +191,6 @@ def p_36_misc(self, args): COME_FROM_FINALLY compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD - - stmt ::= genexpr_func - genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK """ # Some of this is duplicated from parse37. Eventually we'll probably rebase from diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 1868ada98..ef6af551c 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -37,6 +37,7 @@ from xdis import iscode, instruction_size, Instruction from xdis.bytecode import _get_const_info +from xdis.codetype import UnicodeForPython3 from uncompyle6.scanners.tok import Token from uncompyle6.scanner import parse_fn_counts_30_35 @@ -570,16 +571,19 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None if op in self.opc.CONST_OPS: const = argval if iscode(const): - if const.co_name == "": + co_name = const.co_name + if isinstance(const.co_name, UnicodeForPython3): + co_name = const.co_name.value.decode("utf-8") + if co_name == "": assert opname == "LOAD_CONST" opname = "LOAD_LAMBDA" - elif const.co_name == "": + elif co_name == "": opname = "LOAD_GENEXPR" - elif const.co_name == "": + elif co_name == "": opname = "LOAD_DICTCOMP" - elif const.co_name == "": + elif co_name == "": opname = "LOAD_SETCOMP" - elif const.co_name == "": + elif co_name == "": opname = "LOAD_LISTCOMP" else: opname = "LOAD_CODE" @@ -587,8 +591,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None # now holds Code(const) and thus can not be used # for comparison (todo: think about changing this) # pattr = 'code_object @ 0x%x %s->%s' %\ - # (id(const), const.co_filename, const.co_name) - pattr = "" + # (id(const), const.co_filename, co_name) + pattr = "" elif isinstance(const, str): opname = "LOAD_STR" else: diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index e144cd492..e07e26fe3 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -172,9 +172,11 @@ def comprehension_walk( tree = tree[1] pass - if tree in ("genexpr_func_async",): - if tree[3] == "comp_iter": - iter_index = 3 + if tree in ("genexpr_func", "genexpr_func_async",): + for i in range(3, 5): + if tree[i] == "comp_iter": + iter_index = i + break n = tree[iter_index] diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 029735123..a7af8c015 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -146,7 +146,6 @@ def n_build_slice3(self, node): self.prune() # stop recursing def n_classdef(self, node): - if self.version >= (3, 6): self.n_classdef36(node) elif self.version >= (3, 0): @@ -521,7 +520,6 @@ def n_dict(self, node): self.prune() def n_docstring(self, node): - indent = self.indent doc_node = node[0] if doc_node.attr: @@ -543,7 +541,7 @@ def n_docstring(self, node): self.write(indent) docstring = repr(docstring.expandtabs())[1:-1] - for (orig, replace) in ( + for orig, replace in ( ("\\\\", "\t"), ("\\r\\n", "\n"), ("\\n", "\n"), @@ -701,8 +699,11 @@ def n_generator_exp(self, node): self.write("(") iter_index = 3 if self.version > (3, 2): - if self.version >= (3, 6): - if node[0].kind in ("load_closure", "load_genexpr") and self.version >= (3, 8): + if self.version >= (3, 4): + if node[0].kind in ( + "load_closure", + "load_genexpr", + ) and self.version >= (3, 8): code_index = -6 is_lambda = self.is_lambda if node[0].kind == "load_genexpr": @@ -710,13 +711,20 @@ def n_generator_exp(self, node): self.closure_walk(node, collection_index=4) self.is_lambda = is_lambda else: - # Python 3.7+ adds optional "come_froms" at node[0] so count from the end + # Python 3.7+ adds optional "come_froms" at node[0] so count from + # the end. if node == "generator_exp_async" and self.version[:2] == (3, 6): code_index = 0 else: code_index = -6 - iter_index = 4 if self.version < (3, 8) else 3 - self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) + iter_index = ( + 4 + if self.version < (3, 8) and not isinstance(node[4], Token) + else 3 + ) + self.comprehension_walk( + node, iter_index=iter_index, code_index=code_index + ) pass pass else: @@ -1028,7 +1036,6 @@ def n_listcomp(self, node): self.prune() def n_mkfunc(self, node): - code_node = find_code_node(node, -2) code = code_node.attr self.write(code.co_name) @@ -1076,7 +1083,10 @@ def n_return_expr_lambda(self, node): else: # We can't comment out like above because there may be a trailing ')' # that needs to be written - assert len(node) == 3 and node[2] in ("RETURN_VALUE_LAMBDA", "LAMBDA_MARKER") + assert len(node) == 3 and node[2] in ( + "RETURN_VALUE_LAMBDA", + "LAMBDA_MARKER", + ) self.preorder(node[0]) self.prune() From a57ff9227dbe2ecc87e450f2694bc3bff3d9ad45 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 30 Jun 2023 16:20:48 -0400 Subject: [PATCH 359/489] merge with 3.0 branch --- uncompyle6/scanners/scanner3.py | 5 ----- uncompyle6/semantics/n_actions.py | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index aba0297fa..85ddf6684 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -42,7 +42,6 @@ from xdis import iscode, instruction_size, Instruction from xdis.bytecode import _get_const_info -from xdis.codetype import UnicodeForPython3 from uncompyle6.scanners.tok import Token from uncompyle6.scanner import parse_fn_counts_30_35 @@ -577,8 +576,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None const = argval if iscode(const): co_name = const.co_name - if isinstance(const.co_name, UnicodeForPython3): - co_name = const.co_name.value.decode("utf-8") if co_name == "": assert opname == "LOAD_CONST" opname = "LOAD_LAMBDA" @@ -599,8 +596,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None # (id(const), const.co_filename, const.co_name) pattr = "" elif isinstance(const, str) or isinstance(const, unicode): - elif isinstance(const, str): ->>>>>>> python-3.0-to-3.2 opname = "LOAD_STR" else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 9c8bd57a0..068cd82fc 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -721,7 +721,8 @@ def n_generator_exp(self, node): iter_index = 4 else: iter_index = 3 - self.comprehension_walk(node, iter_index=iter_index, code_index=code_index) + self.comprehension_walk(node, iter_index=iter_index, + code_index=code_index) pass pass else: From df1772164c7d3dc6d998eb85332d97d7fa460caf Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 1 Jul 2023 10:33:04 -0400 Subject: [PATCH 360/489] Merge from master --- __pkginfo__.py | 2 +- uncompyle6/bin/uncompile.py | 12 +-- uncompyle6/scanners/scanner3.py | 131 +++++++++++++---------- uncompyle6/semantics/aligner.py | 157 +++++++++++++++++----------- uncompyle6/semantics/customize3.py | 82 ++++++++------- uncompyle6/semantics/customize36.py | 5 +- uncompyle6/semantics/fragments.py | 82 ++++++++------- uncompyle6/semantics/n_actions.py | 4 +- uncompyle6/util.py | 6 ++ 9 files changed, 272 insertions(+), 209 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 4b6d9fe60..723c15a3a 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -75,7 +75,7 @@ ] } ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.2, < 6.2.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.8, < 6.2.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 64416f65b..3dd1399c5 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -11,6 +11,10 @@ import sys import time +from uncompyle6 import verify +from uncompyle6.main import main, status_msg +from uncompyle6.version import __version__ + program = "uncompyle6" __doc__ = """ @@ -67,11 +71,6 @@ program = "uncompyle6" -from uncompyle6 import verify -from uncompyle6.main import main, status_msg -from uncompyle6.version import __version__ - - def usage(): print(__doc__) sys.exit(1) @@ -81,6 +80,8 @@ def main_bin(): if not ( sys.version_info[0:2] in ( + (2, 4), + (2, 5), (2, 6), (2, 7), (3, 0), @@ -99,7 +100,6 @@ def main_bin(): ): print("Error: %s requires Python 2.4-3.11" % program, file=sys.stderr) sys.exit(-1) - recurse_dirs = False numproc = 0 outfile = "-" diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index ef6af551c..8adf0cee6 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -41,6 +41,7 @@ from uncompyle6.scanners.tok import Token from uncompyle6.scanner import parse_fn_counts_30_35 +from uncompyle6.util import get_code_name import xdis # Get all the opcodes into globals @@ -207,11 +208,18 @@ def __init__(self, version, show_asm=None, is_pypy=False): return def bound_collection_from_inst( - self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int, collection_type: str + self, + insts: list, + next_tokens: list, + inst: Instruction, + t: Token, + i: int, + collection_type: str, ): """ - Try to a replace sequence of instruction that ends with a BUILD_xxx with a sequence that can - be parsed much faster, but inserting the token boundary at the beginning of the sequence. + Try to a replace sequence of instruction that ends with a + BUILD_xxx with a sequence that can be parsed much faster, but + inserting the token boundary at the beginning of the sequence. """ count = t.attr assert isinstance(count, int) @@ -291,8 +299,9 @@ def bound_collection_from_inst( def bound_map_from_inst( self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int): """ - Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can - be parsed much faster, but inserting the token boundary at the beginning of the sequence. + Try to a sequence of instruction that ends with a BUILD_MAP into + a sequence that can be parsed much faster, but inserting the + token boundary at the beginning of the sequence. """ count = t.attr assert isinstance(count, int) @@ -307,21 +316,18 @@ def bound_map_from_inst( assert (count * 2) <= i for j in range(collection_start, i, 2): - if insts[j].opname not in ( - "LOAD_CONST", - ): + if insts[j].opname not in ("LOAD_CONST",): return None - if insts[j+1].opname not in ( - "LOAD_CONST", - ): + if insts[j + 1].opname not in ("LOAD_CONST",): return None collection_start = i - (2 * count) collection_enum = CONST_COLLECTIONS.index("CONST_MAP") - # If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace - # add a boundary marker and change LOAD_CONST to something else - new_tokens = next_tokens[:-(2*count)] + # If we get here, all instructions before tokens[i] are LOAD_CONST and + # we can replace add a boundary marker and change LOAD_CONST to + # something else. + new_tokens = next_tokens[: -(2 * count)] start_offset = insts[collection_start].offset new_tokens.append( Token( @@ -351,10 +357,10 @@ def bound_map_from_inst( new_tokens.append( Token( opname="ADD_VALUE", - attr=insts[j+1].argval, - pattr=insts[j+1].argrepr, - offset=insts[j+1].offset, - linestart=insts[j+1].starts_line, + attr=insts[j + 1].argval, + pattr=insts[j + 1].argrepr, + offset=insts[j + 1].offset, + linestart=insts[j + 1].starts_line, has_arg=True, has_extended_arg=False, opc=self.opc, @@ -374,8 +380,9 @@ def bound_map_from_inst( ) return new_tokens - def ingest(self, co, classname=None, code_objects={}, show_asm=None - ): + def ingest( + self, co, classname=None, code_objects={}, show_asm=None + ): """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing @@ -385,14 +392,17 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None Some transformations are made to assist the deparsing grammar: - various types of LOAD_CONST's are categorized in terms of what they load - COME_FROM instructions are added to assist parsing control structures - - operands with stack argument counts or flag masks are appended to the opcode name, e.g.: + - operands with stack argument counts or flag masks are appended to the + opcode name, e.g.: * BUILD_LIST, BUILD_SET - * MAKE_FUNCTION and FUNCTION_CALLS append the number of positional arguments + * MAKE_FUNCTION and FUNCTION_CALLS append the number of positional + arguments - EXTENDED_ARGS instructions are removed - Also, when we encounter certain tokens, we add them to a set which will cause custom - grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST - cause specific rules for the specific number of arguments they take. + Also, when we encounter certain tokens, we add them to a set + which will cause custom grammar rules. Specifically, variable + arg tokens like MAKE_FUNCTION or BUILD_LIST cause specific rules + for the specific number of arguments they take. """ if not show_asm: @@ -418,7 +428,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None n = len(self.insts) for i, inst in enumerate(self.insts): - opname = inst.opname # We need to detect the difference between: # raise AssertionError @@ -435,12 +444,12 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None prev_inst = self.insts[i - 1] assert_can_follow = ( prev_inst.opname in ("JUMP_IF_TRUE", "JUMP_IF_FALSE") - and i + 1 < n ) + and i + 1 < n + ) jump_if_inst = prev_inst else: assert_can_follow = ( - opname in ("POP_JUMP_IF_TRUE", "POP_JUMP_IF_FALSE") - and i + 1 < n + opname in ("POP_JUMP_IF_TRUE", "POP_JUMP_IF_FALSE") and i + 1 < n ) jump_if_inst = inst if assert_can_follow: @@ -450,7 +459,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None and next_inst.argval == "AssertionError" and jump_if_inst.argval ): - raise_idx = self.offset2inst_index[self.prev_op[jump_if_inst.argval]] + raise_idx = self.offset2inst_index[ + self.prev_op[jump_if_inst.argval] + ] raise_inst = self.insts[raise_idx] if raise_inst.opname.startswith("RAISE_VARARGS"): self.load_asserts.add(next_inst.offset) @@ -466,22 +477,21 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None new_tokens = [] for i, inst in enumerate(self.insts): - opname = inst.opname argval = inst.argval pattr = inst.argrepr t = Token( - opname=opname, - attr=argval, - pattr=pattr, - offset=inst.offset, - linestart=inst.starts_line, - op=inst.opcode, - has_arg=inst.has_arg, - has_extended_arg=inst.has_extended_arg, - opc=self.opc, - ) + opname=opname, + attr=argval, + pattr=pattr, + offset=inst.offset, + linestart=inst.starts_line, + op=inst.opcode, + has_arg=inst.has_arg, + has_extended_arg=inst.has_extended_arg, + opc=self.opc, + ) # things that smash new_tokens like BUILD_LIST have to come first. if opname in ( @@ -500,11 +510,13 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None if try_tokens is not None: new_tokens = try_tokens continue - elif opname in ( - "BUILD_MAP", - ): + elif opname in ("BUILD_MAP",): try_tokens = self.bound_map_from_inst( - self.insts, new_tokens, inst, t, i, + self.insts, + new_tokens, + inst, + t, + i, ) if try_tokens is not None: new_tokens = try_tokens @@ -571,9 +583,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None if op in self.opc.CONST_OPS: const = argval if iscode(const): - co_name = const.co_name - if isinstance(const.co_name, UnicodeForPython3): - co_name = const.co_name.value.decode("utf-8") + co_name = get_code_name(const) if co_name == "": assert opname == "LOAD_CONST" opname = "LOAD_LAMBDA" @@ -627,7 +637,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None else: pos_args, name_pair_args, annotate_args = parse_fn_counts_30_35( inst.argval - ) + ) pattr = "%s positional, %s keyword only, %s annotated" % ( pos_args, name_pair_args, annotate_args @@ -715,11 +725,13 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None and self.insts[i + 1].opname == "JUMP_FORWARD" ) - if (self.version[:2] == (3, 0) and self.insts[i + 1].opname == "JUMP_FORWARD" - and not is_continue): + if ( + self.version[:2] == (3, 0) + and self.insts[i + 1].opname == "JUMP_FORWARD" + and not is_continue + ): target_prev = self.offset2inst_index[self.prev_op[target]] - is_continue = ( - self.insts[target_prev].opname == "SETUP_LOOP") + is_continue = self.insts[target_prev].opname == "SETUP_LOOP" if is_continue or ( inst.offset in self.stmts @@ -736,7 +748,10 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None # the "continue" is not on a new line. # There are other situations where we don't catch # CONTINUE as well. - if new_tokens[-1].kind == "JUMP_BACK" and new_tokens[-1].attr <= argval: + if ( + new_tokens[-1].kind == "JUMP_BACK" + and new_tokens[-1].attr <= argval + ): if new_tokens[-2].kind == "BREAK_LOOP": del new_tokens[-1] else: @@ -809,7 +824,10 @@ def find_jump_targets(self, debug): if inst.has_arg: label = self.fixed_jumps.get(offset) oparg = inst.arg - if self.version >= (3, 6) and self.code[offset] == self.opc.EXTENDED_ARG: + if ( + self.version >= (3, 6) + and self.code[offset] == self.opc.EXTENDED_ARG + ): j = xdis.next_offset(op, self.opc, offset) next_offset = xdis.next_offset(op, self.opc, j) else: @@ -1082,7 +1100,6 @@ def detect_control_flow(self, offset, targets, inst_index): and (target > offset) and pretarget.offset != offset ): - # FIXME: hack upon hack... # In some cases the pretarget can be a jump to the next instruction # and these aren't and/or's either. We limit to 3.5+ since we experienced there @@ -1104,7 +1121,6 @@ def detect_control_flow(self, offset, targets, inst_index): # Is it an "and" inside an "if" or "while" block if op == self.opc.POP_JUMP_IF_FALSE: - # Search for another POP_JUMP_IF_FALSE targetting the same op, # in current statement, starting from current offset, and filter # everything inside inner 'or' jumps and midline ifs @@ -1357,7 +1373,6 @@ def detect_control_flow(self, offset, targets, inst_index): self.fixed_jumps[offset] = rtarget self.not_continue.add(pre_rtarget) else: - # FIXME: this is very convoluted and based on rather hacky # empirical evidence. It should go a way when # we have better control-flow analysis diff --git a/uncompyle6/semantics/aligner.py b/uncompyle6/semantics/aligner.py index 1cc68a565..2db50bc2a 100644 --- a/uncompyle6/semantics/aligner.py +++ b/uncompyle6/semantics/aligner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2022 by Rocky Bernstein +# Copyright (c) 2018, 2022-2023 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,41 +14,63 @@ # along with this program. If not, see . import sys -from uncompyle6.semantics.pysource import ( - SourceWalker, SourceWalkerError, find_globals, ASSIGN_DOC_STRING, RETURN_NONE) from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from uncompyle6 import IS_PYPY +from xdis import iscode + +from xdis.version_info import IS_PYPY +from uncompyle6.scanner import get_scanner +from uncompyle6.semantics.pysource import ( + ASSIGN_DOC_STRING, + RETURN_NONE, + SourceWalker, + SourceWalkerError, + find_globals_and_nonlocals +) +from uncompyle6.show import maybe_show_asm + +# + class AligningWalker(SourceWalker, object): - def __init__(self, version, out, scanner, showast=False, - debug_parser=PARSER_DEFAULT_DEBUG, - compile_mode='exec', is_pypy=False): - SourceWalker.__init__(self, version, out, scanner, showast, debug_parser, - compile_mode, is_pypy) + def __init__( + self, + version, + out, + scanner, + showast=False, + debug_parser=PARSER_DEFAULT_DEBUG, + compile_mode="exec", + is_pypy=False, + ): + SourceWalker.__init__( + self, version, out, scanner, showast, debug_parser, compile_mode, is_pypy + ) self.desired_line_number = 0 self.current_line_number = 0 def println(self, *data): - if data and not(len(data) == 1 and data[0] == ''): + if data and not (len(data) == 1 and data[0] == ""): self.write(*data) self.pending_newlines = max(self.pending_newlines, 1) def write(self, *data): if (len(data) == 1) and data[0] == self.indent: - diff = max(self.pending_newlines, - self.desired_line_number - self.current_line_number) - self.f.write('\n'*diff) + diff = max( + self.pending_newlines, + self.desired_line_number - self.current_line_number, + ) + self.f.write("\n" * diff) self.current_line_number += diff self.pending_newlines = 0 - if (len(data) == 0) or (len(data) == 1 and data[0] == ''): + if (len(data) == 0) or (len(data) == 1 and data[0] == ""): return - out = ''.join((str(j) for j in data)) + out = "".join((str(j) for j in data)) n = 0 for i in out: - if i == '\n': + if i == "\n": n += 1 if n == len(out): self.pending_newlines = max(self.pending_newlines, n) @@ -61,25 +83,27 @@ def write(self, *data): break if self.pending_newlines > 0: - diff = max(self.pending_newlines, - self.desired_line_number - self.current_line_number) - self.f.write('\n'*diff) + diff = max( + self.pending_newlines, + self.desired_line_number - self.current_line_number, + ) + self.f.write("\n" * diff) self.current_line_number += diff self.pending_newlines = 0 for i in out[::-1]: - if i == '\n': + if i == "\n": self.pending_newlines += 1 else: break if self.pending_newlines: - out = out[:-self.pending_newlines] + out = out[: -self.pending_newlines] self.f.write(out) def default(self, node): mapping = self._get_mapping(node) - if hasattr(node, 'linestart'): + if hasattr(node, "linestart"): if node.linestart: self.desired_line_number = node.linestart table = mapping[0] @@ -90,25 +114,22 @@ def default(self, node): pass if key.type in table: - self.engine(table[key.type], node) + self.template_engine(table[key.type], node) self.prune() -from xdis import iscode -from uncompyle6.scanner import get_scanner -from uncompyle6.show import ( - maybe_show_asm, -) -# -DEFAULT_DEBUG_OPTS = { - 'asm': False, - 'tree': False, - 'grammar': False -} - -def code_deparse_align(co, out=sys.stderr, version=None, is_pypy=None, - debug_opts=DEFAULT_DEBUG_OPTS, - code_objects={}, compile_mode='exec'): +DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False} + + +def code_deparse_align( + co, + out=sys.stderr, + version=None, + is_pypy=None, + debug_opts=DEFAULT_DEBUG_OPTS, + code_objects={}, + compile_mode="exec", +): """ ingests and deparses a given code block 'co' """ @@ -120,61 +141,73 @@ def code_deparse_align(co, out=sys.stderr, version=None, is_pypy=None, if is_pypy is None: is_pypy = IS_PYPY - # store final output stream for case of error scanner = get_scanner(version, is_pypy=is_pypy) tokens, customize = scanner.ingest(co, code_objects=code_objects) - show_asm = debug_opts.get('asm', None) + show_asm = debug_opts.get("asm", None) maybe_show_asm(show_asm, tokens) debug_parser = dict(PARSER_DEFAULT_DEBUG) - show_grammar = debug_opts.get('grammar', None) - show_grammar = debug_opts.get('grammar', None) + show_grammar = debug_opts.get("grammar", None) + show_grammar = debug_opts.get("grammar", None) if show_grammar: - debug_parser['reduce'] = show_grammar - debug_parser['errorstack'] = True + debug_parser["reduce"] = show_grammar + debug_parser["errorstack"] = True # Build a parse tree from tokenized and massaged disassembly. - show_ast = debug_opts.get('ast', None) - deparsed = AligningWalker(version, scanner, out, showast=show_ast, - debug_parser=debug_parser, compile_mode=compile_mode, - is_pypy = is_pypy) - - is_top_level_module = co.co_name == '' - deparsed.ast = deparsed.build_ast(tokens, customize, co, is_top_level_module=is_top_level_module) - - assert deparsed.ast == 'stmts', 'Should have parsed grammar start' - - del tokens # save memory - - deparsed.mod_globs = find_globals(deparsed.ast, set()) + show_ast = debug_opts.get("ast", None) + deparsed = AligningWalker( + version, + scanner, + out, + showast=show_ast, + debug_parser=debug_parser, + compile_mode=compile_mode, + is_pypy=is_pypy, + ) + + is_top_level_module = co.co_name == "" + deparsed.ast = deparsed.build_ast( + tokens, customize, co, is_top_level_module=is_top_level_module + ) + + assert deparsed.ast == "stmts", "Should have parsed grammar start" + + del tokens # save memory + + (deparsed.mod_globs, _) = find_globals_and_nonlocals( + deparsed.ast, set(), set(), co, version + ) # convert leading '__doc__ = "..." into doc string try: if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0]): - deparsed.print_docstring('', co.co_consts[0]) + deparsed.print_docstring("", co.co_consts[0]) del deparsed.ast[0] if deparsed.ast[-1] == RETURN_NONE: - deparsed.ast.pop() # remove last node + deparsed.ast.pop() # remove last node # todo: if empty, add 'pass' - except: + except Exception: pass # What we've been waiting for: Generate Python source from the parse tree! deparsed.gen_source(deparsed.ast, co.co_name, customize) for g in sorted(deparsed.mod_globs): - deparsed.write('# global %s ## Warning: Unused global\n' % g) + deparsed.write("# global %s ## Warning: Unused global\n" % g) if deparsed.ERROR: raise SourceWalkerError("Deparsing stopped due to parse error") return deparsed -if __name__ == '__main__': + +if __name__ == "__main__": + def deparse_test(co): "This is a docstring" deparsed = code_deparse_align(co) print(deparsed.text) return + deparse_test(deparse_test.__code__) diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 2f388893c..798ba2f34 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018-2021 by Rocky Bernstein +# Copyright (c) 2018-2021, 2023 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,23 +13,20 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -"""Isolate Python 3 version-specific semantic actions here. +""" +Isolate Python 3 version-specific semantic actions here. """ -from uncompyle6.semantics.consts import TABLE_DIRECT - -from xdis import co_flags_is_async, iscode -from uncompyle6.scanner import Code -from uncompyle6.semantics.helper import ( - find_code_node, - gen_function_parens_adjust, -) +from xdis import iscode -from uncompyle6.semantics.make_function3 import make_function3_annotate +from uncompyle6.semantics.consts import TABLE_DIRECT from uncompyle6.semantics.customize35 import customize_for_version35 from uncompyle6.semantics.customize36 import customize_for_version36 from uncompyle6.semantics.customize37 import customize_for_version37 from uncompyle6.semantics.customize38 import customize_for_version38 +from uncompyle6.semantics.helper import find_code_node, gen_function_parens_adjust +from uncompyle6.semantics.make_function3 import make_function3_annotate +from uncompyle6.util import get_code_name def customize_for_version3(self, version): @@ -51,7 +48,7 @@ def customize_for_version3(self, version): "import_cont": (", %c", 2), "kwarg": ("%[0]{attr}=%c", 1), "raise_stmt2": ("%|raise %c from %c\n", 0, 1), - "tf_tryelsestmtl3": ( '%c%-%c%|else:\n%+%c', 1, 3, 5 ), + "tf_tryelsestmtl3": ("%c%-%c%|else:\n%+%c", 1, 3, 5), "store_locals": ("%|# inspect.currentframe().f_locals = __locals__\n",), "with": ("%|with %c:\n%+%c%-", 0, 3), "withasstmt": ("%|with %c as (%c):\n%+%c%-", 0, 2, 3), @@ -67,22 +64,22 @@ def customize_for_version3(self, version): # are different. See test_fileio.py for an example that shows this. def tryfinallystmt(node): suite_stmts = node[1][0] - if len(suite_stmts) == 1 and suite_stmts[0] == 'stmt': + if len(suite_stmts) == 1 and suite_stmts[0] == "stmt": stmt = suite_stmts[0] try_something = stmt[0] if try_something == "try_except": try_something.kind = "tf_try_except" if try_something.kind.startswith("tryelsestmt"): if try_something == "tryelsestmtl3": - try_something.kind = 'tf_tryelsestmtl3' + try_something.kind = "tf_tryelsestmtl3" else: - try_something.kind = 'tf_tryelsestmt' + try_something.kind = "tf_tryelsestmt" self.default(node) + self.n_tryfinallystmt = tryfinallystmt def n_classdef3(node): - """Handle "classdef" nonterminal for 3.0 >= version 3.0 < 3.6 - """ + """Handle "classdef" nonterminal for 3.0 >= version 3.0 < 3.6""" assert (3, 0) <= self.version < (3, 6) @@ -191,18 +188,25 @@ def n_classdef3(node): # the iteration variable. These rules we can ignore # since we pick up the iteration variable some other way and # we definitely don't include in the source _[dd]. - TABLE_DIRECT.update({ - "ifstmt30": ( "%|if %c:\n%+%c%-", - (0, "testfalse_then"), - (1, "_ifstmts_jump30") ), - "ifnotstmt30": ( "%|if not %c:\n%+%c%-", - (0, "testtrue_then"), - (1, "_ifstmts_jump30") ), - "try_except30": ( "%|try:\n%+%c%-%c\n\n", - (1, "suite_stmts_opt"), - (4, "except_handler") ), - - }) + TABLE_DIRECT.update( + { + "ifstmt30": ( + "%|if %c:\n%+%c%-", + (0, "testfalse_then"), + (1, "_ifstmts_jump30"), + ), + "ifnotstmt30": ( + "%|if not %c:\n%+%c%-", + (0, "testtrue_then"), + (1, "_ifstmts_jump30"), + ), + "try_except30": ( + "%|try:\n%+%c%-%c\n\n", + (1, "suite_stmts_opt"), + (4, "except_handler"), + ), + } + ) def n_comp_iter(node): if node[0] == "expr": @@ -235,7 +239,6 @@ def n_yield_from(node): if (3, 2) <= version <= (3, 4): def n_call(node): - mapping = self._get_mapping(node) key = node for i in mapping[1:]: @@ -289,24 +292,23 @@ def n_call(node): self.n_call = n_call def n_mkfunc_annotate(node): - # Handling EXTENDED_ARG before MAKE_FUNCTION ... i = -1 if node[-2] == "EXTENDED_ARG" else 0 if self.version < (3, 3): - code = node[-2 + i] + code_node = node[-2 + i] elif self.version >= (3, 3) or node[-2] == "kwargs": # LOAD_CONST code object .. # LOAD_CONST 'x0' if >= 3.3 # EXTENDED_ARG # MAKE_FUNCTION .. - code = node[-3 + i] + code_node = node[-3 + i] elif node[-3] == "expr": - code = node[-3][0] + code_node = node[-3][0] else: # LOAD_CONST code object .. # MAKE_FUNCTION .. - code = node[-3] + code_node = node[-3] self.indent_more() for annotate_last in range(len(node) - 1, -1, -1): @@ -318,11 +320,15 @@ def n_mkfunc_annotate(node): # But when derived from funcdefdeco it hasn't Would like a better # way to distinquish. if self.f.getvalue()[-4:] == "def ": - self.write(code.attr.co_name) + self.write(get_code_name(code_node.attr)) # FIXME: handle and pass full annotate args make_function3_annotate( - self, node, is_lambda=False, code_node=code, annotate_last=annotate_last + self, + node, + is_lambda=False, + code_node=code_node, + annotate_last=annotate_last, ) if len(self.param_stack) > 1: @@ -339,7 +345,7 @@ def n_mkfunc_annotate(node): "tryelsestmtl3": ( "%|try:\n%+%c%-%c%|else:\n%+%c%-", (1, "suite_stmts_opt"), - 3, # "except_handler_else" or "except_handler" + 3, # "except_handler_else" or "except_handler" (5, "else_suitel"), ), "LOAD_CLASSDEREF": ("%{pattr}",), diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 30bacc019..9b2c6ae93 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2022 by Rocky Bernstein +# Copyright (c) 2019-2023 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ TABLE_DIRECT, TABLE_R, ) +from uncompyle6.util import get_code_name def escape_format(s): @@ -190,7 +191,7 @@ def n_classdef36(node): code_node = build_class[1][1] else: code_node = build_class[1][0] - class_name = code_node.attr.co_name + class_name = get_code_name(code_node.attr) assert "mkfunc" == build_class[1] mkfunc = build_class[1] diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 966f1959e..218aadf1b 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -63,38 +63,33 @@ # FIXME: DRY code with pysource -from __future__ import print_function - import re +import sys +from collections import namedtuple +from typing import Optional -from uncompyle6.semantics import pysource -from uncompyle6 import parser -from uncompyle6.scanner import Token, Code, get_scanner -import uncompyle6.parser as python_parser -from uncompyle6.semantics.check_ast import checker - -from uncompyle6.show import maybe_show_asm, maybe_show_tree - -from uncompyle6.parsers.treenode import SyntaxTree - -from uncompyle6.semantics.pysource import ParserError, StringIO +from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from spark_parser.ast import GenericASTTraversalPruningException from xdis import iscode from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE +import uncompyle6.parser as python_parser +from uncompyle6 import parser +from uncompyle6.parsers.treenode import SyntaxTree +from uncompyle6.scanner import Code, Token, get_scanner +from uncompyle6.semantics import pysource +from uncompyle6.semantics.check_ast import checker from uncompyle6.semantics.consts import ( INDENT_PER_LEVEL, + MAP, NONE, + PASS, PRECEDENCE, TABLE_DIRECT, escape, - MAP, - PASS, ) - -from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from spark_parser.ast import GenericASTTraversalPruningException - -from collections import namedtuple +from uncompyle6.semantics.pysource import ParserError, StringIO +from uncompyle6.show import maybe_show_asm, maybe_show_tree NodeInfo = namedtuple("NodeInfo", "node start finish") ExtractInfo = namedtuple( @@ -149,7 +144,6 @@ class FragmentsWalker(pysource.SourceWalker, object): - MAP_DIRECT_FRAGMENT = () stacked_params = ("f", "indent", "is_lambda", "_globals") @@ -346,7 +340,6 @@ def n_return(self, node): self.prune() # stop recursing def n_return_if_stmt(self, node): - start = len(self.f.getvalue()) + len(self.indent) if self.params["is_lambda"]: node[0].parent = node @@ -667,7 +660,7 @@ def comprehension_walk(self, node, iter_index, code_index=-5): assert n == "comp_iter" # Find the comprehension body. It is the inner-most # node that is not list_.. . - while n == "comp_iter": # list_iter + while n == "comp_iter": # list_iter n = n[0] # recurse one step if n == "comp_for": if n[0] == "SETUP_LOOP": @@ -1123,8 +1116,9 @@ def n_classdef(self, node): n_classdefdeco2 = n_classdef - def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False, - debug_opts=None): + def gen_source( + self, ast, name, customize, is_lambda=False, returnNone=False, debug_opts=None + ): """convert parse tree to Python source code""" rn = self.return_none @@ -1150,7 +1144,6 @@ def build_ast( noneInNames=False, is_top_level_module=False, ): - # FIXME: DRY with pysource.py # assert isinstance(tokens[0], Token) @@ -1463,7 +1456,6 @@ def print_super_classes(self, node): self.set_pos_info(node, start, len(self.f.getvalue())) def print_super_classes3(self, node): - # FIXME: wrap superclasses onto a node # as a custom rule start = len(self.f.getvalue()) @@ -1482,7 +1474,7 @@ def print_super_classes3(self, node): # FIXME: this doesn't handle positional and keyword args # properly. Need to do something more like that below # in the non-PYPY 3.6 case. - self.template_engine(('(%[0]{attr}=%c)', 1), node[n-1]) + self.template_engine(("(%[0]{attr}=%c)", 1), node[n - 1]) return else: kwargs = node[n - 1].attr @@ -1846,9 +1838,13 @@ def template_engine(self, entry, startnode): index = entry[arg] if isinstance(index, tuple): - assert node[index[0]] == index[1], ( - "at %s[%d], expected %s node; got %s" - % (node.kind, arg, node[index[0]].kind, index[1]) + assert ( + node[index[0]] == index[1] + ), "at %s[%d], expected %s node; got %s" % ( + node.kind, + arg, + node[index[0]].kind, + index[1], ) index = index[0] assert isinstance( @@ -1869,9 +1865,13 @@ def template_engine(self, entry, startnode): assert isinstance(tup, tuple) if len(tup) == 3: (index, nonterm_name, self.prec) = tup - assert node[index] == nonterm_name, ( - "at %s[%d], expected '%s' node; got '%s'" - % (node.kind, arg, nonterm_name, node[index].kind) + assert ( + node[index] == nonterm_name + ), "at %s[%d], expected '%s' node; got '%s'" % ( + node.kind, + arg, + nonterm_name, + node[index].kind, ) else: assert len(tup) == 2 @@ -1984,6 +1984,7 @@ def _get_mapping(cls, node): # DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False} + # This interface is deprecated def deparse_code( version, @@ -2074,7 +2075,9 @@ def code_deparse( ) is_top_level_module = co.co_name == "" - deparsed.ast = deparsed.build_ast(tokens, customize, co, is_top_level_module=is_top_level_module) + deparsed.ast = deparsed.build_ast( + tokens, customize, co, is_top_level_module=is_top_level_module + ) assert deparsed.ast == "stmts", "Should have parsed grammar start" @@ -2084,7 +2087,7 @@ def code_deparse( # convert leading '__doc__ = "..." into doc string assert deparsed.ast == "stmts" - (deparsed.mod_globs, nonlocals) = pysource.find_globals_and_nonlocals( + (deparsed.mod_globs, _) = pysource.find_globals_and_nonlocals( deparsed.ast, set(), set(), co, version ) @@ -2135,7 +2138,7 @@ def code_deparse_around_offset( offset, co, out=StringIO(), - version=None, + version=Optional[tuple], is_pypy=None, debug_opts=DEFAULT_DEBUG_OPTS, ): @@ -2147,7 +2150,7 @@ def code_deparse_around_offset( assert iscode(co) if version is None: - version = sysinfo2float() + version = sys.version_info[:3] if is_pypy is None: is_pypy = IS_PYPY @@ -2200,8 +2203,7 @@ def deparsed_find(tup, deparsed, code): """Return a NodeInfo nametuple for a fragment-deparsed `deparsed` at `tup`. `tup` is a name and offset tuple, `deparsed` is a fragment object - and `code` is instruction bytecode. -""" + and `code` is instruction bytecode.""" nodeInfo = None name, last_i = tup if not hasattr(deparsed, "offsets"): diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index a7af8c015..9a1d3ec15 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -25,7 +25,7 @@ from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import Token -from uncompyle6.util import better_repr +from uncompyle6.util import better_repr, get_code_name from uncompyle6.semantics.helper import ( find_code_node, @@ -1038,7 +1038,7 @@ def n_listcomp(self, node): def n_mkfunc(self, node): code_node = find_code_node(node, -2) code = code_node.attr - self.write(code.co_name) + self.write(get_code_name(code)) self.indent_more() self.make_function(node, is_lambda=False, code_node=code_node) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 888ed3683..79b4fbe6e 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -3,8 +3,14 @@ # More could be done here though. from math import copysign +from xdis.codetype import UnicodeForPython3 from xdis.version_info import PYTHON_VERSION_TRIPLE +def get_code_name(code) -> str: + code_name = code.co_name + if isinstance(code_name, UnicodeForPython3): + return code_name.value.decode("utf-8") + return code_name def is_negative_zero(n): """Returns true if n is -0.0""" From f55febfbf019581cb3ec337a1349a610724dabbe Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 1 Jul 2023 10:33:20 -0400 Subject: [PATCH 361/489] Merge from master --- uncompyle6/scanners/scanner3.py | 1 - uncompyle6/semantics/fragments.py | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 8adf0cee6..2517f60bb 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -37,7 +37,6 @@ from xdis import iscode, instruction_size, Instruction from xdis.bytecode import _get_const_info -from xdis.codetype import UnicodeForPython3 from uncompyle6.scanners.tok import Token from uncompyle6.scanner import parse_fn_counts_30_35 diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 218aadf1b..2c0db4703 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -65,8 +65,8 @@ import re import sys +from bisect import bisect_right from collections import namedtuple -from typing import Optional from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser.ast import GenericASTTraversalPruningException @@ -170,13 +170,15 @@ def __init__( tolerate_errors=tolerate_errors, ) - # hide_internal suppresses displaying the additional instructions that sometimes + # Hide_internal suppresses displaying the additional instructions that sometimes # exist in code but but were not written in the source code. # An example is: - # __module__ = __name__ - # If showing source code we generally don't want to show this. However in fragment - # deparsing we generally do need to see these instructions since we may be stopped - # at one. So here we do not want to suppress showing such instructions. + # __module__ = __name__ + # + # If showing source code we generally don't want to show this. However + # in fragment deparsing we generally do need to see these instructions + # since we may be stopped at one. So here we do not want to suppress + # showing such instructions. self.hide_internal = False self.offsets = {} self.last_finish = -1 @@ -2122,9 +2124,6 @@ def code_deparse( return deparsed -from bisect import bisect_right - - def find_gt(a, x): "Find leftmost value greater than x" i = bisect_right(a, x) @@ -2138,7 +2137,7 @@ def code_deparse_around_offset( offset, co, out=StringIO(), - version=Optional[tuple], + version=None, is_pypy=None, debug_opts=DEFAULT_DEBUG_OPTS, ): @@ -2314,5 +2313,6 @@ def deparsed_find(tup, deparsed, code): # # deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets)) # # deparse_test(get_code_for_fn(FragmentsWalker.n_list)) # print("=" * 30) -# # deparse_test_around(408, 'n_list', get_code_for_fn(FragmentsWalker.n_build_list)) +# # deparse_test_around(408, 'n_list', +# get_code_for_fn(FragmentsWalker.n_build_list)) # # deparse_test(inspect.currentframe().f_code) From 96fd3312a6f28f3ca7519037f687c39430d866ec Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 1 Jul 2023 10:54:11 -0400 Subject: [PATCH 362/489] Merge from 3.0 branch --- uncompyle6/bin/uncompile.py | 6 +++-- uncompyle6/scanners/scanner3.py | 3 +-- uncompyle6/semantics/customize3.py | 2 +- uncompyle6/semantics/customize36.py | 3 +-- uncompyle6/semantics/fragments.py | 36 +++++++++++++---------------- uncompyle6/semantics/n_actions.py | 4 ++-- uncompyle6/util.py | 2 +- 7 files changed, 26 insertions(+), 30 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 62bfca225..8d55e3f9c 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -10,7 +10,9 @@ import sys import time -from xdis.version_info import version_tuple_to_str +from uncompyle6.verify import VerifyCmpError +from uncompyle6.main import main, status_msg +from uncompyle6.version import __version__ program = "uncompyle6" @@ -227,7 +229,7 @@ def main_bin(): sys.exit(2) except KeyboardInterrupt: pass - except verify.VerifyCmpError: + except VerifyCmpError: raise else: from multiprocessing import Process, Queue diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index e7e5b2721..e9d58b0b1 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -38,7 +38,6 @@ from uncompyle6.scanners.tok import Token from uncompyle6.scanner import parse_fn_counts_30_35 -from uncompyle6.util import get_code_name import xdis # Get all the opcodes into globals @@ -574,7 +573,7 @@ def ingest( if op in self.opc.CONST_OPS: const = argval if iscode(const): - co_name = get_code_name(const) + co_name = const.co_name if co_name == "": assert opname == "LOAD_CONST" opname = "LOAD_LAMBDA" diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index f7a998b87..b714ddf42 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -322,7 +322,7 @@ def n_mkfunc_annotate(node): # But when derived from funcdefdeco it hasn't Would like a better # way to distinquish. if self.f.getvalue()[-4:] == "def ": - self.write(get_code_name(code_node.attr)) + self.write(code_node.attr.co_name) # FIXME: handle and pass full annotate args make_function3_annotate( diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 9b2c6ae93..184526c8c 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -25,7 +25,6 @@ TABLE_DIRECT, TABLE_R, ) -from uncompyle6.util import get_code_name def escape_format(s): @@ -191,7 +190,7 @@ def n_classdef36(node): code_node = build_class[1][1] else: code_node = build_class[1][0] - class_name = get_code_name(code_node.attr) + class_name = code_node.attr.co_name assert "mkfunc" == build_class[1] mkfunc = build_class[1] diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 13fe3e178..9dcb6da6e 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -65,19 +65,19 @@ import re -from uncompyle6.semantics import pysource -from uncompyle6 import parser -from uncompyle6.scanner import Token, Code, get_scanner -import uncompyle6.parser as python_parser -from uncompyle6.semantics.check_ast import checker - -from uncompyle6.show import maybe_show_asm, maybe_show_tree +from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from spark_parser.ast import GenericASTTraversalPruningException +from xdis import iscode +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE +import uncompyle6.parser as python_parser +from uncompyle6 import parser from uncompyle6.parsers.treenode import SyntaxTree - +from uncompyle6.scanner import Code, Token, get_scanner +from uncompyle6.semantics import pysource +from uncompyle6.semantics.check_ast import checker from uncompyle6.semantics.pysource import ParserError -from xdis import iscode -from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE +from uncompyle6.show import maybe_show_asm, maybe_show_tree if PYTHON_VERSION_TRIPLE < (2, 5): from cStringIO import StringIO @@ -86,18 +86,14 @@ from uncompyle6.semantics.consts import ( INDENT_PER_LEVEL, + MAP, NONE, + PASS, PRECEDENCE, TABLE_DIRECT, escape, - MAP, - PASS, ) -from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from spark_parser.ast import GenericASTTraversalPruningException - -from xdis.version_info import PYTHON_VERSION_TRIPLE if PYTHON_VERSION_TRIPLE < (2, 6): from xdis.namedtuple24 import namedtuple else: @@ -907,7 +903,7 @@ def listcomprehension_walk2(self, node): def n_generator_exp(self, node): start = len(self.f.getvalue()) - self.write('(') + self.write("(") if self.version >= (3, 3): code_index = -6 else: @@ -1067,11 +1063,11 @@ def n_classdef(self, node): subclass = n.attr break pass - if node == 'classdefdeco2': + if node == "classdefdeco2": subclass_info = node else: subclass_info = node[0] - elif buildclass[1][0] == 'load_closure': + elif buildclass[1][0] == "load_closure": # Python 3 with closures not functions load_closure = buildclass[1] if hasattr(load_closure[-3], "attr"): @@ -1094,7 +1090,7 @@ def n_classdef(self, node): subclass = buildclass[1][0].attr subclass_info = node[0] else: - if node == 'classdefdeco2': + if node == "classdefdeco2": buildclass = node else: buildclass = node[0] diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 7222ca0c3..e11527f40 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -25,12 +25,12 @@ from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import Token -from uncompyle6.util import better_repr, get_code_name from uncompyle6.semantics.helper import ( find_code_node, flatten_list, ) +from uncompyle6.util import better_repr class NonterminalActions: @@ -1036,7 +1036,7 @@ def n_listcomp(self, node): def n_mkfunc(self, node): code_node = find_code_node(node, -2) code = code_node.attr - self.write(get_code_name(code)) + self.write(code.co_name) self.indent_more() self.make_function(node, is_lambda=False, code_node=code_node) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 5a16740d9..afb2495fe 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -7,7 +7,7 @@ def is_negative_zero(n): """Returns true if n is -0.0""" return n == 0.0 and copysign(1, n) == -1 -except: +except Exception: def is_negative_zero(n): return False From 18f253ffbeaca70fdafa89ba33a5937ced28acd2 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 29 Jul 2023 12:57:52 -0400 Subject: [PATCH 363/489] 3.3 compatibility --- uncompyle6/main.py | 4 ++-- uncompyle6/semantics/fragments.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index b01f3018e..9423ea663 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -49,7 +49,7 @@ def decompile( co, bytecode_version = PYTHON_VERSION_TRIPLE, out=sys.stdout, - showasm: Optional[str]=None, + showasm=None, showast={}, timestamp=None, showgrammar=False, @@ -240,7 +240,7 @@ def main( compiled_files, source_files, outfile=None, - showasm: Optional[str] = None, + showasm=None, showast={}, do_verify=False, showgrammar=False, diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index c66b63876..2c0db4703 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -2137,7 +2137,7 @@ def code_deparse_around_offset( offset, co, out=StringIO(), - version=Optional[tuple], + version=None, is_pypy=None, debug_opts=DEFAULT_DEBUG_OPTS, ): From f50086f1dae8cca9397fb9e309eb7eae072a0c70 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 11 Aug 2023 14:26:41 -0400 Subject: [PATCH 364/489] Remove type annotation --- uncompyle6/semantics/fragments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index e4eed72c8..5c47935b5 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -2154,7 +2154,7 @@ def code_deparse_around_offset( co, out=StringIO(), version=None, - is_pypy: bool = False, + is_pypy = False, debug_opts=DEFAULT_DEBUG_OPTS, ): """ From 1e95ebd5f6adf95192bc14043531047e02e05236 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Feb 2024 14:49:56 -0500 Subject: [PATCH 365/489] Bump 3.8 version to latest --- admin-tools/setup-master.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/setup-master.sh b/admin-tools/setup-master.sh index 181f857e6..706e81fd6 100755 --- a/admin-tools/setup-master.sh +++ b/admin-tools/setup-master.sh @@ -1,5 +1,5 @@ #!/bin/bash -PYTHON_VERSION=3.8.17 +PYTHON_VERSION=3.8.18 function checkout_version { local repo=$1 From 956829d974a98be5a2b8ea5086ad2d8a21d32acd Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Feb 2024 23:06:07 -0500 Subject: [PATCH 366/489] Correct imports --- uncompyle6/semantics/pysource.py | 11 +++++------ uncompyle6/util.py | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index fb2baeaf6..74ed8a9fa 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -135,8 +135,7 @@ from xdis import COMPILER_FLAG_BIT, iscode from xdis.version_info import PYTHON_VERSION_TRIPLE -import uncompyle6.parser as python_parser -from uncompyle6.parser import get_python_parser +from uncompyle6.parser import parse, get_python_parser from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanner import Code, get_scanner from uncompyle6.scanners.tok import Token @@ -1181,11 +1180,11 @@ def build_ast( p_insts = self.p.insts self.p.insts = self.scanner.insts self.p.offset2inst_index = self.scanner.offset2inst_index - ast = python_parser.parse(self.p, tokens, customize, code) + ast = parse(self.p, tokens, customize, code) self.customize(customize) self.p.insts = p_insts - except (python_parser.ParserError, AssertionError) as e: + except (ParserError, AssertionError) as e: raise ParserError(e, tokens, self.p.debug["reduce"]) transform_tree = self.treeTransform.transform(ast, code) self.maybe_show_tree(ast, phase="after") @@ -1220,9 +1219,9 @@ def build_ast( self.p.insts = self.scanner.insts self.p.offset2inst_index = self.scanner.offset2inst_index self.p.opc = self.scanner.opc - ast = python_parser.parse(self.p, tokens, customize, code) + ast = parse(self.p, tokens, customize, code) self.p.insts = p_insts - except (python_parser.ParserError, AssertionError) as e: + except (ParserError, AssertionError) as e: raise ParserError(e, tokens, self.p.debug["reduce"]) checker(ast, False, self.ast_errors) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 79b4fbe6e..129e7666a 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -3,7 +3,7 @@ # More could be done here though. from math import copysign -from xdis.codetype import UnicodeForPython3 +from xdis.cross_types import UnicodeForPython3 from xdis.version_info import PYTHON_VERSION_TRIPLE def get_code_name(code) -> str: From c25962b998fdb8a54fc2f597cdc80e5950a63224 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Feb 2024 23:12:18 -0500 Subject: [PATCH 367/489] Fix wrong number of Instruction parameters --- uncompyle6/scanners/scanner37base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 1bed72d19..364724d65 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -300,6 +300,8 @@ def tokens_append(j, token): inst.starts_line, inst.is_jump_target, inst.has_extended_arg, + None, + None, ) # Get jump targets From b0e139e6cc25f1b85cfb48836a48d913ab9f3436 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 12:16:17 -0500 Subject: [PATCH 368/489] Partial merge --- uncompyle6/parser.py | 4 +- uncompyle6/semantics/fragments.py | 116 +++++++++++++++++------------- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 8b91f0406..5ca3dc496 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -597,12 +597,12 @@ def p_expr(self, args): compare ::= compare_single compare_single ::= expr expr COMPARE_OP - # A compare_chained is two comparisions, as in: x <= y <= z + # A compare_chained is two comparisons, as in: x <= y <= z compare_chained ::= expr compared_chained_middle ROT_TWO POP_TOP _come_froms compare_chained_right ::= expr COMPARE_OP JUMP_FORWARD - # Non-null kvlist items are broken out in the indiviual grammars + # Non-null kvlist items are broken out in the individual grammars kvlist ::= # Positional arguments in make_function diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 63dc9cf0a..9ffe1c905 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2019, 2021-2023 by Rocky Bernstein +# Copyright (c) 2015-2019, 2021-2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -74,7 +74,6 @@ from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE import uncompyle6.parser as python_parser -from uncompyle6 import parser from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanner import Code, Token, get_scanner from uncompyle6.semantics import pysource @@ -88,7 +87,12 @@ TABLE_DIRECT, escape, ) -from uncompyle6.semantics.pysource import ParserError, StringIO +from uncompyle6.semantics.pysource import ( + DEFAULT_DEBUG_OPTS, + TREE_DEFAULT_DEBUG, + ParserError, + StringIO, +) from uncompyle6.show import maybe_show_asm, maybe_show_tree NodeInfo = namedtuple("NodeInfo", "node start finish") @@ -152,10 +156,11 @@ def __init__( self, version, scanner, - showast=False, + showast=TREE_DEFAULT_DEBUG, debug_parser=PARSER_DEFAULT_DEBUG, compile_mode="exec", - is_pypy=False, + is_pypy=IS_PYPY, + linestarts={}, tolerate_errors=True, ): pysource.SourceWalker.__init__( @@ -167,18 +172,17 @@ def __init__( debug_parser=debug_parser, compile_mode=compile_mode, is_pypy=is_pypy, + linestarts=linestarts, tolerate_errors=tolerate_errors, ) - # Hide_internal suppresses displaying the additional instructions that sometimes + # hide_internal suppresses displaying the additional instructions that sometimes # exist in code but but were not written in the source code. # An example is: - # __module__ = __name__ - # - # If showing source code we generally don't want to show this. However - # in fragment deparsing we generally do need to see these instructions - # since we may be stopped at one. So here we do not want to suppress - # showing such instructions. + # __module__ = __name__ + # If showing source code we generally don't want to show this. However in fragment + # deparsing we generally do need to see these instructions since we may be stopped + # at one. So here we do not want to suppress showing such instructions. self.hide_internal = False self.offsets = {} self.last_finish = -1 @@ -659,7 +663,7 @@ def comprehension_walk(self, node, iter_index, code_index=-5): n = ast[iter_index] - assert n == "comp_iter" + assert n == "comp_iter", n.kind # Find the comprehension body. It is the inner-most # node that is not list_.. . while n == "comp_iter": # list_iter @@ -718,7 +722,7 @@ def comprehension_walk3(self, node, iter_index, code_index=-5): assert iscode(code), node[code_index] code_name = code.co_name - code = Code(code, self.scanner, self.currentclass) + code = Code(code, self.scanner, self.currentclass, self.debug_opts["asm"]) ast = self.build_ast(code._tokens, code._customize, code) @@ -1065,13 +1069,17 @@ def n_classdef(self, node): # Python 3.2 works like this subclass = load_closure[-2].attr else: - raise "Internal Error n_classdef: cannot find class body" + raise RuntimeError( + "Internal Error n_classdef: cannot find class body" + ) if hasattr(buildclass[3], "__len__"): subclass_info = buildclass[3] elif hasattr(buildclass[2], "__len__"): subclass_info = buildclass[2] else: - raise "Internal Error n_classdef: cannot superclass name" + raise RuntimeError( + "Internal Error n_classdef: cannot superclass name" + ) else: subclass = buildclass[1][0].attr subclass_info = node[0] @@ -1119,7 +1127,13 @@ def n_classdef(self, node): n_classdefdeco2 = n_classdef def gen_source( - self, ast, name, customize, is_lambda=False, returnNone=False, debug_opts=None + self, + ast, + name, + customize, + is_lambda=False, + returnNone=False, + debug_opts=DEFAULT_DEBUG_OPTS, ): """convert parse tree to Python source code""" @@ -1205,7 +1219,7 @@ def build_ast( self.p.insts = self.scanner.insts self.p.offset2inst_index = self.scanner.offset2inst_index self.p.opc = self.scanner.opc - ast = parser.parse(self.p, tokens, customize, code) + ast = python_parser.parse(self.p, tokens, customize, code) self.p.insts = p_insts except (python_parser.ParserError, AssertionError) as e: raise ParserError(e, tokens, {}) @@ -1348,7 +1362,7 @@ def extract_node_info(self, nodeInfo): selectedText = text[start:finish] # Compute offsets relative to the beginning of the - # line rather than the beinning of the text + # line rather than the beginning of the text. try: lineStart = text[:start].rindex("\n") + 1 except ValueError: @@ -1356,7 +1370,7 @@ def extract_node_info(self, nodeInfo): adjustedStart = start - lineStart # If selected text is greater than a single line - # just show the first line plus elipses. + # just show the first line plus ellipsis. lines = selectedText.split("\n") if len(lines) > 1: adjustedEnd = len(lines[0]) - adjustedStart @@ -1429,7 +1443,7 @@ def extract_parent_info(self, node): p = node.parent orig_parent = p # If we can get different text, use that as the parent, - # otherwise we'll use the immeditate parent + # otherwise we'll use the immediatate parent. while p and ( hasattr(p, "parent") and p.start == node.start and p.finish == node.finish ): @@ -1566,19 +1580,19 @@ def n_dict(self, node): if node[0].kind.startswith("kvlist"): # Python 3.5+ style key/value list in dict kv_node = node[0] - l = list(kv_node) - length = len(l) + ll = list(kv_node) + length = len(ll) if kv_node[-1].kind.startswith("BUILD_MAP"): length -= 1 i = 0 while i < length: self.write(sep) - name = self.traverse(l[i], indent="") - l[i].parent = kv_node - l[i + 1].parent = kv_node + name = self.traverse(ll[i], indent="") + ll[i].parent = kv_node + ll[i + 1].parent = kv_node self.write(name, ": ") value = self.traverse( - l[i + 1], indent=self.indent + (len(name) + 2) * " " + ll[i + 1], indent=self.indent + (len(name) + 2) * " " ) self.write(sep, name, ": ", value) sep = line_seperator @@ -1588,25 +1602,25 @@ def n_dict(self, node): elif len(node) > 1 and node[1].kind.startswith("kvlist"): # Python 3.0..3.4 style key/value list in dict kv_node = node[1] - l = list(kv_node) - if len(l) > 0 and l[0].kind == "kv3": + ll = list(kv_node) + if len(ll) > 0 and ll[0].kind == "kv3": # Python 3.2 does this kv_node = node[1][0] - l = list(kv_node) + ll = list(kv_node) i = 0 - while i < len(l): - l[i].parent = kv_node - l[i + 1].parent = kv_node + while i < len(ll): + ll[i].parent = kv_node + ll[i + 1].parent = kv_node key_start = len(self.f.getvalue()) + len(sep) - name = self.traverse(l[i + 1], indent="") + name = self.traverse(ll[i + 1], indent="") key_finish = key_start + len(name) val_start = key_finish + 2 value = self.traverse( - l[i], indent=self.indent + (len(name) + 2) * " " + ll[i], indent=self.indent + (len(name) + 2) * " " ) self.write(sep, name, ": ", value) - self.set_pos_info_recurse(l[i + 1], key_start, key_finish) - self.set_pos_info_recurse(l[i], val_start, val_start + len(value)) + self.set_pos_info_recurse(ll[i + 1], key_start, key_finish) + self.set_pos_info_recurse(ll[i], val_start, val_start + len(value)) sep = line_seperator i += 3 pass @@ -1779,7 +1793,7 @@ def n_list(self, node): n_set = n_tuple = n_build_set = n_list def template_engine(self, entry, startnode): - """The format template interpetation engine. See the comment at the + """The format template interpretation engine. See the comment at the beginning of this module for the how we interpret format specifications such as %c, %C, and so on. """ @@ -1810,7 +1824,7 @@ def template_engine(self, entry, startnode): if m.group("child"): node = node[int(m.group("child"))] node.parent = startnode - except: + except Exception: print(node.__dict__) raise @@ -1947,7 +1961,7 @@ def template_engine(self, entry, startnode): start = len(self.f.getvalue()) self.write(eval(expr, d, d)) self.set_pos_info(node, start, len(self.f.getvalue())) - except: + except Exception: print(node) raise m = escape.search(fmt, i) @@ -1962,7 +1976,7 @@ def template_engine(self, entry, startnode): # FIXME figure out how to get these cases to be table driven. # 2. subroutine calls. It the last op is the call and for purposes of printing - # we don't need to print anything special there. However it encompases the + # we don't need to print anything special there. However it encompasses the # entire string of the node fn(...) if startnode.kind == "call": last_node = startnode[-1] @@ -1997,7 +2011,7 @@ def deparse_code( showgrammar=False, code_objects={}, compile_mode="exec", - is_pypy=None, + is_pypy=IS_PYPY, walker=FragmentsWalker, ): debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar} @@ -2050,7 +2064,7 @@ def code_deparse( is_pypy = IS_PYPY # store final output stream for case of error - scanner = get_scanner(version, is_pypy=is_pypy) + scanner = get_scanner(version, is_pypy=is_pypy, show_asm=debug_opts["asm"]) show_asm = debug_opts.get("asm", None) tokens, customize = scanner.ingest(co, code_objects=code_objects, show_asm=show_asm) @@ -2066,14 +2080,15 @@ def code_deparse( # Build Syntax Tree from tokenized and massaged disassembly. # deparsed = pysource.FragmentsWalker(out, scanner, showast=showast) - show_ast = debug_opts.get("ast", None) + show_tree = debug_opts.get("tree", False) deparsed = walker( version, scanner, - showast=show_ast, + showast=show_tree, debug_parser=debug_parser, compile_mode=compile_mode, is_pypy=is_pypy, + linestarts=linestarts, ) is_top_level_module = co.co_name == "" @@ -2094,7 +2109,7 @@ def code_deparse( ) # Just when you think we've forgotten about what we - # were supposed to to: Generate source from the Syntax ree! + # were supposed to do: Generate source from the Syntax tree! deparsed.gen_source(deparsed.ast, co.co_name, customize) deparsed.set_pos_info(deparsed.ast, 0, len(deparsed.text)) @@ -2149,7 +2164,7 @@ def code_deparse_around_offset( assert iscode(co) if version is None: - version = sys.version_info[:3] + version = PYTHON_VERSION_TRIPLE if is_pypy is None: is_pypy = IS_PYPY @@ -2167,7 +2182,7 @@ def code_deparse_around_offset( return deparsed -# Deprecated. Here still for compatability +# Deprecated. Here still for compatibility def deparse_code_around_offset( name, offset, @@ -2176,7 +2191,7 @@ def deparse_code_around_offset( out=StringIO(), showasm=False, showast=False, - showgrammar=False, + showgrammar=PARSER_DEFAULT_DEBUG, is_pypy=False, ): debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar} @@ -2313,6 +2328,5 @@ def deparsed_find(tup, deparsed, code): # # deparse_test(get_code_for_fn(FragmentsWalker.fixup_offsets)) # # deparse_test(get_code_for_fn(FragmentsWalker.n_list)) # print("=" * 30) -# # deparse_test_around(408, 'n_list', -# get_code_for_fn(FragmentsWalker.n_build_list)) +# # deparse_test_around(408, 'n_list', get_code_for_fn(FragmentsWalker.n_build_list)) # # deparse_test(inspect.currentframe().f_code) From ef92f08f56ac5c735b5b81b5fafaf6f0aacb4e86 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 12:29:30 -0500 Subject: [PATCH 369/489] Black files --- uncompyle6/main.py | 30 +++++++++++++----------- uncompyle6/parsers/parse37base.py | 32 ++++++++++++++------------ uncompyle6/scanner.py | 21 ++++++++--------- uncompyle6/scanners/scanner2.py | 28 +++++++++++++--------- uncompyle6/scanners/scanner3.py | 31 ++++++++++++------------- uncompyle6/scanners/scanner37.py | 13 ++++++----- uncompyle6/scanners/scanner37base.py | 21 +++++++---------- uncompyle6/semantics/customize.py | 6 ++--- uncompyle6/semantics/customize38.py | 31 +++++++++++++++++-------- uncompyle6/semantics/make_function1.py | 16 +++++++------ uncompyle6/semantics/n_actions.py | 20 +++++----------- uncompyle6/semantics/pysource.py | 11 +++++---- 12 files changed, 135 insertions(+), 125 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 7f5902c32..a745df153 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -50,7 +50,7 @@ def _get_outstream(outfile): def decompile( co, - bytecode_version = PYTHON_VERSION_TRIPLE, + bytecode_version=PYTHON_VERSION_TRIPLE, out=sys.stdout, showasm=None, showast={}, @@ -83,13 +83,13 @@ def write(s): s += "\n" real_out.write(s) - assert iscode(co), ("%s does not smell like code" % co) + assert iscode(co), "%s does not smell like code" % co co_pypy_str = "PyPy " if is_pypy else "" run_pypy_str = "PyPy " if IS_PYPY else "" sys_version_lines = sys.version.split("\n") if source_encoding: - write(f"# -*- coding: {source_encoding} -*-") + write("# -*- coding: %s -*-" % source_encoding) write( "# uncompyle6 version %s\n" "# %sPython bytecode version base %s%s\n# Decompiled from: %sPython %s" @@ -103,9 +103,9 @@ def write(s): ) ) if co.co_filename: - write(f"# Embedded file name: {co.co_filename}") + write("# Embedded file name: %s" % co.co_filename) if timestamp: - write(f"# Compiled at: {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) @@ -135,7 +135,7 @@ def write(s): (line_no, deparsed.source_linemap[line_no] + header_count) for line_no in sorted(deparsed.source_linemap.keys()) ] - mapstream.write(f"\n\n# {linemap}\n") + mapstream.write("\n\n# %s\n" % linemap) else: if do_fragments: deparse_fn = code_deparse_fragments @@ -163,11 +163,11 @@ def compile_file(source_path): basename = source_path if hasattr(sys, "pypy_version_info"): - bytecode_path = f"{basename}-pypy{version_tuple_to_str()}.pyc" + bytecode_path = "%s-pypy%s.pyc" % (basename, version_tuple_to_str()) else: - bytecode_path = f"{basename}-{version_tuple_to_str()}.pyc" + bytecode_path = "%s-%s.pyc" % (basename, version_tuple_to_str()) - print(f"compiling {source_path} to {bytecode_path}") + print("compiling %s to %s" % (source_path, bytecode_path)) py_compile.compile(source_path, bytecode_path, "exec") return bytecode_path @@ -271,7 +271,7 @@ def main( infile = os.path.join(in_base, filename) # print("XXX", infile) if not os.path.exists(infile): - sys.stderr.write(f"File '{infile}' doesn't exist. Skipped\n") + sys.stderr.write("File '%s' doesn't exist. Skipped\n" % infile) continue if do_linemaps: @@ -319,11 +319,11 @@ def main( ): if e[0] != last_mod: line = "=" * len(e[0]) - outstream.write(f"{line}\n{e[0]}\n{line}\n") + outstream.write("%s\n%s\n%s\n" % (line, e[0], line)) last_mod = e[0] info = offsets[e] extract_info = d.extract_node_info(info) - outstream.write(f"{info.node.format().strip()}" + "\n") + outstream.write("%s" % info.node.format().strip() + "\n") outstream.write(extract_info.selectedLine + "\n") outstream.write(extract_info.markerLine + "\n\n") pass @@ -345,13 +345,15 @@ def main( sys.stdout.write("\n%s\n" % str(e)) if str(e).startswith("Unsupported Python"): sys.stdout.write("\n") - sys.stderr.write(f"\n# Unsupported bytecode in file {infile}\n# {e}\n") + sys.stderr.write( + "\n# Unsupported bytecode in file %s\n# %s\n" % (infile, e) + ) else: if outfile: outstream.close() os.remove(outfile) sys.stdout.write("\n") - sys.stderr.write(f"\nLast file: {infile} ") + sys.stderr.write("\nLast file: %s " % (infile)) raise # except: diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index b9639e97e..a3942f5f8 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -2,11 +2,10 @@ """ Python 3.7 base code. We keep non-custom-generated grammar rules out of this file. """ -from uncompyle6.parser import ParserError, PythonParser, nop_func -from uncompyle6.parsers.treenode import SyntaxTree from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser.spark import rule2str +from uncompyle6.parser import ParserError, PythonParser, nop_func from uncompyle6.parsers.reducecheck import ( and_invalid, ifelsestmt, @@ -16,9 +15,10 @@ or_check, testtrue, tryelsestmtl3, - while1stmt, while1elsestmt, + while1stmt, ) +from uncompyle6.parsers.treenode import SyntaxTree class Python37BaseParser(PythonParser): @@ -54,7 +54,7 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize): expr call CALL_FUNCTION_3 - """ + """ # FIXME: I bet this can be simplified # look for next MAKE_FUNCTION for i in range(i + 1, len(tokens)): @@ -104,7 +104,6 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize): # organization for this. For example, arrange organize by opcode base? def customize_grammar_rules(self, tokens, customize): - is_pypy = False # For a rough break out on the first word. This may @@ -321,18 +320,24 @@ def customize_grammar_rules(self, tokens, customize): elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): if opname == "BUILD_CONST_DICT": - rule = """ + rule = ( + """ add_consts ::= ADD_VALUE* const_list ::= COLLECTION_START add_consts %s dict ::= const_list expr ::= dict - """ % opname + """ + % opname + ) else: - rule = """ + rule = ( + """ add_consts ::= ADD_VALUE* const_list ::= COLLECTION_START add_consts %s expr ::= const_list - """ % opname + """ + % opname + ) self.addRule(rule, nop_func) elif opname_base == "BUILD_CONST_KEY_MAP": @@ -348,7 +353,6 @@ def customize_grammar_rules(self, tokens, customize): self.addRule(rule, nop_func) elif opname_base in ("BUILD_MAP", "BUILD_MAP_UNPACK"): - if opname == "BUILD_MAP_UNPACK": self.addRule( """ @@ -525,7 +529,6 @@ def customize_grammar_rules(self, tokens, customize): "CALL_FUNCTION_VAR_KW", ) ) or opname.startswith("CALL_FUNCTION_KW"): - if opname == "CALL_FUNCTION" and token.attr == 1: rule = """ expr ::= dict_comp @@ -1259,12 +1262,11 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): if fn: return fn(self, lhs, n, rule, ast, tokens, first, last) except Exception: - import sys, traceback + import sys + import traceback print( - ("Exception in %s %s\n" - + "rule: %s\n" - + "offsets %s .. %s") + ("Exception in %s %s\n" + "rule: %s\n" + "offsets %s .. %s") % ( fn.__name__, sys.exc_info()[1], diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 0af8304cc..e7cfa6083 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -21,12 +21,10 @@ scanners, e.g. for Python 2.7 or 3.4. """ +import sys from array import array from collections import namedtuple -import sys -from uncompyle6.scanners.tok import Token -from xdis.version_info import IS_PYPY, version_tuple_to_str import xdis from xdis import ( Bytecode, @@ -36,6 +34,9 @@ instruction_size, next_offset, ) +from xdis.version_info import IS_PYPY, version_tuple_to_str + +from uncompyle6.scanners.tok import Token # The byte code versions we support. # Note: these all have to be tuples of 2 ints @@ -80,6 +81,7 @@ intern = sys.intern L65536 = 65536 + def long(num): return num @@ -108,9 +110,6 @@ def __init__(self, version: tuple, show_asm=None, is_pypy=False): self.show_asm = show_asm self.is_pypy = is_pypy - # Temoorary initialization. - self.opc = ModuleType("uninitialized") - if version[:2] in PYTHON_VERSIONS: v_str = "opcode_%s" % version_tuple_to_str( version, start=0, end=2, delimiter="" @@ -130,9 +129,7 @@ def __init__(self, version: tuple, show_asm=None, is_pypy=False): # FIXME: This weird Python2 behavior is not Python3 self.resetTokenClass() - def bound_collection_from_tokens( - self, tokens, t, i, collection_type - ): + def bound_collection_from_tokens(self, tokens, t, i, collection_type): count = t.attr assert isinstance(count, int) @@ -334,7 +331,7 @@ def print_bytecode(self): else: print("%i\t%s\t" % (i, self.opname[op])) - def first_instr(self, start: int, end: int, instr, target=None, exact=True): + def first_instr(self, start, end, instr, target=None, exact=True): """ Find the first in the block from start to end. is any python bytecode instruction or a list of opcodes @@ -622,8 +619,7 @@ def parse_fn_counts_30_35(argc): return ((argc & 0xFF), (argc >> 8) & 0xFF, annotate_count) -def get_scanner(version: Union[str, tuple], is_pypy=False, show_asm=None) -> Scanner: - +def get_scanner(version, is_pypy=False, show_asm=None): # If version is a string, turn that into the corresponding float. if isinstance(version, str): if version not in canonic_python_version: @@ -684,5 +680,6 @@ def get_scanner(version: Union[str, tuple], is_pypy=False, show_asm=None) -> Sca # scanner = get_scanner('2.7.13', True) # scanner = get_scanner(sys.version[:5], False) from xdis.version_info import PYTHON_VERSION_TRIPLE + scanner = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY, True) tokens, customize = scanner.ingest(co, {}, show_asm="after") diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 695f5fa53..fbd242f7f 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -36,12 +36,12 @@ from __future__ import print_function from copy import copy +from sys import intern -from xdis import code2num, iscode, op_has_argument, instruction_size +from xdis import code2num, instruction_size, iscode, op_has_argument from xdis.bytecode import _get_const_info -from uncompyle6.scanner import Scanner, Token -from sys import intern +from uncompyle6.scanner import Scanner, Token class Scanner2(Scanner): @@ -236,7 +236,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() for i in self.op_range(0, codelen): - # We need to detect the difference between: # raise AssertionError # and @@ -328,9 +327,14 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): "BUILD_SET", ): t = Token( - op_name, oparg, pattr, offset, + op_name, + oparg, + pattr, + offset, self.linestarts.get(offset, None), - op, has_arg, self.opc + op, + has_arg, + self.opc, ) collection_type = op_name.split("_")[1] next_tokens = self.bound_collection_from_tokens( @@ -541,14 +545,17 @@ def build_statement_indices(self): for s in stmt_list: if code[s] == self.opc.JUMP_ABSOLUTE and s not in pass_stmts: target = self.get_target(s) - if target > s or (self.lines and self.lines[last_stmt].l_no == self.lines[s].l_no): + if target > s or ( + self.lines and self.lines[last_stmt].l_no == self.lines[s].l_no + ): stmts.remove(s) continue j = self.prev[s] while code[j] == self.opc.JUMP_ABSOLUTE: j = self.prev[j] if ( - self.version >= (2, 3) and self.opname_for_offset(j) == "LIST_APPEND" + self.version >= (2, 3) + and self.opname_for_offset(j) == "LIST_APPEND" ): # list comprehension stmts.remove(s) continue @@ -925,7 +932,6 @@ def detect_control_flow(self, offset, op, extended_arg): # Is it an "and" inside an "if" or "while" block if op == self.opc.PJIF: - # Search for other POP_JUMP_IF_...'s targeting the # same target, of the current POP_JUMP_... instruction, # starting from current offset, and filter everything inside inner 'or' @@ -1117,7 +1123,6 @@ def detect_control_flow(self, offset, op, extended_arg): # Is this a loop and not an "if" statement? if (if_end < pre_rtarget) and (pre[if_end] in self.setup_loop_targets): - if if_end > start: return else: @@ -1467,11 +1472,12 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): if __name__ == "__main__": import inspect + from xdis.version_info import PYTHON_VERSION_TRIPLE co = inspect.currentframe().f_code tokens, customize = Scanner2(PYTHON_VERSION_TRIPLE).ingest(co) for t in tokens: - print(t) + print(t) pass diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 462957653..3491a25c1 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -35,20 +35,18 @@ from __future__ import print_function -from xdis import iscode, instruction_size, Instruction -from xdis.bytecode import _get_const_info +import sys -from uncompyle6.scanners.tok import Token -from uncompyle6.scanner import parse_fn_counts_30_35 -from uncompyle6.util import get_code_name import xdis # Get all the opcodes into globals import xdis.opcodes.opcode_33 as op3 +from xdis import Instruction, instruction_size, iscode +from xdis.bytecode import _get_const_info -from uncompyle6.scanner import Scanner, CONST_COLLECTIONS - -import sys +from uncompyle6.scanner import CONST_COLLECTIONS, Scanner, parse_fn_counts_30_35 +from uncompyle6.scanners.tok import Token +from uncompyle6.util import get_code_name intern = sys.intern @@ -261,7 +259,7 @@ def bound_collection_from_inst( opname="COLLECTION_START", attr=collection_enum, pattr=collection_type, - offset= "%s_0" % start_offset, + offset="%s_0" % start_offset, linestart=False, has_arg=True, has_extended_arg=False, @@ -296,7 +294,8 @@ def bound_collection_from_inst( return new_tokens def bound_map_from_inst( - self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int): + self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int + ): """ Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can be parsed much faster, but inserting the @@ -379,9 +378,7 @@ def bound_map_from_inst( ) return new_tokens - def ingest( - self, co, classname=None, code_objects={}, show_asm=None - ): + def ingest(self, co, classname=None, code_objects={}, show_asm=None): """ Create "tokens" the bytecode of an Python code object. Largely these are the opcode name, but in some cases that has been modified to make parsing @@ -647,7 +644,9 @@ def ingest( ) pattr = "%s positional, %s keyword only, %s annotated" % ( - pos_args, name_pair_args, annotate_args + pos_args, + name_pair_args, + annotate_args, ) if name_pair_args > 0 and annotate_args > 0: @@ -1542,10 +1541,10 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): if __name__ == "__main__": - from xdis.version_info import PYTHON_VERSION_TRIPLE - import inspect + from xdis.version_info import PYTHON_VERSION_TRIPLE + co = inspect.currentframe().f_code tokens, customize = Scanner3(PYTHON_VERSION_TRIPLE).ingest(co) diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 3206ba09e..4a4f74b79 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -22,14 +22,13 @@ scanner routine for Python 3. """ -from uncompyle6.scanner import CONST_COLLECTIONS -from uncompyle6.scanners.tok import Token - -from uncompyle6.scanners.scanner37base import Scanner37Base - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_37 as opc +from uncompyle6.scanner import CONST_COLLECTIONS +from uncompyle6.scanners.scanner37base import Scanner37Base +from uncompyle6.scanners.tok import Token + # bytecode verification, verify(), uses JUMP_OPS from here JUMP_OPs = opc.JUMP_OPS @@ -193,4 +192,6 @@ def ingest(self, bytecode, classname=None, code_objects={}, show_asm=None): print(t.format()) pass else: - print("Need to be Python 3.7 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 3.7 to demo; I am version %s." % version_tuple_to_str() + ) diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index ccbcec936..499538bd6 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -29,18 +29,16 @@ Finally we save token information. """ -from xdis import iscode, instruction_size, Instruction -from xdis.bytecode import _get_const_info +import sys -from uncompyle6.scanner import Token import xdis # Get all the opcodes into globals import xdis.opcodes.opcode_37 as op3 +from xdis import Instruction, instruction_size, iscode +from xdis.bytecode import _get_const_info -from uncompyle6.scanner import Scanner - -import sys +from uncompyle6.scanner import Scanner, Token globals().update(op3.opmap) @@ -252,7 +250,6 @@ def tokens_append(j, token): n = len(self.insts) for i, inst in enumerate(self.insts): - # We need to detect the difference between: # raise AssertionError # and @@ -282,7 +279,6 @@ def tokens_append(j, token): # To simplify things we want to untangle this. We also # do this loop before we compute jump targets. for i, inst in enumerate(self.insts): - # One artifact of the "too-small" operand problem, is that # some backward jumps, are turned into forward jumps to another # "extended arg" backward jump to the same location. @@ -319,7 +315,6 @@ def tokens_append(j, token): j = 0 for i, inst in enumerate(self.insts): - argval = inst.argval op = inst.opcode @@ -707,9 +702,7 @@ def build_statement_indices(self): # Finish filling the list for last statement slist += [codelen] * (codelen - len(slist)) - def detect_control_flow( - self, offset, targets, inst_index - ): + def detect_control_flow(self, offset, targets, inst_index): """ Detect type of block structures and their boundaries to fix optimized jumps in python2.3+ @@ -956,5 +949,7 @@ def next_except_jump(self, start): for t in tokens: print(t) else: - print("Need to be Python 3.7 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 3.7 to demo; I am version %s." % version_tuple_to_str() + ) pass diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index c708ca370..e2bb3cda7 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -17,15 +17,15 @@ """ from uncompyle6.parsers.treenode import SyntaxTree +from uncompyle6.scanners.tok import Token from uncompyle6.semantics.consts import ( INDENT_PER_LEVEL, NO_PARENTHESIS_EVER, PRECEDENCE, - TABLE_R, TABLE_DIRECT, + TABLE_R, ) from uncompyle6.semantics.helper import flatten_list -from uncompyle6.scanners.tok import Token def customize_for_version(self, is_pypy, version): @@ -87,7 +87,7 @@ def n_call_kw_pypy37(node): if line_number != self.line_number: sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1] pass - self.write("%s%s" (sep, value)) + self.write("%s%s" % (sep, value)) sep = ", " assert n >= len(kwargs_names) diff --git a/uncompyle6/semantics/customize38.py b/uncompyle6/semantics/customize38.py index dc3b1d310..36f89a208 100644 --- a/uncompyle6/semantics/customize38.py +++ b/uncompyle6/semantics/customize38.py @@ -23,8 +23,8 @@ from uncompyle6.semantics.customize37 import FSTRING_CONVERSION_MAP from uncompyle6.semantics.helper import escape_string, strip_quotes -def customize_for_version38(self, version): +def customize_for_version38(self, version): # FIXME: pytest doesn't add proper keys in testing. Reinstate after we have fixed pytest. # for lhs in 'for forelsestmt forelselaststmt ' # 'forelselaststmtc tryfinally38'.split(): @@ -40,10 +40,10 @@ def customize_for_version38(self, version): ), "async_forelse_stmt38": ( "%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n", - (7, 'store'), - (0, 'expr'), - (8, 'for_block'), - (-1, 'else_suite') + (7, "store"), + (0, "expr"), + (8, "for_block"), + (-1, "else_suite"), ), "async_with_stmt38": ( "%|async with %c:\n%+%c%-\n", @@ -70,8 +70,15 @@ def customize_for_version38(self, version): ), # Python 3.8 reverses the order of keys and items # from all prior versions of Python. - "dict_comp_body": ("%c: %c", (0, "expr"), (1, "expr"),), - "except_cond1a": ("%|except %c:\n", (1, "expr"),), + "dict_comp_body": ( + "%c: %c", + (0, "expr"), + (1, "expr"), + ), + "except_cond1a": ( + "%|except %c:\n", + (1, "expr"), + ), "except_cond_as": ( "%|except %c as %c:\n", (1, "expr"), @@ -124,7 +131,11 @@ def customize_for_version38(self, version): "pop_return": ("%|return %c\n", (1, "return_expr")), "popb_return": ("%|return %c\n", (0, "return_expr")), "pop_ex_return": ("%|return %c\n", (0, "return_expr")), - "set_for": (" for %c in %c", (2, "store"), (0, "expr_or_arg"),), + "set_for": ( + " for %c in %c", + (2, "store"), + (0, "expr_or_arg"), + ), "whilestmt38": ( "%|while %c:\n%+%c%-\n\n", (1, ("bool_op", "testexpr", "testexprc")), @@ -322,7 +333,9 @@ def n_formatted_value_debug(node): f_conversion = self.traverse(formatted_value, indent="") # Remove leaving "f" and quotes conversion = strip_quotes(f_conversion[1:]) - f_str = "f%s" % escape_string(("%s%s" % (value_equal, conversion)) + post_str) + f_str = "f%s" % escape_string( + ("%s%s" % (value_equal, conversion)) + post_str + ) self.write(f_str) self.in_format_string = old_in_format_string diff --git a/uncompyle6/semantics/make_function1.py b/uncompyle6/semantics/make_function1.py index 4b47e1eb5..7abb63686 100644 --- a/uncompyle6/semantics/make_function1.py +++ b/uncompyle6/semantics/make_function1.py @@ -17,16 +17,18 @@ All the crazy things we have to do to handle Python functions in Python before 3.0. The saga of changes continues in 3.0 and above and in other files. """ -from uncompyle6.scanner import Code -from uncompyle6.semantics.parser_error import ParserError +from xdis import iscode + from uncompyle6.parser import ParserError as ParserError2 +from uncompyle6.scanner import Code from uncompyle6.semantics.helper import ( - print_docstring, find_all_globals, find_globals_and_nonlocals, find_none, + print_docstring, ) -from xdis import iscode +from uncompyle6.semantics.parser_error import ParserError + def make_function1(self, node, is_lambda, nested=1, code_node=None): """ @@ -36,8 +38,8 @@ def make_function1(self, node, is_lambda, nested=1, code_node=None): def build_param(tree, param_names: list) -> tuple: """build parameters: - - handle defaults - - handle format tuple parameters + - handle defaults + - handle format tuple parameters """ # if formal parameter is a tuple, the parameter name # starts with a dot (eg. '.1', '.2') @@ -186,5 +188,5 @@ def build_param(tree, param_names: list) -> tuple: tree, code.co_name, code._customize, is_lambda=is_lambda, returnNone=rn ) - code._tokens = None # save memory + code._tokens = None # save memory code._customize = None # save memory diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index bf364a466..27df05574 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -16,22 +16,12 @@ Custom Nonterminal action functions. See NonterminalActions docstring. """ -from uncompyle6.semantics.consts import ( - INDENT_PER_LEVEL, - NONE, - PRECEDENCE, - minint, -) - from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import Token +from uncompyle6.semantics.consts import INDENT_PER_LEVEL, NONE, PRECEDENCE, minint +from uncompyle6.semantics.helper import find_code_node, flatten_list from uncompyle6.util import better_repr, get_code_name -from uncompyle6.semantics.helper import ( - find_code_node, - flatten_list, -) - class NonterminalActions: """ @@ -227,8 +217,10 @@ def n_const_list(self, node): else: # from trepan.api import debug; debug() raise TypeError( - ("Internal Error: n_const_list expects dict, list set, or set; got %s" - % lastnodetype) + ( + "Internal Error: n_const_list expects dict, list set, or set; got %s" + % lastnodetype + ) ) self.indent_more(INDENT_PER_LEVEL) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 605db2d72..cd57ca59d 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -773,7 +773,8 @@ def template_engine(self, entry, startnode): """ Expanding '%s' in template '%s[%s]': %s is invalid; has only %d entries - """ % (node.kind, entry, arg, index, len(node)) + """ + % (node.kind, entry, arg, index, len(node)) ) self.preorder(node[index]) @@ -1343,10 +1344,10 @@ def code_deparse( if expected_start: assert ( deparsed.ast == expected_start - ), ( - "Should have parsed grammar start to '%s'; got: %s" % - (expected_start, deparsed.ast.kind) - ) + ), "Should have parsed grammar start to '%s'; got: %s" % ( + expected_start, + deparsed.ast.kind, + ) # save memory del tokens From a1f463982f31494476574c2c12d828bdb9b1e319 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 12:40:25 -0500 Subject: [PATCH 370/489] Black one more file --- uncompyle6/semantics/gencomp-for-3.0.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/gencomp-for-3.0.py b/uncompyle6/semantics/gencomp-for-3.0.py index 3d2e13f0d..ec90ef3dd 100644 --- a/uncompyle6/semantics/gencomp-for-3.0.py +++ b/uncompyle6/semantics/gencomp-for-3.0.py @@ -23,9 +23,9 @@ from uncompyle6.parser import get_python_parser from uncompyle6.scanner import Code +from uncompyle6.scanners.tok import Token from uncompyle6.semantics.consts import PRECEDENCE from uncompyle6.semantics.helper import is_lambda_mode -from uncompyle6.scanners.tok import Token class ComprehensionMixin: @@ -513,8 +513,9 @@ def comprehension_walk_newer( else: self.preorder(node[in_node_index]) - from trepan.api import debug; debug() + from trepan.api import debug + debug() # Here is where we handle nested list iterations. if tree == "list_comp" and self.version != (3, 0): list_iter = tree[1] From 9c5addc0f0cf10a75ef7100e4f61adcd7277b580 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 13:56:28 -0500 Subject: [PATCH 371/489] Python 2.5 compatability --- uncompyle6/main.py | 45 +--------- uncompyle6/scanner.py | 11 ++- uncompyle6/scanners/scanner15.py | 11 +-- uncompyle6/scanners/scanner26.py | 128 +++++++++++++++++---------- uncompyle6/scanners/scanner27.py | 12 +-- uncompyle6/scanners/scanner3.py | 23 +---- uncompyle6/scanners/scanner37base.py | 2 +- uncompyle6/scanners/scanner38.py | 18 ++-- uncompyle6/semantics/fragments.py | 20 ++--- uncompyle6/semantics/n_actions.py | 17 ++-- uncompyle6/semantics/pysource.py | 3 +- uncompyle6/util.py | 9 +- 12 files changed, 131 insertions(+), 168 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index d92a2ad76..020d43fac 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -307,17 +307,6 @@ def main( outstream = sys.stdout if do_linemaps: linemap_stream = sys.stdout - if do_verify: - prefix = os.path.basename(filename) + "-" - if prefix.endswith(".py"): - prefix = prefix[: -len(".py")] - - # Unbuffer output if possible - if sys.stdout.isatty(): - buffering = -1 - else: - buffering = 0 - sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) else: if filename.endswith(".pyc"): current_outfile = os.path.join(out_base, filename[0:-1]) @@ -399,39 +388,7 @@ def main( else: # uncompile successful if current_outfile: outstream.close() - if do_verify: - try: - msg = verify.compare_code_with_srcfile( - infile, current_outfile, do_verify - ) - if not current_outfile: - if not msg: - print("\n# okay decompiling %s" % infile) - okay_files += 1 - else: - verify_failed_files += 1 - print("\n# %s\n\t%s", infile, msg) - pass - else: - okay_files += 1 - pass - 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 - pass - pass - else: - okay_files += 1 + okay_files += 1 pass elif do_verify: sys.stderr.write("\n### uncompile successful, " diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index cb822f026..c04039d86 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -32,9 +32,7 @@ instruction_size, next_offset, ) -from xdis.version_info import PYTHON_VERSION_TRIPLE - -from xdis.version_info import IS_PYPY, version_tuple_to_str +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str from uncompyle6.scanners.tok import Token @@ -106,7 +104,7 @@ def __init__(self, co, scanner, classname=None, show_asm=None): class Scanner: - def __init__(self, version: tuple, show_asm=None, is_pypy=False): + def __init__(self, version, show_asm=None, is_pypy=False): self.version = version self.show_asm = show_asm self.is_pypy = is_pypy @@ -321,7 +319,7 @@ def get_argument(self, pos): return arg def next_offset(self, op, offset): - return xdis.next_offset(op, self.opc, offset) + return next_offset(op, self.opc, offset) def print_bytecode(self): for i in self.op_range(0, len(self.code)): @@ -646,7 +644,7 @@ def get_scanner(version, is_pypy=False, show_asm=None): raise RuntimeError( "Import Python version, %s, for decompilation failed" % version_tuple_to_str(version) - ) + ) if is_pypy: scanner_class_name = "ScannerPyPy%s" % v_str @@ -671,5 +669,6 @@ def get_scanner(version, is_pypy=False, show_asm=None): # scanner = get_scanner('2.7.13', True) # scanner = get_scanner(sys.version[:5], False) from xdis.version_info import PYTHON_VERSION_TRIPLE + scanner = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY, True) tokens, customize = scanner.ingest(co, {}, show_asm="after") diff --git a/uncompyle6/scanners/scanner15.py b/uncompyle6/scanners/scanner15.py index 6f1876784..6a894a2ac 100644 --- a/uncompyle6/scanners/scanner15.py +++ b/uncompyle6/scanners/scanner15.py @@ -6,21 +6,18 @@ grammar parsing. """ +# bytecode verification, verify(), uses JUMP_OPs from here +from xdis.opcodes import opcode_15 + import uncompyle6.scanners.scanner21 as scan # from uncompyle6.scanners.scanner26 import ingest as ingest26 -# bytecode verification, verify(), uses JUMP_OPs from here -from xdis.opcodes import opcode_15 JUMP_OPS = opcode_15.JUMP_OPS -<<<<<<< HEAD -# We base this off of 2.1 instead of the other way around -======= -# We base this off of 2.2 instead of the other way around ->>>>>>> python-3.0-to-3.2 +# We base this off of 2.1 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. diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index b13ae49d3..a8eaef861 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -22,25 +22,28 @@ use in deparsing. """ -import uncompyle6.scanners.scanner2 as scan - -# bytecode verification, verify(), uses JUMP_OPs from here +# bytecode verification, verify(), uses jump_ops from here from xdis import iscode -from xdis.opcodes import opcode_26 from xdis.bytecode import _get_const_info +from xdis.opcodes import opcode_26 from uncompyle6.scanner import Token +from uncompyle6.scanners.scanner2 import Scanner2 JUMP_OPS = opcode_26.JUMP_OPS -class Scanner26(scan.Scanner2): + +class Scanner26(Scanner2): def __init__(self, show_asm=False): - super(Scanner26, self).__init__((2, 6), show_asm) + Scanner2.__init__(self, (2, 6), show_asm) # "setup" opcodes - self.setup_ops = frozenset([ - self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY, - ]) + self.setup_ops = frozenset( + [ + self.opc.SETUP_EXCEPT, + self.opc.SETUP_FINALLY, + ] + ) return @@ -93,17 +96,18 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # 'LOAD_ASSERT' is used in assert statements. self.load_asserts = set() for i in self.op_range(0, codelen): - # We need to detect the difference between: # raise AssertionError # and # assert ... - if (self.code[i] == self.opc.JUMP_IF_TRUE and - i + 4 < codelen and - self.code[i+3] == self.opc.POP_TOP and - self.code[i+4] == self.opc.LOAD_GLOBAL): - if names[self.get_argument(i+4)] == 'AssertionError': - self.load_asserts.add(i+4) + if ( + self.code[i] == self.opc.JUMP_IF_TRUE + and i + 4 < codelen + and self.code[i + 3] == self.opc.POP_TOP + and self.code[i + 4] == self.opc.LOAD_GLOBAL + ): + if names[self.get_argument(i + 4)] == "AssertionError": + self.load_asserts.add(i + 4) jump_targets = self.find_jump_targets(show_asm) # contains (code, [addrRefToCode]) @@ -128,7 +132,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): i += 1 op = self.code[offset] op_name = self.opname[op] - oparg = None; pattr = None + oparg = None + pattr = None if offset in jump_targets: jump_idx = 0 @@ -139,28 +144,37 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # properly. For example, a "loop" with an "if" nested in it should have the # "loop" tag last so the grammar rule matches that properly. last_jump_offset = -1 - for jump_offset in sorted(jump_targets[offset], reverse=True): + for jump_offset in sorted(jump_targets[offset], reverse=True): if jump_offset != last_jump_offset: - tokens.append(Token( - 'COME_FROM', jump_offset, repr(jump_offset), - offset="%s_%d" % (offset, jump_idx), - has_arg = True)) + tokens.append( + Token( + "COME_FROM", + jump_offset, + repr(jump_offset), + offset="%s_%d" % (offset, jump_idx), + has_arg=True, + ) + ) jump_idx += 1 last_jump_offset = jump_offset elif offset in self.thens: - tokens.append(Token( - 'THEN', None, self.thens[offset], - offset="%s_0" % offset, - has_arg = True)) + tokens.append( + Token( + "THEN", + None, + self.thens[offset], + offset="%s_0" % offset, + has_arg=True, + ) + ) - has_arg = (op >= self.opc.HAVE_ARGUMENT) + has_arg = op >= self.opc.HAVE_ARGUMENT if has_arg: oparg = self.get_argument(offset) + extended_arg extended_arg = 0 if op == self.opc.EXTENDED_ARG: - extended_arg += self.extended_arg_val(oparg) - continue - + extended_arg += self.extended_arg_val(oparg) + continue # Note: name used to match on rather than op since # BUILD_SET isn't in earlier Pythons. @@ -169,7 +183,14 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): "BUILD_SET", ): t = Token( - op_name, oparg, pattr, offset, self.linestarts.get(offset, None), op, has_arg, self.opc + op_name, + oparg, + pattr, + offset, + self.linestarts.get(offset, None), + op, + has_arg, + self.opc, ) collection_type = op_name.split("_")[1] @@ -218,8 +239,8 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # FIXME: this is a hack to catch stuff like: # if x: continue # the "continue" is not on a new line. - if len(tokens) and tokens[-1].kind == 'JUMP_BACK': - tokens[-1].kind = intern('CONTINUE') + if len(tokens) and tokens[-1].kind == "JUMP_BACK": + tokens[-1].kind = intern("CONTINUE") elif op in self.opc.JABS_OPS: pattr = repr(oparg) @@ -237,17 +258,23 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # CE - Hack for >= 2.5 # Now all values loaded via LOAD_CLOSURE are packed into # a tuple before calling MAKE_CLOSURE. - if (self.version >= (2, 5) and op == self.opc.BUILD_TUPLE and - self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE): + if ( + self.version >= (2, 5) + and op == self.opc.BUILD_TUPLE + and self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE + ): continue else: - op_name = '%s_%d' % (op_name, oparg) + op_name = "%s_%d" % (op_name, oparg) customize[op_name] = oparg elif self.version > (2, 0) and op == self.opc.CONTINUE_LOOP: customize[op_name] = 0 - elif op_name in """ + elif ( + op_name + in """ CONTINUE_LOOP EXEC_STMT LOAD_LISTCOMP LOAD_SETCOMP - """.split(): + """.split() + ): customize[op_name] = 0 elif op == self.opc.JUMP_ABSOLUTE: # Further classify JUMP_ABSOLUTE into backward jumps @@ -263,23 +290,24 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # rule for that. target = self.get_target(offset) if target <= offset: - op_name = 'JUMP_BACK' - if (offset in self.stmts - and self.code[offset+3] not in (self.opc.END_FINALLY, - self.opc.POP_BLOCK)): - if ((offset in self.linestarts and - tokens[-1].kind == 'JUMP_BACK') - or offset not in self.not_continue): - op_name = 'CONTINUE' + op_name = "JUMP_BACK" + if offset in self.stmts and self.code[offset + 3] not in ( + self.opc.END_FINALLY, + self.opc.POP_BLOCK, + ): + if ( + offset in self.linestarts and tokens[-1].kind == "JUMP_BACK" + ) or offset not in self.not_continue: + op_name = "CONTINUE" else: # FIXME: this is a hack to catch stuff like: # if x: continue # the "continue" is not on a new line. - if tokens[-1].kind == 'JUMP_BACK': + if tokens[-1].kind == "JUMP_BACK": # We need 'intern' since we have # already have processed the previous # token. - tokens[-1].kind = intern('CONTINUE') + tokens[-1].kind = intern("CONTINUE") elif op == self.opc.LOAD_GLOBAL: if offset in self.load_asserts: @@ -331,4 +359,6 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): print(t.format()) pass else: - print("Need to be Python 2.6 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 2.6 to demo; I am version %s." % version_tuple_to_str() + ) diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 01f4ee5a9..ddb8e8ee3 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -7,20 +7,20 @@ """ -from uncompyle6.scanners.scanner2 import Scanner2 - -from xdis.version_info import version_tuple_to_str import sys # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_27 +from xdis.version_info import version_tuple_to_str + +from uncompyle6.scanners.scanner2 import Scanner2 JUMP_OPS = opcode_27.JUMP_OPs class Scanner27(Scanner2): def __init__(self, show_asm=False, is_pypy=False): - super(Scanner27, self).__init__((2, 7), show_asm, is_pypy) + Scanner2.__init__(self, (2, 7), show_asm, is_pypy) # opcodes that start statements self.statement_opcodes = frozenset( @@ -117,4 +117,6 @@ def __init__(self, show_asm=False, is_pypy=False): print(t.format()) pass else: - print("Need to be Python 2.7 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 2.7 to demo; I am version %s." % version_tuple_to_str() + ) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 7f2486c5f..b3d520da8 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -33,11 +33,6 @@ Finally we save token information. """ -from xdis import iscode, instruction_size -from xdis.bytecode import _get_const_info - -from uncompyle6.scanners.tok import Token -from uncompyle6.scanner import parse_fn_counts_30_35 import xdis # Get all the opcodes into globals @@ -54,7 +49,7 @@ class Scanner3(Scanner): def __init__(self, version, show_asm=None, is_pypy=False): - super(Scanner3, self).__init__(version, show_asm, is_pypy) + Scanner.__init__(self, version, show_asm, is_pypy) # Create opcode classification sets # Note: super initialization above initializes self.opc @@ -286,8 +281,7 @@ def bound_collection_from_inst( ) return new_tokens - def bound_map_from_inst( - self, insts, next_tokens, inst, t, i): + def bound_map_from_inst(self, insts, next_tokens, inst, t, i): """ Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can be parsed much faster, but inserting the @@ -1532,16 +1526,3 @@ def rem_or(self, start, end, instr, target=None, include_beyond_target=False): instr_offsets = filtered filtered = [] return instr_offsets - - -if __name__ == "__main__": - import inspect - - from xdis.version_info import PYTHON_VERSION_TRIPLE - - co = inspect.currentframe().f_code - - tokens, customize = Scanner3(PYTHON_VERSION_TRIPLE).ingest(co) - for t in tokens: - print(t) ->>>>>>> python-3.0-to-3.2 diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 2aa457e99..10a2d3e3a 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -48,7 +48,7 @@ class Scanner37Base(Scanner): def __init__(self, version, show_asm=None, debug="", is_pypy=False): - super(Scanner37Base, self).__init__(version, show_asm, is_pypy) + Scanner.__init__(self, version, show_asm, is_pypy) self.offset2tok_index = None self.debug = debug self.is_pypy = is_pypy diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index 6fad6c775..168583286 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -22,13 +22,13 @@ scanner routine for Python 3.7 and up. """ -from uncompyle6.scanners.tok import off2int -from uncompyle6.scanners.scanner37 import Scanner37 -from uncompyle6.scanners.scanner37base import Scanner37Base - # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_38 as opc +from uncompyle6.scanners.scanner37 import Scanner37 +from uncompyle6.scanners.scanner37base import Scanner37Base +from uncompyle6.scanners.tok import off2int + # bytecode verification, verify(), uses JUMP_OPS from here JUMP_OPs = opc.JUMP_OPS @@ -60,8 +60,8 @@ def ingest(self, bytecode, classname=None, code_objects={}, show_asm=None): grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST cause specific rules for the specific number of arguments they take. """ - tokens, customize = super(Scanner38, self).ingest( - bytecode, classname, code_objects, show_asm + tokens, customize = Scanner37.ingest( + self, bytecode, classname, code_objects, show_asm ) # Hacky way to detect loop ranges. @@ -93,7 +93,7 @@ def ingest(self, bytecode, classname=None, code_objects={}, show_asm=None): if len(loop_ends): next_end = loop_ends[-1] else: - next_end = tokens[len(tokens)-1].off2int() + 10 + next_end = tokens[len(tokens) - 1].off2int() + 10 # things that smash new_tokens like BUILD_LIST have to come first. @@ -161,4 +161,6 @@ def ingest(self, bytecode, classname=None, code_objects={}, show_asm=None): print(t.format()) pass else: - print("Need to be Python 3.8 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 3.8 to demo; I am version %s." % version_tuple_to_str() + ) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 9f1ff29a6..a4f908a15 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -65,7 +65,6 @@ import re from bisect import bisect_right -from collections import namedtuple from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser.ast import GenericASTTraversalPruningException @@ -77,7 +76,7 @@ from uncompyle6.scanner import Code, Token, get_scanner from uncompyle6.semantics import pysource from uncompyle6.semantics.check_ast import checker -from uncompyle6.semantics.pysource import ParserError +from uncompyle6.semantics.parser_error import ParserError from uncompyle6.show import maybe_show_asm, maybe_show_tree if PYTHON_VERSION_TRIPLE < (2, 5): @@ -94,19 +93,18 @@ TABLE_DIRECT, escape, ) -if PYTHON_VERSION_TRIPLE < (2, 6): - from xdis.namedtuple24 import namedtuple -else: - from collections import namedtuple - from uncompyle6.semantics.pysource import ( DEFAULT_DEBUG_OPTS, TREE_DEFAULT_DEBUG, - ParserError, StringIO, ) from uncompyle6.show import maybe_show_asm, maybe_show_tree +if PYTHON_VERSION_TRIPLE < (2, 6): + from xdis.namedtuple24 import namedtuple +else: + from collections import namedtuple + NodeInfo = namedtuple("NodeInfo", "node start finish") ExtractInfo = namedtuple( "ExtractInfo", @@ -166,7 +164,7 @@ class FragmentsWalker(pysource.SourceWalker, object): def __init__( self, - version: tuple, + version, scanner, showast=TREE_DEFAULT_DEBUG, debug_parser=PARSER_DEFAULT_DEBUG, @@ -1201,7 +1199,7 @@ def build_ast( ast = python_parser.parse(self.p, tokens, customize, code) self.customize(customize) self.p.insts = p_insts - except (parser.ParserError(e), AssertionError(e)): + except (ParserError(e), AssertionError(e)): raise ParserError(e, tokens) transform_tree = self.treeTransform.transform(ast, code) maybe_show_tree(self, ast) @@ -1241,7 +1239,7 @@ def build_ast( self.p.opc = self.scanner.opc ast = python_parser.parse(self.p, tokens, customize, code) self.p.insts = p_insts - except (parser.ParserError(e), AssertionError(e)): + except (ParserError(e), AssertionError(e)): raise ParserError(e, tokens, {}) checker(ast, False, self.ast_errors) diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 0f9ef18e3..f93ab0d4e 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 by Rocky Bernstein +# Copyright (c) 2022-2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,16 +18,10 @@ from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import Token - -from uncompyle6.semantics.helper import ( - find_code_node, - flatten_list, -) -from uncompyle6.util import better_repr - from uncompyle6.semantics.consts import INDENT_PER_LEVEL, NONE, PRECEDENCE, minint from uncompyle6.semantics.helper import find_code_node, flatten_list -from uncompyle6.util import better_repr, get_code_name +from uncompyle6.util import better_repr + class NonterminalActions: """ @@ -719,8 +713,9 @@ def n_generator_exp(self, node): iter_index = 4 else: iter_index = 3 - self.comprehension_walk(node, iter_index=iter_index, - code_index=code_index) + self.comprehension_walk( + node, iter_index=iter_index, code_index=code_index + ) pass pass else: diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 6b2133ff9..244daa532 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -168,6 +168,7 @@ from uncompyle6.semantics.transform import TreeTransform, is_docstring from uncompyle6.show import maybe_show_tree from uncompyle6.util import better_repr + if PYTHON_VERSION_TRIPLE < (2, 5): from cStringIO import StringIO else: @@ -1260,7 +1261,7 @@ def build_ast( self.p.opc = self.scanner.opc ast = parse(self.p, tokens, customize, code) self.p.insts = p_insts - except python_parser.ParserError, e: + except ParserError, e: raise ParserError(e, tokens, self.p.debug["reduce"]) checker(ast, False, self.ast_errors) diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 313e388ad..186ba3e21 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -4,22 +4,23 @@ try: from math import copysign + def is_negative_zero(n): """Returns true if n is -0.0""" return n == 0.0 and copysign(1, n) == -1 + except Exception: + def is_negative_zero(n): return False -def get_code_name(code) -> str: + +def get_code_name(code): code_name = code.co_name if isinstance(code_name, UnicodeForPython3): return code_name.value.decode("utf-8") return code_name -def is_negative_zero(n): - """Returns true if n is -0.0""" - return n == 0.0 and copysign(1, n) == -1 def better_repr(v, version): """Work around Python's unorthogonal and unhelpful repr() for primitive float From ad16ed69ebd3c3f79f9585200adf961ca34ff837 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 14:54:07 -0500 Subject: [PATCH 372/489] Go over 2.x grammar testing --- test-unit/test_grammar.py | 74 +++++++++++++++++++++++------------ uncompyle6/parser.py | 39 ++++++++++-------- uncompyle6/parsers/parse27.py | 3 ++ uncompyle6/parsers/parse3.py | 71 +++++++++++++++++++++------------ 4 files changed, 122 insertions(+), 65 deletions(-) diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index 683d0bccb..7990b4154 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -1,38 +1,53 @@ import re import unittest + +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE + from uncompyle6.parser import get_python_parser, python_parser -from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY + 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([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())) + self.assertEqual( + remain_tokens, + set([]), + "Remaining tokens %s\n====\n%s" % (remain_tokens, p.dump_grammar()), + ) p = get_python_parser(PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY) - (lhs, rhs, tokens, - right_recursive, dup_rhs) = p.check_sets() - expect_lhs = set(['pos_arg', 'get_iter', 'attribute']) - unused_rhs = set(['list', 'call', 'mkfunc', - 'mklambda', - 'unpack',]) + (lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets() + expect_lhs = set(["pos_arg", "get_iter", "attribute"]) + unused_rhs = set(["list", "call", "mkfunc", "unpack", "lambda_body"]) - expect_right_recursive = frozenset([('designList', - ('store', 'DUP_TOP', 'designList'))]) - expect_lhs.add('kwarg') + expect_right_recursive = frozenset( + [("designList", ("store", "DUP_TOP", "designList"))] + ) + expect_lhs.add("kwarg") + + if PYTHON_VERSION_TRIPLE[:2] == (2, 7): + expect_lhs.add("kv3") + expect_lhs.add("kvlist") + unused_rhs.add("dict") 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',)]) + expect_dup_rhs = frozenset( + [ + ("COME_FROM",), + ("CONTINUE",), + ("JUMP_ABSOLUTE",), + ("LOAD_CONST",), + ("JUMP_BACK",), + ("JUMP_FORWARD",), + ] + ) reduced_dup_rhs = {} for k in dup_rhs: @@ -47,10 +62,21 @@ def check_tokens(tokens, opcode_set): # FIXME: Something got borked here def no_test_dup_rule(self): import inspect - python_parser(PYTHON_VERSION_TRIPLE, 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__': + + python_parser( + PYTHON_VERSION_TRIPLE, + 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() diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 1c354d97e..2cdb24711 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -21,10 +21,11 @@ import sys -from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG -from uncompyle6.show import maybe_show_asm +from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG, GenericASTBuilder from xdis import iscode +from uncompyle6.show import maybe_show_asm + class ParserError(Exception): def __init__(self, token, offset, debug=PARSER_DEFAULT_DEBUG): @@ -91,7 +92,14 @@ def __init__(self, syntax_tree_class, start, debug): # singleton reduction that we can simplify. It also happens to be optional # in its other derivation self.optional_nt |= frozenset( - ("come_froms", "suite_stmts", "l_stmts_opt", "c_stmts_opt", "stmts_opt", "stmt") + ( + "come_froms", + "suite_stmts", + "l_stmts_opt", + "c_stmts_opt", + "stmts_opt", + "stmt", + ) ) # Reduce singleton reductions in these nonterminals: @@ -113,10 +121,10 @@ def ast_first_offset(self, ast): def add_unique_rule(self, rule, opname, arg_count, customize): """Add rule to grammar, but only if it hasn't been added previously - opname and stack_count are used in the customize() semantic - the actions to add the semantic action rule. Stack_count is - used in custom opcodes like MAKE_FUNCTION to indicate how - many arguments it has. Often it is not used. + opname and stack_count are used in the customize() semantic + the actions to add the semantic action rule. Stack_count is + used in custom opcodes like MAKE_FUNCTION to indicate how + many arguments it has. Often it is not used. """ if rule not in self.new_rules: # print("XXX ", rule) # debug @@ -223,7 +231,9 @@ def get_pos_kw(self, token): """ # Low byte indicates number of positional parameters, # high byte number of keyword parameters - assert token.kind.startswith("CALL_FUNCTION") or token.kind.startswith("CALL_METHOD") + assert token.kind.startswith("CALL_FUNCTION") or token.kind.startswith( + "CALL_METHOD" + ) args_pos = token.attr & 0xFF args_kw = (token.attr >> 8) & 0xFF return args_pos, args_kw @@ -304,9 +314,6 @@ def p_stmt(self, args): c_stmts ::= lastc_stmt c_stmts ::= continues - ending_return ::= RETURN_VALUE RETURN_LAST - ending_return ::= RETURN_VALUE_LAMBDA LAMBDA_MARKER - lastc_stmt ::= iflaststmt lastc_stmt ::= forelselaststmt lastc_stmt ::= ifelsestmtc @@ -314,9 +321,6 @@ def p_stmt(self, args): c_stmts_opt ::= c_stmts c_stmts_opt ::= pass - stmts_opt ::= _stmts - stmts_opt ::= pass - # statements inside a loop l_stmts ::= _stmts l_stmts ::= returns @@ -907,9 +911,12 @@ def python_parser( if __name__ == "__main__": def parse_test(co): - from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY + from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE - ast = python_parser(PYTHON_VERSION_TRIPLE[:2], co, showasm=True, is_pypy=IS_PYPY) + ast = python_parser( + PYTHON_VERSION_TRIPLE[:2], co, showasm=True, is_pypy=IS_PYPY + ) print(ast) return + parse_test(parse_test.func_code) diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index 88c0482f5..3518e45bb 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -38,6 +38,9 @@ def p_comprehension27(self, args): stmt ::= dict_comp_func + ending_return ::= RETURN_VALUE RETURN_LAST + ending_return ::= RETURN_VALUE_LAMBDA LAMBDA_MARKER + dict_comp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER store comp_iter JUMP_BACK ending_return diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 7019dbac4..667010f42 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -27,22 +27,24 @@ """ import re -from uncompyle6.scanners.tok import Token + +from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG + from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.reducecheck import ( and_invalid, except_handler_else, ifelsestmt, - ifstmt, iflaststmt, + ifstmt, or_check, testtrue, tryelsestmtl3, tryexcept, - while1stmt + while1stmt, ) from uncompyle6.parsers.treenode import SyntaxTree -from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG +from uncompyle6.scanners.tok import Token class Python3Parser(PythonParser): @@ -79,6 +81,9 @@ def p_comprehension3(self, args): stmt ::= set_comp_func + ending_return ::= RETURN_VALUE RETURN_LAST + ending_return ::= RETURN_VALUE_LAMBDA LAMBDA_MARKER + # TODO this can be simplified set_comp_func ::= BUILD_SET_0 LOAD_ARG FOR_ITER store comp_iter JUMP_BACK ending_return @@ -98,7 +103,7 @@ def p_comprehension3(self, args): """ def p_dict_comp3(self, args): - """" + """ " expr ::= dict_comp stmt ::= dict_comp_func dict_comp_func ::= BUILD_MAP_0 LOAD_ARG FOR_ITER store @@ -519,7 +524,7 @@ def custom_build_class_rule(self, opname, i, token, tokens, customize, is_pypy): expr call CALL_FUNCTION_3 - """ + """ # FIXME: I bet this can be simplified # look for next MAKE_FUNCTION j = i @@ -627,7 +632,11 @@ def custom_classfunc_rule(self, opname, token, customize, next_token, is_pypy): self.add_unique_rule(rule, token.kind, uniq_param, customize) if "LOAD_BUILD_CLASS" in self.seen_ops: - if next_token == "CALL_FUNCTION" and next_token.attr == 1 and pos_args_count > 1: + if ( + next_token == "CALL_FUNCTION" + and next_token.attr == 1 + and pos_args_count > 1 + ): rule = "classdefdeco2 ::= LOAD_BUILD_CLASS mkfunc %s%s_%d" % ( ("expr " * (pos_args_count - 1)), opname, @@ -766,18 +775,24 @@ def customize_grammar_rules(self, tokens, customize): elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): if opname == "BUILD_CONST_DICT": - rule = """ + rule = ( + """ add_consts ::= ADD_VALUE* const_list ::= COLLECTION_START add_consts %s dict ::= const_list expr ::= dict - """ % opname + """ + % opname + ) else: - rule = """ + rule = ( + """ add_consts ::= ADD_VALUE* const_list ::= COLLECTION_START add_consts %s expr ::= const_list - """ % opname + """ + % opname + ) self.addRule(rule, nop_func) elif opname.startswith("BUILD_DICT_OLDER"): @@ -932,7 +947,6 @@ def customize_grammar_rules(self, tokens, customize): "CALL_FUNCTION_VAR_KW", ) ) or opname.startswith("CALL_FUNCTION_KW"): - if opname == "CALL_FUNCTION" and token.attr == 1: rule = """ dict_comp ::= LOAD_DICTCOMP LOAD_STR MAKE_FUNCTION_0 expr @@ -1108,7 +1122,8 @@ def customize_grammar_rules(self, tokens, customize): if has_get_iter_call_function1: rule_pat = ( "generator_exp ::= %sload_closure load_genexpr %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ("pos_arg " * pos_args_count, opname) + "GET_ITER CALL_FUNCTION_1" + % ("pos_arg " * pos_args_count, opname) ) self.add_make_function_rule(rule_pat, opname, token.attr, customize) @@ -1194,7 +1209,6 @@ def customize_grammar_rules(self, tokens, customize): ) self.add_unique_rule(rule, opname, token.attr, customize) - if self.version >= (3, 4): if not self.is_pypy: load_op = "LOAD_STR" @@ -1278,14 +1292,16 @@ def customize_grammar_rules(self, tokens, customize): if has_get_iter_call_function1: rule_pat = ( "generator_exp ::= %sload_genexpr %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ("pos_arg " * pos_args_count, opname) + "GET_ITER CALL_FUNCTION_1" + % ("pos_arg " * pos_args_count, opname) ) self.add_make_function_rule( rule_pat, opname, token.attr, customize ) rule_pat = ( "generator_exp ::= %sload_closure load_genexpr %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ("pos_arg " * pos_args_count, opname) + "GET_ITER CALL_FUNCTION_1" + % ("pos_arg " * pos_args_count, opname) ) self.add_make_function_rule( rule_pat, opname, token.attr, customize @@ -1337,7 +1353,8 @@ def customize_grammar_rules(self, tokens, customize): if has_get_iter_call_function1: rule_pat = ( "generator_exp ::= %sload_genexpr %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ("pos_arg " * pos_args_count, opname) + "GET_ITER CALL_FUNCTION_1" + % ("pos_arg " * pos_args_count, opname) ) self.add_make_function_rule(rule_pat, opname, token.attr, customize) @@ -1349,7 +1366,8 @@ def customize_grammar_rules(self, tokens, customize): # Todo: For Pypy we need to modify this slightly rule_pat = ( "listcomp ::= %sLOAD_LISTCOMP %%s%s expr " - "GET_ITER CALL_FUNCTION_1" % ("expr " * pos_args_count, opname) + "GET_ITER CALL_FUNCTION_1" + % ("expr " * pos_args_count, opname) ) self.add_make_function_rule( rule_pat, opname, token.attr, customize @@ -1580,7 +1598,7 @@ def customize_grammar_rules(self, tokens, customize): } if self.version == (3, 6): - self.reduce_check_table["and"] = and_invalid + self.reduce_check_table["and"] = and_invalid self.check_reduce["and"] = "AST" self.check_reduce["annotate_tuple"] = "noAST" @@ -1610,7 +1628,7 @@ def customize_grammar_rules(self, tokens, customize): def reduce_is_invalid(self, rule, ast, tokens, first, last): lhs = rule[0] n = len(tokens) - last = min(last, n-1) + last = min(last, n - 1) fn = self.reduce_check_table.get(lhs, None) if fn: if fn(self, lhs, n, rule, ast, tokens, first, last): @@ -1636,13 +1654,18 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): condition_jump2 = tokens[min(last - 1, len(tokens) - 1)] # If there are two *distinct* condition jumps, they should not jump to the # same place. Otherwise we have some sort of "and"/"or". - if condition_jump2.kind.startswith("POP_JUMP_IF") and condition_jump != condition_jump2: + if ( + condition_jump2.kind.startswith("POP_JUMP_IF") + and condition_jump != condition_jump2 + ): return condition_jump.attr == condition_jump2.attr - if tokens[last] == "COME_FROM" and tokens[last].off2int() != condition_jump.attr: + if ( + tokens[last] == "COME_FROM" + and tokens[last].off2int() != condition_jump.attr + ): return False - # if condition_jump.attr < condition_jump2.off2int(): # print("XXX", first, last) # for t in range(first, last): print(tokens[t]) @@ -1664,7 +1687,6 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): < tokens[last].off2int() ) elif lhs == "while1stmt": - if while1stmt(self, lhs, n, rule, ast, tokens, first, last): return True @@ -1686,7 +1708,6 @@ def reduce_is_invalid(self, rule, ast, tokens, first, last): return True return False elif lhs == "while1elsestmt": - n = len(tokens) if last == n: # Adjust for fuzziness in parsing From d01a047dfd7103857737ae4d885b99abfac9822a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 4 Feb 2024 15:05:47 -0500 Subject: [PATCH 373/489] More 2-x grammar test fixes --- pytest/test_grammar.py | 15 +++++++++++---- test-unit/test_grammar.py | 3 +++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 8bf4b9e65..d792e7c4b 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -1,7 +1,9 @@ import re + +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE + from uncompyle6.parser import get_python_parser, python_parser from uncompyle6.scanner import get_scanner -from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY def test_grammar(): @@ -28,7 +30,7 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("get_iter") - if PYTHON_VERSION_TRIPLE >= (3, 8) or PYTHON_VERSION_TRIPLE < (3, 0): + if PYTHON_VERSION_TRIPLE >= (3, 8): expect_lhs.add("stmts_opt") else: expect_lhs.add("async_with_as_stmt") @@ -46,7 +48,10 @@ def check_tokens(tokens, opcode_set): expect_lhs.add("kv3") unused_rhs.add("dict") else: - if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] not in ((2, 7), (2, 6)): + if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] not in ( + (2, 7), + (2, 6), + ): # NOTE: this may disappear expect_lhs.add("except_handler_else") @@ -101,7 +106,9 @@ def check_tokens(tokens, opcode_set): ) reduced_dup_rhs = dict((k, dup_rhs[k]) for k in dup_rhs if k not in expect_dup_rhs) if reduced_dup_rhs: - print("\nPossible duplicate RHS that might be folded, into one of the LHS symbols") + print( + "\nPossible duplicate RHS that might be folded, into one of the LHS symbols" + ) for k in reduced_dup_rhs: print(k, reduced_dup_rhs[k]) # assert not reduced_dup_rhs, reduced_dup_rhs diff --git a/test-unit/test_grammar.py b/test-unit/test_grammar.py index 7990b4154..1e27c0746 100644 --- a/test-unit/test_grammar.py +++ b/test-unit/test_grammar.py @@ -29,6 +29,9 @@ def check_tokens(tokens, opcode_set): ) expect_lhs.add("kwarg") + if PYTHON_VERSION_TRIPLE[:2] <= (3, 6): + unused_rhs.add("call") + if PYTHON_VERSION_TRIPLE[:2] == (2, 7): expect_lhs.add("kv3") expect_lhs.add("kvlist") From ece788e09e07d1aed726dc175160df38bb47619e Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 09:11:39 -0500 Subject: [PATCH 374/489] Merge hell --- uncompyle6/bin/uncompile.py | 13 +++++-------- uncompyle6/main.py | 17 ++++++++++------- uncompyle6/scanner.py | 7 +++---- uncompyle6/semantics/pysource.py | 15 +++++++++------ uncompyle6/semantics/transform.py | 3 +-- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 80b151461..b11479e21 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -5,12 +5,10 @@ # by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # -from __future__ import print_function import os import sys import time -from typing import List import click from xdis.version_info import version_tuple_to_str @@ -31,7 +29,6 @@ def usage(): # Usage: # %s [OPTIONS]... [ FILE | DIR]... # %s [--help | -h | --V | --version] ->>>>>>> master # Examples: # %s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout @@ -160,11 +157,11 @@ def main_bin( """ version_tuple = sys.version_info[0:2] - if version_tuple < (3, 7): + if not ((3, 3) <= version_tuple < (3, 6)): print( - f"Error: This version of the {program} runs from Python 3.7 or greater." - f"You need another branch of this code for Python before 3.7." - f""" \n\tYou have version: {version_tuple_to_str()}.""" + "Error: This version of the {program} runs from Python 3.3 to 3.6." + "You need another branch of this code for other Python versions." + " \n\tYou have version: %s." % version_tuple_to_str() ) sys.exit(-1) @@ -172,7 +169,7 @@ def main_bin( out_base = None out_base = None - source_paths: List[str] = [] + source_paths = [] timestamp = False timestampfmt = "# %Y.%m.%d %H:%M:%S %Z" pyc_paths = files diff --git a/uncompyle6/main.py b/uncompyle6/main.py index aaa6c71c5..e970c344e 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -258,7 +258,7 @@ def main( outfile=None, showasm=None, showast={}, - do_verify = None, + do_verify=None, showgrammar: bool = False, source_encoding=None, do_linemaps=False, @@ -358,10 +358,12 @@ def main( deparsed_object.f.close() if PYTHON_VERSION_TRIPLE[:2] != deparsed_object.version[:2]: sys.stdout.write( - f"\n# skipping running {deparsed_object.f.name}; it is" - f"{version_tuple_to_str(deparsed_object.version, end=2)}, " - "and we are " - f"{version_tuple_to_str(PYTHON_VERSION_TRIPLE, end=2)}\n" + "\n# skipping running %s; it is %s and we are %s" + % ( + deparsed_object.f.name, + version_tuple_to_str(deparsed_object.version, end=2), + version_tuple_to_str(PYTHON_VERSION_TRIPLE, end=2), + ) ) else: check_type = "syntax check" @@ -385,10 +387,11 @@ def main( if not valid: verify_failed_files += 1 sys.stderr.write( - f"\n# {check_type} failed on file {deparsed_object.f.name}\n" + "\n# %s failed on file %s\n" + % (check_type, deparsed_object.f.name) ) - # sys.stderr.write(f"Ran {deparsed_object.f.name}\n") + # sys.stderr.write("Ran %\n" % deparsed_object.f.name) pass tot_files += 1 except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e: diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 0b5faa288..0993006f1 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -22,10 +22,8 @@ """ import sys - from array import array from collections import namedtuple -from types import ModuleType import xdis from xdis import ( @@ -629,11 +627,12 @@ def get_scanner(version, is_pypy=False, show_asm=None): # If version is a string, turn that into the corresponding float. if isinstance(version, str): if version not in canonic_python_version: - raise RuntimeError(f"Unknown Python version in xdis {version}") + raise RuntimeError("Unknown Python version in xdis %s" % version) canonic_version = canonic_python_version[version] if canonic_version not in CANONIC2VERSION: raise RuntimeError( - f"Unsupported Python version {version} (canonic {canonic_version})" + "Unsupported Python version %s (canonic %s)" + % (version, canonic_version) ) version = CANONIC2VERSION[canonic_version] diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index d5ace7f0e..fc8614d42 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -131,7 +131,6 @@ import sys from io import StringIO -from typing import Optional from spark_parser import GenericASTTraversal from xdis import COMPILER_FLAG_BIT, iscode @@ -808,9 +807,13 @@ def template_engine(self, entry, startnode): node[index].kind, ) else: - assert node[tup[0]] in tup[1], ( - f"at {node.kind}[{tup[0]}], expected to be in '{tup[1]}' " - f"node; got '{node[tup[0]].kind}'" + assert ( + node[tup[0]] in tup[1] + ), "at %s[%d], expected to be in '%s' node; got '%s'" % ( + node.kind, + arg, + index[1], + node[index[0]].kind, ) else: @@ -1281,7 +1284,7 @@ def _get_mapping(cls, node): def code_deparse( co, out=sys.stdout, - version: Optional[tuple] = None, + version=None, debug_opts=DEFAULT_DEBUG_OPTS, code_objects={}, compile_mode="exec", @@ -1289,7 +1292,7 @@ def code_deparse( walker=SourceWalker, start_offset: int = 0, stop_offset: int = -1, -) -> Optional[SourceWalker]: +): """ ingests and deparses a given code block 'co'. If version is None, we will use the current Python interpreter version. diff --git a/uncompyle6/semantics/transform.py b/uncompyle6/semantics/transform.py index 430f1e0ff..b646071b4 100644 --- a/uncompyle6/semantics/transform.py +++ b/uncompyle6/semantics/transform.py @@ -14,7 +14,6 @@ # along with this program. If not, see . from copy import copy -from typing import Optional from spark_parser import GenericASTTraversal, GenericASTTraversalPruningException @@ -73,7 +72,7 @@ def __init__( self, version: tuple, is_pypy=False, - show_ast: Optional[dict] = None, + show_ast=None, ): self.version = version self.showast = show_ast From 82a64b421d7c65c736e5a939c0ef17e0e4ce4f36 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 11:57:18 -0500 Subject: [PATCH 375/489] Handle annotations properly --- uncompyle6/scanners/scanner3.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index d997a40e2..d29dea90e 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -36,6 +36,7 @@ from __future__ import print_function import sys + import xdis # Get all the opcodes into globals From 70690f2edea8000c56e11812f6d25b988e224610 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 12:19:27 -0500 Subject: [PATCH 376/489] Sync with master --- uncompyle6/bin/pydisassemble.py | 10 ++--- uncompyle6/bin/uncompile.py | 65 +++++++++++++++++++------------ uncompyle6/main.py | 46 +++++++++++++--------- uncompyle6/parsers/parse3.py | 23 ----------- uncompyle6/scanners/scanner33.py | 4 +- uncompyle6/semantics/fragments.py | 6 +-- uncompyle6/semantics/pysource.py | 18 ++++----- uncompyle6/semantics/transform.py | 6 +-- 8 files changed, 90 insertions(+), 88 deletions(-) diff --git a/uncompyle6/bin/pydisassemble.py b/uncompyle6/bin/pydisassemble.py index 7e53c380f..42af82ead 100755 --- a/uncompyle6/bin/pydisassemble.py +++ b/uncompyle6/bin/pydisassemble.py @@ -55,16 +55,16 @@ -V | --version show version and stop -h | --help show this message -""" % ((program,) * 5) +""" % ( + (program,) * 5 +) PATTERNS = ("*.pyc", "*.pyo") def main(): - usage_short = ( - f"""usage: {program} FILE... + usage_short = f"""usage: {program} FILE... Type -h for for full help.""" - ) if len(sys.argv) == 1: sys.stderr.write("No file(s) given\n") @@ -76,7 +76,7 @@ def main(): sys.argv[1:], "hVU", ["help", "version", "uncompyle6"] ) except getopt.GetoptError(e): - sys.stderr.write('%s: %s' % (os.path.basename(sys.argv[0]), e)) + sys.stderr.write("%s: %s" % (os.path.basename(sys.argv[0]), e)) sys.exit(-1) for opt, val in opts: diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index ae112e6e4..cd2cb4981 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -6,22 +6,17 @@ # Copyright (c) 2000-2002 by hartmut Goebel # +import getopt import os import sys import time -from uncompyle6.verify import VerifyCmpError from uncompyle6.main import main, status_msg +from uncompyle6.verify import VerifyCmpError from uncompyle6.version import __version__ program = "uncompyle6" - -def usage(): - print(__doc__) - sys.exit(1) - - __doc__ = """ Usage: %s [OPTIONS]... [ FILE | DIR]... @@ -74,18 +69,44 @@ def usage(): (program,) * 5 ) +program = "uncompyle6" + +def usage(): + print(__doc__) + sys.exit(1) + + +def main_bin(): + if not ( + sys.version_info[0:2] + in ( + (2, 4), + (2, 5), + (2, 6), + (2, 7), + (3, 0), + (3, 1), + (3, 2), + (3, 3), + (3, 4), + (3, 5), + (3, 6), + (3, 7), + (3, 8), + (3, 9), + (3, 10), + (3, 11), + ) ): print('Error: %s requires Python 2.4-3.10' % program) sys.exit(-1) - + recurse_dirs = False numproc = 0 - out_base = None - + outfile = "-" out_base = None source_paths = [] timestamp = False timestampfmt = "# %Y.%m.%d %H:%M:%S %Z" - pyc_paths = files try: opts, pyc_paths = getopt.getopt( @@ -196,17 +217,10 @@ def usage(): out_base = outfile outfile = None - # A second -a turns show_asm="after" into show_asm="before" - if asm_plus or asm: - asm_opt = "both" if asm_plus else "after" - else: - asm_opt = None - if timestamp: print(time.strftime(timestampfmt)) if numproc <= 1: - show_ast = {"before": tree or tree_plus, "after": tree_plus} try: result = main( src_base, @@ -214,14 +228,15 @@ def usage(): pyc_paths, source_paths, outfile, - showasm=asm_opt, - showgrammar=show_grammar, - showast=show_ast, - do_verify=verify, - do_linemaps=linemaps, - start_offset=start_offset, - stop_offset=stop_offset, + showasm=options["showasm"], + showgrammar=options["showgrammar"], + showast=options["showast"], + do_verify=options["do_verify"], + do_linemaps=options["do_linemaps"], + start_offset=0, + stop_offset=-1, ) + result = [options.get("do_verify", None)] + list(result) if len(pyc_paths) > 1: mess = status_msg(*result) print("# " + mess) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index f89fc70c3..908aad7d3 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import ast +# import ast import datetime import os import os.path as osp @@ -52,15 +52,19 @@ def _get_outstream(outfile): pass return open(outfile, 'wb') -def syntax_check(filename: str) -> bool: - with open(filename) as f: - source = f.read() - valid = True - try: - ast.parse(source) - except SyntaxError: - valid = False - return valid +# def syntax_check(filename): +# f = open(filename, "r") +# try: +# source = f.read() +# finally: +# f.close() +# valid = True +# try: +# ast.parse(source) +# except SyntaxError: +# valid = False +# return valid + def decompile( @@ -74,13 +78,13 @@ def decompile( source_encoding=None, code_objects={}, source_size=None, - is_pypy: bool = False, + is_pypy=False, magic_int=None, mapstream=None, do_fragments=False, compile_mode="exec", - start_offset: int = 0, - stop_offset: int = -1, + start_offset=0, + stop_offset=-1, ): """ ingests and deparses a given code block 'co' @@ -215,7 +219,7 @@ def compile_file(source_path): def decompile_file( - filename: str, + filename, outstream=None, showasm=None, showast={}, @@ -293,12 +297,12 @@ def main( showasm=None, showast={}, do_verify=None, - showgrammar: bool = False, + showgrammar = False, source_encoding=None, do_linemaps=False, do_fragments=False, - start_offset: int = 0, - stop_offset: int = -1, + start_offset=0, + stop_offset=-1, ): """ in_base base directory for input files @@ -312,7 +316,9 @@ def main( - stdout out_base=None, outfile=None """ tot_files = okay_files = failed_files = 0 - verify_failed_files = 0 if do_verify else 0 + + verify_failed_files = 0 + current_outfile = outfile linemap_stream = None @@ -423,7 +429,9 @@ def main( print(result.stderr.decode()) else: - valid = syntax_check(deparsed_object.f.name) + print("Syntax checking not supported before Python 3.0") + # valid = syntax_check(deparsed_object.f.name) + valid = True if not valid: verify_failed_files += 1 diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a331a3f31..457ba2de3 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -869,29 +869,6 @@ def customize_grammar_rules(self, tokens, customize): rule = "starred ::= %s %s" % ("expr " * v, opname) self.addRule(rule, nop_func) - elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"): - if opname == "BUILD_CONST_DICT": - rule = ( - """ - add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts %s - dict ::= const_list - expr ::= dict - """ - % opname - ) - else: - rule = ( - """ - add_consts ::= ADD_VALUE* - const_list ::= COLLECTION_START add_consts %s - expr ::= const_list - """ - % opname - ) - self.addRule(rule, nop_func) - ->>>>>>> python-3.0-to-3.2 elif opname_base in ( "BUILD_LIST", "BUILD_SET", diff --git a/uncompyle6/scanners/scanner33.py b/uncompyle6/scanners/scanner33.py index 73de8a713..c517d7073 100644 --- a/uncompyle6/scanners/scanner33.py +++ b/uncompyle6/scanners/scanner33.py @@ -47,4 +47,6 @@ def __init__(self, show_asm=False, is_pypy=False): print(t.format()) pass else: - print("Need to be Python 3.3 to demo; I am version %s." % version_tuple_to_str()) + print( + "Need to be Python 3.3 to demo; I am version %s." % version_tuple_to_str() + ) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 4017282b6..027cd188d 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -2054,8 +2054,8 @@ def code_deparse( code_objects={}, compile_mode="exec", walker=FragmentsWalker, - start_offset: int = 0, - stop_offset: int = -1, + start_offset=0, + stop_offset=-1, ): """ Convert the code object co into a python source fragment. @@ -2189,7 +2189,7 @@ def code_deparse_around_offset( co, out=StringIO(), version=None, - is_pypy = False, + is_pypy=False, debug_opts=DEFAULT_DEBUG_OPTS, ): """ diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 4ebeee81d..67741788d 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -130,9 +130,9 @@ # evaluating the escape code. import sys -from io import StringIO from spark_parser import GenericASTTraversal +from StringIO import StringIO from xdis import COMPILER_FLAG_BIT, iscode from xdis.version_info import PYTHON_VERSION_TRIPLE @@ -221,7 +221,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): def __init__( self, - version: tuple, + version, out, scanner, showast=TREE_DEFAULT_DEBUG, @@ -397,7 +397,7 @@ def str_with_template1(self, ast, indent, sibNum=None): i += 1 return rv - def indent_if_source_nl(self, line_number, indent): + def indent_if_source_nl(self, line_number, indent_spaces): if line_number != self.line_number: self.write("\n" + indent_spaces + INDENT_PER_LEVEL[:-1]) return self.line_number @@ -1206,7 +1206,7 @@ def build_ast( is_lambda=False, noneInNames=False, is_top_level_module=False, - ) -> GenericASTTraversal: + ): # FIXME: DRY with fragments.py # assert isinstance(tokens[0], Token) @@ -1294,8 +1294,8 @@ def code_deparse( compile_mode="exec", is_pypy=IS_PYPY, walker=SourceWalker, - start_offset: int = 0, - stop_offset: int = -1, + start_offset = 0, + stop_offset = -1, ): """ ingests and deparses a given code block 'co'. If version is None, @@ -1452,9 +1452,9 @@ def deparse_code2str( compile_mode="exec", is_pypy=IS_PYPY, walker=SourceWalker, - start_offset: int = 0, - stop_offset: int = -1, -) -> str: + start_offset=0, + stop_offset=-1, +): """ Return the deparsed text for a Python code object. `out` is where any intermediate output for assembly or tree output will be sent. diff --git a/uncompyle6/semantics/transform.py b/uncompyle6/semantics/transform.py index b646071b4..304b4ae09 100644 --- a/uncompyle6/semantics/transform.py +++ b/uncompyle6/semantics/transform.py @@ -56,7 +56,7 @@ def is_docstring(node, version, co_consts): return node == ASSIGN_DOC_STRING(co_consts[0], doc_load) -def is_not_docstring(call_stmt_node) -> bool: +def is_not_docstring(call_stmt_node): try: return ( call_stmt_node == "call_stmt" @@ -70,7 +70,7 @@ def is_not_docstring(call_stmt_node) -> bool: class TreeTransform(GenericASTTraversal, object): def __init__( self, - version: tuple, + version, is_pypy=False, show_ast=None, ): @@ -462,7 +462,7 @@ def traverse(self, node, is_lambda=False): node = self.preorder(node) return node - def transform(self, parse_tree: GenericASTTraversal, code) -> GenericASTTraversal: + def transform(self, parse_tree, code): self.maybe_show_tree(parse_tree) self.ast = copy(parse_tree) del parse_tree From a4971ee27daeee381313d363b4b241ee92946f4b Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 12:33:54 -0500 Subject: [PATCH 377/489] Remove f-strings from merge from master --- uncompyle6/bin/pydisassemble.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/uncompyle6/bin/pydisassemble.py b/uncompyle6/bin/pydisassemble.py index e40e0dfc4..2075e450c 100755 --- a/uncompyle6/bin/pydisassemble.py +++ b/uncompyle6/bin/pydisassemble.py @@ -64,8 +64,9 @@ def main(): usage_short = ( - f"""usage: {program} FILE... + """usage: %s FILE... Type -h for for full help.""" + % program ) if len(sys.argv) == 1: @@ -78,7 +79,7 @@ def main(): sys.argv[1:], "hVU", ["help", "version", "uncompyle6"] ) except getopt.GetoptError as e: - print(f"{os.path.basename(sys.argv[0])}: {e}", file=sys.stderr) + print("%s: %s" % (os.path.basename(sys.argv[0]), e), file=sys.stderr) sys.exit(-1) for opt, val in opts: @@ -86,7 +87,7 @@ def main(): print(__doc__) sys.exit(1) elif opt in ("-V", "--version"): - print(f"{program} {__version__}") + print("%s %s" % (program, __version__)) sys.exit(0) else: print(opt) @@ -97,7 +98,7 @@ def main(): if os.path.exists(files[0]): disassemble_file(file, sys.stdout) else: - print(f"Can't read {files[0]} - skipping", file=sys.stderr) + print("Can't read %s - skipping" % files[0], file=sys.stderr) pass pass return From f9f5a64c87ef19b972f6de0c3110b59dba083eea Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 19:14:50 -0500 Subject: [PATCH 378/489] Attempt to fix annotation bugs --- uncompyle6/bin/uncompile.py | 23 +++++++---- uncompyle6/main.py | 25 ++++-------- uncompyle6/parsers/parse3.py | 59 +++++++++++++++------------- uncompyle6/parsers/parse33.py | 6 +++ uncompyle6/scanners/scanner35.py | 11 +++--- uncompyle6/scanners/scanner37base.py | 6 --- 6 files changed, 67 insertions(+), 63 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index db395b029..03d9c608e 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -14,6 +14,7 @@ from xdis.version_info import version_tuple_to_str from uncompyle6.main import main, status_msg +from uncompyle6.verify import VerifyCmpError from uncompyle6.version import __version__ program = "uncompyle6" @@ -157,12 +158,20 @@ def main_bin( version_tuple = sys.version_info[0:2] if not ((3, 3) <= version_tuple < (3, 6)): - print( - "Error: This version of the {program} runs from Python 3.3 to 3.5." - "You need another branch of this code for other Python versions." - " \n\tYou have version: %s." % version_tuple_to_str() - ) - sys.exit(-1) + if version_tuple > (3, 5): + print( + "This version of the {program} is tailored for Python 3.3 to 3.5.\n" + "It may run on other versions, but there are problems, switch to code " + "from another branch.\n" + "You have version: %s." % version_tuple_to_str() + ) + else: + print( + "Error: This version of the {program} runs from Python 3.3 to 3.5.\n" + "You need another branch of this code for other Python versions." + " \n\tYou have version: %s." % version_tuple_to_str() + ) + sys.exit(-1) numproc = 0 out_base = None @@ -242,7 +251,7 @@ def main_bin( sys.exit(2) except KeyboardInterrupt: pass - except verify.VerifyCmpError: + except VerifyCmpError: raise else: from multiprocessing import Process, Queue diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 0465a1ec4..e044abf22 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -382,25 +382,14 @@ def main( check_type = "syntax check" if do_verify == "run": check_type = "run" - if PYTHON_VERSION_TRIPLE >= (3, 7): - result = subprocess.run( - [sys.executable, deparsed_object.f.name], - capture_output=True, - ) - valid = result.returncode == 0 - output = result.stdout.decode() - if output: - print(output) - pass - else: - result = subprocess.run( - [sys.executable, deparsed_object.f.name], - ) - valid = result.returncode == 0 - pass + return_code = subprocess.call( + [sys.executable, deparsed_object.f.name], + stdout=sys.stdout, + stderr=sys.stderr, + ) + valid = return_code == 0 if not valid: - print(result.stderr.decode()) - + sys.stderr.write("Got return code %d\n" % return_code) else: valid = syntax_check(deparsed_object.f.name) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index f25ae5d7d..f28fb7cac 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1221,9 +1221,24 @@ def customize_grammar_rules(self, tokens, customize): ) ) else: - rule = "mkfunc ::= %s%sload_closure LOAD_CODE LOAD_STR %s" % ( - kwargs_str, - "pos_arg " * pos_args_count, + if self.version == (3, 3): + # 3.3 puts kwargs before pos_arg + pos_kw_tuple = ( + ("kwargs " * kw_args_count), + ("pos_arg " * pos_args_count), + ) + else: + # 3.4 and 3.5 puts pos_arg before kwargs + pos_kw_tuple = ( + "pos_arg " * (pos_args_count), + ("kwargs " * kw_args_count), + ) + rule = ( + "mkfunc ::= %s%s%s " "load_closure LOAD_CODE LOAD_STR %s" + ) % ( + pos_kw_tuple[0], + pos_kw_tuple[1], + "annotate_pair " * (annotate_args), opname, ) self.add_unique_rule(rule, opname, token.attr, customize) @@ -1465,12 +1480,12 @@ def customize_grammar_rules(self, tokens, customize): ) self.add_unique_rule(rule, opname, token.attr, customize) rule = ( - "mkfunc_annotate ::= %s%sannotate_tuple LOAD_CODE LOAD_STR %s" - % ( - ("pos_arg " * pos_args_count), - ("annotate_arg " * annotate_args), - opname, - ) + "mkfunc_annotate ::= %s%sannotate_tuple LOAD_CODE " + "LOAD_STR %s" + ) % ( + ("pos_arg " * pos_args_count), + ("annotate_arg " * annotate_args), + opname, ) if self.version >= (3, 3): if self.version == (3, 3): @@ -1480,29 +1495,19 @@ def customize_grammar_rules(self, tokens, customize): ("pos_arg " * pos_args_count), ) else: - # 3.4 and 3.5puts pos_arg before kwargs + # 3.4 and 3.5 puts pos_arg before kwargs pos_kw_tuple = ( "pos_arg " * (pos_args_count), ("kwargs " * kw_args_count), ) rule = ( - "mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CODE LOAD_STR %s" - % ( - pos_kw_tuple[0], - pos_kw_tuple[1], - ("annotate_arg " * annotate_args), - opname, - ) - ) - self.add_unique_rule(rule, opname, token.attr, customize) - rule = ( - "mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CODE LOAD_STR %s" - % ( - pos_kw_tuple[0], - pos_kw_tuple[1], - ("annotate_arg " * annotate_args), - opname, - ) + "mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CODE " + "LOAD_STR %s" + ) % ( + pos_kw_tuple[0], + pos_kw_tuple[1], + ("annotate_arg " * annotate_args), + opname, ) else: rule = ( diff --git a/uncompyle6/parsers/parse33.py b/uncompyle6/parsers/parse33.py index ce1fc6727..fd3a888fd 100644 --- a/uncompyle6/parsers/parse33.py +++ b/uncompyle6/parsers/parse33.py @@ -16,6 +16,12 @@ def p_33on(self, args): stmt ::= genexpr_func """ + def p_33_function_def(self, args): + """ + annotate_pair ::= LOAD_NAME LOAD_CONST + + """ + def customize_grammar_rules(self, tokens, customize): self.remove_rules( """ diff --git a/uncompyle6/scanners/scanner35.py b/uncompyle6/scanners/scanner35.py index 9af3aaedc..52a825720 100644 --- a/uncompyle6/scanners/scanner35.py +++ b/uncompyle6/scanners/scanner35.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017, 2021-2022 by Rocky Bernstein +# Copyright (c) 2017, 2021-2022, 2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,21 +22,22 @@ scanner routine for Python 3. """ -from __future__ import print_function +# bytecode verification, verify(), uses JUMP_OPs from here +from xdis.opcodes import opcode_35 as opc from uncompyle6.scanners.scanner3 import Scanner3 -# bytecode verification, verify(), uses JUMP_OPs from here -from xdis.opcodes import opcode_35 as opc JUMP_OPS = opc.JUMP_OPS -class Scanner35(Scanner3): +class Scanner35(Scanner3): def __init__(self, show_asm=None, is_pypy=False): Scanner3.__init__(self, (3, 5), show_asm, is_pypy) return + pass + if __name__ == "__main__": from xdis.version_info import PYTHON_VERSION_TRIPLE, version_tuple_to_str diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 499538bd6..34021568f 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -318,12 +318,6 @@ def tokens_append(j, token): argval = inst.argval op = inst.opcode - if inst.opname == "EXTENDED_ARG": - # FIXME: The EXTENDED_ARG is used to signal annotation - # parameters - if i + 1 < n and self.insts[i + 1].opcode != self.opc.MAKE_FUNCTION: - continue - if inst.offset in jump_targets: jump_idx = 0 # We want to process COME_FROMs to the same offset to be in *descending* From 950dd05791b52af1c4ef2034cd04debc4e93270b Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 23:40:42 -0500 Subject: [PATCH 379/489] Merge hell --- uncompyle6/parsers/parse3.py | 2 +- uncompyle6/parsers/parse33.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 969d91090..64c164d4e 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1238,7 +1238,7 @@ def customize_grammar_rules(self, tokens, customize): ) % ( pos_kw_tuple[0], pos_kw_tuple[1], - "annotate_pair " * (annotate_args), + "annotate_tuple " * (annotate_args), opname, ) self.add_unique_rule(rule, opname, token.attr, customize) diff --git a/uncompyle6/parsers/parse33.py b/uncompyle6/parsers/parse33.py index fd3a888fd..ce1fc6727 100644 --- a/uncompyle6/parsers/parse33.py +++ b/uncompyle6/parsers/parse33.py @@ -16,12 +16,6 @@ def p_33on(self, args): stmt ::= genexpr_func """ - def p_33_function_def(self, args): - """ - annotate_pair ::= LOAD_NAME LOAD_CONST - - """ - def customize_grammar_rules(self, tokens, customize): self.remove_rules( """ From 497e2df88afa0d9a22b318bb1ae947d1a72ec59f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 11 Feb 2024 23:54:51 -0500 Subject: [PATCH 380/489] Merge hell --- uncompyle6/semantics/make_function3.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uncompyle6/semantics/make_function3.py b/uncompyle6/semantics/make_function3.py index 73e67c322..7e2326bd6 100644 --- a/uncompyle6/semantics/make_function3.py +++ b/uncompyle6/semantics/make_function3.py @@ -17,12 +17,10 @@ The saga of changes before and after is in other files. """ from xdis import CO_GENERATOR, code_has_star_arg, code_has_star_star_arg, iscode -from uncompyle6.scanner import Code + from uncompyle6.parser import ParserError as ParserError2 from uncompyle6.parsers.treenode import SyntaxTree -from uncompyle6.semantics.parser_error import ParserError from uncompyle6.scanner import Code ->>>>>>> python-3.0-to-3.2 from uncompyle6.semantics.helper import ( find_all_globals, find_globals_and_nonlocals, From 35f9020871f9898142661c8f62f9d42890ea8ec4 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 12 Feb 2024 00:29:18 -0500 Subject: [PATCH 381/489] Adjust for 3.0..3.1 branch --- uncompyle6/bin/uncompile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index ad7d380b2..c43029370 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -157,17 +157,17 @@ def main_bin( """ version_tuple = sys.version_info[0:2] - if not ((3, 3) <= version_tuple < (3, 6)): - if version_tuple > (3, 5): + if not ((3, 0) <= version_tuple < (3, 3)): + if version_tuple > (3, 3): print( - "This version of the {program} is tailored for Python 3.3 to 3.5.\n" + "This version of the {program} is tailored for Python 3.0 to 3.2.\n" "It may run on other versions, but there are problems, switch to code " "from another branch.\n" "You have version: %s." % version_tuple_to_str() ) else: print( - "Error: This version of the {program} runs from Python 3.3 to 3.5.\n" + "Error: This version of the {program} runs from Python 3.0 to 3.2.\n" "You need another branch of this code for other Python versions." " \n\tYou have version: %s." % version_tuple_to_str() ) From a1ffe3e1069dc753a88094b8330ce8f746780283 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 12 Feb 2024 05:16:59 -0500 Subject: [PATCH 382/489] Make uncompyle6 CLI work again --- uncompyle6/bin/uncompile.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 33f08c193..12a4dc547 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -124,7 +124,11 @@ def main_bin(): sys.exit(-1) options = { - "showasm": None + "showasm": None, + "showgrammar": None, + "showast": {}, + "do_verify": None, + "do_linemaps": False, } for opt, val in opts: if opt in ("-h", "--help"): From 1ed2b929887e5e5316f698096a8737bfb0e495e4 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 12 Feb 2024 08:07:54 -0500 Subject: [PATCH 383/489] Administrivia rename branch to python-2.4-to-2.7 --- admin-tools/setup-python-2.4.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 8d42f1b67..78b92b3be 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -3,7 +3,7 @@ PYTHON_VERSION=2.4.6 function checkout_version { local repo=$1 - version=${2:-python-2.4} + version=${2:-python-2.4-to-2.7} echo Checking out $version.4 on $repo ... (cd ../$repo && git checkout $version && pyenv local $PYTHON_VERSION) && \ git pull From 909ec81b55e3a4577a17de4c474fca1de1af47ec Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 12 Feb 2024 08:50:10 -0500 Subject: [PATCH 384/489] More administrivia --- admin-tools/setup-python-3.3.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index 821ca59ac..e51fc7f39 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -27,6 +27,7 @@ trap finish EXIT export PATH=$HOME/.pyenv/bin/pyenv:$PATH +mydir=$(dirname $bs) fulldir=$(readlink -f $mydir) cd $fulldir/.. (cd $fulldir/.. && checkout_version python-spark master && checkout_version python-xdis && From afb79f84e20069dee42d99e72ae6c9a79b4bdacb Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Feb 2024 15:22:02 -0500 Subject: [PATCH 385/489] No f-string in this branch --- uncompyle6/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index a84b5e5b8..c5fbc6f39 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -662,7 +662,7 @@ def prefer_double_quote(string: str) -> str: single quoted string when possible """ if string.find("'") == -1: - return f'"{string}"' + return '"%s"' % string return repr(string) From 028d87dddef4d07d65ef057835f3a4627b370760 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Feb 2024 15:27:15 -0500 Subject: [PATCH 386/489] Merge hell --- uncompyle6/scanner.py | 2 +- uncompyle6/semantics/n_actions.py | 32 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 9995105fd..97a7455f5 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -645,7 +645,7 @@ def get_scanner(version, is_pypy=False, show_asm=None): return scanner -def prefer_double_quote(string: str) -> str: +def prefer_double_quote(string): """ Prefer a double quoted string over a single quoted string when possible diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 93be8fd08..42d15465b 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -48,7 +48,7 @@ def __init__(self): self.prec = 1000 self.in_format_string = False - def n_alias(self, node: SyntaxTree): + def n_alias(self, node): if self.version <= (2, 1): if len(node) == 2: store = node[1] @@ -73,7 +73,7 @@ def n_alias(self, node: SyntaxTree): n_alias37 = n_alias - def n_assign(self, node: SyntaxTree): + def n_assign(self, node): # A horrible hack for Python 3.0 .. 3.2 if (3, 0) <= self.version <= (3, 2) and len(node) == 2: if ( @@ -84,19 +84,19 @@ def n_assign(self, node: SyntaxTree): self.prune() self.default(node) - def n_assign2(self, node: SyntaxTree): + def n_assign2(self, node): for n in node[-2:]: if n[0] == "unpack": n[0].kind = "unpack_w_parens" self.default(node) - def n_assign3(self, node: SyntaxTree): + def n_assign3(self, node): for n in node[-3:]: if n[0] == "unpack": n[0].kind = "unpack_w_parens" self.default(node) - def n_attribute(self, node: SyntaxTree): + def n_attribute(self, node): if node[0] == "LOAD_CONST" or node[0] == "expr" and node[0][0] == "LOAD_CONST": # FIXME: I didn't record which constants parenthesis is # necessary. However, I suspect that we could further @@ -106,7 +106,7 @@ def n_attribute(self, node: SyntaxTree): node.kind = "attribute_w_parens" self.default(node) - def n_bin_op(self, node: SyntaxTree): + def n_bin_op(self, node): """bin_op (formerly "binary_expr") is the Python AST BinOp""" self.preorder(node[0]) self.write(" ") @@ -118,7 +118,7 @@ def n_bin_op(self, node: SyntaxTree): self.prec += 1 self.prune() - def n_build_slice2(self, node: SyntaxTree): + def n_build_slice2(self, node): p = self.prec self.prec = NO_PARENTHESIS_EVER if not node[0].isNone(): @@ -129,7 +129,7 @@ def n_build_slice2(self, node: SyntaxTree): self.prec = p self.prune() # stop recursing - def n_build_slice3(self, node: SyntaxTree): + def n_build_slice3(self, node): p = self.prec self.prec = NO_PARENTHESIS_EVER if not node[0].isNone(): @@ -143,7 +143,7 @@ def n_build_slice3(self, node: SyntaxTree): self.prec = p self.prune() # stop recursing - def n_classdef(self, node: SyntaxTree): + def n_classdef(self, node): if self.version >= (3, 6): self.n_classdef36(node) elif self.version >= (3, 0): @@ -206,7 +206,7 @@ def n_classdef(self, node: SyntaxTree): n_classdefdeco2 = n_classdef - def n_const_list(self, node: SyntaxTree): + def n_const_list(self, node): """ prettyprint a constant dict, list, set or tuple. """ @@ -300,7 +300,7 @@ def n_const_list(self, node: SyntaxTree): self.prune() return - def n_delete_subscript(self, node: SyntaxTree): + def n_delete_subscript(self, node): if node[-2][0] == "build_list" and node[-2][0][-1].kind.startswith( "BUILD_TUPLE" ): @@ -310,7 +310,7 @@ def n_delete_subscript(self, node: SyntaxTree): n_store_subscript = n_subscript = n_delete_subscript - def n_dict(self, node: SyntaxTree): + def n_dict(self, node): """ Prettyprint a dict. 'dict' is something like k = {'a': 1, 'b': 42}" @@ -599,7 +599,7 @@ def n_docstring(self, node): self.println(lines[-1], quote) self.prune() - def n_elifelsestmtr(self, node: SyntaxTree): + def n_elifelsestmtr(self, node): if node[2] == "COME_FROM": return_stmts_node = node[3] node.kind = "elifelsestmtr2" @@ -630,7 +630,7 @@ def n_elifelsestmtr(self, node: SyntaxTree): self.indent_less() self.prune() - def n_except_cond2(self, node: SyntaxTree): + def n_except_cond2(self, node): if node[-1] == "come_from_opt": unpack_node = -3 else: @@ -644,7 +644,7 @@ def n_except_cond2(self, node: SyntaxTree): # FIXME: figure out how to get this into customization # put so that we can get access via super from # the fragments routine. - def n_exec_stmt(self, node: SyntaxTree): + def n_exec_stmt(self, node): """ exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT exec_stmt ::= expr exprlist EXEC_STMT @@ -814,7 +814,7 @@ def n_lambda_body(self, node): self.make_function(node, is_lambda=True, code_node=node[-2]) self.prune() # stop recursing - def n_list(self, node: SyntaxTree): + def n_list(self, node): """ prettyprint a dict, list, set or tuple. """ From e77ccba40e3fa73392fd9867baf0dc4c7251ceb7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 07:15:47 -0500 Subject: [PATCH 387/489] Merge hell --- uncompyle6/scanners/scanner37base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index c6b5936f0..4bdcd8311 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -303,6 +303,7 @@ def tokens_append(j, token): has_arg=jump_inst.has_arg, inst_size=jump_inst.inst_size, has_extended_arg=inst.has_extended_arg, + fallthrough=False, tos_str=None, start_offset=None, ) From 76bca014dcf58a7601275dfb9ac1dc5517a30e4e Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 07:24:14 -0500 Subject: [PATCH 388/489] Merge hell --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 371629876..c3ec0fd86 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -134,7 +134,7 @@ from spark_parser import GenericASTTraversal from StringIO import StringIO from xdis import COMPILER_FLAG_BIT, iscode -from xdis.version_info import PYTHON_VERSION_TRIPLE +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE from uncompyle6.parser import get_python_parser, parse from uncompyle6.parsers.treenode import SyntaxTree From 50f3c64277aa9eb89fcef9d46528028e9b59e099 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 07:44:24 -0500 Subject: [PATCH 389/489] Administrivia --- __pkginfo__.py | 2 +- test/stdlib/2.4-exclude.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 98fa63d50..91d7aa2c6 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -77,7 +77,7 @@ ] } ftp_url = None -install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.8, < 6.2.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.8, < 6.2.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh index 99e11f9e9..74588f741 100644 --- a/test/stdlib/2.4-exclude.sh +++ b/test/stdlib/2.4-exclude.sh @@ -38,8 +38,7 @@ SKIP_TESTS=( [test_winreg.py]=1 # it fails on its own [test_winsound.py]=1 # it fails on its own [test_zlib.py]=1 # it fails on its own - - [test_decimal.py]=1 # + [test_decimal.py]=1 # failes on its own - no module named test_support [test_dis.py]=1 # We change line numbers - duh! [test_generators.py]=1 # Investigate # [test_grammar.py]=1 # fails on its own - no module tests.test_support From f7b0e895ed99f8483da95e61be63c00dbc51536f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 07:54:13 -0500 Subject: [PATCH 390/489] Fix bug ADD_VALUE for tuples --- uncompyle6/semantics/n_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 42d15465b..60894dccb 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -268,7 +268,7 @@ def n_const_list(self, node): elem = elem[0] if elem == "ADD_VALUE": if self.version < (3, 0, 0): - value = "%r" % elem.pattr + value = "%s" % repr(elem.pattr) else: value = "%s" % str(elem.pattr) else: From 9ceb9eb9ac69fa083a417a2237e9ab592b28e57e Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 10:25:10 -0500 Subject: [PATCH 391/489] Administrivia --- admin-tools/setup-python-2.4.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index ed6d2bde5..d54125caf 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -1,7 +1,6 @@ #!/bin/bash # Check out python-2.4-to-2.7 and dependent development branches. -set -e PYTHON_VERSION=2.4.6 bs=${BASH_SOURCE[0]} From f3b3733f15b156514d070703826e1912b726c237 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 12:09:39 -0500 Subject: [PATCH 392/489] Go over 2.6 excludes --- test/stdlib/2.6-exclude.sh | 28 ++++++++++++++-------------- test/stdlib/runtests.sh | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index 657c6cf97..5b3950323 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -8,23 +8,22 @@ SKIP_TESTS=( # [test_shutil.py]=1 # OK but needs PYTHON=pytest [test___all__.py]=1 # it fails on its own - [test_aepack.py]=1 # it fails on its own - [test_al.py]=1 # it fails on its own - [test_anydbm.py]=1 # it fails on its own - [test_applesingle.py]=1 # it fails on its own - + [test_aepack.py]=1 # No module macostools + [test_al.py]=1 # No module macostools + [test_anydbm.py]=pytest + [test_applesingle.py]=1 # No module macostools [test_bsddb185.py]=1 # it fails on its own [test_bsddb3.py]=1 # it fails on its own - [test_bsddb.py]=1 # it fails on its own + [test_bsddb.py]=1 # No module _bsdb - # [test_cd.py]=1 # it fails on its own + [test_cd.py]=1 # i# No module cl [test_cl.py]=1 # it fails on its own [test_codecmaps_cn.py]=1 # it fails on its own [test_codecmaps_jp.py]=1 # it fails on its own [test_codecmaps_kr.py]=1 # it fails on its own [test_codecmaps_tw.py]=1 # it fails on its own [test_commands.py]=1 # it fails on its own - [test_curses.py]=1 # it fails on its own + [test_curses.py]=1 # needs libncurses.so.5 [test_dbm.py]=1 # it fails on its own [test_descr.py]=1 @@ -33,16 +32,16 @@ SKIP_TESTS=( [test_dl.py]=1 # it fails on its own [test_file.py]=1 # it fails on its own - [test_future5.py]=1 # it fails on its own + [test_future5.py]=pytest - # [test_generators.py]=1 # works but use PYTHON=pytest + [test_generators.py]=pytest [test_gl.py]=1 # it fails on its own - # [test_grp.py]=1 # works but use PYTHON=pytest + [test_grp.py]=pytest [test_imageop.py]=1 # it fails on its own [test_imaplib.py]=1 # it fails on its own [test_imgfile.py]=1 # it fails on its own - # [test_ioctl.py]=1 # works but use PYTHON=pytest + [test_ioctl.py]=pytest [test_kqueue.py]=1 # it fails on its own @@ -63,6 +62,7 @@ SKIP_TESTS=( [test_scriptpackages.py]=1 # it fails on its own [test_select.py]=1 # test takes too long to run: 11 seconds + [test_signal.py]=1 # takes more than 15 seconds to run [test_socket.py]=1 # test takes too long to run: 12 seconds [test_startfile.py]=1 # it fails on its own [test_structmembers.py]=1 # it fails on its own @@ -81,8 +81,8 @@ SKIP_TESTS=( [test_winreg.py]=1 # it fails on its own [test_winsound.py]=1 # it fails on its own - [test_zipimport_support.py]=1 # expected test to raise ImportError - [test_zipfile64.py]=1 # Skip Long test + [test_zipimport_support.py]=pytest # expected test to raise ImportError + [test_zipfile.py]=pytest # Skip Long test # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc # .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc ) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 8e1520136..844d703b6 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -191,7 +191,11 @@ if [[ -n $1 ]] ; then files=$@ typeset -a files_ary=( $(echo $@) ) if (( ${#files_ary[@]} == 1 || DONT_SKIP_TESTS == 1 )) ; then - SKIP_TESTS=() + for file in $files; do + if (( SKIP_TESTS[$file] != "pytest" )); then + SKIP_TESTS[$file] = 1; + fi + done fi else files=$(echo test_*.py) @@ -205,9 +209,14 @@ NOT_INVERTED_TESTS=${NOT_INVERTED_TESTS:-1} for file in $files; do # AIX bash doesn't grok [[ -v SKIP... ]] [[ -z ${SKIP_TESTS[$file]} ]] && SKIP_TESTS[$file]=0 - if [[ ${SKIP_TESTS[$file]} == ${NOT_INVERTED_TESTS} ]] ; then - ((skipped++)) - continue + + if [[ ${SKIP_TESTS[$file]} == "pytest" ]]; then + PYTHON=pytest + else + if [[ ${SKIP_TESTS[$file]}s == ${NOT_INVERTED_TESTS} ]] ; then + ((skipped++)) + continue + fi fi # If the fails *before* decompiling, skip it! From 518bedb1d9d811f596c6847f23f215a53811872f Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 18:07:28 -0500 Subject: [PATCH 393/489] ADD_VALUE attributes --- test/stdlib/3.2-exclude.sh | 7 +++++++ test/stdlib/3.3-exclude.sh | 2 +- uncompyle6/semantics/make_function2.py | 22 +++++++++++----------- uncompyle6/semantics/make_function3.py | 1 - uncompyle6/semantics/n_actions.py | 2 +- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/test/stdlib/3.2-exclude.sh b/test/stdlib/3.2-exclude.sh index 5b61dd9b7..f80f9ee85 100644 --- a/test/stdlib/3.2-exclude.sh +++ b/test/stdlib/3.2-exclude.sh @@ -1,6 +1,13 @@ SKIP_TESTS=( [test_descr.py]=1 # FIXME: Works on c90ff51? + [test_cmath.py]=1 # FIXME + # AssertionError: rect1000: rect(complex(0.0, 0.0)) + # Expected: complex(0.0, 0.0) + # Received: complex(0.0, -1.0) + # Received value insufficiently close to expected value. + + [test_cmd_line.py]=1 [test_collections.py]=1 [test_concurrent_futures.py]=1 # too long to run over 46 seconds by itself diff --git a/test/stdlib/3.3-exclude.sh b/test/stdlib/3.3-exclude.sh index ea0efb294..b2d0afe8c 100644 --- a/test/stdlib/3.3-exclude.sh +++ b/test/stdlib/3.3-exclude.sh @@ -11,7 +11,7 @@ SKIP_TESTS=( [test_itertools.py]=1 [test_buffer.py]=1 # FIXME: Works on c90ff51 - [test_cmath.py]=1 # FIXME: Works on c90ff51 + [test_cmath.py]=pytest [test_atexit.py]=1 # The atexit test starting at 3.3 looks for specific comments in error lines diff --git a/uncompyle6/semantics/make_function2.py b/uncompyle6/semantics/make_function2.py index fb186f4f7..bb8ca9ece 100644 --- a/uncompyle6/semantics/make_function2.py +++ b/uncompyle6/semantics/make_function2.py @@ -17,21 +17,22 @@ All the crazy things we have to do to handle Python functions in Python before 3.0. The saga of changes continues in 3.0 and above and in other files. """ -from uncompyle6.scanner import Code -from uncompyle6.semantics.parser_error import ParserError +from itertools import zip_longest + +from xdis import code_has_star_arg, code_has_star_star_arg, iscode + from uncompyle6.parser import ParserError as ParserError2 +from uncompyle6.scanner import Code from uncompyle6.semantics.helper import ( - print_docstring, find_all_globals, find_globals_and_nonlocals, find_none, + print_docstring, ) -from xdis import iscode, code_has_star_arg, code_has_star_star_arg - -from itertools import zip_longest - +from uncompyle6.semantics.parser_error import ParserError from uncompyle6.show import maybe_show_tree_param_default + def make_function2(self, node, is_lambda, nested=1, code_node=None): """ Dump function definition, doc string, and function body. @@ -40,8 +41,8 @@ def make_function2(self, node, is_lambda, nested=1, code_node=None): def build_param(ast, name, default): """build parameters: - - handle defaults - - handle format tuple parameters + - handle defaults + - handle format tuple parameters """ # if formal parameter is a tuple, the paramater name # starts with a dot (eg. '.1', '.2') @@ -52,7 +53,6 @@ def build_param(ast, name, default): if default: value = self.traverse(default, indent="") - maybe_show_tree_param_default(self.showast, name, value) result = "%s=%s" % (name, value) if result[-2:] == "= ": # default was 'LOAD_CONST None' result += "None" @@ -199,5 +199,5 @@ def build_param(ast, name, default): ast, code.co_name, code._customize, is_lambda=is_lambda, returnNone=rn ) - code._tokens = None # save memory + code._tokens = None # save memory code._customize = None # save memory diff --git a/uncompyle6/semantics/make_function3.py b/uncompyle6/semantics/make_function3.py index 7c2960eec..a7377f61f 100644 --- a/uncompyle6/semantics/make_function3.py +++ b/uncompyle6/semantics/make_function3.py @@ -337,7 +337,6 @@ def build_param(ast, name, default, annotation=None): - handle format tuple parameters """ value = self.traverse(default, indent="") - maybe_show_tree_param_default(self.showast, name, value) if annotation: result = "%s: %s=%s" % (name, annotation, value) else: diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 92044a702..cc520ac25 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -278,7 +278,7 @@ def n_const_list(self, node: SyntaxTree): elif elem.optype == "const" and not isinstance(elem.attr, str): value = elem.attr else: - value = "%s" % repr(elem.pattr) + value = "%s" % repr(elem.attr) else: assert elem.kind == "ADD_VALUE_VAR" value = "%s" % elem.pattr From 6c26f3fb8d29ee4565e35fa6d44cc0fee9393de0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 24 Feb 2024 18:23:30 -0500 Subject: [PATCH 394/489] ADD_VALUE types --- test/stdlib/2.6-exclude.sh | 1 + uncompyle6/semantics/make_function2.py | 11 ++--------- uncompyle6/semantics/n_actions.py | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/test/stdlib/2.6-exclude.sh b/test/stdlib/2.6-exclude.sh index 5b3950323..952579a48 100644 --- a/test/stdlib/2.6-exclude.sh +++ b/test/stdlib/2.6-exclude.sh @@ -18,6 +18,7 @@ SKIP_TESTS=( [test_cd.py]=1 # i# No module cl [test_cl.py]=1 # it fails on its own + [test_cmath.py]=pytest [test_codecmaps_cn.py]=1 # it fails on its own [test_codecmaps_jp.py]=1 # it fails on its own [test_codecmaps_kr.py]=1 # it fails on its own diff --git a/uncompyle6/semantics/make_function2.py b/uncompyle6/semantics/make_function2.py index 4d0ee3387..6dd8cd079 100644 --- a/uncompyle6/semantics/make_function2.py +++ b/uncompyle6/semantics/make_function2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2021 by Rocky Bernstein +# Copyright (c) 2015-2021 2024 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # # This program is free software: you can redistribute it and/or modify @@ -17,24 +17,17 @@ All the crazy things we have to do to handle Python functions in Python before 3.0. The saga of changes continues in 3.0 and above and in other files. """ -from itertools import zip_longest - from xdis import code_has_star_arg, code_has_star_star_arg, iscode -from uncompyle6.parser import ParserError as ParserError2 from uncompyle6.scanner import Code from uncompyle6.semantics.helper import ( find_all_globals, find_globals_and_nonlocals, find_none, print_docstring, - zip_longest -) -from xdis import iscode, code_has_star_arg, code_has_star_star_arg - + zip_longest, ) from uncompyle6.semantics.parser_error import ParserError -from uncompyle6.show import maybe_show_tree_param_default def make_function2(self, node, is_lambda, nested=1, code_node=None): diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 2513d6437..e0b0b4f5c 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -277,9 +277,8 @@ def n_const_list(self, node): value = elem.attr elif elem.optype == "const" and not isinstance(elem.attr, str): value = elem.attr ->>>>>>> python-3.0-to-3.2 else: - value = "%s" % repr(elem.attr) + value = "%s" % repr(elem.pattr) else: assert elem.kind == "ADD_VALUE_VAR" value = "%s" % elem.pattr From 404517e426b50aaa2f45c1054e9f48c8fa10afb3 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 25 Feb 2024 06:09:01 -0500 Subject: [PATCH 395/489] Admnistrivia --- admin-tools/merge-for-3.3.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/admin-tools/merge-for-3.3.sh b/admin-tools/merge-for-3.3.sh index aade2e77c..8febb3d94 100755 --- a/admin-tools/merge-for-3.3.sh +++ b/admin-tools/merge-for-3.3.sh @@ -1,5 +1,7 @@ #/bin/bash +owd=$(pwd) cd $(dirname ${BASH_SOURCE[0]}) if . ./setup-python-3.3.sh; then git merge master fi +cd $owd From 7c91694cf98e411233341f4a1081492ec0d7b766 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Mar 2024 05:07:12 -0500 Subject: [PATCH 396/489] merge hell --- uncompyle6/scanner.py | 3 +-- uncompyle6/semantics/gencomp.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 4d04a5e51..bda8d9722 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -22,7 +22,6 @@ """ import sys -from abc import ABC from array import array from collections import namedtuple @@ -109,7 +108,7 @@ def __init__(self, co, scanner, classname=None, show_asm=None): self._tokens, self._customize = scanner.ingest(co, classname, show_asm=show_asm) -class Scanner(ABC): +class Scanner: def __init__(self, version: tuple, show_asm=None, is_pypy=False): self.version = version self.show_asm = show_asm diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 7aba2b46d..c9406e241 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -100,7 +100,7 @@ def comprehension_walk( self, node, iter_index, - code_index = -5, + code_index=-5, ): p = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 From 40e64ba3e0ae8fa331f5635ad312a9cddac58c3c Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Mar 2024 05:31:19 -0500 Subject: [PATCH 397/489] Merge hell --- uncompyle6/parsers/parse2.py | 5 ----- uncompyle6/scanner.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 167af7113..9c2fea7fc 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -25,11 +25,6 @@ that a later phase can turn into a sequence of ASCII text. """ -from uncompyle6.parsers.reducecheck import (except_handler_else, ifelsestmt, tryelsestmt) -from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func -from uncompyle6.parsers.treenode import SyntaxTree -from __future__ import print_function - from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index b62f45b6b..dd6c2b98b 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -297,7 +297,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): """ raise NotImplementedError("This method should have been implemented") - def prev_offset(self, offset: int) -> int: + def prev_offset(self, offset): return self.insts[self.offset2inst_index[offset] - 1].offset def get_inst(self, offset): From 30463f75d6e2c1d92417b27d4e9ab3c68f0c9021 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Mar 2024 05:38:38 -0500 Subject: [PATCH 398/489] 2.4 tolerance (remove annotations) --- uncompyle6/parsers/reducecheck/pop_return.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/uncompyle6/parsers/reducecheck/pop_return.py b/uncompyle6/parsers/reducecheck/pop_return.py index e9da02645..815f4de77 100644 --- a/uncompyle6/parsers/reducecheck/pop_return.py +++ b/uncompyle6/parsers/reducecheck/pop_return.py @@ -1,9 +1,7 @@ # Copyright (c) 2020 Rocky Bernstein -def pop_return_check( - self, lhs: str, n: int, rule, ast, tokens: list, first: int, last: int -) -> bool: +def pop_return_check(self, lhs, n, rule, ast, tokens, first, last): # If the first instruction of return_expr (the instruction after POP_TOP) is # has a linestart, then the POP_TOP was probably part of the previous # statement, such as a call() where the return value is discarded. From 40f9b523b0003023c74523d1fff647f23b402299 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 2 Mar 2024 12:20:57 -0500 Subject: [PATCH 399/489] Merge hell --- uncompyle6/semantics/make_function3.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/uncompyle6/semantics/make_function3.py b/uncompyle6/semantics/make_function3.py index 867e9cc4d..04e9c5978 100644 --- a/uncompyle6/semantics/make_function3.py +++ b/uncompyle6/semantics/make_function3.py @@ -21,6 +21,7 @@ from uncompyle6.parser import ParserError as ParserError2 from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanner import Code +from uncompyle6.scanners.tok import Token from uncompyle6.semantics.helper import ( find_all_globals, find_globals_and_nonlocals, @@ -452,13 +453,6 @@ def build_param(ast, name, default, annotation=None): kw_args = 0 pass - if 3.0 <= self.version <= 3.2: - lambda_index = -2 - elif 3.03 <= self.version: - lambda_index = -3 - else: - lambda_index = None - if lambda_index and is_lambda and iscode(node[lambda_index].attr): assert node[lambda_index].kind == "LOAD_LAMBDA" code = node[lambda_index].attr From ebe0137b2d9e5da7f9a30447949f3e2c7f994f08 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 8 Mar 2024 04:41:46 -0500 Subject: [PATCH 400/489] Merge hell --- uncompyle6/parsers/parse25.py | 3 ++- uncompyle6/parsers/parse26.py | 6 ++++-- uncompyle6/parsers/parse36.py | 7 +++++-- uncompyle6/parsers/parse37.py | 5 ++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 9eaf001fb..9578ed131 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -67,7 +67,8 @@ def p_misc25(self, args): def customize_grammar_rules(self, tokens, customize): # Remove grammar rules inherited from Python 2.6 or Python 2 - self.remove_rules(""" + 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 diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index d9c7d6467..a8a247bc6 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -550,9 +550,11 @@ class Python26ParserSingle(Python2Parser, PythonParserSingle): if PYTHON_VERSION_TRIPLE[:2] == (2, 6): lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets() from uncompyle6.scanner import get_scanner + s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY) - opcode_set = set(s.opc.opname).union(set( - """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM + opcode_set = set(s.opc.opname).union( + set( + """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LAMBDA_MARKER RETURN_LAST """.split() diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index f0a995b7e..53d792c33 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -382,7 +382,10 @@ def customize_grammar_rules(self, tokens, customize): elif opname == "GET_AITER": self.add_unique_doc_rules("get_aiter ::= expr GET_AITER", customize) - if not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) in self.seen_ops: + if ( + not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) + in self.seen_ops + ): self.addRule( """ expr ::= dict_comp_async @@ -581,7 +584,7 @@ def custom_classfunc_rule(self, opname, token, customize, next_token, is_pypy): ) else: self.addRule("expr ::= call_kw36", nop_func) - values = 'expr ' * token.attr + values = "expr " * token.attr rule = "call_kw36 ::= expr %s LOAD_CONST %s" % (values, opname) self.add_unique_rule(rule, token.kind, token.attr, customize) elif opname == "CALL_FUNCTION_EX_KW": diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 555aaaa54..9925ef1c2 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -1347,7 +1347,10 @@ def customize_grammar_rules(self, tokens, customize): elif opname == "GET_AITER": self.add_unique_doc_rules("get_aiter ::= expr GET_AITER", customize) - if not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) in self.seen_ops: + if ( + not set(["MAKE_FUNCTION_0", "MAKE_FUNCTION_CLOSURE"]) + in self.seen_ops + ): self.addRule( """ expr ::= dict_comp_async From dc79ec3a252634ad59c97a347cd055c366d9cf32 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Mar 2024 21:09:25 -0400 Subject: [PATCH 401/489] Correct variable name --- uncompyle6/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index e044abf22..54538b990 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -360,7 +360,7 @@ def main( outstream.write("%s\n%s\n%s\n" % (line, e[0], line)) last_mod = e[0] info = offsets[e] - extract_info = deparse_object.extract_node_info(info) + extract_info = deparsed_object.extract_node_info(info) outstream.write("%s" % info.node.format().strip() + "\n") outstream.write(extract_info.selectedLine + "\n") outstream.write(extract_info.markerLine + "\n\n") From 5dd265021fd4167ecb1b12b0c5c11734a6c39735 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Mar 2024 21:34:47 -0400 Subject: [PATCH 402/489] Add --asm++ or -A option --- uncompyle6/bin/uncompile.py | 14 +++++++------- uncompyle6/scanners/scanner26.py | 4 +++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index 12a4dc547..da1b1f3bf 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -54,7 +54,8 @@ --help show this message Debugging Options: - --asm | -a include byte-code (disables --verify) + --asm | -a show disassembly (disables --verify) + --asm++ | -A also include tokenized assembly (disables --verify) --grammar | -g show matching grammar --tree={before|after} -t {before|after} include syntax before (or after) tree transformation @@ -111,8 +112,8 @@ def main_bin(): try: opts, pyc_paths = getopt.getopt( sys.argv[1:], - "hac:gtTdrVo:p:", - "help asm compile= grammar linemaps recurse " + "haAc:gtTdrVo:p:", + "help asm showasm compile= grammar linemaps recurse " "timestamp tree= tree+ " "fragments verify verify-run version " "syntax-verify " @@ -148,10 +149,7 @@ def main_bin(): elif opt == "--linemaps": options["do_linemaps"] = True elif opt in ("--asm", "-a"): - if options["showasm"] == None: - options["showasm"] = "after" - else: - options["showasm"] = "both" + options["showasm"] = "before" options["do_verify"] = None elif opt in ("--tree", "-t"): if "showast" not in options: @@ -163,6 +161,8 @@ def main_bin(): else: options["showast"]["before"] = True options["do_verify"] = None + elif opt in ("--asm++", "-A"): + options["showasm"] = "both" elif opt in ("--tree+", "-T"): if "showast" not in options: options["showast"] = {} diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index a8eaef861..10bb7c7c8 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -76,8 +76,9 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): # show_asm = 'after' if show_asm in ("both", "before"): + print("\n# ---- before tokenization:") for instr in bytecode.get_instructions(co): - print(instr.disassemble()) + print(instr.disassemble(self.opc)) # Container for tokens tokens = [] @@ -341,6 +342,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): pass if show_asm in ("both", "after"): + print("\n# ---- after tokenization:") for t in tokens: print(t.format(line_prefix="")) print() From c151085387f6c432d05bedd08d16f678794e7201 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 13 Mar 2024 21:44:41 -0400 Subject: [PATCH 403/489] Merge hell --- uncompyle6/scanners/scanner26.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 5111c06cc..10bb7c7c8 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -27,7 +27,6 @@ from xdis.bytecode import _get_const_info from xdis.opcodes import opcode_26 -import uncompyle6.scanners.scanner2 as scan from uncompyle6.scanner import Token from uncompyle6.scanners.scanner2 import Scanner2 From 7209405b2c1b1a8de220350dc067771431c3f744 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 Mar 2024 15:17:37 -0400 Subject: [PATCH 404/489] Adjust setup to correct version --- .pre-commit-config.yaml | 11 ----------- setup.py | 6 +++--- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b51fd5936..23b5c2060 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,14 +9,3 @@ repos: stages: [commit] - id: end-of-file-fixer stages: [commit] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - stages: [commit] -- repo: https://github.com/psf/black - rev: 23.12.1 - hooks: - - id: black - language_version: python3 - stages: [commit] diff --git a/setup.py b/setup.py index c2f8753ef..2dd58a231 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ """Setup script for the 'uncompyle6' distribution.""" SYS_VERSION = sys.version_info[0:2] -if not ((3, 0) <= SYS_VERSION < (3, 3)): +if not ((3, 3) <= SYS_VERSION < (3, 6)): mess = "Python Release 3.0 .. 3.2 are supported in this code branch." if (2, 4) <= SYS_VERSION <= (2, 7): mess += ( @@ -17,9 +17,9 @@ "\nFor your Python, version %s, use the master code/branch." % sys.version[0:3] ) - if (3, 3) >= SYS_VERSION < (3, 6): + if (3, 0) >= SYS_VERSION < (3, 3): mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." + "\nFor your Python, version %s, use the python-3.0-to-3.2 code/branch." % sys.version[0:3] ) elif SYS_VERSION < (2, 4): From 274d5e940514711539e9c817875e3984be43237c Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 Mar 2024 15:19:50 -0400 Subject: [PATCH 405/489] Adjust setup.p --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 2dd58a231..467e2b63f 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ """Setup script for the 'uncompyle6' distribution.""" SYS_VERSION = sys.version_info[0:2] -if not ((3, 3) <= SYS_VERSION < (3, 6)): +if not ((3, 0) <= SYS_VERSION < (3, 3)): mess = "Python Release 3.0 .. 3.2 are supported in this code branch." if (2, 4) <= SYS_VERSION <= (2, 7): mess += ( @@ -17,9 +17,9 @@ "\nFor your Python, version %s, use the master code/branch." % sys.version[0:3] ) - if (3, 0) >= SYS_VERSION < (3, 3): + if (3, 3) >= SYS_VERSION < (3, 6): mess += ( - "\nFor your Python, version %s, use the python-3.0-to-3.2 code/branch." + "\nFor your Python, version %s, use the python-3.3-to-3.6 code/branch." % sys.version[0:3] ) elif SYS_VERSION < (2, 4): From 85e5d725290e914f3ecea73688413977732b9b41 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 Mar 2024 15:21:14 -0400 Subject: [PATCH 406/489] Adjust setup message --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2dd58a231..9e5b42c81 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ SYS_VERSION = sys.version_info[0:2] if not ((3, 3) <= SYS_VERSION < (3, 6)): - mess = "Python Release 3.0 .. 3.2 are supported in this code branch." + mess = "Python Release 3.3 .. 3.5 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." From ee72f6d685a2c675a5f477c5c6f7f55218d2069e Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 15 Mar 2024 22:02:53 -0400 Subject: [PATCH 407/489] Get ready for release 3.9.1 --- .circleci/config.yml | 4 +-- .github/workflows/osx.yml | 4 +-- .github/workflows/ubuntu.yml | 3 +- .github/workflows/windows.yml | 4 +-- NEWS.md | 20 ++++++++++++ __pkginfo__.py | 2 ++ setup.py | 61 ++--------------------------------- uncompyle6/version.py | 2 +- 8 files changed, 33 insertions(+), 67 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f05ee99bf..4850625c2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,9 +43,9 @@ jobs: - run: command: | # Use pip to install dependengcies sudo pip install --user --upgrade setuptools - # Until the next release - sudo pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install --user -e . + # Not sure why "pip install -e" doesn't work above + pip install click spark-parser xdis pip install --user -r requirements-dev.txt # Save dependency cache diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 38eac9b02..724517d62 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index bfabdfeeb..d5093c4ce 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,9 +21,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 34d1ea553..82d36e927 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/NEWS.md b/NEWS.md index 887a597ca..853dd00c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,23 @@ +3.9.1: 2024-05-15 +================= + +Lots of changes major changes. track xdis API has changes. + +Separate Phases more clearly: +* disassembly +* tokenization +* parsing +* abstracting to AST (more is done in newer projects) +* printing + +Although we do not decompile bytecode greater than 3.8, code supports running from up to 3.12. + +Many bugs fixed. + +A lot of Linting and coding style modernization. + +Work done in preparation for Blackhat Asia 2024 + 3.9.0: 2022-12-22 ================= diff --git a/__pkginfo__.py b/__pkginfo__.py index 98fa63d50..2f2201059 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -62,6 +62,8 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Debuggers", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/setup.py b/setup.py index 515ee367c..2ff64d0fe 100755 --- a/setup.py +++ b/setup.py @@ -1,61 +1,6 @@ #!/usr/bin/env python -import setuptools -import sys +"""Setup script for the 'xdis' distribution.""" -"""Setup script for the 'uncompyle6' distribution.""" +from setuptools import setup -SYS_VERSION = sys.version_info[0:2] -if not ((2, 4) <= SYS_VERSION < (3, 13)): - mess = "Python Release 2.6 .. 3.12 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." - % sys.version[0:3] - ) - if (3, 3) <= SYS_VERSION < (3, 6): - mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." - % sys.version[0:3] - ) - elif SYS_VERSION < (2, 4): - mess += ( - "\nThis package is not supported for Python version %s." % sys.version[0:3] - ) - print(mess) - raise Exception(mess) - -from __pkginfo__ import ( - author, - author_email, - install_requires, - license, - long_description, - classifiers, - entry_points, - modname, - py_modules, - short_desc, - __version__, - web, - zip_safe, -) - -setuptools.setup( - author=author, - author_email=author_email, - classifiers=classifiers, - description=short_desc, - entry_points=entry_points, - install_requires=install_requires, - license=license, - long_description=long_description, - long_description_content_type="text/x-rst", - name=modname, - packages=setuptools.find_packages(), - py_modules=py_modules, - test_suite="nose.collector", - url=web, - tests_require=["nose>=1.0"], - version=__version__, - zip_safe=zip_safe, -) +setup(packages=["uncompyle6"]) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 03e22cc7b..669350ed8 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.1.dev0" # noqa +__version__="3.9.1" # noqa From 3aed87ac5e841c63b41fc50c20d776573aa4380b Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 15 Mar 2024 22:02:53 -0400 Subject: [PATCH 408/489] Get ready for release 3.9.1 --- .circleci/config.yml | 4 +-- .github/workflows/osx.yml | 4 +-- .github/workflows/ubuntu.yml | 3 +- .github/workflows/windows.yml | 4 +-- NEWS.md | 20 +++++++++++ __pkginfo__.py | 2 ++ pyproject.toml | 64 +++++++++++++++++++++++++++++++++++ setup.py | 61 ++------------------------------- uncompyle6/version.py | 2 +- 9 files changed, 97 insertions(+), 67 deletions(-) create mode 100644 pyproject.toml diff --git a/.circleci/config.yml b/.circleci/config.yml index f05ee99bf..84edb9518 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,9 +43,9 @@ jobs: - run: command: | # Use pip to install dependengcies sudo pip install --user --upgrade setuptools - # Until the next release - sudo pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install --user -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install --user -r requirements-dev.txt # Save dependency cache diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 38eac9b02..ad8ba5dad 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index bfabdfeeb..8415d348c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,9 +21,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 34d1ea553..176e4ca01 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/NEWS.md b/NEWS.md index 887a597ca..853dd00c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,23 @@ +3.9.1: 2024-05-15 +================= + +Lots of changes major changes. track xdis API has changes. + +Separate Phases more clearly: +* disassembly +* tokenization +* parsing +* abstracting to AST (more is done in newer projects) +* printing + +Although we do not decompile bytecode greater than 3.8, code supports running from up to 3.12. + +Many bugs fixed. + +A lot of Linting and coding style modernization. + +Work done in preparation for Blackhat Asia 2024 + 3.9.0: 2022-12-22 ================= diff --git a/__pkginfo__.py b/__pkginfo__.py index 98fa63d50..2f2201059 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -62,6 +62,8 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Debuggers", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..d78c173e2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,64 @@ +[build-system] +requires = [ + "setuptools>=61.2", +] + +build-backend = "setuptools.build_meta" + +[project] +authors = [ + {name = "Rocky Bernstein", email = "rb@dustyfeet.com"}, +] + +name = "uncompyle6" +description = "Python cross-version byte-code library and disassembler" +dependencies = [ + "click", + "spark-parser >= 1.8.9, < 1.9.0", + "xdis >= 6.0.8, < 6.2.0", +] +readme = "README.rst" +license = {text = "GPL"} +keywords = ["Python bytecode", "bytecode", "disassembler"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 2.4", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.0", + "Programming Language :: Python :: 3.1", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dynamic = ["version"] + +[project.urls] +Homepage = "https://github.com/rocky/python-uncompyle6" +Downloads = "https://github.com/rocky/python-uncompyle6/releases" + +[project.optional-dependencies] +dev = [ + "pre-commit", + "pytest", +] + +[project.scripts] +uncompyle6 = "uncompyle6.bin.uncompile:main_bin" +uncompyle6-tokenize = "uncompyle6.bin.pydisassemble:main" + +[tool.setuptools.dynamic] +version = {attr = "uncompyle6.version.__version__"} diff --git a/setup.py b/setup.py index 515ee367c..2ff64d0fe 100755 --- a/setup.py +++ b/setup.py @@ -1,61 +1,6 @@ #!/usr/bin/env python -import setuptools -import sys +"""Setup script for the 'xdis' distribution.""" -"""Setup script for the 'uncompyle6' distribution.""" +from setuptools import setup -SYS_VERSION = sys.version_info[0:2] -if not ((2, 4) <= SYS_VERSION < (3, 13)): - mess = "Python Release 2.6 .. 3.12 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." - % sys.version[0:3] - ) - if (3, 3) <= SYS_VERSION < (3, 6): - mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." - % sys.version[0:3] - ) - elif SYS_VERSION < (2, 4): - mess += ( - "\nThis package is not supported for Python version %s." % sys.version[0:3] - ) - print(mess) - raise Exception(mess) - -from __pkginfo__ import ( - author, - author_email, - install_requires, - license, - long_description, - classifiers, - entry_points, - modname, - py_modules, - short_desc, - __version__, - web, - zip_safe, -) - -setuptools.setup( - author=author, - author_email=author_email, - classifiers=classifiers, - description=short_desc, - entry_points=entry_points, - install_requires=install_requires, - license=license, - long_description=long_description, - long_description_content_type="text/x-rst", - name=modname, - packages=setuptools.find_packages(), - py_modules=py_modules, - test_suite="nose.collector", - url=web, - tests_require=["nose>=1.0"], - version=__version__, - zip_safe=zip_safe, -) +setup(packages=["uncompyle6"]) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 03e22cc7b..669350ed8 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.1.dev0" # noqa +__version__="3.9.1" # noqa From b7eae4f360e3c47c8870086b124a2c23ffb647e0 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 15 Mar 2024 22:02:53 -0400 Subject: [PATCH 409/489] Get ready for release 3.9.1 --- .circleci/config.yml | 4 +- .github/workflows/osx.yml | 4 +- .github/workflows/ubuntu.yml | 3 +- .github/workflows/windows.yml | 4 +- NEWS.md | 20 ++++++++++ __pkginfo__.py | 2 + admin-tools/make-dist-2.4-2.7.sh | 10 ++++- admin-tools/make-dist-3.0-3.2.sh | 49 ++++++++++++++++++++++++ admin-tools/make-dist-3.3-3.5.sh | 15 +++++++- admin-tools/make-dist-newest.sh | 10 ++++- pyproject.toml | 64 ++++++++++++++++++++++++++++++++ setup.py | 61 ++---------------------------- uncompyle6/version.py | 2 +- 13 files changed, 175 insertions(+), 73 deletions(-) create mode 100644 admin-tools/make-dist-3.0-3.2.sh create mode 100644 pyproject.toml diff --git a/.circleci/config.yml b/.circleci/config.yml index f05ee99bf..84edb9518 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,9 +43,9 @@ jobs: - run: command: | # Use pip to install dependengcies sudo pip install --user --upgrade setuptools - # Until the next release - sudo pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install --user -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install --user -r requirements-dev.txt # Save dependency cache diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 38eac9b02..ad8ba5dad 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index bfabdfeeb..8415d348c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,9 +21,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 34d1ea553..176e4ca01 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,9 +22,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - # Until the next xdis release - pip install git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . + # Not sure why "pip install -e" doesn't work above + # pip install click spark-parser xdis pip install -r requirements-dev.txt - name: Test uncompyle6 run: | diff --git a/NEWS.md b/NEWS.md index 887a597ca..853dd00c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,23 @@ +3.9.1: 2024-05-15 +================= + +Lots of changes major changes. track xdis API has changes. + +Separate Phases more clearly: +* disassembly +* tokenization +* parsing +* abstracting to AST (more is done in newer projects) +* printing + +Although we do not decompile bytecode greater than 3.8, code supports running from up to 3.12. + +Many bugs fixed. + +A lot of Linting and coding style modernization. + +Work done in preparation for Blackhat Asia 2024 + 3.9.0: 2022-12-22 ================= diff --git a/__pkginfo__.py b/__pkginfo__.py index 98fa63d50..2f2201059 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -62,6 +62,8 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Debuggers", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index 0b1f520a5..a0ac73b89 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -3,9 +3,9 @@ PACKAGE=uncompyle6 # FIXME put some of the below in a common routine function finish { - cd $owd + cd $make_dist_uncompyle6_owd } -owd=$(pwd) +make_dist_uncompyle6_owd=$(pwd) trap finish EXIT cd $(dirname ${BASH_SOURCE[0]}) @@ -21,6 +21,11 @@ source $PACKAGE/version.py echo $__version__ for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi if ! pyenv local $pyversion ; then exit $? fi @@ -41,3 +46,4 @@ tarball=dist/${PACKAGE}-${__version_}_-tar.gz if [[ -f $tarball ]]; then rm -v dist/${PACKAGE}-${__version__}-tar.gz fi +finish diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh new file mode 100644 index 000000000..e5149c41e --- /dev/null +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -0,0 +1,49 @@ +#!/bin/bash +PACKAGE=uncompyle6 + +# FIXME put some of the below in a common routine +function finish { + cd $uncompyle6_30_make_dist_owd +} + +cd $(dirname ${BASH_SOURCE[0]}) +uncompyle6_30_make_dist_owd=$(pwd) +trap finish EXIT + +if ! source ./pyenv-3.0-3.2-versions ; then + exit $? +fi +if ! source ./setup-python-3.0.sh ; then + exit $? +fi + +cd .. +source $PACKAGE/version.py +echo $__version__ + +for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi + if ! pyenv local $pyversion ; then + exit $? + fi + # pip bdist_egg create too-general wheels. So + # we narrow that by moving the generated wheel. + + # Pick out first two number of version, e.g. 3.5.1 -> 35 + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_egg bdist_wheel + mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + echo === $pyversion === +done + +python ./setup.py sdist +tarball=dist/${PACKAGE}-${__version__}.tar.gz +if [[ -f $tarball ]]; then + mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz +fi +finish diff --git a/admin-tools/make-dist-3.3-3.5.sh b/admin-tools/make-dist-3.3-3.5.sh index 95426ffb1..1c1f214be 100755 --- a/admin-tools/make-dist-3.3-3.5.sh +++ b/admin-tools/make-dist-3.3-3.5.sh @@ -3,11 +3,11 @@ PACKAGE=uncompyle6 # FIXME put some of the below in a common routine function finish { - cd $owd + cd $uncompyle6_33_make_owd } cd $(dirname ${BASH_SOURCE[0]}) -owd=$(pwd) +uncompyle6_33_make_owd=$(pwd) trap finish EXIT if ! source ./pyenv-3.3-3.5-versions ; then @@ -22,6 +22,11 @@ source $PACKAGE/version.py echo $__version__ for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi if ! pyenv local $pyversion ; then exit $? fi @@ -33,6 +38,12 @@ for pyversion in $PYVERSIONS; do rm -fr build python setup.py bdist_egg bdist_wheel mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + echo === $pyversion === done python ./setup.py sdist +tarball=dist/${PACKAGE}-${__version__}.tar.gz +if [[ -f $tarball ]]; then + mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz +fi +finish diff --git a/admin-tools/make-dist-newest.sh b/admin-tools/make-dist-newest.sh index af04b060b..f5b967af5 100755 --- a/admin-tools/make-dist-newest.sh +++ b/admin-tools/make-dist-newest.sh @@ -3,11 +3,11 @@ PACKAGE=uncompyle6 # FIXME put some of the below in a common routine function finish { - cd $owd + cd $make_uncompyle6_newest_owd } cd $(dirname ${BASH_SOURCE[0]}) -owd=$(pwd) +make_uncompyle6_newest_owd=$(pwd) trap finish EXIT if ! source ./pyenv-newest-versions ; then @@ -22,6 +22,11 @@ source $PACKAGE/version.py echo $__version__ for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi if ! pyenv local $pyversion ; then exit $? fi @@ -36,3 +41,4 @@ for pyversion in $PYVERSIONS; do done python ./setup.py sdist +finish diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..d78c173e2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,64 @@ +[build-system] +requires = [ + "setuptools>=61.2", +] + +build-backend = "setuptools.build_meta" + +[project] +authors = [ + {name = "Rocky Bernstein", email = "rb@dustyfeet.com"}, +] + +name = "uncompyle6" +description = "Python cross-version byte-code library and disassembler" +dependencies = [ + "click", + "spark-parser >= 1.8.9, < 1.9.0", + "xdis >= 6.0.8, < 6.2.0", +] +readme = "README.rst" +license = {text = "GPL"} +keywords = ["Python bytecode", "bytecode", "disassembler"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 2.4", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.0", + "Programming Language :: Python :: 3.1", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dynamic = ["version"] + +[project.urls] +Homepage = "https://github.com/rocky/python-uncompyle6" +Downloads = "https://github.com/rocky/python-uncompyle6/releases" + +[project.optional-dependencies] +dev = [ + "pre-commit", + "pytest", +] + +[project.scripts] +uncompyle6 = "uncompyle6.bin.uncompile:main_bin" +uncompyle6-tokenize = "uncompyle6.bin.pydisassemble:main" + +[tool.setuptools.dynamic] +version = {attr = "uncompyle6.version.__version__"} diff --git a/setup.py b/setup.py index 515ee367c..2ff64d0fe 100755 --- a/setup.py +++ b/setup.py @@ -1,61 +1,6 @@ #!/usr/bin/env python -import setuptools -import sys +"""Setup script for the 'xdis' distribution.""" -"""Setup script for the 'uncompyle6' distribution.""" +from setuptools import setup -SYS_VERSION = sys.version_info[0:2] -if not ((2, 4) <= SYS_VERSION < (3, 13)): - mess = "Python Release 2.6 .. 3.12 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." - % sys.version[0:3] - ) - if (3, 3) <= SYS_VERSION < (3, 6): - mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." - % sys.version[0:3] - ) - elif SYS_VERSION < (2, 4): - mess += ( - "\nThis package is not supported for Python version %s." % sys.version[0:3] - ) - print(mess) - raise Exception(mess) - -from __pkginfo__ import ( - author, - author_email, - install_requires, - license, - long_description, - classifiers, - entry_points, - modname, - py_modules, - short_desc, - __version__, - web, - zip_safe, -) - -setuptools.setup( - author=author, - author_email=author_email, - classifiers=classifiers, - description=short_desc, - entry_points=entry_points, - install_requires=install_requires, - license=license, - long_description=long_description, - long_description_content_type="text/x-rst", - name=modname, - packages=setuptools.find_packages(), - py_modules=py_modules, - test_suite="nose.collector", - url=web, - tests_require=["nose>=1.0"], - version=__version__, - zip_safe=zip_safe, -) +setup(packages=["uncompyle6"]) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 03e22cc7b..669350ed8 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.1.dev0" # noqa +__version__="3.9.1" # noqa From e12d840447ee8330d3e4c756ca2441da3e25e2d7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 16 Mar 2024 03:18:39 -0400 Subject: [PATCH 410/489] 2.x tolerance --- uncompyle6/parsers/reducecheck/whilestmt.py | 6 +-- uncompyle6/parsers/reducecheck/whilestmt38.py | 6 +-- uncompyle6/scanners/scanner30.py | 4 +- uncompyle6/semantics/gencomp-for-3.0.py | 47 ++++++++++++------- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/uncompyle6/parsers/reducecheck/whilestmt.py b/uncompyle6/parsers/reducecheck/whilestmt.py index 6d8ade009..ca092be81 100644 --- a/uncompyle6/parsers/reducecheck/whilestmt.py +++ b/uncompyle6/parsers/reducecheck/whilestmt.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Rocky Bernstein +# Copyright (c) 2020, 2024 Rocky Bernstein # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -13,9 +13,7 @@ # along with this program. If not, see . -def whilestmt( - self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int -) -> bool: +def whilestmt(self, lhs, n, rule, tree, tokens, first, last): # When we are missing a COME_FROM_LOOP, the # "while" statement is nested inside an if/else # so after the POP_BLOCK we have a JUMP_FORWARD which forms the "else" portion of the "if" diff --git a/uncompyle6/parsers/reducecheck/whilestmt38.py b/uncompyle6/parsers/reducecheck/whilestmt38.py index d53d82a8d..32a6116c2 100644 --- a/uncompyle6/parsers/reducecheck/whilestmt38.py +++ b/uncompyle6/parsers/reducecheck/whilestmt38.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Rocky Bernstein +# Copyright (c) 2022, 2024 Rocky Bernstein # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -13,9 +13,7 @@ # along with this program. If not, see . -def whilestmt38_check( - self, lhs: str, n: int, rule, ast, tokens: list, first: int, last: int -) -> bool: +def whilestmt38_check(self, lhs, n, rule, ast, tokens, first, last): # When we are missing a COME_FROM_LOOP, the # "while" statement is nested inside an if/else # so after the POP_BLOCK we have a JUMP_FORWARD which forms the "else" portion of the "if" diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index 87e86cf98..a514dde52 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017, 2020-2022 by Rocky Bernstein +# Copyright (c) 2016-2017, 2020-2022, 2024 by Rocky Bernstein """ Python 3.0 bytecode scanner/deparser @@ -6,8 +6,6 @@ scanner routine for Python 3. """ -from __future__ import print_function - import xdis from xdis import instruction_size diff --git a/uncompyle6/semantics/gencomp-for-3.0.py b/uncompyle6/semantics/gencomp-for-3.0.py index ec90ef3dd..0000b7d5e 100644 --- a/uncompyle6/semantics/gencomp-for-3.0.py +++ b/uncompyle6/semantics/gencomp-for-3.0.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 by Rocky Bernstein +# Copyright (c) 2022-2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -46,7 +46,10 @@ def closure_walk(self, node, collection_index): p = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 - code_index = 0 if node[0] == "load_genexpr" else 1 + if node[0] == "load_genexpr": + code_index = 0 + else: + code_index = 1 tree = self.get_comprehension_function(node, code_index=code_index) # Remove single reductions as in ("stmts", "sstmt"): @@ -56,7 +59,10 @@ def closure_walk(self, node, collection_index): store = tree[3] collection = node[collection_index] - iter_index = 3 if tree == "genexpr_func_async" else 4 + if tree == "genexpr_func_async": + iter_index = 3 + else: + iter_index = 4 n = tree[iter_index] list_if = None assert n == "comp_iter" @@ -98,13 +104,8 @@ def closure_walk(self, node, collection_index): self.preorder(list_if) self.prec = p - def comprehension_walk( - self, - node, - iter_index: Optional[int], - code_index: int = -5, - ): - p: int = self.prec + def comprehension_walk(self, node, iter_index, code_index = -5): + p = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 # FIXME: clean this up @@ -225,8 +226,8 @@ def comprehension_walk( def comprehension_walk_newer( self, node, - iter_index: Optional[int], - code_index: int = -5, + iter_index, + code_index = -5, collection_node=None, ): """Non-closure-based comprehensions the way they are done in Python3 @@ -295,7 +296,10 @@ def comprehension_walk_newer( assert list_afor2 == "list_afor2" store = list_afor2[1] assert store == "store" - n = list_afor2[3] if list_afor2[3] == "list_iter" else list_afor2[2] + if list_afor2[3] == "list_iter": + n = list_afor2[3] + else: + n = list_afor2[2] else: # ??? pass @@ -538,7 +542,7 @@ def comprehension_walk_newer( pass self.prec = p - def get_comprehension_function(self, node, code_index: int): + def get_comprehension_function(self, node, code_index): """ Build the body of a comprehension function and then find the comprehension node buried in the tree which may @@ -583,7 +587,10 @@ def get_comprehension_function(self, node, code_index: int): while len(tree) == 1 or (tree in ("stmt", "sstmt", "return", "return_expr")): self.prec = 100 - tree = tree[1] if tree[0] in ("dom_start", "dom_start_opt") else tree[0] + if tree[0] in ("dom_start", "dom_start_opt"): + tree = tree[1] + else: + tree = tree[0] return tree def listcomp_closure3(self, node): @@ -688,7 +695,10 @@ def listcomp_closure3(self, node): if self.version[:2] == (3, 0) and n[2] == "list_iter": n = n[2] else: - n = n[-2] if n[-1] == "come_from_opt" else n[-1] + if n[-1] == "come_from_opt": + n = n[-2] + else: + n = n[-1] pass elif n == "list_if37": list_ifs.append(n) @@ -698,7 +708,10 @@ def listcomp_closure3(self, node): collections.append(n[0][0]) n = n[1] stores.append(n[1][0]) - n = n[2] if n[2].kind == "list_iter" else n[3] + if n[2].kind == "list_iter": + n = n[2] + else: + n = n[3] pass assert n == "lc_body", tree From 30d7efb24c81026a56458b76ef5510a4c6b0420b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 16 Mar 2024 03:34:31 -0400 Subject: [PATCH 411/489] 3.0 tolerance --- admin-tools/make-dist-3.0-3.2.sh | 0 uncompyle6/semantics/gencomp-for-3.0.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 admin-tools/make-dist-3.0-3.2.sh diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh old mode 100644 new mode 100755 diff --git a/uncompyle6/semantics/gencomp-for-3.0.py b/uncompyle6/semantics/gencomp-for-3.0.py index ec90ef3dd..cab1207fd 100644 --- a/uncompyle6/semantics/gencomp-for-3.0.py +++ b/uncompyle6/semantics/gencomp-for-3.0.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 by Rocky Bernstein +# Copyright (c) 2022-2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -104,7 +104,7 @@ def comprehension_walk( iter_index: Optional[int], code_index: int = -5, ): - p: int = self.prec + p = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 # FIXME: clean this up From 0f34fb672689725f8436dff4c12de7ebd129a848 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 16 Mar 2024 03:37:43 -0400 Subject: [PATCH 412/489] Administrivia --- admin-tools/make-dist-3.0-3.2.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 admin-tools/make-dist-3.0-3.2.sh diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh old mode 100644 new mode 100755 From 393946628126143b9ea14d1792f45e0d3696eebe Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 30 May 2024 04:47:35 -0400 Subject: [PATCH 413/489] Merge hell --- PKG-INFO | 158 ++++++++++++++++++++++++------------------------- pyproject.toml | 64 -------------------- setup.py | 39 +++++++++++- 3 files changed, 116 insertions(+), 145 deletions(-) delete mode 100644 pyproject.toml diff --git a/PKG-INFO b/PKG-INFO index bd7c79cea..374f7eb46 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -7,54 +7,54 @@ Author: Rocky Bernstein, Hartmut Goebel, John Aycock, and others Author-email: rb@dustyfeet.com License: GPL3 Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python Versions| - + |packagestatus| - + .. contents:: - + uncompyle6 ========== - + A native Python cross-version decompiler and fragment decompiler. The successor to decompyle, uncompyle, and uncompyle2. - - + + Introduction ------------ - + *uncompyle6* translates Python bytecode back into equivalent Python source code. It accepts bytecodes from Python version 1.0 to version 3.8, spanning over 24 years of Python releases. We include Dropbox's Python 2.5 bytecode and some PyPy bytecodes. - + Why this? --------- - + Ok, I'll say it: this software is amazing. It is more than your normal hacky decompiler. Using compiler_ technology, the program creates a parse tree of the program from the instructions; nodes at the upper levels that look a little like what might come from a Python AST. So we can really classify and understand what's going on in sections of Python bytecode. - + Building on this, another thing that makes this different from other CPython bytecode decompilers is the ability to deparse just *fragments* of source code and give source-code information around a given bytecode offset. - + I use the tree fragments to deparse fragments of code *at run time* inside my trepan_ debuggers_. For that, bytecode offsets are recorded and associated with fragments of the source code. This purpose, although compatible with the original intention, is yet a little bit different. See this_ for more information. - + Python fragment deparsing given an instruction offset is useful in showing stack traces and can be incorporated into any program that wants to show a location in more detail than just a line number at runtime. This code can be also used when source-code information does not exist and there is just bytecode. Again, my debuggers make use of this. - + There were (and still are) a number of decompyle, uncompyle, uncompyle2, uncompyle3 forks around. Many of them come basically from the same code base, and (almost?) all of them are no longer actively @@ -65,148 +65,148 @@ Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python V forward*. There is some serious refactoring and cleanup in this code base over those old forks. Even more experimental refactoring is going on in decompyle3_. - + This demonstrably does the best in decompiling Python across all Python versions. And even when there is another project that only provides decompilation for subset of Python versions, we generally do demonstrably better for those as well. - + How can we tell? By taking Python bytecode that comes distributed with that version of Python and decompiling these. Among those that successfully decompile, we can then make sure the resulting programs are syntactically correct by running the Python interpreter for that bytecode version. Finally, in cases where the program has a test for itself, we can run the check on the decompiled code. - + We use an automated processes to find bugs. In the issue trackers for other decompilers, you will find a number of bugs we've found along the way. Very few to none of them are fixed in the other decompilers. - + Requirements ------------ - + The code in the git repository can be run from Python 2.4 to the latest Python version, with the exception of Python 3.0 through 3.2. Volunteers are welcome to address these deficiencies if there a desire to do so. - + The way it does this though is by segregating consecutive Python versions into git branches: - + master Python 3.6 and up (uses type annotations) python-3.3-to-3.5 Python 3.3 through 3.5 (Generic Python 3) python-2.4 Python 2.4 through 2.7 (Generic Python 2) - + PyPy 3-2.4 and later works as well. - + The bytecode files it can read have been tested on Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.8 and later PyPy versions. - + Installation ------------ - + You can install from PyPI using the name ``uncompyle6``:: - + pip install uncompyle6 - - + + To install from source code, this project uses setup.py, so it follows the standard Python routine:: - + $ pip install -e . # set up to run from source tree - + or:: - + $ python setup.py install # may need sudo - + A GNU Makefile is also provided so :code:`make install` (possibly as root or sudo) will do the steps above. - + Running Tests ------------- - + :: - + make check - + A GNU makefile has been added to smooth over setting running the right command, and running tests from fastest to slowest. - + If you have remake_ installed, you can see the list of all tasks including tests via :code:`remake --tasks` - - + + Usage ----- - + Run - + :: - + $ uncompyle6 *compiled-python-file-pyc-or-pyo* - + For usage help: - + :: - + $ uncompyle6 -h - + Verification ------------ - + In older versions of Python it was possible to verify bytecode by decompiling bytecode, and then compiling using the Python interpreter for that bytecode version. Having done this, the bytecode produced could be compared with the original bytecode. However as Python's code generation got better, this no longer was feasible. - + If you want Python syntax verification of the correctness of the decompilation process, add the :code:`--syntax-verify` option. However since Python syntax changes, you should use this option if the bytecode is the right bytecode for the Python interpreter that will be checking the syntax. - + You can also cross compare the results with another version of `uncompyle6` since there are sometimes regressions in decompiling specific bytecode as the overall quality improves. - + For Python 3.7 and 3.8, the code in decompyle3_ is generally better. - + Or try specific another python decompiler like uncompyle2_, unpyc37_, or pycdc_. Since the later two work differently, bugs here often aren't in that, and vice versa. - + There is an interesting class of these programs that is readily available give stronger verification: those programs that when run test themselves. Our test suite includes these. - + And Python comes with another a set of programs like this: its test suite for the standard library. We have some code in :code:`test/stdlib` to facilitate this kind of checking too. - + Known Bugs/Restrictions ----------------------- - + The biggest known and possibly fixable (but hard) problem has to do with handling control flow. (Python has probably the most diverse and screwy set of compound statements I've ever seen; there are "else" clauses on loops and try blocks that I suspect many programmers don't know about.) - + All of the Python decompilers that I have looked at have problems decompiling Python's control flow. In some cases we can detect an erroneous decompilation and report that. - + Python support is pretty good for Python 2 - + On the lower end of Python versions, decompilation seems pretty good although we don't have any automated testing in place for Python's distributed tests. Also, we don't have a Python interpreter for versions 1.6, and 2.0. - + In the Python 3 series, Python support is strongest around 3.4 or 3.3 and drops off as you move further away from those versions. Python 3.0 is weird in that it in some ways resembles 2.6 more than it does @@ -218,43 +218,43 @@ Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python V :code:`EXTENDED_ARG` instructions, additional jump optimization has been added. So in sum handling control flow by ad hoc means as is currently done is worse. - + Between Python 3.5, 3.6, 3.7 there have been major changes to the :code:`MAKE_FUNCTION` and :code:`CALL_FUNCTION` instructions. - + Python 3.8 removes :code:`SETUP_LOOP`, :code:`SETUP_EXCEPT`, :code:`BREAK_LOOP`, and :code:`CONTINUE_LOOP`, instructions which may make control-flow detection harder, lacking the more sophisticated control-flow analysis that is planned. We'll see. - + Currently not all Python magic numbers are supported. Specifically in some versions of Python, notably Python 3.6, the magic number has changes several times within a version. - + **We support only released versions, not candidate versions.** Note however that the magic of a released version is usually the same as the *last* candidate version prior to release. - + There are also customized Python interpreters, notably Dropbox, which use their own magic and encrypt bytecode. With the exception of the Dropbox's old Python 2.5 interpreter this kind of thing is not handled. - + We also don't handle PJOrion_ or otherwise obfuscated code. For PJOrion try: PJOrion Deobfuscator_ to unscramble the bytecode to get valid bytecode before trying this tool; pydecipher_ might help with that. - + This program can't decompile Microsoft Windows EXE files created by Py2EXE_, although we can probably decompile the code after you extract the bytecode properly. `Pydeinstaller `_ may help with unpacking Pyinstaller bundlers. - + Handling pathologically long lists of expressions or statements is slow. We don't handle Cython_ or MicroPython which don't use bytecode. - + There are numerous bugs in decompilation. And that's true for every other CPython decompiler I have encountered, even the ones that claimed to be "perfect" on some particular version like 2.4. - + As Python progresses decompilation also gets harder because the compilation is more sophisticated and the language itself is more sophisticated. I suspect that attempts there will be fewer ad-hoc @@ -265,28 +265,28 @@ Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python V project is better funded, I do not intend to make any serious effort to support Python versions 3.8 or 3.9, including bugs that might come in. I imagine at some point I may be interested in it. - + You can easily find bugs by running the tests against the standard test suite that Python uses to check itself. At any given time, there are dozens of known problems that are pretty well isolated and that could be solved if one were to put in the time to do so. The problem is that there aren't that many people who have been working on bug fixing. - + Some of the bugs in 3.7 and 3.8 are simply a matter of back-porting the fixes in decompyle3. Volunteers are welcome to do so. - + You may run across a bug, that you want to report. Please do so after reading `How to report a bug `_ and follow the `instructions when opening an issue `_. - + Be aware that it might not get my attention for a while. If you sponsor or support the project in some way, I'll prioritize your issues above the queue of other things I might be doing instead. - + See Also -------- - + * https://github.com/rocky/python-decompile3 : Much smaller and more modern code, focusing on 3.7 and 3.8. Changes in that will get migrated back here. * 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. Currently unmaintained. * https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations. Currently unmaintained. @@ -297,8 +297,8 @@ Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python V * https://github.com/rocky/python-xasm : Cross Python version assembler * https://github.com/rocky/python-uncompyle6/wiki : Wiki Documents which describe the code and aspects of it in more detail * https://github.com/zrax/pycdc : The README for this C++ code says it aims to support all versions of Python. You can aim your slign shot for the moon too, but I doubt you are going to hit it. This code is best for Python versions around 2.7 and 3.3 when the code was initially developed. Accuracy for current versions of Python3 and early versions of Python is lacking. Without major effort, it is unlikely it can be made to support current Python 3. See its `issue tracker `_ for details. Currently lightly maintained. - - + + .. _Cython: https://en.wikipedia.org/wiki/Cython .. _trepan: https://pypi.python.org/pypi/trepan3k .. _compiler: https://github.com/rocky/python-uncompyle6/wiki/How-does-this-code-work%3F @@ -323,9 +323,9 @@ Description: |buildstatus| |Pypi Installs| |Latest Version| |Supported Python V .. |Latest Version| image:: https://badge.fury.io/py/uncompyle6.svg :target: https://badge.fury.io/py/uncompyle6 .. |Pypi Installs| image:: https://pepy.tech/badge/uncompyle6/month - - -Platform: UNKNOWN + + +Platform: uncompyle6 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index d78c173e2..000000000 --- a/pyproject.toml +++ /dev/null @@ -1,64 +0,0 @@ -[build-system] -requires = [ - "setuptools>=61.2", -] - -build-backend = "setuptools.build_meta" - -[project] -authors = [ - {name = "Rocky Bernstein", email = "rb@dustyfeet.com"}, -] - -name = "uncompyle6" -description = "Python cross-version byte-code library and disassembler" -dependencies = [ - "click", - "spark-parser >= 1.8.9, < 1.9.0", - "xdis >= 6.0.8, < 6.2.0", -] -readme = "README.rst" -license = {text = "GPL"} -keywords = ["Python bytecode", "bytecode", "disassembler"] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python :: 2.4", - "Programming Language :: Python :: 2.5", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.0", - "Programming Language :: Python :: 3.1", - "Programming Language :: Python :: 3.2", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", -] -dynamic = ["version"] - -[project.urls] -Homepage = "https://github.com/rocky/python-uncompyle6" -Downloads = "https://github.com/rocky/python-uncompyle6/releases" - -[project.optional-dependencies] -dev = [ - "pre-commit", - "pytest", -] - -[project.scripts] -uncompyle6 = "uncompyle6.bin.uncompile:main_bin" -uncompyle6-tokenize = "uncompyle6.bin.pydisassemble:main" - -[tool.setuptools.dynamic] -version = {attr = "uncompyle6.version.__version__"} diff --git a/setup.py b/setup.py index d7afd135f..ed59410b6 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,8 @@ #!/usr/bin/env python """Setup script for the 'uncompyle6' distribution.""" +import sys + +import setuptools SYS_VERSION = sys.version_info[0:2] if not ((3, 3) <= SYS_VERSION < (3, 6)): @@ -25,6 +28,38 @@ ) print(mess) raise Exception(mess) -from setuptools import setup -setup(packages=["uncompyle6"]) +from __pkginfo__ import ( + __version__, + author, + author_email, + classifiers, + entry_points, + install_requires, + license, + long_description, + modname, + py_modules, + short_desc, + web, + zip_safe, +) + +setuptools.setup( + author=author, + author_email=author_email, + classifiers=classifiers, + description=short_desc, + entry_points=entry_points, + install_requires=install_requires, + license=license, + long_description=long_description, + long_description_content_type="text/x-rst", + name=modname, + packages=setuptools.find_packages(), + py_modules=py_modules, + test_suite="nose.collector", + url=web, + version=__version__, + zip_safe=zip_safe, +) From 2dfcc1206d796c85cf7998320f68565ac93bcda3 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 30 May 2024 04:52:30 -0400 Subject: [PATCH 414/489] Merge hell --- uncompyle6/semantics/customize36.py | 1 - uncompyle6/semantics/gencomp-for-3.0.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index c1cd03126..a879b0e76 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -26,7 +26,6 @@ TABLE_R, ) from uncompyle6.semantics.helper import escape_string, flatten_list, strip_quotes -from uncompyle6.util import get_code_name def escape_format(s): diff --git a/uncompyle6/semantics/gencomp-for-3.0.py b/uncompyle6/semantics/gencomp-for-3.0.py index 0000b7d5e..d9737ae27 100644 --- a/uncompyle6/semantics/gencomp-for-3.0.py +++ b/uncompyle6/semantics/gencomp-for-3.0.py @@ -17,8 +17,6 @@ """ -from typing import Optional - from xdis import co_flags_is_async, iscode from uncompyle6.parser import get_python_parser From dfa3a41dc981cbbcb2f3dbe16b7aa200a2afe4dc Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 30 May 2024 05:01:57 -0400 Subject: [PATCH 415/489] Merge hell --- uncompyle6/bin/uncompile.py | 2 +- uncompyle6/parsers/parse38.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index da1b1f3bf..9c255e7b8 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -240,7 +240,7 @@ def main_bin(): start_offset=0, stop_offset=-1, ) - result = [options.get("do_verify", None)] + list(result) + result = list(result) if len(pyc_paths) > 1: mess = status_msg(*result) print("# " + mess) diff --git a/uncompyle6/parsers/parse38.py b/uncompyle6/parsers/parse38.py index f0b66eb49..f55897341 100644 --- a/uncompyle6/parsers/parse38.py +++ b/uncompyle6/parsers/parse38.py @@ -416,7 +416,7 @@ def customize_grammar_rules(self, tokens, customize): [opname[: opname.rfind("_")] for opname in self.seen_ops] ) - custom_ops_processed = {"DICT_MERGE"} + custom_ops_processed = set(["DICT_MERGE"]) # Loop over instructions adding custom grammar rules based on # a specific instruction seen. From 21f785c4f47cf1e2dff65a4027775f028cdba26c Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 12 Jul 2024 08:40:49 -0400 Subject: [PATCH 416/489] Merge --- test/stdlib/2.4-exclude.sh | 1 - test/test_pyenvlib.py | 6 ------ 2 files changed, 7 deletions(-) diff --git a/test/stdlib/2.4-exclude.sh b/test/stdlib/2.4-exclude.sh index 551c2d900..3bb058ecd 100644 --- a/test/stdlib/2.4-exclude.sh +++ b/test/stdlib/2.4-exclude.sh @@ -39,7 +39,6 @@ SKIP_TESTS=( [test_winsound.py]=1 # it fails on its own [test_zlib.py]=1 # it fails on its own [test_decimal.py]=1 # fails on its own - no module named test_support ->>>>>>> python-3.0-to-3.2 [test_dis.py]=1 # We change line numbers - duh! [test_generators.py]=1 # fails on its own - no module named test_support # [test_grammar.py]=1 # fails on its own - no module tests.test_support diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index a9db8d5b4..8a7894db1 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -86,12 +86,6 @@ else: if vers == "native": short_vers = os.path.basename(sys.path[-1]) - from xdis.version_info import PYTHON_VERSION_TRIPLE, version_tuple_to_str - - if PYTHON_VERSION_TRIPLE > (3, 0): - version = version_tuple_to_str(end=2) - PYC = f"*.cpython-{version}.pyc" ->>>>>>> python-3.0-to-3.2 test_options[vers] = (sys.path[-1], PYC, short_vers) else: short_vers = vers[:3] From 12fb4c6d0476323f8a7a8e441386db25eb71757b Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 12 Jul 2024 10:18:52 -0400 Subject: [PATCH 417/489] Merge --- test/test_pyenvlib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 434cf8d63..b17977766 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -22,7 +22,6 @@ # Does not work on 2.5.9 or before # from __future__ import print_function ->>>>>>> python-3.0-to-3.2 import os import re import shutil From 3d44adde414d615a9425708125d7bafd5448158d Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 12 Jul 2024 14:39:31 -0400 Subject: [PATCH 418/489] 2.x tolerance (no set literals) --- uncompyle6/parsers/parse3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index f8673bc05..b7b3cc551 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -711,7 +711,7 @@ def customize_grammar_rules(self, tokens, customize): # Note: BUILD_TUPLE_UNPACK_WITH_CALL gets considered by # default because it starts with BUILD. So we'll set to ignore it from # the start. - custom_ops_processed = {"BUILD_TUPLE_UNPACK_WITH_CALL"} + custom_ops_processed = set(["BUILD_TUPLE_UNPACK_WITH_CALL"]) # A set of instruction operation names that exist in the token stream. # We use this customize the grammar that we create. From 7b7c662a20127571f5068001a6a1b992d26f90cd Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 07:28:22 -0400 Subject: [PATCH 419/489] Adjust for 3.3 language --- test/test_pyenvlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 59ac9cede..2fe4f0ee3 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -90,7 +90,7 @@ if PYTHON_VERSION_TRIPLE > (3, 0): version = version_tuple_to_str(end=2) - PYC = f"*.cpython-{version}.pyc" + PYC = "*.cpython-%s.pyc" % version test_options[vers] = (sys.path[-1], PYC, short_vers) else: short_vers = vers[:3] From 6b139af560d93f834b8b527a1dc7e05727eebf90 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 09:49:00 -0400 Subject: [PATCH 420/489] BUILD_MAP is different pre 3.5 --- test/test_pyenvlib.py | 2 +- uncompyle6/scanners/scanner3.py | 32 ++++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 59ac9cede..2fe4f0ee3 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -90,7 +90,7 @@ if PYTHON_VERSION_TRIPLE > (3, 0): version = version_tuple_to_str(end=2) - PYC = f"*.cpython-{version}.pyc" + PYC = "*.cpython-%s.pyc" % version test_options[vers] = (sys.path[-1], PYC, short_vers) else: short_vers = vers[:3] diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index bb201484f..51f43ac07 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -315,17 +315,25 @@ def bound_map_from_inst( if count < 5: return None - collection_start = i - (count * 2) - assert (count * 2) <= i - - for j in range(collection_start, i, 2): - if insts[j].opname not in ("LOAD_CONST",): - return None - if insts[j + 1].opname not in ("LOAD_CONST",): - return None - - collection_start = i - (2 * count) - collection_enum = CONST_COLLECTIONS.index("CONST_MAP") + if self.version >= (3, 5): + # Newer Python BUILD_MAP argument's count is a + # key and value pair so it is multiplied by two. + collection_start = i - (count * 2) + assert (count * 2) <= i + + for j in range(collection_start, i, 2): + if insts[j].opname not in ("LOAD_CONST",): + return None + if insts[j + 1].opname not in ("LOAD_CONST",): + return None + + collection_start = i - (2 * count) + collection_enum = CONST_COLLECTIONS.index("CONST_MAP") + # else: Older Python count is sum of all key and value pairs + # Each pair is added individually like: + # LOAD_CONST ("Max-Age") + # LOAD_CONST ("max-age") + # STORE_MAP # If we get here, all instructions before tokens[i] are LOAD_CONST and # we can replace add a boundary marker and change LOAD_CONST to @@ -524,7 +532,7 @@ def ingest( if try_tokens is not None: new_tokens = try_tokens continue - elif opname in ("BUILD_MAP",): + elif opname in ("BUILD_MAP",) and self.version >= (3, 5): try_tokens = self.bound_map_from_inst( self.insts, new_tokens, From 2ce546784c4f420a88b1b9b44109166d8bb90eee Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 09:51:06 -0400 Subject: [PATCH 421/489] Merge --- test/test_pyenvlib.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 7ee40a9e2..b17977766 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -87,12 +87,6 @@ else: if vers == "native": short_vers = os.path.basename(sys.path[-1]) - from xdis.version_info import PYTHON_VERSION_TRIPLE, version_tuple_to_str - - if PYTHON_VERSION_TRIPLE > (3, 0): - version = version_tuple_to_str(end=2) - PYC = "*.cpython-%s.pyc" % version ->>>>>>> python-3.0-to-3.2 test_options[vers] = (sys.path[-1], PYC, short_vers) else: short_vers = vers[:3] From 049d7c21bb5da74093cb4d80920e48ed12fb3aa8 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 15:57:24 -0400 Subject: [PATCH 422/489] Add grammar rule involving RETURN_END_IF --- uncompyle6/parsers/parse35.py | 2 ++ uncompyle6/semantics/consts.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index fd2bd5cc6..e5bc9b10d 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -111,6 +111,8 @@ def p_35on(self, args): return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM + return ::= return_expr RETURN_END_IF + jb_else ::= JUMP_BACK ELSE ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec ifelsestmtl ::= testexpr c_stmts_opt jb_else else_suitel diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 7b9cd7d1e..7ea9967bc 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -431,7 +431,7 @@ "mkfuncdeco": ("%|@%c\n%c", (0, "expr"), 1), # A custom rule in n_function def distinguishes whether to call this or # function_def_async - "mkfuncdeco0": ("%|def %c\n", (0, "mkfunc")), + "mkfuncdeco0": ("%|def %c\n", (0, ("mkfunc", "mkfunc_annotate"))), # In cases where we desire an explict new line. # After docstrings which are followed by a "def" is From ea36ff9bb13ce7041dc0c77e7155677abca6b647 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 15:57:24 -0400 Subject: [PATCH 423/489] Add grammar rule involving RETURN_END_IF --- test/simple_source/bug35/02_for_else_bug.py | 10 ++++++++++ uncompyle6/parsers/parse35.py | 2 ++ uncompyle6/semantics/consts.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/simple_source/bug35/02_for_else_bug.py diff --git a/test/simple_source/bug35/02_for_else_bug.py b/test/simple_source/bug35/02_for_else_bug.py new file mode 100644 index 000000000..c8f85ad8c --- /dev/null +++ b/test/simple_source/bug35/02_for_else_bug.py @@ -0,0 +1,10 @@ +# Adapted 3.5 from _bootstrap_external.py + + +def spec_from_file_location(loader, location): + if loader: + for _ in __file__: + if location: + break + else: + return None diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index fd2bd5cc6..e5bc9b10d 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -111,6 +111,8 @@ def p_35on(self, args): return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM + return ::= return_expr RETURN_END_IF + jb_else ::= JUMP_BACK ELSE ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec ifelsestmtl ::= testexpr c_stmts_opt jb_else else_suitel diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 7b9cd7d1e..7ea9967bc 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -431,7 +431,7 @@ "mkfuncdeco": ("%|@%c\n%c", (0, "expr"), 1), # A custom rule in n_function def distinguishes whether to call this or # function_def_async - "mkfuncdeco0": ("%|def %c\n", (0, "mkfunc")), + "mkfuncdeco0": ("%|def %c\n", (0, ("mkfunc", "mkfunc_annotate"))), # In cases where we desire an explict new line. # After docstrings which are followed by a "def" is From 9c6f2ee838d492babb54b0719506d393cd2bcd67 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 13 Jul 2024 22:29:58 -0400 Subject: [PATCH 424/489] Improve 3.4 ifelse inside a lambda --- uncompyle6/parsers/parse34.py | 4 ++++ uncompyle6/parsers/parse35.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse34.py b/uncompyle6/parsers/parse34.py index caae5e2ed..53cdd8ea8 100644 --- a/uncompyle6/parsers/parse34.py +++ b/uncompyle6/parsers/parse34.py @@ -53,6 +53,10 @@ def p_misc34(self, args): _ifstmts_jump ::= c_stmts_opt JUMP_ABSOLUTE JUMP_FORWARD COME_FROM genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK + + if_exp_lambda ::= expr jmp_false expr return_if_lambda come_froms return_stmt_lambda LAMBDA_MARKER + + return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK """ def customize_grammar_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index e5bc9b10d..929d920d5 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -108,7 +108,6 @@ def p_35on(self, args): # Python 3.5+ does jump optimization # In <.3.5 the below is a JUMP_FORWARD to a JUMP_ABSOLUTE. - return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM return ::= return_expr RETURN_END_IF From 164437016513d7f401c0eaf728ab62cf6d479bf3 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 15 Jul 2024 09:46:48 -0400 Subject: [PATCH 425/489] Handle long dict litereals in 3.4- better... We detect them in tokenization and turn this into pseudo instructions --- test/bytecode_3.3/03_map.pyc | Bin 746 -> 746 bytes test/bytecode_3.4/03_map.pyc | Bin 632 -> 632 bytes uncompyle6/scanners/scanner3.py | 169 +++++++++++++++++++++++++------ uncompyle6/scanners/scanner38.py | 2 +- uncompyle6/scanners/tok.py | 2 +- 5 files changed, 141 insertions(+), 32 deletions(-) diff --git a/test/bytecode_3.3/03_map.pyc b/test/bytecode_3.3/03_map.pyc index 9712c1eaa8444333271ba545d686fc6aa5e39583..ef181d74d0449df07af52f790cdf2bf3d8e3a53e 100644 GIT binary patch delta 17 YcmaFG`ihlf9uF^ diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 69ca691ca..f8cbf0a17 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -297,9 +297,8 @@ def bound_collection_from_inst( ) return new_tokens - def bound_map_from_inst( - self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int - ): + # FIXME: consider moving to scanner35 + def bound_map_from_inst_35(self, insts: list, next_tokens: list, t: Token, i: int): """ Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can be parsed much faster, but inserting the @@ -314,25 +313,19 @@ def bound_map_from_inst( if count < 5: return None - if self.version >= (3, 5): - # Newer Python BUILD_MAP argument's count is a - # key and value pair so it is multiplied by two. - collection_start = i - (count * 2) - assert (count * 2) <= i - - for j in range(collection_start, i, 2): - if insts[j].opname not in ("LOAD_CONST",): - return None - if insts[j + 1].opname not in ("LOAD_CONST",): - return None - - collection_start = i - (2 * count) - collection_enum = CONST_COLLECTIONS.index("CONST_MAP") - # else: Older Python count is sum of all key and value pairs - # Each pair is added individually like: - # LOAD_CONST ("Max-Age") - # LOAD_CONST ("max-age") - # STORE_MAP + # Newer Python BUILD_MAP argument's count is a + # key and value pair so it is multiplied by two. + collection_start = i - (count * 2) + assert (count * 2) <= i + + for j in range(collection_start, i, 2): + if insts[j].opname not in ("LOAD_CONST",): + return None + if insts[j + 1].opname not in ("LOAD_CONST",): + return None + + collection_start = i - (2 * count) + collection_enum = CONST_COLLECTIONS.index("CONST_MAP") # If we get here, all instructions before tokens[i] are LOAD_CONST and # we can replace add a boundary marker and change LOAD_CONST to @@ -345,7 +338,7 @@ def bound_map_from_inst( attr=collection_enum, pattr="CONST_MAP", offset="%s_0" % start_offset, - linestart=False, + linestart=insts[collection_start].starts_line, has_arg=True, has_extended_arg=False, opc=self.opc, @@ -363,6 +356,7 @@ def bound_map_from_inst( has_arg=True, has_extended_arg=False, opc=self.opc, + optype="pseudo", ) ) new_tokens.append( @@ -375,7 +369,7 @@ def bound_map_from_inst( has_arg=True, has_extended_arg=False, opc=self.opc, - optype=insts[j + 1].optype, + optype="pseudo", ) ) new_tokens.append( @@ -388,7 +382,93 @@ def bound_map_from_inst( has_arg=t.has_arg, has_extended_arg=False, opc=t.opc, - optype=t.optype, + optype="pseudo", + ) + ) + return new_tokens + + def bound_map_from_inst_pre35( + self, insts: list, next_tokens: list, t: Token, i: int + ): + """ + Try to a sequence of instruction that ends with a BUILD_MAP into + a sequence that can be parsed much faster, but inserting the + token boundary at the beginning of the sequence. + """ + count = t.attr + assert isinstance(count, int) + + # For small lists don't bother + if count < 10: + return None + + # Older Python BUILD_MAP argument's count is a + # key and value pair and STORE_MAP. So it is multiplied by three. + collection_end = i + 1 + count * 3 + + for j in range(i + 1, collection_end, 3): + if insts[j].opname not in ("LOAD_CONST",): + return None + if insts[j + 1].opname not in ("LOAD_CONST",): + return None + if insts[j + 2].opname not in ("STORE_MAP",): + return None + + collection_enum = CONST_COLLECTIONS.index("CONST_MAP") + + new_tokens = next_tokens[:i] + start_offset = insts[i].offset + new_tokens.append( + Token( + opname="COLLECTION_START", + attr=collection_enum, + pattr="CONST_MAP", + offset="%s_0" % start_offset, + linestart=insts[i].starts_line, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + optype="pseudo", + ) + ) + for j in range(i + 1, collection_end, 3): + new_tokens.append( + Token( + opname="ADD_KEY", + attr=insts[j + 1].argval, + pattr=insts[j + 1].argrepr, + offset=insts[j + 1].offset, + linestart=insts[j + 1].starts_line, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + optype="pseudo", + ) + ) + new_tokens.append( + Token( + opname="ADD_VALUE", + attr=insts[j].argval, + pattr=insts[j].argrepr, + offset=insts[j].offset, + linestart=insts[j].starts_line, + has_arg=True, + has_extended_arg=False, + opc=self.opc, + optype="pseudo", + ) + ) + new_tokens.append( + Token( + opname="BUILD_DICT_OLDER", + attr=t.attr, + pattr=t.pattr, + offset=t.offset, + linestart=t.linestart, + has_arg=t.has_arg, + has_extended_arg=False, + opc=t.opc, + optype="pseudo", ) ) return new_tokens @@ -494,8 +574,17 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): last_op_was_break = False new_tokens = [] + skip_end_offset = None for i, inst in enumerate(self.insts): + + # BUILD_MAP for < 3.5 can skip *forward* in instructions and + # replace them. So we use the below to get up to the position + # scanned and replaced forward + if skip_end_offset and inst.offset <= skip_end_offset: + continue + skip_end_offset = None + opname = inst.opname argval = inst.argval pattr = inst.argrepr @@ -529,17 +618,37 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if try_tokens is not None: new_tokens = try_tokens continue - elif opname in ("BUILD_MAP",) and self.version >= (3, 5): - try_tokens = self.bound_map_from_inst( + elif opname in ("BUILD_MAP",): + bound_map_from_insts_fn = ( + self.bound_map_from_inst_35 + if self.version >= (3, 5) + else self.bound_map_from_inst_pre35 + ) + try_tokens = bound_map_from_insts_fn( self.insts, new_tokens, - inst, t, i, ) if try_tokens is not None: - new_tokens = try_tokens - continue + if self.version < (3, 5): + assert try_tokens[-1] == "BUILD_DICT_OLDER" + prev_offset = inst.offset + for j in range(i, len(self.insts)): + if self.insts[j].opname == "STORE_NAME": + new_tokens = try_tokens + skip_end_offset = prev_offset + # Set a hacky sentinal to indicate skipping to the + # next instruction + opname = "EXTENDED_ARG" + break + prev_offset = self.insts[j].offset + pass + pass + else: + new_tokens = try_tokens + continue + pass argval = inst.argval op = inst.opcode diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index 062ab668d..55873c46d 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2022 by Rocky Bernstein +# Copyright (c) 2019-2022, 2024 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index efa93a8a8..2cb6d5878 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2021, 2023 by Rocky Bernstein +# Copyright (c) 2016-2021, 2023-2024 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock # From b7e1c51243a4907d23923d99fe029031dbe09559 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 15 Jul 2024 10:06:30 -0400 Subject: [PATCH 426/489] Merge --- uncompyle6/scanners/scanner3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index f4cd82222..e613e8756 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -299,7 +299,7 @@ def bound_collection_from_inst( def bound_map_from_inst_35( self, insts: list, next_tokens: list, t: Token, i: int - ) -> Optional[list]: + ): """ Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can be parsed much faster, but inserting the @@ -424,7 +424,7 @@ def bound_map_from_inst_pre35( opname="COLLECTION_START", attr=collection_enum, pattr="CONST_MAP", - offset=f"{start_offset}_0", + offset="%s_0" % start_offset, linestart=insts[i].starts_line, has_arg=True, has_extended_arg=False, From 1df2ebfbdfc3b0cbc15885729b08936ec4a2bf1b Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 15 Jul 2024 10:11:26 -0400 Subject: [PATCH 427/489] Merge --- uncompyle6/scanners/scanner3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 1e18b9809..db0c5f7f7 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -375,7 +375,7 @@ def bound_map_from_inst(self, insts, next_tokens, t, i): return new_tokens def bound_map_from_inst_pre35( - self, insts: list, next_tokens: list, t: Token, i: int + self, insts, next_tokens, t, i ): """ Try to a sequence of instruction that ends with a BUILD_MAP into From d26a8163c01b7bf611e06d5fbe184945cac77206 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 15 Jul 2024 10:22:42 -0400 Subject: [PATCH 428/489] Merge from 3.0 --- uncompyle6/parsers/parse16.py | 2 +- uncompyle6/parsers/parse37base.py | 2 +- uncompyle6/scanners/scanner26.py | 4 +++- uncompyle6/scanners/scanner3.py | 14 +++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/uncompyle6/parsers/parse16.py b/uncompyle6/parsers/parse16.py index d57180094..66318adf9 100644 --- a/uncompyle6/parsers/parse16.py +++ b/uncompyle6/parsers/parse16.py @@ -38,7 +38,7 @@ class Python16ParserSingle(Python16Parser, PythonParserSingle): if __name__ == '__main__': # Check grammar - p = Python15Parser() + p = Python16Parser() p.check_grammar() p.dump_grammar() diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 83b5b3b1f..02c70ed91 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -138,7 +138,7 @@ def customize_grammar_rules(self, tokens, customize): # Note: BUILD_TUPLE_UNPACK_WITH_CALL gets considered by # default because it starts with BUILD. So we'll set to ignore it from # the start. - custom_ops_processed = {"BUILD_TUPLE_UNPACK_WITH_CALL"} + custom_ops_processed = set(["BUILD_TUPLE_UNPACK_WITH_CALL"]) # A set of instruction operation names that exist in the token stream. # We use this customize the grammar that we create. diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index e911968d9..3f64acf67 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -22,6 +22,8 @@ use in deparsing. """ +from copy import copy + # bytecode verification, verify(), uses jump_ops from here from xdis import iscode from xdis.bytecode import _get_const_info @@ -350,7 +352,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if show_asm in ("both", "after"): print("\n# ---- tokenization:") # FIXME: t.format() is changing tokens! - for t in tokens.copy(): + for t in copy(tokens): print(t.format(line_prefix="")) print() return tokens, customize diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index db0c5f7f7..4914466a6 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -33,6 +33,7 @@ Finally we save token information. """ +from copy import deepcopy import xdis # Get all the opcodes into globals @@ -285,7 +286,7 @@ def bound_collection_from_inst( ) return new_tokens - def bound_map_from_inst(self, insts, next_tokens, t, i): + def bound_map_from_inst_35(self, insts, next_tokens, t, i): """ Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can be parsed much faster, but inserting the @@ -609,11 +610,10 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): continue elif opname in ("BUILD_MAP",): - bound_map_from_insts_fn = ( - self.bound_map_from_inst_35 - if self.version >= (3, 5) - else self.bound_map_from_inst_pre35 - ) + if self.version >= (3, 5): + bound_map_from_insts_fn = self.bound_map_from_inst_35 + else: + bound_map_from_insts_fn = self.bound_map_from_inst_pre35 try_tokens = bound_map_from_insts_fn( self.insts, new_tokens, @@ -898,7 +898,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if show_asm in ("both", "after"): print("\n# ---- tokenization:") # FIXME: t.format() is changing tokens! - for t in new_tokens.copy(): + for t in deepcopy(new_tokens): print(t.format(line_prefix="")) print() return new_tokens, customize From ea15d26ce0de40cdac50f84350cdcfa444d8c24e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 18 Jul 2024 10:40:06 -0400 Subject: [PATCH 429/489] Merge --- uncompyle6/semantics/fragments.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 6a687d9bf..fa3387e00 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1903,9 +1903,13 @@ def template_engine(self, entry, startnode): node[index].kind, ) else: - assert node[tup[0]] in tup[1], ( - f"at {node.kind}[{tup[0]}], expected to be in '{tup[1]}' " - f"node; got '{node[tup[0]].kind}'" + assert ( + node[tup[0]] in tup[1] + ), "at %s[%d], expected to be in '%s' node; got '%s'" % ( + node.kind, + tup[0], + tup[1], + node[tup[0].kind], ) else: From bdc026d3c1aa2e47f69702435143003225e5993e Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 18 Jul 2024 18:56:27 -0400 Subject: [PATCH 430/489] 2.4 tolerance --- uncompyle6/semantics/fragments.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 3f9be3002..658b337c5 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1922,9 +1922,12 @@ def template_engine(self, entry, startnode): node[index].kind, ) else: - assert node[tup[0]] in tup[1], ( - f"at {node.kind}[{tup[0]}], expected to be in '{tup[1]}' " - f"node; got '{node[tup[0]].kind}'" + assert ( + node[tup[0]] in tup[1], +c ), "at %s[%d], expected '%s' node; got '%s'" % ( + tup[0].kind, + tup[1], + node[tup[0]].kind, ) else: From e07597ea44a641f579be03d43dac24d08e089107 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 19 Jul 2024 14:57:37 -0400 Subject: [PATCH 431/489] Fix some syntax bugs created via merge --- uncompyle6/semantics/consts.py | 2 +- uncompyle6/semantics/fragments.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 485cfca26..cfd35a117 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -251,7 +251,7 @@ "assign": ( "%|%c = %p\n", -1, - (0, ("expr", "branch_op"), PRECEDENCE["tuple_list_starred"] + 1) + (0, ("expr", "branch_op")), PRECEDENCE["tuple_list_starred"] + 1 ), "attribute": ("%c.%[1]{pattr}", (0, "expr")), diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 72aba59d8..bdc7822f6 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1912,7 +1912,7 @@ def template_engine(self, entry, startnode): assert isinstance(tup, tuple) if len(tup) == 3: (index, nonterm_name, self.prec) = tup - if isinstance(tup[1], str): + if isinstance(nonterm_name, str): assert ( node[index] == nonterm_name ), "at %s[%d], expected '%s' node; got '%s'" % ( @@ -1923,11 +1923,13 @@ def template_engine(self, entry, startnode): ) else: assert ( - node[tup[0]] in tup[1], - ), "at %s[%d], expected '%s' node; got '%s'" % ( - tup[0].kind, - tup[1], - node[tup[0]].kind, + node[tup[index]] in nonterm_name, + "at %s[%d], expected '%s' node; got '%s'" + % ( + tup[0].kind, + tup[1], + node[tup[0]].kind, + ), ) else: From 836f3b5b78e07fb5bd5bc71ca4153b61b4e8a2b7 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 19 Jul 2024 21:34:11 -0400 Subject: [PATCH 432/489] define stmts_op for 2.6 used in a recently-added rule --- uncompyle6/parsers/parse26.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 0d53675bd..8e57c255a 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -132,6 +132,9 @@ def p_stmt26(self, args): ifelsestmtc ::= testexpr c_stmts_opt ja_cf_pop else_suitec ifelsestmt ::= testexpr stmts_opt ja_cf_pop else_suite + stmts_opt ::= stmts + stmts_opt ::= + # The last except of a "try: ... except" can do this... except_suite ::= stmts_opt COME_FROM JUMP_ABSOLUTE POP_TOP From 1d705b0451db0bfb321ddcdc95d95a073b265d6f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 21 Jul 2024 17:37:15 -0400 Subject: [PATCH 433/489] Merge --- uncompyle6/semantics/fragments.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 38ade16a8..35d43cbe1 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1903,9 +1903,13 @@ def template_engine(self, entry, startnode): node[index].kind, ) else: - assert node[tup[0]] in tup[1], ( - f"at {node.kind}[{tup[0]}], expected to be in '{tup[1]}' " - f"node; got '{node[tup[0]].kind}'" + assert ( + node[tup[0]] in tup[1] + ), "at %s[%d], expected to be in '%s' node; got '%s'" % ( + node.kind, + tup[0], + tup[1], + node[index].kind, ) else: From a35a19d230871c346bda4ef6d8f7eb53e8b78928 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 21 Jul 2024 18:57:43 -0400 Subject: [PATCH 434/489] Merge --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e41efd9cd..58222c583 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,6 @@ pytest -e . Click~=7.0 -xdis>=6.0.4 +xdis >= 6.1.0, < 6.2.0 configobj~=5.0.6 -setuptools~=71.0.3 +setuptools~=59.6.0 From 9f756f74e6ab06c42284001dcf58d2c95aec247c Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 22 Jul 2024 18:03:17 -0400 Subject: [PATCH 435/489] Administrivia --- admin-tools/setup-python-3.0.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/setup-python-3.0.sh b/admin-tools/setup-python-3.0.sh index daefa6266..38aad2694 100644 --- a/admin-tools/setup-python-3.0.sh +++ b/admin-tools/setup-python-3.0.sh @@ -16,6 +16,6 @@ cd $fulldir cd $fulldir/.. (cd $fulldir/.. && \ setup_version python-spark master && \ - checkout_version python-xdis python-3.0) + checkout_version python-xdis python-3.0-to-3.2) checkout_finish python-3.0-to-3.2 From 3491fcc7d3f8b0848d0a1713218ae6d470d052a6 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 18 Aug 2024 12:49:33 -0400 Subject: [PATCH 436/489] Administrivia --- admin-tools/setup-python-3.3.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index 4d2c27cb8..4c87695d1 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -10,6 +10,7 @@ PYTHON_VERSION=3.3.7 uncompyle6_owd=$(pwd) mydir=$(dirname $bs) +cd $mydir fulldir=$(readlink -f $mydir) . ./checkout_common.sh cd $fulldir/.. From 7d017cae084abde2e975397885fba0ea489eafc2 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 8 Oct 2024 19:23:56 -0400 Subject: [PATCH 437/489] Administrivia --- admin-tools/.gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/admin-tools/.gitignore b/admin-tools/.gitignore index 1dd743c6a..183700bc1 100644 --- a/admin-tools/.gitignore +++ b/admin-tools/.gitignore @@ -1,5 +1 @@ /.python-version -<<<<<<< HEAD -/.python-version -======= ->>>>>>> master From 7b155c4219932ef1e1ead1764bce97b3803e78d0 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 10 Oct 2024 17:21:29 -0400 Subject: [PATCH 438/489] Admninistrivia --- __init__.py | 0 setup.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 __init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/setup.py b/setup.py index 2642edf8b..4b7eb983b 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,71 @@ #!/usr/bin/env python """Setup script for the 'uncompyle6' distribution.""" -from setuptools import setup +import os.path as osp +import sys -setup(packages=["uncompyle6"]) +import setuptools + +SYS_VERSION = sys.version_info[0:2] +if not ((3, 6) <= SYS_VERSION < (3, 11)): + mess = "Python Release 3.6 .. 3.10 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." + % sys.version[0:3] + ) + if SYS_VERSION >= (3, 3): + mess += ( + "\nFor your Python, version %s, use the python-3.3-3.5 code/branch." + % sys.version[0:3] + ) + if (3, 0) >= SYS_VERSION < (3, 3): + mess += ( + "\nFor your Python, version %s, use the python-3.0-to-3.2 code/branch." + % sys.version[0:3] + ) + elif SYS_VERSION < (2, 4): + mess += ( + "\nThis package is not supported for Python version %s." % sys.version[0:3] + ) + print(mess) + raise Exception(mess) + +dirname = osp.join(".", osp.dirname(__file__)) +parent_dir = osp.join("..", osp.dirname(__file__)) +sys.path.append(parent_dir) + +from __pkginfo__ import ( + __version__, + author, + author_email, + classifiers, + entry_points, + install_requires, + license, + long_description, + modname, + py_modules, + short_desc, + web, + zip_safe, +) + +setuptools.setup( + author=author, + author_email=author_email, + classifiers=classifiers, + description=short_desc, + entry_points=entry_points, + install_requires=install_requires, + license=license, + long_description=long_description, + long_description_content_type="text/x-rst", + name=modname, + packages=setuptools.find_packages(), + py_modules=py_modules, + test_suite="nose.collector", + url=web, + version=__version__, + zip_safe=zip_safe, +) From 61d8dd3e1fdc2af8875b122e46bfcc91422dd699 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 9 Nov 2024 05:40:46 -0500 Subject: [PATCH 439/489] Address package version woes --- __pkginfo__.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 0e9eaee49..d11c0f54f 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -79,7 +79,7 @@ ] } ftp_url = None -install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.1", "xdis >= 6.1.1, < 6.2.0"] +install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, < 6.2.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/requirements.txt b/requirements.txt index 58222c583..44696be05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ pytest Click~=7.0 xdis >= 6.1.0, < 6.2.0 configobj~=5.0.6 -setuptools~=59.6.0 +setuptools From df79fc120ed82fd9f4dbb368f6e6a758366e6826 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 9 Nov 2024 06:07:58 -0500 Subject: [PATCH 440/489] Merge hell --- uncompyle6/semantics/helper.py | 3 --- uncompyle6/semantics/n_actions.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/uncompyle6/semantics/helper.py b/uncompyle6/semantics/helper.py index e945ea569..73bf7f6b8 100644 --- a/uncompyle6/semantics/helper.py +++ b/uncompyle6/semantics/helper.py @@ -181,9 +181,6 @@ def is_lambda_mode(compile_mode): def print_docstring(self, indent, docstring): - if isinstance(docstring, bytes): - docstring = docstring.decode("utf8", errors="backslashreplace") - quote = '"""' if docstring.find(quote) >= 0: if docstring.find("'''") == -1: diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 2a5298009..62da61902 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -26,7 +26,7 @@ PRECEDENCE, minint, ) -from uncompyle6.semantics.helper import find_code_node, flatten_list +from uncompyle6.semantics.helper import find_code_node, flatten_list, print_docstring from uncompyle6.util import better_repr From bca623c53c7468d8ad4bdb1fe105b8b42624e5e6 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 9 Nov 2024 06:10:10 -0500 Subject: [PATCH 441/489] Allow for newer spark-parser --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b8e8c4628..dcee5ab13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ name = "uncompyle6" description = "Python cross-version byte-code library and disassembler" dependencies = [ "click", - "spark-parser >= 1.8.9, < 1.9.1", + "spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.0, < 6.2.0", ] readme = "README.rst" From 7fd642c70e20aeee028d841d7088bc2478b89425 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 9 Nov 2024 06:28:41 -0500 Subject: [PATCH 442/489] bytes/string tolerance for 3.3 --- uncompyle6/semantics/helper.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/helper.py b/uncompyle6/semantics/helper.py index 78998bec9..0ff4b4191 100644 --- a/uncompyle6/semantics/helper.py +++ b/uncompyle6/semantics/helper.py @@ -153,7 +153,12 @@ def is_lambda_mode(compile_mode: str) -> bool: def print_docstring(self, indent, docstring): if isinstance(docstring, bytes): - docstring = docstring.decode("utf8", errors="backslashreplace") + try: + docstring_try = docstring.decode("utf8", errors="backslashreplace") + except Exception: + docstring = str(docstring) + else: + docstring = docstring_try quote = '"""' if docstring.find(quote) >= 0: From 3fc5e16c3eecfc57c08d06d59aa45ad575e6e159 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 9 Nov 2024 06:43:05 -0500 Subject: [PATCH 443/489] Merge hell --- uncompyle6/semantics/helper.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/uncompyle6/semantics/helper.py b/uncompyle6/semantics/helper.py index 12ed09eb8..73bf7f6b8 100644 --- a/uncompyle6/semantics/helper.py +++ b/uncompyle6/semantics/helper.py @@ -181,14 +181,6 @@ def is_lambda_mode(compile_mode): def print_docstring(self, indent, docstring): - if isinstance(docstring, bytes): - try: - docstring_try = docstring.decode("utf8", errors="backslashreplace") - except Exception: - docstring = str(docstring) - else: - docstring = docstring_try - quote = '"""' if docstring.find(quote) >= 0: if docstring.find("'''") == -1: From f9d32f19d445de1ec692322aa89ff55898040a0d Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 19 Nov 2024 15:27:50 -0500 Subject: [PATCH 444/489] Add BlackHat Asia 2024 and update CircleCI link --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 124b486fa..b3c8c7b11 100644 --- a/README.rst +++ b/README.rst @@ -282,6 +282,7 @@ to spend. See Also -------- +* https://rocky.github.io/blackhat-asia-2024-additional/all-notes-print.html : How to Read and Write a High-Level Bytecode Decompiler: ``uncompyle6`` ``decompyle3`` -- BlackHat 2024 Asia (`video `_. A big thanks to the Organizers and Reviewers for letting me speak. This kind of thing encourages me to work on projects like this. * https://github.com/rocky/python-decompile3 : Much smaller and more modern code, focusing on 3.7 and 3.8. Changes in that will get migrated back here. * 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. Currently unmaintained. * https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations. Currently unmaintained. @@ -306,8 +307,8 @@ See Also .. _uncompyle2: https://github.com/wibiti/uncompyle2 .. _unpyc37: https://github.com/andrew-tavera/unpyc37 .. _this: https://github.com/rocky/python-uncompyle6/wiki/Deparsing-technology-and-its-use-in-exact-location-reporting -.. |buildstatus| image:: https://travis-ci.org/rocky/python-uncompyle6.svg - :target: https://travis-ci.org/rocky/python-uncompyle6 +.. |buildstatus| image:: https://circleci.com/gh/rocky/python-uncompyle6.svg?style=svg + :target: https://app.circleci.com/pipelines/github/rocky/python-uncompyle6 .. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:uncompyle6.svg :target: https://repology.org/project/python:uncompyle6/versions .. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84 From f3dfbbb73d317511ea925824c3108cc520c817ab Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 19 Nov 2024 15:30:44 -0500 Subject: [PATCH 445/489] Merge hell --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index 53256a9d9..be66aa9a6 100644 --- a/README.rst +++ b/README.rst @@ -311,7 +311,6 @@ See Also :target: https://app.circleci.com/pipelines/github/rocky/python-uncompyle6 .. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:uncompyle6.svg :target: https://repology.org/project/python:uncompyle6/versions ->>>>>>> python-3.0-to-3.2 .. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84 .. _pydecipher: https://github.com/mitre/pydecipher .. _Deobfuscator: https://github.com/extremecoders-re/PjOrion-Deobfuscator From 4181bcbc79eaf05d56bb7d1d1f78220cee502559 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 26 Nov 2024 09:43:32 -0500 Subject: [PATCH 446/489] Correct getting code node on mkfunc --- uncompyle6/semantics/fragments.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 8bb7aad18..dead329fe 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -79,14 +79,13 @@ from uncompyle6.semantics.check_ast import checker from uncompyle6.semantics.consts import ( INDENT_PER_LEVEL, - MAP, NONE, PASS, PRECEDENCE, TABLE_DIRECT, - TABLE_R, escape, ) +from uncompyle6.semantics.helper import find_code_node from uncompyle6.semantics.pysource import ( DEFAULT_DEBUG_OPTS, TREE_DEFAULT_DEBUG, @@ -596,17 +595,7 @@ def n_alias(self, node): def n_mkfunc(self, node): start = len(self.f.getvalue()) - if self.version >= (3, 3) or node[-2] == "kwargs": - # LOAD_CONST code object .. - # LOAD_CONST 'x0' if >= 3.3 - # MAKE_FUNCTION .. - code_node = node[-3] - elif node[-2] == "expr": - code_node = node[-2][0] - else: - # LOAD_CONST code object .. - # MAKE_FUNCTION .. - code_node = node[-2] + code_node = find_code_node(node, -2) func_name = code_node.attr.co_name self.write(func_name) self.set_pos_info(code_node, start, len(self.f.getvalue())) From b71cd88b7317d4b4bea71380031e63ad9e500b9f Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 28 Nov 2024 08:01:15 -0500 Subject: [PATCH 447/489] Show return value when not None... And fixup setup.py --- setup.py | 63 +++++++++++++++++++++++++++++++- uncompyle6/semantics/pysource.py | 3 +- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 2642edf8b..88a7072de 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,65 @@ #!/usr/bin/env python """Setup script for the 'uncompyle6' distribution.""" +import sys -from setuptools import setup +import setuptools -setup(packages=["uncompyle6"]) +SYS_VERSION = sys.version_info[0:2] +if not ((3, 6) <= SYS_VERSION < (3, 11)): + mess = "Python Release 3.6 .. 3.10 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." + % sys.version[0:3] + ) + elif SYS_VERSION >= (3, 10): + mess += ( + "\nFor your Python, version %s, use the master code/branch." + % sys.version[0:3] + ) + elif (3, 0) >= SYS_VERSION < (3, 3): + mess += ( + "\nFor your Python, version %s, use the python-3.0-to-3.2 code/branch." + % sys.version[0:3] + ) + elif SYS_VERSION < (2, 4): + mess += ( + "\nThis package is not supported for Python version %s." % sys.version[0:3] + ) + print(mess) + raise Exception(mess) + +from __pkginfo__ import ( + __version__, + author, + author_email, + classifiers, + entry_points, + install_requires, + license, + long_description, + modname, + py_modules, + short_desc, + web, + zip_safe, +) + +setuptools.setup( + author=author, + author_email=author_email, + classifiers=classifiers, + description=short_desc, + entry_points=entry_points, + install_requires=install_requires, + license=license, + long_description=long_description, + long_description_content_type="text/x-rst", + name=modname, + packages=setuptools.find_packages(), + py_modules=py_modules, + test_suite="nose.collector", + url=web, + version=__version__, + zip_safe=zip_safe, +) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 78fd4e8c9..f31d5a552 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1212,6 +1212,7 @@ def build_ast( is_lambda=False, noneInNames=False, is_top_level_module=False, + compile_mode="exec" ) -> GenericASTTraversal: # FIXME: DRY with fragments.py @@ -1262,7 +1263,6 @@ def build_ast( load_const.kind == "LOAD_CONST" and load_const.linestart is None and load_const.attr is None - or is_top_level_module ): # Delete LOAD_CONST (None) RETURN_VALUE del tokens[-2:] @@ -1371,6 +1371,7 @@ def code_deparse( co, is_lambda=is_lambda_mode(compile_mode), is_top_level_module=is_top_level_module, + compile_mode=compile_mode, ) # XXX workaround for profiling From 2f1ab4f63eb76d7826e3ea3f88cc4ea086ce99ca Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Dec 2024 18:05:29 -0500 Subject: [PATCH 448/489] Merge hell --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index f31d5a552..5fb77771b 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1212,7 +1212,7 @@ def build_ast( is_lambda=False, noneInNames=False, is_top_level_module=False, - compile_mode="exec" + compile_mode="exec", ) -> GenericASTTraversal: # FIXME: DRY with fragments.py From a1f3c125ebc52024fd1dabf48bcb5f1810162f81 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 12 Dec 2024 18:20:54 -0500 Subject: [PATCH 449/489] Python 2.4 does not support compile mode --- uncompyle6/semantics/pysource.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index b198154ac..332c43ada 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1378,7 +1378,6 @@ def code_deparse( co, is_lambda=is_lambda_mode(compile_mode), is_top_level_module=is_top_level_module, - compile_mode=compile_mode, ) # XXX workaround for profiling From fb5641111be878309325c9b5a4a1c3ee3c3ef51a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 19 Dec 2024 07:14:01 -0500 Subject: [PATCH 450/489] Python 2.x compatibility --- uncompyle6/scanners/scanner2.py | 2 +- uncompyle6/semantics/customize14.py | 2 +- uncompyle6/semantics/customize26_27.py | 4 +--- uncompyle6/semantics/customize3.py | 3 +-- uncompyle6/semantics/customize35.py | 4 ++-- uncompyle6/semantics/customize36.py | 2 +- uncompyle6/semantics/customize37.py | 2 +- uncompyle6/semantics/customize38.py | 4 ++-- 8 files changed, 10 insertions(+), 13 deletions(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index a1bd9cf51..ce4ad93db 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -492,7 +492,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if show_asm in ("both", "after"): print("\n# ---- tokenization:") # FIXME: t.format() is changing tokens! - for t in new_tokens.copy(): + for t in copy(new_tokens): print(t.format(line_prefix="")) print() return new_tokens, customize diff --git a/uncompyle6/semantics/customize14.py b/uncompyle6/semantics/customize14.py index 566a6ec1f..f16609e8c 100644 --- a/uncompyle6/semantics/customize14.py +++ b/uncompyle6/semantics/customize14.py @@ -19,7 +19,7 @@ ####################### # Python 1.4- Changes # ####################### -def customize_for_version14(self, version: tuple): +def customize_for_version14(self, version): self.TABLE_DIRECT.update( { "print_expr_stmt": (("%|print %c\n", 0)), diff --git a/uncompyle6/semantics/customize26_27.py b/uncompyle6/semantics/customize26_27.py index d70e43f22..1efed7dd4 100644 --- a/uncompyle6/semantics/customize26_27.py +++ b/uncompyle6/semantics/customize26_27.py @@ -15,10 +15,8 @@ """Isolate Python 2.6 and 2.7 version-specific semantic actions here. """ -from uncompyle6.semantics.consts import TABLE_DIRECT - -def customize_for_version26_27(self, version: tuple): +def customize_for_version26_27(self, version): ######################################## # Python 2.6+ # except as diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index fd7ba9609..34eb75157 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -19,7 +19,6 @@ from xdis import iscode -from uncompyle6.semantics.consts import TABLE_DIRECT from uncompyle6.semantics.customize35 import customize_for_version35 from uncompyle6.semantics.customize36 import customize_for_version36 from uncompyle6.semantics.customize37 import customize_for_version37 @@ -28,7 +27,7 @@ from uncompyle6.semantics.make_function3 import make_function3_annotate -def customize_for_version3(self, version: tuple): +def customize_for_version3(self, version): self.TABLE_DIRECT.update( { "comp_for": (" for %c in %c", (2, "store"), (0, "expr")), diff --git a/uncompyle6/semantics/customize35.py b/uncompyle6/semantics/customize35.py index df3714154..578ed8cef 100644 --- a/uncompyle6/semantics/customize35.py +++ b/uncompyle6/semantics/customize35.py @@ -17,14 +17,14 @@ from xdis import co_flags_is_async, iscode -from uncompyle6.semantics.consts import INDENT_PER_LEVEL, PRECEDENCE, TABLE_DIRECT +from uncompyle6.semantics.consts import INDENT_PER_LEVEL, PRECEDENCE from uncompyle6.semantics.helper import flatten_list, gen_function_parens_adjust ####################### # Python 3.5+ Changes # ####################### -def customize_for_version35(self, version: tuple): +def customize_for_version35(self, version): # fmt: off self.TABLE_DIRECT.update( { diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index de47e71cb..309da9c45 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -37,7 +37,7 @@ def escape_format(s): ####################### -def customize_for_version36(self, version: tuple): +def customize_for_version36(self, version): # fmt: off PRECEDENCE["call_kw"] = 0 PRECEDENCE["call_kw36"] = 1 diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index 487012433..cf9793a2c 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -25,7 +25,7 @@ ####################### -def customize_for_version37(self, version: tuple): +def customize_for_version37(self, version): ######################## # Python 3.7+ changes ####################### diff --git a/uncompyle6/semantics/customize38.py b/uncompyle6/semantics/customize38.py index 6d164b442..dc878c57c 100644 --- a/uncompyle6/semantics/customize38.py +++ b/uncompyle6/semantics/customize38.py @@ -19,12 +19,12 @@ # Python 3.8+ changes ####################### -from uncompyle6.semantics.consts import PRECEDENCE, TABLE_DIRECT +from uncompyle6.semantics.consts import PRECEDENCE from uncompyle6.semantics.customize37 import FSTRING_CONVERSION_MAP from uncompyle6.semantics.helper import escape_string, strip_quotes -def customize_for_version38(self, version: tuple): +def customize_for_version38(self, version): # FIXME: pytest doesn't add proper keys in testing. Reinstate after we have fixed pytest. # for lhs in 'for forelsestmt forelselaststmt ' # 'forelselaststmtc tryfinally38'.split(): From 9283ba3dd58fc6caf436aeba591ed3ea743bdc3b Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 21 Dec 2024 02:30:09 -0500 Subject: [PATCH 451/489] Administrivia --- admin-tools/setup-python-2.4.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/setup-python-2.4.sh b/admin-tools/setup-python-2.4.sh index 71e4ee043..ca48c43d5 100644 --- a/admin-tools/setup-python-2.4.sh +++ b/admin-tools/setup-python-2.4.sh @@ -17,7 +17,7 @@ cd $mydir (cd $fulldir/.. && \ setup_version python-spark python-2.4 && \ - setup_version python-xdis python-2.4-to-2.7) + setup_version python-xdis python-2.4) checkout_finish python-2.4-to-2.7 From 70044d688ce728f9d38ac3ffc9a5f00a6927615c Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 11 Sep 2025 06:09:26 -0400 Subject: [PATCH 452/489] Merge stuff --- uncompyle6/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 7238c1a02..33bdc7e11 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -440,7 +440,6 @@ def main( sys.stderr.write("\n# %s" % sys.exc_info()[1]) sys.stderr.write("\n# Can't uncompile %s\n" % infile) ->>>>>>> python-3.6-to-3.10 else: if outfile: outstream.close() From a269190f966c5ed14f35337139dab5d760232bb8 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 11 Sep 2025 06:16:54 -0400 Subject: [PATCH 453/489] Merge woes --- ...continue.pyc => 05_while_if_continue.pyc-notyet} | Bin ..._if_return.pyc => 05_while_if_return.pyc-notyet} | Bin .../{06_list_ifnot.pyc => 06_list_ifnot.pyc-notyet} | Bin test/bytecode_2.7/{06_nop.pyc => 06_nop.pyc-notyet} | Bin test/bytecode_3.6/{06_nop.pyc => 06_nop.pyc-notyet} | Bin 5 files changed, 0 insertions(+), 0 deletions(-) rename test/bytecode_2.7/{05_while_if_continue.pyc => 05_while_if_continue.pyc-notyet} (100%) rename test/bytecode_2.7/{05_while_if_return.pyc => 05_while_if_return.pyc-notyet} (100%) rename test/bytecode_2.7/{06_list_ifnot.pyc => 06_list_ifnot.pyc-notyet} (100%) rename test/bytecode_2.7/{06_nop.pyc => 06_nop.pyc-notyet} (100%) rename test/bytecode_3.6/{06_nop.pyc => 06_nop.pyc-notyet} (100%) diff --git a/test/bytecode_2.7/05_while_if_continue.pyc b/test/bytecode_2.7/05_while_if_continue.pyc-notyet similarity index 100% rename from test/bytecode_2.7/05_while_if_continue.pyc rename to test/bytecode_2.7/05_while_if_continue.pyc-notyet diff --git a/test/bytecode_2.7/05_while_if_return.pyc b/test/bytecode_2.7/05_while_if_return.pyc-notyet similarity index 100% rename from test/bytecode_2.7/05_while_if_return.pyc rename to test/bytecode_2.7/05_while_if_return.pyc-notyet diff --git a/test/bytecode_2.7/06_list_ifnot.pyc b/test/bytecode_2.7/06_list_ifnot.pyc-notyet similarity index 100% rename from test/bytecode_2.7/06_list_ifnot.pyc rename to test/bytecode_2.7/06_list_ifnot.pyc-notyet diff --git a/test/bytecode_2.7/06_nop.pyc b/test/bytecode_2.7/06_nop.pyc-notyet similarity index 100% rename from test/bytecode_2.7/06_nop.pyc rename to test/bytecode_2.7/06_nop.pyc-notyet diff --git a/test/bytecode_3.6/06_nop.pyc b/test/bytecode_3.6/06_nop.pyc-notyet similarity index 100% rename from test/bytecode_3.6/06_nop.pyc rename to test/bytecode_3.6/06_nop.pyc-notyet From 5a1299f045f64d3850e840bb22ddd0a7c98a95c5 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 11 Sep 2025 06:31:14 -0400 Subject: [PATCH 454/489] Python 3.3 compatibility --- uncompyle6/main.py | 1 - uncompyle6/scanners/tok.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 33bdc7e11..4e7fb5c9b 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -431,7 +431,6 @@ def main( sys.stderr.write( "\n# Unsupported bytecode in file %s\n# %s\n" % (infile, e) ) - sys.stderr.write(f"\n# Unsupported bytecode in file {infile}\n# {e}\n") failed_files += 1 if current_outfile: outstream.close() diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 93cdfce63..38d78d0f6 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -17,7 +17,6 @@ import re import sys -from typing import Optional, Union intern = sys.intern @@ -71,7 +70,7 @@ def __init__( ): self.kind = intern(opname) self.has_arg = has_arg - self.attr: Optional[int] = attr + self.attr = attr self.pattr = pattr self.optype = optype if has_extended_arg: From 04159501a479068d8d1d6ae60d4f7b577187ff21 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 11 Sep 2025 06:40:14 -0400 Subject: [PATCH 455/489] Merge woes --- uncompyle6/main.py | 18 +++++++++--------- .../parsers/reducecheck/and_not_check.py | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index a94969265..e0a06573a 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -200,7 +200,7 @@ def write(s): pass real_out.write("\n") return deparsed - except SourceWalkerError, e: + except SourceWalkerError(e): # deparsing failed raise SourceWalkerError(str(e)) @@ -436,12 +436,12 @@ def main( pass tot_files += 1 except ( - ValueError, - SyntaxError, - ParserError, - SourceWalkerError, - ImportError, - ) + ValueError, + SyntaxError, + ParserError, + SourceWalkerError, + ImportError, + ): sys.stdout.write("\n") sys.stderr.write("# file %s\n" % (infile)) failed_files += 1 @@ -453,7 +453,7 @@ def main( sys.stdout.write("\n") sys.stderr.write("\nLast file: %s " % (infile)) raise - except RuntimeError, e: + except RuntimeError(e): sys.stdout.write("\n%s\n" % str(e)) if str(e).startswith("Unsupported Python"): sys.stdout.write("\n") @@ -498,7 +498,7 @@ def main( if not current_outfile: mess = "\n# okay decompiling" # mem_usage = __memUsage() - print mess, infile + print(mess, infile) if current_outfile: sys.stdout.write( "%s -- %s\r" diff --git a/uncompyle6/parsers/reducecheck/and_not_check.py b/uncompyle6/parsers/reducecheck/and_not_check.py index a2c7b7fde..a94c5c2ea 100644 --- a/uncompyle6/parsers/reducecheck/and_not_check.py +++ b/uncompyle6/parsers/reducecheck/and_not_check.py @@ -1,5 +1,4 @@ # Copyright (c) 2020, 2021, 2025 Rocky Bernstein ->>>>>>> python-3.0-to-3.2 def and_not_check( From ee688eba8671b254def56d200b2bb7e1bd8554ff Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 12 Sep 2025 12:01:12 -0400 Subject: [PATCH 456/489] Fix merge compatibility and reinstate 2.7 bytecode --- ...inue.pyc-notyet => 05_while_if_continue.pyc} | Bin ...return.pyc-notyet => 05_while_if_return.pyc} | Bin ..._list_ifnot.pyc-notyet => 06_list_ifnot.pyc} | Bin .../{06_nop.pyc-notyet => 06_nop.pyc} | Bin uncompyle6/main.py | 16 +++++++++------- .../parsers/reducecheck/except_handler.py | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) rename test/bytecode_2.7/{05_while_if_continue.pyc-notyet => 05_while_if_continue.pyc} (100%) rename test/bytecode_2.7/{05_while_if_return.pyc-notyet => 05_while_if_return.pyc} (100%) rename test/bytecode_2.7/{06_list_ifnot.pyc-notyet => 06_list_ifnot.pyc} (100%) rename test/bytecode_2.7/{06_nop.pyc-notyet => 06_nop.pyc} (100%) diff --git a/test/bytecode_2.7/05_while_if_continue.pyc-notyet b/test/bytecode_2.7/05_while_if_continue.pyc similarity index 100% rename from test/bytecode_2.7/05_while_if_continue.pyc-notyet rename to test/bytecode_2.7/05_while_if_continue.pyc diff --git a/test/bytecode_2.7/05_while_if_return.pyc-notyet b/test/bytecode_2.7/05_while_if_return.pyc similarity index 100% rename from test/bytecode_2.7/05_while_if_return.pyc-notyet rename to test/bytecode_2.7/05_while_if_return.pyc diff --git a/test/bytecode_2.7/06_list_ifnot.pyc-notyet b/test/bytecode_2.7/06_list_ifnot.pyc similarity index 100% rename from test/bytecode_2.7/06_list_ifnot.pyc-notyet rename to test/bytecode_2.7/06_list_ifnot.pyc diff --git a/test/bytecode_2.7/06_nop.pyc-notyet b/test/bytecode_2.7/06_nop.pyc similarity index 100% rename from test/bytecode_2.7/06_nop.pyc-notyet rename to test/bytecode_2.7/06_nop.pyc diff --git a/uncompyle6/main.py b/uncompyle6/main.py index e0a06573a..d73190c1a 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -164,7 +164,7 @@ def write(s): if isinstance(mapstream, str): mapstream = _get_outstream(mapstream) - debug_opts = {"asm": showasm, "tree": showast, "grammar": grammar} + debug_opts = {"asm": asm, "tree": showast, "grammar": grammar} deparsed = deparse_code_with_map( co=co, @@ -200,9 +200,10 @@ def write(s): pass real_out.write("\n") return deparsed - except SourceWalkerError(e): + except SourceWalkerError: + ex_value = sys.exc_info()[1] # deparsing failed - raise SourceWalkerError(str(e)) + raise SourceWalkerError(str(ex_value)) def compile_file(source_path): @@ -453,12 +454,13 @@ def main( sys.stdout.write("\n") sys.stderr.write("\nLast file: %s " % (infile)) raise - except RuntimeError(e): - sys.stdout.write("\n%s\n" % str(e)) - if str(e).startswith("Unsupported Python"): + except RuntimeError: + ex_value = sys.exc_info()[1] + sys.stdout.write("\n%s\n" % str(ex_value)) + if str(ex_value).startswith("Unsupported Python"): sys.stdout.write("\n") sys.stderr.write( - "\n# Unsupported bytecode in file %s\n# %s\n" % (infile, e) + "\n# Unsupported bytecode in file %s\n# %s\n" % (infile, ex_value) ) failed_files += 1 if current_outfile: diff --git a/uncompyle6/parsers/reducecheck/except_handler.py b/uncompyle6/parsers/reducecheck/except_handler.py index db1a59543..f6bb0a2f5 100644 --- a/uncompyle6/parsers/reducecheck/except_handler.py +++ b/uncompyle6/parsers/reducecheck/except_handler.py @@ -1,7 +1,7 @@ # Copyright (c) 2020, 2025 Rocky Bernstein -def except_handler(self, lhs, n: int, rule, ast, tokens: list, first: int, last: int): +def except_handler(self, lhs, n, rule, ast, tokens, first, last): end_token = tokens[last - 1] # print("XXX", first, last) From e9e6b3a0dcdf3e8b925fc7a040dba9f9aaf55ad1 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Sep 2025 17:45:45 -0400 Subject: [PATCH 457/489] Get ready for release 3.9.3 --- .gitignore | 2 + ChangeLog-spell-corrected.diff | 4381 ++++++++++++++++++++++++++++++++ Makefile | 1 + NEWS.md | 8 + uncompyle6/version.py | 2 +- 5 files changed, 4393 insertions(+), 1 deletion(-) create mode 100644 ChangeLog-spell-corrected.diff diff --git a/.gitignore b/.gitignore index 752d3a7e4..6a2a97741 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ /.python-version /.tox /.venv* +/ChangeLog-spell-corrected +/ChangeLog.orig /README /__pkginfo__.pyc /dist diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 000000000..b0afc14f5 --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,4381 @@ +--- ChangeLog 2025-09-28 18:50:06.933864316 -0400 ++++ ChangeLog-spell-corrected 2025-09-28 18:49:47.641822080 -0400 +@@ -87,7 +87,7 @@ + + 2024-12-12 rocky + +- * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: ++ * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-12-02 rocky +@@ -113,7 +113,7 @@ + + 2024-11-28 rocky + +- * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Don't remove LOAD_CONST RETURN_VALUE when... the LOAD_CONST has a non-None value, or the LOAD_CONST has a line + associated with it. + +@@ -148,7 +148,7 @@ + uncompyle6/semantics/customize36.py, + uncompyle6/semantics/customize37.py, + uncompyle6/semantics/customize38.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Don't update global tables... Work off of copies of them instead. Issue #503 + + 2024-11-09 rocky +@@ -195,12 +195,12 @@ + + 2024-10-04 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Track branch changes in python-spark + + 2024-09-21 rocky + +- * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: ++ * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: + Adminsitrivia + + 2024-09-21 rocky +@@ -222,13 +222,13 @@ + 2024-07-22 rocky + + * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky + + * admin-tools/checkout_common.sh, admin-tools/setup-master.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky +@@ -237,7 +237,7 @@ + + 2024-07-21 rocky + +- * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: ++ * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: + Get ready for release 3.9.2 + + 2024-07-21 rocky +@@ -274,7 +274,7 @@ + + 2024-07-15 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + Handle long dict litereals in 3.4- better... Bracket in pseudo op COLLECTION_START ... BUILD_xx + + 2024-07-14 rocky +@@ -287,7 +287,7 @@ + 2024-07-13 rocky + + * test/simple_source/bug34/03_ifelse_in_lambda.py, +- uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: + Improve 3.4 ifelse inside a lambda Fixes #426 + + 2024-07-13 rocky +@@ -339,7 +339,7 @@ + + * uncompyle6/parsers/reducecheck/tryexcept.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: + Python 2.5 try/except reduce fix Start getting aligner up to date + + 2024-07-12 rocky +@@ -361,7 +361,7 @@ + 2024-07-12 rocky + + * test/simple_source/bug25/06_if_and_bugs.py, +- uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: ++ uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: + Fix some 2.5 parsing bugs + + 2024-07-12 rocky +@@ -417,7 +417,7 @@ + + 2024-06-03 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: + Use set literals + + 2024-06-03 rocky +@@ -467,7 +467,7 @@ + 2024-03-14 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Name phases "disassembly" and "tokenization" + + 2024-03-14 rocky +@@ -478,7 +478,7 @@ + uncompyle6/parsers/reducecheck/ifstmts_jump.py, + uncompyle6/scanners/scanner37base.py, + uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/make_function2.py: Mis spelling corrections ++ uncompyle6/semantics/make_function2.py: Spelling corrections + + 2024-03-13 rocky + +@@ -561,7 +561,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37.py, uncompyle6/semantics/pysource.py, +- uncompyle6/semantics/transform.py: mark "psuedo ops" ++ uncompyle6/semantics/transform.py: mark "pseudo ops" + + 2024-02-24 rocky + +@@ -580,7 +580,7 @@ + test/stdlib/3.8-exclude.sh, test/stdlib/runtests.sh, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py, + uncompyle6/scanners/scanner37base.py, uncompyle6/scanners/tok.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: + Keep optype info in token... It is useful for ADD_VALUE + + 2024-02-24 rocky +@@ -595,12 +595,12 @@ + + 2024-02-24 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-02-24 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-02-24 rocky +@@ -671,7 +671,7 @@ + + 2024-02-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: + Bugs found in 3.0 decomplation... parsers/parse30.py; fix set comprehension grammar bug + uncompyle6/semantics/n_actions.py: evidence of the evils of + modifying node data (via node.pop) +@@ -691,7 +691,7 @@ + + * uncompyle6/bin/uncompile.py, uncompyle6/main.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: + Handle 3.3 MAKE_FUNCTION annotation args properly + + 2024-02-11 rocky +@@ -766,7 +766,7 @@ + 2024-02-03 rocky + + * .gitignore, test/test_pythonlib.py, uncompyle6/main.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + lint + + 2024-02-03 rocky +@@ -776,7 +776,7 @@ + 2024-02-03 rocky + + * uncompyle6/main.py, uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + Fix up linemap option + + 2024-01-19 R. Bernstein +@@ -848,7 +848,7 @@ + + 2023-08-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: + comprehension in lambda for 3.0 & 3.1 + + 2023-08-12 R. Bernstein +@@ -873,7 +873,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: + chained-compare1 -> chained-compare-middle + + 2023-07-07 rocky +@@ -929,7 +929,7 @@ + * admin-tools/setup-master.sh, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse33.py, uncompyle6/parsers/parse34.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: + Correct generator function parsing for 3.3..3.5 + + 2023-06-29 rocky +@@ -1051,7 +1051,7 @@ + + * uncompyle6/scanners/tok.py: self.opc.version -> + self.opc.version_tuple The next release of xdis will no longer support self.opc.version (a +- float value which doesn't work in the presense of 3.10 and above) ++ float value which doesn't work in the presence of 3.10 and above) + + 2023-01-16 rocky + +@@ -1089,7 +1089,7 @@ + 2023-01-14 rocky + + * uncompyle6/parser.py, uncompyle6/scanners/scanner3.py: 3.4-3.5 +- MAKE_CLOSURE with annotate Docs lie about annnotation args. Slight adjustment here. More is ++ MAKE_CLOSURE with annotate Docs lie about annotation args. Slight adjustment here. More is + probably needed. + + 2022-12-22 rocky +@@ -1199,7 +1199,7 @@ + 2022-11-04 rocky + + * admin-tools/{pyenv-3.1-3.2-versions => pyenv-3.0-3.2-versions}, +- admin-tools/setup-python-3.0.sh: Alow 3.0 setup ++ admin-tools/setup-python-3.0.sh: Allow 3.0 setup + + 2022-11-04 rocky + +@@ -1207,7 +1207,7 @@ + + 2022-11-04 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: + Correct 3.0 list comprehension parsing + + 2022-11-03 rocky +@@ -1311,7 +1311,7 @@ + + 2022-09-21 rocky + +- * uncompyle6/semantics/pysource.py: Hande Python 3.5 make_function() ++ * uncompyle6/semantics/pysource.py: Handle Python 3.5 make_function() + semantic action Fixes #409 + + 2022-09-20 rocky +@@ -1448,7 +1448,7 @@ + 2022-06-16 rocky + + * test/simple_source/bug38/00_while_true_pass.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Python 3.8 while and whileTrue loops + + 2022-06-08 rocky +@@ -1470,9 +1470,9 @@ + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml, admin-tools/pyenv-newest-versions, +- test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: ++ test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: + Administrivia Workflows CI: go back to released versions rather than github +- versions pyenv-newest-versions: updaed to use newest Python releases ++ versions pyenv-newest-versions: updated to use newest Python releases + pypy38.py: fix wrong package name import 3.6-exclude.sh: update and + advance + +@@ -1549,13 +1549,13 @@ + * uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/parsers/parse38.py, + uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: + Start rolling in LOAD_ARG for 3.7+ + + 2022-05-05 rocky + + * test/simple_source/bug36/03_async_from_coroutine.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Fix More 3.6 async parsing ... all from 3.6 test_coroutines.py. More bugs remain + + 2022-05-05 rocky +@@ -1639,12 +1639,12 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: + Handle long 2.x bytecode literals more efficiently + + 2022-04-27 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + Small doc corrections + + 2022-04-27 rocky +@@ -1681,7 +1681,7 @@ + 2022-04-25 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + WIP - extend fast long-literals into older Python3 + + 2022-04-25 rocky +@@ -1702,7 +1702,7 @@ + + * test/simple_source/expression/05_long_literals.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: + Bugs in long-literal handlin Move n_dict to n_actions and special case n_const_list. Generalize + build_collection out of 3.7+ and into all Pythons + +@@ -1728,7 +1728,7 @@ + + 2022-04-21 rocky + +- * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: + Add "transfrormd_by" param to SyntaxTree This aligns code more with decompyle3 + + 2022-04-20 rocky +@@ -1747,7 +1747,7 @@ + + 2022-04-17 rocky + +- * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: + Fold in some decompile changes + + 2022-04-17 rocky +@@ -1764,7 +1764,7 @@ + 2022-04-17 rocky + + * Makefile, uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Split out comprehension code.. sync with decompile a little better + + 2022-04-17 rocky +@@ -1774,7 +1774,7 @@ + + 2022-04-15 rocky + +- * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: + Correct for pypy 3.7 + + 2022-04-15 rocky +@@ -1826,7 +1826,7 @@ + 2022-04-01 rocky + + * admin-tools/pyenv-newest-versions, +- uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump lastest testing Python versions ++ uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump latest testing Python versions + + 2022-03-12 rocky + +@@ -1902,7 +1902,7 @@ + 2022-03-04 rocky + + * uncompyle6/semantics/aligner.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Some small variable-name changes + + 2022-03-03 rocky +@@ -1915,12 +1915,12 @@ + * test/simple_source/bug36/02_genexpr.py, + test/simple_source/bug36/05_36lambda.py, + uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: + MAKE_FUNCTION_8 -> MAKE_FUNCTION_CLOSURE Clarity is important. + + 2022-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Remove TABLE_R0 - it hasn't been used in a while + + 2022-01-18 rocky +@@ -2009,7 +2009,7 @@ + uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + mklambda -> lambda_body matches Python AST better Note: we can't use "lambda" since that is a reserved word + + 2021-12-23 rocky +@@ -2142,7 +2142,7 @@ + uncompyle6/scanners/tok.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function2.py, +- uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: ++ uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: + Python 3.6+ specialization + + 2021-11-03 rocky +@@ -2200,7 +2200,7 @@ + + 2021-10-26 rocky + +- * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: ++ * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: + Admnistrivia: package info + + 2021-10-26 rocky +@@ -2236,7 +2236,7 @@ + + 2021-10-23 rocky + +- * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: ++ * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: + Fragment and other bugs Part of the upgrade process + + 2021-10-23 rocky +@@ -2279,7 +2279,7 @@ + + 2021-10-21 rocky + +- * .github/workflows/ubuntu.yml: Worflows CI testing ++ * .github/workflows/ubuntu.yml: Workflows CI testing + + 2021-10-21 rocky + +@@ -2316,8 +2316,8 @@ + + 2021-10-19 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: +- Revise Python version comparisions And set scanner.show_asm for 3.6 ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: ++ Revise Python version comparisons And set scanner.show_asm for 3.6 + + 2021-10-18 rocky + +@@ -2384,7 +2384,7 @@ + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function3.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + new dis - Python compisons involving tuples + + 2021-10-12 rocky +@@ -2446,7 +2446,7 @@ + + 2020-12-31 R. Bernstein + +- * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> unnecessary ++ * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> uxonnecessary + + 2020-12-27 rocky + +@@ -2454,7 +2454,7 @@ + 3.7+ We were producing: ``` z: z: int = 5 on bytecode_3.7_run/02_var_annotate.pyc ``` because grammar went 5. sstmt ann_assign (4) transformed by n_stmts: ('%|%[2]{attr}: + %c\n', 0) 0. ann_assign_init (3): ('%|%[2]{attr}: %c = %c\n', 0, 1) The "ann_assign" added "z:". Instead we have now: ``` 5. sstmt ann_assign_init (3) transformed by n_stmts: ('%|%[2]{attr}: + %c = %c\n', 0, 1) ``` Also, in the previous statement which appears in the listing (but is +- not actually in the finaly tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion ++ not actually in the finally tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion + + 2020-12-27 R. Bernstein + +@@ -2508,13 +2508,13 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + del_stmt -> delete to match Python AST better + + 2020-09-01 rocky + + * uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precidence on ++ uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precedence on + walrus operator + + 2020-09-01 rocky +@@ -2574,7 +2574,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Use "co_consts" in docstring detection. Note: this is an upheaval because we need to pass "code" or at least + "code.co_consts" to the docstring detection routine + +@@ -2585,7 +2585,7 @@ + 2020-07-19 rocky + + * test/add-test.py, test/simple_source/bug27+/03_doc_assign.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Better doc string detection A bug in 2.7 test_descr.py revealed a problem with the way we were + detecting docstrings. __doc__ = DocDescr() was getting confused with a docstring. This program also reveals other bugs in 3.2+ but we'll deal with + that in another commit. +@@ -2638,7 +2638,7 @@ + + 2020-07-06 rocky + +- * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: ++ * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: + Update bug-fixing expectations + + 2020-07-06 rocky +@@ -2725,7 +2725,7 @@ + 2020-06-15 rocky + + * admin-tools/how-to-make-a-release.md, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Towards fixing a 3.8 try except-as bug + + 2020-06-12 rocky +@@ -2739,7 +2739,7 @@ + + 2020-06-12 rocky + +- * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: ++ * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: + Get ready for release 3.7.1 + + 2020-06-12 rocky +@@ -2885,7 +2885,7 @@ + + 2020-05-09 rocky + +- * uncompyle6/linenumbers.py: Simpify an import, blacken a file. ++ * uncompyle6/linenumbers.py: Simplify an import, blacken a file. + + 2020-05-08 rocky + +@@ -2916,7 +2916,7 @@ + + * uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Bugs in nested async for... * Generalize asyc_for rule Fix bug in picking out comprehension iterator in async for * fix bug in getting expression in such a comprehension * Add %[n]{%x} pattern to template_engine() + + 2020-04-27 rocky +@@ -2970,7 +2970,7 @@ + 2020-04-20 rocky + + * .travis.yml, __pkginfo__.py, uncompyle6/disas.py, +- uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: ++ uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: + Update to use xdis 4.4.0 ... with more correct SipHash and other needed bug fixes. + + 2020-04-18 rocky +@@ -3106,7 +3106,7 @@ + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37base.py: whileelse in 3.6 sometimes has +- come froms... also remove extra "L. " in token printing ++ come_froms... also remove extra "L. " in token printing + + 2020-04-04 rocky + +@@ -3294,7 +3294,7 @@ + + 2020-02-13 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: + transform ifelseif bugs + + 2020-02-11 rocky +@@ -3335,7 +3335,7 @@ + 2020-02-10 rocky + + * uncompyle6/semantics/transform.py: Fix bug introduced by ast +- "tranform" change ++ "transform" change + + 2020-02-10 rocky + +@@ -3370,7 +3370,7 @@ + + 2020-02-10 rocky + +- * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: + is_docsting needs to test for sstmts + + 2020-02-10 rocky +@@ -3425,7 +3425,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize35.py, + uncompyle6/semantics/customize37.py: async with rules back to 3.5 +- and ... add precidence on cascaded "await" expressions ++ and ... add precedence on cascaded "await" expressions + + 2020-02-08 rocky + +@@ -3491,7 +3491,7 @@ + + * test/stdlib/3.2-exclude.sh, test/stdlib/3.4-exclude.sh, + test/stdlib/3.5-exclude.sh, test/stdlib/3.6-exclude.sh: Go over +- 3.2-3.6 runtests.sh exludes... Reinstate a lot of tests broken since c90ff51 ++ 3.2-3.6 runtests.sh excludes... Reinstate a lot of tests broken since c90ff51 + + 2020-02-07 rocky + +@@ -3521,7 +3521,7 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize3.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: + conditional -> if_exp ... to match Python IfExp AST + + 2020-02-06 rocky +@@ -3598,7 +3598,7 @@ + + 2020-02-04 rocky + +- * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: + Adjust assert transform for new "if_and" rule + + 2020-02-04 rocky +@@ -3608,7 +3608,7 @@ + + 2020-02-02 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + __modname__ and __qualname__ detection... since grammar has simplified. May still need work for Python < 3.0 + + 2020-02-02 rocky +@@ -3798,7 +3798,7 @@ + 2020-01-29 rocky + + * test/stdlib/3.7-exclude.sh, test/stdlib/3.8-exclude.sh, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Track grammar "stmt" simplifications class ... * NAME_MODULE constant * QUAL_NAME constant + + 2020-01-28 rocky +@@ -3870,7 +3870,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/reducecheck/ifstmt.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + More 3.x "if" checking. Abbreviate stmts->sstmt + + 2020-01-26 rocky +@@ -3910,7 +3910,7 @@ + + 2020-01-25 rocky + +- * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: ++ * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: + Cut-n-paste grammar rule bug + + 2020-01-25 rocky +@@ -4045,16 +4045,16 @@ + uncompyle6/parsers/reducecheck/ifstmt.py, + uncompyle6/parsers/reducecheck/while1stmt.py, + uncompyle6/semantics/pysource.py: Largish rework: scan while1stmt +- for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we neeed to ++ for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we need to + store opc in the parse object. DRY uses of "last = min(last, len(tokens)) + + 2020-01-23 rocky + +- * test/stdlib/3.7-exclude.sh: Exclue 3.7 test_binascii.py for now ++ * test/stdlib/3.7-exclude.sh: Exclude 3.7 test_binascii.py for now + + 2020-01-23 rocky + +- * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: + Mini-sync with decompyle3: go over runtests.sh 3.8 excludes + + 2020-01-23 rocky +@@ -4222,7 +4222,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37.py: More + parser changes to reinstate what was working in 3.6.2... However, again, probably more precise since we isolate loop rules +- better However, again, this isnt' the full store. Semantics were incorrect ++ better However, again, this isn't the full store. Semantics were incorrect + in Release 3.6.2 and they still are. + + 2020-01-17 rocky +@@ -4237,7 +4237,7 @@ + 2020-01-16 rocky + + * test/simple_source/def/01_class.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + parens around consts when taking attr again + + 2020-01-16 rocky +@@ -4273,7 +4273,7 @@ + 2020-01-15 rocky + + * uncompyle6/parsers/reducecheck/ifelsestmt.py: 3.7 and 2.6 +- coexistance in handling jump targets ++ coexistence in handling jump targets + + 2020-01-15 rocky + +@@ -4349,13 +4349,13 @@ + + 2020-01-14 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: + 3.7 test_fstring now works. + + 2020-01-13 rocky + + * test/simple_source/bug36/10_fstring.py, +- test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: ++ test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: + Handle set/dictionary comprehensions in format strings + + 2020-01-13 rocky +@@ -4432,7 +4432,7 @@ + 2020-01-12 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: + Wacky string at beginning of fn which is not docstring... 3.7.6 test_fstring.py tests this. + + 2020-01-12 rocky +@@ -4833,7 +4833,7 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse2.py: Accomodate "return" in an except ++ * uncompyle6/parsers/parse2.py: Accommodate "return" in an except + handler + + 2020-01-06 rocky +@@ -4867,8 +4867,8 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: +- Python 2.4- doesn't have condition expresions ++ * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: ++ Python 2.4- doesn't have condition expressions + + 2020-01-05 rocky + +@@ -4921,7 +4921,7 @@ + 2020-01-03 rocky + + * test/stdlib/runtests.sh, uncompyle6/parser.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7+ multiple imports of dotted path + + 2020-01-03 rocky +@@ -4945,7 +4945,7 @@ + 2020-01-03 rocky + + * test/simple_source/bug30/06_listcomp.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + Fix a 3.7+ chained compare bug... others remain though. + + 2020-01-02 rocky +@@ -4998,11 +4998,11 @@ + + * uncompyle6/semantics/make_function3.py: Simplify make_function3 by + customization We now have different routines for 3.6+ (and 2.x from before). This is desirable before fixing 3.0..3.5 lambdas with default +- paramerts and * args. ++ parameters and * args. + + 2019-12-27 rocky + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: + Tidy code. * Don't use "str" as a variable name * blacken helper and alphabetically order fns * use helper function `find_code_node()` in transform `mk_func()` + + 2019-12-27 rocky +@@ -5012,7 +5012,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Was dropping docstrings! Add in decompyle make_function36 + + 2019-12-27 rocky +@@ -5118,8 +5118,8 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize35.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: +- Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precidence in ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precedence in + 3.7+ for it children + + 2019-12-18 rocky +@@ -5175,7 +5175,7 @@ + 2019-12-16 rocky + + * test/simple_source/bug37/02_async_for_generator.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: + Add 3.7 async listcomp + + 2019-12-15 rocky +@@ -5189,13 +5189,13 @@ + + 2019-12-15 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Adminsitrivia: improve setup scripts + + 2019-12-15 rocky + + * test/simple_source/def/05_class.py, test/stdlib/runtests.sh, +- uncompyle6/semantics/pysource.py: Fix Python 3.x pringing ++ uncompyle6/semantics/pysource.py: Fix Python 3.x printing + superclasses... class Description: not class Description("Description"). Introduced + in not catching LOAD_CONST->LOAD_STR change + +@@ -5268,7 +5268,7 @@ + + 2019-12-11 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: + Add 3.7+ "and" grammar rule and limit "or" more + + 2019-12-11 rocky +@@ -5290,7 +5290,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/01_if_and_if_bug.py, + test/simple_source/bug36/02_call_ex_kw.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Add another 3.8 try/finally rule and semantic action + + 2019-12-10 rocky +@@ -5341,7 +5341,7 @@ + 2019-12-09 rocky + + * setup.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: ++ uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: + Start to tolerate 3.9 (in pydisassemble) + + 2019-12-09 rocky +@@ -5371,7 +5371,7 @@ + + 2019-12-08 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: + Typos: decompyle3 -> uncompyle6 + + 2019-12-08 R. Bernstein +@@ -5380,7 +5380,7 @@ + + 2019-12-02 rocky + +- * uncompyle6/semantics/make_function.py: Accomodate for optional ++ * uncompyle6/semantics/make_function.pyff: Accommodate for optional + docstring in function kw calculation + + 2019-11-21 rocky +@@ -5434,7 +5434,7 @@ + + 2019-11-18 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Two Bugs ... 2.7: more stringent comparison and comp_if testing 2.6-2.7: fix + botched dict constant translation + +@@ -5470,7 +5470,7 @@ + + 2019-11-16 rocky + +- * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: + Administriva - bump testing versions + + 2019-11-16 rocky +@@ -5508,7 +5508,7 @@ + + 2019-11-16 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + 3.0 assert2... Not like other 3.x due to the lack of POP_JUMP_IF + + 2019-11-16 rocky +@@ -5517,7 +5517,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Add 3.0 try/except rule + + 2019-11-15 rocky +@@ -5549,7 +5549,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + 3.0.1 "ret_or", "ret_and", and "or" rules + + 2019-11-15 rocky +@@ -5568,12 +5568,12 @@ + + 2019-11-14 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Two 3.0 rules ... - ifstmtlastl - ifnotstmt30 + + 2019-11-13 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: + Bang on 3.0.1 control flow... more word is needed though + + 2019-11-12 rocky +@@ -5609,7 +5609,7 @@ + 2019-11-11 rocky + + * test/simple_source/bug30/04_and_del.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Cope more JUMP/POP_IF not being in 3.0... more is probably needed though. + + 2019-11-11 rocky +@@ -5631,8 +5631,8 @@ + 2019-11-10 rocky + + * test/simple_source/bug30/03_ifelse.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: +- More Python 3.0 custom "if" statment handling. ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ More Python 3.0 custom "if" statement handling. + + 2019-11-10 rocky + +@@ -5703,7 +5703,7 @@ + + 2019-10-29 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: + Pypy 3.6 tolerance + + 2019-10-29 rocky +@@ -5732,7 +5732,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Pypy 3.6 tolerance + + 2019-05-11 rocky +@@ -5740,7 +5740,7 @@ + * test/Makefile, test/test_pyenvlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + WIP pypy3.6 handling + + 2019-10-28 rocky +@@ -5774,14 +5774,14 @@ + + 2019-10-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Better simpler fragment fix... remove hide_internal test. We changed the default and that's what + whas causing RETURN_LAST to not get included. + + 2019-10-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fragment fixes (and workarounds) fragments.py: add more parent offsets. blacken buffer parser3.py: + additional grammar rules for fragment parser Misc small typos and corrections + +@@ -5854,7 +5854,7 @@ + + 2019-08-21 rocky + +- * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: ++ * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: + CircleCi 3rd try + + 2019-08-21 rocky +@@ -5958,7 +5958,7 @@ + + 2019-07-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + More excpet_cond futzing + + 2019-07-03 rocky +@@ -6051,7 +6051,7 @@ + + 2019-06-21 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Start to reinstate elif's + + 2019-06-21 R. Bernstein +@@ -6075,7 +6075,7 @@ + + * test/simple_source/bug35/07_build_map_unpack.py, + test/simple_source/comprehension/05_dict_comp.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 2-arg asserts in 3.6+ish Changed files have also been reformatted via the blacken formatter + + 2019-06-16 rocky +@@ -6118,18 +6118,18 @@ + + 2019-06-11 rocky + +- * pytest/test_token.py: Formatting change slighty ++ * pytest/test_token.py: Formatting change slightly + + 2019-06-11 rocky + + * pytest/test_token.py, pytest/testdata/if-2.7.right, +- pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: ++ pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: + Formatting in < 3.0 is different for name ops + + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Nicer assembly display... Fewer extraneous quotes and remove pattrs that don't mean anything. +- Base more on OP poperties like varargs and NAME_OPS ++ Base more on OP properties like varargs and NAME_OPS + + 2019-06-11 rocky + +@@ -6156,8 +6156,8 @@ + + * uncompyle6/parsers/parse36.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/pysource.py: Tweaks to x0ret's anotation type +- handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types ++ uncompyle6/semantics/pysource.py: Tweaks to x0ret's annotation type ++ handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Document what's up with annotation types + + 2019-06-09 x0ret + +@@ -6171,7 +6171,7 @@ + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Fix LOAD_STR messing up docstring +- comparision ++ comparison + + 2019-06-09 R. Bernstein + +@@ -6260,7 +6260,7 @@ + + 2019-06-08 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Another LOAD_STR/CONST isolation in < 3.0 + + 2019-06-08 rocky +@@ -6306,7 +6306,7 @@ + 2019-06-06 rocky + + * uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: + better name for call generator rule + + 2019-06-06 R. Bernstein +@@ -6332,14 +6332,14 @@ + 2019-05-28 x0ret + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + fix unicode docstring again, handling unicode string in py2, fix + docstring indentation + + 2019-05-27 rocky + + * test/simple_source/stmts/00_docstring.py: Reinstate more docstring +- tests But 3.{6,7} are stil broken ++ tests But 3.{6,7} are still broken + + 2019-05-27 rocky + +@@ -6357,13 +6357,13 @@ + + 2019-05-27 x0ret + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + towards supporting unicode: docstring + + 2019-05-24 rocky + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py: Simplfy - TODO fix unicode in ++ uncompyle6/semantics/helper.py: Simplify - TODO fix unicode in + docstrings + + 2019-05-24 rocky +@@ -6453,7 +6453,7 @@ + + 2019-05-14 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Only add forward-jumping COME_FROM in 3.6+ Is this a repeat commit? + + 2019-05-13 rocky +@@ -6512,7 +6512,7 @@ + 2019-05-10 rocky + + * uncompyle6/scanners/scanner3.py: Accept x0ret's suggestion for +- 3.6+ if detection.. in the presense of a try block. Fixes #229 ++ 3.6+ if detection.. in the presence of a try block. Fixes #229 + + 2019-05-10 rocky + +@@ -6535,7 +6535,7 @@ + + * test/simple_source/bug36/02_call_ex_kw.py, + uncompyle6/semantics/customize36.py: Fix 3.6. call_ex_kw semantic +- action Was missing positional args parameter in template. Fix submited by ++ action Was missing positional args parameter in template. Fix submitted by + @x0ret Fixes #227 + + 2019-05-08 rocky +@@ -6575,7 +6575,7 @@ + 2019-05-05 rocky + + * test/simple_source/bug26/04_ifelse_parens.py, +- uncompyle6/semantics/consts.py: IfExp precidence handling in 2.6... 2.7 still has a bug ++ uncompyle6/semantics/consts.py: IfExp precedence handling in 2.6... 2.7 still has a bug + + 2019-05-05 rocky + +@@ -6587,24 +6587,24 @@ + + * uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/pysource.py: Fix precidence between list_if and ++ uncompyle6/semantics/pysource.py: Fix precedence between list_if and + if_expr in 3.x + + 2019-05-04 rocky + + * uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/customize37.py: Ned custom 3.7+ IfExp rules ++ uncompyle6/semantics/customize37.py: Need custom 3.7+ IfExp rules + + 2019-05-04 rocky + + * test/Makefile, test/simple_source/bug37/01_and_not_else.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7: if and not else + + 2019-05-04 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + delete_subscr -> delete_subscript ... to better (but not exactly) match the Python AST + + 2019-05-04 rocky +@@ -6614,7 +6614,7 @@ + 2019-05-03 rocky + + * admin-tools/pyenv-older-versions, +- uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: + Administrivia + + 2019-05-03 rocky +@@ -6678,7 +6678,7 @@ + 2019-05-01 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Better 3.6+ format specification handling + + 2019-04-30 rocky +@@ -6690,7 +6690,7 @@ + 2019-04-30 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Hacky handling of 3.6 format string 'X'. + + 2019-04-30 rocky +@@ -6732,7 +6732,7 @@ + + * uncompyle6/semantics/customize25.py, + uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/pysource.py: Was mssing 2.5 cond3 semantic rule ++ uncompyle6/semantics/pysource.py: Was missing 2.5 cond3 semantic rule + + 2019-04-23 rocky + +@@ -6758,7 +6758,7 @@ + 2019-04-22 rocky + + * test/simple_source/bug36/08_comp_gen_for.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Add rule for 3.x comp_for + + 2019-04-19 rocky +@@ -6794,7 +6794,7 @@ + 2019-04-18 rocky + + * uncompyle6/semantics/make_function.py, +- uncompyle6/semantics/pysource.py: Hacky attemp to add more 3.x ++ uncompyle6/semantics/pysource.py: Hacky attempt to add more 3.x + annotate information in + + 2019-04-17 rocky +@@ -6815,7 +6815,7 @@ + + 2019-04-15 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Improve Python 2.7 generator handling + + 2019-04-15 rocky +@@ -6868,7 +6868,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Add 3.8 try else + + 2019-04-14 rocky +@@ -6889,7 +6889,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Start 3.8 async for/else + + 2019-04-14 rocky +@@ -6916,12 +6916,12 @@ + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust while True grammar rule + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust 3.8 while-stmt rules + + 2019-04-13 rocky +@@ -6933,7 +6933,7 @@ + + 2019-04-12 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + 3.8 try/except handling - again (and more to come) + + 2019-04-11 rocky +@@ -6974,7 +6974,7 @@ + 2019-04-10 rocky + + * Makefile, test/Makefile, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Basic 3.8+ "for" loop handling... More Makefile mangling + + 2019-04-10 rocky +@@ -6995,13 +6995,13 @@ + 2019-04-10 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + 3.8 "for" block ... pysource: Tag older semantics for blocks with "expr" and "for_block" + + 2019-04-09 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner13.py, +- uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: + Small changes - bump required xdis version + + 2019-04-05 rocky +@@ -7020,7 +7020,7 @@ + 2019-03-28 rocky + + * uncompyle6/parsers/parse38.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + [WIP] - move forward a tad on Python 3.8 + + 2019-03-28 rocky +@@ -7044,7 +7044,7 @@ + 2019-03-23 rocky + + * test/simple_source/bug36/01_if_and_if_bug.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: + Adjust 3.7 chained compare for adjusted grammar Add test for last change + + 2019-03-23 rocky +@@ -7155,7 +7155,7 @@ + + 2019-01-05 Yiming Wang + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Better assert and AssertionError determine for Python 2.7 + + 2019-01-05 rocky +@@ -7195,7 +7195,7 @@ + + 2018-12-26 rocky + +- * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: ++ * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: + Use raw string in regexp with "\d"... Bump python versions used in testing + + 2018-12-25 rocky +@@ -7205,7 +7205,7 @@ + + 2018-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6+ control flow + + 2018-12-15 rocky +@@ -7318,12 +7318,12 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/semantics/helper.py: Reinstat expr32 and expr1024 +- rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplfy via putting instructions as comments. ++ rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplify via putting instructions as comments. + + 2018-09-19 rocky + + * uncompyle6/main.py: decompile bytecode_version defaults to Python +- intepreter version Fixes #189 ++ interpreter version. Fixes #189 + + 2018-09-19 rocky + +@@ -7332,7 +7332,7 @@ + + 2018-08-12 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: + Handle Python 2.4 if true + + 2018-08-02 rocky +@@ -7342,8 +7342,8 @@ + 2018-08-02 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, +- .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: +- Guidleines for reporting bugs and openning feature requests ++ .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: ++ Guidleines for reporting bugs and opening feature requests + + 2018-07-15 rocky + +@@ -7403,12 +7403,12 @@ + + 2018-06-24 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Remove some of the 3.0 3.x instruction hackiness + + 2018-06-24 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 comprehensions are a snowflake + + 2018-06-24 rocky +@@ -7438,12 +7438,12 @@ + 2018-06-24 rocky + + * test/simple_source/bug31/06_listcomp.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Improve 3.0 list comprehensions + + 2018-06-23 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Fix Python 3.0 "and" parse rule + + 2018-06-23 rocky +@@ -7463,7 +7463,7 @@ + + * test/Makefile, test/simple_source/bug30/00_chained-compare.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse30.py: Python +- 3.0 chained comparisions ++ 3.0 chained comparisons + + 2018-06-23 rocky + +@@ -7493,7 +7493,7 @@ + + 2018-06-22 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Fix two Python 3.0 bugs... * don't add _[0] list comprehension variables * add POP_TOP in _ifstmts_jmp; c_stmst for now isn't optional + + 2018-06-19 rocky +@@ -7578,7 +7578,7 @@ + 2018-06-12 rocky + + * uncompyle6/parsers/parse30.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tollerance ++ uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tolerance + and... add some 1.4 bytecode tests + + 2018-06-12 rocky +@@ -7589,7 +7589,7 @@ + + 2018-06-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection on Python 3.0 + + 2018-06-11 rocky +@@ -7620,12 +7620,12 @@ + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + 3.0 list comprehensions + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 set comprehensions + + 2018-06-09 rocky +@@ -7666,7 +7666,7 @@ + + * test/simple_source/bug14/01_print.py, + test/stdlib/compile-file.py, test/stdlib/compile_file_1x.py, +- uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: ++ uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: + Improve Python 1.4 bytecode coverage + + 2018-06-04 rocky +@@ -7721,7 +7721,7 @@ + uncompyle6/scanner.py, uncompyle6/scanners/scanner14.py, + uncompyle6/scanners/scanner15.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: + Start Python 1.4 decompilation ... Tidy up test code for issue 162 and comments for some disassembly + massaging. + +@@ -7759,7 +7759,7 @@ + + 2018-05-08 rocky + +- * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: + Note we can't handle try/else sometimes in 2.7 + + 2018-05-08 rocky +@@ -7806,7 +7806,7 @@ + + * test/simple_source/bug26/01_ifelse_listcomp.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + 2.6, 2.7 Parse if else inside list comprehension Fixes #171 + + 2018-04-28 rocky +@@ -7829,7 +7829,7 @@ + * test/simple_source/branching/02_ifelse_lambda.py, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: + Handle if not else in lambdas... Fixes #170 + + 2018-04-23 rocky +@@ -7850,13 +7850,13 @@ + + 2018-04-21 rocky + +- * uncompyle6/parsers/parse35.py: Correct (3.7) use fof ++ * uncompyle6/parsers/parse35.py: Correct (3.7) use for + BUILD_MAP_UNPACK_WITH_CALL + + 2018-04-20 rocky + + * Makefile, uncompyle6/parsers/parse36.py, +- uncompyle6/semantics/customize3.py: Fix 3.7 aysnc def testing ++ uncompyle6/semantics/customize3.py: Fix 3.7 async def testing + + 2018-04-19 rocky + +@@ -7876,7 +7876,7 @@ + + 2018-04-18 rocky + +- * uncompyle6/parsers/parse3.py: 2.6 compatability ++ * uncompyle6/parsers/parse3.py: 2.6 compatibility + + 2018-04-18 rocky + +@@ -7892,7 +7892,7 @@ + + 2018-04-16 rocky + +- * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: ++ * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: + Administrivia + + 2018-04-16 rocky +@@ -7997,7 +7997,7 @@ + 2018-04-08 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Slightly Python 3.x handing of subclasses... which are created via a call to create a subclass. Should be more general though. + + 2018-04-08 rocky +@@ -8040,7 +8040,7 @@ + + * uncompyle6/semantics/customize3.py, + uncompyle6/semantics/pysource.py: Make sure we call 'expr' go set +- precidence right ++ precedence right + + 2018-04-06 rocky + +@@ -8088,7 +8088,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/make_function.py: 3.2-3.4 Functions +- cals/defininitions yet again And we're still not out of the woods. ++ cals/definitions yet again And we're still not out of the woods. + + 2018-04-03 rocky + +@@ -8108,7 +8108,7 @@ + * Makefile, pytest/test_fjt.py, pytest/test_function_call.py, + pytest/test_grammar.py, pytest/test_single_compile.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + DRY scanner code more... Expand 2.6 testing + + 2018-04-03 rocky +@@ -8120,7 +8120,7 @@ + + * pytest/test_fjt.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: + DRY instruction building code... There is a little more that could be done with + self.offset2inst_index + +@@ -8148,7 +8148,7 @@ + + 2018-04-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Handle 3.5+ BUILD_MAP_UNPACK used in dictionaries A number of weaknesses have been uncovered though + + 2018-04-01 rocky +@@ -8168,7 +8168,7 @@ + 2018-03-31 rocky + + * test/simple_source/bug36/10_argparse.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6 argument parsing + + 2018-03-31 rocky +@@ -8194,7 +8194,7 @@ + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Replace all_instrs with inst_matches... which works on 3.6+. Still should write a pytest for this. + + 2018-03-29 rocky +@@ -8246,7 +8246,7 @@ + 2018-03-27 rocky + + * test/grammar-cover/.gitignore, test/grammar-cover/convert.sh, +- test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: ++ test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: + grammar-cover administrivia + + 2018-03-27 rocky +@@ -8289,7 +8289,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: ++ * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: + Grammar coverage hacking + + 2018-03-26 rocky +@@ -8328,7 +8328,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: ++ * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: + Start grammar coverage testing + + 2018-03-26 rocky +@@ -8344,7 +8344,7 @@ + 2018-03-26 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Bang on 3.4 CALL_FUNCTION_VAR + + 2018-03-25 rocky +@@ -8358,7 +8358,7 @@ + 2018-03-25 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: + 3.5 *() arg without further args + + 2018-03-25 R. Bernstein +@@ -8410,7 +8410,7 @@ + 2018-03-24 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Towards handling 3.x' CALL_FUNCTION_VAR correctly + + 2018-03-24 rocky +@@ -8430,17 +8430,17 @@ + 2018-03-22 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + 3.6 try except-as bug + + 2018-03-22 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + Localize call_kw precedence to 3.6 + + 2018-03-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate some 3.x dictcomp grammar rules + + 2018-03-21 rocky +@@ -8460,7 +8460,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/02_kwargs.py, + uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: A +- couple of 3.6 bugs... remove parens around decorators by adjusting precidence Partial ++ couple of 3.6 bugs... remove parens around decorators by adjusting precedence Partial + handling of quotes within 3.6 format strings + + 2018-03-21 rocky +@@ -8616,7 +8616,7 @@ + + 2018-03-08 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Slightly better assert detection + + 2018-03-08 rocky +@@ -8728,28 +8728,28 @@ + 2018-03-06 rocky + + * uncompyle6/parsers/parse26.py: 2.6- CONTINUE/JUMP_BACK confusion +- workaroud ++ workaround + + 2018-03-05 rocky + +- * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: ++ * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: + Administrivia... - Add script to run test_pyenvlib.py on everything - Bump 3.6 version 3.6.4 + + 2018-03-05 rocky + + * test/simple_source/stmts/01_rel_import.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Small changes... pysource.py: Bug fix for relative imports. scanner2.py: Remove a debug expression + + 2018-03-05 rocky + +- * uncompyle6/parsers/parse22.py: Python 2.2 code anomoly? Python 2.2 may generate PRINT_ITEM_CONT in some places for ++ * uncompyle6/parsers/parse22.py: Python 2.2 code anomaly? Python 2.2 may generate PRINT_ITEM_CONT in some places for + PRINT_ITEM + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Need to back off set_comp change a little... There was set_comp already. So what had been setcomp_func is now + merely set_comp_func rather than set_comp. Small improvement but in + the right direction, still +@@ -8758,15 +8758,15 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + dictcomp_func -> dict_comp_func... to match AST better. Also adds a correction in last commit, +- including set_comp -> set_comp_expr where apprpriate Note: can't use dict_comp as that was already used. But ++ including set_comp -> set_comp_expr where appropriate Note: can't use dict_comp as that was already used. But + dict_comp_func is matches AST better than dictcomp_func + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + setcomp_func -> set_comp ... to match AST name more closely + + 2018-03-05 rocky +@@ -8821,7 +8821,7 @@ + + 2018-03-04 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + Prevent 3.6 call_kw deriving itself.. Was causing some calls to be parsed incorrectly + + 2018-03-04 rocky +@@ -8874,7 +8874,7 @@ + + 2018-03-01 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection for 2.7 + + 2018-03-01 rocky +@@ -8929,7 +8929,7 @@ + * pytest/test_grammar.py, pytest/testdata/if-2.7.right, + pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Fallout from more precise token attributes + + 2018-02-28 rocky +@@ -8960,7 +8960,7 @@ + + 2018-02-27 rocky + +- * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: ++ * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: + Start simplifying higher-level API + + 2018-02-27 rocky +@@ -8975,14 +8975,14 @@ + + 2018-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Revise comprehension walking in 3.x... less rigidly and with less magic and more verbiage as to what's + going on + + 2018-02-27 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6+ try/finally bugs Another day another 3.6 bug fix attempted + + 2018-02-27 rocky +@@ -9005,7 +9005,7 @@ + 2018-02-26 rocky + + * test/simple_source/bug36/05_call_star_kw.py, uncompyle6/main.py, +- uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to diretions for improvements ++ uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to directions for improvements + + 2018-02-26 rocky + +@@ -9141,7 +9141,7 @@ + + * test/simple_source/bug27+/03_not_dead_code.py, + test/stdlib/runtests.sh, uncompyle6/parsers/parse27.py: Refine 2.7 +- dead code test .. in a hacky way. Will probalby have to expand this in the future or ++ dead code test .. in a hacky way. Will probably have to expand this in the future or + better do dead code analysis + + 2018-02-18 rocky +@@ -9160,13 +9160,13 @@ + + 2018-02-17 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: +- Beter 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ Better 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too + + 2018-02-15 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Wierd comprehension bug seen via ++ uncompyle6/semantics/pysource.py: Weird comprehension bug seen via + new loctraceback + + 2018-02-15 rocky +@@ -9209,7 +9209,7 @@ + + * test/simple_source/bug35/03_double_star_unpack.py, + uncompyle6/semantics/customize.py: Start to handle 3.5+ +- BUILD_LIST_UNPACK in call .. to implement multple star arguments ++ BUILD_LIST_UNPACK in call .. to implement multiple star arguments + + 2018-02-08 rocky + +@@ -9231,7 +9231,7 @@ + + 2018-02-04 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: + Revert most of last change + + 2018-02-04 rocky +@@ -9253,7 +9253,7 @@ + + 2018-02-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + Clean up fragments code for "for"... And make a little more precise. tag "store" part of "for" in + consts. + +@@ -9365,7 +9365,7 @@ + + 2018-01-27 rocky + +- * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: ++ * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: + Get ready for release 2.15.0 + + 2018-01-27 rocky +@@ -9379,12 +9379,12 @@ + 2018-01-27 rocky + + * uncompyle6/semantics/customize.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY fragments by using OO more effectively Split grammar customization to its own file. It's quite large now. + + 2018-01-27 rocky + +- * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + More linestart hacking. Not very successful though + + 2018-01-26 rocky +@@ -9417,7 +9417,7 @@ + 2018-01-24 rocky + + * pytest/test_disasm.py, uncompyle6/disas.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: + Add deparse_code_with_fragments_and_map and simplify + + 2018-01-23 rocky +@@ -9449,7 +9449,7 @@ + 2018-01-22 rocky + + * test/simple_source/bug27+/02_ifelsetmtl.py, uncompyle6/main.py, +- uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: + JUMP_BACK and CONTINUE need to be treated more similar... fixes 148 + + 2018-01-22 rocky +@@ -9516,7 +9516,7 @@ + 2018-01-18 rocky + + * uncompyle6/__init__.py, uncompyle6/scanner.py: Handle 3.5.2..3.5.2 +- magic... And handle magic better overal by improved xdis use ++ magic... And handle magic better overall by improved xdis use + + 2018-01-13 rocky + +@@ -9668,7 +9668,7 @@ + 2018-01-08 rocky + + * pytest/test_fjt.py, test/simple_source/bug35/05_empty_ifs.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: + Fix 3.5+ bug in if's with pass bodies Fixes #104 in a somewhat hacky way. + + 2018-01-07 rocky +@@ -9707,7 +9707,7 @@ + + 2018-01-06 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Change disassembly to make offsets in COME_FROMs + + 2018-01-06 rocky +@@ -9718,7 +9718,7 @@ + + * test/stdlib/runtests.sh, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Fix bug in 2.5- try/else inside ifelsestmt + + 2017-12-15 rocky +@@ -9734,12 +9734,12 @@ + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + 3.6 FUNCTION_EX_KW fixes + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Grammar rule for 3.6 with .. return + + 2017-12-15 rocky +@@ -9796,7 +9796,7 @@ + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT return_stmt -> return to match AST + + 2017-12-14 R. Bernstein +@@ -9813,7 +9813,7 @@ + + 2017-12-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start handling 3.6 CALL_FUNCTION_KW + + 2017-12-14 rocky +@@ -9842,12 +9842,12 @@ + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Back off of previous refactor a little bit + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Simplify scanner2 so it relies less on custimize dict + + 2017-12-13 rocky +@@ -9943,7 +9943,7 @@ + 2017-12-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 CALL_FUNCTION(_VAR)_KW + + 2017-12-12 rocky +@@ -9956,7 +9956,7 @@ + + 2017-12-12 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on BUILD_MAP_UNPACK_WITH_CALL a little... more cases are needed still. And there's a bug in + BUILD_TUPLE_UNPACK_WITH_CALL now in adding the count twice. + +@@ -9984,7 +9984,7 @@ + * admin-tools/how-to-make-a-release.md, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Start to handle CALL_FUNCTION_EX more accurately + + 2017-12-10 rocky +@@ -10022,7 +10022,7 @@ + + 2017-12-07 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: + Reinstate kwargs1... was just missing the semantic action rule for it + + 2017-12-07 rocky +@@ -10038,7 +10038,7 @@ + + * pytest/test_grammar.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: + grammar isolation and reduction + + 2017-12-07 rocky +@@ -10076,7 +10076,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT break_stmt, continue_stmt -> break, continue... to match AST + + 2017-12-06 rocky +@@ -10097,7 +10097,7 @@ + + 2017-12-05 rocky + +- * test/stdlib/runtests.sh: runtest.sh: remove from exlusion stdlib ++ * test/stdlib/runtests.sh: runtest.sh: remove from exclusion stdlib + test that now work + + 2017-12-05 rocky +@@ -10151,7 +10151,7 @@ + 2017-12-04 rocky + + * test/simple_source/bug26/03_weird26.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Slightly better 3.x list comprehension handling + + 2017-12-04 rocky +@@ -10175,15 +10175,15 @@ + + 2017-12-03 rocky + +- * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: + More weirdness testing + + 2017-12-03 rocky + + * test/simple_source/bug26/{03_weird.py => 03_weird26.py}, + test/stdlib/runtests.sh, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: +- Handle a wierd 2.6 conditional false expression... from 2.6. test_grammar ++ uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: ++ Handle a weird 2.6 conditional false expression... from 2.6. test_grammar + + 2017-12-03 rocky + +@@ -10195,7 +10195,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + NT: load_attr -> attribute to match AST + + 2017-12-03 rocky +@@ -10235,7 +10235,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: + Grammar "COME_FROM"_from cleanups ... tryelse constructs in 2.x fixed up _come_from -> _come_froms + (COME_FROM*) consolidate come_froms rule into sincle parser.py + +@@ -10262,7 +10262,7 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT trystmt -> try_except to match AST + + 2017-12-02 rocky +@@ -10273,7 +10273,7 @@ + 2017-12-02 rocky + + * test/Makefile, test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Fix docstring bug.. small sync with python 2.4 branch + + 2017-12-02 rocky +@@ -10317,7 +10317,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Small grammar isolation bugs + + 2017-12-02 rocky +@@ -10328,7 +10328,7 @@ + + * test/simple_source/stmts/02_test_exec.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse35.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.7 exec stmt grammar rule isolation/reduction + + 2017-12-02 rocky +@@ -10338,7 +10338,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: + whileTrue grammar reduction + + 2017-12-02 rocky +@@ -10358,12 +10358,12 @@ + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate and reduce 3.x conditionals and lambda rules + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + opt_come_from_loop -> come_from_loops... ANd remove unused rules associated with COME_FROM_FINALLY + + 2017-12-01 rocky +@@ -10420,7 +10420,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT mapexpr -> dict to match AST + + 2017-11-30 rocky +@@ -10466,7 +10466,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT setcomp -> set_comp to match AST + + 2017-11-29 rocky +@@ -10475,7 +10475,7 @@ + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + list_compr -> list_comp to match AST... more Python 3 custom rule cleanup + + 2017-11-29 rocky +@@ -10504,7 +10504,7 @@ + 2017-11-29 rocky + + * test/simple_source/bug30/01_ops.py, +- test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: + Better grammar coverage; reduce 3.x mklambda rules + + 2017-11-29 rocky +@@ -10514,7 +10514,7 @@ + test/simple_source/stmts/01_augmented_assign.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT augassign -> aug_assign to match AST + + 2017-11-29 rocky +@@ -10579,7 +10579,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT designatore -> store to match AST + + 2017-11-29 rocky +@@ -10596,7 +10596,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT call_function -> call to match AST + + 2017-11-28 rocky +@@ -10669,7 +10669,7 @@ + + * __pkginfo__.py, + test/simple_source/bug25/01_inplace_true_divide.py, +- uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Mege hell ++ uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Merge hell + + 2017-11-27 rocky + +@@ -10705,7 +10705,7 @@ + 2017-11-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: + Grammar isolation + + 2017-11-27 rocky +@@ -10728,7 +10728,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + Grammar reduction + + 2017-11-26 rocky +@@ -10748,7 +10748,7 @@ + + 2017-11-26 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + localize Python2 ifelsetmtr, compare_chained: 2.7 + + 2017-11-26 rocky +@@ -10841,7 +10841,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/semantics/pysource.py: localize 2 and 3 argument +- BUILD_SLICE... Nontermninal name matches AST anme now. Add test. ++ BUILD_SLICE... Nontermninal name matches AST name now. Add test. + + 2017-11-25 rocky + +@@ -10924,7 +10924,7 @@ + + 2017-11-23 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: + Improve try else in 3.2... Grammar from 3.3 is relevant here + + 2017-11-23 rocky +@@ -10941,7 +10941,7 @@ + 2017-11-23 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: + grammar reduction of while loops + + 2017-11-23 rocky +@@ -10978,17 +10978,17 @@ + 2017-11-22 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Reduce +- unecessary grammar rules in 2.x ++ unnecessary grammar rules in 2.x + + 2017-11-22 rocky + + * test/simple_source/stmts/01_augmented_assign.py, +- uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Increase grammar coverage + + 2017-11-22 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia: add "git pull"s + + 2017-11-18 rocky +@@ -10999,7 +10999,7 @@ + 2017-11-18 rocky + + * pytest/test_grammar.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: + Grammar cleanup: import_as_cont -> import_as + + 2017-11-18 rocky +@@ -11013,7 +11013,7 @@ + + 2017-11-17 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: + Python 3 grammar clean up and reorganization + + 2017-11-17 rocky +@@ -11050,7 +11050,7 @@ + + 2017-11-16 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: + Isolate "assert2" rule + + 2017-11-16 rocky +@@ -11081,11 +11081,11 @@ + 2017-11-15 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: More +- 2.7/2.7- grammer separation & cleanup ++ 2.7/2.7- grammar separation & cleanup + + 2017-11-15 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Grammar cleanup: separate some 2.7 from 2.7- rules + + 2017-11-15 rocky +@@ -11127,7 +11127,7 @@ + + * test/Makefile, test/simple_source/stmts/10_del.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse26.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Profiling workarounds, more coverage ... test/Makefile: more grammar checking. Update python versions + 10_del.pyc add test of DEL_GLOBAL check_ast.py, pysource.py: Profileing workarounds + +@@ -11145,7 +11145,7 @@ + + 2017-11-13 rocky + +- * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: ++ * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: + detected old-style Python 2.4 class better + + 2017-11-13 rocky +@@ -11175,7 +11175,7 @@ + + 2017-11-09 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Fix bug in return-optimized try stmt + + 2017-11-09 rocky +@@ -11305,7 +11305,7 @@ + 2017-10-29 rocky + + * test/simple_source/bug36/10_extended_arg_loop.py, +- uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6 control flow bug... Much more is needed, but it's a start + + 2017-10-29 rocky +@@ -11316,9 +11316,9 @@ + 2017-10-29 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Python 3.6-inspired instruction size cleanup Revise and generalize for Python 3.6+ instructions vs < 3.6 +- instuctions. Used more of the generalized methods in xdis and ++ instructions. Used more of the generalized methods in xdis and + remove some (but not all) of the magic numbers. This is a lot of changes, but not all of the refactoring needed. + Much crap still remains. Also, there are still bugs in handling 3.6 + bytecodes. +@@ -11342,7 +11342,7 @@ + + * pytest/test_pysource.py, uncompyle6/parser.py, + uncompyle6/parsers/parse24.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Start allowing node names in template engine These are now used to assert we have the right node type. Simplify import_from + + 2017-10-13 rocky +@@ -11351,7 +11351,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia - generalize shell code + + 2017-10-12 rocky +@@ -11364,7 +11364,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia + + 2017-10-12 rocky +@@ -11393,7 +11393,7 @@ + * admin-tools/check-newer-versions.sh, + admin-tools/check-older-versions.sh, + admin-tools/how-to-make-a-release.txt, +- admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Adminstrivia + + 2017-10-11 rocky +@@ -11428,7 +11428,7 @@ + + * HOW-TO-REPORT-A-BUG.md, test/Makefile, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Improve parse trace. lambda fixes yet again + + 2017-10-10 rocky +@@ -11438,7 +11438,7 @@ + + 2017-10-10 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: + Misc bugs + + 2017-10-10 R. Bernstein +@@ -11461,7 +11461,7 @@ + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py, + uncompyle6/version.py: Adjust for spark-parser 2.7.0 +- incompatabilities ++ incompatibilities + + 2017-10-05 rocky + +@@ -11494,7 +11494,7 @@ + + 2017-10-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: + spark-parser induced changes... reduce rules can be called without token streams. + + 2017-09-30 rocky +@@ -11518,7 +11518,7 @@ + + 2017-09-26 rocky + +- * uncompyle6/parsers/parse3.py: Pyton 3.1 Annotation args can be ++ * uncompyle6/parsers/parse3.py: Python 3.1 Annotation args can be + unicode? + + 2017-09-25 rocky +@@ -11532,7 +11532,7 @@ + 2017-09-21 rocky + + * pytest/test_pysource.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Unit test for format-specifiers And in the process we catch some small bugs + + 2017-09-20 rocky +@@ -11554,7 +11554,7 @@ + + 2017-09-20 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + More small doc changes + + 2017-09-20 rocky +@@ -11631,7 +11631,7 @@ + + 2017-08-13 rocky + +- * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: ++ * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: + 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 + '2.7.13', accept that in looking up either a scanner or a parser. + +@@ -11657,7 +11657,7 @@ + 2017-07-17 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + xdis's "exception match" is now "exception-match" + + 2017-07-15 rocky +@@ -11682,7 +11682,7 @@ + + 2017-07-09 rocky + +- * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: ++ * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 + + 2017-07-08 rocky +@@ -11697,7 +11697,7 @@ + * 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: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/scanner36.py: + Start supporting Pypy 3.5 (5.7.1-beta) + + 2017-07-05 rocky +@@ -11714,13 +11714,13 @@ + 2017-06-28 rocky + + * uncompyle6/semantics/make_function.py: A guard against badly +- formated bytecode ++ formatted 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 ++ uncompyle6/semantics/pysource.py: 3.x function and annotation bug + fixes + + 2017-06-25 rocky +@@ -11731,7 +11731,7 @@ + + * __pkginfo__.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: + Use xdis' instruction offset calculation fns.. next_offset, op_size, has_argument + + 2017-06-19 rocky +@@ -11798,7 +11798,7 @@ + 2017-06-08 rocky + + * uncompyle6/semantics/make_function.py: Correct make_function3 for +- Pytohn 3.2 ++ Python 3.2 + + 2017-06-08 rocky + +@@ -11812,7 +11812,7 @@ + + 2017-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated + properly. Better grammar structure for Python 3.6 call_function. + +@@ -11820,7 +11820,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, + uncompyle6/scanners/scanner36.py: BUILD_{MAP,TUPLE}_UNPACK & +- CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally succesfull right now. In fact a ++ CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally successful right now. In fact a + regression on one of the test cases + + 2017-06-05 rocky +@@ -11831,7 +11831,7 @@ + + 2017-06-04 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh. + + 2017-06-03 rocky +@@ -11883,7 +11883,7 @@ + + 2017-05-23 rocky + +- * uncompyle6/semantics/pysource.py: Fix up retreiving "async" ++ * uncompyle6/semantics/pysource.py: Fix up retrieving "async" + property on 3.6 + + 2017-05-23 rocky +@@ -11910,7 +11910,7 @@ + + 2017-05-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More explicit about 3.5 UNMAP_PACK Have to reduce 3.5 bytecode testing for now, code is more solid. + + 2017-05-19 rocky +@@ -11943,7 +11943,7 @@ + + 2017-05-19 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before + needing EXTENDED_ARG has been reduced to 256, but theoretically + possible in earlier versions. +@@ -11973,7 +11973,7 @@ + + 2017-05-16 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Allow LOAD_CONST EXTENDED_ARG + + 2017-05-15 rocky +@@ -12011,7 +12011,7 @@ + 2017-05-13 rocky + + * README.rst, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 MAKE_FUNCTION a bit more parse3.py, parse36.py: adding return_closure rule tags what's going + on with this rule pysource.py: start changing semantic rules to support code changed + by new make_function semantics README.rst: typo +@@ -12054,7 +12054,7 @@ + + * pytest/test_CALL_FUNCTION_KW.sh, pytest/test_function_call.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Added support for support for Python 3.6 CALL_FUNCTION_KW + + 2017-05-08 rocky +@@ -12084,7 +12084,7 @@ + + 2017-05-07 rocky + +- * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is sematically equivalent, so it is is correct. ++ * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is semantically equivalent, so it is is correct. + + 2017-05-07 rocky + +@@ -12121,7 +12121,7 @@ + + 2017-05-05 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ + + 2017-05-05 rocky +@@ -12145,7 +12145,7 @@ + 2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + BUILD_MAP_UNPACK'ing of dictionaries in 3.5 + + 2017-05-01 rocky +@@ -12159,7 +12159,7 @@ + 2017-04-29 rocky + + * test/simple_source/bug35/01_map_unpack.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Handle BUILD_MAP_UNPACK in a build_list + + 2017-04-27 rocky +@@ -12180,14 +12180,14 @@ + + 2017-04-22 rocky + +- * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduse scope ++ * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduce scope + of LOAD_ASSERT as expr to 3.4+ + + 2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/verify.py: LOAD_ASSERT can also + be an expr This may have the undesirable property that assert statements might +- get tagged with equivalant low-level Python code that uses "raise ++ get tagged with equivalent low-level Python code that uses "raise + AssertionError", but so be it. Fixes #103 + + 2017-04-22 R. Bernstein +@@ -12200,7 +12200,7 @@ + + 2017-04-22 rocky + +- * HISTORY.md: History keeps gettting amended ++ * HISTORY.md: History keeps getting amended + + 2017-04-22 rocky + +@@ -12219,7 +12219,7 @@ + 2017-04-22 rocky + + * test/simple_source/bug33/02_pos_args.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + 3.3+ bug in handling single kwarg after * Towards fixing issue #110 + + 2017-04-20 rocky +@@ -12245,7 +12245,7 @@ + + 2017-04-17 rocky + +- * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: ++ * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: + Rename test case to something more appropriate + + 2017-04-17 rocky +@@ -12306,7 +12306,7 @@ + + 2017-04-14 rocky + +- * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: ++ * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: + Better names for a test + + 2017-04-13 rocky +@@ -12326,7 +12326,7 @@ + + 2017-04-13 rocky + +- * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous + commit. + +@@ -12349,13 +12349,13 @@ + 2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Towards fixing annotated decorator functions... and annotate functions + + 2017-04-10 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: + grammar typo check_ast: add while1else to list of looping constructs + pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is +@@ -12374,7 +12374,7 @@ + 2017-04-09 rocky + + * test/simple_source/def/10_kw+pos_args-bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Another Python 3.5 FUNCTION_VAR bug Fixes #94 + + 2017-04-09 rocky +@@ -12488,7 +12488,7 @@ + + 2017-02-28 rocky + +- * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: ++ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + Python 2.6 a == b or c == d == 3 grammar bug + + 2017-02-28 rocky +@@ -12539,7 +12539,7 @@ + + 2017-02-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + Python 3.x needs more "while 1" grammar rules + + 2017-02-20 rocky +@@ -12669,7 +12669,7 @@ + + 2017-01-15 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 3.6 BUILD_CONST_KEYMAP + + 2017-01-15 rocky +@@ -12702,7 +12702,7 @@ + 2017-01-10 rocky + + * test/simple_source/bug35/03_double_star_unpack.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Improve BUILD_xxx_UNPACK slightly + + 2017-01-09 rocky +@@ -12721,7 +12721,7 @@ + + 2017-01-08 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Python 3.0 decompile bugs + + 2017-01-08 rocky +@@ -12752,7 +12752,7 @@ + 2017-01-07 rocky + + * test/simple_source/bug35/03_async_await.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Start to add 3.5+ await and async + + 2017-01-07 rocky +@@ -12770,7 +12770,7 @@ + + 2017-01-07 rocky + +- * uncompyle6/semantics/make_function.py: Small Pyhton 3.x annotate ++ * uncompyle6/semantics/make_function.py: Small Python 3.x annotate + bug + + 2017-01-03 rocky +@@ -12789,7 +12789,7 @@ + + 2017-01-02 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Python 3.5 continue detection bug + + 2017-01-01 rocky +@@ -12799,7 +12799,7 @@ + + 2017-01-01 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Towards fixing Python 3.5 return bugs + + 2017-01-01 rocky +@@ -12826,12 +12826,12 @@ + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + dectect_structure() -> detect_control_flow() + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie + + 2016-12-29 rocky +@@ -12868,7 +12868,7 @@ + 2016-12-27 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + WIP : Add THEN to disambigute from "and" + + 2016-12-27 rocky +@@ -12882,11 +12882,11 @@ + + 2016-12-26 R. Bernstein + +- * : Merge pull request #71 from jiangpengcheng/tupple_bug tupples which contain only 1 element need a comma ++ * : Merge pull request #71 from jiangpengcheng/tupple_bug tuples which contain only 1 element need a comma + + 2016-12-26 jiangpch + +- * uncompyle6/semantics/pysource.py: tupples which contain only 1 ++ * uncompyle6/semantics/pysource.py: tuples which contain only 1 + element need a comma + + 2016-12-26 rocky +@@ -12913,7 +12913,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Lint + + 2016-12-24 rocky +@@ -12930,7 +12930,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) + + 2016-12-18 rocky +@@ -12941,7 +12941,7 @@ + + 2016-12-17 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + show-asm on python2.5 is optional make scanner2 look a little more like scanner3 + + 2016-12-16 rocky +@@ -13030,7 +13030,7 @@ + + 2016-11-28 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Shorten Python3 grammars with + and * + + 2016-11-28 rocky +@@ -13069,7 +13069,7 @@ + 2016-11-24 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + 2.7 grammar bug workaround. Fix docstring bug + + 2016-11-24 rocky +@@ -13079,7 +13079,7 @@ + + 2016-11-24 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + <2.7 "if" detection and dup Python 3 grammar rule + + 2016-11-23 rocky +@@ -13162,7 +13162,7 @@ + 2016-11-20 rocky + + * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. + When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code + +@@ -13178,7 +13178,7 @@ + 2016-11-16 rocky + + * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + More AST checking Small fixes in output format + + 2016-11-15 rocky +@@ -13198,17 +13198,17 @@ + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. + + 2016-11-13 rocky +@@ -13244,7 +13244,7 @@ + 2016-11-11 rocky + + * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Revert augassign change but.. Make note of what's going on and add grammar test for bad situations + we have in Python 2.6 (and perhaps others) + +@@ -13264,7 +13264,7 @@ + 2016-11-10 rocky + + * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn + of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were + not. +@@ -13276,7 +13276,7 @@ + 2016-11-07 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py: Possiby tidy grammar ++ uncompyle6/parsers/parse32.py: Possibly tidy grammar + + 2016-11-06 rocky + +@@ -13331,13 +13331,13 @@ + + 2016-10-30 rocky + +- * .gitignore, README.rst, test/simple_source/def/03_class_method.py: ++ * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore + + 2016-10-30 rocky + + * uncompyle6/semantics/make_function.py: More source-code line +- indention in make_function.. and remove Python 3 situations from make_function2() ++ indentation in make_function.. and remove Python 3 situations from make_function2() + + 2016-10-29 rocky + +@@ -13360,20 +13360,20 @@ + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + More complete annotate handling Still have a bit of work to do though. + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, +- uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + Expand annotate return to Python 3.4 + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, +- uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little + + 2016-10-28 rocky +@@ -13386,7 +13386,7 @@ + 2016-10-27 rocky + + * test/simple_source/bug31/{04_def_attr.py => 04_def_annotate.py}, +- uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + Clean and fix Python 3 annotate arg return + + 2016-10-26 rocky +@@ -13461,7 +13461,7 @@ + 2016-10-20 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + further work on supporting single and multiple fstring decompilation + + 2016-10-20 rocky +@@ -13472,7 +13472,7 @@ + 2016-10-19 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + urther work on fstrings for python 3.6 - there is a new opcode + build_string which is used to improve fstring performance, but broke + the fstring support in uncompyle +@@ -13508,7 +13508,7 @@ + 2016-10-13 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may neeed arbitrary come_froms for each except clause ++ uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may need arbitrary come_froms for each except clause + + 2016-10-13 rocky + +@@ -13582,7 +13582,7 @@ + 2016-10-08 rocky + + * uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse21.py, +- uncompyle6/semantics/pysource.py: Simpify python 2.1 grammar Fix bug ++ uncompyle6/semantics/pysource.py: Simplify python 2.1 grammar Fix bug + with -t ... Wasn't showing source text when -t option was given + + 2016-10-08 rocky +@@ -13660,13 +13660,13 @@ + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky +@@ -13696,7 +13696,7 @@ + 2016-09-26 rocky + + * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may + need addressing. We want to process COME_FROMs to the same offset to be in + *descending* order so we have the larger range or biggest +@@ -13746,7 +13746,7 @@ + * pytest/test_grammar.py, pytest/test_single_compile.py, + test/Makefile, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py: Add COME_FROM_LOOP Note: we have regressed in --verify and some tests, but I believe +- that's because we are producing more equivalant (if uglier) ++ that's because we are producing more equivalent (if uglier) + programs. That's a separate problem though. + + 2016-09-22 rocky +@@ -13781,7 +13781,7 @@ + + 2016-09-21 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Python 2 & 3 scanner code ever so slightly closer + + 2016-09-21 rocky +@@ -13791,7 +13791,7 @@ + 2016-09-18 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + Small changes + + 2016-09-11 rocky +@@ -13802,7 +13802,7 @@ + 2016-09-11 rocky + + * test/bytecode_3.6/fstring.py, +- test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: ++ test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + Tidy a bit + + 2016-09-09 rocky +@@ -13816,7 +13816,7 @@ + + 2016-09-09 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 + + 2016-09-09 rocky +@@ -13838,7 +13838,7 @@ + + 2016-09-08 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.0-3.2 *args processing + + 2016-09-08 rocky +@@ -13874,7 +13874,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 2.6- try/except control flow detection + + 2016-09-04 rocky +@@ -13909,7 +13909,7 @@ + + * test/simple_source/bug26/07_generator_return.py, + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: A +- couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: descriminate more on parent type ++ couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: discriminate more on parent type + + 2016-09-03 rocky + +@@ -13925,7 +13925,7 @@ + + * test/simple_source/bug26/08_triple_equals.py, + uncompyle6/scanners/scanner2.py: Python 2.2..2.6 bug in a == b == c +- == d Fix was to remove some come froms. Feels a little hacky though. ++ == d Fix was to remove some COME_FROMS. Feels a little hacky though. + + 2016-09-03 rocky + +@@ -13949,19 +13949,19 @@ + 2016-09-02 rocky + + * test/simple_source/bug26/06_return_pop.py, +- uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning + + 2016-09-02 rocky + + * test/simple_source/bug33/02_named_and_kwargs.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x named param and kwargs bug + + 2016-09-01 rocky + + * test/simple_source/bug26/04_while_and_stmt_one_line.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute + a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. + In Python 2.7+ it's a single op. +@@ -13969,7 +13969,7 @@ + 2016-09-01 rocky + + * test/simple_source/bug26/02_except_as.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Handle Python 2.6 and below "except , " + + 2016-08-31 rocky +@@ -13985,7 +13985,7 @@ + uncompyle6/scanners/scanner3.py, uncompyle6/verify.py: Bug in 3.x + detecting "if" structure and ... scanner3.py: bug in 3.x detecting "if" structure Make scanner2.py + look more like scanner3.py verify.py: add weak-verify which tests +- Pytyon syntax, but not code ++ Python syntax, but not code + + 2016-08-30 rocky + +@@ -14111,7 +14111,7 @@ + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, + uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling + + 2016-08-11 Omer Katz +@@ -14180,7 +14180,7 @@ + 2016-07-29 rocky + + * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. + + 2016-07-28 Daniel Bradburn +@@ -14279,13 +14279,13 @@ + + 2016-07-27 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + Small code clean up + + 2016-07-26 rocky + + * uncompyle6/scanners/tok.py, uncompyle6/semantics/fragments.py, +- uncompyle6/verify.py: Usuability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function ++ uncompyle6/verify.py: Usability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function + + 2016-07-26 rocky + +@@ -14307,7 +14307,7 @@ + test/simple_source/bug_pypy27/03_try_return.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules + + 2016-07-25 rocky +@@ -14369,7 +14369,7 @@ + * README.rst, test/simple_source/stmts/03_if_elif.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little + + 2016-07-25 rocky +@@ -14391,7 +14391,7 @@ + test/Makefile, test/test_pythonlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy + + 2016-07-24 Daniel Bradburn +@@ -14411,19 +14411,19 @@ + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky +@@ -14472,7 +14472,7 @@ + + 2016-07-17 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Adjust test data for changed disasm output + + 2016-07-16 rocky +@@ -14506,14 +14506,14 @@ + + 2016-07-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we + understand better what to do though, we'll go with it. + + 2016-07-14 rocky + + * test/Makefile, uncompyle6/semantics/pysource.py: 3.x __qualname__ +- = supression Class names have become more complicated so the pattern test needs ++ = suppression Class names have become more complicated so the pattern test needs + to be more complex as well. Sigh + + 2016-07-14 rocky +@@ -14576,7 +14576,7 @@ + + * test/simple_source/bug33/05_store_name.py, + test/simple_source/comprehension/05_3x_set_comphension.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 & 3.3 handle STORE_NAME better + + 2016-07-11 rocky +@@ -14631,13 +14631,13 @@ + + 2016-07-10 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Bugs caused by 3.x jump_forward misclasification + + 2016-07-10 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification + + 2016-07-09 rocky +@@ -14728,7 +14728,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Python 3 code cleanup + + 2016-07-08 rocky +@@ -14749,7 +14749,7 @@ + 2016-07-08 rocky + + * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + Python 2.4 generator expressions and gen_comp_body + + 2016-07-08 rocky +@@ -14765,7 +14765,7 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/semantics/pysource.py: Start handling Pyton 2.4 bytecodes ++ uncompyle6/semantics/pysource.py: Start handling Python 2.4 bytecodes + + 2016-07-08 rocky + +@@ -14775,12 +14775,12 @@ + 2016-07-08 rocky + + * test/simple_source/stmts/11_return_val.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.5/2.6 RETURN_VALUE bug + + 2016-07-08 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + 2.5/2.6 fn name clash fixes list conprehension problem + + 2016-07-08 rocky +@@ -14808,7 +14808,7 @@ + + 2016-07-07 rocky + +- * : Remove 2.7 asynchat verifcation for now ++ * : Remove 2.7 asynchat verification for now + + 2016-07-07 rocky + +@@ -14822,7 +14822,7 @@ + + 2016-07-07 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + <2.6 make sure jump back on loops is really "back" + + 2016-07-07 rocky +@@ -14869,7 +14869,7 @@ + + * uncompyle6/semantics/fragments.py, + uncompyle6/semantics/pysource.py: More offsets captrued Add %b +- specifer %b - associate text before specifier pysource.py: small doc ++ specifier %b - associate text before specifier pysource.py: small doc + correction + + 2016-07-03 rocky +@@ -14881,12 +14881,12 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Another 2.6 while stmt. Clean up grammar a little + + 2016-07-03 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + 2.6 improper tagging of RETURN_END_IF + + 2016-07-02 rocky +@@ -14923,7 +14923,7 @@ + 2016-06-30 rocky + + * test/simple_source/stmts/06_for_break.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else + + 2016-06-30 rocky +@@ -14940,13 +14940,13 @@ + 2016-06-30 rocky + + * test/simple_source/comprehension/05_for_for.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6.9 list comprehension + + 2016-06-30 rocky + + * test/simple_source/exception/07_try_pass.py, +- uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in tey/except blocks ++ uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in try/except blocks + + 2016-06-30 rocky + +@@ -14982,7 +14982,7 @@ + + 2016-06-28 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Weird 2.6.9 list comprehension + + 2016-06-28 rocky +@@ -14999,17 +14999,17 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Base 2.5 off of 2.6. Some other small bugs. + + 2016-06-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py: 2.6 try +- except hadnling works now ++ except handling works now + + 2016-06-27 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6 list comprehensions + + 2016-06-27 rocky +@@ -15029,8 +15029,8 @@ + + 2016-06-24 rocky + +- * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 psuedo bytecode I think +- is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better assocate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental ++ * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 pseudo bytecode I think ++ is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better associate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental + changes to get say from python 2.3 bytecode to python 2.7 are + great. Conflicts: uncompyle6/parsers/astnode.py + +@@ -15040,7 +15040,7 @@ + + 2016-06-24 rocky + +- * uncompyle6/scanners/scanner2.py: Small formating changes ... and premonition of 2.6 byteocde work ++ * uncompyle6/scanners/scanner2.py: Small formatting changes ... and premonition of 2.6 byteocde work + + 2016-06-24 rocky + +@@ -15052,7 +15052,7 @@ + * __pkginfo__.py, uncompyle6/parsers/astnode.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 psuedo bytecode. Instead ++ uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 pseudo bytecode. Instead + adjust grammar and semantic actions. Down the line we should to segregate version changes in semantic + code better. + +@@ -15094,7 +15094,7 @@ + 2016-06-22 rocky + + * test/simple_source/expression/05_yield_from.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + differing ways to do "yield from" in 3.3-3.5 + + 2016-06-22 rocky +@@ -15103,7 +15103,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option + + 2016-06-22 rocky +@@ -15113,7 +15113,7 @@ + + 2016-06-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More 3.2 LOAD_CONST removal More python3 custom grammar DRYing + + 2016-06-22 rocky +@@ -15125,7 +15125,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/simple_source/expression/10_lambda.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 MAKE_FUNCTION adjustment + + 2016-06-22 rocky +@@ -15144,18 +15144,18 @@ + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Bang on Python 3.2 decompiling. + + 2016-06-20 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + previous 2.7 class decorator bug fixed in 3.x + + 2016-06-20 rocky +@@ -15187,7 +15187,7 @@ + + * test/simple_source/def/11_mkfunc_closure.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 3.x make closure kw args handling bug + + 2016-06-20 rocky +@@ -15224,7 +15224,7 @@ + * test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 2.7 and 3.x bug in dict comprehensions + + 2016-06-19 rocky +@@ -15242,7 +15242,7 @@ + + * test/simple_source/looping/08_while_except_bug.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 except clause parsing bug + + 2016-06-19 rocky +@@ -15304,18 +15304,18 @@ + * pytest/test_deparse.py, + test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 + + 2016-06-06 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + small changes + + 2016-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + include offset for starting listcomp + + 2016-06-03 rocky +@@ -15337,7 +15337,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Limited support for Python 2.3 + + 2016-06-03 rocky +@@ -15435,7 +15435,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Bang again on Python 2.5 and 2.6 scanners + + 2016-05-29 rocky +@@ -15447,7 +15447,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. + + 2016-05-29 rocky +@@ -15464,7 +15464,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + DRY scanners more + + 2016-05-28 rocky +@@ -15479,7 +15479,7 @@ + * test/simple_source/comprehension/06_list_ifnot.py, + test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Remove dis3. Fix in 3.x list if not comprehension + + 2016-05-28 rocky +@@ -15490,7 +15490,7 @@ + 2016-05-28 rocky + + * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, +- uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + Remove dup 3.x opcodes + + 2016-05-28 rocky +@@ -15500,7 +15500,7 @@ + 2016-05-28 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, +- uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + xdis for Python 3 opcodes + + 2016-05-28 rocky +@@ -15545,7 +15545,7 @@ + test/simple_source/def/06_return_bug.py, + uncompyle6/semantics/pysource.py: final RETURN removal bug We want to remove a final return from a module, but otherwise not. + Note we'll no lonager be able to verify functools.pyc as there is +- now a return after a raise statement. That will have to be delt with ++ now a return after a raise statement. That will have to be dealt with + separately. May address Issue #17. + + 2016-05-22 rocky +@@ -15591,7 +15591,7 @@ + 2016-05-20 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to igore fragment stuff ++ uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to ignore fragment stuff + + 2016-05-19 rocky + +@@ -15602,7 +15602,7 @@ + 2016-05-18 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: ++ test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + Handle marshal frozenset + + 2016-05-18 rocky +@@ -15642,14 +15642,14 @@ + 2016-05-17 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: ++ test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + Fix marshal bug in handling complex numbers + + 2016-05-17 rocky + + * Makefile, test/simple_source/def/09_class_closure.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS + + 2016-05-16 rocky +@@ -15665,7 +15665,7 @@ + + 2016-05-16 rocky + +- * : Readd some 3.x loop tests ++ * : Re-add some 3.x loop tests + + 2016-05-16 rocky + +@@ -15719,7 +15719,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix bug in Python 3 lambda expression handling Some other small cleanup changes + + 2016-05-15 rocky +@@ -15727,7 +15727,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + pydisassemble disassemble without grammar mangling Some other small cleanups as well + + 2016-05-15 rocky +@@ -15767,7 +15767,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs + + 2016-05-15 rocky +@@ -15776,7 +15776,7 @@ + + 2016-05-14 rocky + +- * test/Makefile, uncompyle6/scanners/dis3.py: Python2 comptability ++ * test/Makefile, uncompyle6/scanners/dis3.py: Python2 compatibility + in using Python 3 disassembly Also fixes ablility to run bytecode 3.5 tests from 2.x now For Python 2 reading python3 bytstrings, we need to make sure we + confer the character to a number. + +@@ -15800,7 +15800,7 @@ + 2016-05-14 rocky + + * ChangeLog, __pkginfo__.py, uncompyle6/version.py: Fix botched +- entry point names Get ready for relase 2.3.6 ++ entry point names Get ready for release 2.3.6 + + 2016-05-14 rocky + +@@ -15839,7 +15839,7 @@ + 2016-05-12 rocky + + * uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + More small changes + + 2016-05-12 rocky +@@ -15856,7 +15856,7 @@ + + * __pkginfo__.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires + sparck 1.2.0) * some optimization in scanner3 + +@@ -15870,7 +15870,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, + uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Redo make_function for *, arg main(*, file='foo') and things like that now work + + 2016-05-11 rocky +@@ -15902,7 +15902,7 @@ + 2016-05-09 rocky + + * test/simple_source/stmts/09_whiletrue_bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 "while True" bug + + 2016-05-09 rocky +@@ -15972,7 +15972,7 @@ + + * test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/main.py, uncompyle6/parser.py: come_from_opt handles +- and/or precidence properly main.py: give a better error message when file is not found. ++ and/or precedence properly main.py: give a better error message when file is not found. + + 2016-05-08 rocky + +@@ -15996,7 +15996,7 @@ + + * HISTORY.md, test/simple_source/branching/10_if_pass.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections + + 2016-05-08 rocky +@@ -16013,7 +16013,7 @@ + + * test/simple_source/expression/05_yield_from.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. + + 2016-05-06 rocky +@@ -16042,7 +16042,7 @@ + test/simple_source/stmts/10_if_break_finally.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: More +- Python 2 and 3 deparsing bugs fixed * while + if break * try + finall /pass ++ Python 2 and 3 deparsing bugs fixed * while + if break * try + finally pass + + 2016-05-05 rocky + +@@ -16078,19 +16078,19 @@ + 2016-05-05 rocky + + * test/simple_source/def/05_abc_class.py, +- test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + Python 3.5 abc.py bug distilled + + 2016-05-05 rocky + +- * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: ++ * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + Add cross-Python-protable 3.5 dis module + + 2016-05-04 rocky + + * test/simple_source/stmts/05_with.py, + uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo + + 2016-05-03 rocky +@@ -16100,7 +16100,7 @@ + 2016-05-03 rocky + + * uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Don't repeat next_except_jump + + 2016-05-03 rocky +@@ -16150,7 +16150,7 @@ + + * ChangeLog, NEWS, __pkginfo__.py, bin/pydisassemble, + bin/uncompyle6, setup.py, uncompyle6/__init__.py, +- uncompyle6/version.py: Add -V | --version and simplfy changing it ++ uncompyle6/version.py: Add -V | --version and simplify changing it + + 2016-05-01 rocky + +@@ -16212,13 +16212,13 @@ + + 2016-04-30 rocky + +- * uncompyle6/parsers/parse3.py: Python 3.5 if statments decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 ++ * uncompyle6/parsers/parse3.py: Python 3.5 if statements decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 + + 2016-04-28 rocky + + * requirements.txt, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + spark -> spark_parser + + 2016-04-28 rocky +@@ -16366,7 +16366,7 @@ + 2016-01-02 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Make ScannerXX() initialization the same on Python 2.x and 3.x + + 2016-01-02 rocky +@@ -16460,7 +16460,7 @@ + 2015-12-31 rocky + + * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3.3 > dotted class names + + 2015-12-30 rocky +@@ -16483,7 +16483,7 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Remove accidental schmutz. Try using pattr on 3.4 to get fn names + + 2015-12-30 rocky +@@ -16523,14 +16523,14 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py: Tidy parse3 grammer a little ++ * uncompyle6/parsers/parse3.py: Tidy parse3 grammar a little + + 2015-12-30 rocky + + * test/simple_source/exception/25_try_except.py, + test/test_pythonlib.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + Towards Python3 getting try/except working more often. + + 2015-12-29 rocky +@@ -16563,7 +16563,7 @@ + + * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, + uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + scanner3: Python 2.6 compatibility: change set initializations. Get + rid of * import opcode_*: only a little of the much-needed larger + cleanup Makefile: remove 3.x bytecode checking from Python 2.x for +@@ -16582,7 +16582,7 @@ + + * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python3 marshal codes and start to handle cross-version Python + code object types, introducing scan.Code3 + +@@ -16632,7 +16632,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16648,7 +16648,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16708,9 +16708,9 @@ + test/simple_source/{simple_stmts => stmts}/15_assert.py, + test/simple_source/stmts/15_for_if.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE +- get jump offsets into jump attributes. Fix up 3.2 scanner paritally ++ get jump offsets into jump attributes. Fix up 3.2 scanner partially + and use that in 3.4 for in cross version disassembly. + + 2015-12-26 rocky +@@ -16747,7 +16747,7 @@ + 2015-12-25 rocky + + * .gitignore, ChangeLog, MANIFEST.in, NEWS, __pkginfo__.py, +- test/Makefile: Get ready for releaes 2.0.0 ++ test/Makefile: Get ready for release 2.0.0 + + 2015-12-25 rocky + +@@ -16777,7 +16777,7 @@ + + * pytest/test_load.py, test/dis-compare.py, uncompyle6/disas.py, + uncompyle6/load.py, uncompyle6/main.py, uncompyle6/verify.py: Show +- embeded timestamp of byte-decompiled file ++ embedded timestamp of byte-decompiled file + + 2015-12-23 rocky + +@@ -16792,7 +16792,7 @@ + + * test/simple_source/simple_stmts/00_import.py, + test/simple_source/simple_stmts/00_pass.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start Python3 class(superclass) handling + + 2015-12-23 rocky +@@ -16808,13 +16808,13 @@ + + 2015-12-23 rocky + +- * uncompyle6/semantics/fragments.py: Add fragmnet offsets for 'from ++ * uncompyle6/semantics/fragments.py: Add fragment offsets for 'from + x import..' + + 2015-12-22 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Propogate offsets in imports. ++ uncompyle6/semantics/pysource.py: Propagate offsets in imports. + Added a new %x format specifier. + + 2015-12-22 rocky +@@ -16826,7 +16826,7 @@ + uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Allow comments in grammar rules. Start working on Python3 class (not + finished). More test organization. + +@@ -16835,7 +16835,7 @@ + * test/simple_source/def/01_class.py, + test/simple_source/def/10_class.py, + uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/parsers/parse3.py: Remove Python2 buitin "print" from ++ uncompyle6/parsers/parse3.py: Remove Python2 builtin "print" from + Python3's grammr. Start class tests + + 2015-12-22 rocky +@@ -16843,7 +16843,7 @@ + * bin/uncompyle6, uncompyle6/main.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/spark.py, + uncompyle6/semantics/pysource.py: main.py, pysource.py DRY +- deparse_code from main. Is better on showing exception errrors such ++ deparse_code from main. Is better on showing exception errors such + as when a pyc file is not found uncompyle6: Hook in --grammar option + to showing grammar. rules. Default now does not show timestamp. + +@@ -16870,7 +16870,7 @@ + test/simple_source/slice/{01_slice.py => 02_slice.py}, + uncompyle6/main.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/spark.py, uncompyle6/semantics/pysource.py: Add +- spark option to show grammer. Revise uncompyle options. Start to ++ spark option to show grammar. Revise uncompyle options. Start to + reorganize tests more + + 2015-12-21 rocky +@@ -16908,8 +16908,8 @@ + test/simple_source/exception/01_try_except.py, + test/simple_source/misc/assign_none_str.py, + test/simple_source/{misc/assign.py => simple_stmts/00_assign.py}, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: +- Start Python3 execption handling ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ Start Python3 exception handling + + 2015-12-21 rocky + +@@ -17019,7 +17019,7 @@ + + * test/Makefile, test/simple-source/misc/assign_none.py, + test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Python 3 decompilation from Python2 + + 2015-12-20 rocky +@@ -17037,7 +17037,7 @@ + 2015-12-20 rocky + + * Makefile, README.rst, test/Makefile, test/dis-compare.py, +- uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: ++ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + Go over makefiles to make "make check" work. walker, deparser: use + zip_longest + +@@ -17048,8 +17048,8 @@ + + 2015-12-19 rocky + +- * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatiblity +- for getting precidence. n_mkfunc needs to key off of bytecode ++ * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatibility ++ for getting precedence. n_mkfunc needs to key off of bytecode + version, not running Python version. + + 2015-12-19 rocky +@@ -17107,7 +17107,7 @@ + test/simple-source/precedence/left.py, + test/simple-source/precedence/right.py, + test/simple-source/precedence/structure.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + Python 3 bytecode handles opcodes with varargs (better). Decompiling + assert works. Add more of the simple tests and their compiled + bytecode. +@@ -17135,7 +17135,7 @@ + uncompyle6/scanners/scanner34.py: marshal.py: Python2 marshal code + shouldn't try to turn a code object into a string. parse3.py: handle + both keyword and positional function calls. scanner34.py: Remove +- extra level of quoting in LOAD_CONST. Keyward handling now works ++ extra level of quoting in LOAD_CONST. Keyword handling now works + cross Python 2/3. Some other spelling and doc fixes. + + 2015-12-18 rocky +@@ -17144,12 +17144,12 @@ + uncompyle6/disas.py, uncompyle6/parser.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/walker.py: Python3 postional arguments. Clean up code ++ uncompyle6/walker.py: Python3 positional arguments. Clean up code + more along the lines of uncompyle3. + + 2015-12-18 rocky + +- * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: ++ * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + disas.py: Do better for finding/turning a .py file into a .pyc file + across supported versions of Python. Add for else list comprehension + test +@@ -17185,7 +17185,7 @@ + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/verify.py: Python 2.6 compatability via ericfrederich's ++ uncompyle6/verify.py: Python 2.6 compatibility via ericfrederich's + patch. DRY version-checking code + + 2015-12-17 rocky +@@ -17237,12 +17237,12 @@ + test/simple-source/branching/ifelse.py, + test/simple-source/looping/for.py, uncompyle6/__init__.py, + uncompyle6/disas.py, uncompyle6/parsers/spark.py: Add spark grammar +- debugging. Start to comment grammer construct covered by simple ++ debugging. Start to comment grammar construct covered by simple + tests. + + 2015-12-17 rocky + +- * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + Python 3.4 correct grammar for some looping constructs + + 2015-12-17 rocky +@@ -17275,14 +17275,14 @@ + 2015-12-16 rocky + + * uncompyle6/deparser.py, uncompyle6/disas.py, +- uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: ++ uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + Add LICENSE. Add demo programs and DRY code a little + + 2015-12-16 rocky + + * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + On Python3.4 decompiling Python 3.4 instructions, use its built-in + disassembler routines. In contrast to what was here, they most + likely work! +@@ -17305,7 +17305,7 @@ + test/source_3.4/branching/ifelse.py, uncompyle6/.gitignore, + uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Start 3.4 more stringent disassembly testing. Disassembly format has + changed slightly. misc small bugs. + +@@ -17338,7 +17338,7 @@ + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Split out marhsal and disassemble code and spell disassemble + correctly. Fix some lint issues + +@@ -17423,7 +17423,7 @@ + + 2015-12-14 rocky + +- * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: ++ * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: + uncompyle6/dparser -> uncompyle6/parser + + 2015-12-14 rocky +@@ -17529,7 +17529,7 @@ + test/ok_2.7/asynchat.pyc_dis, test/ok_2.7/asyncore.pyc_dis, + test/ok_2.7/atexit.pyc_dis, test/ok_2.7/audiodev.pyc_dis, + test/test_pythonlib.py, uncompyle6/walker.py: test_pythonlib: Fix +- bug in traversing directores walker.py: imports; Add test Python2.5 ++ bug in traversing directories walker.py: imports; Add test Python2.5 + bytecode - it works! Makefile: remove temporary directories and _dis + files which were added by mistake + +@@ -17601,7 +17601,7 @@ + * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, + uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, +- uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + Correct MANIFEST->MANIFEST.in more lint + + 2015-12-13 R. Bernstein +@@ -17618,7 +17618,7 @@ + uncompyle6/__init__.py, uncompyle6/disas.py, + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/scanner25.py, uncompyle6/scanner26.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our + own disassembler. Python's will do fine + +@@ -17704,7 +17704,7 @@ + + * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, + uncompyle6/scanner25.py, uncompyle6/scanner27.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + Minimal disassemble, ast compile and deparse work on Python 3. Some + linting + +@@ -17719,7 +17719,7 @@ + uncompyle6/scanner.py, uncompyle6/scanner25.py, + uncompyle6/scanner26.py, uncompyle6/scanner27.py, + uncompyle6/verify.py, uncompyle6/walker.py: More Python3 +- compatability. Remove duplicate disassembly code and get it from ++ compatibility. Remove duplicate disassembly code and get it from + Python's standard library instead. + + 2015-12-12 rocky +@@ -17729,7 +17729,7 @@ + + 2015-12-11 rocky + +- * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: ++ * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + python3 compatibiity and remove some flake8 warnings. + + 2015-12-11 rocky +@@ -17804,7 +17804,7 @@ + 2013-07-16 root + + * uncompyle2/__init__.py, uncompyle2/disas.py, +- uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: ++ uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + marshal disassembly improvement + + 2013-06-20 Mysterie +@@ -17992,4 +17992,3 @@ + 2012-06-05 Mysterie + + * first commit +- diff --git a/Makefile b/Makefile index bd5703341..b409121a1 100644 --- a/Makefile +++ b/Makefile @@ -131,5 +131,6 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff .PHONY: $(PHONY) diff --git a/NEWS.md b/NEWS.md index 6a7c23004..b3f1e67bd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +3.9.3: 2025-09-28 +================= + +- Python 3.9+ tolerance and modern Python packaging, sigh. +- Don't update global tables, copy them instead; Use a single TABLE copy (gdesmar) +- Correct print_docstring()'s `docstring.find(quote) +- short options -h and -v now do the right thing. + 3.9.2: 2024-07-21 ================= diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 4cf2974e4..fbfcd30e2 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.3.dev0" # noqa +__version__="3.9.3" # noqa From 53c0e9d5e9c2e1d5a2198f027f6a73527d27745a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Sep 2025 17:45:45 -0400 Subject: [PATCH 458/489] Get ready for release 3.9.3 --- .gitignore | 2 + ChangeLog-spell-corrected.diff | 4381 ++++++++++++++++++++++++ Makefile | 1 + NEWS.md | 8 + admin-tools/check-3.6-3.10-versions.sh | 30 + admin-tools/pyenv-3.6-3.10-versions | 8 + admin-tools/pyenv-newest-versions | 2 +- test/Makefile | 10 +- uncompyle6/version.py | 2 +- 9 files changed, 4438 insertions(+), 6 deletions(-) create mode 100644 ChangeLog-spell-corrected.diff create mode 100644 admin-tools/check-3.6-3.10-versions.sh create mode 100644 admin-tools/pyenv-3.6-3.10-versions diff --git a/.gitignore b/.gitignore index 752d3a7e4..6a2a97741 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ /.python-version /.tox /.venv* +/ChangeLog-spell-corrected +/ChangeLog.orig /README /__pkginfo__.pyc /dist diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 000000000..b0afc14f5 --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,4381 @@ +--- ChangeLog 2025-09-28 18:50:06.933864316 -0400 ++++ ChangeLog-spell-corrected 2025-09-28 18:49:47.641822080 -0400 +@@ -87,7 +87,7 @@ + + 2024-12-12 rocky + +- * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: ++ * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-12-02 rocky +@@ -113,7 +113,7 @@ + + 2024-11-28 rocky + +- * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Don't remove LOAD_CONST RETURN_VALUE when... the LOAD_CONST has a non-None value, or the LOAD_CONST has a line + associated with it. + +@@ -148,7 +148,7 @@ + uncompyle6/semantics/customize36.py, + uncompyle6/semantics/customize37.py, + uncompyle6/semantics/customize38.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Don't update global tables... Work off of copies of them instead. Issue #503 + + 2024-11-09 rocky +@@ -195,12 +195,12 @@ + + 2024-10-04 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Track branch changes in python-spark + + 2024-09-21 rocky + +- * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: ++ * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: + Adminsitrivia + + 2024-09-21 rocky +@@ -222,13 +222,13 @@ + 2024-07-22 rocky + + * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky + + * admin-tools/checkout_common.sh, admin-tools/setup-master.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky +@@ -237,7 +237,7 @@ + + 2024-07-21 rocky + +- * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: ++ * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: + Get ready for release 3.9.2 + + 2024-07-21 rocky +@@ -274,7 +274,7 @@ + + 2024-07-15 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + Handle long dict litereals in 3.4- better... Bracket in pseudo op COLLECTION_START ... BUILD_xx + + 2024-07-14 rocky +@@ -287,7 +287,7 @@ + 2024-07-13 rocky + + * test/simple_source/bug34/03_ifelse_in_lambda.py, +- uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: + Improve 3.4 ifelse inside a lambda Fixes #426 + + 2024-07-13 rocky +@@ -339,7 +339,7 @@ + + * uncompyle6/parsers/reducecheck/tryexcept.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: + Python 2.5 try/except reduce fix Start getting aligner up to date + + 2024-07-12 rocky +@@ -361,7 +361,7 @@ + 2024-07-12 rocky + + * test/simple_source/bug25/06_if_and_bugs.py, +- uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: ++ uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: + Fix some 2.5 parsing bugs + + 2024-07-12 rocky +@@ -417,7 +417,7 @@ + + 2024-06-03 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: + Use set literals + + 2024-06-03 rocky +@@ -467,7 +467,7 @@ + 2024-03-14 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Name phases "disassembly" and "tokenization" + + 2024-03-14 rocky +@@ -478,7 +478,7 @@ + uncompyle6/parsers/reducecheck/ifstmts_jump.py, + uncompyle6/scanners/scanner37base.py, + uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/make_function2.py: Mis spelling corrections ++ uncompyle6/semantics/make_function2.py: Spelling corrections + + 2024-03-13 rocky + +@@ -561,7 +561,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37.py, uncompyle6/semantics/pysource.py, +- uncompyle6/semantics/transform.py: mark "psuedo ops" ++ uncompyle6/semantics/transform.py: mark "pseudo ops" + + 2024-02-24 rocky + +@@ -580,7 +580,7 @@ + test/stdlib/3.8-exclude.sh, test/stdlib/runtests.sh, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py, + uncompyle6/scanners/scanner37base.py, uncompyle6/scanners/tok.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: + Keep optype info in token... It is useful for ADD_VALUE + + 2024-02-24 rocky +@@ -595,12 +595,12 @@ + + 2024-02-24 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-02-24 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-02-24 rocky +@@ -671,7 +671,7 @@ + + 2024-02-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: + Bugs found in 3.0 decomplation... parsers/parse30.py; fix set comprehension grammar bug + uncompyle6/semantics/n_actions.py: evidence of the evils of + modifying node data (via node.pop) +@@ -691,7 +691,7 @@ + + * uncompyle6/bin/uncompile.py, uncompyle6/main.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: + Handle 3.3 MAKE_FUNCTION annotation args properly + + 2024-02-11 rocky +@@ -766,7 +766,7 @@ + 2024-02-03 rocky + + * .gitignore, test/test_pythonlib.py, uncompyle6/main.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + lint + + 2024-02-03 rocky +@@ -776,7 +776,7 @@ + 2024-02-03 rocky + + * uncompyle6/main.py, uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + Fix up linemap option + + 2024-01-19 R. Bernstein +@@ -848,7 +848,7 @@ + + 2023-08-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: + comprehension in lambda for 3.0 & 3.1 + + 2023-08-12 R. Bernstein +@@ -873,7 +873,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: + chained-compare1 -> chained-compare-middle + + 2023-07-07 rocky +@@ -929,7 +929,7 @@ + * admin-tools/setup-master.sh, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse33.py, uncompyle6/parsers/parse34.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: + Correct generator function parsing for 3.3..3.5 + + 2023-06-29 rocky +@@ -1051,7 +1051,7 @@ + + * uncompyle6/scanners/tok.py: self.opc.version -> + self.opc.version_tuple The next release of xdis will no longer support self.opc.version (a +- float value which doesn't work in the presense of 3.10 and above) ++ float value which doesn't work in the presence of 3.10 and above) + + 2023-01-16 rocky + +@@ -1089,7 +1089,7 @@ + 2023-01-14 rocky + + * uncompyle6/parser.py, uncompyle6/scanners/scanner3.py: 3.4-3.5 +- MAKE_CLOSURE with annotate Docs lie about annnotation args. Slight adjustment here. More is ++ MAKE_CLOSURE with annotate Docs lie about annotation args. Slight adjustment here. More is + probably needed. + + 2022-12-22 rocky +@@ -1199,7 +1199,7 @@ + 2022-11-04 rocky + + * admin-tools/{pyenv-3.1-3.2-versions => pyenv-3.0-3.2-versions}, +- admin-tools/setup-python-3.0.sh: Alow 3.0 setup ++ admin-tools/setup-python-3.0.sh: Allow 3.0 setup + + 2022-11-04 rocky + +@@ -1207,7 +1207,7 @@ + + 2022-11-04 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: + Correct 3.0 list comprehension parsing + + 2022-11-03 rocky +@@ -1311,7 +1311,7 @@ + + 2022-09-21 rocky + +- * uncompyle6/semantics/pysource.py: Hande Python 3.5 make_function() ++ * uncompyle6/semantics/pysource.py: Handle Python 3.5 make_function() + semantic action Fixes #409 + + 2022-09-20 rocky +@@ -1448,7 +1448,7 @@ + 2022-06-16 rocky + + * test/simple_source/bug38/00_while_true_pass.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Python 3.8 while and whileTrue loops + + 2022-06-08 rocky +@@ -1470,9 +1470,9 @@ + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml, admin-tools/pyenv-newest-versions, +- test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: ++ test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: + Administrivia Workflows CI: go back to released versions rather than github +- versions pyenv-newest-versions: updaed to use newest Python releases ++ versions pyenv-newest-versions: updated to use newest Python releases + pypy38.py: fix wrong package name import 3.6-exclude.sh: update and + advance + +@@ -1549,13 +1549,13 @@ + * uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/parsers/parse38.py, + uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: + Start rolling in LOAD_ARG for 3.7+ + + 2022-05-05 rocky + + * test/simple_source/bug36/03_async_from_coroutine.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Fix More 3.6 async parsing ... all from 3.6 test_coroutines.py. More bugs remain + + 2022-05-05 rocky +@@ -1639,12 +1639,12 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: + Handle long 2.x bytecode literals more efficiently + + 2022-04-27 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + Small doc corrections + + 2022-04-27 rocky +@@ -1681,7 +1681,7 @@ + 2022-04-25 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + WIP - extend fast long-literals into older Python3 + + 2022-04-25 rocky +@@ -1702,7 +1702,7 @@ + + * test/simple_source/expression/05_long_literals.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: + Bugs in long-literal handlin Move n_dict to n_actions and special case n_const_list. Generalize + build_collection out of 3.7+ and into all Pythons + +@@ -1728,7 +1728,7 @@ + + 2022-04-21 rocky + +- * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: + Add "transfrormd_by" param to SyntaxTree This aligns code more with decompyle3 + + 2022-04-20 rocky +@@ -1747,7 +1747,7 @@ + + 2022-04-17 rocky + +- * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: + Fold in some decompile changes + + 2022-04-17 rocky +@@ -1764,7 +1764,7 @@ + 2022-04-17 rocky + + * Makefile, uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Split out comprehension code.. sync with decompile a little better + + 2022-04-17 rocky +@@ -1774,7 +1774,7 @@ + + 2022-04-15 rocky + +- * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: + Correct for pypy 3.7 + + 2022-04-15 rocky +@@ -1826,7 +1826,7 @@ + 2022-04-01 rocky + + * admin-tools/pyenv-newest-versions, +- uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump lastest testing Python versions ++ uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump latest testing Python versions + + 2022-03-12 rocky + +@@ -1902,7 +1902,7 @@ + 2022-03-04 rocky + + * uncompyle6/semantics/aligner.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Some small variable-name changes + + 2022-03-03 rocky +@@ -1915,12 +1915,12 @@ + * test/simple_source/bug36/02_genexpr.py, + test/simple_source/bug36/05_36lambda.py, + uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: + MAKE_FUNCTION_8 -> MAKE_FUNCTION_CLOSURE Clarity is important. + + 2022-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Remove TABLE_R0 - it hasn't been used in a while + + 2022-01-18 rocky +@@ -2009,7 +2009,7 @@ + uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + mklambda -> lambda_body matches Python AST better Note: we can't use "lambda" since that is a reserved word + + 2021-12-23 rocky +@@ -2142,7 +2142,7 @@ + uncompyle6/scanners/tok.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function2.py, +- uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: ++ uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: + Python 3.6+ specialization + + 2021-11-03 rocky +@@ -2200,7 +2200,7 @@ + + 2021-10-26 rocky + +- * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: ++ * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: + Admnistrivia: package info + + 2021-10-26 rocky +@@ -2236,7 +2236,7 @@ + + 2021-10-23 rocky + +- * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: ++ * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: + Fragment and other bugs Part of the upgrade process + + 2021-10-23 rocky +@@ -2279,7 +2279,7 @@ + + 2021-10-21 rocky + +- * .github/workflows/ubuntu.yml: Worflows CI testing ++ * .github/workflows/ubuntu.yml: Workflows CI testing + + 2021-10-21 rocky + +@@ -2316,8 +2316,8 @@ + + 2021-10-19 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: +- Revise Python version comparisions And set scanner.show_asm for 3.6 ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: ++ Revise Python version comparisons And set scanner.show_asm for 3.6 + + 2021-10-18 rocky + +@@ -2384,7 +2384,7 @@ + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function3.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + new dis - Python compisons involving tuples + + 2021-10-12 rocky +@@ -2446,7 +2446,7 @@ + + 2020-12-31 R. Bernstein + +- * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> unnecessary ++ * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> uxonnecessary + + 2020-12-27 rocky + +@@ -2454,7 +2454,7 @@ + 3.7+ We were producing: ``` z: z: int = 5 on bytecode_3.7_run/02_var_annotate.pyc ``` because grammar went 5. sstmt ann_assign (4) transformed by n_stmts: ('%|%[2]{attr}: + %c\n', 0) 0. ann_assign_init (3): ('%|%[2]{attr}: %c = %c\n', 0, 1) The "ann_assign" added "z:". Instead we have now: ``` 5. sstmt ann_assign_init (3) transformed by n_stmts: ('%|%[2]{attr}: + %c = %c\n', 0, 1) ``` Also, in the previous statement which appears in the listing (but is +- not actually in the finaly tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion ++ not actually in the finally tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion + + 2020-12-27 R. Bernstein + +@@ -2508,13 +2508,13 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + del_stmt -> delete to match Python AST better + + 2020-09-01 rocky + + * uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precidence on ++ uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precedence on + walrus operator + + 2020-09-01 rocky +@@ -2574,7 +2574,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Use "co_consts" in docstring detection. Note: this is an upheaval because we need to pass "code" or at least + "code.co_consts" to the docstring detection routine + +@@ -2585,7 +2585,7 @@ + 2020-07-19 rocky + + * test/add-test.py, test/simple_source/bug27+/03_doc_assign.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Better doc string detection A bug in 2.7 test_descr.py revealed a problem with the way we were + detecting docstrings. __doc__ = DocDescr() was getting confused with a docstring. This program also reveals other bugs in 3.2+ but we'll deal with + that in another commit. +@@ -2638,7 +2638,7 @@ + + 2020-07-06 rocky + +- * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: ++ * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: + Update bug-fixing expectations + + 2020-07-06 rocky +@@ -2725,7 +2725,7 @@ + 2020-06-15 rocky + + * admin-tools/how-to-make-a-release.md, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Towards fixing a 3.8 try except-as bug + + 2020-06-12 rocky +@@ -2739,7 +2739,7 @@ + + 2020-06-12 rocky + +- * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: ++ * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: + Get ready for release 3.7.1 + + 2020-06-12 rocky +@@ -2885,7 +2885,7 @@ + + 2020-05-09 rocky + +- * uncompyle6/linenumbers.py: Simpify an import, blacken a file. ++ * uncompyle6/linenumbers.py: Simplify an import, blacken a file. + + 2020-05-08 rocky + +@@ -2916,7 +2916,7 @@ + + * uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Bugs in nested async for... * Generalize asyc_for rule Fix bug in picking out comprehension iterator in async for * fix bug in getting expression in such a comprehension * Add %[n]{%x} pattern to template_engine() + + 2020-04-27 rocky +@@ -2970,7 +2970,7 @@ + 2020-04-20 rocky + + * .travis.yml, __pkginfo__.py, uncompyle6/disas.py, +- uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: ++ uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: + Update to use xdis 4.4.0 ... with more correct SipHash and other needed bug fixes. + + 2020-04-18 rocky +@@ -3106,7 +3106,7 @@ + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37base.py: whileelse in 3.6 sometimes has +- come froms... also remove extra "L. " in token printing ++ come_froms... also remove extra "L. " in token printing + + 2020-04-04 rocky + +@@ -3294,7 +3294,7 @@ + + 2020-02-13 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: + transform ifelseif bugs + + 2020-02-11 rocky +@@ -3335,7 +3335,7 @@ + 2020-02-10 rocky + + * uncompyle6/semantics/transform.py: Fix bug introduced by ast +- "tranform" change ++ "transform" change + + 2020-02-10 rocky + +@@ -3370,7 +3370,7 @@ + + 2020-02-10 rocky + +- * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: + is_docsting needs to test for sstmts + + 2020-02-10 rocky +@@ -3425,7 +3425,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize35.py, + uncompyle6/semantics/customize37.py: async with rules back to 3.5 +- and ... add precidence on cascaded "await" expressions ++ and ... add precedence on cascaded "await" expressions + + 2020-02-08 rocky + +@@ -3491,7 +3491,7 @@ + + * test/stdlib/3.2-exclude.sh, test/stdlib/3.4-exclude.sh, + test/stdlib/3.5-exclude.sh, test/stdlib/3.6-exclude.sh: Go over +- 3.2-3.6 runtests.sh exludes... Reinstate a lot of tests broken since c90ff51 ++ 3.2-3.6 runtests.sh excludes... Reinstate a lot of tests broken since c90ff51 + + 2020-02-07 rocky + +@@ -3521,7 +3521,7 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize3.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: + conditional -> if_exp ... to match Python IfExp AST + + 2020-02-06 rocky +@@ -3598,7 +3598,7 @@ + + 2020-02-04 rocky + +- * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: + Adjust assert transform for new "if_and" rule + + 2020-02-04 rocky +@@ -3608,7 +3608,7 @@ + + 2020-02-02 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + __modname__ and __qualname__ detection... since grammar has simplified. May still need work for Python < 3.0 + + 2020-02-02 rocky +@@ -3798,7 +3798,7 @@ + 2020-01-29 rocky + + * test/stdlib/3.7-exclude.sh, test/stdlib/3.8-exclude.sh, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Track grammar "stmt" simplifications class ... * NAME_MODULE constant * QUAL_NAME constant + + 2020-01-28 rocky +@@ -3870,7 +3870,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/reducecheck/ifstmt.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + More 3.x "if" checking. Abbreviate stmts->sstmt + + 2020-01-26 rocky +@@ -3910,7 +3910,7 @@ + + 2020-01-25 rocky + +- * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: ++ * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: + Cut-n-paste grammar rule bug + + 2020-01-25 rocky +@@ -4045,16 +4045,16 @@ + uncompyle6/parsers/reducecheck/ifstmt.py, + uncompyle6/parsers/reducecheck/while1stmt.py, + uncompyle6/semantics/pysource.py: Largish rework: scan while1stmt +- for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we neeed to ++ for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we need to + store opc in the parse object. DRY uses of "last = min(last, len(tokens)) + + 2020-01-23 rocky + +- * test/stdlib/3.7-exclude.sh: Exclue 3.7 test_binascii.py for now ++ * test/stdlib/3.7-exclude.sh: Exclude 3.7 test_binascii.py for now + + 2020-01-23 rocky + +- * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: + Mini-sync with decompyle3: go over runtests.sh 3.8 excludes + + 2020-01-23 rocky +@@ -4222,7 +4222,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37.py: More + parser changes to reinstate what was working in 3.6.2... However, again, probably more precise since we isolate loop rules +- better However, again, this isnt' the full store. Semantics were incorrect ++ better However, again, this isn't the full store. Semantics were incorrect + in Release 3.6.2 and they still are. + + 2020-01-17 rocky +@@ -4237,7 +4237,7 @@ + 2020-01-16 rocky + + * test/simple_source/def/01_class.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + parens around consts when taking attr again + + 2020-01-16 rocky +@@ -4273,7 +4273,7 @@ + 2020-01-15 rocky + + * uncompyle6/parsers/reducecheck/ifelsestmt.py: 3.7 and 2.6 +- coexistance in handling jump targets ++ coexistence in handling jump targets + + 2020-01-15 rocky + +@@ -4349,13 +4349,13 @@ + + 2020-01-14 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: + 3.7 test_fstring now works. + + 2020-01-13 rocky + + * test/simple_source/bug36/10_fstring.py, +- test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: ++ test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: + Handle set/dictionary comprehensions in format strings + + 2020-01-13 rocky +@@ -4432,7 +4432,7 @@ + 2020-01-12 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: + Wacky string at beginning of fn which is not docstring... 3.7.6 test_fstring.py tests this. + + 2020-01-12 rocky +@@ -4833,7 +4833,7 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse2.py: Accomodate "return" in an except ++ * uncompyle6/parsers/parse2.py: Accommodate "return" in an except + handler + + 2020-01-06 rocky +@@ -4867,8 +4867,8 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: +- Python 2.4- doesn't have condition expresions ++ * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: ++ Python 2.4- doesn't have condition expressions + + 2020-01-05 rocky + +@@ -4921,7 +4921,7 @@ + 2020-01-03 rocky + + * test/stdlib/runtests.sh, uncompyle6/parser.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7+ multiple imports of dotted path + + 2020-01-03 rocky +@@ -4945,7 +4945,7 @@ + 2020-01-03 rocky + + * test/simple_source/bug30/06_listcomp.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + Fix a 3.7+ chained compare bug... others remain though. + + 2020-01-02 rocky +@@ -4998,11 +4998,11 @@ + + * uncompyle6/semantics/make_function3.py: Simplify make_function3 by + customization We now have different routines for 3.6+ (and 2.x from before). This is desirable before fixing 3.0..3.5 lambdas with default +- paramerts and * args. ++ parameters and * args. + + 2019-12-27 rocky + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: + Tidy code. * Don't use "str" as a variable name * blacken helper and alphabetically order fns * use helper function `find_code_node()` in transform `mk_func()` + + 2019-12-27 rocky +@@ -5012,7 +5012,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Was dropping docstrings! Add in decompyle make_function36 + + 2019-12-27 rocky +@@ -5118,8 +5118,8 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize35.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: +- Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precidence in ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precedence in + 3.7+ for it children + + 2019-12-18 rocky +@@ -5175,7 +5175,7 @@ + 2019-12-16 rocky + + * test/simple_source/bug37/02_async_for_generator.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: + Add 3.7 async listcomp + + 2019-12-15 rocky +@@ -5189,13 +5189,13 @@ + + 2019-12-15 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Adminsitrivia: improve setup scripts + + 2019-12-15 rocky + + * test/simple_source/def/05_class.py, test/stdlib/runtests.sh, +- uncompyle6/semantics/pysource.py: Fix Python 3.x pringing ++ uncompyle6/semantics/pysource.py: Fix Python 3.x printing + superclasses... class Description: not class Description("Description"). Introduced + in not catching LOAD_CONST->LOAD_STR change + +@@ -5268,7 +5268,7 @@ + + 2019-12-11 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: + Add 3.7+ "and" grammar rule and limit "or" more + + 2019-12-11 rocky +@@ -5290,7 +5290,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/01_if_and_if_bug.py, + test/simple_source/bug36/02_call_ex_kw.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Add another 3.8 try/finally rule and semantic action + + 2019-12-10 rocky +@@ -5341,7 +5341,7 @@ + 2019-12-09 rocky + + * setup.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: ++ uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: + Start to tolerate 3.9 (in pydisassemble) + + 2019-12-09 rocky +@@ -5371,7 +5371,7 @@ + + 2019-12-08 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: + Typos: decompyle3 -> uncompyle6 + + 2019-12-08 R. Bernstein +@@ -5380,7 +5380,7 @@ + + 2019-12-02 rocky + +- * uncompyle6/semantics/make_function.py: Accomodate for optional ++ * uncompyle6/semantics/make_function.pyff: Accommodate for optional + docstring in function kw calculation + + 2019-11-21 rocky +@@ -5434,7 +5434,7 @@ + + 2019-11-18 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Two Bugs ... 2.7: more stringent comparison and comp_if testing 2.6-2.7: fix + botched dict constant translation + +@@ -5470,7 +5470,7 @@ + + 2019-11-16 rocky + +- * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: + Administriva - bump testing versions + + 2019-11-16 rocky +@@ -5508,7 +5508,7 @@ + + 2019-11-16 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + 3.0 assert2... Not like other 3.x due to the lack of POP_JUMP_IF + + 2019-11-16 rocky +@@ -5517,7 +5517,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Add 3.0 try/except rule + + 2019-11-15 rocky +@@ -5549,7 +5549,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + 3.0.1 "ret_or", "ret_and", and "or" rules + + 2019-11-15 rocky +@@ -5568,12 +5568,12 @@ + + 2019-11-14 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Two 3.0 rules ... - ifstmtlastl - ifnotstmt30 + + 2019-11-13 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: + Bang on 3.0.1 control flow... more word is needed though + + 2019-11-12 rocky +@@ -5609,7 +5609,7 @@ + 2019-11-11 rocky + + * test/simple_source/bug30/04_and_del.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Cope more JUMP/POP_IF not being in 3.0... more is probably needed though. + + 2019-11-11 rocky +@@ -5631,8 +5631,8 @@ + 2019-11-10 rocky + + * test/simple_source/bug30/03_ifelse.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: +- More Python 3.0 custom "if" statment handling. ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ More Python 3.0 custom "if" statement handling. + + 2019-11-10 rocky + +@@ -5703,7 +5703,7 @@ + + 2019-10-29 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: + Pypy 3.6 tolerance + + 2019-10-29 rocky +@@ -5732,7 +5732,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Pypy 3.6 tolerance + + 2019-05-11 rocky +@@ -5740,7 +5740,7 @@ + * test/Makefile, test/test_pyenvlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + WIP pypy3.6 handling + + 2019-10-28 rocky +@@ -5774,14 +5774,14 @@ + + 2019-10-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Better simpler fragment fix... remove hide_internal test. We changed the default and that's what + whas causing RETURN_LAST to not get included. + + 2019-10-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fragment fixes (and workarounds) fragments.py: add more parent offsets. blacken buffer parser3.py: + additional grammar rules for fragment parser Misc small typos and corrections + +@@ -5854,7 +5854,7 @@ + + 2019-08-21 rocky + +- * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: ++ * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: + CircleCi 3rd try + + 2019-08-21 rocky +@@ -5958,7 +5958,7 @@ + + 2019-07-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + More excpet_cond futzing + + 2019-07-03 rocky +@@ -6051,7 +6051,7 @@ + + 2019-06-21 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Start to reinstate elif's + + 2019-06-21 R. Bernstein +@@ -6075,7 +6075,7 @@ + + * test/simple_source/bug35/07_build_map_unpack.py, + test/simple_source/comprehension/05_dict_comp.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 2-arg asserts in 3.6+ish Changed files have also been reformatted via the blacken formatter + + 2019-06-16 rocky +@@ -6118,18 +6118,18 @@ + + 2019-06-11 rocky + +- * pytest/test_token.py: Formatting change slighty ++ * pytest/test_token.py: Formatting change slightly + + 2019-06-11 rocky + + * pytest/test_token.py, pytest/testdata/if-2.7.right, +- pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: ++ pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: + Formatting in < 3.0 is different for name ops + + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Nicer assembly display... Fewer extraneous quotes and remove pattrs that don't mean anything. +- Base more on OP poperties like varargs and NAME_OPS ++ Base more on OP properties like varargs and NAME_OPS + + 2019-06-11 rocky + +@@ -6156,8 +6156,8 @@ + + * uncompyle6/parsers/parse36.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/pysource.py: Tweaks to x0ret's anotation type +- handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types ++ uncompyle6/semantics/pysource.py: Tweaks to x0ret's annotation type ++ handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Document what's up with annotation types + + 2019-06-09 x0ret + +@@ -6171,7 +6171,7 @@ + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Fix LOAD_STR messing up docstring +- comparision ++ comparison + + 2019-06-09 R. Bernstein + +@@ -6260,7 +6260,7 @@ + + 2019-06-08 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Another LOAD_STR/CONST isolation in < 3.0 + + 2019-06-08 rocky +@@ -6306,7 +6306,7 @@ + 2019-06-06 rocky + + * uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: + better name for call generator rule + + 2019-06-06 R. Bernstein +@@ -6332,14 +6332,14 @@ + 2019-05-28 x0ret + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + fix unicode docstring again, handling unicode string in py2, fix + docstring indentation + + 2019-05-27 rocky + + * test/simple_source/stmts/00_docstring.py: Reinstate more docstring +- tests But 3.{6,7} are stil broken ++ tests But 3.{6,7} are still broken + + 2019-05-27 rocky + +@@ -6357,13 +6357,13 @@ + + 2019-05-27 x0ret + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + towards supporting unicode: docstring + + 2019-05-24 rocky + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py: Simplfy - TODO fix unicode in ++ uncompyle6/semantics/helper.py: Simplify - TODO fix unicode in + docstrings + + 2019-05-24 rocky +@@ -6453,7 +6453,7 @@ + + 2019-05-14 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Only add forward-jumping COME_FROM in 3.6+ Is this a repeat commit? + + 2019-05-13 rocky +@@ -6512,7 +6512,7 @@ + 2019-05-10 rocky + + * uncompyle6/scanners/scanner3.py: Accept x0ret's suggestion for +- 3.6+ if detection.. in the presense of a try block. Fixes #229 ++ 3.6+ if detection.. in the presence of a try block. Fixes #229 + + 2019-05-10 rocky + +@@ -6535,7 +6535,7 @@ + + * test/simple_source/bug36/02_call_ex_kw.py, + uncompyle6/semantics/customize36.py: Fix 3.6. call_ex_kw semantic +- action Was missing positional args parameter in template. Fix submited by ++ action Was missing positional args parameter in template. Fix submitted by + @x0ret Fixes #227 + + 2019-05-08 rocky +@@ -6575,7 +6575,7 @@ + 2019-05-05 rocky + + * test/simple_source/bug26/04_ifelse_parens.py, +- uncompyle6/semantics/consts.py: IfExp precidence handling in 2.6... 2.7 still has a bug ++ uncompyle6/semantics/consts.py: IfExp precedence handling in 2.6... 2.7 still has a bug + + 2019-05-05 rocky + +@@ -6587,24 +6587,24 @@ + + * uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/pysource.py: Fix precidence between list_if and ++ uncompyle6/semantics/pysource.py: Fix precedence between list_if and + if_expr in 3.x + + 2019-05-04 rocky + + * uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/customize37.py: Ned custom 3.7+ IfExp rules ++ uncompyle6/semantics/customize37.py: Need custom 3.7+ IfExp rules + + 2019-05-04 rocky + + * test/Makefile, test/simple_source/bug37/01_and_not_else.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7: if and not else + + 2019-05-04 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + delete_subscr -> delete_subscript ... to better (but not exactly) match the Python AST + + 2019-05-04 rocky +@@ -6614,7 +6614,7 @@ + 2019-05-03 rocky + + * admin-tools/pyenv-older-versions, +- uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: + Administrivia + + 2019-05-03 rocky +@@ -6678,7 +6678,7 @@ + 2019-05-01 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Better 3.6+ format specification handling + + 2019-04-30 rocky +@@ -6690,7 +6690,7 @@ + 2019-04-30 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Hacky handling of 3.6 format string 'X'. + + 2019-04-30 rocky +@@ -6732,7 +6732,7 @@ + + * uncompyle6/semantics/customize25.py, + uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/pysource.py: Was mssing 2.5 cond3 semantic rule ++ uncompyle6/semantics/pysource.py: Was missing 2.5 cond3 semantic rule + + 2019-04-23 rocky + +@@ -6758,7 +6758,7 @@ + 2019-04-22 rocky + + * test/simple_source/bug36/08_comp_gen_for.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Add rule for 3.x comp_for + + 2019-04-19 rocky +@@ -6794,7 +6794,7 @@ + 2019-04-18 rocky + + * uncompyle6/semantics/make_function.py, +- uncompyle6/semantics/pysource.py: Hacky attemp to add more 3.x ++ uncompyle6/semantics/pysource.py: Hacky attempt to add more 3.x + annotate information in + + 2019-04-17 rocky +@@ -6815,7 +6815,7 @@ + + 2019-04-15 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Improve Python 2.7 generator handling + + 2019-04-15 rocky +@@ -6868,7 +6868,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Add 3.8 try else + + 2019-04-14 rocky +@@ -6889,7 +6889,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Start 3.8 async for/else + + 2019-04-14 rocky +@@ -6916,12 +6916,12 @@ + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust while True grammar rule + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust 3.8 while-stmt rules + + 2019-04-13 rocky +@@ -6933,7 +6933,7 @@ + + 2019-04-12 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + 3.8 try/except handling - again (and more to come) + + 2019-04-11 rocky +@@ -6974,7 +6974,7 @@ + 2019-04-10 rocky + + * Makefile, test/Makefile, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Basic 3.8+ "for" loop handling... More Makefile mangling + + 2019-04-10 rocky +@@ -6995,13 +6995,13 @@ + 2019-04-10 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + 3.8 "for" block ... pysource: Tag older semantics for blocks with "expr" and "for_block" + + 2019-04-09 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner13.py, +- uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: + Small changes - bump required xdis version + + 2019-04-05 rocky +@@ -7020,7 +7020,7 @@ + 2019-03-28 rocky + + * uncompyle6/parsers/parse38.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + [WIP] - move forward a tad on Python 3.8 + + 2019-03-28 rocky +@@ -7044,7 +7044,7 @@ + 2019-03-23 rocky + + * test/simple_source/bug36/01_if_and_if_bug.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: + Adjust 3.7 chained compare for adjusted grammar Add test for last change + + 2019-03-23 rocky +@@ -7155,7 +7155,7 @@ + + 2019-01-05 Yiming Wang + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Better assert and AssertionError determine for Python 2.7 + + 2019-01-05 rocky +@@ -7195,7 +7195,7 @@ + + 2018-12-26 rocky + +- * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: ++ * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: + Use raw string in regexp with "\d"... Bump python versions used in testing + + 2018-12-25 rocky +@@ -7205,7 +7205,7 @@ + + 2018-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6+ control flow + + 2018-12-15 rocky +@@ -7318,12 +7318,12 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/semantics/helper.py: Reinstat expr32 and expr1024 +- rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplfy via putting instructions as comments. ++ rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplify via putting instructions as comments. + + 2018-09-19 rocky + + * uncompyle6/main.py: decompile bytecode_version defaults to Python +- intepreter version Fixes #189 ++ interpreter version. Fixes #189 + + 2018-09-19 rocky + +@@ -7332,7 +7332,7 @@ + + 2018-08-12 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: + Handle Python 2.4 if true + + 2018-08-02 rocky +@@ -7342,8 +7342,8 @@ + 2018-08-02 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, +- .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: +- Guidleines for reporting bugs and openning feature requests ++ .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: ++ Guidleines for reporting bugs and opening feature requests + + 2018-07-15 rocky + +@@ -7403,12 +7403,12 @@ + + 2018-06-24 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Remove some of the 3.0 3.x instruction hackiness + + 2018-06-24 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 comprehensions are a snowflake + + 2018-06-24 rocky +@@ -7438,12 +7438,12 @@ + 2018-06-24 rocky + + * test/simple_source/bug31/06_listcomp.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Improve 3.0 list comprehensions + + 2018-06-23 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Fix Python 3.0 "and" parse rule + + 2018-06-23 rocky +@@ -7463,7 +7463,7 @@ + + * test/Makefile, test/simple_source/bug30/00_chained-compare.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse30.py: Python +- 3.0 chained comparisions ++ 3.0 chained comparisons + + 2018-06-23 rocky + +@@ -7493,7 +7493,7 @@ + + 2018-06-22 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Fix two Python 3.0 bugs... * don't add _[0] list comprehension variables * add POP_TOP in _ifstmts_jmp; c_stmst for now isn't optional + + 2018-06-19 rocky +@@ -7578,7 +7578,7 @@ + 2018-06-12 rocky + + * uncompyle6/parsers/parse30.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tollerance ++ uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tolerance + and... add some 1.4 bytecode tests + + 2018-06-12 rocky +@@ -7589,7 +7589,7 @@ + + 2018-06-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection on Python 3.0 + + 2018-06-11 rocky +@@ -7620,12 +7620,12 @@ + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + 3.0 list comprehensions + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 set comprehensions + + 2018-06-09 rocky +@@ -7666,7 +7666,7 @@ + + * test/simple_source/bug14/01_print.py, + test/stdlib/compile-file.py, test/stdlib/compile_file_1x.py, +- uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: ++ uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: + Improve Python 1.4 bytecode coverage + + 2018-06-04 rocky +@@ -7721,7 +7721,7 @@ + uncompyle6/scanner.py, uncompyle6/scanners/scanner14.py, + uncompyle6/scanners/scanner15.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: + Start Python 1.4 decompilation ... Tidy up test code for issue 162 and comments for some disassembly + massaging. + +@@ -7759,7 +7759,7 @@ + + 2018-05-08 rocky + +- * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: + Note we can't handle try/else sometimes in 2.7 + + 2018-05-08 rocky +@@ -7806,7 +7806,7 @@ + + * test/simple_source/bug26/01_ifelse_listcomp.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + 2.6, 2.7 Parse if else inside list comprehension Fixes #171 + + 2018-04-28 rocky +@@ -7829,7 +7829,7 @@ + * test/simple_source/branching/02_ifelse_lambda.py, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: + Handle if not else in lambdas... Fixes #170 + + 2018-04-23 rocky +@@ -7850,13 +7850,13 @@ + + 2018-04-21 rocky + +- * uncompyle6/parsers/parse35.py: Correct (3.7) use fof ++ * uncompyle6/parsers/parse35.py: Correct (3.7) use for + BUILD_MAP_UNPACK_WITH_CALL + + 2018-04-20 rocky + + * Makefile, uncompyle6/parsers/parse36.py, +- uncompyle6/semantics/customize3.py: Fix 3.7 aysnc def testing ++ uncompyle6/semantics/customize3.py: Fix 3.7 async def testing + + 2018-04-19 rocky + +@@ -7876,7 +7876,7 @@ + + 2018-04-18 rocky + +- * uncompyle6/parsers/parse3.py: 2.6 compatability ++ * uncompyle6/parsers/parse3.py: 2.6 compatibility + + 2018-04-18 rocky + +@@ -7892,7 +7892,7 @@ + + 2018-04-16 rocky + +- * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: ++ * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: + Administrivia + + 2018-04-16 rocky +@@ -7997,7 +7997,7 @@ + 2018-04-08 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Slightly Python 3.x handing of subclasses... which are created via a call to create a subclass. Should be more general though. + + 2018-04-08 rocky +@@ -8040,7 +8040,7 @@ + + * uncompyle6/semantics/customize3.py, + uncompyle6/semantics/pysource.py: Make sure we call 'expr' go set +- precidence right ++ precedence right + + 2018-04-06 rocky + +@@ -8088,7 +8088,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/make_function.py: 3.2-3.4 Functions +- cals/defininitions yet again And we're still not out of the woods. ++ cals/definitions yet again And we're still not out of the woods. + + 2018-04-03 rocky + +@@ -8108,7 +8108,7 @@ + * Makefile, pytest/test_fjt.py, pytest/test_function_call.py, + pytest/test_grammar.py, pytest/test_single_compile.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + DRY scanner code more... Expand 2.6 testing + + 2018-04-03 rocky +@@ -8120,7 +8120,7 @@ + + * pytest/test_fjt.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: + DRY instruction building code... There is a little more that could be done with + self.offset2inst_index + +@@ -8148,7 +8148,7 @@ + + 2018-04-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Handle 3.5+ BUILD_MAP_UNPACK used in dictionaries A number of weaknesses have been uncovered though + + 2018-04-01 rocky +@@ -8168,7 +8168,7 @@ + 2018-03-31 rocky + + * test/simple_source/bug36/10_argparse.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6 argument parsing + + 2018-03-31 rocky +@@ -8194,7 +8194,7 @@ + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Replace all_instrs with inst_matches... which works on 3.6+. Still should write a pytest for this. + + 2018-03-29 rocky +@@ -8246,7 +8246,7 @@ + 2018-03-27 rocky + + * test/grammar-cover/.gitignore, test/grammar-cover/convert.sh, +- test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: ++ test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: + grammar-cover administrivia + + 2018-03-27 rocky +@@ -8289,7 +8289,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: ++ * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: + Grammar coverage hacking + + 2018-03-26 rocky +@@ -8328,7 +8328,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: ++ * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: + Start grammar coverage testing + + 2018-03-26 rocky +@@ -8344,7 +8344,7 @@ + 2018-03-26 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Bang on 3.4 CALL_FUNCTION_VAR + + 2018-03-25 rocky +@@ -8358,7 +8358,7 @@ + 2018-03-25 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: + 3.5 *() arg without further args + + 2018-03-25 R. Bernstein +@@ -8410,7 +8410,7 @@ + 2018-03-24 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Towards handling 3.x' CALL_FUNCTION_VAR correctly + + 2018-03-24 rocky +@@ -8430,17 +8430,17 @@ + 2018-03-22 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + 3.6 try except-as bug + + 2018-03-22 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + Localize call_kw precedence to 3.6 + + 2018-03-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate some 3.x dictcomp grammar rules + + 2018-03-21 rocky +@@ -8460,7 +8460,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/02_kwargs.py, + uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: A +- couple of 3.6 bugs... remove parens around decorators by adjusting precidence Partial ++ couple of 3.6 bugs... remove parens around decorators by adjusting precedence Partial + handling of quotes within 3.6 format strings + + 2018-03-21 rocky +@@ -8616,7 +8616,7 @@ + + 2018-03-08 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Slightly better assert detection + + 2018-03-08 rocky +@@ -8728,28 +8728,28 @@ + 2018-03-06 rocky + + * uncompyle6/parsers/parse26.py: 2.6- CONTINUE/JUMP_BACK confusion +- workaroud ++ workaround + + 2018-03-05 rocky + +- * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: ++ * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: + Administrivia... - Add script to run test_pyenvlib.py on everything - Bump 3.6 version 3.6.4 + + 2018-03-05 rocky + + * test/simple_source/stmts/01_rel_import.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Small changes... pysource.py: Bug fix for relative imports. scanner2.py: Remove a debug expression + + 2018-03-05 rocky + +- * uncompyle6/parsers/parse22.py: Python 2.2 code anomoly? Python 2.2 may generate PRINT_ITEM_CONT in some places for ++ * uncompyle6/parsers/parse22.py: Python 2.2 code anomaly? Python 2.2 may generate PRINT_ITEM_CONT in some places for + PRINT_ITEM + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Need to back off set_comp change a little... There was set_comp already. So what had been setcomp_func is now + merely set_comp_func rather than set_comp. Small improvement but in + the right direction, still +@@ -8758,15 +8758,15 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + dictcomp_func -> dict_comp_func... to match AST better. Also adds a correction in last commit, +- including set_comp -> set_comp_expr where apprpriate Note: can't use dict_comp as that was already used. But ++ including set_comp -> set_comp_expr where appropriate Note: can't use dict_comp as that was already used. But + dict_comp_func is matches AST better than dictcomp_func + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + setcomp_func -> set_comp ... to match AST name more closely + + 2018-03-05 rocky +@@ -8821,7 +8821,7 @@ + + 2018-03-04 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + Prevent 3.6 call_kw deriving itself.. Was causing some calls to be parsed incorrectly + + 2018-03-04 rocky +@@ -8874,7 +8874,7 @@ + + 2018-03-01 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection for 2.7 + + 2018-03-01 rocky +@@ -8929,7 +8929,7 @@ + * pytest/test_grammar.py, pytest/testdata/if-2.7.right, + pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Fallout from more precise token attributes + + 2018-02-28 rocky +@@ -8960,7 +8960,7 @@ + + 2018-02-27 rocky + +- * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: ++ * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: + Start simplifying higher-level API + + 2018-02-27 rocky +@@ -8975,14 +8975,14 @@ + + 2018-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Revise comprehension walking in 3.x... less rigidly and with less magic and more verbiage as to what's + going on + + 2018-02-27 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6+ try/finally bugs Another day another 3.6 bug fix attempted + + 2018-02-27 rocky +@@ -9005,7 +9005,7 @@ + 2018-02-26 rocky + + * test/simple_source/bug36/05_call_star_kw.py, uncompyle6/main.py, +- uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to diretions for improvements ++ uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to directions for improvements + + 2018-02-26 rocky + +@@ -9141,7 +9141,7 @@ + + * test/simple_source/bug27+/03_not_dead_code.py, + test/stdlib/runtests.sh, uncompyle6/parsers/parse27.py: Refine 2.7 +- dead code test .. in a hacky way. Will probalby have to expand this in the future or ++ dead code test .. in a hacky way. Will probably have to expand this in the future or + better do dead code analysis + + 2018-02-18 rocky +@@ -9160,13 +9160,13 @@ + + 2018-02-17 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: +- Beter 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ Better 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too + + 2018-02-15 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Wierd comprehension bug seen via ++ uncompyle6/semantics/pysource.py: Weird comprehension bug seen via + new loctraceback + + 2018-02-15 rocky +@@ -9209,7 +9209,7 @@ + + * test/simple_source/bug35/03_double_star_unpack.py, + uncompyle6/semantics/customize.py: Start to handle 3.5+ +- BUILD_LIST_UNPACK in call .. to implement multple star arguments ++ BUILD_LIST_UNPACK in call .. to implement multiple star arguments + + 2018-02-08 rocky + +@@ -9231,7 +9231,7 @@ + + 2018-02-04 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: + Revert most of last change + + 2018-02-04 rocky +@@ -9253,7 +9253,7 @@ + + 2018-02-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + Clean up fragments code for "for"... And make a little more precise. tag "store" part of "for" in + consts. + +@@ -9365,7 +9365,7 @@ + + 2018-01-27 rocky + +- * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: ++ * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: + Get ready for release 2.15.0 + + 2018-01-27 rocky +@@ -9379,12 +9379,12 @@ + 2018-01-27 rocky + + * uncompyle6/semantics/customize.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY fragments by using OO more effectively Split grammar customization to its own file. It's quite large now. + + 2018-01-27 rocky + +- * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + More linestart hacking. Not very successful though + + 2018-01-26 rocky +@@ -9417,7 +9417,7 @@ + 2018-01-24 rocky + + * pytest/test_disasm.py, uncompyle6/disas.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: + Add deparse_code_with_fragments_and_map and simplify + + 2018-01-23 rocky +@@ -9449,7 +9449,7 @@ + 2018-01-22 rocky + + * test/simple_source/bug27+/02_ifelsetmtl.py, uncompyle6/main.py, +- uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: + JUMP_BACK and CONTINUE need to be treated more similar... fixes 148 + + 2018-01-22 rocky +@@ -9516,7 +9516,7 @@ + 2018-01-18 rocky + + * uncompyle6/__init__.py, uncompyle6/scanner.py: Handle 3.5.2..3.5.2 +- magic... And handle magic better overal by improved xdis use ++ magic... And handle magic better overall by improved xdis use + + 2018-01-13 rocky + +@@ -9668,7 +9668,7 @@ + 2018-01-08 rocky + + * pytest/test_fjt.py, test/simple_source/bug35/05_empty_ifs.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: + Fix 3.5+ bug in if's with pass bodies Fixes #104 in a somewhat hacky way. + + 2018-01-07 rocky +@@ -9707,7 +9707,7 @@ + + 2018-01-06 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Change disassembly to make offsets in COME_FROMs + + 2018-01-06 rocky +@@ -9718,7 +9718,7 @@ + + * test/stdlib/runtests.sh, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Fix bug in 2.5- try/else inside ifelsestmt + + 2017-12-15 rocky +@@ -9734,12 +9734,12 @@ + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + 3.6 FUNCTION_EX_KW fixes + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Grammar rule for 3.6 with .. return + + 2017-12-15 rocky +@@ -9796,7 +9796,7 @@ + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT return_stmt -> return to match AST + + 2017-12-14 R. Bernstein +@@ -9813,7 +9813,7 @@ + + 2017-12-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start handling 3.6 CALL_FUNCTION_KW + + 2017-12-14 rocky +@@ -9842,12 +9842,12 @@ + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Back off of previous refactor a little bit + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Simplify scanner2 so it relies less on custimize dict + + 2017-12-13 rocky +@@ -9943,7 +9943,7 @@ + 2017-12-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 CALL_FUNCTION(_VAR)_KW + + 2017-12-12 rocky +@@ -9956,7 +9956,7 @@ + + 2017-12-12 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on BUILD_MAP_UNPACK_WITH_CALL a little... more cases are needed still. And there's a bug in + BUILD_TUPLE_UNPACK_WITH_CALL now in adding the count twice. + +@@ -9984,7 +9984,7 @@ + * admin-tools/how-to-make-a-release.md, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Start to handle CALL_FUNCTION_EX more accurately + + 2017-12-10 rocky +@@ -10022,7 +10022,7 @@ + + 2017-12-07 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: + Reinstate kwargs1... was just missing the semantic action rule for it + + 2017-12-07 rocky +@@ -10038,7 +10038,7 @@ + + * pytest/test_grammar.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: + grammar isolation and reduction + + 2017-12-07 rocky +@@ -10076,7 +10076,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT break_stmt, continue_stmt -> break, continue... to match AST + + 2017-12-06 rocky +@@ -10097,7 +10097,7 @@ + + 2017-12-05 rocky + +- * test/stdlib/runtests.sh: runtest.sh: remove from exlusion stdlib ++ * test/stdlib/runtests.sh: runtest.sh: remove from exclusion stdlib + test that now work + + 2017-12-05 rocky +@@ -10151,7 +10151,7 @@ + 2017-12-04 rocky + + * test/simple_source/bug26/03_weird26.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Slightly better 3.x list comprehension handling + + 2017-12-04 rocky +@@ -10175,15 +10175,15 @@ + + 2017-12-03 rocky + +- * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: + More weirdness testing + + 2017-12-03 rocky + + * test/simple_source/bug26/{03_weird.py => 03_weird26.py}, + test/stdlib/runtests.sh, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: +- Handle a wierd 2.6 conditional false expression... from 2.6. test_grammar ++ uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: ++ Handle a weird 2.6 conditional false expression... from 2.6. test_grammar + + 2017-12-03 rocky + +@@ -10195,7 +10195,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + NT: load_attr -> attribute to match AST + + 2017-12-03 rocky +@@ -10235,7 +10235,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: + Grammar "COME_FROM"_from cleanups ... tryelse constructs in 2.x fixed up _come_from -> _come_froms + (COME_FROM*) consolidate come_froms rule into sincle parser.py + +@@ -10262,7 +10262,7 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT trystmt -> try_except to match AST + + 2017-12-02 rocky +@@ -10273,7 +10273,7 @@ + 2017-12-02 rocky + + * test/Makefile, test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Fix docstring bug.. small sync with python 2.4 branch + + 2017-12-02 rocky +@@ -10317,7 +10317,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Small grammar isolation bugs + + 2017-12-02 rocky +@@ -10328,7 +10328,7 @@ + + * test/simple_source/stmts/02_test_exec.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse35.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.7 exec stmt grammar rule isolation/reduction + + 2017-12-02 rocky +@@ -10338,7 +10338,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: + whileTrue grammar reduction + + 2017-12-02 rocky +@@ -10358,12 +10358,12 @@ + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate and reduce 3.x conditionals and lambda rules + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + opt_come_from_loop -> come_from_loops... ANd remove unused rules associated with COME_FROM_FINALLY + + 2017-12-01 rocky +@@ -10420,7 +10420,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT mapexpr -> dict to match AST + + 2017-11-30 rocky +@@ -10466,7 +10466,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT setcomp -> set_comp to match AST + + 2017-11-29 rocky +@@ -10475,7 +10475,7 @@ + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + list_compr -> list_comp to match AST... more Python 3 custom rule cleanup + + 2017-11-29 rocky +@@ -10504,7 +10504,7 @@ + 2017-11-29 rocky + + * test/simple_source/bug30/01_ops.py, +- test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: + Better grammar coverage; reduce 3.x mklambda rules + + 2017-11-29 rocky +@@ -10514,7 +10514,7 @@ + test/simple_source/stmts/01_augmented_assign.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT augassign -> aug_assign to match AST + + 2017-11-29 rocky +@@ -10579,7 +10579,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT designatore -> store to match AST + + 2017-11-29 rocky +@@ -10596,7 +10596,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT call_function -> call to match AST + + 2017-11-28 rocky +@@ -10669,7 +10669,7 @@ + + * __pkginfo__.py, + test/simple_source/bug25/01_inplace_true_divide.py, +- uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Mege hell ++ uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Merge hell + + 2017-11-27 rocky + +@@ -10705,7 +10705,7 @@ + 2017-11-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: + Grammar isolation + + 2017-11-27 rocky +@@ -10728,7 +10728,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + Grammar reduction + + 2017-11-26 rocky +@@ -10748,7 +10748,7 @@ + + 2017-11-26 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + localize Python2 ifelsetmtr, compare_chained: 2.7 + + 2017-11-26 rocky +@@ -10841,7 +10841,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/semantics/pysource.py: localize 2 and 3 argument +- BUILD_SLICE... Nontermninal name matches AST anme now. Add test. ++ BUILD_SLICE... Nontermninal name matches AST name now. Add test. + + 2017-11-25 rocky + +@@ -10924,7 +10924,7 @@ + + 2017-11-23 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: + Improve try else in 3.2... Grammar from 3.3 is relevant here + + 2017-11-23 rocky +@@ -10941,7 +10941,7 @@ + 2017-11-23 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: + grammar reduction of while loops + + 2017-11-23 rocky +@@ -10978,17 +10978,17 @@ + 2017-11-22 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Reduce +- unecessary grammar rules in 2.x ++ unnecessary grammar rules in 2.x + + 2017-11-22 rocky + + * test/simple_source/stmts/01_augmented_assign.py, +- uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Increase grammar coverage + + 2017-11-22 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia: add "git pull"s + + 2017-11-18 rocky +@@ -10999,7 +10999,7 @@ + 2017-11-18 rocky + + * pytest/test_grammar.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: + Grammar cleanup: import_as_cont -> import_as + + 2017-11-18 rocky +@@ -11013,7 +11013,7 @@ + + 2017-11-17 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: + Python 3 grammar clean up and reorganization + + 2017-11-17 rocky +@@ -11050,7 +11050,7 @@ + + 2017-11-16 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: + Isolate "assert2" rule + + 2017-11-16 rocky +@@ -11081,11 +11081,11 @@ + 2017-11-15 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: More +- 2.7/2.7- grammer separation & cleanup ++ 2.7/2.7- grammar separation & cleanup + + 2017-11-15 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Grammar cleanup: separate some 2.7 from 2.7- rules + + 2017-11-15 rocky +@@ -11127,7 +11127,7 @@ + + * test/Makefile, test/simple_source/stmts/10_del.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse26.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Profiling workarounds, more coverage ... test/Makefile: more grammar checking. Update python versions + 10_del.pyc add test of DEL_GLOBAL check_ast.py, pysource.py: Profileing workarounds + +@@ -11145,7 +11145,7 @@ + + 2017-11-13 rocky + +- * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: ++ * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: + detected old-style Python 2.4 class better + + 2017-11-13 rocky +@@ -11175,7 +11175,7 @@ + + 2017-11-09 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Fix bug in return-optimized try stmt + + 2017-11-09 rocky +@@ -11305,7 +11305,7 @@ + 2017-10-29 rocky + + * test/simple_source/bug36/10_extended_arg_loop.py, +- uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6 control flow bug... Much more is needed, but it's a start + + 2017-10-29 rocky +@@ -11316,9 +11316,9 @@ + 2017-10-29 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Python 3.6-inspired instruction size cleanup Revise and generalize for Python 3.6+ instructions vs < 3.6 +- instuctions. Used more of the generalized methods in xdis and ++ instructions. Used more of the generalized methods in xdis and + remove some (but not all) of the magic numbers. This is a lot of changes, but not all of the refactoring needed. + Much crap still remains. Also, there are still bugs in handling 3.6 + bytecodes. +@@ -11342,7 +11342,7 @@ + + * pytest/test_pysource.py, uncompyle6/parser.py, + uncompyle6/parsers/parse24.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Start allowing node names in template engine These are now used to assert we have the right node type. Simplify import_from + + 2017-10-13 rocky +@@ -11351,7 +11351,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia - generalize shell code + + 2017-10-12 rocky +@@ -11364,7 +11364,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia + + 2017-10-12 rocky +@@ -11393,7 +11393,7 @@ + * admin-tools/check-newer-versions.sh, + admin-tools/check-older-versions.sh, + admin-tools/how-to-make-a-release.txt, +- admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Adminstrivia + + 2017-10-11 rocky +@@ -11428,7 +11428,7 @@ + + * HOW-TO-REPORT-A-BUG.md, test/Makefile, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Improve parse trace. lambda fixes yet again + + 2017-10-10 rocky +@@ -11438,7 +11438,7 @@ + + 2017-10-10 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: + Misc bugs + + 2017-10-10 R. Bernstein +@@ -11461,7 +11461,7 @@ + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py, + uncompyle6/version.py: Adjust for spark-parser 2.7.0 +- incompatabilities ++ incompatibilities + + 2017-10-05 rocky + +@@ -11494,7 +11494,7 @@ + + 2017-10-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: + spark-parser induced changes... reduce rules can be called without token streams. + + 2017-09-30 rocky +@@ -11518,7 +11518,7 @@ + + 2017-09-26 rocky + +- * uncompyle6/parsers/parse3.py: Pyton 3.1 Annotation args can be ++ * uncompyle6/parsers/parse3.py: Python 3.1 Annotation args can be + unicode? + + 2017-09-25 rocky +@@ -11532,7 +11532,7 @@ + 2017-09-21 rocky + + * pytest/test_pysource.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Unit test for format-specifiers And in the process we catch some small bugs + + 2017-09-20 rocky +@@ -11554,7 +11554,7 @@ + + 2017-09-20 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + More small doc changes + + 2017-09-20 rocky +@@ -11631,7 +11631,7 @@ + + 2017-08-13 rocky + +- * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: ++ * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: + 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 + '2.7.13', accept that in looking up either a scanner or a parser. + +@@ -11657,7 +11657,7 @@ + 2017-07-17 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + xdis's "exception match" is now "exception-match" + + 2017-07-15 rocky +@@ -11682,7 +11682,7 @@ + + 2017-07-09 rocky + +- * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: ++ * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 + + 2017-07-08 rocky +@@ -11697,7 +11697,7 @@ + * 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: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/scanner36.py: + Start supporting Pypy 3.5 (5.7.1-beta) + + 2017-07-05 rocky +@@ -11714,13 +11714,13 @@ + 2017-06-28 rocky + + * uncompyle6/semantics/make_function.py: A guard against badly +- formated bytecode ++ formatted 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 ++ uncompyle6/semantics/pysource.py: 3.x function and annotation bug + fixes + + 2017-06-25 rocky +@@ -11731,7 +11731,7 @@ + + * __pkginfo__.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: + Use xdis' instruction offset calculation fns.. next_offset, op_size, has_argument + + 2017-06-19 rocky +@@ -11798,7 +11798,7 @@ + 2017-06-08 rocky + + * uncompyle6/semantics/make_function.py: Correct make_function3 for +- Pytohn 3.2 ++ Python 3.2 + + 2017-06-08 rocky + +@@ -11812,7 +11812,7 @@ + + 2017-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated + properly. Better grammar structure for Python 3.6 call_function. + +@@ -11820,7 +11820,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, + uncompyle6/scanners/scanner36.py: BUILD_{MAP,TUPLE}_UNPACK & +- CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally succesfull right now. In fact a ++ CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally successful right now. In fact a + regression on one of the test cases + + 2017-06-05 rocky +@@ -11831,7 +11831,7 @@ + + 2017-06-04 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh. + + 2017-06-03 rocky +@@ -11883,7 +11883,7 @@ + + 2017-05-23 rocky + +- * uncompyle6/semantics/pysource.py: Fix up retreiving "async" ++ * uncompyle6/semantics/pysource.py: Fix up retrieving "async" + property on 3.6 + + 2017-05-23 rocky +@@ -11910,7 +11910,7 @@ + + 2017-05-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More explicit about 3.5 UNMAP_PACK Have to reduce 3.5 bytecode testing for now, code is more solid. + + 2017-05-19 rocky +@@ -11943,7 +11943,7 @@ + + 2017-05-19 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before + needing EXTENDED_ARG has been reduced to 256, but theoretically + possible in earlier versions. +@@ -11973,7 +11973,7 @@ + + 2017-05-16 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Allow LOAD_CONST EXTENDED_ARG + + 2017-05-15 rocky +@@ -12011,7 +12011,7 @@ + 2017-05-13 rocky + + * README.rst, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 MAKE_FUNCTION a bit more parse3.py, parse36.py: adding return_closure rule tags what's going + on with this rule pysource.py: start changing semantic rules to support code changed + by new make_function semantics README.rst: typo +@@ -12054,7 +12054,7 @@ + + * pytest/test_CALL_FUNCTION_KW.sh, pytest/test_function_call.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Added support for support for Python 3.6 CALL_FUNCTION_KW + + 2017-05-08 rocky +@@ -12084,7 +12084,7 @@ + + 2017-05-07 rocky + +- * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is sematically equivalent, so it is is correct. ++ * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is semantically equivalent, so it is is correct. + + 2017-05-07 rocky + +@@ -12121,7 +12121,7 @@ + + 2017-05-05 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ + + 2017-05-05 rocky +@@ -12145,7 +12145,7 @@ + 2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + BUILD_MAP_UNPACK'ing of dictionaries in 3.5 + + 2017-05-01 rocky +@@ -12159,7 +12159,7 @@ + 2017-04-29 rocky + + * test/simple_source/bug35/01_map_unpack.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Handle BUILD_MAP_UNPACK in a build_list + + 2017-04-27 rocky +@@ -12180,14 +12180,14 @@ + + 2017-04-22 rocky + +- * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduse scope ++ * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduce scope + of LOAD_ASSERT as expr to 3.4+ + + 2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/verify.py: LOAD_ASSERT can also + be an expr This may have the undesirable property that assert statements might +- get tagged with equivalant low-level Python code that uses "raise ++ get tagged with equivalent low-level Python code that uses "raise + AssertionError", but so be it. Fixes #103 + + 2017-04-22 R. Bernstein +@@ -12200,7 +12200,7 @@ + + 2017-04-22 rocky + +- * HISTORY.md: History keeps gettting amended ++ * HISTORY.md: History keeps getting amended + + 2017-04-22 rocky + +@@ -12219,7 +12219,7 @@ + 2017-04-22 rocky + + * test/simple_source/bug33/02_pos_args.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + 3.3+ bug in handling single kwarg after * Towards fixing issue #110 + + 2017-04-20 rocky +@@ -12245,7 +12245,7 @@ + + 2017-04-17 rocky + +- * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: ++ * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: + Rename test case to something more appropriate + + 2017-04-17 rocky +@@ -12306,7 +12306,7 @@ + + 2017-04-14 rocky + +- * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: ++ * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: + Better names for a test + + 2017-04-13 rocky +@@ -12326,7 +12326,7 @@ + + 2017-04-13 rocky + +- * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous + commit. + +@@ -12349,13 +12349,13 @@ + 2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Towards fixing annotated decorator functions... and annotate functions + + 2017-04-10 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: + grammar typo check_ast: add while1else to list of looping constructs + pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is +@@ -12374,7 +12374,7 @@ + 2017-04-09 rocky + + * test/simple_source/def/10_kw+pos_args-bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Another Python 3.5 FUNCTION_VAR bug Fixes #94 + + 2017-04-09 rocky +@@ -12488,7 +12488,7 @@ + + 2017-02-28 rocky + +- * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: ++ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + Python 2.6 a == b or c == d == 3 grammar bug + + 2017-02-28 rocky +@@ -12539,7 +12539,7 @@ + + 2017-02-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + Python 3.x needs more "while 1" grammar rules + + 2017-02-20 rocky +@@ -12669,7 +12669,7 @@ + + 2017-01-15 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 3.6 BUILD_CONST_KEYMAP + + 2017-01-15 rocky +@@ -12702,7 +12702,7 @@ + 2017-01-10 rocky + + * test/simple_source/bug35/03_double_star_unpack.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Improve BUILD_xxx_UNPACK slightly + + 2017-01-09 rocky +@@ -12721,7 +12721,7 @@ + + 2017-01-08 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Python 3.0 decompile bugs + + 2017-01-08 rocky +@@ -12752,7 +12752,7 @@ + 2017-01-07 rocky + + * test/simple_source/bug35/03_async_await.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Start to add 3.5+ await and async + + 2017-01-07 rocky +@@ -12770,7 +12770,7 @@ + + 2017-01-07 rocky + +- * uncompyle6/semantics/make_function.py: Small Pyhton 3.x annotate ++ * uncompyle6/semantics/make_function.py: Small Python 3.x annotate + bug + + 2017-01-03 rocky +@@ -12789,7 +12789,7 @@ + + 2017-01-02 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Python 3.5 continue detection bug + + 2017-01-01 rocky +@@ -12799,7 +12799,7 @@ + + 2017-01-01 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Towards fixing Python 3.5 return bugs + + 2017-01-01 rocky +@@ -12826,12 +12826,12 @@ + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + dectect_structure() -> detect_control_flow() + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie + + 2016-12-29 rocky +@@ -12868,7 +12868,7 @@ + 2016-12-27 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + WIP : Add THEN to disambigute from "and" + + 2016-12-27 rocky +@@ -12882,11 +12882,11 @@ + + 2016-12-26 R. Bernstein + +- * : Merge pull request #71 from jiangpengcheng/tupple_bug tupples which contain only 1 element need a comma ++ * : Merge pull request #71 from jiangpengcheng/tupple_bug tuples which contain only 1 element need a comma + + 2016-12-26 jiangpch + +- * uncompyle6/semantics/pysource.py: tupples which contain only 1 ++ * uncompyle6/semantics/pysource.py: tuples which contain only 1 + element need a comma + + 2016-12-26 rocky +@@ -12913,7 +12913,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Lint + + 2016-12-24 rocky +@@ -12930,7 +12930,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) + + 2016-12-18 rocky +@@ -12941,7 +12941,7 @@ + + 2016-12-17 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + show-asm on python2.5 is optional make scanner2 look a little more like scanner3 + + 2016-12-16 rocky +@@ -13030,7 +13030,7 @@ + + 2016-11-28 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Shorten Python3 grammars with + and * + + 2016-11-28 rocky +@@ -13069,7 +13069,7 @@ + 2016-11-24 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + 2.7 grammar bug workaround. Fix docstring bug + + 2016-11-24 rocky +@@ -13079,7 +13079,7 @@ + + 2016-11-24 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + <2.7 "if" detection and dup Python 3 grammar rule + + 2016-11-23 rocky +@@ -13162,7 +13162,7 @@ + 2016-11-20 rocky + + * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. + When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code + +@@ -13178,7 +13178,7 @@ + 2016-11-16 rocky + + * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + More AST checking Small fixes in output format + + 2016-11-15 rocky +@@ -13198,17 +13198,17 @@ + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. + + 2016-11-13 rocky +@@ -13244,7 +13244,7 @@ + 2016-11-11 rocky + + * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Revert augassign change but.. Make note of what's going on and add grammar test for bad situations + we have in Python 2.6 (and perhaps others) + +@@ -13264,7 +13264,7 @@ + 2016-11-10 rocky + + * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn + of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were + not. +@@ -13276,7 +13276,7 @@ + 2016-11-07 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py: Possiby tidy grammar ++ uncompyle6/parsers/parse32.py: Possibly tidy grammar + + 2016-11-06 rocky + +@@ -13331,13 +13331,13 @@ + + 2016-10-30 rocky + +- * .gitignore, README.rst, test/simple_source/def/03_class_method.py: ++ * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore + + 2016-10-30 rocky + + * uncompyle6/semantics/make_function.py: More source-code line +- indention in make_function.. and remove Python 3 situations from make_function2() ++ indentation in make_function.. and remove Python 3 situations from make_function2() + + 2016-10-29 rocky + +@@ -13360,20 +13360,20 @@ + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + More complete annotate handling Still have a bit of work to do though. + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, +- uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + Expand annotate return to Python 3.4 + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, +- uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little + + 2016-10-28 rocky +@@ -13386,7 +13386,7 @@ + 2016-10-27 rocky + + * test/simple_source/bug31/{04_def_attr.py => 04_def_annotate.py}, +- uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + Clean and fix Python 3 annotate arg return + + 2016-10-26 rocky +@@ -13461,7 +13461,7 @@ + 2016-10-20 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + further work on supporting single and multiple fstring decompilation + + 2016-10-20 rocky +@@ -13472,7 +13472,7 @@ + 2016-10-19 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + urther work on fstrings for python 3.6 - there is a new opcode + build_string which is used to improve fstring performance, but broke + the fstring support in uncompyle +@@ -13508,7 +13508,7 @@ + 2016-10-13 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may neeed arbitrary come_froms for each except clause ++ uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may need arbitrary come_froms for each except clause + + 2016-10-13 rocky + +@@ -13582,7 +13582,7 @@ + 2016-10-08 rocky + + * uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse21.py, +- uncompyle6/semantics/pysource.py: Simpify python 2.1 grammar Fix bug ++ uncompyle6/semantics/pysource.py: Simplify python 2.1 grammar Fix bug + with -t ... Wasn't showing source text when -t option was given + + 2016-10-08 rocky +@@ -13660,13 +13660,13 @@ + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky +@@ -13696,7 +13696,7 @@ + 2016-09-26 rocky + + * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may + need addressing. We want to process COME_FROMs to the same offset to be in + *descending* order so we have the larger range or biggest +@@ -13746,7 +13746,7 @@ + * pytest/test_grammar.py, pytest/test_single_compile.py, + test/Makefile, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py: Add COME_FROM_LOOP Note: we have regressed in --verify and some tests, but I believe +- that's because we are producing more equivalant (if uglier) ++ that's because we are producing more equivalent (if uglier) + programs. That's a separate problem though. + + 2016-09-22 rocky +@@ -13781,7 +13781,7 @@ + + 2016-09-21 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Python 2 & 3 scanner code ever so slightly closer + + 2016-09-21 rocky +@@ -13791,7 +13791,7 @@ + 2016-09-18 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + Small changes + + 2016-09-11 rocky +@@ -13802,7 +13802,7 @@ + 2016-09-11 rocky + + * test/bytecode_3.6/fstring.py, +- test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: ++ test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + Tidy a bit + + 2016-09-09 rocky +@@ -13816,7 +13816,7 @@ + + 2016-09-09 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 + + 2016-09-09 rocky +@@ -13838,7 +13838,7 @@ + + 2016-09-08 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.0-3.2 *args processing + + 2016-09-08 rocky +@@ -13874,7 +13874,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 2.6- try/except control flow detection + + 2016-09-04 rocky +@@ -13909,7 +13909,7 @@ + + * test/simple_source/bug26/07_generator_return.py, + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: A +- couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: descriminate more on parent type ++ couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: discriminate more on parent type + + 2016-09-03 rocky + +@@ -13925,7 +13925,7 @@ + + * test/simple_source/bug26/08_triple_equals.py, + uncompyle6/scanners/scanner2.py: Python 2.2..2.6 bug in a == b == c +- == d Fix was to remove some come froms. Feels a little hacky though. ++ == d Fix was to remove some COME_FROMS. Feels a little hacky though. + + 2016-09-03 rocky + +@@ -13949,19 +13949,19 @@ + 2016-09-02 rocky + + * test/simple_source/bug26/06_return_pop.py, +- uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning + + 2016-09-02 rocky + + * test/simple_source/bug33/02_named_and_kwargs.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x named param and kwargs bug + + 2016-09-01 rocky + + * test/simple_source/bug26/04_while_and_stmt_one_line.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute + a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. + In Python 2.7+ it's a single op. +@@ -13969,7 +13969,7 @@ + 2016-09-01 rocky + + * test/simple_source/bug26/02_except_as.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Handle Python 2.6 and below "except , " + + 2016-08-31 rocky +@@ -13985,7 +13985,7 @@ + uncompyle6/scanners/scanner3.py, uncompyle6/verify.py: Bug in 3.x + detecting "if" structure and ... scanner3.py: bug in 3.x detecting "if" structure Make scanner2.py + look more like scanner3.py verify.py: add weak-verify which tests +- Pytyon syntax, but not code ++ Python syntax, but not code + + 2016-08-30 rocky + +@@ -14111,7 +14111,7 @@ + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, + uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling + + 2016-08-11 Omer Katz +@@ -14180,7 +14180,7 @@ + 2016-07-29 rocky + + * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. + + 2016-07-28 Daniel Bradburn +@@ -14279,13 +14279,13 @@ + + 2016-07-27 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + Small code clean up + + 2016-07-26 rocky + + * uncompyle6/scanners/tok.py, uncompyle6/semantics/fragments.py, +- uncompyle6/verify.py: Usuability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function ++ uncompyle6/verify.py: Usability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function + + 2016-07-26 rocky + +@@ -14307,7 +14307,7 @@ + test/simple_source/bug_pypy27/03_try_return.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules + + 2016-07-25 rocky +@@ -14369,7 +14369,7 @@ + * README.rst, test/simple_source/stmts/03_if_elif.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little + + 2016-07-25 rocky +@@ -14391,7 +14391,7 @@ + test/Makefile, test/test_pythonlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy + + 2016-07-24 Daniel Bradburn +@@ -14411,19 +14411,19 @@ + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky +@@ -14472,7 +14472,7 @@ + + 2016-07-17 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Adjust test data for changed disasm output + + 2016-07-16 rocky +@@ -14506,14 +14506,14 @@ + + 2016-07-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we + understand better what to do though, we'll go with it. + + 2016-07-14 rocky + + * test/Makefile, uncompyle6/semantics/pysource.py: 3.x __qualname__ +- = supression Class names have become more complicated so the pattern test needs ++ = suppression Class names have become more complicated so the pattern test needs + to be more complex as well. Sigh + + 2016-07-14 rocky +@@ -14576,7 +14576,7 @@ + + * test/simple_source/bug33/05_store_name.py, + test/simple_source/comprehension/05_3x_set_comphension.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 & 3.3 handle STORE_NAME better + + 2016-07-11 rocky +@@ -14631,13 +14631,13 @@ + + 2016-07-10 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Bugs caused by 3.x jump_forward misclasification + + 2016-07-10 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification + + 2016-07-09 rocky +@@ -14728,7 +14728,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Python 3 code cleanup + + 2016-07-08 rocky +@@ -14749,7 +14749,7 @@ + 2016-07-08 rocky + + * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + Python 2.4 generator expressions and gen_comp_body + + 2016-07-08 rocky +@@ -14765,7 +14765,7 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/semantics/pysource.py: Start handling Pyton 2.4 bytecodes ++ uncompyle6/semantics/pysource.py: Start handling Python 2.4 bytecodes + + 2016-07-08 rocky + +@@ -14775,12 +14775,12 @@ + 2016-07-08 rocky + + * test/simple_source/stmts/11_return_val.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.5/2.6 RETURN_VALUE bug + + 2016-07-08 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + 2.5/2.6 fn name clash fixes list conprehension problem + + 2016-07-08 rocky +@@ -14808,7 +14808,7 @@ + + 2016-07-07 rocky + +- * : Remove 2.7 asynchat verifcation for now ++ * : Remove 2.7 asynchat verification for now + + 2016-07-07 rocky + +@@ -14822,7 +14822,7 @@ + + 2016-07-07 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + <2.6 make sure jump back on loops is really "back" + + 2016-07-07 rocky +@@ -14869,7 +14869,7 @@ + + * uncompyle6/semantics/fragments.py, + uncompyle6/semantics/pysource.py: More offsets captrued Add %b +- specifer %b - associate text before specifier pysource.py: small doc ++ specifier %b - associate text before specifier pysource.py: small doc + correction + + 2016-07-03 rocky +@@ -14881,12 +14881,12 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Another 2.6 while stmt. Clean up grammar a little + + 2016-07-03 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + 2.6 improper tagging of RETURN_END_IF + + 2016-07-02 rocky +@@ -14923,7 +14923,7 @@ + 2016-06-30 rocky + + * test/simple_source/stmts/06_for_break.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else + + 2016-06-30 rocky +@@ -14940,13 +14940,13 @@ + 2016-06-30 rocky + + * test/simple_source/comprehension/05_for_for.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6.9 list comprehension + + 2016-06-30 rocky + + * test/simple_source/exception/07_try_pass.py, +- uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in tey/except blocks ++ uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in try/except blocks + + 2016-06-30 rocky + +@@ -14982,7 +14982,7 @@ + + 2016-06-28 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Weird 2.6.9 list comprehension + + 2016-06-28 rocky +@@ -14999,17 +14999,17 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Base 2.5 off of 2.6. Some other small bugs. + + 2016-06-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py: 2.6 try +- except hadnling works now ++ except handling works now + + 2016-06-27 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6 list comprehensions + + 2016-06-27 rocky +@@ -15029,8 +15029,8 @@ + + 2016-06-24 rocky + +- * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 psuedo bytecode I think +- is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better assocate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental ++ * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 pseudo bytecode I think ++ is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better associate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental + changes to get say from python 2.3 bytecode to python 2.7 are + great. Conflicts: uncompyle6/parsers/astnode.py + +@@ -15040,7 +15040,7 @@ + + 2016-06-24 rocky + +- * uncompyle6/scanners/scanner2.py: Small formating changes ... and premonition of 2.6 byteocde work ++ * uncompyle6/scanners/scanner2.py: Small formatting changes ... and premonition of 2.6 byteocde work + + 2016-06-24 rocky + +@@ -15052,7 +15052,7 @@ + * __pkginfo__.py, uncompyle6/parsers/astnode.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 psuedo bytecode. Instead ++ uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 pseudo bytecode. Instead + adjust grammar and semantic actions. Down the line we should to segregate version changes in semantic + code better. + +@@ -15094,7 +15094,7 @@ + 2016-06-22 rocky + + * test/simple_source/expression/05_yield_from.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + differing ways to do "yield from" in 3.3-3.5 + + 2016-06-22 rocky +@@ -15103,7 +15103,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option + + 2016-06-22 rocky +@@ -15113,7 +15113,7 @@ + + 2016-06-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More 3.2 LOAD_CONST removal More python3 custom grammar DRYing + + 2016-06-22 rocky +@@ -15125,7 +15125,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/simple_source/expression/10_lambda.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 MAKE_FUNCTION adjustment + + 2016-06-22 rocky +@@ -15144,18 +15144,18 @@ + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Bang on Python 3.2 decompiling. + + 2016-06-20 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + previous 2.7 class decorator bug fixed in 3.x + + 2016-06-20 rocky +@@ -15187,7 +15187,7 @@ + + * test/simple_source/def/11_mkfunc_closure.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 3.x make closure kw args handling bug + + 2016-06-20 rocky +@@ -15224,7 +15224,7 @@ + * test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 2.7 and 3.x bug in dict comprehensions + + 2016-06-19 rocky +@@ -15242,7 +15242,7 @@ + + * test/simple_source/looping/08_while_except_bug.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 except clause parsing bug + + 2016-06-19 rocky +@@ -15304,18 +15304,18 @@ + * pytest/test_deparse.py, + test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 + + 2016-06-06 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + small changes + + 2016-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + include offset for starting listcomp + + 2016-06-03 rocky +@@ -15337,7 +15337,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Limited support for Python 2.3 + + 2016-06-03 rocky +@@ -15435,7 +15435,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Bang again on Python 2.5 and 2.6 scanners + + 2016-05-29 rocky +@@ -15447,7 +15447,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. + + 2016-05-29 rocky +@@ -15464,7 +15464,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + DRY scanners more + + 2016-05-28 rocky +@@ -15479,7 +15479,7 @@ + * test/simple_source/comprehension/06_list_ifnot.py, + test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Remove dis3. Fix in 3.x list if not comprehension + + 2016-05-28 rocky +@@ -15490,7 +15490,7 @@ + 2016-05-28 rocky + + * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, +- uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + Remove dup 3.x opcodes + + 2016-05-28 rocky +@@ -15500,7 +15500,7 @@ + 2016-05-28 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, +- uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + xdis for Python 3 opcodes + + 2016-05-28 rocky +@@ -15545,7 +15545,7 @@ + test/simple_source/def/06_return_bug.py, + uncompyle6/semantics/pysource.py: final RETURN removal bug We want to remove a final return from a module, but otherwise not. + Note we'll no lonager be able to verify functools.pyc as there is +- now a return after a raise statement. That will have to be delt with ++ now a return after a raise statement. That will have to be dealt with + separately. May address Issue #17. + + 2016-05-22 rocky +@@ -15591,7 +15591,7 @@ + 2016-05-20 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to igore fragment stuff ++ uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to ignore fragment stuff + + 2016-05-19 rocky + +@@ -15602,7 +15602,7 @@ + 2016-05-18 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: ++ test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + Handle marshal frozenset + + 2016-05-18 rocky +@@ -15642,14 +15642,14 @@ + 2016-05-17 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: ++ test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + Fix marshal bug in handling complex numbers + + 2016-05-17 rocky + + * Makefile, test/simple_source/def/09_class_closure.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS + + 2016-05-16 rocky +@@ -15665,7 +15665,7 @@ + + 2016-05-16 rocky + +- * : Readd some 3.x loop tests ++ * : Re-add some 3.x loop tests + + 2016-05-16 rocky + +@@ -15719,7 +15719,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix bug in Python 3 lambda expression handling Some other small cleanup changes + + 2016-05-15 rocky +@@ -15727,7 +15727,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + pydisassemble disassemble without grammar mangling Some other small cleanups as well + + 2016-05-15 rocky +@@ -15767,7 +15767,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs + + 2016-05-15 rocky +@@ -15776,7 +15776,7 @@ + + 2016-05-14 rocky + +- * test/Makefile, uncompyle6/scanners/dis3.py: Python2 comptability ++ * test/Makefile, uncompyle6/scanners/dis3.py: Python2 compatibility + in using Python 3 disassembly Also fixes ablility to run bytecode 3.5 tests from 2.x now For Python 2 reading python3 bytstrings, we need to make sure we + confer the character to a number. + +@@ -15800,7 +15800,7 @@ + 2016-05-14 rocky + + * ChangeLog, __pkginfo__.py, uncompyle6/version.py: Fix botched +- entry point names Get ready for relase 2.3.6 ++ entry point names Get ready for release 2.3.6 + + 2016-05-14 rocky + +@@ -15839,7 +15839,7 @@ + 2016-05-12 rocky + + * uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + More small changes + + 2016-05-12 rocky +@@ -15856,7 +15856,7 @@ + + * __pkginfo__.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires + sparck 1.2.0) * some optimization in scanner3 + +@@ -15870,7 +15870,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, + uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Redo make_function for *, arg main(*, file='foo') and things like that now work + + 2016-05-11 rocky +@@ -15902,7 +15902,7 @@ + 2016-05-09 rocky + + * test/simple_source/stmts/09_whiletrue_bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 "while True" bug + + 2016-05-09 rocky +@@ -15972,7 +15972,7 @@ + + * test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/main.py, uncompyle6/parser.py: come_from_opt handles +- and/or precidence properly main.py: give a better error message when file is not found. ++ and/or precedence properly main.py: give a better error message when file is not found. + + 2016-05-08 rocky + +@@ -15996,7 +15996,7 @@ + + * HISTORY.md, test/simple_source/branching/10_if_pass.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections + + 2016-05-08 rocky +@@ -16013,7 +16013,7 @@ + + * test/simple_source/expression/05_yield_from.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. + + 2016-05-06 rocky +@@ -16042,7 +16042,7 @@ + test/simple_source/stmts/10_if_break_finally.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: More +- Python 2 and 3 deparsing bugs fixed * while + if break * try + finall /pass ++ Python 2 and 3 deparsing bugs fixed * while + if break * try + finally pass + + 2016-05-05 rocky + +@@ -16078,19 +16078,19 @@ + 2016-05-05 rocky + + * test/simple_source/def/05_abc_class.py, +- test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + Python 3.5 abc.py bug distilled + + 2016-05-05 rocky + +- * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: ++ * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + Add cross-Python-protable 3.5 dis module + + 2016-05-04 rocky + + * test/simple_source/stmts/05_with.py, + uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo + + 2016-05-03 rocky +@@ -16100,7 +16100,7 @@ + 2016-05-03 rocky + + * uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Don't repeat next_except_jump + + 2016-05-03 rocky +@@ -16150,7 +16150,7 @@ + + * ChangeLog, NEWS, __pkginfo__.py, bin/pydisassemble, + bin/uncompyle6, setup.py, uncompyle6/__init__.py, +- uncompyle6/version.py: Add -V | --version and simplfy changing it ++ uncompyle6/version.py: Add -V | --version and simplify changing it + + 2016-05-01 rocky + +@@ -16212,13 +16212,13 @@ + + 2016-04-30 rocky + +- * uncompyle6/parsers/parse3.py: Python 3.5 if statments decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 ++ * uncompyle6/parsers/parse3.py: Python 3.5 if statements decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 + + 2016-04-28 rocky + + * requirements.txt, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + spark -> spark_parser + + 2016-04-28 rocky +@@ -16366,7 +16366,7 @@ + 2016-01-02 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Make ScannerXX() initialization the same on Python 2.x and 3.x + + 2016-01-02 rocky +@@ -16460,7 +16460,7 @@ + 2015-12-31 rocky + + * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3.3 > dotted class names + + 2015-12-30 rocky +@@ -16483,7 +16483,7 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Remove accidental schmutz. Try using pattr on 3.4 to get fn names + + 2015-12-30 rocky +@@ -16523,14 +16523,14 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py: Tidy parse3 grammer a little ++ * uncompyle6/parsers/parse3.py: Tidy parse3 grammar a little + + 2015-12-30 rocky + + * test/simple_source/exception/25_try_except.py, + test/test_pythonlib.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + Towards Python3 getting try/except working more often. + + 2015-12-29 rocky +@@ -16563,7 +16563,7 @@ + + * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, + uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + scanner3: Python 2.6 compatibility: change set initializations. Get + rid of * import opcode_*: only a little of the much-needed larger + cleanup Makefile: remove 3.x bytecode checking from Python 2.x for +@@ -16582,7 +16582,7 @@ + + * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python3 marshal codes and start to handle cross-version Python + code object types, introducing scan.Code3 + +@@ -16632,7 +16632,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16648,7 +16648,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16708,9 +16708,9 @@ + test/simple_source/{simple_stmts => stmts}/15_assert.py, + test/simple_source/stmts/15_for_if.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE +- get jump offsets into jump attributes. Fix up 3.2 scanner paritally ++ get jump offsets into jump attributes. Fix up 3.2 scanner partially + and use that in 3.4 for in cross version disassembly. + + 2015-12-26 rocky +@@ -16747,7 +16747,7 @@ + 2015-12-25 rocky + + * .gitignore, ChangeLog, MANIFEST.in, NEWS, __pkginfo__.py, +- test/Makefile: Get ready for releaes 2.0.0 ++ test/Makefile: Get ready for release 2.0.0 + + 2015-12-25 rocky + +@@ -16777,7 +16777,7 @@ + + * pytest/test_load.py, test/dis-compare.py, uncompyle6/disas.py, + uncompyle6/load.py, uncompyle6/main.py, uncompyle6/verify.py: Show +- embeded timestamp of byte-decompiled file ++ embedded timestamp of byte-decompiled file + + 2015-12-23 rocky + +@@ -16792,7 +16792,7 @@ + + * test/simple_source/simple_stmts/00_import.py, + test/simple_source/simple_stmts/00_pass.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start Python3 class(superclass) handling + + 2015-12-23 rocky +@@ -16808,13 +16808,13 @@ + + 2015-12-23 rocky + +- * uncompyle6/semantics/fragments.py: Add fragmnet offsets for 'from ++ * uncompyle6/semantics/fragments.py: Add fragment offsets for 'from + x import..' + + 2015-12-22 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Propogate offsets in imports. ++ uncompyle6/semantics/pysource.py: Propagate offsets in imports. + Added a new %x format specifier. + + 2015-12-22 rocky +@@ -16826,7 +16826,7 @@ + uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Allow comments in grammar rules. Start working on Python3 class (not + finished). More test organization. + +@@ -16835,7 +16835,7 @@ + * test/simple_source/def/01_class.py, + test/simple_source/def/10_class.py, + uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/parsers/parse3.py: Remove Python2 buitin "print" from ++ uncompyle6/parsers/parse3.py: Remove Python2 builtin "print" from + Python3's grammr. Start class tests + + 2015-12-22 rocky +@@ -16843,7 +16843,7 @@ + * bin/uncompyle6, uncompyle6/main.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/spark.py, + uncompyle6/semantics/pysource.py: main.py, pysource.py DRY +- deparse_code from main. Is better on showing exception errrors such ++ deparse_code from main. Is better on showing exception errors such + as when a pyc file is not found uncompyle6: Hook in --grammar option + to showing grammar. rules. Default now does not show timestamp. + +@@ -16870,7 +16870,7 @@ + test/simple_source/slice/{01_slice.py => 02_slice.py}, + uncompyle6/main.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/spark.py, uncompyle6/semantics/pysource.py: Add +- spark option to show grammer. Revise uncompyle options. Start to ++ spark option to show grammar. Revise uncompyle options. Start to + reorganize tests more + + 2015-12-21 rocky +@@ -16908,8 +16908,8 @@ + test/simple_source/exception/01_try_except.py, + test/simple_source/misc/assign_none_str.py, + test/simple_source/{misc/assign.py => simple_stmts/00_assign.py}, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: +- Start Python3 execption handling ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ Start Python3 exception handling + + 2015-12-21 rocky + +@@ -17019,7 +17019,7 @@ + + * test/Makefile, test/simple-source/misc/assign_none.py, + test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Python 3 decompilation from Python2 + + 2015-12-20 rocky +@@ -17037,7 +17037,7 @@ + 2015-12-20 rocky + + * Makefile, README.rst, test/Makefile, test/dis-compare.py, +- uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: ++ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + Go over makefiles to make "make check" work. walker, deparser: use + zip_longest + +@@ -17048,8 +17048,8 @@ + + 2015-12-19 rocky + +- * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatiblity +- for getting precidence. n_mkfunc needs to key off of bytecode ++ * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatibility ++ for getting precedence. n_mkfunc needs to key off of bytecode + version, not running Python version. + + 2015-12-19 rocky +@@ -17107,7 +17107,7 @@ + test/simple-source/precedence/left.py, + test/simple-source/precedence/right.py, + test/simple-source/precedence/structure.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + Python 3 bytecode handles opcodes with varargs (better). Decompiling + assert works. Add more of the simple tests and their compiled + bytecode. +@@ -17135,7 +17135,7 @@ + uncompyle6/scanners/scanner34.py: marshal.py: Python2 marshal code + shouldn't try to turn a code object into a string. parse3.py: handle + both keyword and positional function calls. scanner34.py: Remove +- extra level of quoting in LOAD_CONST. Keyward handling now works ++ extra level of quoting in LOAD_CONST. Keyword handling now works + cross Python 2/3. Some other spelling and doc fixes. + + 2015-12-18 rocky +@@ -17144,12 +17144,12 @@ + uncompyle6/disas.py, uncompyle6/parser.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/walker.py: Python3 postional arguments. Clean up code ++ uncompyle6/walker.py: Python3 positional arguments. Clean up code + more along the lines of uncompyle3. + + 2015-12-18 rocky + +- * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: ++ * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + disas.py: Do better for finding/turning a .py file into a .pyc file + across supported versions of Python. Add for else list comprehension + test +@@ -17185,7 +17185,7 @@ + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/verify.py: Python 2.6 compatability via ericfrederich's ++ uncompyle6/verify.py: Python 2.6 compatibility via ericfrederich's + patch. DRY version-checking code + + 2015-12-17 rocky +@@ -17237,12 +17237,12 @@ + test/simple-source/branching/ifelse.py, + test/simple-source/looping/for.py, uncompyle6/__init__.py, + uncompyle6/disas.py, uncompyle6/parsers/spark.py: Add spark grammar +- debugging. Start to comment grammer construct covered by simple ++ debugging. Start to comment grammar construct covered by simple + tests. + + 2015-12-17 rocky + +- * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + Python 3.4 correct grammar for some looping constructs + + 2015-12-17 rocky +@@ -17275,14 +17275,14 @@ + 2015-12-16 rocky + + * uncompyle6/deparser.py, uncompyle6/disas.py, +- uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: ++ uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + Add LICENSE. Add demo programs and DRY code a little + + 2015-12-16 rocky + + * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + On Python3.4 decompiling Python 3.4 instructions, use its built-in + disassembler routines. In contrast to what was here, they most + likely work! +@@ -17305,7 +17305,7 @@ + test/source_3.4/branching/ifelse.py, uncompyle6/.gitignore, + uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Start 3.4 more stringent disassembly testing. Disassembly format has + changed slightly. misc small bugs. + +@@ -17338,7 +17338,7 @@ + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Split out marhsal and disassemble code and spell disassemble + correctly. Fix some lint issues + +@@ -17423,7 +17423,7 @@ + + 2015-12-14 rocky + +- * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: ++ * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: + uncompyle6/dparser -> uncompyle6/parser + + 2015-12-14 rocky +@@ -17529,7 +17529,7 @@ + test/ok_2.7/asynchat.pyc_dis, test/ok_2.7/asyncore.pyc_dis, + test/ok_2.7/atexit.pyc_dis, test/ok_2.7/audiodev.pyc_dis, + test/test_pythonlib.py, uncompyle6/walker.py: test_pythonlib: Fix +- bug in traversing directores walker.py: imports; Add test Python2.5 ++ bug in traversing directories walker.py: imports; Add test Python2.5 + bytecode - it works! Makefile: remove temporary directories and _dis + files which were added by mistake + +@@ -17601,7 +17601,7 @@ + * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, + uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, +- uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + Correct MANIFEST->MANIFEST.in more lint + + 2015-12-13 R. Bernstein +@@ -17618,7 +17618,7 @@ + uncompyle6/__init__.py, uncompyle6/disas.py, + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/scanner25.py, uncompyle6/scanner26.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our + own disassembler. Python's will do fine + +@@ -17704,7 +17704,7 @@ + + * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, + uncompyle6/scanner25.py, uncompyle6/scanner27.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + Minimal disassemble, ast compile and deparse work on Python 3. Some + linting + +@@ -17719,7 +17719,7 @@ + uncompyle6/scanner.py, uncompyle6/scanner25.py, + uncompyle6/scanner26.py, uncompyle6/scanner27.py, + uncompyle6/verify.py, uncompyle6/walker.py: More Python3 +- compatability. Remove duplicate disassembly code and get it from ++ compatibility. Remove duplicate disassembly code and get it from + Python's standard library instead. + + 2015-12-12 rocky +@@ -17729,7 +17729,7 @@ + + 2015-12-11 rocky + +- * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: ++ * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + python3 compatibiity and remove some flake8 warnings. + + 2015-12-11 rocky +@@ -17804,7 +17804,7 @@ + 2013-07-16 root + + * uncompyle2/__init__.py, uncompyle2/disas.py, +- uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: ++ uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + marshal disassembly improvement + + 2013-06-20 Mysterie +@@ -17992,4 +17992,3 @@ + 2012-06-05 Mysterie + + * first commit +- diff --git a/Makefile b/Makefile index bd5703341..b409121a1 100644 --- a/Makefile +++ b/Makefile @@ -131,5 +131,6 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff .PHONY: $(PHONY) diff --git a/NEWS.md b/NEWS.md index 6a7c23004..b3f1e67bd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +3.9.3: 2025-09-28 +================= + +- Python 3.9+ tolerance and modern Python packaging, sigh. +- Don't update global tables, copy them instead; Use a single TABLE copy (gdesmar) +- Correct print_docstring()'s `docstring.find(quote) +- short options -h and -v now do the right thing. + 3.9.2: 2024-07-21 ================= diff --git a/admin-tools/check-3.6-3.10-versions.sh b/admin-tools/check-3.6-3.10-versions.sh new file mode 100644 index 000000000..99fb08fa3 --- /dev/null +++ b/admin-tools/check-3.6-3.10-versions.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Run tests over all Python versions in branch python-3.3-3.5 +set -e +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-3.3-3.5-versions ; then + exit $? +fi +if ! source ./setup-python-3.3.sh ; then + exit $? +fi + +cd .. +for version in $PYVERSIONS; do + echo --- $version --- + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check ; then + exit $? + fi + echo === $version === +done +finish diff --git a/admin-tools/pyenv-3.6-3.10-versions b/admin-tools/pyenv-3.6-3.10-versions new file mode 100644 index 000000000..aa7eabca6 --- /dev/null +++ b/admin-tools/pyenv-3.6-3.10-versions @@ -0,0 +1,8 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the master branch. +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='3.6 pypy3.6 pypy3.7 pypy3.810 pyston-2.3.5 3.8 3.9 3.10' diff --git a/admin-tools/pyenv-newest-versions b/admin-tools/pyenv-newest-versions index b8dd8d584..aeac11e36 100644 --- a/admin-tools/pyenv-newest-versions +++ b/admin-tools/pyenv-newest-versions @@ -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.6.15 pypy3.6-7.3.1 3.7.16 pypy3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.18' +export PYVERSIONS='3.11 3.12 3.13' diff --git a/test/Makefile b/test/Makefile index 83f713e15..4e941f83b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -80,11 +80,9 @@ check-3.8: check-bytecode $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE) -check-3.9: check-bytecode - @echo "Note that we do not support decompiling Python 3.9 bytecode - no 3.9 tests run" +check-3.9 check-3.10 check-3.11 check-3.12 check-3.13: check-bytecode + @echo "Note that we do not support decompiling this version's bytecode - no 3.9 tests run" -check-3.10: check-bytecode - @echo "Note that we do not support decompiling Python 3.10 bytecode - no 3.10 tests run" # FIXME #: this is called when running under pypy3.5-5.8.0, pypy2-5.6.0, pypy3.6-7.3.0 or pypy3.8-7.3.7 @@ -317,6 +315,10 @@ check-bytecode-3.8: $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify +#: Check deparsing Python 3.8 +check-bytecode-3.9 check-bytecode-3.10 check-bytecode-3.11 check-bytecode-3.12 check-bytecode-3.13: + @echo "We don't support decompiling this bytecode for this version" + #: short tests for bytecodes only for this version of Python check-native-short: $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --syntax-verify $(COMPILE) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 4cf2974e4..fbfcd30e2 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.3.dev0" # noqa +__version__="3.9.3" # noqa From 877a81724751008fb5acc50f3d6e0270c339d03a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Sep 2025 17:45:45 -0400 Subject: [PATCH 459/489] Get ready for release 3.9.3 --- .gitignore | 2 + ChangeLog-spell-corrected.diff | 4381 ++++++++++++++++++++++++ Makefile | 1 + NEWS.md | 8 + admin-tools/check-3.6-3.10-versions.sh | 30 + admin-tools/checkout_common.sh | 1 + admin-tools/pyenv-3.6-3.10-versions | 8 + admin-tools/pyenv-newest-versions | 2 +- admin-tools/setup-python-3.3.sh | 1 + test/Makefile | 10 +- uncompyle6/version.py | 2 +- 11 files changed, 4440 insertions(+), 6 deletions(-) create mode 100644 ChangeLog-spell-corrected.diff create mode 100644 admin-tools/check-3.6-3.10-versions.sh create mode 100644 admin-tools/pyenv-3.6-3.10-versions diff --git a/.gitignore b/.gitignore index 752d3a7e4..6a2a97741 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ /.python-version /.tox /.venv* +/ChangeLog-spell-corrected +/ChangeLog.orig /README /__pkginfo__.pyc /dist diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 000000000..b0afc14f5 --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,4381 @@ +--- ChangeLog 2025-09-28 18:50:06.933864316 -0400 ++++ ChangeLog-spell-corrected 2025-09-28 18:49:47.641822080 -0400 +@@ -87,7 +87,7 @@ + + 2024-12-12 rocky + +- * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: ++ * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-12-02 rocky +@@ -113,7 +113,7 @@ + + 2024-11-28 rocky + +- * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Don't remove LOAD_CONST RETURN_VALUE when... the LOAD_CONST has a non-None value, or the LOAD_CONST has a line + associated with it. + +@@ -148,7 +148,7 @@ + uncompyle6/semantics/customize36.py, + uncompyle6/semantics/customize37.py, + uncompyle6/semantics/customize38.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Don't update global tables... Work off of copies of them instead. Issue #503 + + 2024-11-09 rocky +@@ -195,12 +195,12 @@ + + 2024-10-04 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Track branch changes in python-spark + + 2024-09-21 rocky + +- * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: ++ * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: + Adminsitrivia + + 2024-09-21 rocky +@@ -222,13 +222,13 @@ + 2024-07-22 rocky + + * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky + + * admin-tools/checkout_common.sh, admin-tools/setup-master.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky +@@ -237,7 +237,7 @@ + + 2024-07-21 rocky + +- * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: ++ * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: + Get ready for release 3.9.2 + + 2024-07-21 rocky +@@ -274,7 +274,7 @@ + + 2024-07-15 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + Handle long dict litereals in 3.4- better... Bracket in pseudo op COLLECTION_START ... BUILD_xx + + 2024-07-14 rocky +@@ -287,7 +287,7 @@ + 2024-07-13 rocky + + * test/simple_source/bug34/03_ifelse_in_lambda.py, +- uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: + Improve 3.4 ifelse inside a lambda Fixes #426 + + 2024-07-13 rocky +@@ -339,7 +339,7 @@ + + * uncompyle6/parsers/reducecheck/tryexcept.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: + Python 2.5 try/except reduce fix Start getting aligner up to date + + 2024-07-12 rocky +@@ -361,7 +361,7 @@ + 2024-07-12 rocky + + * test/simple_source/bug25/06_if_and_bugs.py, +- uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: ++ uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: + Fix some 2.5 parsing bugs + + 2024-07-12 rocky +@@ -417,7 +417,7 @@ + + 2024-06-03 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: + Use set literals + + 2024-06-03 rocky +@@ -467,7 +467,7 @@ + 2024-03-14 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Name phases "disassembly" and "tokenization" + + 2024-03-14 rocky +@@ -478,7 +478,7 @@ + uncompyle6/parsers/reducecheck/ifstmts_jump.py, + uncompyle6/scanners/scanner37base.py, + uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/make_function2.py: Mis spelling corrections ++ uncompyle6/semantics/make_function2.py: Spelling corrections + + 2024-03-13 rocky + +@@ -561,7 +561,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37.py, uncompyle6/semantics/pysource.py, +- uncompyle6/semantics/transform.py: mark "psuedo ops" ++ uncompyle6/semantics/transform.py: mark "pseudo ops" + + 2024-02-24 rocky + +@@ -580,7 +580,7 @@ + test/stdlib/3.8-exclude.sh, test/stdlib/runtests.sh, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py, + uncompyle6/scanners/scanner37base.py, uncompyle6/scanners/tok.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: + Keep optype info in token... It is useful for ADD_VALUE + + 2024-02-24 rocky +@@ -595,12 +595,12 @@ + + 2024-02-24 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-02-24 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-02-24 rocky +@@ -671,7 +671,7 @@ + + 2024-02-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: + Bugs found in 3.0 decomplation... parsers/parse30.py; fix set comprehension grammar bug + uncompyle6/semantics/n_actions.py: evidence of the evils of + modifying node data (via node.pop) +@@ -691,7 +691,7 @@ + + * uncompyle6/bin/uncompile.py, uncompyle6/main.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: + Handle 3.3 MAKE_FUNCTION annotation args properly + + 2024-02-11 rocky +@@ -766,7 +766,7 @@ + 2024-02-03 rocky + + * .gitignore, test/test_pythonlib.py, uncompyle6/main.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + lint + + 2024-02-03 rocky +@@ -776,7 +776,7 @@ + 2024-02-03 rocky + + * uncompyle6/main.py, uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + Fix up linemap option + + 2024-01-19 R. Bernstein +@@ -848,7 +848,7 @@ + + 2023-08-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: + comprehension in lambda for 3.0 & 3.1 + + 2023-08-12 R. Bernstein +@@ -873,7 +873,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: + chained-compare1 -> chained-compare-middle + + 2023-07-07 rocky +@@ -929,7 +929,7 @@ + * admin-tools/setup-master.sh, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse33.py, uncompyle6/parsers/parse34.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: + Correct generator function parsing for 3.3..3.5 + + 2023-06-29 rocky +@@ -1051,7 +1051,7 @@ + + * uncompyle6/scanners/tok.py: self.opc.version -> + self.opc.version_tuple The next release of xdis will no longer support self.opc.version (a +- float value which doesn't work in the presense of 3.10 and above) ++ float value which doesn't work in the presence of 3.10 and above) + + 2023-01-16 rocky + +@@ -1089,7 +1089,7 @@ + 2023-01-14 rocky + + * uncompyle6/parser.py, uncompyle6/scanners/scanner3.py: 3.4-3.5 +- MAKE_CLOSURE with annotate Docs lie about annnotation args. Slight adjustment here. More is ++ MAKE_CLOSURE with annotate Docs lie about annotation args. Slight adjustment here. More is + probably needed. + + 2022-12-22 rocky +@@ -1199,7 +1199,7 @@ + 2022-11-04 rocky + + * admin-tools/{pyenv-3.1-3.2-versions => pyenv-3.0-3.2-versions}, +- admin-tools/setup-python-3.0.sh: Alow 3.0 setup ++ admin-tools/setup-python-3.0.sh: Allow 3.0 setup + + 2022-11-04 rocky + +@@ -1207,7 +1207,7 @@ + + 2022-11-04 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: + Correct 3.0 list comprehension parsing + + 2022-11-03 rocky +@@ -1311,7 +1311,7 @@ + + 2022-09-21 rocky + +- * uncompyle6/semantics/pysource.py: Hande Python 3.5 make_function() ++ * uncompyle6/semantics/pysource.py: Handle Python 3.5 make_function() + semantic action Fixes #409 + + 2022-09-20 rocky +@@ -1448,7 +1448,7 @@ + 2022-06-16 rocky + + * test/simple_source/bug38/00_while_true_pass.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Python 3.8 while and whileTrue loops + + 2022-06-08 rocky +@@ -1470,9 +1470,9 @@ + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml, admin-tools/pyenv-newest-versions, +- test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: ++ test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: + Administrivia Workflows CI: go back to released versions rather than github +- versions pyenv-newest-versions: updaed to use newest Python releases ++ versions pyenv-newest-versions: updated to use newest Python releases + pypy38.py: fix wrong package name import 3.6-exclude.sh: update and + advance + +@@ -1549,13 +1549,13 @@ + * uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/parsers/parse38.py, + uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: + Start rolling in LOAD_ARG for 3.7+ + + 2022-05-05 rocky + + * test/simple_source/bug36/03_async_from_coroutine.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Fix More 3.6 async parsing ... all from 3.6 test_coroutines.py. More bugs remain + + 2022-05-05 rocky +@@ -1639,12 +1639,12 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: + Handle long 2.x bytecode literals more efficiently + + 2022-04-27 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + Small doc corrections + + 2022-04-27 rocky +@@ -1681,7 +1681,7 @@ + 2022-04-25 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + WIP - extend fast long-literals into older Python3 + + 2022-04-25 rocky +@@ -1702,7 +1702,7 @@ + + * test/simple_source/expression/05_long_literals.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: + Bugs in long-literal handlin Move n_dict to n_actions and special case n_const_list. Generalize + build_collection out of 3.7+ and into all Pythons + +@@ -1728,7 +1728,7 @@ + + 2022-04-21 rocky + +- * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: + Add "transfrormd_by" param to SyntaxTree This aligns code more with decompyle3 + + 2022-04-20 rocky +@@ -1747,7 +1747,7 @@ + + 2022-04-17 rocky + +- * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: + Fold in some decompile changes + + 2022-04-17 rocky +@@ -1764,7 +1764,7 @@ + 2022-04-17 rocky + + * Makefile, uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Split out comprehension code.. sync with decompile a little better + + 2022-04-17 rocky +@@ -1774,7 +1774,7 @@ + + 2022-04-15 rocky + +- * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: + Correct for pypy 3.7 + + 2022-04-15 rocky +@@ -1826,7 +1826,7 @@ + 2022-04-01 rocky + + * admin-tools/pyenv-newest-versions, +- uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump lastest testing Python versions ++ uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump latest testing Python versions + + 2022-03-12 rocky + +@@ -1902,7 +1902,7 @@ + 2022-03-04 rocky + + * uncompyle6/semantics/aligner.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Some small variable-name changes + + 2022-03-03 rocky +@@ -1915,12 +1915,12 @@ + * test/simple_source/bug36/02_genexpr.py, + test/simple_source/bug36/05_36lambda.py, + uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: + MAKE_FUNCTION_8 -> MAKE_FUNCTION_CLOSURE Clarity is important. + + 2022-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Remove TABLE_R0 - it hasn't been used in a while + + 2022-01-18 rocky +@@ -2009,7 +2009,7 @@ + uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + mklambda -> lambda_body matches Python AST better Note: we can't use "lambda" since that is a reserved word + + 2021-12-23 rocky +@@ -2142,7 +2142,7 @@ + uncompyle6/scanners/tok.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function2.py, +- uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: ++ uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: + Python 3.6+ specialization + + 2021-11-03 rocky +@@ -2200,7 +2200,7 @@ + + 2021-10-26 rocky + +- * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: ++ * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: + Admnistrivia: package info + + 2021-10-26 rocky +@@ -2236,7 +2236,7 @@ + + 2021-10-23 rocky + +- * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: ++ * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: + Fragment and other bugs Part of the upgrade process + + 2021-10-23 rocky +@@ -2279,7 +2279,7 @@ + + 2021-10-21 rocky + +- * .github/workflows/ubuntu.yml: Worflows CI testing ++ * .github/workflows/ubuntu.yml: Workflows CI testing + + 2021-10-21 rocky + +@@ -2316,8 +2316,8 @@ + + 2021-10-19 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: +- Revise Python version comparisions And set scanner.show_asm for 3.6 ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: ++ Revise Python version comparisons And set scanner.show_asm for 3.6 + + 2021-10-18 rocky + +@@ -2384,7 +2384,7 @@ + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function3.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + new dis - Python compisons involving tuples + + 2021-10-12 rocky +@@ -2446,7 +2446,7 @@ + + 2020-12-31 R. Bernstein + +- * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> unnecessary ++ * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> uxonnecessary + + 2020-12-27 rocky + +@@ -2454,7 +2454,7 @@ + 3.7+ We were producing: ``` z: z: int = 5 on bytecode_3.7_run/02_var_annotate.pyc ``` because grammar went 5. sstmt ann_assign (4) transformed by n_stmts: ('%|%[2]{attr}: + %c\n', 0) 0. ann_assign_init (3): ('%|%[2]{attr}: %c = %c\n', 0, 1) The "ann_assign" added "z:". Instead we have now: ``` 5. sstmt ann_assign_init (3) transformed by n_stmts: ('%|%[2]{attr}: + %c = %c\n', 0, 1) ``` Also, in the previous statement which appears in the listing (but is +- not actually in the finaly tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion ++ not actually in the finally tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion + + 2020-12-27 R. Bernstein + +@@ -2508,13 +2508,13 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + del_stmt -> delete to match Python AST better + + 2020-09-01 rocky + + * uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precidence on ++ uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precedence on + walrus operator + + 2020-09-01 rocky +@@ -2574,7 +2574,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Use "co_consts" in docstring detection. Note: this is an upheaval because we need to pass "code" or at least + "code.co_consts" to the docstring detection routine + +@@ -2585,7 +2585,7 @@ + 2020-07-19 rocky + + * test/add-test.py, test/simple_source/bug27+/03_doc_assign.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Better doc string detection A bug in 2.7 test_descr.py revealed a problem with the way we were + detecting docstrings. __doc__ = DocDescr() was getting confused with a docstring. This program also reveals other bugs in 3.2+ but we'll deal with + that in another commit. +@@ -2638,7 +2638,7 @@ + + 2020-07-06 rocky + +- * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: ++ * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: + Update bug-fixing expectations + + 2020-07-06 rocky +@@ -2725,7 +2725,7 @@ + 2020-06-15 rocky + + * admin-tools/how-to-make-a-release.md, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Towards fixing a 3.8 try except-as bug + + 2020-06-12 rocky +@@ -2739,7 +2739,7 @@ + + 2020-06-12 rocky + +- * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: ++ * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: + Get ready for release 3.7.1 + + 2020-06-12 rocky +@@ -2885,7 +2885,7 @@ + + 2020-05-09 rocky + +- * uncompyle6/linenumbers.py: Simpify an import, blacken a file. ++ * uncompyle6/linenumbers.py: Simplify an import, blacken a file. + + 2020-05-08 rocky + +@@ -2916,7 +2916,7 @@ + + * uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Bugs in nested async for... * Generalize asyc_for rule Fix bug in picking out comprehension iterator in async for * fix bug in getting expression in such a comprehension * Add %[n]{%x} pattern to template_engine() + + 2020-04-27 rocky +@@ -2970,7 +2970,7 @@ + 2020-04-20 rocky + + * .travis.yml, __pkginfo__.py, uncompyle6/disas.py, +- uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: ++ uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: + Update to use xdis 4.4.0 ... with more correct SipHash and other needed bug fixes. + + 2020-04-18 rocky +@@ -3106,7 +3106,7 @@ + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37base.py: whileelse in 3.6 sometimes has +- come froms... also remove extra "L. " in token printing ++ come_froms... also remove extra "L. " in token printing + + 2020-04-04 rocky + +@@ -3294,7 +3294,7 @@ + + 2020-02-13 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: + transform ifelseif bugs + + 2020-02-11 rocky +@@ -3335,7 +3335,7 @@ + 2020-02-10 rocky + + * uncompyle6/semantics/transform.py: Fix bug introduced by ast +- "tranform" change ++ "transform" change + + 2020-02-10 rocky + +@@ -3370,7 +3370,7 @@ + + 2020-02-10 rocky + +- * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: + is_docsting needs to test for sstmts + + 2020-02-10 rocky +@@ -3425,7 +3425,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize35.py, + uncompyle6/semantics/customize37.py: async with rules back to 3.5 +- and ... add precidence on cascaded "await" expressions ++ and ... add precedence on cascaded "await" expressions + + 2020-02-08 rocky + +@@ -3491,7 +3491,7 @@ + + * test/stdlib/3.2-exclude.sh, test/stdlib/3.4-exclude.sh, + test/stdlib/3.5-exclude.sh, test/stdlib/3.6-exclude.sh: Go over +- 3.2-3.6 runtests.sh exludes... Reinstate a lot of tests broken since c90ff51 ++ 3.2-3.6 runtests.sh excludes... Reinstate a lot of tests broken since c90ff51 + + 2020-02-07 rocky + +@@ -3521,7 +3521,7 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize3.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: + conditional -> if_exp ... to match Python IfExp AST + + 2020-02-06 rocky +@@ -3598,7 +3598,7 @@ + + 2020-02-04 rocky + +- * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: + Adjust assert transform for new "if_and" rule + + 2020-02-04 rocky +@@ -3608,7 +3608,7 @@ + + 2020-02-02 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + __modname__ and __qualname__ detection... since grammar has simplified. May still need work for Python < 3.0 + + 2020-02-02 rocky +@@ -3798,7 +3798,7 @@ + 2020-01-29 rocky + + * test/stdlib/3.7-exclude.sh, test/stdlib/3.8-exclude.sh, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Track grammar "stmt" simplifications class ... * NAME_MODULE constant * QUAL_NAME constant + + 2020-01-28 rocky +@@ -3870,7 +3870,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/reducecheck/ifstmt.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + More 3.x "if" checking. Abbreviate stmts->sstmt + + 2020-01-26 rocky +@@ -3910,7 +3910,7 @@ + + 2020-01-25 rocky + +- * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: ++ * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: + Cut-n-paste grammar rule bug + + 2020-01-25 rocky +@@ -4045,16 +4045,16 @@ + uncompyle6/parsers/reducecheck/ifstmt.py, + uncompyle6/parsers/reducecheck/while1stmt.py, + uncompyle6/semantics/pysource.py: Largish rework: scan while1stmt +- for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we neeed to ++ for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we need to + store opc in the parse object. DRY uses of "last = min(last, len(tokens)) + + 2020-01-23 rocky + +- * test/stdlib/3.7-exclude.sh: Exclue 3.7 test_binascii.py for now ++ * test/stdlib/3.7-exclude.sh: Exclude 3.7 test_binascii.py for now + + 2020-01-23 rocky + +- * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: + Mini-sync with decompyle3: go over runtests.sh 3.8 excludes + + 2020-01-23 rocky +@@ -4222,7 +4222,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37.py: More + parser changes to reinstate what was working in 3.6.2... However, again, probably more precise since we isolate loop rules +- better However, again, this isnt' the full store. Semantics were incorrect ++ better However, again, this isn't the full store. Semantics were incorrect + in Release 3.6.2 and they still are. + + 2020-01-17 rocky +@@ -4237,7 +4237,7 @@ + 2020-01-16 rocky + + * test/simple_source/def/01_class.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + parens around consts when taking attr again + + 2020-01-16 rocky +@@ -4273,7 +4273,7 @@ + 2020-01-15 rocky + + * uncompyle6/parsers/reducecheck/ifelsestmt.py: 3.7 and 2.6 +- coexistance in handling jump targets ++ coexistence in handling jump targets + + 2020-01-15 rocky + +@@ -4349,13 +4349,13 @@ + + 2020-01-14 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: + 3.7 test_fstring now works. + + 2020-01-13 rocky + + * test/simple_source/bug36/10_fstring.py, +- test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: ++ test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: + Handle set/dictionary comprehensions in format strings + + 2020-01-13 rocky +@@ -4432,7 +4432,7 @@ + 2020-01-12 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: + Wacky string at beginning of fn which is not docstring... 3.7.6 test_fstring.py tests this. + + 2020-01-12 rocky +@@ -4833,7 +4833,7 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse2.py: Accomodate "return" in an except ++ * uncompyle6/parsers/parse2.py: Accommodate "return" in an except + handler + + 2020-01-06 rocky +@@ -4867,8 +4867,8 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: +- Python 2.4- doesn't have condition expresions ++ * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: ++ Python 2.4- doesn't have condition expressions + + 2020-01-05 rocky + +@@ -4921,7 +4921,7 @@ + 2020-01-03 rocky + + * test/stdlib/runtests.sh, uncompyle6/parser.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7+ multiple imports of dotted path + + 2020-01-03 rocky +@@ -4945,7 +4945,7 @@ + 2020-01-03 rocky + + * test/simple_source/bug30/06_listcomp.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + Fix a 3.7+ chained compare bug... others remain though. + + 2020-01-02 rocky +@@ -4998,11 +4998,11 @@ + + * uncompyle6/semantics/make_function3.py: Simplify make_function3 by + customization We now have different routines for 3.6+ (and 2.x from before). This is desirable before fixing 3.0..3.5 lambdas with default +- paramerts and * args. ++ parameters and * args. + + 2019-12-27 rocky + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: + Tidy code. * Don't use "str" as a variable name * blacken helper and alphabetically order fns * use helper function `find_code_node()` in transform `mk_func()` + + 2019-12-27 rocky +@@ -5012,7 +5012,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Was dropping docstrings! Add in decompyle make_function36 + + 2019-12-27 rocky +@@ -5118,8 +5118,8 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize35.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: +- Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precidence in ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precedence in + 3.7+ for it children + + 2019-12-18 rocky +@@ -5175,7 +5175,7 @@ + 2019-12-16 rocky + + * test/simple_source/bug37/02_async_for_generator.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: + Add 3.7 async listcomp + + 2019-12-15 rocky +@@ -5189,13 +5189,13 @@ + + 2019-12-15 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Adminsitrivia: improve setup scripts + + 2019-12-15 rocky + + * test/simple_source/def/05_class.py, test/stdlib/runtests.sh, +- uncompyle6/semantics/pysource.py: Fix Python 3.x pringing ++ uncompyle6/semantics/pysource.py: Fix Python 3.x printing + superclasses... class Description: not class Description("Description"). Introduced + in not catching LOAD_CONST->LOAD_STR change + +@@ -5268,7 +5268,7 @@ + + 2019-12-11 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: + Add 3.7+ "and" grammar rule and limit "or" more + + 2019-12-11 rocky +@@ -5290,7 +5290,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/01_if_and_if_bug.py, + test/simple_source/bug36/02_call_ex_kw.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Add another 3.8 try/finally rule and semantic action + + 2019-12-10 rocky +@@ -5341,7 +5341,7 @@ + 2019-12-09 rocky + + * setup.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: ++ uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: + Start to tolerate 3.9 (in pydisassemble) + + 2019-12-09 rocky +@@ -5371,7 +5371,7 @@ + + 2019-12-08 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: + Typos: decompyle3 -> uncompyle6 + + 2019-12-08 R. Bernstein +@@ -5380,7 +5380,7 @@ + + 2019-12-02 rocky + +- * uncompyle6/semantics/make_function.py: Accomodate for optional ++ * uncompyle6/semantics/make_function.pyff: Accommodate for optional + docstring in function kw calculation + + 2019-11-21 rocky +@@ -5434,7 +5434,7 @@ + + 2019-11-18 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Two Bugs ... 2.7: more stringent comparison and comp_if testing 2.6-2.7: fix + botched dict constant translation + +@@ -5470,7 +5470,7 @@ + + 2019-11-16 rocky + +- * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: + Administriva - bump testing versions + + 2019-11-16 rocky +@@ -5508,7 +5508,7 @@ + + 2019-11-16 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + 3.0 assert2... Not like other 3.x due to the lack of POP_JUMP_IF + + 2019-11-16 rocky +@@ -5517,7 +5517,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Add 3.0 try/except rule + + 2019-11-15 rocky +@@ -5549,7 +5549,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + 3.0.1 "ret_or", "ret_and", and "or" rules + + 2019-11-15 rocky +@@ -5568,12 +5568,12 @@ + + 2019-11-14 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Two 3.0 rules ... - ifstmtlastl - ifnotstmt30 + + 2019-11-13 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: + Bang on 3.0.1 control flow... more word is needed though + + 2019-11-12 rocky +@@ -5609,7 +5609,7 @@ + 2019-11-11 rocky + + * test/simple_source/bug30/04_and_del.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Cope more JUMP/POP_IF not being in 3.0... more is probably needed though. + + 2019-11-11 rocky +@@ -5631,8 +5631,8 @@ + 2019-11-10 rocky + + * test/simple_source/bug30/03_ifelse.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: +- More Python 3.0 custom "if" statment handling. ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ More Python 3.0 custom "if" statement handling. + + 2019-11-10 rocky + +@@ -5703,7 +5703,7 @@ + + 2019-10-29 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: + Pypy 3.6 tolerance + + 2019-10-29 rocky +@@ -5732,7 +5732,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Pypy 3.6 tolerance + + 2019-05-11 rocky +@@ -5740,7 +5740,7 @@ + * test/Makefile, test/test_pyenvlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + WIP pypy3.6 handling + + 2019-10-28 rocky +@@ -5774,14 +5774,14 @@ + + 2019-10-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Better simpler fragment fix... remove hide_internal test. We changed the default and that's what + whas causing RETURN_LAST to not get included. + + 2019-10-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fragment fixes (and workarounds) fragments.py: add more parent offsets. blacken buffer parser3.py: + additional grammar rules for fragment parser Misc small typos and corrections + +@@ -5854,7 +5854,7 @@ + + 2019-08-21 rocky + +- * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: ++ * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: + CircleCi 3rd try + + 2019-08-21 rocky +@@ -5958,7 +5958,7 @@ + + 2019-07-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + More excpet_cond futzing + + 2019-07-03 rocky +@@ -6051,7 +6051,7 @@ + + 2019-06-21 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Start to reinstate elif's + + 2019-06-21 R. Bernstein +@@ -6075,7 +6075,7 @@ + + * test/simple_source/bug35/07_build_map_unpack.py, + test/simple_source/comprehension/05_dict_comp.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 2-arg asserts in 3.6+ish Changed files have also been reformatted via the blacken formatter + + 2019-06-16 rocky +@@ -6118,18 +6118,18 @@ + + 2019-06-11 rocky + +- * pytest/test_token.py: Formatting change slighty ++ * pytest/test_token.py: Formatting change slightly + + 2019-06-11 rocky + + * pytest/test_token.py, pytest/testdata/if-2.7.right, +- pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: ++ pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: + Formatting in < 3.0 is different for name ops + + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Nicer assembly display... Fewer extraneous quotes and remove pattrs that don't mean anything. +- Base more on OP poperties like varargs and NAME_OPS ++ Base more on OP properties like varargs and NAME_OPS + + 2019-06-11 rocky + +@@ -6156,8 +6156,8 @@ + + * uncompyle6/parsers/parse36.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/pysource.py: Tweaks to x0ret's anotation type +- handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types ++ uncompyle6/semantics/pysource.py: Tweaks to x0ret's annotation type ++ handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Document what's up with annotation types + + 2019-06-09 x0ret + +@@ -6171,7 +6171,7 @@ + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Fix LOAD_STR messing up docstring +- comparision ++ comparison + + 2019-06-09 R. Bernstein + +@@ -6260,7 +6260,7 @@ + + 2019-06-08 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Another LOAD_STR/CONST isolation in < 3.0 + + 2019-06-08 rocky +@@ -6306,7 +6306,7 @@ + 2019-06-06 rocky + + * uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: + better name for call generator rule + + 2019-06-06 R. Bernstein +@@ -6332,14 +6332,14 @@ + 2019-05-28 x0ret + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + fix unicode docstring again, handling unicode string in py2, fix + docstring indentation + + 2019-05-27 rocky + + * test/simple_source/stmts/00_docstring.py: Reinstate more docstring +- tests But 3.{6,7} are stil broken ++ tests But 3.{6,7} are still broken + + 2019-05-27 rocky + +@@ -6357,13 +6357,13 @@ + + 2019-05-27 x0ret + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + towards supporting unicode: docstring + + 2019-05-24 rocky + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py: Simplfy - TODO fix unicode in ++ uncompyle6/semantics/helper.py: Simplify - TODO fix unicode in + docstrings + + 2019-05-24 rocky +@@ -6453,7 +6453,7 @@ + + 2019-05-14 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Only add forward-jumping COME_FROM in 3.6+ Is this a repeat commit? + + 2019-05-13 rocky +@@ -6512,7 +6512,7 @@ + 2019-05-10 rocky + + * uncompyle6/scanners/scanner3.py: Accept x0ret's suggestion for +- 3.6+ if detection.. in the presense of a try block. Fixes #229 ++ 3.6+ if detection.. in the presence of a try block. Fixes #229 + + 2019-05-10 rocky + +@@ -6535,7 +6535,7 @@ + + * test/simple_source/bug36/02_call_ex_kw.py, + uncompyle6/semantics/customize36.py: Fix 3.6. call_ex_kw semantic +- action Was missing positional args parameter in template. Fix submited by ++ action Was missing positional args parameter in template. Fix submitted by + @x0ret Fixes #227 + + 2019-05-08 rocky +@@ -6575,7 +6575,7 @@ + 2019-05-05 rocky + + * test/simple_source/bug26/04_ifelse_parens.py, +- uncompyle6/semantics/consts.py: IfExp precidence handling in 2.6... 2.7 still has a bug ++ uncompyle6/semantics/consts.py: IfExp precedence handling in 2.6... 2.7 still has a bug + + 2019-05-05 rocky + +@@ -6587,24 +6587,24 @@ + + * uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/pysource.py: Fix precidence between list_if and ++ uncompyle6/semantics/pysource.py: Fix precedence between list_if and + if_expr in 3.x + + 2019-05-04 rocky + + * uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/customize37.py: Ned custom 3.7+ IfExp rules ++ uncompyle6/semantics/customize37.py: Need custom 3.7+ IfExp rules + + 2019-05-04 rocky + + * test/Makefile, test/simple_source/bug37/01_and_not_else.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7: if and not else + + 2019-05-04 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + delete_subscr -> delete_subscript ... to better (but not exactly) match the Python AST + + 2019-05-04 rocky +@@ -6614,7 +6614,7 @@ + 2019-05-03 rocky + + * admin-tools/pyenv-older-versions, +- uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: + Administrivia + + 2019-05-03 rocky +@@ -6678,7 +6678,7 @@ + 2019-05-01 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Better 3.6+ format specification handling + + 2019-04-30 rocky +@@ -6690,7 +6690,7 @@ + 2019-04-30 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Hacky handling of 3.6 format string 'X'. + + 2019-04-30 rocky +@@ -6732,7 +6732,7 @@ + + * uncompyle6/semantics/customize25.py, + uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/pysource.py: Was mssing 2.5 cond3 semantic rule ++ uncompyle6/semantics/pysource.py: Was missing 2.5 cond3 semantic rule + + 2019-04-23 rocky + +@@ -6758,7 +6758,7 @@ + 2019-04-22 rocky + + * test/simple_source/bug36/08_comp_gen_for.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Add rule for 3.x comp_for + + 2019-04-19 rocky +@@ -6794,7 +6794,7 @@ + 2019-04-18 rocky + + * uncompyle6/semantics/make_function.py, +- uncompyle6/semantics/pysource.py: Hacky attemp to add more 3.x ++ uncompyle6/semantics/pysource.py: Hacky attempt to add more 3.x + annotate information in + + 2019-04-17 rocky +@@ -6815,7 +6815,7 @@ + + 2019-04-15 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Improve Python 2.7 generator handling + + 2019-04-15 rocky +@@ -6868,7 +6868,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Add 3.8 try else + + 2019-04-14 rocky +@@ -6889,7 +6889,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Start 3.8 async for/else + + 2019-04-14 rocky +@@ -6916,12 +6916,12 @@ + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust while True grammar rule + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust 3.8 while-stmt rules + + 2019-04-13 rocky +@@ -6933,7 +6933,7 @@ + + 2019-04-12 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + 3.8 try/except handling - again (and more to come) + + 2019-04-11 rocky +@@ -6974,7 +6974,7 @@ + 2019-04-10 rocky + + * Makefile, test/Makefile, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Basic 3.8+ "for" loop handling... More Makefile mangling + + 2019-04-10 rocky +@@ -6995,13 +6995,13 @@ + 2019-04-10 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + 3.8 "for" block ... pysource: Tag older semantics for blocks with "expr" and "for_block" + + 2019-04-09 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner13.py, +- uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: + Small changes - bump required xdis version + + 2019-04-05 rocky +@@ -7020,7 +7020,7 @@ + 2019-03-28 rocky + + * uncompyle6/parsers/parse38.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + [WIP] - move forward a tad on Python 3.8 + + 2019-03-28 rocky +@@ -7044,7 +7044,7 @@ + 2019-03-23 rocky + + * test/simple_source/bug36/01_if_and_if_bug.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: + Adjust 3.7 chained compare for adjusted grammar Add test for last change + + 2019-03-23 rocky +@@ -7155,7 +7155,7 @@ + + 2019-01-05 Yiming Wang + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Better assert and AssertionError determine for Python 2.7 + + 2019-01-05 rocky +@@ -7195,7 +7195,7 @@ + + 2018-12-26 rocky + +- * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: ++ * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: + Use raw string in regexp with "\d"... Bump python versions used in testing + + 2018-12-25 rocky +@@ -7205,7 +7205,7 @@ + + 2018-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6+ control flow + + 2018-12-15 rocky +@@ -7318,12 +7318,12 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/semantics/helper.py: Reinstat expr32 and expr1024 +- rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplfy via putting instructions as comments. ++ rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplify via putting instructions as comments. + + 2018-09-19 rocky + + * uncompyle6/main.py: decompile bytecode_version defaults to Python +- intepreter version Fixes #189 ++ interpreter version. Fixes #189 + + 2018-09-19 rocky + +@@ -7332,7 +7332,7 @@ + + 2018-08-12 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: + Handle Python 2.4 if true + + 2018-08-02 rocky +@@ -7342,8 +7342,8 @@ + 2018-08-02 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, +- .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: +- Guidleines for reporting bugs and openning feature requests ++ .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: ++ Guidleines for reporting bugs and opening feature requests + + 2018-07-15 rocky + +@@ -7403,12 +7403,12 @@ + + 2018-06-24 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Remove some of the 3.0 3.x instruction hackiness + + 2018-06-24 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 comprehensions are a snowflake + + 2018-06-24 rocky +@@ -7438,12 +7438,12 @@ + 2018-06-24 rocky + + * test/simple_source/bug31/06_listcomp.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Improve 3.0 list comprehensions + + 2018-06-23 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Fix Python 3.0 "and" parse rule + + 2018-06-23 rocky +@@ -7463,7 +7463,7 @@ + + * test/Makefile, test/simple_source/bug30/00_chained-compare.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse30.py: Python +- 3.0 chained comparisions ++ 3.0 chained comparisons + + 2018-06-23 rocky + +@@ -7493,7 +7493,7 @@ + + 2018-06-22 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Fix two Python 3.0 bugs... * don't add _[0] list comprehension variables * add POP_TOP in _ifstmts_jmp; c_stmst for now isn't optional + + 2018-06-19 rocky +@@ -7578,7 +7578,7 @@ + 2018-06-12 rocky + + * uncompyle6/parsers/parse30.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tollerance ++ uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tolerance + and... add some 1.4 bytecode tests + + 2018-06-12 rocky +@@ -7589,7 +7589,7 @@ + + 2018-06-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection on Python 3.0 + + 2018-06-11 rocky +@@ -7620,12 +7620,12 @@ + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + 3.0 list comprehensions + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 set comprehensions + + 2018-06-09 rocky +@@ -7666,7 +7666,7 @@ + + * test/simple_source/bug14/01_print.py, + test/stdlib/compile-file.py, test/stdlib/compile_file_1x.py, +- uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: ++ uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: + Improve Python 1.4 bytecode coverage + + 2018-06-04 rocky +@@ -7721,7 +7721,7 @@ + uncompyle6/scanner.py, uncompyle6/scanners/scanner14.py, + uncompyle6/scanners/scanner15.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: + Start Python 1.4 decompilation ... Tidy up test code for issue 162 and comments for some disassembly + massaging. + +@@ -7759,7 +7759,7 @@ + + 2018-05-08 rocky + +- * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: + Note we can't handle try/else sometimes in 2.7 + + 2018-05-08 rocky +@@ -7806,7 +7806,7 @@ + + * test/simple_source/bug26/01_ifelse_listcomp.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + 2.6, 2.7 Parse if else inside list comprehension Fixes #171 + + 2018-04-28 rocky +@@ -7829,7 +7829,7 @@ + * test/simple_source/branching/02_ifelse_lambda.py, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: + Handle if not else in lambdas... Fixes #170 + + 2018-04-23 rocky +@@ -7850,13 +7850,13 @@ + + 2018-04-21 rocky + +- * uncompyle6/parsers/parse35.py: Correct (3.7) use fof ++ * uncompyle6/parsers/parse35.py: Correct (3.7) use for + BUILD_MAP_UNPACK_WITH_CALL + + 2018-04-20 rocky + + * Makefile, uncompyle6/parsers/parse36.py, +- uncompyle6/semantics/customize3.py: Fix 3.7 aysnc def testing ++ uncompyle6/semantics/customize3.py: Fix 3.7 async def testing + + 2018-04-19 rocky + +@@ -7876,7 +7876,7 @@ + + 2018-04-18 rocky + +- * uncompyle6/parsers/parse3.py: 2.6 compatability ++ * uncompyle6/parsers/parse3.py: 2.6 compatibility + + 2018-04-18 rocky + +@@ -7892,7 +7892,7 @@ + + 2018-04-16 rocky + +- * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: ++ * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: + Administrivia + + 2018-04-16 rocky +@@ -7997,7 +7997,7 @@ + 2018-04-08 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Slightly Python 3.x handing of subclasses... which are created via a call to create a subclass. Should be more general though. + + 2018-04-08 rocky +@@ -8040,7 +8040,7 @@ + + * uncompyle6/semantics/customize3.py, + uncompyle6/semantics/pysource.py: Make sure we call 'expr' go set +- precidence right ++ precedence right + + 2018-04-06 rocky + +@@ -8088,7 +8088,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/make_function.py: 3.2-3.4 Functions +- cals/defininitions yet again And we're still not out of the woods. ++ cals/definitions yet again And we're still not out of the woods. + + 2018-04-03 rocky + +@@ -8108,7 +8108,7 @@ + * Makefile, pytest/test_fjt.py, pytest/test_function_call.py, + pytest/test_grammar.py, pytest/test_single_compile.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + DRY scanner code more... Expand 2.6 testing + + 2018-04-03 rocky +@@ -8120,7 +8120,7 @@ + + * pytest/test_fjt.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: + DRY instruction building code... There is a little more that could be done with + self.offset2inst_index + +@@ -8148,7 +8148,7 @@ + + 2018-04-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Handle 3.5+ BUILD_MAP_UNPACK used in dictionaries A number of weaknesses have been uncovered though + + 2018-04-01 rocky +@@ -8168,7 +8168,7 @@ + 2018-03-31 rocky + + * test/simple_source/bug36/10_argparse.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6 argument parsing + + 2018-03-31 rocky +@@ -8194,7 +8194,7 @@ + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Replace all_instrs with inst_matches... which works on 3.6+. Still should write a pytest for this. + + 2018-03-29 rocky +@@ -8246,7 +8246,7 @@ + 2018-03-27 rocky + + * test/grammar-cover/.gitignore, test/grammar-cover/convert.sh, +- test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: ++ test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: + grammar-cover administrivia + + 2018-03-27 rocky +@@ -8289,7 +8289,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: ++ * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: + Grammar coverage hacking + + 2018-03-26 rocky +@@ -8328,7 +8328,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: ++ * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: + Start grammar coverage testing + + 2018-03-26 rocky +@@ -8344,7 +8344,7 @@ + 2018-03-26 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Bang on 3.4 CALL_FUNCTION_VAR + + 2018-03-25 rocky +@@ -8358,7 +8358,7 @@ + 2018-03-25 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: + 3.5 *() arg without further args + + 2018-03-25 R. Bernstein +@@ -8410,7 +8410,7 @@ + 2018-03-24 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Towards handling 3.x' CALL_FUNCTION_VAR correctly + + 2018-03-24 rocky +@@ -8430,17 +8430,17 @@ + 2018-03-22 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + 3.6 try except-as bug + + 2018-03-22 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + Localize call_kw precedence to 3.6 + + 2018-03-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate some 3.x dictcomp grammar rules + + 2018-03-21 rocky +@@ -8460,7 +8460,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/02_kwargs.py, + uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: A +- couple of 3.6 bugs... remove parens around decorators by adjusting precidence Partial ++ couple of 3.6 bugs... remove parens around decorators by adjusting precedence Partial + handling of quotes within 3.6 format strings + + 2018-03-21 rocky +@@ -8616,7 +8616,7 @@ + + 2018-03-08 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Slightly better assert detection + + 2018-03-08 rocky +@@ -8728,28 +8728,28 @@ + 2018-03-06 rocky + + * uncompyle6/parsers/parse26.py: 2.6- CONTINUE/JUMP_BACK confusion +- workaroud ++ workaround + + 2018-03-05 rocky + +- * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: ++ * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: + Administrivia... - Add script to run test_pyenvlib.py on everything - Bump 3.6 version 3.6.4 + + 2018-03-05 rocky + + * test/simple_source/stmts/01_rel_import.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Small changes... pysource.py: Bug fix for relative imports. scanner2.py: Remove a debug expression + + 2018-03-05 rocky + +- * uncompyle6/parsers/parse22.py: Python 2.2 code anomoly? Python 2.2 may generate PRINT_ITEM_CONT in some places for ++ * uncompyle6/parsers/parse22.py: Python 2.2 code anomaly? Python 2.2 may generate PRINT_ITEM_CONT in some places for + PRINT_ITEM + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Need to back off set_comp change a little... There was set_comp already. So what had been setcomp_func is now + merely set_comp_func rather than set_comp. Small improvement but in + the right direction, still +@@ -8758,15 +8758,15 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + dictcomp_func -> dict_comp_func... to match AST better. Also adds a correction in last commit, +- including set_comp -> set_comp_expr where apprpriate Note: can't use dict_comp as that was already used. But ++ including set_comp -> set_comp_expr where appropriate Note: can't use dict_comp as that was already used. But + dict_comp_func is matches AST better than dictcomp_func + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + setcomp_func -> set_comp ... to match AST name more closely + + 2018-03-05 rocky +@@ -8821,7 +8821,7 @@ + + 2018-03-04 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + Prevent 3.6 call_kw deriving itself.. Was causing some calls to be parsed incorrectly + + 2018-03-04 rocky +@@ -8874,7 +8874,7 @@ + + 2018-03-01 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection for 2.7 + + 2018-03-01 rocky +@@ -8929,7 +8929,7 @@ + * pytest/test_grammar.py, pytest/testdata/if-2.7.right, + pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Fallout from more precise token attributes + + 2018-02-28 rocky +@@ -8960,7 +8960,7 @@ + + 2018-02-27 rocky + +- * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: ++ * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: + Start simplifying higher-level API + + 2018-02-27 rocky +@@ -8975,14 +8975,14 @@ + + 2018-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Revise comprehension walking in 3.x... less rigidly and with less magic and more verbiage as to what's + going on + + 2018-02-27 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6+ try/finally bugs Another day another 3.6 bug fix attempted + + 2018-02-27 rocky +@@ -9005,7 +9005,7 @@ + 2018-02-26 rocky + + * test/simple_source/bug36/05_call_star_kw.py, uncompyle6/main.py, +- uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to diretions for improvements ++ uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to directions for improvements + + 2018-02-26 rocky + +@@ -9141,7 +9141,7 @@ + + * test/simple_source/bug27+/03_not_dead_code.py, + test/stdlib/runtests.sh, uncompyle6/parsers/parse27.py: Refine 2.7 +- dead code test .. in a hacky way. Will probalby have to expand this in the future or ++ dead code test .. in a hacky way. Will probably have to expand this in the future or + better do dead code analysis + + 2018-02-18 rocky +@@ -9160,13 +9160,13 @@ + + 2018-02-17 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: +- Beter 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ Better 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too + + 2018-02-15 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Wierd comprehension bug seen via ++ uncompyle6/semantics/pysource.py: Weird comprehension bug seen via + new loctraceback + + 2018-02-15 rocky +@@ -9209,7 +9209,7 @@ + + * test/simple_source/bug35/03_double_star_unpack.py, + uncompyle6/semantics/customize.py: Start to handle 3.5+ +- BUILD_LIST_UNPACK in call .. to implement multple star arguments ++ BUILD_LIST_UNPACK in call .. to implement multiple star arguments + + 2018-02-08 rocky + +@@ -9231,7 +9231,7 @@ + + 2018-02-04 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: + Revert most of last change + + 2018-02-04 rocky +@@ -9253,7 +9253,7 @@ + + 2018-02-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + Clean up fragments code for "for"... And make a little more precise. tag "store" part of "for" in + consts. + +@@ -9365,7 +9365,7 @@ + + 2018-01-27 rocky + +- * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: ++ * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: + Get ready for release 2.15.0 + + 2018-01-27 rocky +@@ -9379,12 +9379,12 @@ + 2018-01-27 rocky + + * uncompyle6/semantics/customize.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY fragments by using OO more effectively Split grammar customization to its own file. It's quite large now. + + 2018-01-27 rocky + +- * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + More linestart hacking. Not very successful though + + 2018-01-26 rocky +@@ -9417,7 +9417,7 @@ + 2018-01-24 rocky + + * pytest/test_disasm.py, uncompyle6/disas.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: + Add deparse_code_with_fragments_and_map and simplify + + 2018-01-23 rocky +@@ -9449,7 +9449,7 @@ + 2018-01-22 rocky + + * test/simple_source/bug27+/02_ifelsetmtl.py, uncompyle6/main.py, +- uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: + JUMP_BACK and CONTINUE need to be treated more similar... fixes 148 + + 2018-01-22 rocky +@@ -9516,7 +9516,7 @@ + 2018-01-18 rocky + + * uncompyle6/__init__.py, uncompyle6/scanner.py: Handle 3.5.2..3.5.2 +- magic... And handle magic better overal by improved xdis use ++ magic... And handle magic better overall by improved xdis use + + 2018-01-13 rocky + +@@ -9668,7 +9668,7 @@ + 2018-01-08 rocky + + * pytest/test_fjt.py, test/simple_source/bug35/05_empty_ifs.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: + Fix 3.5+ bug in if's with pass bodies Fixes #104 in a somewhat hacky way. + + 2018-01-07 rocky +@@ -9707,7 +9707,7 @@ + + 2018-01-06 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Change disassembly to make offsets in COME_FROMs + + 2018-01-06 rocky +@@ -9718,7 +9718,7 @@ + + * test/stdlib/runtests.sh, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Fix bug in 2.5- try/else inside ifelsestmt + + 2017-12-15 rocky +@@ -9734,12 +9734,12 @@ + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + 3.6 FUNCTION_EX_KW fixes + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Grammar rule for 3.6 with .. return + + 2017-12-15 rocky +@@ -9796,7 +9796,7 @@ + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT return_stmt -> return to match AST + + 2017-12-14 R. Bernstein +@@ -9813,7 +9813,7 @@ + + 2017-12-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start handling 3.6 CALL_FUNCTION_KW + + 2017-12-14 rocky +@@ -9842,12 +9842,12 @@ + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Back off of previous refactor a little bit + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Simplify scanner2 so it relies less on custimize dict + + 2017-12-13 rocky +@@ -9943,7 +9943,7 @@ + 2017-12-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 CALL_FUNCTION(_VAR)_KW + + 2017-12-12 rocky +@@ -9956,7 +9956,7 @@ + + 2017-12-12 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on BUILD_MAP_UNPACK_WITH_CALL a little... more cases are needed still. And there's a bug in + BUILD_TUPLE_UNPACK_WITH_CALL now in adding the count twice. + +@@ -9984,7 +9984,7 @@ + * admin-tools/how-to-make-a-release.md, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Start to handle CALL_FUNCTION_EX more accurately + + 2017-12-10 rocky +@@ -10022,7 +10022,7 @@ + + 2017-12-07 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: + Reinstate kwargs1... was just missing the semantic action rule for it + + 2017-12-07 rocky +@@ -10038,7 +10038,7 @@ + + * pytest/test_grammar.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: + grammar isolation and reduction + + 2017-12-07 rocky +@@ -10076,7 +10076,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT break_stmt, continue_stmt -> break, continue... to match AST + + 2017-12-06 rocky +@@ -10097,7 +10097,7 @@ + + 2017-12-05 rocky + +- * test/stdlib/runtests.sh: runtest.sh: remove from exlusion stdlib ++ * test/stdlib/runtests.sh: runtest.sh: remove from exclusion stdlib + test that now work + + 2017-12-05 rocky +@@ -10151,7 +10151,7 @@ + 2017-12-04 rocky + + * test/simple_source/bug26/03_weird26.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Slightly better 3.x list comprehension handling + + 2017-12-04 rocky +@@ -10175,15 +10175,15 @@ + + 2017-12-03 rocky + +- * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: + More weirdness testing + + 2017-12-03 rocky + + * test/simple_source/bug26/{03_weird.py => 03_weird26.py}, + test/stdlib/runtests.sh, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: +- Handle a wierd 2.6 conditional false expression... from 2.6. test_grammar ++ uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: ++ Handle a weird 2.6 conditional false expression... from 2.6. test_grammar + + 2017-12-03 rocky + +@@ -10195,7 +10195,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + NT: load_attr -> attribute to match AST + + 2017-12-03 rocky +@@ -10235,7 +10235,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: + Grammar "COME_FROM"_from cleanups ... tryelse constructs in 2.x fixed up _come_from -> _come_froms + (COME_FROM*) consolidate come_froms rule into sincle parser.py + +@@ -10262,7 +10262,7 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT trystmt -> try_except to match AST + + 2017-12-02 rocky +@@ -10273,7 +10273,7 @@ + 2017-12-02 rocky + + * test/Makefile, test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Fix docstring bug.. small sync with python 2.4 branch + + 2017-12-02 rocky +@@ -10317,7 +10317,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Small grammar isolation bugs + + 2017-12-02 rocky +@@ -10328,7 +10328,7 @@ + + * test/simple_source/stmts/02_test_exec.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse35.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.7 exec stmt grammar rule isolation/reduction + + 2017-12-02 rocky +@@ -10338,7 +10338,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: + whileTrue grammar reduction + + 2017-12-02 rocky +@@ -10358,12 +10358,12 @@ + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate and reduce 3.x conditionals and lambda rules + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + opt_come_from_loop -> come_from_loops... ANd remove unused rules associated with COME_FROM_FINALLY + + 2017-12-01 rocky +@@ -10420,7 +10420,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT mapexpr -> dict to match AST + + 2017-11-30 rocky +@@ -10466,7 +10466,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT setcomp -> set_comp to match AST + + 2017-11-29 rocky +@@ -10475,7 +10475,7 @@ + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + list_compr -> list_comp to match AST... more Python 3 custom rule cleanup + + 2017-11-29 rocky +@@ -10504,7 +10504,7 @@ + 2017-11-29 rocky + + * test/simple_source/bug30/01_ops.py, +- test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: + Better grammar coverage; reduce 3.x mklambda rules + + 2017-11-29 rocky +@@ -10514,7 +10514,7 @@ + test/simple_source/stmts/01_augmented_assign.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT augassign -> aug_assign to match AST + + 2017-11-29 rocky +@@ -10579,7 +10579,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT designatore -> store to match AST + + 2017-11-29 rocky +@@ -10596,7 +10596,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT call_function -> call to match AST + + 2017-11-28 rocky +@@ -10669,7 +10669,7 @@ + + * __pkginfo__.py, + test/simple_source/bug25/01_inplace_true_divide.py, +- uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Mege hell ++ uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Merge hell + + 2017-11-27 rocky + +@@ -10705,7 +10705,7 @@ + 2017-11-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: + Grammar isolation + + 2017-11-27 rocky +@@ -10728,7 +10728,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + Grammar reduction + + 2017-11-26 rocky +@@ -10748,7 +10748,7 @@ + + 2017-11-26 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + localize Python2 ifelsetmtr, compare_chained: 2.7 + + 2017-11-26 rocky +@@ -10841,7 +10841,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/semantics/pysource.py: localize 2 and 3 argument +- BUILD_SLICE... Nontermninal name matches AST anme now. Add test. ++ BUILD_SLICE... Nontermninal name matches AST name now. Add test. + + 2017-11-25 rocky + +@@ -10924,7 +10924,7 @@ + + 2017-11-23 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: + Improve try else in 3.2... Grammar from 3.3 is relevant here + + 2017-11-23 rocky +@@ -10941,7 +10941,7 @@ + 2017-11-23 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: + grammar reduction of while loops + + 2017-11-23 rocky +@@ -10978,17 +10978,17 @@ + 2017-11-22 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Reduce +- unecessary grammar rules in 2.x ++ unnecessary grammar rules in 2.x + + 2017-11-22 rocky + + * test/simple_source/stmts/01_augmented_assign.py, +- uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Increase grammar coverage + + 2017-11-22 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia: add "git pull"s + + 2017-11-18 rocky +@@ -10999,7 +10999,7 @@ + 2017-11-18 rocky + + * pytest/test_grammar.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: + Grammar cleanup: import_as_cont -> import_as + + 2017-11-18 rocky +@@ -11013,7 +11013,7 @@ + + 2017-11-17 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: + Python 3 grammar clean up and reorganization + + 2017-11-17 rocky +@@ -11050,7 +11050,7 @@ + + 2017-11-16 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: + Isolate "assert2" rule + + 2017-11-16 rocky +@@ -11081,11 +11081,11 @@ + 2017-11-15 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: More +- 2.7/2.7- grammer separation & cleanup ++ 2.7/2.7- grammar separation & cleanup + + 2017-11-15 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Grammar cleanup: separate some 2.7 from 2.7- rules + + 2017-11-15 rocky +@@ -11127,7 +11127,7 @@ + + * test/Makefile, test/simple_source/stmts/10_del.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse26.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Profiling workarounds, more coverage ... test/Makefile: more grammar checking. Update python versions + 10_del.pyc add test of DEL_GLOBAL check_ast.py, pysource.py: Profileing workarounds + +@@ -11145,7 +11145,7 @@ + + 2017-11-13 rocky + +- * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: ++ * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: + detected old-style Python 2.4 class better + + 2017-11-13 rocky +@@ -11175,7 +11175,7 @@ + + 2017-11-09 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Fix bug in return-optimized try stmt + + 2017-11-09 rocky +@@ -11305,7 +11305,7 @@ + 2017-10-29 rocky + + * test/simple_source/bug36/10_extended_arg_loop.py, +- uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6 control flow bug... Much more is needed, but it's a start + + 2017-10-29 rocky +@@ -11316,9 +11316,9 @@ + 2017-10-29 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Python 3.6-inspired instruction size cleanup Revise and generalize for Python 3.6+ instructions vs < 3.6 +- instuctions. Used more of the generalized methods in xdis and ++ instructions. Used more of the generalized methods in xdis and + remove some (but not all) of the magic numbers. This is a lot of changes, but not all of the refactoring needed. + Much crap still remains. Also, there are still bugs in handling 3.6 + bytecodes. +@@ -11342,7 +11342,7 @@ + + * pytest/test_pysource.py, uncompyle6/parser.py, + uncompyle6/parsers/parse24.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Start allowing node names in template engine These are now used to assert we have the right node type. Simplify import_from + + 2017-10-13 rocky +@@ -11351,7 +11351,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia - generalize shell code + + 2017-10-12 rocky +@@ -11364,7 +11364,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia + + 2017-10-12 rocky +@@ -11393,7 +11393,7 @@ + * admin-tools/check-newer-versions.sh, + admin-tools/check-older-versions.sh, + admin-tools/how-to-make-a-release.txt, +- admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Adminstrivia + + 2017-10-11 rocky +@@ -11428,7 +11428,7 @@ + + * HOW-TO-REPORT-A-BUG.md, test/Makefile, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Improve parse trace. lambda fixes yet again + + 2017-10-10 rocky +@@ -11438,7 +11438,7 @@ + + 2017-10-10 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: + Misc bugs + + 2017-10-10 R. Bernstein +@@ -11461,7 +11461,7 @@ + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py, + uncompyle6/version.py: Adjust for spark-parser 2.7.0 +- incompatabilities ++ incompatibilities + + 2017-10-05 rocky + +@@ -11494,7 +11494,7 @@ + + 2017-10-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: + spark-parser induced changes... reduce rules can be called without token streams. + + 2017-09-30 rocky +@@ -11518,7 +11518,7 @@ + + 2017-09-26 rocky + +- * uncompyle6/parsers/parse3.py: Pyton 3.1 Annotation args can be ++ * uncompyle6/parsers/parse3.py: Python 3.1 Annotation args can be + unicode? + + 2017-09-25 rocky +@@ -11532,7 +11532,7 @@ + 2017-09-21 rocky + + * pytest/test_pysource.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Unit test for format-specifiers And in the process we catch some small bugs + + 2017-09-20 rocky +@@ -11554,7 +11554,7 @@ + + 2017-09-20 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + More small doc changes + + 2017-09-20 rocky +@@ -11631,7 +11631,7 @@ + + 2017-08-13 rocky + +- * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: ++ * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: + 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 + '2.7.13', accept that in looking up either a scanner or a parser. + +@@ -11657,7 +11657,7 @@ + 2017-07-17 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + xdis's "exception match" is now "exception-match" + + 2017-07-15 rocky +@@ -11682,7 +11682,7 @@ + + 2017-07-09 rocky + +- * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: ++ * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 + + 2017-07-08 rocky +@@ -11697,7 +11697,7 @@ + * 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: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/scanner36.py: + Start supporting Pypy 3.5 (5.7.1-beta) + + 2017-07-05 rocky +@@ -11714,13 +11714,13 @@ + 2017-06-28 rocky + + * uncompyle6/semantics/make_function.py: A guard against badly +- formated bytecode ++ formatted 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 ++ uncompyle6/semantics/pysource.py: 3.x function and annotation bug + fixes + + 2017-06-25 rocky +@@ -11731,7 +11731,7 @@ + + * __pkginfo__.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: + Use xdis' instruction offset calculation fns.. next_offset, op_size, has_argument + + 2017-06-19 rocky +@@ -11798,7 +11798,7 @@ + 2017-06-08 rocky + + * uncompyle6/semantics/make_function.py: Correct make_function3 for +- Pytohn 3.2 ++ Python 3.2 + + 2017-06-08 rocky + +@@ -11812,7 +11812,7 @@ + + 2017-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated + properly. Better grammar structure for Python 3.6 call_function. + +@@ -11820,7 +11820,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, + uncompyle6/scanners/scanner36.py: BUILD_{MAP,TUPLE}_UNPACK & +- CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally succesfull right now. In fact a ++ CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally successful right now. In fact a + regression on one of the test cases + + 2017-06-05 rocky +@@ -11831,7 +11831,7 @@ + + 2017-06-04 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh. + + 2017-06-03 rocky +@@ -11883,7 +11883,7 @@ + + 2017-05-23 rocky + +- * uncompyle6/semantics/pysource.py: Fix up retreiving "async" ++ * uncompyle6/semantics/pysource.py: Fix up retrieving "async" + property on 3.6 + + 2017-05-23 rocky +@@ -11910,7 +11910,7 @@ + + 2017-05-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More explicit about 3.5 UNMAP_PACK Have to reduce 3.5 bytecode testing for now, code is more solid. + + 2017-05-19 rocky +@@ -11943,7 +11943,7 @@ + + 2017-05-19 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before + needing EXTENDED_ARG has been reduced to 256, but theoretically + possible in earlier versions. +@@ -11973,7 +11973,7 @@ + + 2017-05-16 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Allow LOAD_CONST EXTENDED_ARG + + 2017-05-15 rocky +@@ -12011,7 +12011,7 @@ + 2017-05-13 rocky + + * README.rst, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 MAKE_FUNCTION a bit more parse3.py, parse36.py: adding return_closure rule tags what's going + on with this rule pysource.py: start changing semantic rules to support code changed + by new make_function semantics README.rst: typo +@@ -12054,7 +12054,7 @@ + + * pytest/test_CALL_FUNCTION_KW.sh, pytest/test_function_call.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Added support for support for Python 3.6 CALL_FUNCTION_KW + + 2017-05-08 rocky +@@ -12084,7 +12084,7 @@ + + 2017-05-07 rocky + +- * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is sematically equivalent, so it is is correct. ++ * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is semantically equivalent, so it is is correct. + + 2017-05-07 rocky + +@@ -12121,7 +12121,7 @@ + + 2017-05-05 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ + + 2017-05-05 rocky +@@ -12145,7 +12145,7 @@ + 2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + BUILD_MAP_UNPACK'ing of dictionaries in 3.5 + + 2017-05-01 rocky +@@ -12159,7 +12159,7 @@ + 2017-04-29 rocky + + * test/simple_source/bug35/01_map_unpack.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Handle BUILD_MAP_UNPACK in a build_list + + 2017-04-27 rocky +@@ -12180,14 +12180,14 @@ + + 2017-04-22 rocky + +- * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduse scope ++ * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduce scope + of LOAD_ASSERT as expr to 3.4+ + + 2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/verify.py: LOAD_ASSERT can also + be an expr This may have the undesirable property that assert statements might +- get tagged with equivalant low-level Python code that uses "raise ++ get tagged with equivalent low-level Python code that uses "raise + AssertionError", but so be it. Fixes #103 + + 2017-04-22 R. Bernstein +@@ -12200,7 +12200,7 @@ + + 2017-04-22 rocky + +- * HISTORY.md: History keeps gettting amended ++ * HISTORY.md: History keeps getting amended + + 2017-04-22 rocky + +@@ -12219,7 +12219,7 @@ + 2017-04-22 rocky + + * test/simple_source/bug33/02_pos_args.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + 3.3+ bug in handling single kwarg after * Towards fixing issue #110 + + 2017-04-20 rocky +@@ -12245,7 +12245,7 @@ + + 2017-04-17 rocky + +- * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: ++ * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: + Rename test case to something more appropriate + + 2017-04-17 rocky +@@ -12306,7 +12306,7 @@ + + 2017-04-14 rocky + +- * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: ++ * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: + Better names for a test + + 2017-04-13 rocky +@@ -12326,7 +12326,7 @@ + + 2017-04-13 rocky + +- * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous + commit. + +@@ -12349,13 +12349,13 @@ + 2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Towards fixing annotated decorator functions... and annotate functions + + 2017-04-10 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: + grammar typo check_ast: add while1else to list of looping constructs + pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is +@@ -12374,7 +12374,7 @@ + 2017-04-09 rocky + + * test/simple_source/def/10_kw+pos_args-bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Another Python 3.5 FUNCTION_VAR bug Fixes #94 + + 2017-04-09 rocky +@@ -12488,7 +12488,7 @@ + + 2017-02-28 rocky + +- * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: ++ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + Python 2.6 a == b or c == d == 3 grammar bug + + 2017-02-28 rocky +@@ -12539,7 +12539,7 @@ + + 2017-02-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + Python 3.x needs more "while 1" grammar rules + + 2017-02-20 rocky +@@ -12669,7 +12669,7 @@ + + 2017-01-15 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 3.6 BUILD_CONST_KEYMAP + + 2017-01-15 rocky +@@ -12702,7 +12702,7 @@ + 2017-01-10 rocky + + * test/simple_source/bug35/03_double_star_unpack.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Improve BUILD_xxx_UNPACK slightly + + 2017-01-09 rocky +@@ -12721,7 +12721,7 @@ + + 2017-01-08 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Python 3.0 decompile bugs + + 2017-01-08 rocky +@@ -12752,7 +12752,7 @@ + 2017-01-07 rocky + + * test/simple_source/bug35/03_async_await.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Start to add 3.5+ await and async + + 2017-01-07 rocky +@@ -12770,7 +12770,7 @@ + + 2017-01-07 rocky + +- * uncompyle6/semantics/make_function.py: Small Pyhton 3.x annotate ++ * uncompyle6/semantics/make_function.py: Small Python 3.x annotate + bug + + 2017-01-03 rocky +@@ -12789,7 +12789,7 @@ + + 2017-01-02 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Python 3.5 continue detection bug + + 2017-01-01 rocky +@@ -12799,7 +12799,7 @@ + + 2017-01-01 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Towards fixing Python 3.5 return bugs + + 2017-01-01 rocky +@@ -12826,12 +12826,12 @@ + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + dectect_structure() -> detect_control_flow() + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie + + 2016-12-29 rocky +@@ -12868,7 +12868,7 @@ + 2016-12-27 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + WIP : Add THEN to disambigute from "and" + + 2016-12-27 rocky +@@ -12882,11 +12882,11 @@ + + 2016-12-26 R. Bernstein + +- * : Merge pull request #71 from jiangpengcheng/tupple_bug tupples which contain only 1 element need a comma ++ * : Merge pull request #71 from jiangpengcheng/tupple_bug tuples which contain only 1 element need a comma + + 2016-12-26 jiangpch + +- * uncompyle6/semantics/pysource.py: tupples which contain only 1 ++ * uncompyle6/semantics/pysource.py: tuples which contain only 1 + element need a comma + + 2016-12-26 rocky +@@ -12913,7 +12913,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Lint + + 2016-12-24 rocky +@@ -12930,7 +12930,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) + + 2016-12-18 rocky +@@ -12941,7 +12941,7 @@ + + 2016-12-17 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + show-asm on python2.5 is optional make scanner2 look a little more like scanner3 + + 2016-12-16 rocky +@@ -13030,7 +13030,7 @@ + + 2016-11-28 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Shorten Python3 grammars with + and * + + 2016-11-28 rocky +@@ -13069,7 +13069,7 @@ + 2016-11-24 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + 2.7 grammar bug workaround. Fix docstring bug + + 2016-11-24 rocky +@@ -13079,7 +13079,7 @@ + + 2016-11-24 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + <2.7 "if" detection and dup Python 3 grammar rule + + 2016-11-23 rocky +@@ -13162,7 +13162,7 @@ + 2016-11-20 rocky + + * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. + When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code + +@@ -13178,7 +13178,7 @@ + 2016-11-16 rocky + + * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + More AST checking Small fixes in output format + + 2016-11-15 rocky +@@ -13198,17 +13198,17 @@ + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. + + 2016-11-13 rocky +@@ -13244,7 +13244,7 @@ + 2016-11-11 rocky + + * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Revert augassign change but.. Make note of what's going on and add grammar test for bad situations + we have in Python 2.6 (and perhaps others) + +@@ -13264,7 +13264,7 @@ + 2016-11-10 rocky + + * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn + of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were + not. +@@ -13276,7 +13276,7 @@ + 2016-11-07 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py: Possiby tidy grammar ++ uncompyle6/parsers/parse32.py: Possibly tidy grammar + + 2016-11-06 rocky + +@@ -13331,13 +13331,13 @@ + + 2016-10-30 rocky + +- * .gitignore, README.rst, test/simple_source/def/03_class_method.py: ++ * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore + + 2016-10-30 rocky + + * uncompyle6/semantics/make_function.py: More source-code line +- indention in make_function.. and remove Python 3 situations from make_function2() ++ indentation in make_function.. and remove Python 3 situations from make_function2() + + 2016-10-29 rocky + +@@ -13360,20 +13360,20 @@ + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + More complete annotate handling Still have a bit of work to do though. + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, +- uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + Expand annotate return to Python 3.4 + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, +- uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little + + 2016-10-28 rocky +@@ -13386,7 +13386,7 @@ + 2016-10-27 rocky + + * test/simple_source/bug31/{04_def_attr.py => 04_def_annotate.py}, +- uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + Clean and fix Python 3 annotate arg return + + 2016-10-26 rocky +@@ -13461,7 +13461,7 @@ + 2016-10-20 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + further work on supporting single and multiple fstring decompilation + + 2016-10-20 rocky +@@ -13472,7 +13472,7 @@ + 2016-10-19 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + urther work on fstrings for python 3.6 - there is a new opcode + build_string which is used to improve fstring performance, but broke + the fstring support in uncompyle +@@ -13508,7 +13508,7 @@ + 2016-10-13 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may neeed arbitrary come_froms for each except clause ++ uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may need arbitrary come_froms for each except clause + + 2016-10-13 rocky + +@@ -13582,7 +13582,7 @@ + 2016-10-08 rocky + + * uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse21.py, +- uncompyle6/semantics/pysource.py: Simpify python 2.1 grammar Fix bug ++ uncompyle6/semantics/pysource.py: Simplify python 2.1 grammar Fix bug + with -t ... Wasn't showing source text when -t option was given + + 2016-10-08 rocky +@@ -13660,13 +13660,13 @@ + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky +@@ -13696,7 +13696,7 @@ + 2016-09-26 rocky + + * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may + need addressing. We want to process COME_FROMs to the same offset to be in + *descending* order so we have the larger range or biggest +@@ -13746,7 +13746,7 @@ + * pytest/test_grammar.py, pytest/test_single_compile.py, + test/Makefile, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py: Add COME_FROM_LOOP Note: we have regressed in --verify and some tests, but I believe +- that's because we are producing more equivalant (if uglier) ++ that's because we are producing more equivalent (if uglier) + programs. That's a separate problem though. + + 2016-09-22 rocky +@@ -13781,7 +13781,7 @@ + + 2016-09-21 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Python 2 & 3 scanner code ever so slightly closer + + 2016-09-21 rocky +@@ -13791,7 +13791,7 @@ + 2016-09-18 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + Small changes + + 2016-09-11 rocky +@@ -13802,7 +13802,7 @@ + 2016-09-11 rocky + + * test/bytecode_3.6/fstring.py, +- test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: ++ test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + Tidy a bit + + 2016-09-09 rocky +@@ -13816,7 +13816,7 @@ + + 2016-09-09 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 + + 2016-09-09 rocky +@@ -13838,7 +13838,7 @@ + + 2016-09-08 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.0-3.2 *args processing + + 2016-09-08 rocky +@@ -13874,7 +13874,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 2.6- try/except control flow detection + + 2016-09-04 rocky +@@ -13909,7 +13909,7 @@ + + * test/simple_source/bug26/07_generator_return.py, + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: A +- couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: descriminate more on parent type ++ couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: discriminate more on parent type + + 2016-09-03 rocky + +@@ -13925,7 +13925,7 @@ + + * test/simple_source/bug26/08_triple_equals.py, + uncompyle6/scanners/scanner2.py: Python 2.2..2.6 bug in a == b == c +- == d Fix was to remove some come froms. Feels a little hacky though. ++ == d Fix was to remove some COME_FROMS. Feels a little hacky though. + + 2016-09-03 rocky + +@@ -13949,19 +13949,19 @@ + 2016-09-02 rocky + + * test/simple_source/bug26/06_return_pop.py, +- uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning + + 2016-09-02 rocky + + * test/simple_source/bug33/02_named_and_kwargs.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x named param and kwargs bug + + 2016-09-01 rocky + + * test/simple_source/bug26/04_while_and_stmt_one_line.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute + a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. + In Python 2.7+ it's a single op. +@@ -13969,7 +13969,7 @@ + 2016-09-01 rocky + + * test/simple_source/bug26/02_except_as.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Handle Python 2.6 and below "except , " + + 2016-08-31 rocky +@@ -13985,7 +13985,7 @@ + uncompyle6/scanners/scanner3.py, uncompyle6/verify.py: Bug in 3.x + detecting "if" structure and ... scanner3.py: bug in 3.x detecting "if" structure Make scanner2.py + look more like scanner3.py verify.py: add weak-verify which tests +- Pytyon syntax, but not code ++ Python syntax, but not code + + 2016-08-30 rocky + +@@ -14111,7 +14111,7 @@ + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, + uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling + + 2016-08-11 Omer Katz +@@ -14180,7 +14180,7 @@ + 2016-07-29 rocky + + * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. + + 2016-07-28 Daniel Bradburn +@@ -14279,13 +14279,13 @@ + + 2016-07-27 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + Small code clean up + + 2016-07-26 rocky + + * uncompyle6/scanners/tok.py, uncompyle6/semantics/fragments.py, +- uncompyle6/verify.py: Usuability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function ++ uncompyle6/verify.py: Usability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function + + 2016-07-26 rocky + +@@ -14307,7 +14307,7 @@ + test/simple_source/bug_pypy27/03_try_return.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules + + 2016-07-25 rocky +@@ -14369,7 +14369,7 @@ + * README.rst, test/simple_source/stmts/03_if_elif.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little + + 2016-07-25 rocky +@@ -14391,7 +14391,7 @@ + test/Makefile, test/test_pythonlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy + + 2016-07-24 Daniel Bradburn +@@ -14411,19 +14411,19 @@ + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky +@@ -14472,7 +14472,7 @@ + + 2016-07-17 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Adjust test data for changed disasm output + + 2016-07-16 rocky +@@ -14506,14 +14506,14 @@ + + 2016-07-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we + understand better what to do though, we'll go with it. + + 2016-07-14 rocky + + * test/Makefile, uncompyle6/semantics/pysource.py: 3.x __qualname__ +- = supression Class names have become more complicated so the pattern test needs ++ = suppression Class names have become more complicated so the pattern test needs + to be more complex as well. Sigh + + 2016-07-14 rocky +@@ -14576,7 +14576,7 @@ + + * test/simple_source/bug33/05_store_name.py, + test/simple_source/comprehension/05_3x_set_comphension.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 & 3.3 handle STORE_NAME better + + 2016-07-11 rocky +@@ -14631,13 +14631,13 @@ + + 2016-07-10 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Bugs caused by 3.x jump_forward misclasification + + 2016-07-10 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification + + 2016-07-09 rocky +@@ -14728,7 +14728,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Python 3 code cleanup + + 2016-07-08 rocky +@@ -14749,7 +14749,7 @@ + 2016-07-08 rocky + + * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + Python 2.4 generator expressions and gen_comp_body + + 2016-07-08 rocky +@@ -14765,7 +14765,7 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/semantics/pysource.py: Start handling Pyton 2.4 bytecodes ++ uncompyle6/semantics/pysource.py: Start handling Python 2.4 bytecodes + + 2016-07-08 rocky + +@@ -14775,12 +14775,12 @@ + 2016-07-08 rocky + + * test/simple_source/stmts/11_return_val.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.5/2.6 RETURN_VALUE bug + + 2016-07-08 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + 2.5/2.6 fn name clash fixes list conprehension problem + + 2016-07-08 rocky +@@ -14808,7 +14808,7 @@ + + 2016-07-07 rocky + +- * : Remove 2.7 asynchat verifcation for now ++ * : Remove 2.7 asynchat verification for now + + 2016-07-07 rocky + +@@ -14822,7 +14822,7 @@ + + 2016-07-07 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + <2.6 make sure jump back on loops is really "back" + + 2016-07-07 rocky +@@ -14869,7 +14869,7 @@ + + * uncompyle6/semantics/fragments.py, + uncompyle6/semantics/pysource.py: More offsets captrued Add %b +- specifer %b - associate text before specifier pysource.py: small doc ++ specifier %b - associate text before specifier pysource.py: small doc + correction + + 2016-07-03 rocky +@@ -14881,12 +14881,12 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Another 2.6 while stmt. Clean up grammar a little + + 2016-07-03 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + 2.6 improper tagging of RETURN_END_IF + + 2016-07-02 rocky +@@ -14923,7 +14923,7 @@ + 2016-06-30 rocky + + * test/simple_source/stmts/06_for_break.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else + + 2016-06-30 rocky +@@ -14940,13 +14940,13 @@ + 2016-06-30 rocky + + * test/simple_source/comprehension/05_for_for.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6.9 list comprehension + + 2016-06-30 rocky + + * test/simple_source/exception/07_try_pass.py, +- uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in tey/except blocks ++ uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in try/except blocks + + 2016-06-30 rocky + +@@ -14982,7 +14982,7 @@ + + 2016-06-28 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Weird 2.6.9 list comprehension + + 2016-06-28 rocky +@@ -14999,17 +14999,17 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Base 2.5 off of 2.6. Some other small bugs. + + 2016-06-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py: 2.6 try +- except hadnling works now ++ except handling works now + + 2016-06-27 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6 list comprehensions + + 2016-06-27 rocky +@@ -15029,8 +15029,8 @@ + + 2016-06-24 rocky + +- * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 psuedo bytecode I think +- is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better assocate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental ++ * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 pseudo bytecode I think ++ is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better associate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental + changes to get say from python 2.3 bytecode to python 2.7 are + great. Conflicts: uncompyle6/parsers/astnode.py + +@@ -15040,7 +15040,7 @@ + + 2016-06-24 rocky + +- * uncompyle6/scanners/scanner2.py: Small formating changes ... and premonition of 2.6 byteocde work ++ * uncompyle6/scanners/scanner2.py: Small formatting changes ... and premonition of 2.6 byteocde work + + 2016-06-24 rocky + +@@ -15052,7 +15052,7 @@ + * __pkginfo__.py, uncompyle6/parsers/astnode.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 psuedo bytecode. Instead ++ uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 pseudo bytecode. Instead + adjust grammar and semantic actions. Down the line we should to segregate version changes in semantic + code better. + +@@ -15094,7 +15094,7 @@ + 2016-06-22 rocky + + * test/simple_source/expression/05_yield_from.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + differing ways to do "yield from" in 3.3-3.5 + + 2016-06-22 rocky +@@ -15103,7 +15103,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option + + 2016-06-22 rocky +@@ -15113,7 +15113,7 @@ + + 2016-06-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More 3.2 LOAD_CONST removal More python3 custom grammar DRYing + + 2016-06-22 rocky +@@ -15125,7 +15125,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/simple_source/expression/10_lambda.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 MAKE_FUNCTION adjustment + + 2016-06-22 rocky +@@ -15144,18 +15144,18 @@ + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Bang on Python 3.2 decompiling. + + 2016-06-20 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + previous 2.7 class decorator bug fixed in 3.x + + 2016-06-20 rocky +@@ -15187,7 +15187,7 @@ + + * test/simple_source/def/11_mkfunc_closure.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 3.x make closure kw args handling bug + + 2016-06-20 rocky +@@ -15224,7 +15224,7 @@ + * test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 2.7 and 3.x bug in dict comprehensions + + 2016-06-19 rocky +@@ -15242,7 +15242,7 @@ + + * test/simple_source/looping/08_while_except_bug.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 except clause parsing bug + + 2016-06-19 rocky +@@ -15304,18 +15304,18 @@ + * pytest/test_deparse.py, + test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 + + 2016-06-06 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + small changes + + 2016-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + include offset for starting listcomp + + 2016-06-03 rocky +@@ -15337,7 +15337,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Limited support for Python 2.3 + + 2016-06-03 rocky +@@ -15435,7 +15435,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Bang again on Python 2.5 and 2.6 scanners + + 2016-05-29 rocky +@@ -15447,7 +15447,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. + + 2016-05-29 rocky +@@ -15464,7 +15464,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + DRY scanners more + + 2016-05-28 rocky +@@ -15479,7 +15479,7 @@ + * test/simple_source/comprehension/06_list_ifnot.py, + test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Remove dis3. Fix in 3.x list if not comprehension + + 2016-05-28 rocky +@@ -15490,7 +15490,7 @@ + 2016-05-28 rocky + + * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, +- uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + Remove dup 3.x opcodes + + 2016-05-28 rocky +@@ -15500,7 +15500,7 @@ + 2016-05-28 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, +- uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + xdis for Python 3 opcodes + + 2016-05-28 rocky +@@ -15545,7 +15545,7 @@ + test/simple_source/def/06_return_bug.py, + uncompyle6/semantics/pysource.py: final RETURN removal bug We want to remove a final return from a module, but otherwise not. + Note we'll no lonager be able to verify functools.pyc as there is +- now a return after a raise statement. That will have to be delt with ++ now a return after a raise statement. That will have to be dealt with + separately. May address Issue #17. + + 2016-05-22 rocky +@@ -15591,7 +15591,7 @@ + 2016-05-20 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to igore fragment stuff ++ uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to ignore fragment stuff + + 2016-05-19 rocky + +@@ -15602,7 +15602,7 @@ + 2016-05-18 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: ++ test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + Handle marshal frozenset + + 2016-05-18 rocky +@@ -15642,14 +15642,14 @@ + 2016-05-17 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: ++ test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + Fix marshal bug in handling complex numbers + + 2016-05-17 rocky + + * Makefile, test/simple_source/def/09_class_closure.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS + + 2016-05-16 rocky +@@ -15665,7 +15665,7 @@ + + 2016-05-16 rocky + +- * : Readd some 3.x loop tests ++ * : Re-add some 3.x loop tests + + 2016-05-16 rocky + +@@ -15719,7 +15719,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix bug in Python 3 lambda expression handling Some other small cleanup changes + + 2016-05-15 rocky +@@ -15727,7 +15727,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + pydisassemble disassemble without grammar mangling Some other small cleanups as well + + 2016-05-15 rocky +@@ -15767,7 +15767,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs + + 2016-05-15 rocky +@@ -15776,7 +15776,7 @@ + + 2016-05-14 rocky + +- * test/Makefile, uncompyle6/scanners/dis3.py: Python2 comptability ++ * test/Makefile, uncompyle6/scanners/dis3.py: Python2 compatibility + in using Python 3 disassembly Also fixes ablility to run bytecode 3.5 tests from 2.x now For Python 2 reading python3 bytstrings, we need to make sure we + confer the character to a number. + +@@ -15800,7 +15800,7 @@ + 2016-05-14 rocky + + * ChangeLog, __pkginfo__.py, uncompyle6/version.py: Fix botched +- entry point names Get ready for relase 2.3.6 ++ entry point names Get ready for release 2.3.6 + + 2016-05-14 rocky + +@@ -15839,7 +15839,7 @@ + 2016-05-12 rocky + + * uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + More small changes + + 2016-05-12 rocky +@@ -15856,7 +15856,7 @@ + + * __pkginfo__.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires + sparck 1.2.0) * some optimization in scanner3 + +@@ -15870,7 +15870,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, + uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Redo make_function for *, arg main(*, file='foo') and things like that now work + + 2016-05-11 rocky +@@ -15902,7 +15902,7 @@ + 2016-05-09 rocky + + * test/simple_source/stmts/09_whiletrue_bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 "while True" bug + + 2016-05-09 rocky +@@ -15972,7 +15972,7 @@ + + * test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/main.py, uncompyle6/parser.py: come_from_opt handles +- and/or precidence properly main.py: give a better error message when file is not found. ++ and/or precedence properly main.py: give a better error message when file is not found. + + 2016-05-08 rocky + +@@ -15996,7 +15996,7 @@ + + * HISTORY.md, test/simple_source/branching/10_if_pass.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections + + 2016-05-08 rocky +@@ -16013,7 +16013,7 @@ + + * test/simple_source/expression/05_yield_from.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. + + 2016-05-06 rocky +@@ -16042,7 +16042,7 @@ + test/simple_source/stmts/10_if_break_finally.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: More +- Python 2 and 3 deparsing bugs fixed * while + if break * try + finall /pass ++ Python 2 and 3 deparsing bugs fixed * while + if break * try + finally pass + + 2016-05-05 rocky + +@@ -16078,19 +16078,19 @@ + 2016-05-05 rocky + + * test/simple_source/def/05_abc_class.py, +- test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + Python 3.5 abc.py bug distilled + + 2016-05-05 rocky + +- * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: ++ * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + Add cross-Python-protable 3.5 dis module + + 2016-05-04 rocky + + * test/simple_source/stmts/05_with.py, + uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo + + 2016-05-03 rocky +@@ -16100,7 +16100,7 @@ + 2016-05-03 rocky + + * uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Don't repeat next_except_jump + + 2016-05-03 rocky +@@ -16150,7 +16150,7 @@ + + * ChangeLog, NEWS, __pkginfo__.py, bin/pydisassemble, + bin/uncompyle6, setup.py, uncompyle6/__init__.py, +- uncompyle6/version.py: Add -V | --version and simplfy changing it ++ uncompyle6/version.py: Add -V | --version and simplify changing it + + 2016-05-01 rocky + +@@ -16212,13 +16212,13 @@ + + 2016-04-30 rocky + +- * uncompyle6/parsers/parse3.py: Python 3.5 if statments decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 ++ * uncompyle6/parsers/parse3.py: Python 3.5 if statements decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 + + 2016-04-28 rocky + + * requirements.txt, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + spark -> spark_parser + + 2016-04-28 rocky +@@ -16366,7 +16366,7 @@ + 2016-01-02 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Make ScannerXX() initialization the same on Python 2.x and 3.x + + 2016-01-02 rocky +@@ -16460,7 +16460,7 @@ + 2015-12-31 rocky + + * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3.3 > dotted class names + + 2015-12-30 rocky +@@ -16483,7 +16483,7 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Remove accidental schmutz. Try using pattr on 3.4 to get fn names + + 2015-12-30 rocky +@@ -16523,14 +16523,14 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py: Tidy parse3 grammer a little ++ * uncompyle6/parsers/parse3.py: Tidy parse3 grammar a little + + 2015-12-30 rocky + + * test/simple_source/exception/25_try_except.py, + test/test_pythonlib.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + Towards Python3 getting try/except working more often. + + 2015-12-29 rocky +@@ -16563,7 +16563,7 @@ + + * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, + uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + scanner3: Python 2.6 compatibility: change set initializations. Get + rid of * import opcode_*: only a little of the much-needed larger + cleanup Makefile: remove 3.x bytecode checking from Python 2.x for +@@ -16582,7 +16582,7 @@ + + * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python3 marshal codes and start to handle cross-version Python + code object types, introducing scan.Code3 + +@@ -16632,7 +16632,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16648,7 +16648,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16708,9 +16708,9 @@ + test/simple_source/{simple_stmts => stmts}/15_assert.py, + test/simple_source/stmts/15_for_if.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE +- get jump offsets into jump attributes. Fix up 3.2 scanner paritally ++ get jump offsets into jump attributes. Fix up 3.2 scanner partially + and use that in 3.4 for in cross version disassembly. + + 2015-12-26 rocky +@@ -16747,7 +16747,7 @@ + 2015-12-25 rocky + + * .gitignore, ChangeLog, MANIFEST.in, NEWS, __pkginfo__.py, +- test/Makefile: Get ready for releaes 2.0.0 ++ test/Makefile: Get ready for release 2.0.0 + + 2015-12-25 rocky + +@@ -16777,7 +16777,7 @@ + + * pytest/test_load.py, test/dis-compare.py, uncompyle6/disas.py, + uncompyle6/load.py, uncompyle6/main.py, uncompyle6/verify.py: Show +- embeded timestamp of byte-decompiled file ++ embedded timestamp of byte-decompiled file + + 2015-12-23 rocky + +@@ -16792,7 +16792,7 @@ + + * test/simple_source/simple_stmts/00_import.py, + test/simple_source/simple_stmts/00_pass.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start Python3 class(superclass) handling + + 2015-12-23 rocky +@@ -16808,13 +16808,13 @@ + + 2015-12-23 rocky + +- * uncompyle6/semantics/fragments.py: Add fragmnet offsets for 'from ++ * uncompyle6/semantics/fragments.py: Add fragment offsets for 'from + x import..' + + 2015-12-22 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Propogate offsets in imports. ++ uncompyle6/semantics/pysource.py: Propagate offsets in imports. + Added a new %x format specifier. + + 2015-12-22 rocky +@@ -16826,7 +16826,7 @@ + uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Allow comments in grammar rules. Start working on Python3 class (not + finished). More test organization. + +@@ -16835,7 +16835,7 @@ + * test/simple_source/def/01_class.py, + test/simple_source/def/10_class.py, + uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/parsers/parse3.py: Remove Python2 buitin "print" from ++ uncompyle6/parsers/parse3.py: Remove Python2 builtin "print" from + Python3's grammr. Start class tests + + 2015-12-22 rocky +@@ -16843,7 +16843,7 @@ + * bin/uncompyle6, uncompyle6/main.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/spark.py, + uncompyle6/semantics/pysource.py: main.py, pysource.py DRY +- deparse_code from main. Is better on showing exception errrors such ++ deparse_code from main. Is better on showing exception errors such + as when a pyc file is not found uncompyle6: Hook in --grammar option + to showing grammar. rules. Default now does not show timestamp. + +@@ -16870,7 +16870,7 @@ + test/simple_source/slice/{01_slice.py => 02_slice.py}, + uncompyle6/main.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/spark.py, uncompyle6/semantics/pysource.py: Add +- spark option to show grammer. Revise uncompyle options. Start to ++ spark option to show grammar. Revise uncompyle options. Start to + reorganize tests more + + 2015-12-21 rocky +@@ -16908,8 +16908,8 @@ + test/simple_source/exception/01_try_except.py, + test/simple_source/misc/assign_none_str.py, + test/simple_source/{misc/assign.py => simple_stmts/00_assign.py}, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: +- Start Python3 execption handling ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ Start Python3 exception handling + + 2015-12-21 rocky + +@@ -17019,7 +17019,7 @@ + + * test/Makefile, test/simple-source/misc/assign_none.py, + test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Python 3 decompilation from Python2 + + 2015-12-20 rocky +@@ -17037,7 +17037,7 @@ + 2015-12-20 rocky + + * Makefile, README.rst, test/Makefile, test/dis-compare.py, +- uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: ++ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + Go over makefiles to make "make check" work. walker, deparser: use + zip_longest + +@@ -17048,8 +17048,8 @@ + + 2015-12-19 rocky + +- * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatiblity +- for getting precidence. n_mkfunc needs to key off of bytecode ++ * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatibility ++ for getting precedence. n_mkfunc needs to key off of bytecode + version, not running Python version. + + 2015-12-19 rocky +@@ -17107,7 +17107,7 @@ + test/simple-source/precedence/left.py, + test/simple-source/precedence/right.py, + test/simple-source/precedence/structure.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + Python 3 bytecode handles opcodes with varargs (better). Decompiling + assert works. Add more of the simple tests and their compiled + bytecode. +@@ -17135,7 +17135,7 @@ + uncompyle6/scanners/scanner34.py: marshal.py: Python2 marshal code + shouldn't try to turn a code object into a string. parse3.py: handle + both keyword and positional function calls. scanner34.py: Remove +- extra level of quoting in LOAD_CONST. Keyward handling now works ++ extra level of quoting in LOAD_CONST. Keyword handling now works + cross Python 2/3. Some other spelling and doc fixes. + + 2015-12-18 rocky +@@ -17144,12 +17144,12 @@ + uncompyle6/disas.py, uncompyle6/parser.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/walker.py: Python3 postional arguments. Clean up code ++ uncompyle6/walker.py: Python3 positional arguments. Clean up code + more along the lines of uncompyle3. + + 2015-12-18 rocky + +- * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: ++ * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + disas.py: Do better for finding/turning a .py file into a .pyc file + across supported versions of Python. Add for else list comprehension + test +@@ -17185,7 +17185,7 @@ + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/verify.py: Python 2.6 compatability via ericfrederich's ++ uncompyle6/verify.py: Python 2.6 compatibility via ericfrederich's + patch. DRY version-checking code + + 2015-12-17 rocky +@@ -17237,12 +17237,12 @@ + test/simple-source/branching/ifelse.py, + test/simple-source/looping/for.py, uncompyle6/__init__.py, + uncompyle6/disas.py, uncompyle6/parsers/spark.py: Add spark grammar +- debugging. Start to comment grammer construct covered by simple ++ debugging. Start to comment grammar construct covered by simple + tests. + + 2015-12-17 rocky + +- * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + Python 3.4 correct grammar for some looping constructs + + 2015-12-17 rocky +@@ -17275,14 +17275,14 @@ + 2015-12-16 rocky + + * uncompyle6/deparser.py, uncompyle6/disas.py, +- uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: ++ uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + Add LICENSE. Add demo programs and DRY code a little + + 2015-12-16 rocky + + * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + On Python3.4 decompiling Python 3.4 instructions, use its built-in + disassembler routines. In contrast to what was here, they most + likely work! +@@ -17305,7 +17305,7 @@ + test/source_3.4/branching/ifelse.py, uncompyle6/.gitignore, + uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Start 3.4 more stringent disassembly testing. Disassembly format has + changed slightly. misc small bugs. + +@@ -17338,7 +17338,7 @@ + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Split out marhsal and disassemble code and spell disassemble + correctly. Fix some lint issues + +@@ -17423,7 +17423,7 @@ + + 2015-12-14 rocky + +- * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: ++ * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: + uncompyle6/dparser -> uncompyle6/parser + + 2015-12-14 rocky +@@ -17529,7 +17529,7 @@ + test/ok_2.7/asynchat.pyc_dis, test/ok_2.7/asyncore.pyc_dis, + test/ok_2.7/atexit.pyc_dis, test/ok_2.7/audiodev.pyc_dis, + test/test_pythonlib.py, uncompyle6/walker.py: test_pythonlib: Fix +- bug in traversing directores walker.py: imports; Add test Python2.5 ++ bug in traversing directories walker.py: imports; Add test Python2.5 + bytecode - it works! Makefile: remove temporary directories and _dis + files which were added by mistake + +@@ -17601,7 +17601,7 @@ + * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, + uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, +- uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + Correct MANIFEST->MANIFEST.in more lint + + 2015-12-13 R. Bernstein +@@ -17618,7 +17618,7 @@ + uncompyle6/__init__.py, uncompyle6/disas.py, + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/scanner25.py, uncompyle6/scanner26.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our + own disassembler. Python's will do fine + +@@ -17704,7 +17704,7 @@ + + * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, + uncompyle6/scanner25.py, uncompyle6/scanner27.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + Minimal disassemble, ast compile and deparse work on Python 3. Some + linting + +@@ -17719,7 +17719,7 @@ + uncompyle6/scanner.py, uncompyle6/scanner25.py, + uncompyle6/scanner26.py, uncompyle6/scanner27.py, + uncompyle6/verify.py, uncompyle6/walker.py: More Python3 +- compatability. Remove duplicate disassembly code and get it from ++ compatibility. Remove duplicate disassembly code and get it from + Python's standard library instead. + + 2015-12-12 rocky +@@ -17729,7 +17729,7 @@ + + 2015-12-11 rocky + +- * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: ++ * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + python3 compatibiity and remove some flake8 warnings. + + 2015-12-11 rocky +@@ -17804,7 +17804,7 @@ + 2013-07-16 root + + * uncompyle2/__init__.py, uncompyle2/disas.py, +- uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: ++ uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + marshal disassembly improvement + + 2013-06-20 Mysterie +@@ -17992,4 +17992,3 @@ + 2012-06-05 Mysterie + + * first commit +- diff --git a/Makefile b/Makefile index bd5703341..b409121a1 100644 --- a/Makefile +++ b/Makefile @@ -131,5 +131,6 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff .PHONY: $(PHONY) diff --git a/NEWS.md b/NEWS.md index 6a7c23004..b3f1e67bd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +3.9.3: 2025-09-28 +================= + +- Python 3.9+ tolerance and modern Python packaging, sigh. +- Don't update global tables, copy them instead; Use a single TABLE copy (gdesmar) +- Correct print_docstring()'s `docstring.find(quote) +- short options -h and -v now do the right thing. + 3.9.2: 2024-07-21 ================= diff --git a/admin-tools/check-3.6-3.10-versions.sh b/admin-tools/check-3.6-3.10-versions.sh new file mode 100644 index 000000000..99fb08fa3 --- /dev/null +++ b/admin-tools/check-3.6-3.10-versions.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Run tests over all Python versions in branch python-3.3-3.5 +set -e +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-3.3-3.5-versions ; then + exit $? +fi +if ! source ./setup-python-3.3.sh ; then + exit $? +fi + +cd .. +for version in $PYVERSIONS; do + echo --- $version --- + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check ; then + exit $? + fi + echo === $version === +done +finish diff --git a/admin-tools/checkout_common.sh b/admin-tools/checkout_common.sh index c5ffd7f4e..ed45465b2 100644 --- a/admin-tools/checkout_common.sh +++ b/admin-tools/checkout_common.sh @@ -17,5 +17,6 @@ function checkout_finish { cd $uncompyle6_owd git checkout $branch && pyenv local $PYTHON_VERSION && git pull rc=$? + pyenv local $PYTHON_VERSION return $rc } diff --git a/admin-tools/pyenv-3.6-3.10-versions b/admin-tools/pyenv-3.6-3.10-versions new file mode 100644 index 000000000..aa7eabca6 --- /dev/null +++ b/admin-tools/pyenv-3.6-3.10-versions @@ -0,0 +1,8 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the master branch. +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='3.6 pypy3.6 pypy3.7 pypy3.810 pyston-2.3.5 3.8 3.9 3.10' diff --git a/admin-tools/pyenv-newest-versions b/admin-tools/pyenv-newest-versions index b8dd8d584..aeac11e36 100644 --- a/admin-tools/pyenv-newest-versions +++ b/admin-tools/pyenv-newest-versions @@ -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.6.15 pypy3.6-7.3.1 3.7.16 pypy3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.18' +export PYVERSIONS='3.11 3.12 3.13' diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index f1d41ebf4..18fee07c2 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -7,6 +7,7 @@ if [[ $0 == $bs ]] ; then fi PYTHON_VERSION=3.3 +pyenv local $PYTHON_VERSION uncompyle6_owd=$(pwd) mydir=$(dirname $bs) diff --git a/test/Makefile b/test/Makefile index 83f713e15..4e941f83b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -80,11 +80,9 @@ check-3.8: check-bytecode $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE) -check-3.9: check-bytecode - @echo "Note that we do not support decompiling Python 3.9 bytecode - no 3.9 tests run" +check-3.9 check-3.10 check-3.11 check-3.12 check-3.13: check-bytecode + @echo "Note that we do not support decompiling this version's bytecode - no 3.9 tests run" -check-3.10: check-bytecode - @echo "Note that we do not support decompiling Python 3.10 bytecode - no 3.10 tests run" # FIXME #: this is called when running under pypy3.5-5.8.0, pypy2-5.6.0, pypy3.6-7.3.0 or pypy3.8-7.3.7 @@ -317,6 +315,10 @@ check-bytecode-3.8: $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify +#: Check deparsing Python 3.8 +check-bytecode-3.9 check-bytecode-3.10 check-bytecode-3.11 check-bytecode-3.12 check-bytecode-3.13: + @echo "We don't support decompiling this bytecode for this version" + #: short tests for bytecodes only for this version of Python check-native-short: $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --syntax-verify $(COMPILE) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 4cf2974e4..fbfcd30e2 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.3.dev0" # noqa +__version__="3.9.3" # noqa From 0c071ad17a74c160d96f0c7f0022736b00a1bad9 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Sep 2025 17:45:45 -0400 Subject: [PATCH 460/489] Get ready for release 3.9.3 --- .gitignore | 2 + ChangeLog-spell-corrected.diff | 4381 ++++++++++++++++++++++++ Makefile | 1 + NEWS.md | 8 + admin-tools/check-3.3-3.5-versions.sh | 0 admin-tools/check-3.6-3.10-versions.sh | 30 + admin-tools/checkout_common.sh | 1 + admin-tools/pyenv-3.6-3.10-versions | 8 + admin-tools/pyenv-newest-versions | 2 +- admin-tools/setup-python-3.3.sh | 1 + test/Makefile | 10 +- uncompyle6/version.py | 2 +- 12 files changed, 4440 insertions(+), 6 deletions(-) create mode 100644 ChangeLog-spell-corrected.diff mode change 100644 => 100755 admin-tools/check-3.3-3.5-versions.sh create mode 100755 admin-tools/check-3.6-3.10-versions.sh create mode 100644 admin-tools/pyenv-3.6-3.10-versions diff --git a/.gitignore b/.gitignore index 752d3a7e4..6a2a97741 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ /.python-version /.tox /.venv* +/ChangeLog-spell-corrected +/ChangeLog.orig /README /__pkginfo__.pyc /dist diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 000000000..b0afc14f5 --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,4381 @@ +--- ChangeLog 2025-09-28 18:50:06.933864316 -0400 ++++ ChangeLog-spell-corrected 2025-09-28 18:49:47.641822080 -0400 +@@ -87,7 +87,7 @@ + + 2024-12-12 rocky + +- * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: ++ * .pre-commit-config.yaml, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-12-02 rocky +@@ -113,7 +113,7 @@ + + 2024-11-28 rocky + +- * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Don't remove LOAD_CONST RETURN_VALUE when... the LOAD_CONST has a non-None value, or the LOAD_CONST has a line + associated with it. + +@@ -148,7 +148,7 @@ + uncompyle6/semantics/customize36.py, + uncompyle6/semantics/customize37.py, + uncompyle6/semantics/customize38.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Don't update global tables... Work off of copies of them instead. Issue #503 + + 2024-11-09 rocky +@@ -195,12 +195,12 @@ + + 2024-10-04 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Track branch changes in python-spark + + 2024-09-21 rocky + +- * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: ++ * admin-tools/.gitignore, admin-tools/setup-python-3.3.sh: + Adminsitrivia + + 2024-09-21 rocky +@@ -222,13 +222,13 @@ + 2024-07-22 rocky + + * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky + + * admin-tools/checkout_common.sh, admin-tools/setup-master.sh, +- admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-07-22 rocky +@@ -237,7 +237,7 @@ + + 2024-07-21 rocky + +- * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: ++ * NEWS.md, pyproject.toml, requirements.txt, uncompyle6/version.py: + Get ready for release 3.9.2 + + 2024-07-21 rocky +@@ -274,7 +274,7 @@ + + 2024-07-15 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + Handle long dict litereals in 3.4- better... Bracket in pseudo op COLLECTION_START ... BUILD_xx + + 2024-07-14 rocky +@@ -287,7 +287,7 @@ + 2024-07-13 rocky + + * test/simple_source/bug34/03_ifelse_in_lambda.py, +- uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py: + Improve 3.4 ifelse inside a lambda Fixes #426 + + 2024-07-13 rocky +@@ -339,7 +339,7 @@ + + * uncompyle6/parsers/reducecheck/tryexcept.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/aligner.py, uncompyle6/semantics/linemap.py: + Python 2.5 try/except reduce fix Start getting aligner up to date + + 2024-07-12 rocky +@@ -361,7 +361,7 @@ + 2024-07-12 rocky + + * test/simple_source/bug25/06_if_and_bugs.py, +- uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: ++ uncompyle6/parsers/parse25.py, uncompyle6/semantics/customize25.py: + Fix some 2.5 parsing bugs + + 2024-07-12 rocky +@@ -417,7 +417,7 @@ + + 2024-06-03 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37base.py: + Use set literals + + 2024-06-03 rocky +@@ -467,7 +467,7 @@ + 2024-03-14 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Name phases "disassembly" and "tokenization" + + 2024-03-14 rocky +@@ -478,7 +478,7 @@ + uncompyle6/parsers/reducecheck/ifstmts_jump.py, + uncompyle6/scanners/scanner37base.py, + uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/make_function2.py: Mis spelling corrections ++ uncompyle6/semantics/make_function2.py: Spelling corrections + + 2024-03-13 rocky + +@@ -561,7 +561,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37.py, uncompyle6/semantics/pysource.py, +- uncompyle6/semantics/transform.py: mark "psuedo ops" ++ uncompyle6/semantics/transform.py: mark "pseudo ops" + + 2024-02-24 rocky + +@@ -580,7 +580,7 @@ + test/stdlib/3.8-exclude.sh, test/stdlib/runtests.sh, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py, + uncompyle6/scanners/scanner37base.py, uncompyle6/scanners/tok.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/n_actions.py: + Keep optype info in token... It is useful for ADD_VALUE + + 2024-02-24 rocky +@@ -595,12 +595,12 @@ + + 2024-02-24 rocky + +- * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: ++ * admin-tools/setup-python-3.0.sh, admin-tools/setup-python-3.3.sh: + Administrivia + + 2024-02-24 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia + + 2024-02-24 rocky +@@ -671,7 +671,7 @@ + + 2024-02-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/n_actions.py: + Bugs found in 3.0 decomplation... parsers/parse30.py; fix set comprehension grammar bug + uncompyle6/semantics/n_actions.py: evidence of the evils of + modifying node data (via node.pop) +@@ -691,7 +691,7 @@ + + * uncompyle6/bin/uncompile.py, uncompyle6/main.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner33.py: + Handle 3.3 MAKE_FUNCTION annotation args properly + + 2024-02-11 rocky +@@ -766,7 +766,7 @@ + 2024-02-03 rocky + + * .gitignore, test/test_pythonlib.py, uncompyle6/main.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + lint + + 2024-02-03 rocky +@@ -776,7 +776,7 @@ + 2024-02-03 rocky + + * uncompyle6/main.py, uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + Fix up linemap option + + 2024-01-19 R. Bernstein +@@ -848,7 +848,7 @@ + + 2023-08-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py: + comprehension in lambda for 3.0 & 3.1 + + 2023-08-12 R. Bernstein +@@ -873,7 +873,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize37.py: + chained-compare1 -> chained-compare-middle + + 2023-07-07 rocky +@@ -929,7 +929,7 @@ + * admin-tools/setup-master.sh, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse33.py, uncompyle6/parsers/parse34.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: ++ uncompyle6/semantics/gencomp.py, uncompyle6/semantics/n_actions.py: + Correct generator function parsing for 3.3..3.5 + + 2023-06-29 rocky +@@ -1051,7 +1051,7 @@ + + * uncompyle6/scanners/tok.py: self.opc.version -> + self.opc.version_tuple The next release of xdis will no longer support self.opc.version (a +- float value which doesn't work in the presense of 3.10 and above) ++ float value which doesn't work in the presence of 3.10 and above) + + 2023-01-16 rocky + +@@ -1089,7 +1089,7 @@ + 2023-01-14 rocky + + * uncompyle6/parser.py, uncompyle6/scanners/scanner3.py: 3.4-3.5 +- MAKE_CLOSURE with annotate Docs lie about annnotation args. Slight adjustment here. More is ++ MAKE_CLOSURE with annotate Docs lie about annotation args. Slight adjustment here. More is + probably needed. + + 2022-12-22 rocky +@@ -1199,7 +1199,7 @@ + 2022-11-04 rocky + + * admin-tools/{pyenv-3.1-3.2-versions => pyenv-3.0-3.2-versions}, +- admin-tools/setup-python-3.0.sh: Alow 3.0 setup ++ admin-tools/setup-python-3.0.sh: Allow 3.0 setup + + 2022-11-04 rocky + +@@ -1207,7 +1207,7 @@ + + 2022-11-04 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/gencomp.py: + Correct 3.0 list comprehension parsing + + 2022-11-03 rocky +@@ -1311,7 +1311,7 @@ + + 2022-09-21 rocky + +- * uncompyle6/semantics/pysource.py: Hande Python 3.5 make_function() ++ * uncompyle6/semantics/pysource.py: Handle Python 3.5 make_function() + semantic action Fixes #409 + + 2022-09-20 rocky +@@ -1448,7 +1448,7 @@ + 2022-06-16 rocky + + * test/simple_source/bug38/00_while_true_pass.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Python 3.8 while and whileTrue loops + + 2022-06-08 rocky +@@ -1470,9 +1470,9 @@ + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml, admin-tools/pyenv-newest-versions, +- test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: ++ test/stdlib/3.7-exclude.sh, uncompyle6/scanners/pypy38.py: + Administrivia Workflows CI: go back to released versions rather than github +- versions pyenv-newest-versions: updaed to use newest Python releases ++ versions pyenv-newest-versions: updated to use newest Python releases + pypy38.py: fix wrong package name import 3.6-exclude.sh: update and + advance + +@@ -1549,13 +1549,13 @@ + * uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/parsers/parse38.py, + uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/gencomp.py: + Start rolling in LOAD_ARG for 3.7+ + + 2022-05-05 rocky + + * test/simple_source/bug36/03_async_from_coroutine.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Fix More 3.6 async parsing ... all from 3.6 test_coroutines.py. More bugs remain + + 2022-05-05 rocky +@@ -1639,12 +1639,12 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner37.py: + Handle long 2.x bytecode literals more efficiently + + 2022-04-27 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + Small doc corrections + + 2022-04-27 rocky +@@ -1681,7 +1681,7 @@ + 2022-04-25 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner37.py: + WIP - extend fast long-literals into older Python3 + + 2022-04-25 rocky +@@ -1702,7 +1702,7 @@ + + * test/simple_source/expression/05_long_literals.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner37base.py, +- uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/n_actions.py, uncompyle6/semantics/pysource.py: + Bugs in long-literal handlin Move n_dict to n_actions and special case n_const_list. Generalize + build_collection out of 3.7+ and into all Pythons + +@@ -1728,7 +1728,7 @@ + + 2022-04-21 rocky + +- * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/parsers/treenode.py, uncompyle6/semantics/transform.py: + Add "transfrormd_by" param to SyntaxTree This aligns code more with decompyle3 + + 2022-04-20 rocky +@@ -1747,7 +1747,7 @@ + + 2022-04-17 rocky + +- * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/gencomp.py, uncompyle6/semantics/pysource.py: + Fold in some decompile changes + + 2022-04-17 rocky +@@ -1764,7 +1764,7 @@ + 2022-04-17 rocky + + * Makefile, uncompyle6/semantics/gencomp.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Split out comprehension code.. sync with decompile a little better + + 2022-04-17 rocky +@@ -1774,7 +1774,7 @@ + + 2022-04-15 rocky + +- * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: ++ * uncompyle6/scanners/pypy37.py, uncompyle6/scanners/scanner37.py: + Correct for pypy 3.7 + + 2022-04-15 rocky +@@ -1826,7 +1826,7 @@ + 2022-04-01 rocky + + * admin-tools/pyenv-newest-versions, +- uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump lastest testing Python versions ++ uncompyle6/semantics/pysource.py: Small changes test code for pysource and bump latest testing Python versions + + 2022-03-12 rocky + +@@ -1902,7 +1902,7 @@ + 2022-03-04 rocky + + * uncompyle6/semantics/aligner.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Some small variable-name changes + + 2022-03-03 rocky +@@ -1915,12 +1915,12 @@ + * test/simple_source/bug36/02_genexpr.py, + test/simple_source/bug36/05_36lambda.py, + uncompyle6/parsers/parse36.py, uncompyle6/parsers/parse37.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/scanners/scanner3.py: + MAKE_FUNCTION_8 -> MAKE_FUNCTION_CLOSURE Clarity is important. + + 2022-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Remove TABLE_R0 - it hasn't been used in a while + + 2022-01-18 rocky +@@ -2009,7 +2009,7 @@ + uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + mklambda -> lambda_body matches Python AST better Note: we can't use "lambda" since that is a reserved word + + 2021-12-23 rocky +@@ -2142,7 +2142,7 @@ + uncompyle6/scanners/tok.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function2.py, +- uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: ++ uncompyle6/semantics/make_function36.py, uncompyle6/verify.py: + Python 3.6+ specialization + + 2021-11-03 rocky +@@ -2200,7 +2200,7 @@ + + 2021-10-26 rocky + +- * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: ++ * __pkginfo__.py, admin-tools/make-dist-older.sh, setup.py: + Admnistrivia: package info + + 2021-10-26 rocky +@@ -2236,7 +2236,7 @@ + + 2021-10-23 rocky + +- * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: ++ * admin-tools/setup-master.sh, uncompyle6/semantics/fragments.py: + Fragment and other bugs Part of the upgrade process + + 2021-10-23 rocky +@@ -2279,7 +2279,7 @@ + + 2021-10-21 rocky + +- * .github/workflows/ubuntu.yml: Worflows CI testing ++ * .github/workflows/ubuntu.yml: Workflows CI testing + + 2021-10-21 rocky + +@@ -2316,8 +2316,8 @@ + + 2021-10-19 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: +- Revise Python version comparisions And set scanner.show_asm for 3.6 ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner36.py: ++ Revise Python version comparisons And set scanner.show_asm for 3.6 + + 2021-10-18 rocky + +@@ -2384,7 +2384,7 @@ + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py, + uncompyle6/semantics/make_function3.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + new dis - Python compisons involving tuples + + 2021-10-12 rocky +@@ -2446,7 +2446,7 @@ + + 2020-12-31 R. Bernstein + +- * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> unnecessary ++ * : Merge pull request #340 from timgates42/bugfix_typo_unnecessary docs: fix simple typo, unecessary -> uxonnecessary + + 2020-12-27 rocky + +@@ -2454,7 +2454,7 @@ + 3.7+ We were producing: ``` z: z: int = 5 on bytecode_3.7_run/02_var_annotate.pyc ``` because grammar went 5. sstmt ann_assign (4) transformed by n_stmts: ('%|%[2]{attr}: + %c\n', 0) 0. ann_assign_init (3): ('%|%[2]{attr}: %c = %c\n', 0, 1) The "ann_assign" added "z:". Instead we have now: ``` 5. sstmt ann_assign_init (3) transformed by n_stmts: ('%|%[2]{attr}: + %c = %c\n', 0, 1) ``` Also, in the previous statement which appears in the listing (but is +- not actually in the finaly tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion ++ not actually in the finally tree) we had: 4. sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store So we now preface the node type with "deleted", e.g.: 4. deleted sstmt assign (2): ('%|%c = %p\n', -1, (0, 200)) 0. expr L. L. 7 26 LOAD_CONST 5 1. store to reduce confusion + + 2020-12-27 R. Bernstein + +@@ -2508,13 +2508,13 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse37.py, + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + del_stmt -> delete to match Python AST better + + 2020-09-01 rocky + + * uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precidence on ++ uncompyle6/semantics/customize38.py: little sync with decompyle3 Add another forelsestmt (found only in a loop) Add precedence on + walrus operator + + 2020-09-01 rocky +@@ -2574,7 +2574,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Use "co_consts" in docstring detection. Note: this is an upheaval because we need to pass "code" or at least + "code.co_consts" to the docstring detection routine + +@@ -2585,7 +2585,7 @@ + 2020-07-19 rocky + + * test/add-test.py, test/simple_source/bug27+/03_doc_assign.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Better doc string detection A bug in 2.7 test_descr.py revealed a problem with the way we were + detecting docstrings. __doc__ = DocDescr() was getting confused with a docstring. This program also reveals other bugs in 3.2+ but we'll deal with + that in another commit. +@@ -2638,7 +2638,7 @@ + + 2020-07-06 rocky + +- * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: ++ * .github/ISSUE_TEMPLATE/bug-report.md, HOW-TO-REPORT-A-BUG.md: + Update bug-fixing expectations + + 2020-07-06 rocky +@@ -2725,7 +2725,7 @@ + 2020-06-15 rocky + + * admin-tools/how-to-make-a-release.md, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Towards fixing a 3.8 try except-as bug + + 2020-06-12 rocky +@@ -2739,7 +2739,7 @@ + + 2020-06-12 rocky + +- * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: ++ * .circleci/config.yml, .travis.yml, NEWS.md, uncompyle6/version.py: + Get ready for release 3.7.1 + + 2020-06-12 rocky +@@ -2885,7 +2885,7 @@ + + 2020-05-09 rocky + +- * uncompyle6/linenumbers.py: Simpify an import, blacken a file. ++ * uncompyle6/linenumbers.py: Simplify an import, blacken a file. + + 2020-05-08 rocky + +@@ -2916,7 +2916,7 @@ + + * uncompyle6/parsers/parse37base.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Bugs in nested async for... * Generalize asyc_for rule Fix bug in picking out comprehension iterator in async for * fix bug in getting expression in such a comprehension * Add %[n]{%x} pattern to template_engine() + + 2020-04-27 rocky +@@ -2970,7 +2970,7 @@ + 2020-04-20 rocky + + * .travis.yml, __pkginfo__.py, uncompyle6/disas.py, +- uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: ++ uncompyle6/linenumbers.py, uncompyle6/main.py, uncompyle6/verify.py: + Update to use xdis 4.4.0 ... with more correct SipHash and other needed bug fixes. + + 2020-04-18 rocky +@@ -3106,7 +3106,7 @@ + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner37base.py: whileelse in 3.6 sometimes has +- come froms... also remove extra "L. " in token printing ++ come_froms... also remove extra "L. " in token printing + + 2020-04-04 rocky + +@@ -3294,7 +3294,7 @@ + + 2020-02-13 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/transform.py: + transform ifelseif bugs + + 2020-02-11 rocky +@@ -3335,7 +3335,7 @@ + 2020-02-10 rocky + + * uncompyle6/semantics/transform.py: Fix bug introduced by ast +- "tranform" change ++ "transform" change + + 2020-02-10 rocky + +@@ -3370,7 +3370,7 @@ + + 2020-02-10 rocky + +- * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.5-exclude.sh, uncompyle6/semantics/transform.py: + is_docsting needs to test for sstmts + + 2020-02-10 rocky +@@ -3425,7 +3425,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize35.py, + uncompyle6/semantics/customize37.py: async with rules back to 3.5 +- and ... add precidence on cascaded "await" expressions ++ and ... add precedence on cascaded "await" expressions + + 2020-02-08 rocky + +@@ -3491,7 +3491,7 @@ + + * test/stdlib/3.2-exclude.sh, test/stdlib/3.4-exclude.sh, + test/stdlib/3.5-exclude.sh, test/stdlib/3.6-exclude.sh: Go over +- 3.2-3.6 runtests.sh exludes... Reinstate a lot of tests broken since c90ff51 ++ 3.2-3.6 runtests.sh excludes... Reinstate a lot of tests broken since c90ff51 + + 2020-02-07 rocky + +@@ -3521,7 +3521,7 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize3.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize37.py, uncompyle6/semantics/helper.py: + conditional -> if_exp ... to match Python IfExp AST + + 2020-02-06 rocky +@@ -3598,7 +3598,7 @@ + + 2020-02-04 rocky + +- * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/2.5-exclude.sh, uncompyle6/semantics/transform.py: + Adjust assert transform for new "if_and" rule + + 2020-02-04 rocky +@@ -3608,7 +3608,7 @@ + + 2020-02-02 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + __modname__ and __qualname__ detection... since grammar has simplified. May still need work for Python < 3.0 + + 2020-02-02 rocky +@@ -3798,7 +3798,7 @@ + 2020-01-29 rocky + + * test/stdlib/3.7-exclude.sh, test/stdlib/3.8-exclude.sh, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Track grammar "stmt" simplifications class ... * NAME_MODULE constant * QUAL_NAME constant + + 2020-01-28 rocky +@@ -3870,7 +3870,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/reducecheck/ifstmt.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + More 3.x "if" checking. Abbreviate stmts->sstmt + + 2020-01-26 rocky +@@ -3910,7 +3910,7 @@ + + 2020-01-25 rocky + +- * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: ++ * test/stdlib/3.3-exclude.sh, uncompyle6/parsers/parse35.py: + Cut-n-paste grammar rule bug + + 2020-01-25 rocky +@@ -4045,16 +4045,16 @@ + uncompyle6/parsers/reducecheck/ifstmt.py, + uncompyle6/parsers/reducecheck/while1stmt.py, + uncompyle6/semantics/pysource.py: Largish rework: scan while1stmt +- for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we neeed to ++ for jump out .. to disambiguate. For this, we use the self.opc JUMP_OPS sets. For this, we need to + store opc in the parse object. DRY uses of "last = min(last, len(tokens)) + + 2020-01-23 rocky + +- * test/stdlib/3.7-exclude.sh: Exclue 3.7 test_binascii.py for now ++ * test/stdlib/3.7-exclude.sh: Exclude 3.7 test_binascii.py for now + + 2020-01-23 rocky + +- * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: ++ * test/stdlib/3.8-exclude.sh, uncompyle6/semantics/transform.py: + Mini-sync with decompyle3: go over runtests.sh 3.8 excludes + + 2020-01-23 rocky +@@ -4222,7 +4222,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse37.py: More + parser changes to reinstate what was working in 3.6.2... However, again, probably more precise since we isolate loop rules +- better However, again, this isnt' the full store. Semantics were incorrect ++ better However, again, this isn't the full store. Semantics were incorrect + in Release 3.6.2 and they still are. + + 2020-01-17 rocky +@@ -4237,7 +4237,7 @@ + 2020-01-16 rocky + + * test/simple_source/def/01_class.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + parens around consts when taking attr again + + 2020-01-16 rocky +@@ -4273,7 +4273,7 @@ + 2020-01-15 rocky + + * uncompyle6/parsers/reducecheck/ifelsestmt.py: 3.7 and 2.6 +- coexistance in handling jump targets ++ coexistence in handling jump targets + + 2020-01-15 rocky + +@@ -4349,13 +4349,13 @@ + + 2020-01-14 rocky + +- * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: ++ * test/stdlib/3.7-exclude.sh, uncompyle6/semantics/customize36.py: + 3.7 test_fstring now works. + + 2020-01-13 rocky + + * test/simple_source/bug36/10_fstring.py, +- test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: ++ test/stdlib/3.6-exclude.sh, uncompyle6/semantics/customize36.py: + Handle set/dictionary comprehensions in format strings + + 2020-01-13 rocky +@@ -4432,7 +4432,7 @@ + 2020-01-12 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/transform.py: + Wacky string at beginning of fn which is not docstring... 3.7.6 test_fstring.py tests this. + + 2020-01-12 rocky +@@ -4833,7 +4833,7 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse2.py: Accomodate "return" in an except ++ * uncompyle6/parsers/parse2.py: Accommodate "return" in an except + handler + + 2020-01-06 rocky +@@ -4867,8 +4867,8 @@ + + 2020-01-06 rocky + +- * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: +- Python 2.4- doesn't have condition expresions ++ * uncompyle6/parsers/parse21.py, uncompyle6/parsers/parse24.py: ++ Python 2.4- doesn't have condition expressions + + 2020-01-05 rocky + +@@ -4921,7 +4921,7 @@ + 2020-01-03 rocky + + * test/stdlib/runtests.sh, uncompyle6/parser.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7+ multiple imports of dotted path + + 2020-01-03 rocky +@@ -4945,7 +4945,7 @@ + 2020-01-03 rocky + + * test/simple_source/bug30/06_listcomp.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + Fix a 3.7+ chained compare bug... others remain though. + + 2020-01-02 rocky +@@ -4998,11 +4998,11 @@ + + * uncompyle6/semantics/make_function3.py: Simplify make_function3 by + customization We now have different routines for 3.6+ (and 2.x from before). This is desirable before fixing 3.0..3.5 lambdas with default +- paramerts and * args. ++ parameters and * args. + + 2019-12-27 rocky + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/transform.py: + Tidy code. * Don't use "str" as a variable name * blacken helper and alphabetically order fns * use helper function `find_code_node()` in transform `mk_func()` + + 2019-12-27 rocky +@@ -5012,7 +5012,7 @@ + uncompyle6/semantics/make_function2.py, + uncompyle6/semantics/make_function3.py, + uncompyle6/semantics/make_function36.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Was dropping docstrings! Add in decompyle make_function36 + + 2019-12-27 rocky +@@ -5118,8 +5118,8 @@ + uncompyle6/parsers/parse37base.py, uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize.py, + uncompyle6/semantics/customize35.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: +- Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precidence in ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ Redo the way we handle complex literals and 3.7+ bug fixes... In 3.7+ remove assert_expr* parser rules Fix "call" precedence in + 3.7+ for it children + + 2019-12-18 rocky +@@ -5175,7 +5175,7 @@ + 2019-12-16 rocky + + * test/simple_source/bug37/02_async_for_generator.py, +- uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse37base.py, uncompyle6/semantics/pysource.py: + Add 3.7 async listcomp + + 2019-12-15 rocky +@@ -5189,13 +5189,13 @@ + + 2019-12-15 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Adminsitrivia: improve setup scripts + + 2019-12-15 rocky + + * test/simple_source/def/05_class.py, test/stdlib/runtests.sh, +- uncompyle6/semantics/pysource.py: Fix Python 3.x pringing ++ uncompyle6/semantics/pysource.py: Fix Python 3.x printing + superclasses... class Description: not class Description("Description"). Introduced + in not catching LOAD_CONST->LOAD_STR change + +@@ -5268,7 +5268,7 @@ + + 2019-12-11 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/parsers/parse37base.py: + Add 3.7+ "and" grammar rule and limit "or" more + + 2019-12-11 rocky +@@ -5290,7 +5290,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/01_if_and_if_bug.py, + test/simple_source/bug36/02_call_ex_kw.py, +- uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: ++ uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize38.py: + Add another 3.8 try/finally rule and semantic action + + 2019-12-10 rocky +@@ -5341,7 +5341,7 @@ + 2019-12-09 rocky + + * setup.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: ++ uncompyle6/scanners/scanner38.py, uncompyle6/scanners/scanner39.py: + Start to tolerate 3.9 (in pydisassemble) + + 2019-12-09 rocky +@@ -5371,7 +5371,7 @@ + + 2019-12-08 rocky + +- * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: ++ * uncompyle6/parsers/parse37.py, uncompyle6/scanners/scanner38.py: + Typos: decompyle3 -> uncompyle6 + + 2019-12-08 R. Bernstein +@@ -5380,7 +5380,7 @@ + + 2019-12-02 rocky + +- * uncompyle6/semantics/make_function.py: Accomodate for optional ++ * uncompyle6/semantics/make_function.pyff: Accommodate for optional + docstring in function kw calculation + + 2019-11-21 rocky +@@ -5434,7 +5434,7 @@ + + 2019-11-18 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Two Bugs ... 2.7: more stringent comparison and comp_if testing 2.6-2.7: fix + botched dict constant translation + +@@ -5470,7 +5470,7 @@ + + 2019-11-16 rocky + +- * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-newer-versions, admin-tools/setup-master.sh: + Administriva - bump testing versions + + 2019-11-16 rocky +@@ -5508,7 +5508,7 @@ + + 2019-11-16 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + 3.0 assert2... Not like other 3.x due to the lack of POP_JUMP_IF + + 2019-11-16 rocky +@@ -5517,7 +5517,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Add 3.0 try/except rule + + 2019-11-15 rocky +@@ -5549,7 +5549,7 @@ + + 2019-11-15 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + 3.0.1 "ret_or", "ret_and", and "or" rules + + 2019-11-15 rocky +@@ -5568,12 +5568,12 @@ + + 2019-11-14 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Two 3.0 rules ... - ifstmtlastl - ifnotstmt30 + + 2019-11-13 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/parsers/treenode.py: + Bang on 3.0.1 control flow... more word is needed though + + 2019-11-12 rocky +@@ -5609,7 +5609,7 @@ + 2019-11-11 rocky + + * test/simple_source/bug30/04_and_del.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Cope more JUMP/POP_IF not being in 3.0... more is probably needed though. + + 2019-11-11 rocky +@@ -5631,8 +5631,8 @@ + 2019-11-10 rocky + + * test/simple_source/bug30/03_ifelse.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: +- More Python 3.0 custom "if" statment handling. ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ More Python 3.0 custom "if" statement handling. + + 2019-11-10 rocky + +@@ -5703,7 +5703,7 @@ + + 2019-10-29 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/customize36.py: + Pypy 3.6 tolerance + + 2019-10-29 rocky +@@ -5732,7 +5732,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: ++ uncompyle6/semantics/pysource.py, uncompyle6/semantics/transform.py: + Pypy 3.6 tolerance + + 2019-05-11 rocky +@@ -5740,7 +5740,7 @@ + * test/Makefile, test/test_pyenvlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + WIP pypy3.6 handling + + 2019-10-28 rocky +@@ -5774,14 +5774,14 @@ + + 2019-10-12 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Better simpler fragment fix... remove hide_internal test. We changed the default and that's what + whas causing RETURN_LAST to not get included. + + 2019-10-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fragment fixes (and workarounds) fragments.py: add more parent offsets. blacken buffer parser3.py: + additional grammar rules for fragment parser Misc small typos and corrections + +@@ -5854,7 +5854,7 @@ + + 2019-08-21 rocky + +- * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: ++ * .circleci/config.yml, __pkginfo__.py, requirements-dev.txt: + CircleCi 3rd try + + 2019-08-21 rocky +@@ -5958,7 +5958,7 @@ + + 2019-07-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + More excpet_cond futzing + + 2019-07-03 rocky +@@ -6051,7 +6051,7 @@ + + 2019-06-21 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Start to reinstate elif's + + 2019-06-21 R. Bernstein +@@ -6075,7 +6075,7 @@ + + * test/simple_source/bug35/07_build_map_unpack.py, + test/simple_source/comprehension/05_dict_comp.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 2-arg asserts in 3.6+ish Changed files have also been reformatted via the blacken formatter + + 2019-06-16 rocky +@@ -6118,18 +6118,18 @@ + + 2019-06-11 rocky + +- * pytest/test_token.py: Formatting change slighty ++ * pytest/test_token.py: Formatting change slightly + + 2019-06-11 rocky + + * pytest/test_token.py, pytest/testdata/if-2.7.right, +- pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: ++ pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/tok.py: + Formatting in < 3.0 is different for name ops + + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Nicer assembly display... Fewer extraneous quotes and remove pattrs that don't mean anything. +- Base more on OP poperties like varargs and NAME_OPS ++ Base more on OP properties like varargs and NAME_OPS + + 2019-06-11 rocky + +@@ -6156,8 +6156,8 @@ + + * uncompyle6/parsers/parse36.py, + uncompyle6/semantics/customize36.py, +- uncompyle6/semantics/pysource.py: Tweaks to x0ret's anotation type +- handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types ++ uncompyle6/semantics/pysource.py: Tweaks to x0ret's annotation type ++ handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Document what's up with annotation types + + 2019-06-09 x0ret + +@@ -6171,7 +6171,7 @@ + 2019-06-11 rocky + + * uncompyle6/scanners/tok.py: Fix LOAD_STR messing up docstring +- comparision ++ comparison + + 2019-06-09 R. Bernstein + +@@ -6260,7 +6260,7 @@ + + 2019-06-08 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Another LOAD_STR/CONST isolation in < 3.0 + + 2019-06-08 rocky +@@ -6306,7 +6306,7 @@ + 2019-06-06 rocky + + * uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: ++ uncompyle6/semantics/customize3.py, uncompyle6/semantics/helper.py: + better name for call generator rule + + 2019-06-06 R. Bernstein +@@ -6332,14 +6332,14 @@ + 2019-05-28 x0ret + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + fix unicode docstring again, handling unicode string in py2, fix + docstring indentation + + 2019-05-27 rocky + + * test/simple_source/stmts/00_docstring.py: Reinstate more docstring +- tests But 3.{6,7} are stil broken ++ tests But 3.{6,7} are still broken + + 2019-05-27 rocky + +@@ -6357,13 +6357,13 @@ + + 2019-05-27 x0ret + +- * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + towards supporting unicode: docstring + + 2019-05-24 rocky + + * test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py: Simplfy - TODO fix unicode in ++ uncompyle6/semantics/helper.py: Simplify - TODO fix unicode in + docstrings + + 2019-05-24 rocky +@@ -6453,7 +6453,7 @@ + + 2019-05-14 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Only add forward-jumping COME_FROM in 3.6+ Is this a repeat commit? + + 2019-05-13 rocky +@@ -6512,7 +6512,7 @@ + 2019-05-10 rocky + + * uncompyle6/scanners/scanner3.py: Accept x0ret's suggestion for +- 3.6+ if detection.. in the presense of a try block. Fixes #229 ++ 3.6+ if detection.. in the presence of a try block. Fixes #229 + + 2019-05-10 rocky + +@@ -6535,7 +6535,7 @@ + + * test/simple_source/bug36/02_call_ex_kw.py, + uncompyle6/semantics/customize36.py: Fix 3.6. call_ex_kw semantic +- action Was missing positional args parameter in template. Fix submited by ++ action Was missing positional args parameter in template. Fix submitted by + @x0ret Fixes #227 + + 2019-05-08 rocky +@@ -6575,7 +6575,7 @@ + 2019-05-05 rocky + + * test/simple_source/bug26/04_ifelse_parens.py, +- uncompyle6/semantics/consts.py: IfExp precidence handling in 2.6... 2.7 still has a bug ++ uncompyle6/semantics/consts.py: IfExp precedence handling in 2.6... 2.7 still has a bug + + 2019-05-05 rocky + +@@ -6587,24 +6587,24 @@ + + * uncompyle6/semantics/consts.py, + uncompyle6/semantics/customize37.py, +- uncompyle6/semantics/pysource.py: Fix precidence between list_if and ++ uncompyle6/semantics/pysource.py: Fix precedence between list_if and + if_expr in 3.x + + 2019-05-04 rocky + + * uncompyle6/parsers/parse37.py, +- uncompyle6/semantics/customize37.py: Ned custom 3.7+ IfExp rules ++ uncompyle6/semantics/customize37.py: Need custom 3.7+ IfExp rules + + 2019-05-04 rocky + + * test/Makefile, test/simple_source/bug37/01_and_not_else.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize37.py: + 3.7: if and not else + + 2019-05-04 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + delete_subscr -> delete_subscript ... to better (but not exactly) match the Python AST + + 2019-05-04 rocky +@@ -6614,7 +6614,7 @@ + 2019-05-03 rocky + + * admin-tools/pyenv-older-versions, +- uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner37.py, uncompyle6/scanners/scanner38.py: + Administrivia + + 2019-05-03 rocky +@@ -6678,7 +6678,7 @@ + 2019-05-01 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Better 3.6+ format specification handling + + 2019-04-30 rocky +@@ -6690,7 +6690,7 @@ + 2019-04-30 rocky + + * test/simple_source/bug36/01_fstring.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize36.py: + Hacky handling of 3.6 format string 'X'. + + 2019-04-30 rocky +@@ -6732,7 +6732,7 @@ + + * uncompyle6/semantics/customize25.py, + uncompyle6/semantics/customize26_27.py, +- uncompyle6/semantics/pysource.py: Was mssing 2.5 cond3 semantic rule ++ uncompyle6/semantics/pysource.py: Was missing 2.5 cond3 semantic rule + + 2019-04-23 rocky + +@@ -6758,7 +6758,7 @@ + 2019-04-22 rocky + + * test/simple_source/bug36/08_comp_gen_for.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Add rule for 3.x comp_for + + 2019-04-19 rocky +@@ -6794,7 +6794,7 @@ + 2019-04-18 rocky + + * uncompyle6/semantics/make_function.py, +- uncompyle6/semantics/pysource.py: Hacky attemp to add more 3.x ++ uncompyle6/semantics/pysource.py: Hacky attempt to add more 3.x + annotate information in + + 2019-04-17 rocky +@@ -6815,7 +6815,7 @@ + + 2019-04-15 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/semantics/pysource.py: + Improve Python 2.7 generator handling + + 2019-04-15 rocky +@@ -6868,7 +6868,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Add 3.8 try else + + 2019-04-14 rocky +@@ -6889,7 +6889,7 @@ + + 2019-04-14 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Start 3.8 async for/else + + 2019-04-14 rocky +@@ -6916,12 +6916,12 @@ + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust while True grammar rule + + 2019-04-13 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + Adjust 3.8 while-stmt rules + + 2019-04-13 rocky +@@ -6933,7 +6933,7 @@ + + 2019-04-12 rocky + +- * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse38.py, uncompyle6/semantics/customize3.py: + 3.8 try/except handling - again (and more to come) + + 2019-04-11 rocky +@@ -6974,7 +6974,7 @@ + 2019-04-10 rocky + + * Makefile, test/Makefile, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + Basic 3.8+ "for" loop handling... More Makefile mangling + + 2019-04-10 rocky +@@ -6995,13 +6995,13 @@ + 2019-04-10 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse38.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize3.py: + 3.8 "for" block ... pysource: Tag older semantics for blocks with "expr" and "for_block" + + 2019-04-09 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner13.py, +- uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner14.py, uncompyle6/scanners/scanner38.py: + Small changes - bump required xdis version + + 2019-04-05 rocky +@@ -7020,7 +7020,7 @@ + 2019-03-28 rocky + + * uncompyle6/parsers/parse38.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner38.py: + [WIP] - move forward a tad on Python 3.8 + + 2019-03-28 rocky +@@ -7044,7 +7044,7 @@ + 2019-03-23 rocky + + * test/simple_source/bug36/01_if_and_if_bug.py, +- uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: ++ uncompyle6/parsers/parse37.py, uncompyle6/semantics/customize3.py: + Adjust 3.7 chained compare for adjusted grammar Add test for last change + + 2019-03-23 rocky +@@ -7155,7 +7155,7 @@ + + 2019-01-05 Yiming Wang + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Better assert and AssertionError determine for Python 2.7 + + 2019-01-05 rocky +@@ -7195,7 +7195,7 @@ + + 2018-12-26 rocky + +- * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: ++ * admin-tools/pyenv-newer-versions, uncompyle6/parsers/parse27.py: + Use raw string in regexp with "\d"... Bump python versions used in testing + + 2018-12-25 rocky +@@ -7205,7 +7205,7 @@ + + 2018-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6+ control flow + + 2018-12-15 rocky +@@ -7318,12 +7318,12 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, + uncompyle6/semantics/helper.py: Reinstat expr32 and expr1024 +- rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplfy via putting instructions as comments. ++ rules... to speed up handling long literal lists. See also issue #188 Update issue forms to simplify via putting instructions as comments. + + 2018-09-19 rocky + + * uncompyle6/main.py: decompile bytecode_version defaults to Python +- intepreter version Fixes #189 ++ interpreter version. Fixes #189 + + 2018-09-19 rocky + +@@ -7332,7 +7332,7 @@ + + 2018-08-12 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/semantics/customize.py: + Handle Python 2.4 if true + + 2018-08-02 rocky +@@ -7342,8 +7342,8 @@ + 2018-08-02 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, +- .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: +- Guidleines for reporting bugs and openning feature requests ++ .github/ISSUE_TEMPLATE/feature-request.md, requirements-dev.txt: ++ Guidleines for reporting bugs and opening feature requests + + 2018-07-15 rocky + +@@ -7403,12 +7403,12 @@ + + 2018-06-24 rocky + +- * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ * uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Remove some of the 3.0 3.x instruction hackiness + + 2018-06-24 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 comprehensions are a snowflake + + 2018-06-24 rocky +@@ -7438,12 +7438,12 @@ + 2018-06-24 rocky + + * test/simple_source/bug31/06_listcomp.py, +- uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Improve 3.0 list comprehensions + + 2018-06-23 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Fix Python 3.0 "and" parse rule + + 2018-06-23 rocky +@@ -7463,7 +7463,7 @@ + + * test/Makefile, test/simple_source/bug30/00_chained-compare.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse30.py: Python +- 3.0 chained comparisions ++ 3.0 chained comparisons + + 2018-06-23 rocky + +@@ -7493,7 +7493,7 @@ + + 2018-06-22 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/customize3.py: + Fix two Python 3.0 bugs... * don't add _[0] list comprehension variables * add POP_TOP in _ifstmts_jmp; c_stmst for now isn't optional + + 2018-06-19 rocky +@@ -7578,7 +7578,7 @@ + 2018-06-12 rocky + + * uncompyle6/parsers/parse30.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tollerance ++ uncompyle6/scanners/scanner3.py: More 3.0 bug fixing and tolerance + and... add some 1.4 bytecode tests + + 2018-06-12 rocky +@@ -7589,7 +7589,7 @@ + + 2018-06-12 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection on Python 3.0 + + 2018-06-11 rocky +@@ -7620,12 +7620,12 @@ + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + 3.0 list comprehensions + + 2018-06-09 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/semantics/pysource.py: + Python 3.0 set comprehensions + + 2018-06-09 rocky +@@ -7666,7 +7666,7 @@ + + * test/simple_source/bug14/01_print.py, + test/stdlib/compile-file.py, test/stdlib/compile_file_1x.py, +- uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: ++ uncompyle6/parsers/parse14.py, uncompyle6/scanners/scanner14.py: + Improve Python 1.4 bytecode coverage + + 2018-06-04 rocky +@@ -7721,7 +7721,7 @@ + uncompyle6/scanner.py, uncompyle6/scanners/scanner14.py, + uncompyle6/scanners/scanner15.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, uncompyle6/scanners/scanner23.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py: + Start Python 1.4 decompilation ... Tidy up test code for issue 162 and comments for some disassembly + massaging. + +@@ -7759,7 +7759,7 @@ + + 2018-05-08 rocky + +- * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug27+/05_try_else.py, test/stdlib/runtests.sh: + Note we can't handle try/else sometimes in 2.7 + + 2018-05-08 rocky +@@ -7806,7 +7806,7 @@ + + * test/simple_source/bug26/01_ifelse_listcomp.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + 2.6, 2.7 Parse if else inside list comprehension Fixes #171 + + 2018-04-28 rocky +@@ -7829,7 +7829,7 @@ + * test/simple_source/branching/02_ifelse_lambda.py, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py: + Handle if not else in lambdas... Fixes #170 + + 2018-04-23 rocky +@@ -7850,13 +7850,13 @@ + + 2018-04-21 rocky + +- * uncompyle6/parsers/parse35.py: Correct (3.7) use fof ++ * uncompyle6/parsers/parse35.py: Correct (3.7) use for + BUILD_MAP_UNPACK_WITH_CALL + + 2018-04-20 rocky + + * Makefile, uncompyle6/parsers/parse36.py, +- uncompyle6/semantics/customize3.py: Fix 3.7 aysnc def testing ++ uncompyle6/semantics/customize3.py: Fix 3.7 async def testing + + 2018-04-19 rocky + +@@ -7876,7 +7876,7 @@ + + 2018-04-18 rocky + +- * uncompyle6/parsers/parse3.py: 2.6 compatability ++ * uncompyle6/parsers/parse3.py: 2.6 compatibility + + 2018-04-18 rocky + +@@ -7892,7 +7892,7 @@ + + 2018-04-16 rocky + +- * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: ++ * admin-tools/pyenv-newer-versions, pytest/test_grammar.py: + Administrivia + + 2018-04-16 rocky +@@ -7997,7 +7997,7 @@ + 2018-04-08 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Slightly Python 3.x handing of subclasses... which are created via a call to create a subclass. Should be more general though. + + 2018-04-08 rocky +@@ -8040,7 +8040,7 @@ + + * uncompyle6/semantics/customize3.py, + uncompyle6/semantics/pysource.py: Make sure we call 'expr' go set +- precidence right ++ precedence right + + 2018-04-06 rocky + +@@ -8088,7 +8088,7 @@ + + * uncompyle6/semantics/customize.py, + uncompyle6/semantics/make_function.py: 3.2-3.4 Functions +- cals/defininitions yet again And we're still not out of the woods. ++ cals/definitions yet again And we're still not out of the woods. + + 2018-04-03 rocky + +@@ -8108,7 +8108,7 @@ + * Makefile, pytest/test_fjt.py, pytest/test_function_call.py, + pytest/test_grammar.py, pytest/test_single_compile.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + DRY scanner code more... Expand 2.6 testing + + 2018-04-03 rocky +@@ -8120,7 +8120,7 @@ + + * pytest/test_fjt.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py: + DRY instruction building code... There is a little more that could be done with + self.offset2inst_index + +@@ -8148,7 +8148,7 @@ + + 2018-04-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Handle 3.5+ BUILD_MAP_UNPACK used in dictionaries A number of weaknesses have been uncovered though + + 2018-04-01 rocky +@@ -8168,7 +8168,7 @@ + 2018-03-31 rocky + + * test/simple_source/bug36/10_argparse.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6 argument parsing + + 2018-03-31 rocky +@@ -8194,7 +8194,7 @@ + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Replace all_instrs with inst_matches... which works on 3.6+. Still should write a pytest for this. + + 2018-03-29 rocky +@@ -8246,7 +8246,7 @@ + 2018-03-27 rocky + + * test/grammar-cover/.gitignore, test/grammar-cover/convert.sh, +- test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: ++ test/grammar-cover/run-and-email.sh, test/stdlib/.gitignore: + grammar-cover administrivia + + 2018-03-27 rocky +@@ -8289,7 +8289,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: ++ * test/grammar-cover/README.md, test/grammar-cover/grammar.sh: + Grammar coverage hacking + + 2018-03-26 rocky +@@ -8328,7 +8328,7 @@ + + 2018-03-26 rocky + +- * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: ++ * test/grammar-cover/convert.sh, test/grammar-cover/grammar24.sh: + Start grammar coverage testing + + 2018-03-26 rocky +@@ -8344,7 +8344,7 @@ + 2018-03-26 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Bang on 3.4 CALL_FUNCTION_VAR + + 2018-03-25 rocky +@@ -8358,7 +8358,7 @@ + 2018-03-25 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/customize.py: + 3.5 *() arg without further args + + 2018-03-25 R. Bernstein +@@ -8410,7 +8410,7 @@ + 2018-03-24 rocky + + * test/simple_source/bug35/04_call_function.py, +- uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/customize.py, uncompyle6/semantics/pysource.py: + Towards handling 3.x' CALL_FUNCTION_VAR correctly + + 2018-03-24 rocky +@@ -8430,17 +8430,17 @@ + 2018-03-22 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + 3.6 try except-as bug + + 2018-03-22 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: + Localize call_kw precedence to 3.6 + + 2018-03-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate some 3.x dictcomp grammar rules + + 2018-03-21 rocky +@@ -8460,7 +8460,7 @@ + * test/simple_source/bug36/01_fstring.py, + test/simple_source/bug36/02_kwargs.py, + uncompyle6/semantics/consts.py, uncompyle6/semantics/customize.py: A +- couple of 3.6 bugs... remove parens around decorators by adjusting precidence Partial ++ couple of 3.6 bugs... remove parens around decorators by adjusting precedence Partial + handling of quotes within 3.6 format strings + + 2018-03-21 rocky +@@ -8616,7 +8616,7 @@ + + 2018-03-08 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Slightly better assert detection + + 2018-03-08 rocky +@@ -8728,28 +8728,28 @@ + 2018-03-06 rocky + + * uncompyle6/parsers/parse26.py: 2.6- CONTINUE/JUMP_BACK confusion +- workaroud ++ workaround + + 2018-03-05 rocky + +- * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: ++ * admin-tools/run-pyenvlib-test-all.sh, admin-tools/setup-master.sh: + Administrivia... - Add script to run test_pyenvlib.py on everything - Bump 3.6 version 3.6.4 + + 2018-03-05 rocky + + * test/simple_source/stmts/01_rel_import.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Small changes... pysource.py: Bug fix for relative imports. scanner2.py: Remove a debug expression + + 2018-03-05 rocky + +- * uncompyle6/parsers/parse22.py: Python 2.2 code anomoly? Python 2.2 may generate PRINT_ITEM_CONT in some places for ++ * uncompyle6/parsers/parse22.py: Python 2.2 code anomaly? Python 2.2 may generate PRINT_ITEM_CONT in some places for + PRINT_ITEM + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Need to back off set_comp change a little... There was set_comp already. So what had been setcomp_func is now + merely set_comp_func rather than set_comp. Small improvement but in + the right direction, still +@@ -8758,15 +8758,15 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + dictcomp_func -> dict_comp_func... to match AST better. Also adds a correction in last commit, +- including set_comp -> set_comp_expr where apprpriate Note: can't use dict_comp as that was already used. But ++ including set_comp -> set_comp_expr where appropriate Note: can't use dict_comp as that was already used. But + dict_comp_func is matches AST better than dictcomp_func + + 2018-03-05 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + setcomp_func -> set_comp ... to match AST name more closely + + 2018-03-05 rocky +@@ -8821,7 +8821,7 @@ + + 2018-03-04 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + Prevent 3.6 call_kw deriving itself.. Was causing some calls to be parsed incorrectly + + 2018-03-04 rocky +@@ -8874,7 +8874,7 @@ + + 2018-03-01 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Better "continue" detection for 2.7 + + 2018-03-01 rocky +@@ -8929,7 +8929,7 @@ + * pytest/test_grammar.py, pytest/testdata/if-2.7.right, + pytest/testdata/ifelse-2.7.right, uncompyle6/scanners/scanner2.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/tok.py, uncompyle6/semantics/pysource.py: + Fallout from more precise token attributes + + 2018-02-28 rocky +@@ -8960,7 +8960,7 @@ + + 2018-02-27 rocky + +- * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: ++ * HISTORY.md, uncompyle6/main.py, uncompyle6/semantics/fragments.py: + Start simplifying higher-level API + + 2018-02-27 rocky +@@ -8975,14 +8975,14 @@ + + 2018-02-27 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Revise comprehension walking in 3.x... less rigidly and with less magic and more verbiage as to what's + going on + + 2018-02-27 rocky + + * test/simple_source/bug36/04_try_finally.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/customize.py: + 3.6+ try/finally bugs Another day another 3.6 bug fix attempted + + 2018-02-27 rocky +@@ -9005,7 +9005,7 @@ + 2018-02-26 rocky + + * test/simple_source/bug36/05_call_star_kw.py, uncompyle6/main.py, +- uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to diretions for improvements ++ uncompyle6/semantics/make_function.py: 3.6 MAKE_FUNCTION workarounds Still wrong, but points to directions for improvements + + 2018-02-26 rocky + +@@ -9141,7 +9141,7 @@ + + * test/simple_source/bug27+/03_not_dead_code.py, + test/stdlib/runtests.sh, uncompyle6/parsers/parse27.py: Refine 2.7 +- dead code test .. in a hacky way. Will probalby have to expand this in the future or ++ dead code test .. in a hacky way. Will probably have to expand this in the future or + better do dead code analysis + + 2018-02-18 rocky +@@ -9160,13 +9160,13 @@ + + 2018-02-17 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: +- Beter 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ Better 2.7 end_if and COME_FROM determination Fixes #149 ... Add more tests too + + 2018-02-15 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Wierd comprehension bug seen via ++ uncompyle6/semantics/pysource.py: Weird comprehension bug seen via + new loctraceback + + 2018-02-15 rocky +@@ -9209,7 +9209,7 @@ + + * test/simple_source/bug35/03_double_star_unpack.py, + uncompyle6/semantics/customize.py: Start to handle 3.5+ +- BUILD_LIST_UNPACK in call .. to implement multple star arguments ++ BUILD_LIST_UNPACK in call .. to implement multiple star arguments + + 2018-02-08 rocky + +@@ -9231,7 +9231,7 @@ + + 2018-02-04 rocky + +- * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py: + Revert most of last change + + 2018-02-04 rocky +@@ -9253,7 +9253,7 @@ + + 2018-02-03 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + Clean up fragments code for "for"... And make a little more precise. tag "store" part of "for" in + consts. + +@@ -9365,7 +9365,7 @@ + + 2018-01-27 rocky + +- * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: ++ * NEWS, admin-tools/how-to-make-a-release.md, uncompyle6/version.py: + Get ready for release 2.15.0 + + 2018-01-27 rocky +@@ -9379,12 +9379,12 @@ + 2018-01-27 rocky + + * uncompyle6/semantics/customize.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY fragments by using OO more effectively Split grammar customization to its own file. It's quite large now. + + 2018-01-27 rocky + +- * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/linemap.py, uncompyle6/semantics/pysource.py: + More linestart hacking. Not very successful though + + 2018-01-26 rocky +@@ -9417,7 +9417,7 @@ + 2018-01-24 rocky + + * pytest/test_disasm.py, uncompyle6/disas.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/linemap.py: + Add deparse_code_with_fragments_and_map and simplify + + 2018-01-23 rocky +@@ -9449,7 +9449,7 @@ + 2018-01-22 rocky + + * test/simple_source/bug27+/02_ifelsetmtl.py, uncompyle6/main.py, +- uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner27.py: + JUMP_BACK and CONTINUE need to be treated more similar... fixes 148 + + 2018-01-22 rocky +@@ -9516,7 +9516,7 @@ + 2018-01-18 rocky + + * uncompyle6/__init__.py, uncompyle6/scanner.py: Handle 3.5.2..3.5.2 +- magic... And handle magic better overal by improved xdis use ++ magic... And handle magic better overall by improved xdis use + + 2018-01-13 rocky + +@@ -9668,7 +9668,7 @@ + 2018-01-08 rocky + + * pytest/test_fjt.py, test/simple_source/bug35/05_empty_ifs.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner36.py: + Fix 3.5+ bug in if's with pass bodies Fixes #104 in a somewhat hacky way. + + 2018-01-07 rocky +@@ -9707,7 +9707,7 @@ + + 2018-01-06 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Change disassembly to make offsets in COME_FROMs + + 2018-01-06 rocky +@@ -9718,7 +9718,7 @@ + + * test/stdlib/runtests.sh, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Fix bug in 2.5- try/else inside ifelsestmt + + 2017-12-15 rocky +@@ -9734,12 +9734,12 @@ + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + 3.6 FUNCTION_EX_KW fixes + + 2017-12-15 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Grammar rule for 3.6 with .. return + + 2017-12-15 rocky +@@ -9796,7 +9796,7 @@ + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse30.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT return_stmt -> return to match AST + + 2017-12-14 R. Bernstein +@@ -9813,7 +9813,7 @@ + + 2017-12-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start handling 3.6 CALL_FUNCTION_KW + + 2017-12-14 rocky +@@ -9842,12 +9842,12 @@ + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Back off of previous refactor a little bit + + 2017-12-13 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Simplify scanner2 so it relies less on custimize dict + + 2017-12-13 rocky +@@ -9943,7 +9943,7 @@ + 2017-12-12 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 CALL_FUNCTION(_VAR)_KW + + 2017-12-12 rocky +@@ -9956,7 +9956,7 @@ + + 2017-12-12 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on BUILD_MAP_UNPACK_WITH_CALL a little... more cases are needed still. And there's a bug in + BUILD_TUPLE_UNPACK_WITH_CALL now in adding the count twice. + +@@ -9984,7 +9984,7 @@ + * admin-tools/how-to-make-a-release.md, + uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Start to handle CALL_FUNCTION_EX more accurately + + 2017-12-10 rocky +@@ -10022,7 +10022,7 @@ + + 2017-12-07 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py: + Reinstate kwargs1... was just missing the semantic action rule for it + + 2017-12-07 rocky +@@ -10038,7 +10038,7 @@ + + * pytest/test_grammar.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/parsers/parse36.py: + grammar isolation and reduction + + 2017-12-07 rocky +@@ -10076,7 +10076,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT break_stmt, continue_stmt -> break, continue... to match AST + + 2017-12-06 rocky +@@ -10097,7 +10097,7 @@ + + 2017-12-05 rocky + +- * test/stdlib/runtests.sh: runtest.sh: remove from exlusion stdlib ++ * test/stdlib/runtests.sh: runtest.sh: remove from exclusion stdlib + test that now work + + 2017-12-05 rocky +@@ -10151,7 +10151,7 @@ + 2017-12-04 rocky + + * test/simple_source/bug26/03_weird26.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Slightly better 3.x list comprehension handling + + 2017-12-04 rocky +@@ -10175,15 +10175,15 @@ + + 2017-12-03 rocky + +- * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: ++ * test/simple_source/bug26/03_weird26.py, test/stdlib/runtests.sh: + More weirdness testing + + 2017-12-03 rocky + + * test/simple_source/bug26/{03_weird.py => 03_weird26.py}, + test/stdlib/runtests.sh, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: +- Handle a wierd 2.6 conditional false expression... from 2.6. test_grammar ++ uncompyle6/parsers/parse27.py, uncompyle6/semantics/consts.py: ++ Handle a weird 2.6 conditional false expression... from 2.6. test_grammar + + 2017-12-03 rocky + +@@ -10195,7 +10195,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + NT: load_attr -> attribute to match AST + + 2017-12-03 rocky +@@ -10235,7 +10235,7 @@ + * uncompyle6/parser.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner2.py: + Grammar "COME_FROM"_from cleanups ... tryelse constructs in 2.x fixed up _come_from -> _come_froms + (COME_FROM*) consolidate come_froms rule into sincle parser.py + +@@ -10262,7 +10262,7 @@ + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT trystmt -> try_except to match AST + + 2017-12-02 rocky +@@ -10273,7 +10273,7 @@ + 2017-12-02 rocky + + * test/Makefile, test/simple_source/stmts/00_docstring.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + Fix docstring bug.. small sync with python 2.4 branch + + 2017-12-02 rocky +@@ -10317,7 +10317,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner2.py: + Small grammar isolation bugs + + 2017-12-02 rocky +@@ -10328,7 +10328,7 @@ + + * test/simple_source/stmts/02_test_exec.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse35.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.7 exec stmt grammar rule isolation/reduction + + 2017-12-02 rocky +@@ -10338,7 +10338,7 @@ + + 2017-12-02 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse35.py: + whileTrue grammar reduction + + 2017-12-02 rocky +@@ -10358,12 +10358,12 @@ + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Isolate and reduce 3.x conditionals and lambda rules + + 2017-12-01 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + opt_come_from_loop -> come_from_loops... ANd remove unused rules associated with COME_FROM_FINALLY + + 2017-12-01 rocky +@@ -10420,7 +10420,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT mapexpr -> dict to match AST + + 2017-11-30 rocky +@@ -10466,7 +10466,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT setcomp -> set_comp to match AST + + 2017-11-29 rocky +@@ -10475,7 +10475,7 @@ + uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + list_compr -> list_comp to match AST... more Python 3 custom rule cleanup + + 2017-11-29 rocky +@@ -10504,7 +10504,7 @@ + 2017-11-29 rocky + + * test/simple_source/bug30/01_ops.py, +- test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/stmts/00_import.py, uncompyle6/parsers/parse3.py: + Better grammar coverage; reduce 3.x mklambda rules + + 2017-11-29 rocky +@@ -10514,7 +10514,7 @@ + test/simple_source/stmts/01_augmented_assign.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/fragments.py: + NT augassign -> aug_assign to match AST + + 2017-11-29 rocky +@@ -10579,7 +10579,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT designatore -> store to match AST + + 2017-11-29 rocky +@@ -10596,7 +10596,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py, + uncompyle6/parsers/parse36.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + NT call_function -> call to match AST + + 2017-11-28 rocky +@@ -10669,7 +10669,7 @@ + + * __pkginfo__.py, + test/simple_source/bug25/01_inplace_true_divide.py, +- uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Mege hell ++ uncompyle6/parser.py, uncompyle6/parsers/parse25.py: Merge hell + + 2017-11-27 rocky + +@@ -10705,7 +10705,7 @@ + 2017-11-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse23.py, uncompyle6/parsers/parse27.py: + Grammar isolation + + 2017-11-27 rocky +@@ -10728,7 +10728,7 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse27.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + Grammar reduction + + 2017-11-26 rocky +@@ -10748,7 +10748,7 @@ + + 2017-11-26 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + localize Python2 ifelsetmtr, compare_chained: 2.7 + + 2017-11-26 rocky +@@ -10841,7 +10841,7 @@ + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, + uncompyle6/semantics/pysource.py: localize 2 and 3 argument +- BUILD_SLICE... Nontermninal name matches AST anme now. Add test. ++ BUILD_SLICE... Nontermninal name matches AST name now. Add test. + + 2017-11-25 rocky + +@@ -10924,7 +10924,7 @@ + + 2017-11-23 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py: + Improve try else in 3.2... Grammar from 3.3 is relevant here + + 2017-11-23 rocky +@@ -10941,7 +10941,7 @@ + 2017-11-23 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, +- uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: ++ uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse34.py: + grammar reduction of while loops + + 2017-11-23 rocky +@@ -10978,17 +10978,17 @@ + 2017-11-22 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: Reduce +- unecessary grammar rules in 2.x ++ unnecessary grammar rules in 2.x + + 2017-11-22 rocky + + * test/simple_source/stmts/01_augmented_assign.py, +- uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Increase grammar coverage + + 2017-11-22 rocky + +- * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: ++ * admin-tools/setup-master.sh, admin-tools/setup-python-2.4.sh: + Administrivia: add "git pull"s + + 2017-11-18 rocky +@@ -10999,7 +10999,7 @@ + 2017-11-18 rocky + + * pytest/test_grammar.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse24.py, uncompyle6/semantics/pysource.py: + Grammar cleanup: import_as_cont -> import_as + + 2017-11-18 rocky +@@ -11013,7 +11013,7 @@ + + 2017-11-17 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse33.py: + Python 3 grammar clean up and reorganization + + 2017-11-17 rocky +@@ -11050,7 +11050,7 @@ + + 2017-11-16 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse3.py: + Isolate "assert2" rule + + 2017-11-16 rocky +@@ -11081,11 +11081,11 @@ + 2017-11-15 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: More +- 2.7/2.7- grammer separation & cleanup ++ 2.7/2.7- grammar separation & cleanup + + 2017-11-15 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py: + Grammar cleanup: separate some 2.7 from 2.7- rules + + 2017-11-15 rocky +@@ -11127,7 +11127,7 @@ + + * test/Makefile, test/simple_source/stmts/10_del.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse26.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Profiling workarounds, more coverage ... test/Makefile: more grammar checking. Update python versions + 10_del.pyc add test of DEL_GLOBAL check_ast.py, pysource.py: Profileing workarounds + +@@ -11145,7 +11145,7 @@ + + 2017-11-13 rocky + +- * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: ++ * ChangeLog, uncompyle6/parser.py, uncompyle6/semantics/pysource.py: + detected old-style Python 2.4 class better + + 2017-11-13 rocky +@@ -11175,7 +11175,7 @@ + + 2017-11-09 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Fix bug in return-optimized try stmt + + 2017-11-09 rocky +@@ -11305,7 +11305,7 @@ + 2017-10-29 rocky + + * test/simple_source/bug36/10_extended_arg_loop.py, +- uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + Python 3.6 control flow bug... Much more is needed, but it's a start + + 2017-10-29 rocky +@@ -11316,9 +11316,9 @@ + 2017-10-29 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + Python 3.6-inspired instruction size cleanup Revise and generalize for Python 3.6+ instructions vs < 3.6 +- instuctions. Used more of the generalized methods in xdis and ++ instructions. Used more of the generalized methods in xdis and + remove some (but not all) of the magic numbers. This is a lot of changes, but not all of the refactoring needed. + Much crap still remains. Also, there are still bugs in handling 3.6 + bytecodes. +@@ -11342,7 +11342,7 @@ + + * pytest/test_pysource.py, uncompyle6/parser.py, + uncompyle6/parsers/parse24.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Start allowing node names in template engine These are now used to assert we have the right node type. Simplify import_from + + 2017-10-13 rocky +@@ -11351,7 +11351,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia - generalize shell code + + 2017-10-12 rocky +@@ -11364,7 +11364,7 @@ + + 2017-10-12 rocky + +- * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ * admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Administrivia + + 2017-10-12 rocky +@@ -11393,7 +11393,7 @@ + * admin-tools/check-newer-versions.sh, + admin-tools/check-older-versions.sh, + admin-tools/how-to-make-a-release.txt, +- admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: ++ admin-tools/make-dist-newer.sh, admin-tools/make-dist-older.sh: + Adminstrivia + + 2017-10-11 rocky +@@ -11428,7 +11428,7 @@ + + * HOW-TO-REPORT-A-BUG.md, test/Makefile, uncompyle6/parser.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + Improve parse trace. lambda fixes yet again + + 2017-10-10 rocky +@@ -11438,7 +11438,7 @@ + + 2017-10-10 rocky + +- * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner3.py: + Misc bugs + + 2017-10-10 R. Bernstein +@@ -11461,7 +11461,7 @@ + uncompyle6/semantics/make_function.py, + uncompyle6/semantics/pysource.py, uncompyle6/verify.py, + uncompyle6/version.py: Adjust for spark-parser 2.7.0 +- incompatabilities ++ incompatibilities + + 2017-10-05 rocky + +@@ -11494,7 +11494,7 @@ + + 2017-10-02 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: + spark-parser induced changes... reduce rules can be called without token streams. + + 2017-09-30 rocky +@@ -11518,7 +11518,7 @@ + + 2017-09-26 rocky + +- * uncompyle6/parsers/parse3.py: Pyton 3.1 Annotation args can be ++ * uncompyle6/parsers/parse3.py: Python 3.1 Annotation args can be + unicode? + + 2017-09-25 rocky +@@ -11532,7 +11532,7 @@ + 2017-09-21 rocky + + * pytest/test_pysource.py, uncompyle6/semantics/consts.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Unit test for format-specifiers And in the process we catch some small bugs + + 2017-09-20 rocky +@@ -11554,7 +11554,7 @@ + + 2017-09-20 rocky + +- * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/semantics/consts.py, uncompyle6/semantics/pysource.py: + More small doc changes + + 2017-09-20 rocky +@@ -11631,7 +11631,7 @@ + + 2017-08-13 rocky + +- * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: ++ * pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: + 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 + '2.7.13', accept that in looking up either a scanner or a parser. + +@@ -11657,7 +11657,7 @@ + 2017-07-17 rocky + + * __pkginfo__.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner30.py: + xdis's "exception match" is now "exception-match" + + 2017-07-15 rocky +@@ -11682,7 +11682,7 @@ + + 2017-07-09 rocky + +- * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: ++ * ChangeLog, HOW-TO-REPORT-A-BUG.md, NEWS, uncompyle6/version.py: + Get ready for release 2.11.2 + + 2017-07-08 rocky +@@ -11697,7 +11697,7 @@ + * 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: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/scanner36.py: + Start supporting Pypy 3.5 (5.7.1-beta) + + 2017-07-05 rocky +@@ -11714,13 +11714,13 @@ + 2017-06-28 rocky + + * uncompyle6/semantics/make_function.py: A guard against badly +- formated bytecode ++ formatted 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 ++ uncompyle6/semantics/pysource.py: 3.x function and annotation bug + fixes + + 2017-06-25 rocky +@@ -11731,7 +11731,7 @@ + + * __pkginfo__.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner30.py, uncompyle6/semantics/pysource.py: + Use xdis' instruction offset calculation fns.. next_offset, op_size, has_argument + + 2017-06-19 rocky +@@ -11798,7 +11798,7 @@ + 2017-06-08 rocky + + * uncompyle6/semantics/make_function.py: Correct make_function3 for +- Pytohn 3.2 ++ Python 3.2 + + 2017-06-08 rocky + +@@ -11812,7 +11812,7 @@ + + 2017-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + Remove hacky fragments try fixup... hacky call_function code is also not needed or will be reinstated + properly. Better grammar structure for Python 3.6 call_function. + +@@ -11820,7 +11820,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, + uncompyle6/scanners/scanner36.py: BUILD_{MAP,TUPLE}_UNPACK & +- CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally succesfull right now. In fact a ++ CALL_FUNCTION_EX_KW... Bang on these in 3.6. Not totally successful right now. In fact a + regression on one of the test cases + + 2017-06-05 rocky +@@ -11831,7 +11831,7 @@ + + 2017-06-04 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.5 *args with kwargs handling. 3.5 is a snowflake here. Thank you, Python. Fully fixes Issue 95. 3.6 is broken on this source, but for a *different* reason. Sigh. + + 2017-06-03 rocky +@@ -11883,7 +11883,7 @@ + + 2017-05-23 rocky + +- * uncompyle6/semantics/pysource.py: Fix up retreiving "async" ++ * uncompyle6/semantics/pysource.py: Fix up retrieving "async" + property on 3.6 + + 2017-05-23 rocky +@@ -11910,7 +11910,7 @@ + + 2017-05-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More explicit about 3.5 UNMAP_PACK Have to reduce 3.5 bytecode testing for now, code is more solid. + + 2017-05-19 rocky +@@ -11943,7 +11943,7 @@ + + 2017-05-19 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner3.py: + EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before + needing EXTENDED_ARG has been reduced to 256, but theoretically + possible in earlier versions. +@@ -11973,7 +11973,7 @@ + + 2017-05-16 rocky + +- * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Allow LOAD_CONST EXTENDED_ARG + + 2017-05-15 rocky +@@ -12011,7 +12011,7 @@ + 2017-05-13 rocky + + * README.rst, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + Bang on 3.6 MAKE_FUNCTION a bit more parse3.py, parse36.py: adding return_closure rule tags what's going + on with this rule pysource.py: start changing semantic rules to support code changed + by new make_function semantics README.rst: typo +@@ -12054,7 +12054,7 @@ + + * pytest/test_CALL_FUNCTION_KW.sh, pytest/test_function_call.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py, +- uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner36.py, uncompyle6/semantics/pysource.py: + Added support for support for Python 3.6 CALL_FUNCTION_KW + + 2017-05-08 rocky +@@ -12084,7 +12084,7 @@ + + 2017-05-07 rocky + +- * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is sematically equivalent, so it is is correct. ++ * test/Makefile: --weak-verify on 3.3 with inclusion of last commit Note that the result is semantically equivalent, so it is is correct. + + 2017-05-07 rocky + +@@ -12121,7 +12121,7 @@ + + 2017-05-05 rocky + +- * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py: + Improve Python 3.2 decompilation ... by removing a lot of the control-flow labels of 3.3+ + + 2017-05-05 rocky +@@ -12145,7 +12145,7 @@ + 2017-05-02 rocky + + * test/simple_source/bug35/01_map_unpack.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + BUILD_MAP_UNPACK'ing of dictionaries in 3.5 + + 2017-05-01 rocky +@@ -12159,7 +12159,7 @@ + 2017-04-29 rocky + + * test/simple_source/bug35/01_map_unpack.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Handle BUILD_MAP_UNPACK in a build_list + + 2017-04-27 rocky +@@ -12180,14 +12180,14 @@ + + 2017-04-22 rocky + +- * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduse scope ++ * uncompyle6/parser.py, uncompyle6/parsers/parse34.py: Reduce scope + of LOAD_ASSERT as expr to 3.4+ + + 2017-04-22 rocky + + * uncompyle6/parser.py, uncompyle6/verify.py: LOAD_ASSERT can also + be an expr This may have the undesirable property that assert statements might +- get tagged with equivalant low-level Python code that uses "raise ++ get tagged with equivalent low-level Python code that uses "raise + AssertionError", but so be it. Fixes #103 + + 2017-04-22 R. Bernstein +@@ -12200,7 +12200,7 @@ + + 2017-04-22 rocky + +- * HISTORY.md: History keeps gettting amended ++ * HISTORY.md: History keeps getting amended + + 2017-04-22 rocky + +@@ -12219,7 +12219,7 @@ + 2017-04-22 rocky + + * test/simple_source/bug33/02_pos_args.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/make_function.py: + 3.3+ bug in handling single kwarg after * Towards fixing issue #110 + + 2017-04-20 rocky +@@ -12245,7 +12245,7 @@ + + 2017-04-17 rocky + +- * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: ++ * test/simple_source/bug36/{01_if_file.py => 01_extended_arg.py}: + Rename test case to something more appropriate + + 2017-04-17 rocky +@@ -12306,7 +12306,7 @@ + + 2017-04-14 rocky + +- * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: ++ * test/simple_source/bug27+/{03_if_true_else.py => 03_if_1_else.py}: + Better names for a test + + 2017-04-13 rocky +@@ -12326,7 +12326,7 @@ + + 2017-04-13 rocky + +- * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse23.py, uncompyle6/semantics/pysource.py: + Add Python 2.3 rule for "if 1: ..." Fully fixes #97 for Python 2.3. Python 2.4 was fixed in a previous + commit. + +@@ -12349,13 +12349,13 @@ + 2017-04-11 rocky + + * test/simple_source/bug31/04_def_annotate.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Towards fixing annotated decorator functions... and annotate functions + + 2017-04-10 rocky + + * uncompyle6/parsers/parse2.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + Misc bugs parse2.py: restore accidently-removed while1stmt rule scanner27.py: + grammar typo check_ast: add while1else to list of looping constructs + pysource.py: CALL_FUNCTION_VAR_KW_ARGS with positional args rule is +@@ -12374,7 +12374,7 @@ + 2017-04-09 rocky + + * test/simple_source/def/10_kw+pos_args-bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Another Python 3.5 FUNCTION_VAR bug Fixes #94 + + 2017-04-09 rocky +@@ -12488,7 +12488,7 @@ + + 2017-02-28 rocky + +- * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: ++ * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse26.py: + Python 2.6 a == b or c == d == 3 grammar bug + + 2017-02-28 rocky +@@ -12539,7 +12539,7 @@ + + 2017-02-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse35.py: + Python 3.x needs more "while 1" grammar rules + + 2017-02-20 rocky +@@ -12669,7 +12669,7 @@ + + 2017-01-15 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Handle 3.6 BUILD_CONST_KEYMAP + + 2017-01-15 rocky +@@ -12702,7 +12702,7 @@ + 2017-01-10 rocky + + * test/simple_source/bug35/03_double_star_unpack.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Improve BUILD_xxx_UNPACK slightly + + 2017-01-09 rocky +@@ -12721,7 +12721,7 @@ + + 2017-01-08 rocky + +- * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse30.py, uncompyle6/scanners/scanner3.py: + Python 3.0 decompile bugs + + 2017-01-08 rocky +@@ -12752,7 +12752,7 @@ + 2017-01-07 rocky + + * test/simple_source/bug35/03_async_await.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + Start to add 3.5+ await and async + + 2017-01-07 rocky +@@ -12770,7 +12770,7 @@ + + 2017-01-07 rocky + +- * uncompyle6/semantics/make_function.py: Small Pyhton 3.x annotate ++ * uncompyle6/semantics/make_function.py: Small Python 3.x annotate + bug + + 2017-01-03 rocky +@@ -12789,7 +12789,7 @@ + + 2017-01-02 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Python 3.5 continue detection bug + + 2017-01-01 rocky +@@ -12799,7 +12799,7 @@ + + 2017-01-01 rocky + +- * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: + Towards fixing Python 3.5 return bugs + + 2017-01-01 rocky +@@ -12826,12 +12826,12 @@ + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + dectect_structure() -> detect_control_flow() + + 2016-12-29 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + DRY code and emitted Python 3 source * Python 3: break; continue -> break * Use variable in detect_structure for pre[rtarget] * Make Python 2 and Python 3 detect_structure more alie + + 2016-12-29 rocky +@@ -12868,7 +12868,7 @@ + 2016-12-27 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + WIP : Add THEN to disambigute from "and" + + 2016-12-27 rocky +@@ -12882,11 +12882,11 @@ + + 2016-12-26 R. Bernstein + +- * : Merge pull request #71 from jiangpengcheng/tupple_bug tupples which contain only 1 element need a comma ++ * : Merge pull request #71 from jiangpengcheng/tupple_bug tuples which contain only 1 element need a comma + + 2016-12-26 jiangpch + +- * uncompyle6/semantics/pysource.py: tupples which contain only 1 ++ * uncompyle6/semantics/pysource.py: tuples which contain only 1 + element need a comma + + 2016-12-26 rocky +@@ -12913,7 +12913,7 @@ + uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, + uncompyle6/scanners/scanner22.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Lint + + 2016-12-24 rocky +@@ -12930,7 +12930,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/bin/uncompile.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse25.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python flake8 crap Was testing realgud's C-x!8 (goto flake8 warning/error) + + 2016-12-18 rocky +@@ -12941,7 +12941,7 @@ + + 2016-12-17 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: + show-asm on python2.5 is optional make scanner2 look a little more like scanner3 + + 2016-12-16 rocky +@@ -13030,7 +13030,7 @@ + + 2016-11-28 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse36.py: + Shorten Python3 grammars with + and * + + 2016-11-28 rocky +@@ -13069,7 +13069,7 @@ + 2016-11-24 rocky + + * uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/helper.py, uncompyle6/semantics/pysource.py: + 2.7 grammar bug workaround. Fix docstring bug + + 2016-11-24 rocky +@@ -13079,7 +13079,7 @@ + + 2016-11-24 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: + <2.7 "if" detection and dup Python 3 grammar rule + + 2016-11-23 rocky +@@ -13162,7 +13162,7 @@ + 2016-11-20 rocky + + * pytest/test_fjt.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Start to improve detect_structure for 2.7 and 2.x Add debug flag to find_jump_targets to show the structure we found. + When there are control-flow bugs, it's often reflected here. scanner3.py: make code make more similar to 2.x code + +@@ -13178,7 +13178,7 @@ + 2016-11-16 rocky + + * test/simple_source/bug26/03_if_vs_and.py, uncompyle6/main.py, +- uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/check_ast.py, uncompyle6/semantics/pysource.py: + More AST checking Small fixes in output format + + 2016-11-15 rocky +@@ -13198,17 +13198,17 @@ + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + WIP remove COME_FROMs around ignore_if's + + 2016-11-14 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Show line numbers in 2.6 "after" asm .. start to understand some of the Python 2.6 bytecode parse failures. + + 2016-11-13 rocky +@@ -13244,7 +13244,7 @@ + 2016-11-11 rocky + + * uncompyle6/parser.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Revert augassign change but.. Make note of what's going on and add grammar test for bad situations + we have in Python 2.6 (and perhaps others) + +@@ -13264,7 +13264,7 @@ + 2016-11-10 rocky + + * uncompyle6/main.py, uncompyle6/semantics/check_ast.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Detect some erroneous decompilations Until we can actually prevent these in grammar rules, we will warn + of improper decompilations. Also, we now stop when we hit a decompile error. Previously we were + not. +@@ -13276,7 +13276,7 @@ + 2016-11-07 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse30.py, +- uncompyle6/parsers/parse32.py: Possiby tidy grammar ++ uncompyle6/parsers/parse32.py: Possibly tidy grammar + + 2016-11-06 rocky + +@@ -13331,13 +13331,13 @@ + + 2016-10-30 rocky + +- * .gitignore, README.rst, test/simple_source/def/03_class_method.py: ++ * .gitignore, README.rst, test/simple_source/def/03_class_method.py: + Note github unpyc3 and.. - Add source to bytecode_2.2/03_class_method.pyc - more ignore + + 2016-10-30 rocky + + * uncompyle6/semantics/make_function.py: More source-code line +- indention in make_function.. and remove Python 3 situations from make_function2() ++ indentation in make_function.. and remove Python 3 situations from make_function2() + + 2016-10-29 rocky + +@@ -13360,20 +13360,20 @@ + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse31.py, uncompyle6/parsers/parse32.py, +- uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse35.py, uncompyle6/semantics/pysource.py: + More complete annotate handling Still have a bit of work to do though. + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/parse32.py, uncompyle6/parsers/parse33.py, +- uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse34.py, uncompyle6/semantics/pysource.py: + Expand annotate return to Python 3.4 + + 2016-10-28 rocky + + * pytest/test_grammar.py, uncompyle6/parsers/parse31.py, +- uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse32.py, uncompyle6/semantics/pysource.py: + Expand annotate handling to 3.3 (and possibly 3.2) - DRY Python 3.1-3.3 grammar a little + + 2016-10-28 rocky +@@ -13386,7 +13386,7 @@ + 2016-10-27 rocky + + * test/simple_source/bug31/{04_def_attr.py => 04_def_annotate.py}, +- uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse31.py, uncompyle6/semantics/pysource.py: + Clean and fix Python 3 annotate arg return + + 2016-10-26 rocky +@@ -13461,7 +13461,7 @@ + 2016-10-20 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + further work on supporting single and multiple fstring decompilation + + 2016-10-20 rocky +@@ -13472,7 +13472,7 @@ + 2016-10-19 moagstar + + * pytest/test_fstring.py, uncompyle6/parsers/parse3.py, +- uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse36.py, uncompyle6/semantics/pysource.py: + urther work on fstrings for python 3.6 - there is a new opcode + build_string which is used to improve fstring performance, but broke + the fstring support in uncompyle +@@ -13508,7 +13508,7 @@ + 2016-10-13 rocky + + * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may neeed arbitrary come_froms for each except clause ++ uncompyle6/scanners/scanner26.py: 2.6 try statement (and below) They may need arbitrary come_froms for each except clause + + 2016-10-13 rocky + +@@ -13582,7 +13582,7 @@ + 2016-10-08 rocky + + * uncompyle6/bin/uncompile.py, uncompyle6/parsers/parse21.py, +- uncompyle6/semantics/pysource.py: Simpify python 2.1 grammar Fix bug ++ uncompyle6/semantics/pysource.py: Simplify python 2.1 grammar Fix bug + with -t ... Wasn't showing source text when -t option was given + + 2016-10-08 rocky +@@ -13660,13 +13660,13 @@ + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Python 3: "and" doesn't have optional come_from + + 2016-10-05 rocky +@@ -13696,7 +13696,7 @@ + 2016-09-26 rocky + + * HISTORY.md, uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Interval order COME_FROMs in Python3 This bug had possibly caused lots of grammar pollution which may + need addressing. We want to process COME_FROMs to the same offset to be in + *descending* order so we have the larger range or biggest +@@ -13746,7 +13746,7 @@ + * pytest/test_grammar.py, pytest/test_single_compile.py, + test/Makefile, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py: Add COME_FROM_LOOP Note: we have regressed in --verify and some tests, but I believe +- that's because we are producing more equivalant (if uglier) ++ that's because we are producing more equivalent (if uglier) + programs. That's a separate problem though. + + 2016-09-22 rocky +@@ -13781,7 +13781,7 @@ + + 2016-09-21 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Python 2 & 3 scanner code ever so slightly closer + + 2016-09-21 rocky +@@ -13791,7 +13791,7 @@ + 2016-09-18 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/semantics/pysource.py: + Small changes + + 2016-09-11 rocky +@@ -13802,7 +13802,7 @@ + 2016-09-11 rocky + + * test/bytecode_3.6/fstring.py, +- test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: ++ test/bytecode_3.6/fstring_single.py, uncompyle6/parsers/parse35.py: + Tidy a bit + + 2016-09-09 rocky +@@ -13816,7 +13816,7 @@ + + 2016-09-09 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + ret_cond adjustment for < 2.7 and ... "<= 2.6" -> "< 2.7" since python 2.6's version is 2.6000001 + + 2016-09-09 rocky +@@ -13838,7 +13838,7 @@ + + 2016-09-08 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.0-3.2 *args processing + + 2016-09-08 rocky +@@ -13874,7 +13874,7 @@ + + * uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 2.6- try/except control flow detection + + 2016-09-04 rocky +@@ -13909,7 +13909,7 @@ + + * test/simple_source/bug26/07_generator_return.py, + uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: A +- couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: descriminate more on parent type ++ couple more 2.6 (and below) bugs fixed * Detect "return None" inside if statement * another case of triple ==, ==, == scanner2.py: detect_structure: discriminate more on parent type + + 2016-09-03 rocky + +@@ -13925,7 +13925,7 @@ + + * test/simple_source/bug26/08_triple_equals.py, + uncompyle6/scanners/scanner2.py: Python 2.2..2.6 bug in a == b == c +- == d Fix was to remove some come froms. Feels a little hacky though. ++ == d Fix was to remove some COME_FROMS. Feels a little hacky though. + + 2016-09-03 rocky + +@@ -13949,19 +13949,19 @@ + 2016-09-02 rocky + + * test/simple_source/bug26/06_return_pop.py, +- uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + Python 2.6- bug: RETURN_ENDIF, POP_TOP .. POP_TOP should be excluded as a potentional statement beginning + + 2016-09-02 rocky + + * test/simple_source/bug33/02_named_and_kwargs.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x named param and kwargs bug + + 2016-09-01 rocky + + * test/simple_source/bug26/04_while_and_stmt_one_line.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.6- bug: while..and: stmt - on one line If 2.6 or before POP_BLOCK after a JUMP_IF_FALSE does not constitute + a new statement. The POP_BLOCK is really part of the JUMP_IF_FALSE. + In Python 2.7+ it's a single op. +@@ -13969,7 +13969,7 @@ + 2016-09-01 rocky + + * test/simple_source/bug26/02_except_as.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Handle Python 2.6 and below "except , " + + 2016-08-31 rocky +@@ -13985,7 +13985,7 @@ + uncompyle6/scanners/scanner3.py, uncompyle6/verify.py: Bug in 3.x + detecting "if" structure and ... scanner3.py: bug in 3.x detecting "if" structure Make scanner2.py + look more like scanner3.py verify.py: add weak-verify which tests +- Pytyon syntax, but not code ++ Python syntax, but not code + + 2016-08-30 rocky + +@@ -14111,7 +14111,7 @@ + * README.rst, uncompyle6/parser.py, uncompyle6/parsers/parse22.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner22.py, + uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/semantics/pysource.py: + Start handling Python 2.2 bytecode and... Fix some bugs in Python 2.3-2.5 bytecode handling + + 2016-08-11 Omer Katz +@@ -14180,7 +14180,7 @@ + 2016-07-29 rocky + + * uncompyle6/parsers/parse35.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix 3.5 misclassifying RETURN_VALUE We use location of SETUP_EXCEPT instructions to disambiguate. + + 2016-07-28 Daniel Bradburn +@@ -14279,13 +14279,13 @@ + + 2016-07-27 rocky + +- * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse2.py, uncompyle6/semantics/pysource.py: + Small code clean up + + 2016-07-26 rocky + + * uncompyle6/scanners/tok.py, uncompyle6/semantics/fragments.py, +- uncompyle6/verify.py: Usuability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function ++ uncompyle6/verify.py: Usability fixes * try using format for __str__ * Explicitly nuke self.attr and self.pattr when no arg * Sync pysource and format wrt make_function + + 2016-07-26 rocky + +@@ -14307,7 +14307,7 @@ + test/simple_source/bug_pypy27/03_try_return.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + More PyPy grammar rules * assert one and two-arg form * trystmt Simplify adding multiple grammar rules + + 2016-07-25 rocky +@@ -14369,7 +14369,7 @@ + * README.rst, test/simple_source/stmts/03_if_elif.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse27.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Handle PyPy JUMP_IF_NOT_DEBUG Update README.rst to note PyPY and reorganize a little + + 2016-07-25 rocky +@@ -14391,7 +14391,7 @@ + test/Makefile, test/test_pythonlib.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + PyPy support * Use proper PYPY 32 opcodes * handle opcodes LOOKUP_METHOD and CALL_METHOD * Administrative stuff for PyPy + + 2016-07-24 Daniel Bradburn +@@ -14411,19 +14411,19 @@ + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky + + * test/simple_source/bug27+/05_for_try_except.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner27.py: + Another 2.7 'continue' detection bug + + 2016-07-23 rocky +@@ -14472,7 +14472,7 @@ + + 2016-07-17 rocky + +- * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: ++ * pytest/testdata/if-2.7.right, pytest/testdata/ifelse-2.7.right: + Adjust test data for changed disasm output + + 2016-07-16 rocky +@@ -14506,14 +14506,14 @@ + + 2016-07-14 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Attempt to get 3.5 RETURN_END_IF working This feels hacky and I'm not sure is quite right. Untili we + understand better what to do though, we'll go with it. + + 2016-07-14 rocky + + * test/Makefile, uncompyle6/semantics/pysource.py: 3.x __qualname__ +- = supression Class names have become more complicated so the pattern test needs ++ = suppression Class names have become more complicated so the pattern test needs + to be more complex as well. Sigh + + 2016-07-14 rocky +@@ -14576,7 +14576,7 @@ + + * test/simple_source/bug33/05_store_name.py, + test/simple_source/comprehension/05_3x_set_comphension.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 & 3.3 handle STORE_NAME better + + 2016-07-11 rocky +@@ -14631,13 +14631,13 @@ + + 2016-07-10 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + Bugs caused by 3.x jump_forward misclasification + + 2016-07-10 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py: + Python 3 better CONTINUE op classification Also document what's up with JUMP_ABSOLUTE classification + + 2016-07-09 rocky +@@ -14728,7 +14728,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Python 3 code cleanup + + 2016-07-08 rocky +@@ -14749,7 +14749,7 @@ + 2016-07-08 rocky + + * uncompyle6/parsers/parse24.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner26.py: + Python 2.4 generator expressions and gen_comp_body + + 2016-07-08 rocky +@@ -14765,7 +14765,7 @@ + uncompyle6/parser.py, uncompyle6/parsers/parse24.py, + uncompyle6/parsers/parse25.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner24.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/semantics/pysource.py: Start handling Pyton 2.4 bytecodes ++ uncompyle6/semantics/pysource.py: Start handling Python 2.4 bytecodes + + 2016-07-08 rocky + +@@ -14775,12 +14775,12 @@ + 2016-07-08 rocky + + * test/simple_source/stmts/11_return_val.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + 2.5/2.6 RETURN_VALUE bug + + 2016-07-08 rocky + +- * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: ++ * uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: + 2.5/2.6 fn name clash fixes list conprehension problem + + 2016-07-08 rocky +@@ -14808,7 +14808,7 @@ + + 2016-07-07 rocky + +- * : Remove 2.7 asynchat verifcation for now ++ * : Remove 2.7 asynchat verification for now + + 2016-07-07 rocky + +@@ -14822,7 +14822,7 @@ + + 2016-07-07 rocky + +- * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + <2.6 make sure jump back on loops is really "back" + + 2016-07-07 rocky +@@ -14869,7 +14869,7 @@ + + * uncompyle6/semantics/fragments.py, + uncompyle6/semantics/pysource.py: More offsets captrued Add %b +- specifer %b - associate text before specifier pysource.py: small doc ++ specifier %b - associate text before specifier pysource.py: small doc + correction + + 2016-07-03 rocky +@@ -14881,12 +14881,12 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py: + Another 2.6 while stmt. Clean up grammar a little + + 2016-07-03 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/scanners/scanner2.py: + 2.6 improper tagging of RETURN_END_IF + + 2016-07-02 rocky +@@ -14923,7 +14923,7 @@ + 2016-06-30 rocky + + * test/simple_source/stmts/06_for_break.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + More 2.6.9 bugs fixed * break loop parsing bug * ifelsestmt semantic-action bug in handling else + + 2016-06-30 rocky +@@ -14940,13 +14940,13 @@ + 2016-06-30 rocky + + * test/simple_source/comprehension/05_for_for.py, +- uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6.9 list comprehension + + 2016-06-30 rocky + + * test/simple_source/exception/07_try_pass.py, +- uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in tey/except blocks ++ uncompyle6/scanners/scanner2.py: <= 2.6 weird jump out of try block Allow COME_FROMs to appare via JUMP_FORWARD in try/except blocks + + 2016-06-30 rocky + +@@ -14982,7 +14982,7 @@ + + 2016-06-28 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + Weird 2.6.9 list comprehension + + 2016-06-28 rocky +@@ -14999,17 +14999,17 @@ + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py, + uncompyle6/parsers/parse27.py, uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Base 2.5 off of 2.6. Some other small bugs. + + 2016-06-27 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/parse26.py: 2.6 try +- except hadnling works now ++ except handling works now + + 2016-06-27 rocky + +- * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse26.py, uncompyle6/semantics/pysource.py: + 2.6 list comprehensions + + 2016-06-27 rocky +@@ -15029,8 +15029,8 @@ + + 2016-06-24 rocky + +- * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 psuedo bytecode I think +- is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better assocate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental ++ * : WIP Python-2.6 but don't remove opcodes The scheme for turning 2.6 bytecode into 2.7 pseudo bytecode I think ++ is a lose. I won't work for fragment handling. Instead, change the grammar and syntax rules This also has the benefits: * We see how code generation changed over releases by looking at grammar and semantic rules rather than arbitrary code * We can better associate with what's running (in a sense this is a restatement of broken fragment handling) * With the right structure in place we are in a better position to handle 2.5, 2.4, etc. That is, after a while, the incremental + changes to get say from python 2.3 bytecode to python 2.7 are + great. Conflicts: uncompyle6/parsers/astnode.py + +@@ -15040,7 +15040,7 @@ + + 2016-06-24 rocky + +- * uncompyle6/scanners/scanner2.py: Small formating changes ... and premonition of 2.6 byteocde work ++ * uncompyle6/scanners/scanner2.py: Small formatting changes ... and premonition of 2.6 byteocde work + + 2016-06-24 rocky + +@@ -15052,7 +15052,7 @@ + * __pkginfo__.py, uncompyle6/parsers/astnode.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse26.py, + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 psuedo bytecode. Instead ++ uncompyle6/semantics/pysource.py: WIP 2.6 redo bytecode handling Don't try to convert 2.6 bytecode to 2.7 pseudo bytecode. Instead + adjust grammar and semantic actions. Down the line we should to segregate version changes in semantic + code better. + +@@ -15094,7 +15094,7 @@ + 2016-06-22 rocky + + * test/simple_source/expression/05_yield_from.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + differing ways to do "yield from" in 3.3-3.5 + + 2016-06-22 rocky +@@ -15103,7 +15103,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python 3.5 yield from and ... * fragments.py: Handle pass stmt sometimes * scanners: regularize Python 2 scanners some * test/test_pyenvlib.py: add python 3.5.1 option + + 2016-06-22 rocky +@@ -15113,7 +15113,7 @@ + + 2016-06-22 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + More 3.2 LOAD_CONST removal More python3 custom grammar DRYing + + 2016-06-22 rocky +@@ -15125,7 +15125,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/simple_source/expression/10_lambda.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3.2 MAKE_FUNCTION adjustment + + 2016-06-22 rocky +@@ -15144,18 +15144,18 @@ + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Bang on Python 3.2 decompiling. + + 2016-06-20 rocky + + * uncompyle6/parsers/parse3.py, uncompyle6/scanner.py, +- uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py: + Python 3 needs Python2's RETURN_END_IF Make python2 and python3 scanner look more the same + + 2016-06-20 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py: + previous 2.7 class decorator bug fixed in 3.x + + 2016-06-20 rocky +@@ -15187,7 +15187,7 @@ + + * test/simple_source/def/11_mkfunc_closure.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 3.x make closure kw args handling bug + + 2016-06-20 rocky +@@ -15224,7 +15224,7 @@ + * test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + 2.7 and 3.x bug in dict comprehensions + + 2016-06-19 rocky +@@ -15242,7 +15242,7 @@ + + * test/simple_source/looping/08_while_except_bug.py, + uncompyle6/parser.py, uncompyle6/parsers/parse2.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 except clause parsing bug + + 2016-06-19 rocky +@@ -15304,18 +15304,18 @@ + * pytest/test_deparse.py, + test/simple_source/comprehension/05_set_comprehension.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix python 3 set comprehension and ... Add a few set/list comprehension offsets for Python 3 + + 2016-06-06 rocky + + * uncompyle6/parser.py, uncompyle6/parsers/astnode.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + small changes + + 2016-06-06 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/fragments.py: + include offset for starting listcomp + + 2016-06-03 rocky +@@ -15337,7 +15337,7 @@ + uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner23.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Limited support for Python 2.3 + + 2016-06-03 rocky +@@ -15435,7 +15435,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: ++ uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py: + Bang again on Python 2.5 and 2.6 scanners + + 2016-05-29 rocky +@@ -15447,7 +15447,7 @@ + 2016-05-29 rocky + + * uncompyle6/scanners/scanner2.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Start to DRY 2.6 scanner Note: can't use xdis 2.6 opcode until another xdis release. + + 2016-05-29 rocky +@@ -15464,7 +15464,7 @@ + + * uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner33.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + DRY scanners more + + 2016-05-28 rocky +@@ -15479,7 +15479,7 @@ + * test/simple_source/comprehension/06_list_ifnot.py, + test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/scanners/dis3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/semantics/pysource.py: + Remove dis3. Fix in 3.x list if not comprehension + + 2016-05-28 rocky +@@ -15490,7 +15490,7 @@ + 2016-05-28 rocky + + * uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_33.py, +- uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: ++ uncompyle6/opcodes/opcode_34.py, uncompyle6/scanners/scanner3.py: + Remove dup 3.x opcodes + + 2016-05-28 rocky +@@ -15500,7 +15500,7 @@ + 2016-05-28 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner32.py, +- uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py: + xdis for Python 3 opcodes + + 2016-05-28 rocky +@@ -15545,7 +15545,7 @@ + test/simple_source/def/06_return_bug.py, + uncompyle6/semantics/pysource.py: final RETURN removal bug We want to remove a final return from a module, but otherwise not. + Note we'll no lonager be able to verify functools.pyc as there is +- now a return after a raise statement. That will have to be delt with ++ now a return after a raise statement. That will have to be dealt with + separately. May address Issue #17. + + 2016-05-22 rocky +@@ -15591,7 +15591,7 @@ + 2016-05-20 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to igore fragment stuff ++ uncompyle6/semantics/pysource.py: Fragment fixes fragments.py: * Use "%x" specifier if for iterators * Add '%D' interpretation pysource.py: TABLE_DIRECT can get messed up from running fragments duplicate "%x" specifier to ignore fragment stuff + + 2016-05-19 rocky + +@@ -15602,7 +15602,7 @@ + 2016-05-18 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: ++ test/simple_source/expression/06_frozenset.py, uncompyle6/marsh.py: + Handle marshal frozenset + + 2016-05-18 rocky +@@ -15642,14 +15642,14 @@ + 2016-05-17 rocky + + * pytest/test_marsh.py, +- test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: ++ test/simple_source/expression/02_complex.py, uncompyle6/marsh.py: + Fix marshal bug in handling complex numbers + + 2016-05-17 rocky + + * Makefile, test/simple_source/def/09_class_closure.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Fix Python 3.x bugs * class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS + + 2016-05-16 rocky +@@ -15665,7 +15665,7 @@ + + 2016-05-16 rocky + +- * : Readd some 3.x loop tests ++ * : Re-add some 3.x loop tests + + 2016-05-16 rocky + +@@ -15719,7 +15719,7 @@ + + * test/simple_source/expression/05_lambda.py, + test/test_pyenvlib.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py: + Fix bug in Python 3 lambda expression handling Some other small cleanup changes + + 2016-05-15 rocky +@@ -15727,7 +15727,7 @@ + * uncompyle6/bin/pydisassemble.py, uncompyle6/disas.py, + uncompyle6/parser.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: ++ uncompyle6/scanners/scanner35.py, uncompyle6/scanners/tok.py: + pydisassemble disassemble without grammar mangling Some other small cleanups as well + + 2016-05-15 rocky +@@ -15767,7 +15767,7 @@ + + * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, + uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY scanner34 and scanner35 handle 3.0..3.4 build maps as key/value pairs + + 2016-05-15 rocky +@@ -15776,7 +15776,7 @@ + + 2016-05-14 rocky + +- * test/Makefile, uncompyle6/scanners/dis3.py: Python2 comptability ++ * test/Makefile, uncompyle6/scanners/dis3.py: Python2 compatibility + in using Python 3 disassembly Also fixes ablility to run bytecode 3.5 tests from 2.x now For Python 2 reading python3 bytstrings, we need to make sure we + confer the character to a number. + +@@ -15800,7 +15800,7 @@ + 2016-05-14 rocky + + * ChangeLog, __pkginfo__.py, uncompyle6/version.py: Fix botched +- entry point names Get ready for relase 2.3.6 ++ entry point names Get ready for release 2.3.6 + + 2016-05-14 rocky + +@@ -15839,7 +15839,7 @@ + 2016-05-12 rocky + + * uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner35.py: + More small changes + + 2016-05-12 rocky +@@ -15856,7 +15856,7 @@ + + * __pkginfo__.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Misc fixups/cleanups * parse3.py Had botched if-for-else test by grammar addition * semantics/*.py: Show errorstack in failed parse when -g (requires + sparck 1.2.0) * some optimization in scanner3 + +@@ -15870,7 +15870,7 @@ + uncompyle6/parsers/parse3.py, uncompyle6/scanners/dis35.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner34.py, + uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Redo make_function for *, arg main(*, file='foo') and things like that now work + + 2016-05-11 rocky +@@ -15902,7 +15902,7 @@ + 2016-05-09 rocky + + * test/simple_source/stmts/09_whiletrue_bug.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Python 3 "while True" bug + + 2016-05-09 rocky +@@ -15972,7 +15972,7 @@ + + * test/simple_source/comprehension/10-list-ifnot.py, + uncompyle6/main.py, uncompyle6/parser.py: come_from_opt handles +- and/or precidence properly main.py: give a better error message when file is not found. ++ and/or precedence properly main.py: give a better error message when file is not found. + + 2016-05-08 rocky + +@@ -15996,7 +15996,7 @@ + + * HISTORY.md, test/simple_source/branching/10_if_pass.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner35.py: + Fix 3.5 if..pass bug Update HISTORY.MD to include Dan Pascu. Some minor doc corrections + + 2016-05-08 rocky +@@ -16013,7 +16013,7 @@ + + * test/simple_source/expression/05_yield_from.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3 yield from Start dealing with MAKE_FUNCTION flags - not done yet. + + 2016-05-06 rocky +@@ -16042,7 +16042,7 @@ + test/simple_source/stmts/10_if_break_finally.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py: More +- Python 2 and 3 deparsing bugs fixed * while + if break * try + finall /pass ++ Python 2 and 3 deparsing bugs fixed * while + if break * try + finally pass + + 2016-05-05 rocky + +@@ -16078,19 +16078,19 @@ + 2016-05-05 rocky + + * test/simple_source/def/05_abc_class.py, +- test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: ++ test/simple_source/def/06_classbug.py, uncompyle6/parsers/parse3.py: + Python 3.5 abc.py bug distilled + + 2016-05-05 rocky + +- * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: ++ * uncompyle6/scanners/dis35.py, uncompyle6/scanners/scanner35.py: + Add cross-Python-protable 3.5 dis module + + 2016-05-04 rocky + + * test/simple_source/stmts/05_with.py, + uncompyle6/opcodes/opcode_35.py, uncompyle6/parser.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner35.py: + Handle 3.5 with [as] scanner35.py: Fix a small variable-name typo + + 2016-05-03 rocky +@@ -16100,7 +16100,7 @@ + 2016-05-03 rocky + + * uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/scanners/scanner35.py: + Don't repeat next_except_jump + + 2016-05-03 rocky +@@ -16150,7 +16150,7 @@ + + * ChangeLog, NEWS, __pkginfo__.py, bin/pydisassemble, + bin/uncompyle6, setup.py, uncompyle6/__init__.py, +- uncompyle6/version.py: Add -V | --version and simplfy changing it ++ uncompyle6/version.py: Add -V | --version and simplify changing it + + 2016-05-01 rocky + +@@ -16212,13 +16212,13 @@ + + 2016-04-30 rocky + +- * uncompyle6/parsers/parse3.py: Python 3.5 if statments decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 ++ * uncompyle6/parsers/parse3.py: Python 3.5 if statements decompyle Sometimes it doesn't need JUMP_FORWARD _come_from _come_from For example: def handle2(module): if module == 'foo': try: module = 1 except ImportError as exc: module = exc return module And: if __name__: for i in (1, 2): x = 3 + + 2016-04-28 rocky + + * requirements.txt, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + spark -> spark_parser + + 2016-04-28 rocky +@@ -16366,7 +16366,7 @@ + 2016-01-02 rocky + + * uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, +- uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: ++ uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py: + Make ScannerXX() initialization the same on Python 2.x and 3.x + + 2016-01-02 rocky +@@ -16460,7 +16460,7 @@ + 2015-12-31 rocky + + * test/simple_source/def/05_class.py, uncompyle6/parsers/parse3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Handle Python 3.3 > dotted class names + + 2015-12-30 rocky +@@ -16483,7 +16483,7 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ * uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Remove accidental schmutz. Try using pattr on 3.4 to get fn names + + 2015-12-30 rocky +@@ -16523,14 +16523,14 @@ + + 2015-12-30 rocky + +- * uncompyle6/parsers/parse3.py: Tidy parse3 grammer a little ++ * uncompyle6/parsers/parse3.py: Tidy parse3 grammar a little + + 2015-12-30 rocky + + * test/simple_source/exception/25_try_except.py, + test/test_pythonlib.py, uncompyle6/parsers/parse3.py, + uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/scanners/scanner34.py, uncompyle6/semantics/pysource.py: + Towards Python3 getting try/except working more often. + + 2015-12-29 rocky +@@ -16563,7 +16563,7 @@ + + * README.rst, test/Makefile, uncompyle6/opcodes/opcode_32.py, + uncompyle6/opcodes/opcode_33.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: ++ uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py: + scanner3: Python 2.6 compatibility: change set initializations. Get + rid of * import opcode_*: only a little of the much-needed larger + cleanup Makefile: remove 3.x bytecode checking from Python 2.x for +@@ -16582,7 +16582,7 @@ + + * uncompyle6/disas.py, uncompyle6/load.py, uncompyle6/main.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner3.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Add Python3 marshal codes and start to handle cross-version Python + code object types, introducing scan.Code3 + +@@ -16632,7 +16632,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16648,7 +16648,7 @@ + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, + uncompyle6/scanners/scanner3.py, uncompyle6/scanners/scanner32.py, + uncompyle6/scanners/scanner33.py, uncompyle6/scanners/scanner34.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + DRY Python3 scanner code. Some cross version handling fixed. Some + Python 3.2 and 3.3 deparse fixes. + +@@ -16708,9 +16708,9 @@ + test/simple_source/{simple_stmts => stmts}/15_assert.py, + test/simple_source/stmts/15_for_if.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Fix up looping by reinstating JUMP_ABSOLUTE -> JUMP_BACK or CONTINUE +- get jump offsets into jump attributes. Fix up 3.2 scanner paritally ++ get jump offsets into jump attributes. Fix up 3.2 scanner partially + and use that in 3.4 for in cross version disassembly. + + 2015-12-26 rocky +@@ -16747,7 +16747,7 @@ + 2015-12-25 rocky + + * .gitignore, ChangeLog, MANIFEST.in, NEWS, __pkginfo__.py, +- test/Makefile: Get ready for releaes 2.0.0 ++ test/Makefile: Get ready for release 2.0.0 + + 2015-12-25 rocky + +@@ -16777,7 +16777,7 @@ + + * pytest/test_load.py, test/dis-compare.py, uncompyle6/disas.py, + uncompyle6/load.py, uncompyle6/main.py, uncompyle6/verify.py: Show +- embeded timestamp of byte-decompiled file ++ embedded timestamp of byte-decompiled file + + 2015-12-23 rocky + +@@ -16792,7 +16792,7 @@ + + * test/simple_source/simple_stmts/00_import.py, + test/simple_source/simple_stmts/00_pass.py, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: + Start Python3 class(superclass) handling + + 2015-12-23 rocky +@@ -16808,13 +16808,13 @@ + + 2015-12-23 rocky + +- * uncompyle6/semantics/fragments.py: Add fragmnet offsets for 'from ++ * uncompyle6/semantics/fragments.py: Add fragment offsets for 'from + x import..' + + 2015-12-22 rocky + + * uncompyle6/semantics/fragments.py, +- uncompyle6/semantics/pysource.py: Propogate offsets in imports. ++ uncompyle6/semantics/pysource.py: Propagate offsets in imports. + Added a new %x format specifier. + + 2015-12-22 rocky +@@ -16826,7 +16826,7 @@ + uncompyle6/opcodes/opcode_27.py, uncompyle6/opcodes/opcode_34.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/parsers/spark.py, +- uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: ++ uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: + Allow comments in grammar rules. Start working on Python3 class (not + finished). More test organization. + +@@ -16835,7 +16835,7 @@ + * test/simple_source/def/01_class.py, + test/simple_source/def/10_class.py, + uncompyle6/opcodes/opcode_32.py, uncompyle6/opcodes/opcode_34.py, +- uncompyle6/parsers/parse3.py: Remove Python2 buitin "print" from ++ uncompyle6/parsers/parse3.py: Remove Python2 builtin "print" from + Python3's grammr. Start class tests + + 2015-12-22 rocky +@@ -16843,7 +16843,7 @@ + * bin/uncompyle6, uncompyle6/main.py, uncompyle6/parser.py, + uncompyle6/parsers/parse2.py, uncompyle6/parsers/spark.py, + uncompyle6/semantics/pysource.py: main.py, pysource.py DRY +- deparse_code from main. Is better on showing exception errrors such ++ deparse_code from main. Is better on showing exception errors such + as when a pyc file is not found uncompyle6: Hook in --grammar option + to showing grammar. rules. Default now does not show timestamp. + +@@ -16870,7 +16870,7 @@ + test/simple_source/slice/{01_slice.py => 02_slice.py}, + uncompyle6/main.py, uncompyle6/parsers/parse3.py, + uncompyle6/parsers/spark.py, uncompyle6/semantics/pysource.py: Add +- spark option to show grammer. Revise uncompyle options. Start to ++ spark option to show grammar. Revise uncompyle options. Start to + reorganize tests more + + 2015-12-21 rocky +@@ -16908,8 +16908,8 @@ + test/simple_source/exception/01_try_except.py, + test/simple_source/misc/assign_none_str.py, + test/simple_source/{misc/assign.py => simple_stmts/00_assign.py}, +- uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: +- Start Python3 execption handling ++ uncompyle6/parsers/parse3.py, uncompyle6/semantics/pysource.py: ++ Start Python3 exception handling + + 2015-12-21 rocky + +@@ -17019,7 +17019,7 @@ + + * test/Makefile, test/simple-source/misc/assign_none.py, + test/simple-source/misc/assign_none_str.py, uncompyle6/marsh.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Python 3 decompilation from Python2 + + 2015-12-20 rocky +@@ -17037,7 +17037,7 @@ + 2015-12-20 rocky + + * Makefile, README.rst, test/Makefile, test/dis-compare.py, +- uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: ++ uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/walker.py: + Go over makefiles to make "make check" work. walker, deparser: use + zip_longest + +@@ -17048,8 +17048,8 @@ + + 2015-12-19 rocky + +- * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatiblity +- for getting precidence. n_mkfunc needs to key off of bytecode ++ * uncompyle6/deparser.py, uncompyle6/walker.py: Python3 compatibility ++ for getting precedence. n_mkfunc needs to key off of bytecode + version, not running Python version. + + 2015-12-19 rocky +@@ -17107,7 +17107,7 @@ + test/simple-source/precedence/left.py, + test/simple-source/precedence/right.py, + test/simple-source/precedence/structure.py, +- uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner34.py: + Python 3 bytecode handles opcodes with varargs (better). Decompiling + assert works. Add more of the simple tests and their compiled + bytecode. +@@ -17135,7 +17135,7 @@ + uncompyle6/scanners/scanner34.py: marshal.py: Python2 marshal code + shouldn't try to turn a code object into a string. parse3.py: handle + both keyword and positional function calls. scanner34.py: Remove +- extra level of quoting in LOAD_CONST. Keyward handling now works ++ extra level of quoting in LOAD_CONST. Keyword handling now works + cross Python 2/3. Some other spelling and doc fixes. + + 2015-12-18 rocky +@@ -17144,12 +17144,12 @@ + uncompyle6/disas.py, uncompyle6/parser.py, + uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, + uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/walker.py: Python3 postional arguments. Clean up code ++ uncompyle6/walker.py: Python3 positional arguments. Clean up code + more along the lines of uncompyle3. + + 2015-12-18 rocky + +- * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: ++ * test/simple-source/comprehension/forelse.py, uncompyle6/disas.py: + disas.py: Do better for finding/turning a .py file into a .pyc file + across supported versions of Python. Add for else list comprehension + test +@@ -17185,7 +17185,7 @@ + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/verify.py: Python 2.6 compatability via ericfrederich's ++ uncompyle6/verify.py: Python 2.6 compatibility via ericfrederich's + patch. DRY version-checking code + + 2015-12-17 rocky +@@ -17237,12 +17237,12 @@ + test/simple-source/branching/ifelse.py, + test/simple-source/looping/for.py, uncompyle6/__init__.py, + uncompyle6/disas.py, uncompyle6/parsers/spark.py: Add spark grammar +- debugging. Start to comment grammer construct covered by simple ++ debugging. Start to comment grammar construct covered by simple + tests. + + 2015-12-17 rocky + +- * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: ++ * uncompyle6/opcodes/opcode_34.py, uncompyle6/parsers/parse3.py: + Python 3.4 correct grammar for some looping constructs + + 2015-12-17 rocky +@@ -17275,14 +17275,14 @@ + 2015-12-16 rocky + + * uncompyle6/deparser.py, uncompyle6/disas.py, +- uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: ++ uncompyle6/parser.py, uncompyle6/scanner.py, uncompyle6/walker.py: + Add LICENSE. Add demo programs and DRY code a little + + 2015-12-16 rocky + + * uncompyle6/opcodes/opcode_34.py, uncompyle6/scanner.py, + uncompyle6/scanners/scanner25.py, uncompyle6/scanners/scanner26.py, +- uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner27.py, uncompyle6/scanners/scanner34.py: + On Python3.4 decompiling Python 3.4 instructions, use its built-in + disassembler routines. In contrast to what was here, they most + likely work! +@@ -17305,7 +17305,7 @@ + test/source_3.4/branching/ifelse.py, uncompyle6/.gitignore, + uncompyle6/scanner.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Start 3.4 more stringent disassembly testing. Disassembly format has + changed slightly. misc small bugs. + +@@ -17338,7 +17338,7 @@ + uncompyle6/deparser.py, uncompyle6/disas.py, uncompyle6/magics.py, + uncompyle6/marsh.py, uncompyle6/scanners/scanner25.py, + uncompyle6/scanners/scanner26.py, uncompyle6/scanners/scanner27.py, +- uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: ++ uncompyle6/scanners/scanner32.py, uncompyle6/scanners/scanner34.py: + Split out marhsal and disassemble code and spell disassemble + correctly. Fix some lint issues + +@@ -17423,7 +17423,7 @@ + + 2015-12-14 rocky + +- * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: ++ * uncompyle6/{dparser.py => parser.py}, uncompyle6/walker.py: + uncompyle6/dparser -> uncompyle6/parser + + 2015-12-14 rocky +@@ -17529,7 +17529,7 @@ + test/ok_2.7/asynchat.pyc_dis, test/ok_2.7/asyncore.pyc_dis, + test/ok_2.7/atexit.pyc_dis, test/ok_2.7/audiodev.pyc_dis, + test/test_pythonlib.py, uncompyle6/walker.py: test_pythonlib: Fix +- bug in traversing directores walker.py: imports; Add test Python2.5 ++ bug in traversing directories walker.py: imports; Add test Python2.5 + bytecode - it works! Makefile: remove temporary directories and _dis + files which were added by mistake + +@@ -17601,7 +17601,7 @@ + * MANIFEST, MANIFEST.in, PKG-INFO, README.rst, + uncompyle6/opcodes/opcode_23.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/opcodes/opcode_27.py, uncompyle6/scanner25.py, +- uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner26.py, uncompyle6/spark.py, uncompyle6/verify.py: + Correct MANIFEST->MANIFEST.in more lint + + 2015-12-13 R. Bernstein +@@ -17618,7 +17618,7 @@ + uncompyle6/__init__.py, uncompyle6/disas.py, + uncompyle6/opcodes/opcode_25.py, uncompyle6/opcodes/opcode_26.py, + uncompyle6/scanner25.py, uncompyle6/scanner26.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/verify.py: + Make uncompyle6 run on Python3.4 and Python 2.7 We don't need our + own disassembler. Python's will do fine + +@@ -17704,7 +17704,7 @@ + + * tox.ini, uncompyle-code.py, uncompyle6/dparser.py, + uncompyle6/scanner25.py, uncompyle6/scanner27.py, +- uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: ++ uncompyle6/scanner34.py, uncompyle6/spark.py, uncompyle6/walker.py: + Minimal disassemble, ast compile and deparse work on Python 3. Some + linting + +@@ -17719,7 +17719,7 @@ + uncompyle6/scanner.py, uncompyle6/scanner25.py, + uncompyle6/scanner26.py, uncompyle6/scanner27.py, + uncompyle6/verify.py, uncompyle6/walker.py: More Python3 +- compatability. Remove duplicate disassembly code and get it from ++ compatibility. Remove duplicate disassembly code and get it from + Python's standard library instead. + + 2015-12-12 rocky +@@ -17729,7 +17729,7 @@ + + 2015-12-11 rocky + +- * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: ++ * uncompyle-code.py, uncompyle6/__init__.py, uncompyle6/walker.py: + python3 compatibiity and remove some flake8 warnings. + + 2015-12-11 rocky +@@ -17804,7 +17804,7 @@ + 2013-07-16 root + + * uncompyle2/__init__.py, uncompyle2/disas.py, +- uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: ++ uncompyle2/magics.py, uncompyle2/scanner27.py, uncompyle2/walker.py: + marshal disassembly improvement + + 2013-06-20 Mysterie +@@ -17992,4 +17992,3 @@ + 2012-06-05 Mysterie + + * first commit +- diff --git a/Makefile b/Makefile index bd5703341..b409121a1 100644 --- a/Makefile +++ b/Makefile @@ -131,5 +131,6 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff .PHONY: $(PHONY) diff --git a/NEWS.md b/NEWS.md index 6a7c23004..b3f1e67bd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +3.9.3: 2025-09-28 +================= + +- Python 3.9+ tolerance and modern Python packaging, sigh. +- Don't update global tables, copy them instead; Use a single TABLE copy (gdesmar) +- Correct print_docstring()'s `docstring.find(quote) +- short options -h and -v now do the right thing. + 3.9.2: 2024-07-21 ================= diff --git a/admin-tools/check-3.3-3.5-versions.sh b/admin-tools/check-3.3-3.5-versions.sh old mode 100644 new mode 100755 diff --git a/admin-tools/check-3.6-3.10-versions.sh b/admin-tools/check-3.6-3.10-versions.sh new file mode 100755 index 000000000..99fb08fa3 --- /dev/null +++ b/admin-tools/check-3.6-3.10-versions.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Run tests over all Python versions in branch python-3.3-3.5 +set -e +function finish { + cd $owd +} +owd=$(pwd) +trap finish EXIT + +cd $(dirname ${BASH_SOURCE[0]}) +if ! source ./pyenv-3.3-3.5-versions ; then + exit $? +fi +if ! source ./setup-python-3.3.sh ; then + exit $? +fi + +cd .. +for version in $PYVERSIONS; do + echo --- $version --- + if ! pyenv local $version ; then + exit $? + fi + make clean && python setup.py develop + if ! make check ; then + exit $? + fi + echo === $version === +done +finish diff --git a/admin-tools/checkout_common.sh b/admin-tools/checkout_common.sh index c5ffd7f4e..ed45465b2 100644 --- a/admin-tools/checkout_common.sh +++ b/admin-tools/checkout_common.sh @@ -17,5 +17,6 @@ function checkout_finish { cd $uncompyle6_owd git checkout $branch && pyenv local $PYTHON_VERSION && git pull rc=$? + pyenv local $PYTHON_VERSION return $rc } diff --git a/admin-tools/pyenv-3.6-3.10-versions b/admin-tools/pyenv-3.6-3.10-versions new file mode 100644 index 000000000..aa7eabca6 --- /dev/null +++ b/admin-tools/pyenv-3.6-3.10-versions @@ -0,0 +1,8 @@ +# -*- shell-script -*- +# Sets PYVERSIONS to be pyenv versions that +# we can use in the master branch. +if [[ $0 == ${BASH_SOURCE[0]} ]] ; then + echo "This script should be *sourced* rather than run directly through bash" + exit 1 +fi +export PYVERSIONS='3.6 pypy3.6 pypy3.7 pypy3.810 pyston-2.3.5 3.8 3.9 3.10' diff --git a/admin-tools/pyenv-newest-versions b/admin-tools/pyenv-newest-versions index b8dd8d584..aeac11e36 100644 --- a/admin-tools/pyenv-newest-versions +++ b/admin-tools/pyenv-newest-versions @@ -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.6.15 pypy3.6-7.3.1 3.7.16 pypy3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.18' +export PYVERSIONS='3.11 3.12 3.13' diff --git a/admin-tools/setup-python-3.3.sh b/admin-tools/setup-python-3.3.sh index f1d41ebf4..18fee07c2 100755 --- a/admin-tools/setup-python-3.3.sh +++ b/admin-tools/setup-python-3.3.sh @@ -7,6 +7,7 @@ if [[ $0 == $bs ]] ; then fi PYTHON_VERSION=3.3 +pyenv local $PYTHON_VERSION uncompyle6_owd=$(pwd) mydir=$(dirname $bs) diff --git a/test/Makefile b/test/Makefile index 83f713e15..4e941f83b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -80,11 +80,9 @@ check-3.8: check-bytecode $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE) -check-3.9: check-bytecode - @echo "Note that we do not support decompiling Python 3.9 bytecode - no 3.9 tests run" +check-3.9 check-3.10 check-3.11 check-3.12 check-3.13: check-bytecode + @echo "Note that we do not support decompiling this version's bytecode - no 3.9 tests run" -check-3.10: check-bytecode - @echo "Note that we do not support decompiling Python 3.10 bytecode - no 3.10 tests run" # FIXME #: this is called when running under pypy3.5-5.8.0, pypy2-5.6.0, pypy3.6-7.3.0 or pypy3.8-7.3.7 @@ -317,6 +315,10 @@ check-bytecode-3.8: $(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run $(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify +#: Check deparsing Python 3.8 +check-bytecode-3.9 check-bytecode-3.10 check-bytecode-3.11 check-bytecode-3.12 check-bytecode-3.13: + @echo "We don't support decompiling this bytecode for this version" + #: short tests for bytecodes only for this version of Python check-native-short: $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --syntax-verify $(COMPILE) diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 4cf2974e4..fbfcd30e2 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -14,4 +14,4 @@ # This file is suitable for sourcing inside POSIX shell as # well as importing into Python # fmt: off -__version__="3.9.3.dev0" # noqa +__version__="3.9.3" # noqa From 2f4581c171f6943502240359823dde8bf160c24e Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 28 Sep 2025 22:07:56 -0400 Subject: [PATCH 461/489] Merge stuff --- __pkginfo__.py | 4 +- admin-tools/make-dist-2.4-2.7.sh | 10 +- pytest/validate.py | 2 - requirements-dev.txt | 1 - uncompyle6/bin/uncompile.py | 154 +------------------------------ 5 files changed, 11 insertions(+), 160 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index aff2c2dfd..ed61a05d9 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -36,7 +36,7 @@ # Things that change more often go here. copyright = """ -Copyright (C) 2015-2021, 2024 Rocky Bernstein . +Copyright (C) 2015-2021, 2024-2025 Rocky Bernstein . """ classifiers = [ @@ -79,7 +79,7 @@ ] } ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, < 6.2.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, < 6.3.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index a0ac73b89..ca751b640 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -32,18 +32,20 @@ for pyversion in $PYVERSIONS; do rm -fr build python setup.py bdist_egg + echo === $pyversion === done -pyenv local 2.7.18 -python setup.py bdist_wheel -mv -v dist/${PACKAGE}-$__version__-py2{.py3,}-none-any.whl +pyenv local 2.7 +# python setup.py bdist_wheel +#E mv -v dist/${PACKAGE}-$__version__-py2{.py3,}-none-any.whl # Pypi can only have one source tarball. # Tarballs can get created from the above setup, so make sure to remove them since we want # the tarball from master. +python ./setup.py sdist tarball=dist/${PACKAGE}-${__version_}_-tar.gz if [[ -f $tarball ]]; then - rm -v dist/${PACKAGE}-${__version__}-tar.gz + mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi finish diff --git a/pytest/validate.py b/pytest/validate.py index 524ee191d..ed5e75448 100644 --- a/pytest/validate.py +++ b/pytest/validate.py @@ -23,8 +23,6 @@ else: from StringIO import StringIO -import six - def _dis_to_text(co): return Bytecode(co).dis() diff --git a/requirements-dev.txt b/requirements-dev.txt index df568d767..3bb6f1d94 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,2 @@ flake8 -six pytest==3.2.5 # for 2.7 < PYTHON_VERSION <= 3.2 use pytest 2.9.2; for 3.1 2.10 diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index f4812c3a3..51e6ddca4 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # Mode: -*- python -*- # -# Copyright (c) 2015-2017, 2019-2020, 2023-2024 +# Copyright (c) 2015-2017, 2019-2020, 2023-2025 # by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # @@ -99,160 +99,12 @@ def main_bin(): (3, 11), (3, 12), (3, 13), + (3, 14), ) ): - print('Error: %s requires Python 2.4-3.10' % program) + print('Error: %s requires Python 2.4-3.14' % program) sys.exit(-1) recurse_dirs = False -======= -# __doc__ = """ -# Usage: -# %s [OPTIONS]... [ FILE | DIR]... -# %s [--help | --version] - -# Examples: -# %s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout -# %s -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis -# %s -o /tmp /usr/lib/python1.5 # decompile whole library - -# Options: -# -o output decompiled files to this path: -# if multiple input files are decompiled, the common prefix -# is stripped from these names and the remainder appended to -# -# uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc -# -> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis -# uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc -# -> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis -# uncompyle6 -o /tmp /usr/lib/python1.5 -# -> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis -# --compile | -c -# attempts a decompilation after compiling -# -d print timestamps -# -p use number of processes -# -r recurse directories looking for .pyc and .pyo files -# --fragments use fragments deparser -# --verify compare generated source with input byte-code -# --verify-run compile generated source, run it and check exit code -# --syntax-verify compile generated source -# --linemaps generated line number correspondencies between byte-code -# and generated source output -# --encoding -# use in generated source according to pep-0263 -# --help show this message - -# Debugging Options: -# --asm | -a include byte-code (disables --verify) -# --grammar | -g show matching grammar -# --tree={before|after} -# -t {before|after} include syntax before (or after) tree transformation -# (disables --verify) -# --tree++ | -T add template rules to --tree=before when possible - -# Extensions of generated files: -# '.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify) -# + '_unverified' successfully decompile but --verify failed -# + '_failed' decompile failed (contact author for enhancement) -# """ % ( -# (program,) * 5 -# ) - - -@click.command() -@click.option( - "--asm++/--no-asm++", - "-A", - "asm_plus", - default=False, - help="show xdis assembler and tokenized assembler", -) -@click.option("--asm/--no-asm", "-a", default=False) -@click.option("--grammar/--no-grammar", "-g", "show_grammar", default=False) -@click.option("--tree/--no-tree", "-t", default=False) -@click.option( - "--tree++/--no-tree++", - "-T", - "tree_plus", - default=False, - help="show parse tree and Abstract Syntax Tree", -) -@click.option( - "--linemaps/--no-linemaps", - default=False, - help="show line number correspondencies between byte-code " - "and generated source output", -) -@click.option( - "--verify", - type=click.Choice(["run", "syntax"]), - default=None, -) -@click.option( - "--recurse/--no-recurse", - "-r", - "recurse_dirs", - default=False, -) -@click.option( - "--output", - "-o", - "outfile", - type=click.Path( - exists=True, file_okay=True, dir_okay=True, writable=True, resolve_path=True - ), - required=False, -) -@click.version_option(version=__version__) -@click.option( - "--start-offset", - "start_offset", - default=0, - help="start decomplation at offset; default is 0 or the starting offset.", -) -@click.option( - "--stop-offset", - "stop_offset", - default=-1, - help="stop decomplation when seeing an offset greater or equal to this; default is " - "-1 which indicates no stopping point.", -) -@click.argument("files", nargs=-1, type=click.Path(readable=True), required=True) -def main_bin( - asm: bool, - asm_plus: bool, - show_grammar, - tree: bool, - tree_plus: bool, - linemaps: bool, - verify, - recurse_dirs: bool, - outfile, - start_offset: int, - stop_offset: int, - files, -): - """ - Cross Python bytecode decompiler for Python bytecode up to Python 3.8. - """ - - version_tuple = sys.version_info[0:2] - if not ((3, 0) <= version_tuple < (3, 3)): - if version_tuple > (3, 3): - print( - "This version of the {program} is tailored for Python 3.0 to 3.2.\n" - "It may run on other versions, but there are problems, switch to code " - "from another branch.\n" - "You have version: %s." % version_tuple_to_str() - ) - else: - print( - "Error: This version of the {program} runs from Python 3.0 to 3.2.\n" - "You need another branch of this code for other Python versions." - " \n\tYou have version: %s." % version_tuple_to_str() - ) - sys.exit(-1) - ->>>>>>> python-3.0-to-3.2 numproc = 0 outfile = "-" out_base = None From 31d05beeda36b82ca2e95f036242552a9fc48e5c Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 462/489] Update bug-report.md --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - From ef54aba434cb88ac535c1931ccb386bdfa05499a Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 463/489] Update bug-report.md --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-3.0-3.2.sh | 2 +- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..be931037c 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -44,6 +44,6 @@ done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish From fa73def06b155acec5689acf4cb69afad220a8a6 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 29 Sep 2025 06:11:19 -0400 Subject: [PATCH 464/489] Get CircleCI working again? --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b7649f127..adcb0481e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -64,7 +64,7 @@ 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: sudo pip install -e . && make check-3.6 + - run: make check-3.6 - run: cd ./test/stdlib && 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 From d2466c6c23f497ed13eb9a81ec4635038be7a4d5 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 465/489] Update bug-report.md --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-2.4-2.7.sh | 2 +- admin-tools/make-dist-3.0-3.2.sh | 2 +- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index ac04cb504..725ff80f4 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -44,7 +44,7 @@ pyenv local 2.7 # the tarball from master. python ./setup.py sdist -tarball=dist/${PACKAGE}-${__version_}_-tar.gz +tarball=dist/${PACKAGE}-${__version__}-tar.gz if [[ -f $tarball ]]; then mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..be931037c 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -44,6 +44,6 @@ done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish From 93c13d30a23b99a2cdb871f009b5c6eb2bb2ca0c Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 466/489] Update bug-report.md, NEWS and dist files --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-2.4-2.7.sh | 2 +- admin-tools/make-dist-3.0-3.2.sh | 2 +- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index ac04cb504..eaf0b5cc0 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -44,7 +44,7 @@ pyenv local 2.7 # the tarball from master. python ./setup.py sdist -tarball=dist/${PACKAGE}-${__version_}_-tar.gz +tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..be931037c 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -44,6 +44,6 @@ done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish From 7de336b77718e9582cfce48cb0340a569eac0be9 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 467/489] Update bug-report.md, NEWS and dist files --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-2.4-2.7.sh | 2 +- admin-tools/make-dist-3.0-3.2.sh | 4 +-- 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index ac04cb504..eaf0b5cc0 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -44,7 +44,7 @@ pyenv local 2.7 # the tarball from master. python ./setup.py sdist -tarball=dist/${PACKAGE}-${__version_}_-tar.gz +tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..33ec1cf23 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -37,13 +37,13 @@ for pyversion in $PYVERSIONS; do first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl echo === $pyversion === done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish From c500844574a2a958866aa2a4f6cddc9e6b4f5130 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 468/489] Update bug-report.md, NEWS and dist files --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-2.4-2.7.sh | 2 +- admin-tools/make-dist-3.0-3.2.sh | 4 +-- admin-tools/make-dist-3.3-3.5.sh | 2 +- admin-tools/make-dsit-3.6-3.10.sh | 49 ++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 36 deletions(-) create mode 100755 admin-tools/make-dsit-3.6-3.10.sh diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index ac04cb504..eaf0b5cc0 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -44,7 +44,7 @@ pyenv local 2.7 # the tarball from master. python ./setup.py sdist -tarball=dist/${PACKAGE}-${__version_}_-tar.gz +tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..33ec1cf23 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -37,13 +37,13 @@ for pyversion in $PYVERSIONS; do first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl echo === $pyversion === done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish diff --git a/admin-tools/make-dist-3.3-3.5.sh b/admin-tools/make-dist-3.3-3.5.sh index 9cbc9695e..4588a43d2 100755 --- a/admin-tools/make-dist-3.3-3.5.sh +++ b/admin-tools/make-dist-3.3-3.5.sh @@ -37,7 +37,7 @@ for pyversion in $PYVERSIONS; do first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl echo === $pyversion === done diff --git a/admin-tools/make-dsit-3.6-3.10.sh b/admin-tools/make-dsit-3.6-3.10.sh new file mode 100755 index 000000000..2d5eaa855 --- /dev/null +++ b/admin-tools/make-dsit-3.6-3.10.sh @@ -0,0 +1,49 @@ +#!/bin/bash +PACKAGE=uncompyle6 + +# FIXME put some of the below in a common routine +function finish { + cd $uncompyle6_33_make_owd +} + +cd $(dirname ${BASH_SOURCE[0]}) +uncompyle6_33_make_owd=$(pwd) +trap finish EXIT + +if ! source ./pyenv-3.6-3.10-versions ; then + exit $? +fi +if ! source ./setup-python-3.6.sh ; then + exit $? +fi + +cd .. +source $PACKAGE/version.py +echo $__version__ + +for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi + if ! pyenv local $pyversion ; then + exit $? + fi + # pip bdist_egg create too-general wheels. So + # we narrow that by moving the generated wheel. + + # Pick out first two number of version, e.g. 3.5.1 -> 35 + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_egg bdist_wheel + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl + echo === $pyversion === +done + +python ./setup.py sdist +tarball=dist/${PACKAGE}-${__version__}.tar.gz +if [[ -f $tarball ]]; then + mv -v $tarball dist/${PACKAGE}_36-${__version__}.tar.gz +fi +finish From 0a143a1583e1400934a00a89a98ae4e22daf054a Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Mon, 29 Sep 2025 05:40:28 -0400 Subject: [PATCH 469/489] Update bug-report.md, NEWS and dist files --- .github/ISSUE_TEMPLATE/bug-report.md | 51 +++++++++++----------------- NEWS.md | 2 +- admin-tools/make-dist-2.4-2.7.sh | 2 +- admin-tools/make-dist-3.0-3.2.sh | 4 +-- admin-tools/make-dist-3.3-3.5.sh | 2 +- admin-tools/make-dist-3.6-3.10.sh | 49 ++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 36 deletions(-) create mode 100755 admin-tools/make-dist-3.6-3.10.sh diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 60c6cd6a7..0c91c7272 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,42 +5,32 @@ about: Tell us about uncompyle6 bugs --- @@ -115,7 +104,7 @@ Please modify for your setup - Uncompyle6 version: output from `uncompyle6 --version` or `pip show uncompyle6` - xdis version: output from `pydisasm --version` or or `pip show xdis` - Python version for the version of Python the byte-compiled the file: `python -c "import sys; print(sys.version)"` where `python` is the correct CPython or PyPy binary. -- OS and Version: [e.g. Ubuntu bionic] +- OS and Version: [e.g., Ubuntu bionic] --> @@ -125,8 +114,8 @@ Please modify for your setup ## Priority - diff --git a/NEWS.md b/NEWS.md index b3f1e67bd..f332498d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -3.9.3: 2025-09-28 +3.9.3: 2025-09-29 ================= - Python 3.9+ tolerance and modern Python packaging, sigh. diff --git a/admin-tools/make-dist-2.4-2.7.sh b/admin-tools/make-dist-2.4-2.7.sh index ac04cb504..eaf0b5cc0 100755 --- a/admin-tools/make-dist-2.4-2.7.sh +++ b/admin-tools/make-dist-2.4-2.7.sh @@ -44,7 +44,7 @@ pyenv local 2.7 # the tarball from master. python ./setup.py sdist -tarball=dist/${PACKAGE}-${__version_}_-tar.gz +tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then mv -v $tarball dist/${PACKAGE}_24-${__version__}.tar.gz fi diff --git a/admin-tools/make-dist-3.0-3.2.sh b/admin-tools/make-dist-3.0-3.2.sh index e5149c41e..33ec1cf23 100644 --- a/admin-tools/make-dist-3.0-3.2.sh +++ b/admin-tools/make-dist-3.0-3.2.sh @@ -37,13 +37,13 @@ for pyversion in $PYVERSIONS; do first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl echo === $pyversion === done python ./setup.py sdist tarball=dist/${PACKAGE}-${__version__}.tar.gz if [[ -f $tarball ]]; then - mv -v $tarball dist/${PACKAGE}_31-${__version__}.tar.gz + mv -v $tarball dist/${PACKAGE}_30-${__version__}.tar.gz fi finish diff --git a/admin-tools/make-dist-3.3-3.5.sh b/admin-tools/make-dist-3.3-3.5.sh index 9cbc9695e..4588a43d2 100755 --- a/admin-tools/make-dist-3.3-3.5.sh +++ b/admin-tools/make-dist-3.3-3.5.sh @@ -37,7 +37,7 @@ for pyversion in $PYVERSIONS; do first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') rm -fr build python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl echo === $pyversion === done diff --git a/admin-tools/make-dist-3.6-3.10.sh b/admin-tools/make-dist-3.6-3.10.sh new file mode 100755 index 000000000..2d5eaa855 --- /dev/null +++ b/admin-tools/make-dist-3.6-3.10.sh @@ -0,0 +1,49 @@ +#!/bin/bash +PACKAGE=uncompyle6 + +# FIXME put some of the below in a common routine +function finish { + cd $uncompyle6_33_make_owd +} + +cd $(dirname ${BASH_SOURCE[0]}) +uncompyle6_33_make_owd=$(pwd) +trap finish EXIT + +if ! source ./pyenv-3.6-3.10-versions ; then + exit $? +fi +if ! source ./setup-python-3.6.sh ; then + exit $? +fi + +cd .. +source $PACKAGE/version.py +echo $__version__ + +for pyversion in $PYVERSIONS; do + echo --- $pyversion --- + if [[ ${pyversion:0:4} == "pypy" ]] ; then + echo "$pyversion - PyPy does not get special packaging" + continue + fi + if ! pyenv local $pyversion ; then + exit $? + fi + # pip bdist_egg create too-general wheels. So + # we narrow that by moving the generated wheel. + + # Pick out first two number of version, e.g. 3.5.1 -> 35 + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_egg bdist_wheel + mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl + echo === $pyversion === +done + +python ./setup.py sdist +tarball=dist/${PACKAGE}-${__version__}.tar.gz +if [[ -f $tarball ]]; then + mv -v $tarball dist/${PACKAGE}_36-${__version__}.tar.gz +fi +finish From 1198edfd4bd2526948f50a78169e009819f4bd45 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 1 Oct 2025 05:58:39 -0400 Subject: [PATCH 470/489] Packaging administrivia --- pyproject.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eb6e70385..830283390 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: PyPy", ] dynamic = ["version"] @@ -68,8 +69,3 @@ version = {attr = "uncompyle6.version.__version__"} [tool.setuptools.packages.find] include = ["uncompyle6*"] # Include all subpackages - -[tool.pyright] -include = ["trepan"] -# exclude = [] -ignore = ["dist", "docs", "tmp", ".cache"] From b428516e7128a2dba9ea9e680fba953c6ec244b9 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Oct 2025 10:48:58 -0400 Subject: [PATCH 471/489] Revise README.rst to mention Git branches for install. --- README.rst | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 7f2ce6d00..447f3e5d1 100644 --- a/README.rst +++ b/README.rst @@ -86,12 +86,20 @@ The way it does this, though, is by segregating consecutive Python versions into git branches: master +<<<<<<< Updated upstream Python 3.11 and up python-3.6-to-3.10 Python 3.6 to python-3.10 (uses type annotations) +======= + Python 3.11 and up (uses poetry install, and newer Python idioms) +python-3.6-to-3.10 + Python 3.6 through 3.10 (uses newer f-strings, and more modern, and more modern Type annotations) +>>>>>>> Stashed changes +python-3.3-to-3.5 + Python 3.3 through 3.5 (Generic Python 3) python-3.3-to-3.5 Python 3.3 through 3.5 (Generic Python 3) -python-2.4 +python-2.4-to-2.7 Python 2.4 through 2.7 (Generic Python 2) PyPy 3-2.4 and later works as well. @@ -103,18 +111,42 @@ versions. Installation ------------ -You can install from PyPI using the name ``uncompyle6``:: +*For recent Python releases (Python 3.11+)*, you can install from PyPI using the name ``uncompyle6``:: pip install uncompyle6 +*For Python releases before 3.11*, do not install using PyPI, but instead install using a file in the [GitHub Releases section](https://github.com/rocky/python-uncompyle6/releases). Older Python used to use `easy_install `_. But this is no longer supported in PyPi. -To install from source code, this project uses setup.py, so it follows the standard Python routine:: +If the Python version you are running uncompyle6 is between Python 2.4 through 2.7, use a tarball called uncompyle6_24-*x.y.z*.tar.gz. - $ pip install -e . # set up to run from source tree +If the Python version you are running uncompyle6 is between Python 3.0 through 3.2, use a tarball called uncompyle6_30-*x.y.z*.tar.gz. + +If the Python version you are running uncompyle6 is between Python 3.3 through 3.5, use a tarball called uncompyle6_33-*x.y.z*.tar.gz. + +If the Python version you are running uncompyle6 is between Python 3.6 through 3.11, use a tarball called uncompyle6_36-*x.y.z*.tar.gz. + +If the Python version you are running uncompyle6 is 3.11 or later, use a called uncompyle6-*x.y.z*.tar.gz. + +You can also try eggs or wheel that have the same version designation, e.g., uncompyle6-*x.y.z*-py39-non-any.whl for a Python 3.9 installation. *However, note that *the version without the designation, means Python 3.11 or greater*. -or:: +Similarly a tarball with without `_`*xx* works only from Python 3.11 or greaters + + +Rationale for using Git Branches +++++++++++++++++++++++++++++++++ + +It is currently impossible (if not impractical) to have one Python source code of this complexity and with this many features that can run both Python 2.7 and Python 3.13+. The languages have drifted so much, and Packing is vastly different. In fact, the packaging practice for Python 3.11+ is incompatible with Python 2.7 (and before back to Python 2.4), which favored "easy_install". + +Installation from source text +++++++++++++++++++++++++++++++ + +To install from source code make sure you have the right github +branch. See the Requirements section for the Git branch names. + +After setting the right branch: + + $ pip install -e . # set up to run from source tree - $ python setup.py install # may need sudo A GNU Makefile is also provided, so :code:`make install` (possibly as root or sudo) will do the steps above. @@ -274,7 +306,11 @@ Be aware that it might not get my attention for a while. If you sponsor or support the project in some way, I'll prioritize your issues above the queue of other things I might be doing instead. In rare situations, I can do a hand decompilation of bytecode for a fee. +<<<<<<< Updated upstream However, this is expensive, usually beyond what most people are willing +======= +However this is expansive, usually beyond what most people are willing +>>>>>>> Stashed changes to spend. See Also From 0985f1ef6ea7792ad68c30d4dea660d65dce3441 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Oct 2025 21:13:02 -0400 Subject: [PATCH 472/489] Merge woes --- __pkginfo__.py | 3 ++ setup-pretoml.py | 71 ------------------------------------------------ 2 files changed, 3 insertions(+), 71 deletions(-) delete mode 100644 setup-pretoml.py diff --git a/__pkginfo__.py b/__pkginfo__.py index d11c0f54f..84cb7fb04 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -106,4 +106,7 @@ def read(*rnames): # Get info from files; set: long_description and VERSION long_description = read("README.rst") + "\n" + +# The "exec" below rewrites __version__. +__version__="??" exec(read("uncompyle6/version.py")) diff --git a/setup-pretoml.py b/setup-pretoml.py deleted file mode 100644 index 57f786c54..000000000 --- a/setup-pretoml.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -import sys - -import setuptools - -"""Setup script for the 'uncompyle6' distribution.""" - -SYS_VERSION = sys.version_info[0:2] -if SYS_VERSION < (3, 6): - mess = "Python Release 3.6 .. 3.12 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." - % sys.version[0:3] - ) - if SYS_VERSION >= (3, 6): - mess += ( - "\nFor your Python, version %s, use the master code/branch." - % sys.version[0:3] - ) - if (3, 0) >= SYS_VERSION < (3, 3): - mess += ( - "\nFor your Python, version %s, use the python-3.0-to-3.2 code/branch." - % sys.version[0:3] - ) - if (3, 3) >= SYS_VERSION < (3, 6): - mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch." - % sys.version[0:3] - ) - elif SYS_VERSION < (2, 4): - mess += ( - "\nThis package is not supported for Python version %s." % sys.version[0:3] - ) - print(mess) - raise Exception(mess) - -from __pkginfo__ import ( - __version__, - author, - author_email, - classifiers, - entry_points, - install_requires, - license, - long_description, - modname, - py_modules, - short_desc, - web, - zip_safe, -) - -setuptools.setup( - author=author, - author_email=author_email, - classifiers=classifiers, - description=short_desc, - entry_points=entry_points, - install_requires=install_requires, - license=license, - long_description=long_description, - long_description_content_type="text/x-rst", - name=modname, - packages=setuptools.find_packages(), - py_modules=py_modules, - test_suite="nose.collector", - url=web, - version=__version__, - zip_safe=zip_safe, -) From 6e91fb578a9237775a01b7567a5ec3a75ec9bb11 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 6 Oct 2025 21:16:40 -0400 Subject: [PATCH 473/489] Merge woes --- __pkginfo__.py | 7 ++++--- setup.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 84cb7fb04..7c5dc7313 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018, 2020-2021 2024 Rocky Bernstein +# Copyright (C) 2018, 2020-2021 2024-2025 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ # Things that change more often go here. copyright = """ -Copyright (C) 2015-2021, 2024 Rocky Bernstein . +Copyright (C) 2015-2021, 2024-2025 Rocky Bernstein . """ classifiers = [ @@ -64,6 +64,7 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Debuggers", "Topic :: Software Development :: Libraries :: Python Modules", @@ -84,7 +85,7 @@ license = "GPL3" mailing_list = "python-debugger@googlegroups.com" modname = "uncompyle6" -py_modules = None +py_modules = [] short_desc = "Python cross-version byte-code decompiler" web = "https://github.com/rocky/python-uncompyle6/" diff --git a/setup.py b/setup.py index e2e4c80a0..bf467810a 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,6 @@ sys.stderr.write("Please install using uncompyle6_36-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") sys.stderr.write("Or to install from source, use the python-3.3-to-3.5 code/branch.\n") sys.exit(1) ->>>>>>> python-3.6-to-3.10 elif SYS_VERSION < (2, 4): sys.stderr.write("This package is not supported for Python\n") sys.exit(1) From 44ad6812518c79e0cbb72953900de0af0f5b1b33 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Oct 2025 06:49:53 -0400 Subject: [PATCH 474/489] Testing on python-3.6-to-3.10 branch --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7e7834cf1..f52835aa9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2 filters: branches: - only: master + only: python-3.6-to-3.10 jobs: build: working_directory: ~/rocky/python-uncompyle6 @@ -16,7 +16,7 @@ jobs: # To see the list of pre-built images that CircleCI provides for most common languages see # https://circleci.com/docs/2.0/circleci-images/ docker: - - image: cimg/python:3.13 + - image: cimg/python:3.10 steps: # Machine Setup # 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 From 0b63c422000d61f18263cec6c543df5a2af116dc Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Oct 2025 06:59:01 -0400 Subject: [PATCH 475/489] More Workflows testing in 3.6-3.10 branch --- .github/workflows/osx.yml | 6 +++--- .github/workflows/ubuntu.yml | 6 +++--- .github/workflows/windows.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index bcfad6b0a..3d4efccce 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -2,9 +2,9 @@ name: uncompyle6 (osx) on: push: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] pull_request: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: [3.13] + python-version: ['3.8', '3.10'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 1aea17df1..80ad6ef41 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -2,16 +2,16 @@ name: uncompyle6 (ubuntu) on: push: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] pull_request: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.13] + python-version: ['3.8', '3.9'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 693c8db69..0fbdd9625 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,9 +2,9 @@ name: uncompyle6 (windows) on: push: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] pull_request: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] jobs: build: @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [windows] - python-version: [3.13] + python-version: ['3.8'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} From 4fec4dc3f44c637d8ff4c80cc3622713af9a11ee Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Oct 2025 07:12:54 -0400 Subject: [PATCH 476/489] Merge woes --- setup.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/setup.py b/setup.py index dbcf791b3..3293beacc 100755 --- a/setup.py +++ b/setup.py @@ -9,23 +9,24 @@ major = sys.version_info[0] minor = sys.version_info[1] SYS_VERSION = sys.version_info[0:2] -if not ((3, 0) <= SYS_VERSION < (3, 3)): - mess = "Python Release 3.0 .. 3.2 are supported in this code branch." +if not ((3, 0) <= SYS_VERSION < (3, 2)): + sys.stderr.write("Python Release 3.0 .. 3.2 are supported in this code branch. You are running Python %s.%s.\n" % (major, minor)) if (2, 4) <= SYS_VERSION <= (2, 7): - mess += ( - "\nFor your Python, version %s, use the python-2.4 code/branch." - % sys.version[0:3] - ) - if SYS_VERSION >= (3, 6): - mess += ( - "\nFor your Python, version %s, use the master code/branch." - % sys.version[0:3] - ) - if (3, 3) >= SYS_VERSION < (3, 6): - mess += ( - "\nFor your Python, version %s, use the python-3.3-to-3.6 code/branch." - % sys.version[0:3] - ) + sys.stderr.write("Please install using uncompyle6_24-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") + sys.stderr.write("Or to install from source, use the python-2.4-to-2.7 code/branch.\n") + sys.exit(1) + elif SYS_VERSION >= (3, 10): + sys.stderr.write("Please install using uncompyle6-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") + sys.stderr.write("Or to install from source, use the master code/branch.\n") + sys.exit(1) + elif (3, 3) >= SYS_VERSION < (3, 6): + sys.stderr.write("Please install using uncompyle6_33-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") + sys.stderr.write("Or to install from source, use the python-3.3-to-3.6 code/branch.\n") + sys.exit(1) + elif (3, 6) >= SYS_VERSION < (3, 10): + sys.stderr.write("Please install using uncompyle6_36-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") + sys.stderr.write("Or to install from source, use the python-3.3-to-3.5 code/branch.\n") + sys.exit(1) elif SYS_VERSION < (2, 4): sys.stderr.write("This package is not supported for Python\n") sys.exit(1) From 62bd820254f6d4cbef4a31def5906b712be2149b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Oct 2025 08:00:56 -0400 Subject: [PATCH 477/489] Merge stuff --- README.rst | 6 +----- setup.py | 8 +++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index c090ce530..231f0c750 100644 --- a/README.rst +++ b/README.rst @@ -142,13 +142,9 @@ branch. See the Requirements section for the Git branch names. After setting the right branch:: - $ pip install -e . # set up to run from source tree - - $ python setup.py install # may need sudo A GNU Makefile is also provided, so :code:``make install`` (possibly as root or sudo) will do the steps above. ->>>>>>> python-3.0-to-3.2 Running Tests ------------- @@ -161,7 +157,7 @@ A GNU makefile has been added to smooth over setting up and running the right command, and running tests from fastest to slowest. If you have remake_ installed, you can see the list of all tasks -including tests via :code:`remake --tasks` +including tests via :code:``remake --tasks`` Usage diff --git a/setup.py b/setup.py index 714762648..4baa2f4ef 100755 --- a/setup.py +++ b/setup.py @@ -5,16 +5,15 @@ import sys import setuptools -import sys major = sys.version_info[0] minor = sys.version_info[1] SYS_VERSION = sys.version_info[0:2] if not ((2, 4) <= SYS_VERSION < (3, 0)): sys.stderr.write("Python Release 2.4 .. 2.7 are supported in this code branch. You are running Python %s.%s.\n" % (major, minor)) - if (2, 4) <= SYS_VERSION <= (2, 7): - sys.stderr.write("Please install using uncompyle6_24-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") - sys.stderr.write("Or to install from source, use the python-2.4-to-2.7 code/branch.\n") + if (3, 0) <= SYS_VERSION <= (3, 3): + sys.stderr.write("Please install using uncompyle6_30-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") + sys.stderr.write("Or to install from source, use the python-3.0-to-3.2 code/branch.\n") sys.exit(1) elif SYS_VERSION >= (3, 10): sys.stderr.write("Please install using uncompyle6-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") @@ -32,7 +31,6 @@ sys.stderr.write("This package is not supported for Python\n") sys.exit(1) raise Exception("Wrong Python version") ->>>>>>> python-3.0-to-3.2 from __pkginfo__ import ( __version__, From 76a6454e1810b1affdc6c1bfc6b391b7ecef17ed Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Nov 2025 11:59:58 -0500 Subject: [PATCH 478/489] Merge stuff --- __pkginfo__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 84cb7fb04..28f7c474a 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018, 2020-2021 2024 Rocky Bernstein +# Copyright (C) 2018, 2020-2021 2024-2025 Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ # Things that change more often go here. copyright = """ -Copyright (C) 2015-2021, 2024 Rocky Bernstein . +Copyright (C) 2015-2021, 2024-2025 Rocky Bernstein . """ classifiers = [ @@ -79,7 +79,7 @@ ] } ftp_url = None -install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, < 6.2.0"] +install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.2", "xdis > 6.2.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" From 2fc4723a77d784b6e4dcca2e34d9f19a10a52e77 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 14 Nov 2025 22:00:39 -0500 Subject: [PATCH 479/489] Administrivia --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3293beacc..de55b2d02 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ major = sys.version_info[0] minor = sys.version_info[1] SYS_VERSION = sys.version_info[0:2] -if not ((3, 0) <= SYS_VERSION < (3, 2)): +if not ((3, 0) <= SYS_VERSION < (3, 3)): sys.stderr.write("Python Release 3.0 .. 3.2 are supported in this code branch. You are running Python %s.%s.\n" % (major, minor)) if (2, 4) <= SYS_VERSION <= (2, 7): sys.stderr.write("Please install using uncompyle6_24-x.y.z.tar.gz from https://github.com/rocky/python-uncompyle6/releases\n") From ddef45d4a5ca249031371aa58b6d857ad5e64e79 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 15 Nov 2025 06:23:04 -0500 Subject: [PATCH 480/489] Merge stuff --- __pkginfo__.py | 3 --- uncompyle6/code_fns.py | 7 +------ uncompyle6/scanners/scanner26.py | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 757d7d21a..44066ef60 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -81,9 +81,6 @@ } ftp_url = None install_requires = ["spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, > 6.2.0"] -======= -install_requires = ["click", "spark-parser >= 1.8.9, < 1.9.2", "xdis > 6.2.0"] ->>>>>>> python-3.0-to-3.2 license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/uncompyle6/code_fns.py b/uncompyle6/code_fns.py index f43d670b9..e0b92d175 100644 --- a/uncompyle6/code_fns.py +++ b/uncompyle6/code_fns.py @@ -72,13 +72,8 @@ def disco_loop(disasm, queue, real_out): real_out.write( "\n# %s of %s\n" % (co.co_name, co.co_filename) -======= - print( - "\n# %s of %s" % (co.co_name, co.co_filename), - file=real_out, ->>>>>>> python-3.0-to-3.2 ) - tokens, customize = disasm(co) + tokens, _ = disasm(co) for t in tokens: if iscode(t.pattr): queue.append(t.pattr) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 3f64acf67..abfa9bdd3 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -80,7 +80,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None): if show_asm in ("both", "before"): print("\n# ---- disassembly:") bytecode.disassemble_bytes( - co.co_code, + co, varnames=co.co_varnames, names=co.co_names, constants=co.co_consts, From ec3cf10328d5f5c896c051db342786085cec1554 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 15 Nov 2025 06:51:52 -0500 Subject: [PATCH 481/489] Address pre-commit problems? --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cbf372a9..b51fd5936 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,17 +6,17 @@ repos: hooks: - id: check-merge-conflict - id: debug-statements - stages: [pre-commit] + stages: [commit] - id: end-of-file-fixer - stages: [pre-commit] + stages: [commit] - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort - stages: [pre-commit] + stages: [commit] - repo: https://github.com/psf/black rev: 23.12.1 hooks: - id: black language_version: python3 - stages: [pre-commit] + stages: [commit] From 8f38452319a1f799b1c55e56df5553561ff43145 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 15 Nov 2025 06:52:48 -0500 Subject: [PATCH 482/489] CI: correct right used for xdis install --- .circleci/config.yml | 2 +- .github/workflows/osx.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- .pre-commit-config.yaml | 12 ++++++------ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3941ee981..2b5239641 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,7 +43,7 @@ jobs: - run: command: | # Use pip to install dependengcies # pip install --user --upgrade setuptools - pip install --user -e git+https://github.com/rocky/python-xdis.git#egg=xdis + pip install --user -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis pip install --user -e . # Not sure why "pip install -e" doesn't work above # pip install click spark-parser xdis diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 3e181d75d..a4ef68496 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git#egg=xdis + pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # Not sure why "pip install -e" doesn't work above # pip install click spark-parser xdis diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index fc710c875..367e2fa6b 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,7 +21,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git#egg=xdis + pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # pip install click spark-parser xdis pip install -r requirements-dev.txt diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a3dfdefd3..6fdd62199 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git#egg=xdis + pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # Not sure why "pip install -e" doesn't work above # pip install click spark-parser xdis diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b51fd5936..b5dba40fa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,9 +14,9 @@ repos: hooks: - id: isort stages: [commit] -- repo: https://github.com/psf/black - rev: 23.12.1 - hooks: - - id: black - language_version: python3 - stages: [commit] +# - repo: https://github.com/psf/black +# rev: 23.12.1 +# hooks: +# - id: black +# language_version: python3 +# stages: [commit] From 17ec5ee0c572594a5b4112081203dc39737f7ac9 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 15 Nov 2025 07:01:15 -0500 Subject: [PATCH 483/489] CI yet again --- .github/workflows/osx.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index a4ef68496..335968964 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" + pip install --local -e "git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # Not sure why "pip install -e" doesn't work above # pip install click spark-parser xdis diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 367e2fa6b..d68eecd45 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,7 +21,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" + pip install --local -e "git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # pip install click spark-parser xdis pip install -r requirements-dev.txt diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 6fdd62199..97127c6f9 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | # Until the next xdis release - pip install --local -e git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" + pip install --local -e "git+https://github.com/rocky/python-xdis.git@python-3.6-to-3.10#egg=xdis" pip install -e . # Not sure why "pip install -e" doesn't work above # pip install click spark-parser xdis From cac5c2c43e3a00d6c28c8b1df4545cc79b202db8 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 17 Nov 2025 09:11:09 -0500 Subject: [PATCH 484/489] Merge stuff --- __pkginfo__.py | 2 +- uncompyle6/main.py | 2 +- uncompyle6/scanners/scanner3.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 44066ef60..07b80d2e3 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -80,7 +80,7 @@ ] } ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.1.1, > 6.2.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.2", "xdis >= 6.2"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 68b5ae023..6a416bd04 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -515,7 +515,7 @@ def main( if not current_outfile: mess = "\n# okay decompiling" # mem_usage = __memUsage() - print(mess, infile) + print mess, infile if current_outfile: sys.stdout.write( "%s -- %s\r" diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index d21ec2b08..72bc70d6a 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -38,13 +38,12 @@ # Get all the opcodes into globals import xdis.opcodes.opcode_33 as op3 -from xdis import Instruction, instruction_size, iscode +from xdis import instruction_size, iscode from xdis.bytecode import _get_const_info from xdis.opcodes.opcode_3x import parse_fn_counts_30_35 from uncompyle6.scanner import CONST_COLLECTIONS, Scanner from uncompyle6.scanners.tok import Token -from uncompyle6.util import get_code_name globals().update(op3.opmap) From 14f6b7b2512806c931599e26c09841248dfbe6d4 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 23 Nov 2025 08:15:51 -0500 Subject: [PATCH 485/489] Use newer xdis API --- .gitignore | 1 + uncompyle6/verify.py | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 6a2a97741..6127cff4f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /.eggs /.hypothesis /.idea +/.jython_cache /.mypy_cache /.pytest_cache /.python-version diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 33a525e9d..c991fbe92 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -1,5 +1,5 @@ # -# (C) Copyright 2015-2018, 2020-2021, 2023 by Rocky Bernstein +# (C) Copyright 2015-2018, 2020-2021, 2023, 2025 by Rocky Bernstein # (C) Copyright 2000-2002 by hartmut Goebel # # This program is free software: you can redistribute it and/or modify @@ -18,18 +18,19 @@ byte-code verification """ -from __future__ import print_function +import operator +import sys +from functools import reduce +from subprocess import call -import operator, sys import xdis.std as dis -from subprocess import call +from xdis import PYTHON_MAGIC_INT, iscode, load_file, load_module, pretty_code_flags +from xdis.version_info import PythonImplementation import uncompyle6 from uncompyle6.scanner import Token as ScannerToken, get_scanner -from xdis import iscode, load_file, load_module, pretty_code_flags, PYTHON_MAGIC_INT truediv = operator.truediv -from functools import reduce def code_equal(a, b): @@ -485,9 +486,10 @@ def compare_code_with_srcfile(pyc_filename, src_filename, verify): timestamp, magic_int, code_obj1, - is_pypy, + python_implementation, source_size, sip_hash, + _, ) = load_module(pyc_filename) if magic_int != PYTHON_MAGIC_INT: msg = ( @@ -500,6 +502,7 @@ def compare_code_with_srcfile(pyc_filename, src_filename, verify): except SyntaxError as e: # src_filename can be the first of a group sometimes return str(e).replace(src_filename, pyc_filename) + is_pypy = python_impementation is PythonImplementation.PyPy cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify) if verify == "verify-run": try: @@ -520,19 +523,22 @@ def compare_files(pyc_filename1, pyc_filename2, verify): timestamp, magic_int1, code_obj1, - is_pypy, + python_implementation, source_size, sip_hash, - ) = uncompyle6.load_module(pyc_filename1) + _ + ) = load_module(pyc_filename1) + is_pypy = python_implementation is PythonImplementation.PyPy ( version2, timestamp, magic_int2, code_obj2, - is_pypy, + python_implementation, source_size, sip_hash, - ) = uncompyle6.load_module(pyc_filename2) + _ + ) = load_module(pyc_filename2) if (magic_int1 != magic_int2) and verify == "verify": verify = "weak_verify" cmp_code_objects(version1, is_pypy, code_obj1, code_obj2, verify) From 9d0d8fb1a33fc7a55c510d6c579599113e9ac6b1 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 25 Nov 2025 03:45:38 -0500 Subject: [PATCH 486/489] Merge stuff --- uncompyle6/verify.py | 1 - 1 file changed, 1 deletion(-) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index d87759b30..efcdfffac 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -27,7 +27,6 @@ from xdis import PYTHON_MAGIC_INT, iscode, load_file, load_module, pretty_code_flags from xdis.version_info import PythonImplementation -import uncompyle6 from uncompyle6.scanner import Token as ScannerToken, get_scanner truediv = operator.div From 5094332c0e94cd6f0291ec35eeaa041ebb3bc900 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 10 Jan 2026 18:13:06 -0500 Subject: [PATCH 487/489] Merge stuff --- uncompyle6/scanner.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index aa34a2b1a..cdbaaf902 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -115,17 +115,14 @@ def __init__(self, version_tuple: tuple, show_asm=None, is_pypy=False): self.show_asm = show_asm self.is_pypy = is_pypy - # Temporary initialization. - self.opc = ModuleType("uninitialized") - if version_tuple[:2] in PYTHON_VERSIONS: - v_str = f"""opcode_{version_tuple_to_str(version_tuple, start=0, end=2, delimiter="")}""" + v_str = "opcode_%s" % version_tuple_to_str(version_tuple, start=0, end=2, delimiter="") python_implementation = ( PythonImplementation.PyPy if is_pypy else PythonImplementation.CPython ) self.opc = get_opcode_module(version_tuple, python_implementation) else: - raise TypeError("%s is not a Python version I know about" % v_str(version)) + raise TypeError("%s is not a Python version I know about" % v_str(version_tuple)) self.opname = self.opc.opname From 43ed72f1bd51f6757f6fb7715691df18e68be6f3 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 10 Jan 2026 18:18:54 -0500 Subject: [PATCH 488/489] Merge stuff --- uncompyle6/scanner.py | 3 +-- uncompyle6/scanners/scanner2.py | 2 +- uncompyle6/scanners/scanner3.py | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 635ccc417..d626cb85e 100644 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -21,7 +21,6 @@ scanners, e.g. for Python 2.7 or 3.4. """ -import sys from array import array from xdis import ( @@ -33,7 +32,7 @@ next_offset, ) from xdis.op_imports import get_opcode_module -from xdis.version_info import IS_PYPY, PythonImplementation, version_tuple_to_str +from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, PythonImplementation, version_tuple_to_str from uncompyle6.scanners.tok import Token diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 183fe0dd8..375bebc5f 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2025 by Rocky Bernstein +# Copyright (c) 2015-2026 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index c105a7b1c..8852b9383 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -36,12 +36,11 @@ from copy import deepcopy import xdis # Get all the opcodes into globals -import xdis.opcodes.opcode_33 as op3 -from xdis import Instruction, instruction_size, iscode +from xdis.opcodes import opcode_33 as op3 +from xdis import instruction_size, iscode from xdis.bytecode import _get_const_info # Get all the opcodes into globals -from xdis.opcodes import opcode_33 as op3 from xdis.opcodes.opcode_3x.opcode_3x import parse_fn_counts_30_35 from uncompyle6.scanner import CONST_COLLECTIONS, Scanner From c303c8a5023aa6f98f36e28b9d3c7f0dc813e8c9 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 24 Apr 2026 10:10:50 -0400 Subject: [PATCH 489/489] CI woes --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index bf3780e27..7bbf20e39 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,3 @@ flake8 six -pytest==9.0.3 # for 2.7 < PYTHON_VERSION <= 3.2 use pytest 2.9.2; for 3.1 2.10 +pytest # for 2.7 < PYTHON_VERSION <= 3.2 use pytest 2.9.2; for 3.1 2.10