More Python version comparison conversions

This commit is contained in:
rocky 2021-10-16 11:33:03 -04:00
parent c68b74a9c6
commit e8e006bb8c
19 changed files with 167 additions and 162 deletions

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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={

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -1,4 +1,4 @@
# Copyright (c) 2016-2018 by Rocky Bernstein
# Copyright (c) 2016-2018, 2021 by Rocky Bernstein
"""
Python 2.2 bytecode massaging.

View File

@ -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

View File

@ -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

View File

@ -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([

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)