Simplify make_function3 by customization

We now have different routines for 3.6+
(and 2.x from before).

This is desirable before fixing 3.0..3.5 lambdas with default
paramerts and * args.
This commit is contained in:
rocky
2019-12-27 12:58:00 -05:00
parent db2fdb30fd
commit 62c249d6b2
2 changed files with 38 additions and 195 deletions

Binary file not shown.

View File

@@ -341,10 +341,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
- handle defaults
- handle format tuple parameters
"""
if self.version >= 3.6:
value = default
else:
value = self.traverse(default, indent="")
value = self.traverse(default, indent="")
maybe_show_tree_param_default(self.showast, name, value)
if annotation:
result = "%s: %s=%s" % (name, annotation, value)
@@ -380,9 +377,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
# not to be confused with keyword parameters which may appear after *.
args_attr = args_node.attr
if isinstance(args_attr, tuple) or (
self.version >= 3.6 and isinstance(args_attr, list)
):
if isinstance(args_attr, tuple):
if len(args_attr) == 3:
pos_args, kw_args, annotate_argc = args_attr
else:
@@ -428,9 +423,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
lc_index = -3
pass
if (
self.version <= 3.5
and len(node) > 2
if (len(node) > 2
and (have_kwargs or node[lc_index].kind != "load_closure")
):
@@ -458,85 +451,11 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
default_values_start : default_values_start + args_node.attr[0]
]
else:
if self.version < 3.6:
defparams = node[: args_node.attr[0]]
kw_args = 0
else:
defparams = []
# FIXME: DRY with code below
default, kw_args, annotate_argc = args_node.attr[0:3]
if default:
expr_node = node[0]
if node[0] == "pos_arg":
expr_node = expr_node[0]
assert (
expr_node == "expr"
), "expecting mkfunc default node to be an expr"
if expr_node[0] == "LOAD_CONST" and isinstance(
expr_node[0].attr, tuple
):
defparams = [repr(a) for a in expr_node[0].attr]
elif expr_node[0] in frozenset(("list", "tuple", "dict", "set")):
defparams = [
self.traverse(n, indent="") for n in expr_node[0][:-1]
]
else:
defparams = []
pass
else:
if self.version < 3.6:
defparams = node[: args_node.attr]
defparams = node[: args_node.attr[0]]
kw_args = 0
else:
default, kw_args, annotate, closure = args_node.attr
if default:
expr_node = node[0]
if node[0] == "pos_arg":
expr_node = expr_node[0]
assert (
expr_node == "expr"
), "expecting mkfunc default node to be an expr"
if expr_node[0] == "LOAD_CONST" and isinstance(
expr_node[0].attr, tuple
):
defparams = [repr(a) for a in expr_node[0].attr]
elif expr_node[0] in frozenset(("list", "tuple", "dict", "set")):
defparams = [self.traverse(n, indent="") for n in expr_node[0][:-1]]
else:
defparams = []
i = -4
kw_pairs = 0
if closure:
# FIXME: fill in
annotate = node[i]
i -= 1
if annotate_argc:
# Turn into subroutine and DRY with other use
annotate_node = node[i]
if annotate_node == "expr":
annotate_node = annotate_node[0]
annotate_name_node = annotate_node[-1]
if annotate_node == "dict" and annotate_name_node.kind.startswith(
"BUILD_CONST_KEY_MAP"
):
types = [
self.traverse(n, indent="") for n in annotate_node[:-2]
]
names = annotate_node[-2].attr
l = len(types)
assert l == len(names)
for i in range(l):
annotate_dict[names[i]] = types[i]
pass
pass
i -= 1
if kw_args:
kw_node = node[i]
if kw_node == "expr":
kw_node = kw_node[0]
if kw_node == "dict":
kw_pairs = kw_node[-1].attr
else:
defparams = node[: args_node.attr]
kw_args = 0
pass
if lambda_index and is_lambda and iscode(node[lambda_index].attr):
@@ -554,7 +473,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
paramnames = list(scanner_code.co_varnames[:argc])
if kwonlyargcount > 0:
if self.version <= 3.5 and is_lambda:
if is_lambda:
kwargs = []
for i in range(kwonlyargcount):
paramnames.append(scanner_code.co_varnames[argc+i])
@@ -580,11 +499,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
self.ERROR = p
return
if self.version >= 3.0:
if self.version < 3.6:
kw_pairs = args_node.attr[1]
else:
kw_pairs = 0
kw_pairs = 0
i = len(paramnames) - len(defparams)
@@ -613,18 +528,15 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
params.reverse() # back to correct order
if code_has_star_arg(code):
if self.version > 3.0:
star_arg = code.co_varnames[argc + kwonlyargcount]
if annotate_dict and star_arg in annotate_dict:
params.append("*%s: %s" % (star_arg, annotate_dict[star_arg]))
else:
params.append("*%s" % star_arg)
pass
if is_lambda and self.version <= 3.5:
params.reverse()
star_arg = code.co_varnames[argc + kwonlyargcount]
if annotate_dict and star_arg in annotate_dict:
params.append("*%s: %s" % (star_arg, annotate_dict[star_arg]))
else:
params.append("*%s" % code.co_varnames[argc])
if not is_lambda or self.version >= 3.6:
params.append("*%s" % star_arg)
pass
if is_lambda:
params.reverse()
if not is_lambda:
argc += 1
# dump parameter list (with default values)
@@ -670,106 +582,37 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
self.write(", ")
ends_in_comma = True
if 3.0 <= self.version <= 3.5:
kw_args = [None] * kwonlyargcount
kw_nodes = node[0]
if kw_nodes == "kwargs":
for n in kw_nodes:
name = eval(n[0].pattr)
default = self.traverse(n[1], indent="")
idx = kwargs.index(name)
kw_args[idx] = "%s=%s" % (name, default)
pass
kw_args = [None] * kwonlyargcount
kw_nodes = node[0]
if kw_nodes == "kwargs":
for n in kw_nodes:
name = eval(n[0].pattr)
default = self.traverse(n[1], indent="")
idx = kwargs.index(name)
kw_args[idx] = "%s=%s" % (name, default)
pass
pass
# FIXME: something weird is going on and the below
# might not be right. On 3.4 kw_nodes != "kwarg"
# because of some sort of type mismatch. I think
# the test is for versions earlier than 3.3
# on 3.5 if we have "kwarg" we still want to do this.
# Perhaps we should be testing that kw_nodes is iterable?
if kw_nodes != "kwarg" or self.version == 3.5:
other_kw = [c == None for c in kw_args]
for i, flag in enumerate(other_kw):
if flag:
if i < len(kwargs):
kw_args[i] = "%s" % kwargs[i]
else:
del kw_args[i]
pass
self.write(", ".join(kw_args))
ends_in_comma = False
pass
elif self.version >= 3.6:
# argc = node[-1].attr
# co = node[-3].attr
# argcount = co.co_argcount
# kwonlyargcount = co.co_kwonlyargcount
free_tup = ann_dict = kw_dict = default_tup = None
fn_bits = node[-1].attr
# Skip over:
# MAKE_FUNCTION,
# optional docstring
# LOAD_CONST qualified name,
# LOAD_CONST code object
index = -4 # Skip over:
if node[-2] == "docstring":
index = -5
else:
index = -4
if fn_bits[-1]:
free_tup = node[index]
index -= 1
if fn_bits[-2]:
ann_dict = node[index]
index -= 1
if fn_bits[-3]:
kw_dict = node[index]
index -= 1
if fn_bits[-4]:
default_tup = node[index]
if kw_dict == "expr":
kw_dict = kw_dict[0]
# FIXME: handle free_tup, annotate_dict, and default_tup
kw_args = [None] * kwonlyargcount
if kw_dict:
assert kw_dict == "dict"
defaults = [self.traverse(n, indent="") for n in kw_dict[:-2]]
names = eval(self.traverse(kw_dict[-2]))
assert len(defaults) == len(names)
sep = ""
# FIXME: possibly handle line breaks
for i, n in enumerate(names):
idx = kwargs.index(n)
if annotate_dict and n in annotate_dict:
t = "%s: %s=%s" % (n, annotate_dict[n], defaults[i])
else:
t = "%s=%s" % (n, defaults[i])
kw_args[idx] = t
pass
pass
# handle others
# FIXME: something weird is going on and the below
# might not be right. On 3.4 kw_nodes != "kwarg"
# because of some sort of type mismatch. I think
# the test is for versions earlier than 3.3
# on 3.5 if we have "kwarg" we still want to do this.
# Perhaps we should be testing that kw_nodes is iterable?
if kw_nodes != "kwarg" or self.version == 3.5:
other_kw = [c == None for c in kw_args]
for i, flag in enumerate(other_kw):
if flag:
n = kwargs[i]
if ann_dict and n in annotate_dict:
kw_args[i] = "%s: %s" % (n, annotate_dict[n])
if i < len(kwargs):
kw_args[i] = "%s" % kwargs[i]
else:
kw_args[i] = "%s" % n
del kw_args[i]
pass
self.write(", ".join(kw_args))
ends_in_comma = False
pass
pass
else: