Python 3.5 *args with kwargs handling.

3.5 is a snowflake here. Thank you, Python.

Fully fixes Issue 95.

3.6 is broken on this source, but for a *different* reason. Sigh.
This commit is contained in:
rocky
2017-06-04 17:53:51 -04:00
parent 844221cd43
commit eb92418224
2 changed files with 27 additions and 3 deletions

View File

@@ -496,8 +496,8 @@ class Python3Parser(PythonParser):
token.type = self.call_fn_name(token) token.type = self.call_fn_name(token)
uniq_param = args_kw + args_pos uniq_param = args_kw + args_pos
if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR'): if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR'):
# Python 3.5 changes the stack position of where * args, the # Python 3.5 changes the stack position of *args. KW args come
# first LOAD_FAST, below are located. # after *args.
# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX # Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX
if opname.endswith('KW'): if opname.endswith('KW'):
kw = 'expr ' kw = 'expr '

View File

@@ -358,9 +358,33 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = p self.prec = p
self.prune() self.prune()
self.n_async_call_function = n_async_call_function self.n_async_call_function = n_async_call_function
self.n_build_list_unpack = self.n_build_list self.n_build_list_unpack = self.n_build_list
if version == 3.5:
def n_call_function(node):
mapping = self._get_mapping(node)
table = mapping[0]
key = node
for i in mapping[1:]:
key = key[i]
pass
if key.type.startswith('CALL_FUNCTION_VAR_KW'):
# Python 3.5 changes the stack position of *args. kwargs come
# after *args whereas in earlier Pythons, *args is at the end
# which simpilfiies things from our perspective.
# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX
# We will just swap the order to make it look like earlier Python 3.
entry = table[key.type]
kwarg_pos = entry[2][1]
args_pos = kwarg_pos - 1
# Put last node[args_pos] after subsequent kwargs
while node[kwarg_pos] == 'kwarg' and kwarg_pos < len(node):
# swap node[args_pos] with node[kwargs_pos]
node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
args_pos = kwarg_pos
kwarg_pos += 1
self.default(node)
self.n_call_function = n_call_function
def n_funcdef(node): def n_funcdef(node):
if self.version == 3.6: if self.version == 3.6: