From 4e3f8429723e91c7fc967d3e732e0aacf303a78b Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Wed, 8 May 2013 20:56:16 +0200 Subject: [PATCH] Add &optional arguments. Python doesn't really have that concept, so make them clash with &key arguments. --- hy/compiler.py | 20 ++++++++++++++++---- tests/compilers/test_ast.py | 2 ++ tests/native_tests/language.hy | 8 ++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index dd6af76..776e304 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -402,6 +402,9 @@ class HyASTCompiler(object): if expr == "&rest" and lambda_keyword is None: lambda_keyword = expr elif expr == "&optional": + if len(defaults) > 0: + raise HyCompileError("There can only be &optional " + "arguments or one &key argument") lambda_keyword = expr elif expr == "&key": lambda_keyword = expr @@ -427,8 +430,8 @@ class HyASTCompiler(object): "argument") else: if len(defaults) > 0: - raise HyCompileError("There can only be " - "one &key argument") + raise HyCompileError("There can only be &optional " + "arguments or one &key argument") # As you can see, Python has a funny way of # defining keyword arguments. for k, v in expr.items(): @@ -436,8 +439,17 @@ class HyASTCompiler(object): ret += self.compile(v) defaults.append(ret.force_expr) elif lambda_keyword == "&optional": - # not implemented yet. - pass + if isinstance(expr, HyList): + if not len(expr) == 2: + raise TypeError("optional args should be bare names " + "or 2-item lists") + k, v = expr + else: + k = expr + v = HySymbol("None").replace(k) + args.append(k) + ret += self.compile(v) + defaults.append(ret.force_expr) elif lambda_keyword == "&kwargs": if kwargs: raise HyCompileError("There can only be one " diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 11d4915..8f11f66 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -353,6 +353,8 @@ def test_ast_non_kwapplyable(): def test_ast_lambda_lists(): """Ensure the compiler chokes on invalid lambda-lists""" cant_compile('(fn [&key {"a" b} &key {"foo" bar}] [a foo])') + cant_compile('(fn [&optional a &key {"foo" bar}] [a foo])') + cant_compile('(fn [&optional [a b c]] a)') def test_ast_print(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 9abc43c..330824d 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -645,6 +645,14 @@ (assert (= (kwapply (foo) {"b" 42}) [None 42]))) +(defn test-optional-arguments [] + "NATIVE: test &optional function arguments" + (defn foo [a b &optional c [d 42]] [a b c d]) + (assert (= (foo 1 2) [1 2 None 42])) + (assert (= (foo 1 2 3) [1 2 3 42])) + (assert (= (foo 1 2 3 4) [1 2 3 4]))) + + (defn test-quoted-hoistable [] "NATIVE: test quoted hoistable" (setf f (quote (if true true true)))