From e8e006bb8c03ebbee1ff1008e4d00a81765a094a Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 16 Oct 2021 11:33:03 -0400 Subject: [PATCH] More Python version comparison conversions --- admin-tools/check-newer-versions.sh | 29 ------- admin-tools/pyenv-newer-versions | 8 -- pytest/test_fjt.py | 10 +-- pytest/test_grammar.py | 34 ++++----- pytest/validate.py | 7 +- uncompyle6/disas.py | 4 +- uncompyle6/parser.py | 2 +- uncompyle6/scanner.py | 6 +- uncompyle6/scanners/scanner2.py | 60 +++++++-------- uncompyle6/scanners/scanner22.py | 2 +- uncompyle6/scanners/scanner23.py | 4 +- uncompyle6/scanners/scanner24.py | 7 +- uncompyle6/scanners/scanner26.py | 4 +- uncompyle6/scanners/scanner27.py | 110 ++++++++++++++++++--------- uncompyle6/scanners/scanner37.py | 4 +- uncompyle6/scanners/scanner37base.py | 8 +- uncompyle6/scanners/scanner38.py | 26 ++++--- uncompyle6/semantics/customize.py | 2 +- uncompyle6/semantics/customize3.py | 2 +- 19 files changed, 167 insertions(+), 162 deletions(-) delete mode 100755 admin-tools/check-newer-versions.sh delete mode 100644 admin-tools/pyenv-newer-versions diff --git a/admin-tools/check-newer-versions.sh b/admin-tools/check-newer-versions.sh deleted file mode 100755 index ed87f8bd..00000000 --- a/admin-tools/check-newer-versions.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/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 $? -fi -if ! source ./setup-master.sh ; then - exit $? -fi -cd .. -for version in $PYVERSIONS; do - echo --- $version --- - if ! pyenv local $version ; then - exit $? - fi - make clean && pip install -e . - if ! make check-short; then - exit $? - fi - echo === $version === -done -make check diff --git a/admin-tools/pyenv-newer-versions b/admin-tools/pyenv-newer-versions deleted file mode 100644 index d1dba953..00000000 --- a/admin-tools/pyenv-newer-versions +++ /dev/null @@ -1,8 +0,0 @@ -# -*- 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.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/pytest/test_fjt.py b/pytest/test_fjt.py index 9987a9cf..2529b190 100644 --- a/pytest/test_fjt.py +++ b/pytest/test_fjt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -from uncompyle6 import PYTHON_VERSION, IS_PYPY +from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY from uncompyle6.scanner import get_scanner def bug(state, slotstate): if state: @@ -21,8 +21,8 @@ def bug_loop(disassemble, tb=None): def test_if_in_for(): code = bug.__code__ - scan = get_scanner(PYTHON_VERSION) - if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY: + scan = get_scanner(PYTHON_VERSION_TRIPLE) + if (2, 7) <= PYTHON_VERSION_TRIPLE < (3, 1) and not IS_PYPY: scan.build_instructions(code) fjt = scan.find_jump_targets(False) @@ -51,7 +51,7 @@ def test_if_in_for(): # previous bug was not mistaking while-loop for if-then {'start': 48, 'end': 67, 'type': 'while-loop'}] - elif 3.2 < PYTHON_VERSION <= 3.4: + elif (3, 2) < PYTHON_VERSION_TRIPLE <= (3, 4): scan.build_instructions(code) fjt = scan.find_jump_targets(False) assert {69: [66], 63: [18]} == fjt @@ -62,6 +62,6 @@ def test_if_in_for(): {'end': 59, 'type': 'for-loop', 'start': 31}, {'end': 63, 'type': 'for-else', 'start': 62}] else: - print("FIXME: should fix for %s" % PYTHON_VERSION) + print("FIXME: should fix for %s" % ".".join([str(v) for v in PYTHON_VERSION_TRIPLE])) assert True return diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index eeb04e8f..8b3f6b88 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -1,7 +1,7 @@ import re -from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY # , PYTHON_VERSION from uncompyle6.parser import get_python_parser, python_parser from uncompyle6.scanner import get_scanner +from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY def test_grammar(): @@ -16,19 +16,19 @@ def test_grammar(): p.dump_grammar(), ) - p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY) + p = get_python_parser(PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY) (lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets() # We have custom rules that create the below expect_lhs = set(["pos_arg"]) - if PYTHON_VERSION < 3.8: - if PYTHON_VERSION < 3.7: + if PYTHON_VERSION_TRIPLE < (3, 8): + if PYTHON_VERSION_TRIPLE < (3, 7): expect_lhs.add("attribute") expect_lhs.add("get_iter") - if PYTHON_VERSION > 3.7 or PYTHON_VERSION < 3.0: + if PYTHON_VERSION_TRIPLE >= (3, 8) or PYTHON_VERSION_TRIPLE < (3, 0): expect_lhs.add("stmts_opt") else: expect_lhs.add("async_with_as_stmt") @@ -38,15 +38,15 @@ def test_grammar(): expect_right_recursive = set([("designList", ("store", "DUP_TOP", "designList"))]) - if PYTHON_VERSION <= 3.6: + if PYTHON_VERSION_TRIPLE <= (3, 6): unused_rhs.add("call") - if PYTHON_VERSION > 2.6: + if PYTHON_VERSION_TRIPLE >= (3, 0): expect_lhs.add("kvlist") expect_lhs.add("kv3") unused_rhs.add("dict") - if PYTHON_VERSION < 3.7 and PYTHON_VERSION != 2.7: + if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] != (2, 7): # NOTE: this may disappear expect_lhs.add("except_handler_else") @@ -60,8 +60,8 @@ def test_grammar(): """.split() ) ) - if PYTHON_VERSION >= 3.0: - if PYTHON_VERSION < 3.7: + if PYTHON_VERSION_TRIPLE >= (3, 0): + if PYTHON_VERSION_TRIPLE < (3, 7): expect_lhs.add("annotate_arg") expect_lhs.add("annotate_tuple") unused_rhs.add("mkfunc_annotate") @@ -69,7 +69,7 @@ def test_grammar(): unused_rhs.add("dict_comp") unused_rhs.add("classdefdeco1") unused_rhs.add("tryelsestmtl") - if PYTHON_VERSION >= 3.5: + if PYTHON_VERSION_TRIPLE >= (3, 7): expect_right_recursive.add( (("l_stmts", ("lastl_stmt", "come_froms", "l_stmts"))) ) @@ -80,7 +80,7 @@ def test_grammar(): expect_lhs.add("kwarg") # FIXME - if PYTHON_VERSION < 3.8: + if PYTHON_VERSION_TRIPLE < (3, 8): assert expect_lhs == set(lhs) assert unused_rhs == set(rhs) @@ -103,7 +103,7 @@ def test_grammar(): print(k, reduced_dup_rhs[k]) # assert not reduced_dup_rhs, reduced_dup_rhs - s = get_scanner(PYTHON_VERSION, IS_PYPY) + s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY) ignore_set = set( """ JUMP_BACK CONTINUE @@ -116,12 +116,12 @@ def test_grammar(): RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST """.split() ) - if 2.6 <= PYTHON_VERSION <= 2.7: + if (2, 6) <= PYTHON_VERSION_TRIPLE <= (2, 7): opcode_set = set(s.opc.opname).union(ignore_set) - if PYTHON_VERSION == 2.6: + if PYTHON_VERSION_TRIPLE[:2] == (2, 6): opcode_set.add("THEN") check_tokens(tokens, opcode_set) - elif PYTHON_VERSION == 3.4: + elif PYTHON_VERSION_TRIPLE[:2] == (3, 4): ignore_set.add("LOAD_CLASSNAME") ignore_set.add("STORE_LOCALS") opcode_set = set(s.opc.opname).union(ignore_set) @@ -132,7 +132,7 @@ def test_dup_rule(): import inspect python_parser( - PYTHON_VERSION, + PYTHON_VERSION_TRIPLE, inspect.currentframe().f_code, is_pypy=IS_PYPY, parser_debug={ diff --git a/pytest/validate.py b/pytest/validate.py index 833dd02d..7ba3d527 100644 --- a/pytest/validate.py +++ b/pytest/validate.py @@ -9,12 +9,13 @@ import tempfile import functools # uncompyle6 / xdis -from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse +from uncompyle6 import code_deparse +from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY # TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there from xdis import Bytecode, get_opcode -opc = get_opcode(PYTHON_VERSION, IS_PYPY) +opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY) Bytecode = functools.partial(Bytecode, opc=opc) import six @@ -127,7 +128,7 @@ def validate_uncompyle(text, mode="exec"): original_text = text deparsed = code_deparse( - original_code, out=six.StringIO(), version=PYTHON_VERSION, compile_mode=mode + original_code, out=six.StringIO(), version=PYTHON_VERSION_TRIPLE, compile_mode=mode ) uncompyled_text = deparsed.text uncompyled_code = compile(uncompyled_text, "", "exec") diff --git a/uncompyle6/disas.py b/uncompyle6/disas.py index 843fb9a3..220753ae 100644 --- a/uncompyle6/disas.py +++ b/uncompyle6/disas.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016, 2818-2020 by Rocky Bernstein +# Copyright (c) 2015-2016, 2818-2021 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -47,7 +47,7 @@ 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) + print("# Python %s" % ".".join([str(v) for v in version]), file=real_out) if co.co_filename: print("# Embedded file name: %s" % co.co_filename, file=real_out) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index bba57f41..0d94d26d 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -642,7 +642,7 @@ def get_python_parser( # If version is a string, turn that into the corresponding float. if isinstance(version, str): - version = py_str2float(version) + version = tuple([int(v) for v in version.split(".")[:3]]) # FIXME: there has to be a better way... # We could do this as a table lookup, but that would force us diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 5896266e..d5433b3a 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016, 2018-2020 by Rocky Bernstein +# Copyright (c) 2016, 2018-2021 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -105,7 +105,7 @@ class Scanner(object): self.show_asm = show_asm self.is_pypy = is_pypy - if version in PYTHON_VERSIONS: + if version[:2] in PYTHON_VERSIONS: if is_pypy: v_str = "opcode_%spypy" % ("".join([str(v) for v in version])) else: @@ -113,7 +113,7 @@ class Scanner(object): exec("from xdis.opcodes import %s" % v_str) exec("self.opc = %s" % v_str) else: - raise TypeError("%s is not a Python version I know about" % version) + raise TypeError("%s is not a Python version I know about" % ".".join([str(v) for v in version])) self.opname = self.opc.opname diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index e25bb587..f21a8edb 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2020 by Rocky Bernstein +# Copyright (c) 2015-2021 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # @@ -288,7 +288,7 @@ class Scanner2(Scanner): # last_offset = jump_offset come_from_name = "COME_FROM" op_name = self.opname_for_offset(jump_offset) - if op_name.startswith("SETUP_") and self.version == 2.7: + if op_name.startswith("SETUP_") and self.version[:2] == (2, 7): come_from_type = op_name[len("SETUP_") :] if come_from_type not in ("LOOP", "EXCEPT"): come_from_name = "COME_FROM_%s" % come_from_type @@ -350,12 +350,12 @@ class Scanner2(Scanner): pattr = names[oparg] elif op in self.opc.JREL_OPS: # use instead: hasattr(self, 'patch_continue'): ? - if self.version == 2.7: + if self.version[:2] == (2, 7): self.patch_continue(tokens, offset, op) pattr = repr(offset + 3 + oparg) elif op in self.opc.JABS_OPS: # use instead: hasattr(self, 'patch_continue'): ? - if self.version == 2.7: + if self.version[:2] == (2, 7): self.patch_continue(tokens, offset, op) pattr = repr(oparg) elif op in self.opc.LOCAL_OPS: @@ -515,7 +515,7 @@ class Scanner2(Scanner): while code[j] == self.opc.JUMP_ABSOLUTE: j = self.prev[j] if ( - self.version >= 2.3 and self.opname_for_offset(j) == "LIST_APPEND" + self.version >= (2, 3) and self.opname_for_offset(j) == "LIST_APPEND" ): # list comprehension stmts.remove(s) continue @@ -529,7 +529,7 @@ class Scanner2(Scanner): prev = code[self.prev[s]] if ( prev == self.opc.ROT_TWO - or self.version < 2.7 + or self.version < (2, 7) and prev in ( self.opc.JUMP_IF_FALSE, @@ -543,7 +543,7 @@ class Scanner2(Scanner): j = self.prev[s] while code[j] in self.designator_ops: j = self.prev[j] - if self.version > 2.1 and code[j] == self.opc.FOR_ITER: + if self.version > (2, 1) and code[j] == self.opc.FOR_ITER: stmts.remove(s) continue last_stmt = s @@ -563,7 +563,7 @@ class Scanner2(Scanner): jmp = self.prev[self.get_target(except_match)] # In Python < 2.7 we may have jumps to jumps - if self.version < 2.7 and self.code[jmp] in self.jump_forward: + if self.version < (2, 7) and self.code[jmp] in self.jump_forward: self.not_continue.add(jmp) jmp = self.get_target(jmp) prev_offset = self.prev[except_match] @@ -587,7 +587,7 @@ class Scanner2(Scanner): op = self.code[i] if op == self.opc.END_FINALLY: if count_END_FINALLY == count_SETUP_: - if self.version == 2.7: + if self.version[:2] == (2, 7): assert self.code[self.prev[i]] in self.jump_forward | frozenset( [self.opc.RETURN_VALUE] ) @@ -649,7 +649,7 @@ class Scanner2(Scanner): # Account for the fact that < 2.7 has an explicit # POP_TOP instruction in the equivalate POP_JUMP_IF # construct - if self.version < 2.7: + if self.version < (2, 7): jump_forward_offset = jump_back_offset + 4 return_val_offset1 = self.prev[ self.prev[self.prev[loop_end_offset]] @@ -691,7 +691,7 @@ class Scanner2(Scanner): jump_back_offset += 1 if_offset = None - if self.version < 2.7: + if self.version < (2, 7): # Look for JUMP_IF POP_TOP ... if code[self.prev[next_line_byte]] == self.opc.POP_TOP and ( code[self.prev[self.prev[next_line_byte]]] in self.pop_jump_if @@ -703,7 +703,7 @@ class Scanner2(Scanner): if if_offset: loop_type = "while" self.ignore_if.add(if_offset) - if self.version < 2.7 and ( + if self.version < (2, 7) and ( code[self.prev[jump_back_offset]] == self.opc.RETURN_VALUE ): self.ignore_if.add(self.prev[jump_back_offset]) @@ -735,7 +735,7 @@ class Scanner2(Scanner): setup_target = self.get_target(jump_back_offset, self.opc.JUMP_ABSOLUTE) - if self.version > 2.1 and code[setup_target] in ( + if self.version > (2, 1) and code[setup_target] in ( self.opc.FOR_ITER, self.opc.GET_ITER, ): @@ -745,7 +745,7 @@ class Scanner2(Scanner): # Look for a test condition immediately after the # SETUP_LOOP while if ( - self.version < 2.7 + self.version < (2, 7) and self.code[self.prev[next_line_byte]] == self.opc.POP_TOP ): test_op_offset = self.prev[self.prev[next_line_byte]] @@ -822,7 +822,7 @@ class Scanner2(Scanner): if target != start_else: end_else = self.get_target(jmp) if self.code[jmp] == self.opc.JUMP_FORWARD: - if self.version <= 2.6: + if self.version <= (2, 6): self.fixed_jumps[jmp] = target else: self.fixed_jumps[jmp] = -1 @@ -833,7 +833,7 @@ class Scanner2(Scanner): if end_else != start_else: r_end_else = self.restrict_to_parent(end_else, parent) # May be able to drop the 2.7 test. - if self.version == 2.7: + if self.version[:2] == (2, 7): self.structs.append( {"type": "try-else", "start": i + 1, "end": r_end_else} ) @@ -861,7 +861,7 @@ class Scanner2(Scanner): # possibly I am "skipping over" a "pass" or null statement. test_target = target - if self.version < 2.7: + if self.version < (2, 7): # Before 2.7 we have to deal with the fact that there is an extra # POP_TOP that is logically associated with the JUMP_IF's (even though # the instance set is called "self.pop_jump_if") @@ -981,7 +981,7 @@ class Scanner2(Scanner): self.fixed_jumps[offset] = fix or match[-1] return else: - if self.version < 2.7 and parent["type"] in ( + if self.version < (2, 7) and parent["type"] in ( "root", "for-loop", "if-then", @@ -997,7 +997,7 @@ class Scanner2(Scanner): self.fixed_jumps[offset] = match[-1] return else: # op != self.opc.PJIT - if self.version < 2.7 and code[offset + 3] == self.opc.POP_TOP: + if self.version < (2, 7) and code[offset + 3] == self.opc.POP_TOP: assert_offset = offset + 4 else: assert_offset = offset + 3 @@ -1039,7 +1039,7 @@ class Scanner2(Scanner): if offset in self.ignore_if: return - if self.version == 2.7: + if self.version == (2, 7): if ( code[pre_rtarget] == self.opc.JUMP_ABSOLUTE and pre_rtarget in self.stmts @@ -1109,7 +1109,7 @@ class Scanner2(Scanner): if_then_maybe = None - if 2.2 <= self.version <= 2.6: + if (2, 2) <= self.version <= (2, 6): # Take the JUMP_IF target. In an "if/then", it will be # a POP_TOP instruction and the instruction before it # will be a JUMP_FORWARD to just after the POP_TOP. @@ -1159,13 +1159,13 @@ class Scanner2(Scanner): "end": pre_rtarget, } - elif self.version == 2.7: + elif self.version[:2] == (2, 7): self.structs.append( {"type": "if-then", "start": start - 3, "end": pre_rtarget} ) # FIXME: this is yet another case were we need dominators. - if pre_rtarget not in self.linestarts or self.version < 2.7: + if pre_rtarget not in self.linestarts or self.version < (2, 7): self.not_continue.add(pre_rtarget) if rtarget < end_offset: @@ -1194,7 +1194,7 @@ class Scanner2(Scanner): {"type": "else", "start": rtarget, "end": end_offset} ) elif code_pre_rtarget == self.opc.RETURN_VALUE: - if self.version == 2.7 or pre_rtarget not in self.ignore_if: + if self.version[:2] == (2, 7) or pre_rtarget not in self.ignore_if: # Below, 10 is exception-match. If there is an exception # match in the compare, then this is an exception # clause not an if-then clause @@ -1207,7 +1207,7 @@ class Scanner2(Scanner): ) self.thens[start] = rtarget if ( - self.version == 2.7 + self.version[:2] == (2, 7) or code[pre_rtarget + 1] != self.opc.JUMP_FORWARD ): # The below is a big hack until we get @@ -1220,7 +1220,7 @@ class Scanner2(Scanner): # instruction before. self.fixed_jumps[offset] = rtarget if ( - self.version == 2.7 + self.version[:2] == (2, 7) and self.insts[ self.offset2inst_index[pre[pre_rtarget]] ].is_jump_target @@ -1291,7 +1291,7 @@ class Scanner2(Scanner): # if (op in self.opc.JREL_OPS and # (self.version < 2.0 or op != self.opc.FOR_ITER)): label = offset + 3 + oparg - elif self.version == 2.7 and op in self.opc.JABS_OPS: + elif self.version[:2] == (2, 7) and op in self.opc.JABS_OPS: if op in ( self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP, @@ -1307,7 +1307,7 @@ class Scanner2(Scanner): # We REALLY REALLY need a better way to handle control flow # Expecially for < 2.7 if label is not None and label != -1: - if self.version == 2.7: + if self.version[:2] == (2, 7): # FIXME: rocky: I think we need something like this... if label in self.setup_loops: source = self.setup_loops[label] @@ -1342,7 +1342,7 @@ class Scanner2(Scanner): # handle COME_FROM's from a loop inside if's # It probably should. if ( - self.version > 2.6 + self.version > (2, 6) or self.code[source] != self.opc.SETUP_LOOP or self.code[label] != self.opc.JUMP_FORWARD ): @@ -1354,7 +1354,7 @@ class Scanner2(Scanner): elif ( op == self.opc.END_FINALLY and offset in self.fixed_jumps - and self.version == 2.7 + and self.version[:2] == (2, 7) ): label = self.fixed_jumps[offset] targets[label] = targets.get(label, []) + [offset] diff --git a/uncompyle6/scanners/scanner22.py b/uncompyle6/scanners/scanner22.py index cb75f25d..ab8848a4 100644 --- a/uncompyle6/scanners/scanner22.py +++ b/uncompyle6/scanners/scanner22.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2018 by Rocky Bernstein +# Copyright (c) 2016-2018, 2021 by Rocky Bernstein """ Python 2.2 bytecode massaging. diff --git a/uncompyle6/scanners/scanner23.py b/uncompyle6/scanners/scanner23.py index d009d95d..30991d56 100644 --- a/uncompyle6/scanners/scanner23.py +++ b/uncompyle6/scanners/scanner23.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2018 by Rocky Bernstein +# Copyright (c) 2016-2018, 2021 by Rocky Bernstein """ Python 2.3 bytecode massaging. @@ -23,6 +23,6 @@ class Scanner23(scan.Scanner24): self.opname = opcode_23.opname # These are the only differences in initialization between # 2.3-2.6 - self.version = 2.3 + self.version = (2, 3) self.genexpr_name = '' return diff --git a/uncompyle6/scanners/scanner24.py b/uncompyle6/scanners/scanner24.py index 107a6d60..c77284f2 100755 --- a/uncompyle6/scanners/scanner24.py +++ b/uncompyle6/scanners/scanner24.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017 by Rocky Bernstein +# Copyright (c) 2016-2017, 2021 by Rocky Bernstein """ Python 2.4 bytecode massaging. @@ -10,6 +10,7 @@ import uncompyle6.scanners.scanner25 as scan # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_24 + JUMP_OPS = opcode_24.JUMP_OPS # We base this off of 2.5 instead of the other way around @@ -23,6 +24,6 @@ class Scanner24(scan.Scanner25): # 2.4, 2.5 and 2.6 self.opc = opcode_24 self.opname = opcode_24.opname - self.version = 2.4 - self.genexpr_name = '' + self.version = (2, 4) + self.genexpr_name = "" return diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 6c0ab135..6c8d4de4 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2017 by Rocky Bernstein +# Copyright (c) 2015-2017, 2021 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # @@ -40,7 +40,7 @@ JUMP_OPS = opcode_26.JUMP_OPS class Scanner26(scan.Scanner2): def __init__(self, show_asm=False): - super(Scanner26, self).__init__(2.6, show_asm) + super(Scanner26, self).__init__((2, 6), show_asm) # "setup" opcodes self.setup_ops = frozenset([ diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index f8be9de6..79b31153 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2018 by Rocky Bernstein +# Copyright (c) 2015-2018, 2021 by Rocky Bernstein """ Python 2.7 bytecode ingester. @@ -12,77 +12,115 @@ from __future__ import print_function from uncompyle6.scanners.scanner2 import Scanner2 from uncompyle6 import PYTHON3 + if PYTHON3: import sys + intern = sys.intern # bytecode verification, verify(), uses JUMP_OPs from here from xdis.opcodes import opcode_27 + JUMP_OPS = opcode_27.JUMP_OPs + class Scanner27(Scanner2): def __init__(self, show_asm=False, is_pypy=False): - super(Scanner27, self).__init__(2.7, show_asm, is_pypy) + super(Scanner27, self).__init__((2, 7), show_asm, is_pypy) # opcodes that start statements self.statement_opcodes = frozenset( - self.statement_opcodes | set([ - # New in 2.7 - self.opc.SETUP_WITH, - self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, - self.opc.STORE_SLICE_2, self.opc.STORE_SLICE_3, - self.opc.DELETE_SLICE_0, self.opc.DELETE_SLICE_1, - self.opc.DELETE_SLICE_2, self.opc.DELETE_SLICE_3, - ])) + self.statement_opcodes + | set( + [ + # New in 2.7 + self.opc.SETUP_WITH, + self.opc.STORE_SLICE_0, + self.opc.STORE_SLICE_1, + self.opc.STORE_SLICE_2, + self.opc.STORE_SLICE_3, + self.opc.DELETE_SLICE_0, + self.opc.DELETE_SLICE_1, + self.opc.DELETE_SLICE_2, + self.opc.DELETE_SLICE_3, + ] + ) + ) # opcodes which expect a variable number pushed values and whose # count is in the opcode. For parsing we generally change the # opcode name to include that number. - varargs_ops = set([ - self.opc.BUILD_LIST, self.opc.BUILD_TUPLE, - self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE, - self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION, - self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR, - self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW, - self.opc.DUP_TOPX, self.opc.RAISE_VARARGS, - # New in Python 2.7 - self.opc.BUILD_SET, self.opc.BUILD_MAP]) + varargs_ops = set( + [ + self.opc.BUILD_LIST, + self.opc.BUILD_TUPLE, + self.opc.BUILD_SLICE, + self.opc.UNPACK_SEQUENCE, + self.opc.MAKE_FUNCTION, + self.opc.CALL_FUNCTION, + self.opc.MAKE_CLOSURE, + self.opc.CALL_FUNCTION_VAR, + self.opc.CALL_FUNCTION_KW, + self.opc.CALL_FUNCTION_VAR_KW, + self.opc.DUP_TOPX, + self.opc.RAISE_VARARGS, + # New in Python 2.7 + self.opc.BUILD_SET, + self.opc.BUILD_MAP, + ] + ) if is_pypy: varargs_ops.add(self.opc.CALL_METHOD) self.varargs_ops = frozenset(varargs_ops) # "setup" opcodes - self.setup_ops = frozenset([ - self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY, - # New in 2.7 - self.opc.SETUP_WITH]) + self.setup_ops = frozenset( + [ + self.opc.SETUP_EXCEPT, + self.opc.SETUP_FINALLY, + # New in 2.7 + self.opc.SETUP_WITH, + ] + ) # opcodes that store values into a variable - self.designator_ops = frozenset([ - self.opc.STORE_FAST, self.opc.STORE_NAME, - self.opc.STORE_GLOBAL, self.opc.STORE_DEREF, self.opc.STORE_ATTR, - self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, self.opc.STORE_SLICE_2, - self.opc.STORE_SLICE_3, self.opc.STORE_SUBSCR, self.opc.UNPACK_SEQUENCE, - self.opc.JUMP_ABSOLUTE - ]) + self.designator_ops = frozenset( + [ + self.opc.STORE_FAST, + self.opc.STORE_NAME, + self.opc.STORE_GLOBAL, + self.opc.STORE_DEREF, + self.opc.STORE_ATTR, + self.opc.STORE_SLICE_0, + self.opc.STORE_SLICE_1, + self.opc.STORE_SLICE_2, + self.opc.STORE_SLICE_3, + self.opc.STORE_SUBSCR, + self.opc.UNPACK_SEQUENCE, + self.opc.JUMP_ABSOLUTE, + ] + ) - self.pop_jump_if_or_pop = frozenset([self.opc.JUMP_IF_FALSE_OR_POP, - self.opc.JUMP_IF_TRUE_OR_POP]) + self.pop_jump_if_or_pop = frozenset( + [self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP] + ) return pass + if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - if PYTHON_VERSION == 2.7: + from xdis.version_info import PYTHON_VERSION_TRIPLE + + if PYTHON_VERSION_TRIPLE[:2] == (2, 7): import inspect + co = inspect.currentframe().f_code tokens, customize = Scanner27().ingest(co) for t in tokens: print(t) pass else: - print("Need to be Python 2.7 to demo; I am %s." % - PYTHON_VERSION) + print("Need to be Python 2.7 to demo; I am %s." % ".".join(str(v) for v in PYTHON_VERSION_TRIPLE)) diff --git a/uncompyle6/scanners/scanner37.py b/uncompyle6/scanners/scanner37.py index 44dfdd76..0dde1cf0 100644 --- a/uncompyle6/scanners/scanner37.py +++ b/uncompyle6/scanners/scanner37.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2019 by Rocky Bernstein +# Copyright (c) 2016-2019, 2021 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ JUMP_OPs = opc.JUMP_OPS class Scanner37(Scanner37Base): def __init__(self, show_asm=None): - Scanner37Base.__init__(self, 3.7, show_asm) + Scanner37Base.__init__(self, (3, 7), show_asm) return pass diff --git a/uncompyle6/scanners/scanner37base.py b/uncompyle6/scanners/scanner37base.py index 3478c6d3..4df09e3e 100644 --- a/uncompyle6/scanners/scanner37base.py +++ b/uncompyle6/scanners/scanner37base.py @@ -55,7 +55,7 @@ class Scanner37Base(Scanner): # Ops that start SETUP_ ... We will COME_FROM with these names # Some blocks and END_ statements. And they can start # a new statement - if self.version < 3.8: + if self.version < (3, 8): setup_ops = [ self.opc.SETUP_LOOP, self.opc.SETUP_EXCEPT, @@ -468,7 +468,7 @@ class Scanner37Base(Scanner): and self.insts[i + 1].opname == "JUMP_FORWARD" ) - if self.version < 3.8 and ( + if self.version < (3, 8) and ( is_continue or ( inst.offset in self.stmts @@ -712,7 +712,7 @@ class Scanner37Base(Scanner): end = current_end parent = struct - if self.version < 3.8 and op == self.opc.SETUP_LOOP: + if self.version < (3, 8) and op == self.opc.SETUP_LOOP: # We categorize loop types: 'for', 'while', 'while 1' with # possibly suffixes '-loop' and '-else' # Try to find the jump_back instruction of the loop. @@ -820,7 +820,7 @@ class Scanner37Base(Scanner): target = inst.argval self.fixed_jumps[offset] = target - elif self.version < 3.8 and op == self.opc.SETUP_EXCEPT: + elif self.version < (3, 8) and op == self.opc.SETUP_EXCEPT: target = self.get_target(offset) end = self.restrict_to_parent(target, parent) self.fixed_jumps[offset] = end diff --git a/uncompyle6/scanners/scanner38.py b/uncompyle6/scanners/scanner38.py index 7f81afc5..90928f48 100644 --- a/uncompyle6/scanners/scanner38.py +++ b/uncompyle6/scanners/scanner38.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2020 by Rocky Bernstein +# Copyright (c) 2019-2021 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ JUMP_OPs = opc.JUMP_OPS class Scanner38(Scanner37): def __init__(self, show_asm=None): - Scanner37Base.__init__(self, 3.8, show_asm) + Scanner37Base.__init__(self, (3, 8), show_asm) self.debug = False return @@ -61,7 +61,7 @@ class Scanner38(Scanner37): if self.debug and jump_back_targets: print(jump_back_targets) loop_ends = [] - next_end = tokens[len(tokens)-1].off2int() + 10 + next_end = tokens[len(tokens) - 1].off2int() + 10 for i, token in enumerate(tokens): opname = token.kind offset = token.offset @@ -70,13 +70,19 @@ class Scanner38(Scanner37): if self.debug: print("%sremove loop offset %s" % (" " * len(loop_ends), offset)) pass - next_end = loop_ends[-1] if len(loop_ends) else tokens[len(tokens)-1].off2int() + 10 + next_end = ( + loop_ends[-1] + if len(loop_ends) + else tokens[len(tokens) - 1].off2int() + 10 + ) if offset in jump_back_targets: next_end = off2int(jump_back_targets[offset], prefer_last=False) if self.debug: - print("%sadding loop offset %s ending at %s" % - (' ' * len(loop_ends), offset, next_end)) + print( + "%sadding loop offset %s ending at %s" + % (" " * len(loop_ends), offset, next_end) + ) loop_ends.append(next_end) # Turn JUMP opcodes into "BREAK_LOOP" opcodes. @@ -107,10 +113,7 @@ class Scanner38(Scanner37): jump_back_token = tokens[jump_back_index] # Is this a forward jump not next to a JUMP_BACK ? ... - break_loop = ( - token.linestart - and jump_back_token != "JUMP_BACK" - ) + break_loop = token.linestart and jump_back_token != "JUMP_BACK" # or if there is looping jump back, then that loop # should start before where the "break" instruction sits. @@ -136,5 +139,4 @@ if __name__ == "__main__": print(t.format()) pass else: - print("Need to be Python 3.8 to demo; I am %s." % - PYTHON_VERSION) + print("Need to be Python 3.8 to demo; I am %s." % PYTHON_VERSION) diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index afe1cd06..0d850ef8 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018-2019 by Rocky Bernstein +# Copyright (c) 2018-2019, 2021 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index b7812407..abde5cba 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -398,7 +398,7 @@ def customize_for_version3(self, version): self.default(node) self.n_call = n_call - elif version < 3.2: + elif version < (3, 2): def n_call(node): mapping = self._get_mapping(node)