You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Correct generator function parsing for 3.3..3.5
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PYTHON_VERSION=3.7.16
|
||||
PYTHON_VERSION=3.8.17
|
||||
|
||||
function checkout_version {
|
||||
local repo=$1
|
||||
|
@@ -80,7 +80,6 @@ def usage():
|
||||
|
||||
|
||||
def main_bin():
|
||||
current_bytecode_supported = True
|
||||
recurse_dirs = False
|
||||
numproc = 0
|
||||
outfile = "-"
|
||||
|
@@ -15,12 +15,12 @@ class Python33Parser(Python32Parser):
|
||||
# Python 3.3+ adds yield from.
|
||||
expr ::= yield_from
|
||||
yield_from ::= expr expr YIELD_FROM
|
||||
stmt ::= genexpr_func
|
||||
"""
|
||||
|
||||
def customize_grammar_rules(self, tokens, customize):
|
||||
self.remove_rules("""
|
||||
# 3.3+ adds POP_BLOCKS
|
||||
genexpr_func ::= LOAD_ARG FOR_ITER store comp_iter JUMP_BACK
|
||||
whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK NOP COME_FROM_LOOP
|
||||
whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK NOP COME_FROM_LOOP
|
||||
""")
|
||||
|
@@ -52,6 +52,8 @@ class Python34Parser(Python33Parser):
|
||||
yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM
|
||||
|
||||
_ifstmts_jump ::= c_stmts_opt JUMP_ABSOLUTE JUMP_FORWARD COME_FROM
|
||||
|
||||
genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK
|
||||
"""
|
||||
|
||||
def customize_grammar_rules(self, tokens, customize):
|
||||
|
@@ -191,9 +191,6 @@ class Python36Parser(Python35Parser):
|
||||
COME_FROM_FINALLY
|
||||
|
||||
compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
|
||||
|
||||
stmt ::= genexpr_func
|
||||
genexpr_func ::= LOAD_ARG _come_froms FOR_ITER store comp_iter JUMP_BACK
|
||||
"""
|
||||
|
||||
# Some of this is duplicated from parse37. Eventually we'll probably rebase from
|
||||
|
@@ -39,6 +39,7 @@ from typing import Optional, Tuple
|
||||
|
||||
from xdis import iscode, instruction_size, Instruction
|
||||
from xdis.bytecode import _get_const_info
|
||||
from xdis.codetype import UnicodeForPython3
|
||||
|
||||
from uncompyle6.scanners.tok import Token
|
||||
from uncompyle6.scanner import parse_fn_counts_30_35
|
||||
@@ -572,16 +573,19 @@ class Scanner3(Scanner):
|
||||
if op in self.opc.CONST_OPS:
|
||||
const = argval
|
||||
if iscode(const):
|
||||
if const.co_name == "<lambda>":
|
||||
co_name = const.co_name
|
||||
if isinstance(const.co_name, UnicodeForPython3):
|
||||
co_name = const.co_name.value.decode("utf-8")
|
||||
if co_name == "<lambda>":
|
||||
assert opname == "LOAD_CONST"
|
||||
opname = "LOAD_LAMBDA"
|
||||
elif const.co_name == "<genexpr>":
|
||||
elif co_name == "<genexpr>":
|
||||
opname = "LOAD_GENEXPR"
|
||||
elif const.co_name == "<dictcomp>":
|
||||
elif co_name == "<dictcomp>":
|
||||
opname = "LOAD_DICTCOMP"
|
||||
elif const.co_name == "<setcomp>":
|
||||
elif co_name == "<setcomp>":
|
||||
opname = "LOAD_SETCOMP"
|
||||
elif const.co_name == "<listcomp>":
|
||||
elif co_name == "<listcomp>":
|
||||
opname = "LOAD_LISTCOMP"
|
||||
else:
|
||||
opname = "LOAD_CODE"
|
||||
@@ -589,8 +593,8 @@ class Scanner3(Scanner):
|
||||
# now holds Code(const) and thus can not be used
|
||||
# for comparison (todo: think about changing this)
|
||||
# pattr = 'code_object @ 0x%x %s->%s' %\
|
||||
# (id(const), const.co_filename, const.co_name)
|
||||
pattr = "<code_object " + const.co_name + ">"
|
||||
# (id(const), const.co_filename, co_name)
|
||||
pattr = "<code_object " + co_name + ">"
|
||||
elif isinstance(const, str):
|
||||
opname = "LOAD_STR"
|
||||
else:
|
||||
|
@@ -174,9 +174,11 @@ class ComprehensionMixin:
|
||||
tree = tree[1]
|
||||
pass
|
||||
|
||||
if tree in ("genexpr_func_async",):
|
||||
if tree[3] == "comp_iter":
|
||||
iter_index = 3
|
||||
if tree in ("genexpr_func", "genexpr_func_async",):
|
||||
for i in range(3, 5):
|
||||
if tree[i] == "comp_iter":
|
||||
iter_index = i
|
||||
break
|
||||
|
||||
n = tree[iter_index]
|
||||
|
||||
|
@@ -146,7 +146,6 @@ class NonterminalActions:
|
||||
self.prune() # stop recursing
|
||||
|
||||
def n_classdef(self, node):
|
||||
|
||||
if self.version >= (3, 6):
|
||||
self.n_classdef36(node)
|
||||
elif self.version >= (3, 0):
|
||||
@@ -228,8 +227,10 @@ class NonterminalActions:
|
||||
else:
|
||||
# from trepan.api import debug; debug()
|
||||
raise TypeError(
|
||||
("Internal Error: n_const_list expects dict, list set, or set; got "
|
||||
f"{lastnodetype}")
|
||||
(
|
||||
"Internal Error: n_const_list expects dict, list set, or set; got "
|
||||
f"{lastnodetype}"
|
||||
)
|
||||
)
|
||||
|
||||
self.indent_more(INDENT_PER_LEVEL)
|
||||
@@ -521,7 +522,6 @@ class NonterminalActions:
|
||||
self.prune()
|
||||
|
||||
def n_docstring(self, node):
|
||||
|
||||
indent = self.indent
|
||||
doc_node = node[0]
|
||||
if doc_node.attr:
|
||||
@@ -543,7 +543,7 @@ class NonterminalActions:
|
||||
self.write(indent)
|
||||
docstring = repr(docstring.expandtabs())[1:-1]
|
||||
|
||||
for (orig, replace) in (
|
||||
for orig, replace in (
|
||||
("\\\\", "\t"),
|
||||
("\\r\\n", "\n"),
|
||||
("\\n", "\n"),
|
||||
@@ -701,8 +701,11 @@ class NonterminalActions:
|
||||
self.write("(")
|
||||
iter_index = 3
|
||||
if self.version > (3, 2):
|
||||
if self.version >= (3, 6):
|
||||
if node[0].kind in ("load_closure", "load_genexpr") and self.version >= (3, 8):
|
||||
if self.version >= (3, 4):
|
||||
if node[0].kind in (
|
||||
"load_closure",
|
||||
"load_genexpr",
|
||||
) and self.version >= (3, 8):
|
||||
code_index = -6
|
||||
is_lambda = self.is_lambda
|
||||
if node[0].kind == "load_genexpr":
|
||||
@@ -710,13 +713,20 @@ class NonterminalActions:
|
||||
self.closure_walk(node, collection_index=4)
|
||||
self.is_lambda = is_lambda
|
||||
else:
|
||||
# Python 3.7+ adds optional "come_froms" at node[0] so count from the end
|
||||
# Python 3.7+ adds optional "come_froms" at node[0] so count from
|
||||
# the end.
|
||||
if node == "generator_exp_async" and self.version[:2] == (3, 6):
|
||||
code_index = 0
|
||||
else:
|
||||
code_index = -6
|
||||
iter_index = 4 if self.version < (3, 8) else 3
|
||||
self.comprehension_walk(node, iter_index=iter_index, code_index=code_index)
|
||||
iter_index = (
|
||||
4
|
||||
if self.version < (3, 8) and not isinstance(node[4], Token)
|
||||
else 3
|
||||
)
|
||||
self.comprehension_walk(
|
||||
node, iter_index=iter_index, code_index=code_index
|
||||
)
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
@@ -1028,7 +1038,6 @@ class NonterminalActions:
|
||||
self.prune()
|
||||
|
||||
def n_mkfunc(self, node):
|
||||
|
||||
code_node = find_code_node(node, -2)
|
||||
code = code_node.attr
|
||||
self.write(code.co_name)
|
||||
@@ -1076,7 +1085,10 @@ class NonterminalActions:
|
||||
else:
|
||||
# We can't comment out like above because there may be a trailing ')'
|
||||
# that needs to be written
|
||||
assert len(node) == 3 and node[2] in ("RETURN_VALUE_LAMBDA", "LAMBDA_MARKER")
|
||||
assert len(node) == 3 and node[2] in (
|
||||
"RETURN_VALUE_LAMBDA",
|
||||
"LAMBDA_MARKER",
|
||||
)
|
||||
self.preorder(node[0])
|
||||
self.prune()
|
||||
|
||||
|
Reference in New Issue
Block a user