mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-10-07 10:13:39 +00:00
More Python version comparison conversions
This commit is contained in:
parent
c68b74a9c6
commit
e8e006bb8c
@ -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
|
@ -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'
|
@ -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
|
||||
|
@ -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={
|
||||
|
@ -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, "<string>", "exec")
|
||||
|
@ -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 <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# 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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# 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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 by Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
@ -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]
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
||||
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
|
||||
"""
|
||||
Python 2.2 bytecode massaging.
|
||||
|
||||
|
@ -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 = '<generator expression>'
|
||||
return
|
||||
|
@ -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 = '<generator expression>'
|
||||
self.version = (2, 4)
|
||||
self.genexpr_name = "<generator expression>"
|
||||
return
|
||||
|
@ -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 <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
@ -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([
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user