diff --git a/NEWS.rst b/NEWS.rst index 3d562db..acd3d09 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -8,6 +8,7 @@ Removals * Dotted lists, `HyCons`, `cons`, `cons?`, and `list*` have been removed. These were redundant with Python's built-in data structures and Hy's most common model types (`HyExpression`, `HyList`, etc.). +* `&key` is no longer special in lambda lists. Use `&optional` instead. Other Breaking Changes ------------------------------ diff --git a/docs/language/api.rst b/docs/language/api.rst index 1fe0f83..e4c6f42 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -493,28 +493,6 @@ Parameters may have the following keywords in front of them: => (total-value 100 1) 101.0 -&key - Parameter is a dict of keyword arguments. The keys of the dict - specify the parameter names and the values give the default values - of the parameters. - - .. code-block:: clj - - => (defn key-parameters [&key {"a" 1 "b" 2}] - ... (print "a is" a "and b is" b)) - => (key-parameters :a 1 :b 2) - a is 1 and b is 2 - => (key-parameters :b 1 :a 2) - a is 2 and b is 1 - - The following declarations are equivalent: - - .. code-block:: clj - - (defn key-parameters [&key {"a" 1 "b" 2}]) - - (defn key-parameters [&optional [a 1] [b 2]]) - &kwargs Parameter will contain 0 or more keyword arguments. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index e8e53e8..00a15b4 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -443,17 +443,6 @@ similar to `*args` and `**kwargs` in Python:: => (optional-arg #* args #** kwargs) [1, 2, 4, 3] -There's also a dictionary-style keyword arguments construction that -looks like: - -.. code-block:: clj - - (defn another-style [&key {"key1" "val1" "key2" "val2"}] - [key1 key2]) - -The difference here is that since it's a dictionary, you can't rely on -any specific ordering to the arguments. - Hy also supports ``*args`` and ``**kwargs`` in parameter lists. In Python:: def some_func(foo, bar, *args, **kwargs): diff --git a/hy/compiler.py b/hy/compiler.py index 491f9f0..83c4e25 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -529,7 +529,7 @@ class HyASTCompiler(object): def _parse_lambda_list(self, exprs): """ Return FunctionDef parameter values from lambda list.""" - ll_keywords = ("&rest", "&optional", "&key", "&kwonly", "&kwargs") + ll_keywords = ("&rest", "&optional", "&kwonly", "&kwargs") ret = Result() args = [] defaults = [] @@ -542,13 +542,7 @@ class HyASTCompiler(object): for expr in exprs: if expr in ll_keywords: - if expr == "&optional": - if len(defaults) > 0: - raise HyTypeError(expr, - "There can only be &optional " - "arguments or one &key argument") - lambda_keyword = expr - elif expr in ("&rest", "&key", "&kwonly", "&kwargs"): + if expr in ("&optional", "&rest", "&kwonly", "&kwargs"): lambda_keyword = expr else: raise HyTypeError(expr, @@ -566,27 +560,6 @@ class HyASTCompiler(object): "There can only be one " "&rest argument") varargs = expr - elif lambda_keyword == "&key": - if type(expr) != HyDict: - raise HyTypeError(expr, - "There can only be one &key " - "argument") - else: - if len(defaults) > 0: - raise HyTypeError(expr, - "There can only be &optional " - "arguments or one &key argument") - # As you can see, Python has a funny way of - # defining keyword arguments. - it = iter(expr) - for k, v in zip(it, it): - if not isinstance(k, HyString): - raise HyTypeError(expr, - "Only strings can be used " - "as parameter names") - args.append(k) - ret += self.compile(v) - defaults.append(ret.force_expr) elif lambda_keyword == "&optional": if isinstance(expr, HyList): if not len(expr) == 2: diff --git a/hy/contrib/walk.hy b/hy/contrib/walk.hy index 6bc93d1..28093ed 100644 --- a/hy/contrib/walk.hy +++ b/hy/contrib/walk.hy @@ -84,7 +84,7 @@ splits a fn argument list into sections based on &-headers. returns an OrderedDict mapping headers to sublists. Arguments without a header are under None. " - (setv headers '[&optional &key &rest &kwonly &kwargs] + (setv headers '[&optional &rest &kwonly &kwargs] sections (OrderedDict [(, None [])]) header None) (for [arg form] @@ -177,14 +177,7 @@ Arguments without a header are under None. ~(self.expand-symbols (second pair))])] [True (.add protected pair) - (.append argslist pair)]))] - [(= header '&key) - (setv &key-dict '{}) - (for [[k v] (-> section first partition)] - (.add protected k) - (.append &key-dict k) - (.append &key-dict (self.expand-symbols v))) - (.append argslist &key-dict)])) + (.append argslist pair)]))])) (, protected argslist)) (defn handle-fn [self] diff --git a/hy/core/bootstrap.hy b/hy/core/bootstrap.hy index e061ef0..14539c3 100644 --- a/hy/core/bootstrap.hy +++ b/hy/core/bootstrap.hy @@ -18,7 +18,7 @@ (% "received a `%s' instead of a symbol for macro name" (. (type name) __name__))))) - (for* [kw '[&kwonly &kwargs &key]] + (for* [kw '[&kwonly &kwargs]] (if* (in kw lambda-list) (raise (hy.errors.HyTypeError macro-name (% "macros cannot use %s" diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index e8d5af8..fb23169 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -396,8 +396,6 @@ def test_ast_non_decoratable(): 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)') cant_compile('(fn [&optional [1 2]] (list 1 2))') @@ -427,13 +425,6 @@ def test_lambda_list_keywords_rest(): can_compile("(fn (&optional a &rest xs) (print xs))") -def test_lambda_list_keywords_key(): - """ Ensure we can compile functions with &key.""" - can_compile("(fn (x &key {foo True}) (list x foo))") - cant_compile("(fn (x &key {bar \"baz\"} &key {foo 42}) (list x bar foo))") - cant_compile("(fn (x &key {1 2 3 4}) (list x))") - - def test_lambda_list_keywords_kwargs(): """ Ensure we can compile functions with &kwargs.""" can_compile("(fn (x &kwargs kw) (list x kw))") diff --git a/tests/native_tests/contrib/walk.hy b/tests/native_tests/contrib/walk.hy index f6463e1..b062186 100644 --- a/tests/native_tests/contrib/walk.hy +++ b/tests/native_tests/contrib/walk.hy @@ -295,19 +295,6 @@ (assert (= (foo 10 20 30) (, 10 20 30))))) -(defn test-let-key [] - (let [a 1 - b 6 - d 2] - (defn foo [&key {a a b None c d}] - (, a b c)) - (assert (= (foo) - (, 1 None 2))) - (assert (= (foo 10 20 30) - (, 10 20 30))) - (assert (= (, a b d) - (, 1 6 2))))) - (defn test-let-closure [] (let [count 0] (defn +count [&optional [x 1]] diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index ff61db9..f8cea69 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1374,14 +1374,6 @@ (assert (= (foo 10 20 30) [10 (, 20 30) {}]))) -(defn test-key-arguments [] - "NATIVE: test &key function arguments" - (defn foo [&key {"a" None "b" 1}] [a b]) - (assert (= (foo) [None 1])) - (assert (= (foo :a 2) [2 1])) - (assert (= (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]) diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy index 0eb7d03..1b9986b 100644 --- a/tests/native_tests/native_macros.hy +++ b/tests/native_tests/native_macros.hy @@ -61,7 +61,7 @@ (foo x y)) (defn test-macro-kw [] - "NATIVE: test that an error is raised when &kwonly, &kwargs, or &key is used in a macro" + "NATIVE: test that an error is raised when &kwonly or &kwargs is used in a macro" (try (eval '(defmacro f [&kwonly a b])) (except [e HyTypeError] @@ -72,12 +72,6 @@ (eval '(defmacro f [&kwargs kw])) (except [e HyTypeError] (assert (= e.message "macros cannot use &kwargs"))) - (else (assert False))) - - (try - (eval '(defmacro f [&key {"kw" "xyz"}])) - (except [e HyTypeError] - (assert (= e.message "macros cannot use &key"))) (else (assert False)))) (defn test-fn-calling-macro []