From f9133060702589e597542a274f942883392d5d75 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 16 Sep 2022 19:03:00 -0400 Subject: [PATCH 1/4] Use github xdis... So we pick up newer versions of Python 3.{7,8,9}.14 & 3.10.7 --- .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 16671d66..c08a884b 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -23,7 +23,7 @@ jobs: 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 git+https://github.com/rocky/python-xdis#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 3123be7f..0294b57b 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+https://github.com/rocky/python-xdis#egg=xdis + pip install git+https://github.com/rocky/python-xdis#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 f096f927..91084679 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -23,7 +23,7 @@ jobs: 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 git+https://github.com/rocky/python-xdis#egg=xdis pip install -e . pip install -r requirements-dev.txt - name: Test uncompyle6 From a68f440d6faa6abc3b318a0097024e95eab9744a Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Sep 2022 01:59:42 -0400 Subject: [PATCH 2/4] Sync with decompyle3 Better PyPy 3.7 tolerance --- test/stdlib/runtests.sh | 27 +++++++- uncompyle6/parsers/parse37.py | 15 ++--- uncompyle6/semantics/customize.py | 97 +++++++++++++++++++---------- uncompyle6/semantics/customize36.py | 2 + uncompyle6/semantics/gencomp.py | 23 ++++++- 5 files changed, 119 insertions(+), 45 deletions(-) diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 01891309..b0c74644 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -29,7 +29,19 @@ function displaytime { # Python version setup FULLVERSION=$(pyenv local) PYVERSION=${FULLVERSION%.*} -MINOR=${FULLVERSION##?.?.} + +if [[ $PYVERSION =~ 'pypy' ]] ; then + IS_PYPY=1 +else + IS_PYPY=0 +fi + +if [[ $FULLVERSION =~ pypy([2-3])\.([7-9]) ]]; then + MAJOR="${BASH_REMATCH[1]}" + MINOR="${BASH_REMATCH[2]}" +else + MINOR=${FULLVERSION##?.?.} +fi STOP_ONERROR=${STOP_ONERROR:-1} @@ -150,7 +162,12 @@ done mkdir $TESTDIR || exit $? -cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR + +if ((IS_PYPY)); then + cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib-python/${MAJOR}/test $TESTDIR +else + cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR +fi if [[ $PYVERSION == 3.2 ]] ; then cp ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test/* $TESTDIR cd $TESTDIR @@ -209,7 +226,11 @@ for file in $files; do ((i++)) # (( i > 40 )) && break short_name=$(basename $file .py) - decompiled_file=$short_name-${PYVERSION}.pyc + 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 =========== diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 5d168ab4..80d9c6dd 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -138,7 +138,8 @@ class Python37Parser(Python37BaseParser): returns ::= _stmts return stmt ::= genexpr_func - genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK + genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter + _come_froms JUMP_BACK _come_froms """ pass @@ -1365,7 +1366,7 @@ class Python37Parser(Python37BaseParser): genexpr_func_async ::= LOAD_ARG func_async_prefix store func_async_middle comp_iter - JUMP_LOOP COME_FROM + JUMP_BACK COME_FROM POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP # FIXME this is a workaround for probalby some bug in the Earley parser @@ -1377,7 +1378,7 @@ class Python37Parser(Python37BaseParser): list_afor2 ::= func_async_prefix store func_async_middle list_iter - JUMP_LOOP COME_FROM + JUMP_BACK COME_FROM POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP list_comp_async ::= BUILD_LIST_0 LOAD_ARG list_afor2 @@ -1463,13 +1464,13 @@ class Python37Parser(Python37BaseParser): genexpr_func_async ::= LOAD_ARG async_iter store_async_iter_end comp_iter - JUMP_LOOP COME_FROM + JUMP_BACK COME_FROM POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP list_afor2 ::= async_iter store list_iter - JUMP_LOOP + JUMP_BACK COME_FROM_FINALLY END_ASYNC_FOR @@ -1479,7 +1480,7 @@ class Python37Parser(Python37BaseParser): store func_async_middle set_iter - JUMP_LOOP COME_FROM + JUMP_BACK COME_FROM POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP set_afor2 ::= expr_or_arg @@ -1490,7 +1491,7 @@ class Python37Parser(Python37BaseParser): set_iter_async ::= async_iter store set_iter - JUMP_LOOP + JUMP_BACK _come_froms END_ASYNC_FOR diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index 43942937..93855726 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -17,7 +17,13 @@ """ from uncompyle6.parsers.treenode import SyntaxTree -from uncompyle6.semantics.consts import INDENT_PER_LEVEL, NO_PARENTHESIS_EVER, PRECEDENCE, TABLE_R, TABLE_DIRECT +from uncompyle6.semantics.consts import ( + INDENT_PER_LEVEL, + NO_PARENTHESIS_EVER, + PRECEDENCE, + TABLE_R, + TABLE_DIRECT, +) from uncompyle6.semantics.helper import flatten_list from uncompyle6.scanners.tok import Token @@ -27,22 +33,29 @@ def customize_for_version(self, is_pypy, version): ######################## # PyPy changes ####################### + # fmt: off TABLE_DIRECT.update({ - "assert": ("%|assert %c\n", 0), - "assert_pypy": ( '%|assert %c\n' , (1, 'assert_expr') ), - # This is as a result of an if transformation - 'assert0_pypy': ( '%|assert %c\n' , 0), - 'assert_not_pypy': ( '%|assert not %c\n' , (1, 'assert_exp') ), - 'assert2_not_pypy': ( '%|assert not %c, %c\n' , (1, 'assert_exp'), - (4, 'expr') ), - 'assert2_pypy': ( '%|assert %c, %c\n' , (1, 'assert_expr'), - (4, 'expr') ), - 'try_except_pypy': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ), - 'tryfinallystmt_pypy': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 3 ), - 'assign3_pypy': ( '%|%c, %c, %c = %c, %c, %c\n', 5, 4, 3, 0, 1, 2 ), - 'assign2_pypy': ( '%|%c, %c = %c, %c\n', 3, 2, 0, 1), + "assert": ("%|assert %c\n", 0), + # This can happen as a result of an if transformation + "assert2": ("%|assert %c, %c\n", 0, 3), + "assert_pypy": ( "%|assert %c\n" , (1, "assert_expr") ), + # This is as a result of an if transformation + 'assert0_pypy': ( "%|assert %c\n" , 0), + + 'assert_not_pypy': ( "%|assert not %c\n" , (1, "assert_exp") ), + "assert2_not_pypy": ( + "%|assert not %c, %c\n", + (1, "assert_exp"), + (4, "expr"), + ), + + "try_except_pypy": ( "%|try:\n%+%c%-%c\n\n", 1, 2 ), + "tryfinallystmt_pypy": ( "%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", 1, 3 ), + "assign3_pypy": ( "%|%c, %c, %c = %c, %c, %c\n", 5, 4, 3, 0, 1, 2 ), + "assign2_pypy": ( "%|%c, %c = %c, %c\n", 3, 2, 0, 1), }) + # fmt: on if version[:2] >= (3, 7): @@ -53,12 +66,18 @@ def customize_for_version(self, is_pypy, version): kw_names = node[-2] assert kw_names == "pypy_kw_keys" - flat_elems = flatten_list(node[1:-2]) - n = len(flat_elems) - assert n == arg_count kwargs_names = kw_names[0].attr kwarg_count = len(kwargs_names) pos_argc = arg_count - kwarg_count + + flat_elems = flatten_list(node[1:-2]) + n = len(flat_elems) + assert n == arg_count, "n: %s, arg_count: %s\n%s" % ( + n, + arg_count, + node, + ) + sep = "" for i in range(pos_argc): @@ -95,20 +114,23 @@ def customize_for_version(self, is_pypy, version): ######################## # Without PyPy ####################### - TABLE_DIRECT.update({ - # "assert" and "assert_expr" are added via transform rules. - "assert": ("%|assert %c\n", 0), - "assert2": ("%|assert %c, %c\n", 0, 3), - - # Created only via transformation - "assertnot": ("%|assert not %p\n", (0, PRECEDENCE['unary_not'])), - "assert2not": ( "%|assert not %p, %c\n" , - (0, PRECEDENCE['unary_not']), 3 ), - - "assign2": ("%|%c, %c = %c, %c\n", 3, 4, 0, 1), - "assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2), - "try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3), - }) + TABLE_DIRECT.update( + { + # "assert" and "assert_expr" are added via transform rules. + "assert": ("%|assert %c\n", 0), + "assert2": ("%|assert %c, %c\n", 0, 3), + # Created only via transformation + "assertnot": ("%|assert not %p\n", (0, PRECEDENCE["unary_not"])), + "assert2not": ( + "%|assert not %p, %c\n", + (0, PRECEDENCE["unary_not"]), + 3, + ), + "assign2": ("%|%c, %c = %c, %c\n", 3, 4, 0, 1), + "assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2), + "try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3), + } + ) if version >= (3, 0): if version >= (3, 2): TABLE_DIRECT.update( @@ -187,6 +209,7 @@ 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) @@ -195,6 +218,7 @@ def customize_for_version(self, is_pypy, version): self.n_iftrue_stmt24 = n_iftrue_stmt24 elif version < (1, 4): from uncompyle6.semantics.customize14 import customize_for_version14 + customize_for_version14(self, version) def n_call(node): @@ -210,9 +234,16 @@ def customize_for_version(self, is_pypy, version): sep = ", " self.write(")") else: - self.template_engine(("%p(%P)", - (0, "expr", 100), (1,-1,", ", NO_PARENTHESIS_EVER)), node) + self.template_engine( + ( + "%p(%P)", + (0, "expr", 100), + (1, -1, ", ", NO_PARENTHESIS_EVER), + ), + node, + ) self.prune() + self.n_call = n_call else: # 1.0 <= version <= 2.3: diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index dde3dc3b..6c2339c7 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -167,6 +167,8 @@ def customize_for_version36(self, version): if node == "classdefdeco2": if isinstance(node[1][1].attr, str): class_name = node[1][1].attr + if self.is_pypy and class_name.find("") > 0: + class_name = class_name.split(".")[-1] else: class_name = node[1][2].attr build_class = node diff --git a/uncompyle6/semantics/gencomp.py b/uncompyle6/semantics/gencomp.py index 52f228ca..ae3f82eb 100644 --- a/uncompyle6/semantics/gencomp.py +++ b/uncompyle6/semantics/gencomp.py @@ -97,9 +97,12 @@ class ComprehensionMixin: self.prec = p def comprehension_walk( - self, node, iter_index: Optional[int], code_index: int = -5, + self, + node, + iter_index: Optional[int], + code_index: int = -5, ): - p = self.prec + p: int = self.prec self.prec = PRECEDENCE["lambda_body"] - 1 # FIXME: clean this up @@ -152,6 +155,22 @@ class ComprehensionMixin: while len(tree) == 1: tree = tree[0] + if tree == "stmts": + # FIXME: rest is a return None? + # Verify this + # rest = tree[1:] + tree = tree[0] + elif tree == "lambda_start": + assert len(tree) <= 3 + tree = tree[-2] + if tree == "return_expr_lambda": + tree = tree[1] + pass + + if tree in ("genexpr_func_async",): + if tree[3] == "comp_iter": + iter_index = 3 + n = tree[iter_index] assert n == "comp_iter", n.kind From 600688a65d72627b703ff6145be6681426f9ab64 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 17 Sep 2022 10:13:27 -0400 Subject: [PATCH 3/4] Sync with decompyle3 --- admin-tools/pyenv-newest-versions | 2 +- test/bytecode_3.6_run/10_fstring.pyc | Bin 1526 -> 2203 bytes test/simple_source/bug36/10_fstring.py | 24 +++++++++--- uncompyle6/semantics/customize37.py | 49 +++++++++++++++++++------ 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/admin-tools/pyenv-newest-versions b/admin-tools/pyenv-newest-versions index b6dd3491..f2c5ebcc 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.13 pypy3.8-7.3.9 pyston-2.3.3 3.8.13' +export PYVERSIONS='3.6.15 pypy3.6-7.3.1 3.7.14 pypy3.8-7.3.9 pyston-2.3.3 3.8.14' diff --git a/test/bytecode_3.6_run/10_fstring.pyc b/test/bytecode_3.6_run/10_fstring.pyc index b54bc4915c6d5d47f46d0f73b50da8cb08d7d842..c3ae23255cfd7e886ed86bb7ebae1caba60a6e58 100644 GIT binary patch literal 2203 zcmb^yU2oJzaChyybIe^Xgph;~z)1?>3LFGlDj|rFpj4`=NEH&Lt5%ld**knVcChat zG2!W=(uY2@&ryCrpZi<-vafy0U&vEu)=5aBK6XztJD%P7o}IhbXt>}1eKq{6!Pr0S z*s3G_7$JYj83QI6aLGYP0T$TXOj=NZYL^QpZCO$F4uhJi?1)`UR>4tK{2l?fhrA(2 z`pj-cI#7oOjCL(K0!`_vGiqeWVQj}%?i54b+0%R&-xa+&oEvgAGR0uR+&T}FaYHs> zN{+&`Y{CWA=#BNxs!?NSX4g_pyn7MvHeptd!zFnRF3SnH0v>vO9_C;k_sJt)rtq}7 zSy$7rFyx&5z>-OusSB^&-+3lDqu-A#5ic3s{t07~j+}vOu!uUw;X1T%zX;^htel0b z@VT1pU4k1!ZZXWvjJzzbe8b=-+}dVvYbd0rJZQsbNX^0IbJn_}`G)43+5*)HG0|qx zZX+xp=u!SV#@L}0~4 zCuu*7(=dqhWhBaDqwu)$L%ND0T67ZQ6FJ9tMy_eTr1{-_{-|&}gCy*yX`HwB`Sn8F z^!9m6^FZ@e%|p#W^Ow1WBEf1{h=!{xK^{g?PRbhY9%8nld0ShZG%cFG--$3J-+Sa` zi;IhejmRw;E~wZ$Jd;+MC~5WIrF#{W4oNvJ+9^9v5OT`UmN2<1gR`W^_NN3#3{0Aq)!y5h76EzMrY}%=fjOtGH7%Gu0ntiMO%g-S9f|CTB->$Tm6j93h`Y)J45NPki88^c0!F zeAoU%ys=TcC~A-1lhSr!&1E0TNQD+{?9I-p5cl1Oag_JNbZve4Thd;dDrQUXPPWD2 z#X_{^u@|V3TV+PH-AkhcyRq7dR1EnkD;TW_wv#*~8`LX|3-il7q>E-}@qO8K-o}HC z4~u)`#-58PL^xVUg(MAtkK4Q$u~IZw(!LjXkcMTOAG1$2FFz@R8D;MkLRn94zW-+% zns?)478a1+BQFYP>2CYp7hm50>V!cG^)Z4etYSEmu@|w81WqFBU^d%O!NOLx{auu( z6TMB+Pe^(U(H7rgK6W@_)MEM^3uJ}^-D_EPpgUAsF-HNNlkl&N4tJdf1n{)ah6o+q<>wop7UUozuo^zK_N8{ohd2L3N7y zfn{^B(yEY$Nw9{qK)b%bmcoGMg0B1in?VqlC)qVrkS!AWRC`022Dpj`zmN%HIozpa z#Mz@@Fh7&HWpjk)i7_wjw?VdK@Lg@;v^p4cuQh*L=J7IJrtIoU_-c^6mQ}Oi?N}wc zs**4TrA3-+ho%_$sH^34*7kbPf2C`|YEFddMQzg!>Bec-&(cAHZ;3{Zc_!HvGGnW^ zL9EX_-%R?!#@AVvX1ek&0+e6CV_5?gMr%PVYfle|k@XCzJW3N?LD7LS5o@v-^{23yfGz1eQ|NAi3nop!b^w)a+3j9sv6 z55;VgRqw%TqnYpG)(5#h1putnQD9DAs zU?v}L%b?w8Ka8%zAYg_ngm2BSZp3j7Z7eKmsQs;=lo}^W}P5bYh;LKiHURYVZzxIH}lBI;2j9`kuofQ0JS1t8%S)03i z`x*{3oGAK9nHmq@SPD@p diff --git a/test/simple_source/bug36/10_fstring.py b/test/simple_source/bug36/10_fstring.py index 876f15e9..52f79481 100644 --- a/test/simple_source/bug36/10_fstring.py +++ b/test/simple_source/bug36/10_fstring.py @@ -59,9 +59,9 @@ log_rounds = 5 assert "05$" == f"{log_rounds:02d}$" -def testit(a, b, l): - # print(l) - return l +def testit(a, b, ll): + # print(ll) + return ll # The call below shows the need for BUILD_STRING to count expr arguments. @@ -102,11 +102,11 @@ assert f"x={x*y:{width}}" == "x=foofoo " # equivalent thing. For compatiblity with older Python we'll use "%" # instead of a format string def f(): - f"""Not a docstring""" + f"""Not a docstring""" # noqa def g(): - """Not a docstring""" f"" + """Not a docstring""" f"" # noqa assert f.__doc__ is None @@ -129,3 +129,17 @@ assert f'{f"{0}"*3}' == "000" # The former, {{ confuses the format strings so dictionary/set comprehensions # don't work. assert f"expr={ {x: y for x, y in [(1, 2), ]}}" == "expr={1: 2}" + + +class Line: + def __init__(self, x, y): + self.x = x + self.y = y + + # From 3.7 test_typing.py + def __str__(self): + return f"{self.x} -> {self.y}" + + +line = Line(1, 2) +assert str(line) == "1 -> 2" diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index fe4c0c4b..b2680432 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -94,8 +94,7 @@ def customize_for_version37(self, version): # need parenthesis. # Note there are async dictionary expressions are like await expr's # the below is just the default fersion - "await_expr": ("await %p", (0, PRECEDENCE["await_expr"]-1)), - + "await_expr": ("await %p", (0, PRECEDENCE["await_expr"] - 1)), "await_stmt": ("%|%c\n", 0), "c_async_with_stmt": ("%|async with %c:\n%+%c%-", (0, "expr"), 3), "call_ex": ("%c(%p)", (0, "expr"), (1, 100)), @@ -156,7 +155,10 @@ def customize_for_version37(self, version): (2, "import_from_attr37"), (3, "store"), ), - "import_one": ("%c", (0, "importlists"),), + "import_one": ( + "%c", + (0, "importlists"), + ), "importattr37": ("%c", (0, "IMPORT_NAME_ATTR")), "import_from_attr37": ( "%c import %c", @@ -165,12 +167,9 @@ def customize_for_version37(self, version): ), "list_afor": ( " async for %[1]{%c} in %c%[1]{%c}", - (1, "store"), (0, "get_aiter"), (3, "list_iter"), - ), - - "list_afor": ( - " async for %[1]{%c} in %c%[1]{%c}", - (1, "store"), (0, "get_aiter"), (3, "list_iter"), + (1, "store"), + (0, "get_aiter"), + (3, "list_iter"), ), "list_if37": (" if %p%c", (0, 27), 1), @@ -408,12 +407,17 @@ def customize_for_version37(self, version): self.n_call = n_call def n_compare_chained(node): - if node[0] == "compare_chained37": + if node[0] in ( + "c_compare_chained37", + "c_compare_chained37_false", + "compare_chained37", + "compare_chained37_false", + ): self.default(node[0]) else: self.default(node) - self.n_compare_chained = n_compare_chained + self.n_compare_chained = self.n_c_compare_chained = n_compare_chained def n_importlist37(node): if len(node) == 1: @@ -439,3 +443,26 @@ def customize_for_version37(self, version): self.prune() self.n_list_comp_async = n_list_comp_async + + # FIXME: The following adjusts I guess a bug in the parser. + # It might be as simple as renaming grammar symbol "testtrue" to "testtrue_or_false" + # and then keeping this as is with the name change. + # Fixing in the parsing by inspection is harder than doing it here. + def n_testtrue(node): + compare_chained37 = node[0] + if ( + compare_chained37 == "compare_chained37" + and compare_chained37[1] == "compare_chained1b_37" + ): + compare_chained1b_37 = compare_chained37[1] + if ( + len(compare_chained1b_37) > 2 + and compare_chained1b_37[-2] == "JUMP_FORWARD" + ): + node.kind = "testfalse" + pass + pass + self.default(node) + return + + self.n_testtrue = n_testtrue From 62760eb556534bd703b4f351cec098437e933d40 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 18 Sep 2022 21:11:20 -0400 Subject: [PATCH 4/4] Deal with 2.x EXTENDED_ARGS on JUMP_ABSOLUTE in scanner2's "continue" detection Fixes #310 --- uncompyle6/scanners/scanner2.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index 3b4b77da..71bb0f94 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -417,7 +417,16 @@ class Scanner2(Scanner): # 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"