Refactor function argument compilation

This commit is contained in:
Ryan Gonzalez 2019-09-23 12:28:39 -05:00
parent 6eedb19a07
commit fd8514718b

View File

@ -1440,27 +1440,32 @@ class HyASTCompiler(object):
maybe(sym("&kwargs") + NASYM)), maybe(sym("&kwargs") + NASYM)),
many(FORM)]) many(FORM)])
def compile_function_def(self, expr, root, params, body): def compile_function_def(self, expr, root, params, body):
force_functiondef = root in ("fn*", "fn/a") force_functiondef = root in ("fn*", "fn/a")
node = asty.AsyncFunctionDef if root == "fn/a" else asty.FunctionDef node = asty.AsyncFunctionDef if root == "fn/a" else asty.FunctionDef
ret = Result()
mandatory, optional, rest, kwonly, kwargs = params mandatory, optional, rest, kwonly, kwargs = params
optional, defaults, ret = self._parse_optional_args(optional)
kwonly, kw_defaults, ret2 = self._parse_optional_args(kwonly, True)
ret += ret2
main_args = mandatory + optional
main_args, kwonly, [rest], [kwargs] = ( optional = optional or []
[[x and asty.arg(x, arg=ast_str(x), annotation=None) kwonly = kwonly or []
for x in o]
for o in (main_args or [], kwonly or [], [rest], [kwargs])]) mandatory_ast, _, ret = self._compile_arguments_set(mandatory, False, ret)
optional_ast, optional_defaults, ret = self._compile_arguments_set(optional, True, ret)
kwonly_ast, kwonly_defaults, ret = self._compile_arguments_set(kwonly, False, ret)
rest_ast = kwargs_ast = None
if rest is not None:
[rest_ast], _, ret = self._compile_arguments_set([rest], False, ret)
if kwargs is not None:
[kwargs_ast], _, ret = self._compile_arguments_set([kwargs], False, ret)
args = ast.arguments( args = ast.arguments(
args=main_args, defaults=defaults, args=mandatory_ast + optional_ast, defaults=optional_defaults,
vararg=rest, vararg=rest_ast,
posonlyargs=[], posonlyargs=[],
kwonlyargs=kwonly, kw_defaults=kw_defaults, kwonlyargs=kwonly_ast, kw_defaults=kwonly_defaults,
kwarg=kwargs) kwarg=kwargs_ast)
body = self._compile_branch(body) body = self._compile_branch(body)
@ -1482,21 +1487,35 @@ class HyASTCompiler(object):
ret += Result(expr=ast_name, temp_variables=[ast_name, ret.stmts[-1]]) ret += Result(expr=ast_name, temp_variables=[ast_name, ret.stmts[-1]])
return ret return ret
def _parse_optional_args(self, expr, allow_no_default=False): def _compile_arguments_set(self, decls, implicit_default_none, ret):
# [a b [c 5] d] → ([a, b, c, d], [None, None, 5, d], <ret>) args_ast = []
names, defaults, ret = [], [], Result() args_defaults = []
for x in expr or []:
sym, value = ( for decl in decls:
x if isinstance(x, HyList) default = None
else (x, None) if allow_no_default
else (x, HySymbol('None').replace(x))) # funcparserlib will check to make sure that the only times we
names.append(sym) # ever have a HyList here are due to a default value.
if value is None: if isinstance(decl, HyList):
defaults.append(None) sym, default = decl
else: else:
ret += self.compile(value) sym = decl
defaults.append(ret.force_expr) if implicit_default_none:
return names, defaults, ret default = HySymbol('None').replace(sym)
if default is not None:
ret += self.compile(default)
args_defaults.append(ret.force_expr)
else:
# Note that the only time any None should ever appear here
# is in kwargs, since the order of those with defaults vs
# those without isn't significant in the same way as
# positional args.
args_defaults.append(None)
args_ast.append(asty.arg(sym, arg=ast_str(sym), annotation=None))
return args_ast, args_defaults, ret
@special("return", [maybe(FORM)]) @special("return", [maybe(FORM)])
def compile_return(self, expr, root, arg): def compile_return(self, expr, root, arg):