From 8c374904f58fb271d267e36f8ca5ceced280b9df Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 20 Jun 2016 09:50:37 -0400 Subject: [PATCH] 3.x make closure kw args handling bug --- test/bytecode_3.4/11_mkfunc_closure.pyc | Bin 0 -> 559 bytes test/simple_source/def/11_mkfunc_closure.py | 6 ++ uncompyle6/parsers/parse3.py | 64 ++++++++++---------- uncompyle6/scanners/scanner3.py | 6 +- uncompyle6/semantics/fragments.py | 30 ++++----- uncompyle6/semantics/pysource.py | 14 +++-- 6 files changed, 66 insertions(+), 54 deletions(-) create mode 100644 test/bytecode_3.4/11_mkfunc_closure.pyc create mode 100644 test/simple_source/def/11_mkfunc_closure.py diff --git a/test/bytecode_3.4/11_mkfunc_closure.pyc b/test/bytecode_3.4/11_mkfunc_closure.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ca926ff06cdcf21561bdd476f2ba4bce04140d4 GIT binary patch literal 559 zcmZWlu};G<5IrX;EmawqkdWBP09F?!gqUC}LkFY?=@b%&h9+^alZqlX5PS>2!|0WX zg@uiYvx5o}mhSXyKfm{UAES-o>*v+^I{>^H+B5(UE(}TEdxRMyt7+&>lzkI=rl;FlC^JCJtGq!BeG_O=WRWKq z9fz59#H5I|Mtp&<3$9hd#cd;06&HJpMDwe>nYEW($z;Cd^|G1CYOk#lS=P%!9Pmcy zhU>hn3xQg;DiJ&t86S_aoM*%%ajEGy`}I-OcQ=32= 3.3: - self.add_unique_rule('listcomp ::= %sload_closure ' - 'LOAD_LISTCOMP LOAD_CONST %s expr ' - 'GET_ITER CALL_FUNCTION_1' % - ('expr ' * token.attr, opname), - opname, token.attr, customize) + if self.version >= 3.4: + rule = ('listcomp ::= %sload_closure LOAD_LISTCOMP LOAD_CONST %s expr ' + 'GET_ITER CALL_FUNCTION_1' % ('expr ' * args_pos, opname)) else: - self.add_unique_rule('listcomp ::= %sload_closure ' - 'LOAD_LISTCOMP %s expr ' - 'GET_ITER CALL_FUNCTION_1' % - ('expr ' * token.attr, opname), - opname, token.attr, customize) + rule = ('listcomp ::= %sload_closure LOAD_LISTCOMP %s expr ' + 'GET_ITER CALL_FUNCTION_1' % ('expr ' * args_pos, opname)) + self.add_unique_rule(rule, opname, token.attr, customize) - self.add_unique_rule('setcomp ::= %sload_closure LOAD_SETCOMP %s expr ' - 'GET_ITER CALL_FUNCTION_1' % - ('expr ' * token.attr, opname), - opname, token.attr, customize) self.add_unique_rule('dictcomp ::= %sload_closure LOAD_DICTCOMP %s ' 'expr GET_ITER CALL_FUNCTION_1' % - ('pos_arg '* token.attr, opname), + ('pos_arg '* args_pos, opname), opname, token.attr, customize) - rule = ('mkfunc ::= %s load_closure LOAD_CONST %s' - % ('expr ' * token.attr, opname)) - - # Python 3.5+ instead of above? - rule = ('mkfunc ::= %s load_closure LOAD_CONST LOAD_CONST %s' - % ('expr ' * token.attr, opname)) + # FIXME: kwarg processing is missing here. + # Note order of kwargs and pos args changed between 3.3-3.4 + if self.version <= 3.2: + rule = ('mkfunc ::= %sload_closure LOAD_CONST kwargs %s' + % ('expr ' * args_pos, opname)) + elif self.version >= 3.3: + rule = ('mkfunc ::= kwargs %sload_closure LOAD_CONST LOAD_CONST %s' + % ('expr ' * args_pos, opname)) self.add_unique_rule(rule, opname, token.attr, customize) - rule = ('mkfunc ::= %s load_closure load_genexpr %s' - % ('pos_arg ' * token.attr, opname)) + rule = ('mkfunc ::= %sload_closure load_genexpr %s' + % ('pos_arg ' * args_pos, opname)) self.add_unique_rule(rule, opname, token.attr, customize) - rule = ('mkfunc ::= %s load_closure LOAD_CONST %s' - % ('expr ' * token.attr, opname)) + rule = ('mkfunc ::= %sload_closure LOAD_CONST %s' + % ('expr ' * args_pos, opname)) self.add_unique_rule(rule, opname, token.attr, customize) return diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 0a5a37a7..9fa9c391 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -126,12 +126,12 @@ class Scanner3(scan.Scanner): else: pattr = const pass - elif opname == 'MAKE_FUNCTION': + elif opname in ('MAKE_FUNCTION', 'MAKE_CLOSURE'): argc = inst.argval attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF) pos_args, name_pair_args, annotate_args = attr if name_pair_args > 0: - opname = 'MAKE_FUNCTION_N%d' % name_pair_args + opname = '%s_N%d' % (opname, name_pair_args) pass if annotate_args > 0: opname = '%s_A_%d' % [opname, annotate_args] @@ -149,7 +149,7 @@ class Scanner3(scan.Scanner): ) continue elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE', - 'BUILD_MAP', 'UNPACK_SEQUENCE', 'MAKE_CLOSURE', + 'BUILD_MAP', 'UNPACK_SEQUENCE', 'RAISE_VARARGS' ): pos_args = inst.argval diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 5b23c908..ee54876c 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -468,29 +468,25 @@ class FragmentsWalker(pysource.SourceWalker, object): def n_mkfunc(self, node): start = len(self.f.getvalue()) - if self.version >= 3.0: + + if self.version >= 3.3 or node[-2] == 'kwargs': # LOAD_CONST code object .. # LOAD_CONST 'x0' if >= 3.3 # MAKE_FUNCTION .. - if self.version >= 3.4: - func_name = node[-2].attr - code_index = -3 - elif self.version == 3.3: - func_name = node[-2].pattr - code_index = -3 - else: - func_name = node[-2].attr.co_name - code_index = -2 - pass + code_index = -3 else: # LOAD_CONST code object .. # MAKE_FUNCTION .. - func_name = node[-2].attr.co_name code_index = -2 + code = node[code_index] + func_name = code.attr.co_name self.write(func_name) + self.indentMore() self.make_function(node, isLambda=False, code_index=code_index) + self.set_pos_info(node, start, len(self.f.getvalue())) + if len(self.param_stack) > 1: self.write('\n\n') else: @@ -741,8 +737,14 @@ class FragmentsWalker(pysource.SourceWalker, object): start = len(self.f.getvalue()) self.set_pos_info(buildclass[0], start, start + len('class')+2) - if buildclass[1][0] == 'kwargs': - subclass = buildclass[1][1].attr + assert 'mkfunc' == buildclass[1] + mkfunc = buildclass[1] + if mkfunc[0] == 'kwargs': + for n in mkfunc: + if hasattr(n, 'attr') and iscode(n.attr): + subclass = n.attr + break + pass subclass_info = node if node == 'classdefdeco2' else node[0] elif buildclass[1][0] == 'load_closure': # Python 3 with closures not functions diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 028168a5..5beafbcd 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -955,9 +955,9 @@ class SourceWalker(GenericASTTraversal, object): def n_mkfunc(self, node): - if self.version >= 3.3: + if self.version >= 3.3 or node[-2] == 'kwargs': # LOAD_CONST code object .. - # LOAD_CONST 'x0' + # LOAD_CONST 'x0' if >= 3.3 # MAKE_FUNCTION .. code_index = -3 else: @@ -1194,8 +1194,14 @@ class SourceWalker(GenericASTTraversal, object): currentclass = node[1][0].pattr buildclass = node[0] - if buildclass[1][0] == 'kwargs': - subclass = buildclass[1][1].attr + assert 'mkfunc' == buildclass[1] + mkfunc = buildclass[1] + if mkfunc[0] == 'kwargs': + for n in mkfunc: + if hasattr(n, 'attr') and iscode(n.attr): + subclass = n.attr + break + pass subclass_info = node if node == 'classdefdeco2' else node[0] elif buildclass[1][0] == 'load_closure': # Python 3 with closures not functions