From 3e1300eb23f853cef37bc92a048ae6d0fe1ad58f Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 29 Apr 2020 10:12:54 -0400 Subject: [PATCH] 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() --- uncompyle6/parsers/parse37base.py | 2 +- uncompyle6/semantics/customize37.py | 6 +++++ uncompyle6/semantics/fragments.py | 2 +- uncompyle6/semantics/pysource.py | 41 +++++++++++++++++++++-------- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index d2f45243..673d2683 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -614,7 +614,7 @@ class Python37BaseParser(PythonParser): JUMP_BACK COME_FROM POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP 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_iter ::= list_afor """, diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index 0fdd35e4..52e42fbc 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -143,6 +143,12 @@ def customize_for_version37(self, version): "importattr37": ("%c", (0, "IMPORT_NAME_ATTR")), "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_not": (" if not %p%c", (0, 27), 1), "testfalse_not_or": ("not %c or %c", (0, "expr"), (2, "expr")), diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 4ab631e3..7abdb574 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -963,7 +963,7 @@ class FragmentsWalker(pysource.SourceWalker, object): self.prune() - def n_listcomp(self, node): + def n_list_comp(self, node): self.write("[") if node[0].kind == "load_closure": self.listcomprehension_walk2(node) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 6f21dcbc..630021f5 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -80,7 +80,7 @@ Python. # # 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. # If a tuple is given, the first item is the node index while # 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, # 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 # 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 # 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 # value, an integer. # @@ -115,7 +115,13 @@ Python. # # %- 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. # @@ -1205,7 +1211,7 @@ class SourceWalker(GenericASTTraversal, object): ast = ast[0] # Pick out important parts of the comprehension: - # * the variable we interate over: "store" + # * the variable we iterate over: "store" # * the results we accumulate: "n" is_30_dict_comp = False @@ -1265,17 +1271,25 @@ class SourceWalker(GenericASTTraversal, object): # Iterate to find the innermost store # 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 if self.version == 3.0 and len(n) == 3: assert n[0] == "expr" and n[1] == "expr" 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: n = n[0] if n in ("list_for", "comp_for"): if n[2] == "store" and not store: store = n[2] + if not comp_store: + comp_store = store n = n[3] elif n in ("list_if", "list_if_not", "list_if37", "list_if37_not", @@ -2112,7 +2126,6 @@ class SourceWalker(GenericASTTraversal, object): self.prec = p arg += 1 elif typ == "{": - d = node.__dict__ expr = m.group("expr") # Line mapping stuff @@ -2123,10 +2136,16 @@ class SourceWalker(GenericASTTraversal, object): ): self.source_linemap[self.current_line_number] = node.linestart - try: - self.write(eval(expr, d, d)) - except: - raise + if expr[0] == "%": + index = entry[arg] + self.template_engine((expr, index), node) + arg += 1 + else: + d = node.__dict__ + try: + self.write(eval(expr, d, d)) + except: + raise m = escape.search(fmt, i) self.write(fmt[i:])