Bugs in nested async for...

* Generalize asyc_for rule
 Fix bug in picking out comprehension iterator in async for
* fix bug in getting expression in such a comprehension
* Add %[n]{%x} pattern to template_engine()
This commit is contained in:
rocky
2020-04-29 10:12:54 -04:00
parent a4eaeea5b2
commit 3e1300eb23
4 changed files with 38 additions and 13 deletions

View File

@@ -614,7 +614,7 @@ class Python37BaseParser(PythonParser):
JUMP_BACK COME_FROM JUMP_BACK COME_FROM
POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP
list_comp_async ::= BUILD_LIST_0 LOAD_FAST list_afor2 list_comp_async ::= BUILD_LIST_0 LOAD_FAST list_afor2
get_aiter ::= LOAD_DEREF GET_AITER get_aiter ::= expr GET_AITER
list_afor ::= get_aiter list_afor2 list_afor ::= get_aiter list_afor2
list_iter ::= list_afor list_iter ::= list_afor
""", """,

View File

@@ -143,6 +143,12 @@ def customize_for_version37(self, version):
"importattr37": ("%c", (0, "IMPORT_NAME_ATTR")), "importattr37": ("%c", (0, "IMPORT_NAME_ATTR")),
"importlist37": ("%C", (0, maxint, ", ")), "importlist37": ("%C", (0, maxint, ", ")),
"list_afor": (
" async for %[1]{%c} in %c%[1]{%c}",
(1, "store"), (0, "get_aiter"), (3, "list_iter"),
),
"list_if37": (" if %p%c", (0, 27), 1), "list_if37": (" if %p%c", (0, 27), 1),
"list_if37_not": (" if not %p%c", (0, 27), 1), "list_if37_not": (" if not %p%c", (0, 27), 1),
"testfalse_not_or": ("not %c or %c", (0, "expr"), (2, "expr")), "testfalse_not_or": ("not %c or %c", (0, "expr"), (2, "expr")),

View File

@@ -963,7 +963,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
self.prune() self.prune()
def n_listcomp(self, node): def n_list_comp(self, node):
self.write("[") self.write("[")
if node[0].kind == "load_closure": if node[0].kind == "load_closure":
self.listcomprehension_walk2(node) self.listcomprehension_walk2(node)

View File

@@ -80,7 +80,7 @@ Python.
# #
# Escapes in the format string are: # Escapes in the format string are:
# #
# %c evaluate the node recursively. Its argument is a single # %c evaluate/traverse the node recursively. Its argument is a single
# integer or tuple representing a node index. # integer or tuple representing a node index.
# If a tuple is given, the first item is the node index while # If a tuple is given, the first item is the node index while
# the second item is a string giving the node/noterminal name. # the second item is a string giving the node/noterminal name.
@@ -91,7 +91,7 @@ Python.
# index and the precedence value, an integer. If 3 items are given, # index and the precedence value, an integer. If 3 items are given,
# the second item is the nonterminal name and the precedence is given last. # the second item is the nonterminal name and the precedence is given last.
# #
# %C evaluate children recursively, with sibling children separated by the # %C evaluate/travers children recursively, with sibling children separated by the
# given string. It needs a 3-tuple: a starting node, the maximimum # given string. It needs a 3-tuple: a starting node, the maximimum
# value of an end node, and a string to be inserted between sibling children # value of an end node, and a string to be inserted between sibling children
# #
@@ -99,7 +99,7 @@ Python.
# on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints # on the LHS of an assignment statement since BUILD_TUPLE_n pretty-prints
# other tuples. The specifier takes no arguments # other tuples. The specifier takes no arguments
# #
# %P same as %C but sets operator precedence. Its argument is a 4-tuple: # %P same as %C but sets operator precedence. Its argument is a 4-tuple:
# the node low and high indices, the separator, a string the precidence # the node low and high indices, the separator, a string the precidence
# value, an integer. # value, an integer.
# #
@@ -115,7 +115,13 @@ Python.
# #
# %- decrease current indentation level. Takes no arguments. # %- decrease current indentation level. Takes no arguments.
# #
# %{...} evaluate ... in context of N # %{EXPR} Python eval(EXPR) in context of node. Takes no arguments
#
# %[N]{EXPR} Python eval(EXPR) in context of node[N]. Takes no arguments
#
# %[N]{%X} evaluate/recurse on child node[N], using specifier %X.
# %X can be one of the above, e.g. %c, %p, etc. Takes the arguemnts
# that the specifier uses.
# #
# %% literal '%'. Takes no arguments. # %% literal '%'. Takes no arguments.
# #
@@ -1205,7 +1211,7 @@ class SourceWalker(GenericASTTraversal, object):
ast = ast[0] ast = ast[0]
# Pick out important parts of the comprehension: # Pick out important parts of the comprehension:
# * the variable we interate over: "store" # * the variable we iterate over: "store"
# * the results we accumulate: "n" # * the results we accumulate: "n"
is_30_dict_comp = False is_30_dict_comp = False
@@ -1265,17 +1271,25 @@ class SourceWalker(GenericASTTraversal, object):
# Iterate to find the innermost store # Iterate to find the innermost store
# We'll come back to the list iteration below. # We'll come back to the list iteration below.
while n in ("list_iter", "comp_iter"): while n in ("list_iter", "list_afor", "list_afor2", "comp_iter"):
# iterate one nesting deeper # iterate one nesting deeper
if self.version == 3.0 and len(n) == 3: if self.version == 3.0 and len(n) == 3:
assert n[0] == "expr" and n[1] == "expr" assert n[0] == "expr" and n[1] == "expr"
n = n[1] n = n[1]
elif n == "list_afor":
n = n[1]
elif n == "list_afor2":
if n[1] == "store":
store = n[1]
n = n[3]
else: else:
n = n[0] n = n[0]
if n in ("list_for", "comp_for"): if n in ("list_for", "comp_for"):
if n[2] == "store" and not store: if n[2] == "store" and not store:
store = n[2] store = n[2]
if not comp_store:
comp_store = store
n = n[3] n = n[3]
elif n in ("list_if", "list_if_not", elif n in ("list_if", "list_if_not",
"list_if37", "list_if37_not", "list_if37", "list_if37_not",
@@ -2112,7 +2126,6 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = p self.prec = p
arg += 1 arg += 1
elif typ == "{": elif typ == "{":
d = node.__dict__
expr = m.group("expr") expr = m.group("expr")
# Line mapping stuff # Line mapping stuff
@@ -2123,10 +2136,16 @@ class SourceWalker(GenericASTTraversal, object):
): ):
self.source_linemap[self.current_line_number] = node.linestart self.source_linemap[self.current_line_number] = node.linestart
try: if expr[0] == "%":
self.write(eval(expr, d, d)) index = entry[arg]
except: self.template_engine((expr, index), node)
raise arg += 1
else:
d = node.__dict__
try:
self.write(eval(expr, d, d))
except:
raise
m = escape.search(fmt, i) m = escape.search(fmt, i)
self.write(fmt[i:]) self.write(fmt[i:])