From 8eb4d6a576ce440ff3054f446603135d9e56a0c2 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 4 Sep 2020 19:30:48 -0400 Subject: [PATCH] Fix bit rot in fragments.py build_ast() added a code argument n_dict(): was out of sync with corresponding pysource routine pysource.py: small doc typo --- uncompyle6/semantics/fragments.py | 124 ++++++++++++++++++++++-------- uncompyle6/semantics/pysource.py | 2 +- 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 9489c001..18cb7802 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1200,7 +1200,7 @@ class FragmentsWalker(pysource.SourceWalker, object): p_insts = self.p.insts self.p.insts = self.scanner.insts self.p.offset2inst_index = self.scanner.offset2inst_index - ast = parser.parse(self.p, tokens, customize) + ast = parser.parse(self.p, tokens, customize, code) self.p.insts = p_insts except (parser.ParserError, AssertionError) as e: raise ParserError(e, tokens, {}) @@ -1544,7 +1544,8 @@ class FragmentsWalker(pysource.SourceWalker, object): line_seperator = ",\n" + self.indent sep = INDENT_PER_LEVEL[:-1] start = len(self.f.getvalue()) - self.write("{") + if node[0] != "dict_entry": + self.write("{") self.set_pos_info(node[0], start, start + 1) if self.version >= 3.0 and not self.is_pypy: @@ -1570,7 +1571,7 @@ class FragmentsWalker(pysource.SourceWalker, object): i += 2 pass pass - elif node[1].kind.startswith("kvlist"): + elif len(node) > 1 and node[1].kind.startswith("kvlist"): # Python 3.0..3.4 style key/value list in dict kv_node = node[1] l = list(kv_node) @@ -1596,37 +1597,98 @@ class FragmentsWalker(pysource.SourceWalker, object): i += 3 pass pass + elif node[-1].kind.startswith("BUILD_CONST_KEY_MAP"): + # Python 3.6+ style const map + keys = node[-2].pattr + values = node[:-2] + # FIXME: Line numbers? + for key, value in zip(keys, values): + self.write(sep) + self.write(repr(key)) + line_number = self.line_number + self.write(":") + self.write(self.traverse(value[0])) + sep = ", " + if line_number != self.line_number: + sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1] + line_number = self.line_number + else: + sep += " " + pass + pass + if sep.startswith(",\n"): + self.write(sep[1:]) + pass + elif node[0].kind.startswith("dict_entry"): + assert self.version >= 3.5 + template = ("%C", (0, len(node[0]), ", **")) + self.template_engine(template, node[0]) + sep = "" + elif node[-1].kind.startswith("BUILD_MAP_UNPACK") or node[ + -1 + ].kind.startswith("dict_entry"): + assert self.version >= 3.5 + # FIXME: I think we can intermingle dict_comp's with other + # dictionary kinds of things. The most common though is + # a sequence of dict_comp's + kwargs = node[-1].attr + template = ("**%C", (0, kwargs, ", **")) + self.template_engine(template, node) + sep = "" + pass else: - # Python 2 style kvlist - assert node[-1].kind.startswith("kvlist") - kv_node = node[-1] # goto kvlist + # Python 2 style kvlist. Find beginning of kvlist. + indent = self.indent + " " + line_number = self.line_number + if node[0].kind.startswith("BUILD_MAP"): + if len(node) > 1 and node[1].kind in ("kvlist", "kvlist_n"): + kv_node = node[1] + else: + kv_node = node[1:] + self.kv_map(kv_node, sep, line_number, indent) - for kv in kv_node: - assert kv in ("kv", "kv2", "kv3") - # kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR - # kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR - # kv3 ::= expr expr STORE_MAP - if kv == "kv": - name = self.traverse(kv[-2], indent="") - kv[1].parent = kv_node - value = self.traverse( - kv[1], indent=self.indent + (len(name) + 2) * " " - ) - elif kv == "kv2": - name = self.traverse(kv[1], indent="") - kv[-3].parent = kv_node - value = self.traverse( - kv[-3], indent=self.indent + (len(name) + 2) * " " - ) - elif kv == "kv3": - name = self.traverse(kv[-2], indent="") - kv[0].parent = kv_node - value = self.traverse( - kv[0], indent=self.indent + (len(name) + 2) * " " - ) - self.write(sep, name, ": ", value) - sep = line_seperator + else: + sep = "" + opname = node[-1].kind + if self.is_pypy and self.version >= 3.5: + if opname.startswith("BUILD_CONST_KEY_MAP"): + keys = node[-2].attr + # FIXME: DRY this and the above + for i in range(len(keys)): + key = keys[i] + value = self.traverse(node[i], indent="") + self.write(sep, key, ": ", value) + sep = ", " + if line_number != self.line_number: + sep += "\n" + self.indent + " " + line_number = self.line_number + pass + pass + pass + else: + if opname.startswith("kvlist"): + list_node = node[0] + else: + list_node = node + + assert list_node[-1].kind.startswith("BUILD_MAP") + for i in range(0, len(list_node) - 1, 2): + key = self.traverse(list_node[i], indent="") + value = self.traverse(list_node[i + 1], indent="") + self.write(sep, key, ": ", value) + sep = ", " + if line_number != self.line_number: + sep += "\n" + self.indent + " " + line_number = self.line_number + pass + pass + pass + elif opname.startswith("kvlist"): + kv_node = node[-1] + self.kv_map(node[-1], sep, line_number, indent) + + pass self.write("}") finish = len(self.f.getvalue()) self.set_pos_info(node, start, finish) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index e398a990..340bbbed 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1660,7 +1660,7 @@ class SourceWalker(GenericASTTraversal, object): """ prettyprint a dict 'dict' is something like k = {'a': 1, 'b': 42}" - We will source-code use line breaks to guide us when to break. + We will use source-code line breaks to guide us when to break. """ p = self.prec self.prec = 100