diff --git a/hy/compiler.py b/hy/compiler.py index a1ef47d..cd69df2 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1255,35 +1255,33 @@ class HyASTCompiler(object): return ret - # apply only needs to be defined for python3 - if sys.version_info[0] >= 3: - @builds("apply") - @checkargs(min=2, max=3) - def compile_apply_expression(self, expr): - expr.pop(0) # apply - call = self.compile(expr.pop(0)) - call = ast.Call(func=call.expr, - args=[], - keywords=[], - starargs=None, - kwargs=None, - lineno=expr.start_line, - col_offset=expr.start_column) - ret = call + @builds("apply") + @checkargs(min=1, max=3) + def compile_apply_expression(self, expr): + expr.pop(0) # apply + call = self.compile(expr.pop(0)) + call = ast.Call(func=call.expr, + args=[], + keywords=[], + starargs=None, + kwargs=None, + lineno=expr.start_line, + col_offset=expr.start_column) + ret = call - #add star args if any + if expr: stargs = expr.pop(0) if stargs is not None: stargs = self.compile(stargs) call.starargs = stargs.force_expr ret = stargs + ret - if expr != []: - kwargs = self.compile(expr.pop(0)) - call.kwargs = kwargs.force_expr - ret = kwargs + ret + if expr: + kwargs = self.compile(expr.pop(0)) + call.kwargs = kwargs.force_expr + ret = kwargs + ret - return ret + return ret @builds("not") @builds("~") diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 509526a..c2cadd0 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -121,10 +121,15 @@ "Use a dictionary as keyword arguments" (let [[-fun (car call)] [-args (cdr call)] - [-okwargs kwargs]] + [-okwargs `[(list (.items ~kwargs))]]] (while (= -fun "kwapply") ;; join any further kw - (setv -okwargs (+ (car (cdr -args)) -okwargs)) + (if (not (= (len -args) 2)) + (macro-error + call + (.format "Trying to call nested kwapply with {0} args instead of 2" + (len -args)))) + (.insert -okwargs 0 `(list (.items ~(car (cdr -args))))) (setv -fun (car (car -args))) (setv -args (cdr (car -args)))) - `(apply ~-fun [~@-args] ~-okwargs))) + `(apply ~-fun [~@-args] (dict (sum ~-okwargs []))))) diff --git a/tests/compilers/test_error_reporting.py b/tests/compilers/test_error_reporting.py new file mode 100644 index 0000000..879f358 --- /dev/null +++ b/tests/compilers/test_error_reporting.py @@ -0,0 +1,27 @@ +# Copyright (c) 2013 Nicolas Dandrimont +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from .test_ast import can_compile, cant_compile + + +def test_macro_nested_kwapply(): + "Make sure nested kwapply compile correctly" + can_compile("(kwapply (kwapply (foo) bar) baz)") + cant_compile("(kwapply (kwapply (foo)) bar)") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 4bf35d5..1c22567 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -153,14 +153,16 @@ (setv mydict {"one" "three"}) (assert (= (kwapply (kwtest) mydict) mydict)) (assert (= (kwapply (kwtest) ((fn [] {"one" "two"}))) {"one" "two"})) - (assert (= (kwapply - (kwapply - (kwapply - (kwapply (kwtest) {"x" 4}) - {"x" 8}) - {"x" (- 3 2) "y" 2}) + (assert (= (kwapply + (kwapply + (kwapply + (kwapply + (kwapply (kwtest) {"x" 4}) + mydict) + {"x" 8}) + {"x" (- 3 2) "y" 2}) {"y" 5 "z" 3}) - {"x" 1 "y" 5 "z" 3}))) + {"x" 1 "y" 5 "z" 3 "one" "three"}))) (defn test-apply [] "NATIVE: test working with args and functions" @@ -168,7 +170,9 @@ (assert (= (apply sumit [1] {"b" 2 "c" 3}) 6)) (assert (= (apply sumit [1 2 2]) 5)) (assert (= (apply sumit [] {"a" 1 "b" 1 "c" 2}) 4)) - (assert (= (apply sumit ((fn [] [1 1])) {"c" 1}) 3))) + (assert (= (apply sumit ((fn [] [1 1])) {"c" 1}) 3)) + (defn noargs [] [1 2 3]) + (assert (= (apply noargs) [1 2 3]))) (defn test-dotted [] "NATIVE: test dotted invocation" @@ -784,13 +788,12 @@ (defn test-continue-continuation [] "NATIVE: test checking if continue actually continues" (setv y []) - (for [x (range 10)] - (if (!= x 5) - (continue)) + (for [x (range 10)] + (if (!= x 5) + (continue)) (.append y x)) (assert (= y [5]))) (defn test-empty-list [] "Evaluate an empty list to a []" (assert (= () []))) -