You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
3.x make closure kw args handling bug
This commit is contained in:
BIN
test/bytecode_3.4/11_mkfunc_closure.pyc
Normal file
BIN
test/bytecode_3.4/11_mkfunc_closure.pyc
Normal file
Binary file not shown.
6
test/simple_source/def/11_mkfunc_closure.py
Normal file
6
test/simple_source/def/11_mkfunc_closure.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# From python 3.4 window_events.py
|
||||
# Problem was in handling MAKE_CLOSURE or
|
||||
# getting the '*' parameter correct.
|
||||
class _OverlappedFuture(futures.Future):
|
||||
def __init__(self, ov, *, loop=None):
|
||||
super().__init__(loop=loop)
|
@@ -378,9 +378,9 @@ class Python3Parser(PythonParser):
|
||||
elif tokens[i].type.startswith('MAKE_CLOSURE'):
|
||||
break
|
||||
pass
|
||||
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION"
|
||||
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION or MAKE_CLOSURE"
|
||||
assert tokens[i+1].type == 'LOAD_CONST', \
|
||||
"build_class expecting CONST after MAKE_FUNCTION"
|
||||
"build_class expecting CONST after MAKE_FUNCTION/MAKE_CLOSURE"
|
||||
for i in range(i, len(tokens)):
|
||||
if tokens[i].type == 'CALL_FUNCTION':
|
||||
call_fn_tok = tokens[i]
|
||||
@@ -434,6 +434,7 @@ class Python3Parser(PythonParser):
|
||||
mkfunc ::= {pos_arg}^n LOAD_CONST MAKE_FUNCTION_n
|
||||
mklambda ::= {pos_arg}^n LOAD_LAMBDA MAKE_FUNCTION_n
|
||||
mkfunc ::= {pos_arg}^n load_closure LOAD_CONST MAKE_FUNCTION_n
|
||||
mkfunc ::= {pos_arg}^n load_closure LOAD_CONST MAKE_CLOSURE_n
|
||||
genexpr ::= {pos_arg}^n LOAD_GENEXPR MAKE_FUNCTION_n
|
||||
|
||||
listcomp ::= load_closure expr GET_ITER CALL_FUNCTION_1
|
||||
@@ -526,12 +527,13 @@ class Python3Parser(PythonParser):
|
||||
elif opname_base == 'UNPACK_LIST':
|
||||
rule = 'unpack_list ::= ' + opname + ' designator' * token.attr
|
||||
elif opname_base.startswith('MAKE_FUNCTION'):
|
||||
# DRY with MAKE_CLOSURE
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_CONST %s' %
|
||||
('pos_arg '* args_pos, opname))
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
if self.version == 3.3:
|
||||
# positional args cafter keyword args
|
||||
# positional args after keyword args
|
||||
rule = ('mkfunc ::= kwargs %s%s %s' %
|
||||
('pos_arg ' * args_pos,
|
||||
'LOAD_CONST ' * 2,
|
||||
@@ -547,49 +549,45 @@ class Python3Parser(PythonParser):
|
||||
('pos_arg ' * args_pos, opname))
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
elif opname.startswith('MAKE_CLOSURE'):
|
||||
self.add_unique_rule('mklambda ::= %sload_closure LOAD_LAMBDA LOAD_CONST %s' %
|
||||
('pos_arg ' * token.attr, opname), opname, token.attr,
|
||||
customize)
|
||||
# DRY with MAKE_FUNCTION
|
||||
# Note: this probably doesn't handle kwargs proprerly
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
rule = ('mklambda ::= %sload_closure LOAD_LAMBDA LOAD_CONST %s' %
|
||||
('pos_arg '* args_pos, opname))
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
self.add_unique_rule('genexpr ::= %sload_closure '
|
||||
'load_genexpr %s '
|
||||
'expr GET_ITER CALL_FUNCTION_1' %
|
||||
('pos_arg ' * token.attr, opname),
|
||||
('pos_arg ' * args_pos, opname),
|
||||
opname, token.attr, customize)
|
||||
if self.version >= 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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user