diff --git a/test/bytecode_3.5_run/07_build_map_unpack.pyc b/test/bytecode_3.5_run/07_build_map_unpack.pyc new file mode 100644 index 00000000..b16a0cc0 Binary files /dev/null and b/test/bytecode_3.5_run/07_build_map_unpack.pyc differ diff --git a/test/simple_source/bug35/07_build_map_unpack.py b/test/simple_source/bug35/07_build_map_unpack.py new file mode 100644 index 00000000..60733f83 --- /dev/null +++ b/test/simple_source/bug35/07_build_map_unpack.py @@ -0,0 +1,10 @@ +# Adapted from Python 3.6 trace.py +# Bug was in handling BUID_TUPLE_UNPACK created via +# *opts.arguments +import argparse +parser = argparse.ArgumentParser() +parser.add_argument('filename', nargs='?') +parser.add_argument('arguments', nargs=argparse.REMAINDER) +opts = parser.parse_args(["foo", "a", "b"]) +argv = opts.filename, *opts.arguments +assert argv == ('foo', 'a', 'b') diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 8577b394..c9d4414c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -626,7 +626,7 @@ class Python3Parser(PythonParser): self.addRule(rule, nop_func) rule = 'expr ::= build_list_unpack' self.addRule(rule, nop_func) - elif opname_base == 'BUILD_MAP': + elif opname_base in ('BUILD_MAP', 'BUILD_MAP_UNPACK'): kvlist_n = "kvlist_%s" % token.attr if opname == 'BUILD_MAP_n': # PyPy sometimes has no count. Sigh. @@ -645,23 +645,21 @@ class Python3Parser(PythonParser): # FIXME: Use the attr # so this doesn't run into exponential parsing time. if opname.startswith('BUILD_MAP_UNPACK'): - # FIXME: start here - # rule = "%s ::= %s %s" % (kvlist_n, 'expr ' * (token.attr*2), opname) - rule = kvlist_n + ' ::= ' + 'expr ' * (token.attr*2) self.add_unique_rule(rule, opname, token.attr, customize) rule = 'dict_entry ::= ' + 'expr ' * (token.attr*2) self.add_unique_rule(rule, opname, token.attr, customize) - rule = 'dict ::= %s' % ('dict_entry ' * token.attr) - self.addRule(rule, nop_func) + # FIXME: start here. The LHS should be unmap_dict, not dict. # FIXME: really we need a combination of dict_entry-like things. # It just so happens the most common case is not to mix # dictionary comphensions with dictionary, elements if self.seen_LOAD_DICTCOMP: rule = 'dict ::= %s%s' % ('dict_comp ' * token.attr, opname) self.addRule(rule, nop_func) - - rule = 'unmap_dict ::= %s%s' % (('dict ' * token.attr), opname) + rule = """ + expr ::= unmap_dict + unmap_dict ::= %s%s + """ % ('expr ' * token.attr, opname) else: rule = "%s ::= %s %s" % (kvlist_n, 'expr ' * (token.attr*2), opname) self.add_unique_rule(rule, opname, token.attr, customize) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index df925890..ecfbe7ed 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -144,7 +144,7 @@ class Scanner3(Scanner): varargs_ops.add(self.opc.CALL_METHOD) if self.version >= 3.5: varargs_ops |= set([self.opc.BUILD_SET_UNPACK, - # self.opc.BUILD_MAP_UNPACK, # we will handle this later + self.opc.BUILD_MAP_UNPACK, # we will handle this later self.opc.BUILD_LIST_UNPACK, self.opc.BUILD_TUPLE_UNPACK]) if self.version >= 3.6: diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index f6389fb1..029c34eb 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -351,6 +351,7 @@ def customize_for_version3(self, version): PRECEDENCE['call_ex_kw2'] = 100 PRECEDENCE['call_ex_kw3'] = 100 PRECEDENCE['call_ex_kw4'] = 100 + PRECEDENCE['unmap_dict'] = 0 TABLE_DIRECT.update({ 'tryfinally36': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',