Correct generator function parsing for 3.3..3.5

This commit is contained in:
rocky
2023-06-30 15:43:27 -04:00
parent 828b1c989d
commit 4b296e1ead
8 changed files with 44 additions and 28 deletions

View File

@@ -1,5 +1,5 @@
#!/bin/bash
PYTHON_VERSION=3.7.16
PYTHON_VERSION=3.8.17
function checkout_version {
local repo=$1

View File

@@ -80,7 +80,6 @@ def usage():
def main_bin():
current_bytecode_supported = True
recurse_dirs = False
numproc = 0
outfile = "-"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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