From 1080a457b17a4300b407f14b35848def0b1813ae Mon Sep 17 00:00:00 2001 From: James King Date: Thu, 18 Apr 2013 22:27:38 -0400 Subject: [PATCH] Implemented &key and added tests --- hy/compiler.py | 32 +++++++++++++++++++------------- tests/compilers/test_ast.py | 19 +++++++++++++++---- tests/native_tests/language.hy | 5 +++++ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 5e38c80..9bfcdb7 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -189,11 +189,12 @@ class HyASTCompiler(object): return ret def _parse_lambda_list(self, exprs): + """ Return FunctionDef parameter values from lambda list.""" exprs.reverse() args = [] - keywords = [] + defaults = [] varargs = None - kwargs = {} + kwargs = None lambda_keyword = None while exprs: @@ -227,25 +228,30 @@ class HyASTCompiler(object): varargs = str(expr) elif lambda_keyword == "&key": if type(expr) != HyDict: - raise TypeError("FOOBAR") + raise TypeError("There can only be one &key " + "argument") else: - if len(keywords) > 0: + if len(defaults) > 0: raise HyCompileError("There can only be " "one &key argument") - keywords = [ast.keyword(arg=ast_str(k), - value=self.compile(v), - lineno=expr.start_line, - col_offset=expr.start_column) - for k, v in expr.items()] + # As you can see, Python has a funny way of + # defining keyword arguments. + for k in expr.keys(): + args.append(k) + for v in expr.values(): + defaults.append(self.compile(v)) elif lambda_keyword == "&optional": # not implemented yet. pass elif lambda_keyword == "&kwargs": + if kwargs: + raise HyCompileError("There can only be one " + "&kwargs argument") kwargs = str(expr) if not kwargs: kwargs = None - return args, keywords, varargs, kwargs + return args, defaults, varargs, kwargs @builds(list) def compile_raw_list(self, entries): @@ -1103,7 +1109,7 @@ class HyASTCompiler(object): expression.start_line, expression.start_column) - args, keywords, stararg, kwargs = self._parse_lambda_list(sig) + args, defaults, stararg, kwargs = self._parse_lambda_list(sig) ret = ast.FunctionDef( name=name, @@ -1120,8 +1126,8 @@ class HyASTCompiler(object): vararg=stararg, kwarg=kwargs, kwonlyargs=[], - kw_defaults=keywords, - defaults=[]), + kw_defaults=[], + defaults=defaults), body=body, decorator_list=[]) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 3720901..c6decf9 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -334,14 +334,25 @@ def test_ast_tuple(): assert type(code) == ast.Tuple -def test_lambda_list_keywords(): +def test_lambda_list_keywords_rest(): """ Ensure we can compile functions with lambda list keywords.""" hy_compile(tokenize("(fn (x &rest xs) (print xs))")) cant_compile("(fn (x &rest xs &rest ys) (print xs))") -def test_lambda_list_keywords_optional(): - """ Ensure we can compile functions with &optional.""" - hy_compile(tokenize("(fn (x &optional (foo True)) foo)")) +def test_lambda_list_keywords_key(): + """ Ensure we can compile functions with &key.""" + hy_compile(tokenize("(fn (x &key {foo True}) (list x foo))")) + cant_compile("(fn (x &key {bar \"baz\"} &key {foo 42}) (list x bar foo))") + +def test_lambda_list_keywords_kwargs(): + """ Ensure we can compile functions with &kwargs.""" + hy_compile(tokenize("(fn (x &kwargs kw) (list x kw))")) + cant_compile("(fn (x &kwargs xs &kwargs ys) (list x xs ys))") + +def test_lambda_list_keywords_mixed(): + """ Ensure we can mix them up.""" + hy_compile(tokenize("(fn (x &rest xs &kwargs kw) (list x xs kw))")) + cant_compile("(fn (x &rest xs &key {bar \"baz\"}))") def test_ast_unicode_strings(): """Ensure we handle unicode strings correctly""" diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 00d9a38..7269ccc 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -616,3 +616,8 @@ (assert (= (dirname "/some/path") "/some")) (assert (= op.dirname dirname)) (assert (= dn dirname))) + +(defn test-lambda-keyword-lists [] + "NATIVE: test lambda keyword lists" + (defn foo (x &rest xs &kwargs kw) [x xs kw]) + (assert (= (foo 10 20 30) [10, (20, 30), {}])))