From dcbf8d2cf7b8ecce5f56f583a1e9005b92933ebc Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 1 May 2016 20:54:42 -0400 Subject: [PATCH] Bug in 3.5 constant map parsing --- uncompyle6/parsers/parse3.py | 6 ++++ uncompyle6/scanners/scanner35.py | 20 ++++--------- uncompyle6/semantics/pysource.py | 50 ++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 48b0b8b2..643db4d8 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -615,6 +615,12 @@ class Python3Parser(PythonParser): elif opname_base in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'): rule = 'build_list ::= ' + 'expr ' * token.attr + opname self.add_unique_rule(rule, opname, token.attr, customize) + elif self.version >= 3.5 and opname_base == 'BUILD_MAP': + kvlist_n = "kvlist_%s" % token.attr + rule = kvlist_n + ' ::= ' + 'expr ' * (token.attr*2) + self.add_unique_rule(rule, opname, token.attr, customize) + rule = "mapexpr ::= %s %s" % (kvlist_n, opname) + self.add_unique_rule(rule, opname, token.attr, customize) elif opname_base in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'): rule = 'unpack ::= ' + opname + ' designator' * token.attr self.add_unique_rule(rule, opname, token.attr, customize) diff --git a/uncompyle6/scanners/scanner35.py b/uncompyle6/scanners/scanner35.py index c05fceb3..89b373b5 100644 --- a/uncompyle6/scanners/scanner35.py +++ b/uncompyle6/scanners/scanner35.py @@ -14,7 +14,6 @@ import dis, inspect from array import array import uncompyle6.scanners.scanner3 as scan3 -from uncompyle6 import PYTHON_VERSION from uncompyle6.code import iscode from uncompyle6.scanner import Token @@ -29,13 +28,10 @@ from uncompyle6.opcodes.opcode_35 import * class Scanner35(scan3.Scanner3): - def disassemble(self, co, classname=None, code_objects={}): - fn = self.disassemble_built_in if PYTHON_VERSION == 3.4 \ - else self.disassemble_generic - return fn(co, classname, code_objects=code_objects) - - def disassemble_built_in(self, co, classname=None, - code_objects={}): + # Note: we can't use built-in disassembly routines, unless + # we do post-processing like we do here. + def disassemble(self, co, classname=None, + code_objects={}): # Container for tokens tokens = [] customize = {} @@ -116,17 +112,11 @@ class Scanner35(scan3.Scanner3): pattr = const pass elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE', + 'BUILD_MAP', 'UNPACK_SEQUENCE', 'MAKE_FUNCTION', 'MAKE_CLOSURE', 'DUP_TOPX', 'RAISE_VARARGS' ): - # if opname == 'BUILD_TUPLE' and \ - # self.code[self.prev[offset]] == LOAD_CLOSURE: - # continue - # else: - # op_name = '%s_%d' % (op_name, oparg) - # if opname != BUILD_SLICE: - # customize[op_name] = oparg opname = '%s_%d' % (opname, inst.argval) if inst.opname != 'BUILD_SLICE': customize[opname] = inst.argval diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 03b67e27..52c23497 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -81,7 +81,6 @@ if PYTHON3: minint = -sys.maxsize-1 maxint = sys.maxsize else: - from itertools import izip_longest as zip_longest from StringIO import StringIO minint = -sys.maxint-1 maxint = sys.maxint @@ -1148,29 +1147,42 @@ class SourceWalker(GenericASTTraversal, object): """ p = self.prec self.prec = 100 - assert node[-1] == 'kvlist' - node = node[-1] # goto kvlist self.indentMore(INDENT_PER_LEVEL) line_seperator = ',\n' + self.indent sep = INDENT_PER_LEVEL[:-1] self.write('{') - for kv in 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='') - value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ') - elif kv == 'kv2': - name = self.traverse(kv[1], indent='') - value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ') - elif kv == 'kv3': - name = self.traverse(kv[-2], indent='') - value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ') - self.write(sep, name, ': ', value) - sep = line_seperator + + if node[0].type.startswith('kvlist'): + # Python 3.5 style key/value list in mapexpr + l = list(node[0]) + i = 0 + while i < len(l): + name = self.traverse(l[i], indent='') + value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ') + self.write(sep, name, ': ', value) + sep = line_seperator + i += 2 + else: + assert node[-1] == 'kvlist' + node = node[-1] # goto kvlist + + for kv in 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='') + value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ') + elif kv == 'kv2': + name = self.traverse(kv[1], indent='') + value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ') + elif kv == 'kv3': + name = self.traverse(kv[-2], indent='') + value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ') + self.write(sep, name, ': ', value) + sep = line_seperator self.write('}') self.indentLess(INDENT_PER_LEVEL) self.prec = p