From f5754b404e24d7621a4e0f9bf604788848285e1e Mon Sep 17 00:00:00 2001 From: Guillermo Vaya Date: Wed, 24 Jul 2013 00:25:48 +0200 Subject: [PATCH 1/6] Define kwapply as a macro Define apply if python3 Added apply tests --- hy/compiler.py | 36 ++++++++++++++++++++++++---------- hy/core/language.hy | 4 ++-- hy/core/macros.hy | 13 ++++++++++++ tests/native_tests/language.hy | 17 +++++++++++++++- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index f14c79f..a1ef47d 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1255,19 +1255,35 @@ class HyASTCompiler(object): return ret - @builds("kwapply") - @checkargs(2) - def compile_kwapply_expression(self, expr): - expr.pop(0) # kwapply - call = self.compile(expr.pop(0)) - kwargs = self.compile(expr.pop(0)) + # 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 - if type(call.expr) != ast.Call: - raise HyTypeError(expr, "kwapplying a non-call") + #add star args if any + stargs = expr.pop(0) + if stargs is not None: + stargs = self.compile(stargs) + call.starargs = stargs.force_expr + ret = stargs + ret - call.expr.kwargs = kwargs.force_expr + if expr != []: + kwargs = self.compile(expr.pop(0)) + call.kwargs = kwargs.force_expr + ret = kwargs + ret - return kwargs + call + return ret @builds("not") @builds("~") diff --git a/hy/core/language.hy b/hy/core/language.hy index a96b25d..7574dc0 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -213,8 +213,8 @@ (= n 0)) (def *exports* ["cycle" "dec" "distinct" "drop" "drop_while" "empty?" - "even?" "filter" "float?" "inc" - "instance?" "integer?" "iterable?" "iterate" "iterator?" "neg?" + "even?" "filter" "float?" "inc" "instance?" "integer?" + "iterable?" "iterate" "iterator?" "neg?" "none?" "nth" "numeric?" "odd?" "pos?" "remove" "repeat" "repeatedly" "second" "string?" "take" "take_nth" "take_while" "zero?"]) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 17792f9..9498b87 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -25,6 +25,7 @@ ;;; These macros form the hy language ;;; They are automatically required in every module, except inside hy.core +(import [functools [reduce]]) (defmacro for [args &rest body] "shorthand for nested foreach loops: @@ -116,3 +117,15 @@ ;; TODO: this needs some gensym love `(foreach [_hy_yield_from_x ~iterable] (yield _hy_yield_from_x))) + +(defmacro kwapply [call kwargs] + "Use a dictionary as keyword arguments" + (let [[-fun (car call)] + [-args (cdr call)] + [-okwargs kwargs]] + (while (= -fun "kwapply") ;; join any further kw + (setv -okwargs (+ (car (cdr -args)) -okwargs)) + (setv -fun (car (car -args))) + (setv -args (cdr (car -args)))) + + `(apply ~-fun [~@-args] ~-okwargs))) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index d19ca17..4bf35d5 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -152,8 +152,23 @@ (assert (= (kwapply (kwtest) {"one" "two"}) {"one" "two"})) (setv mydict {"one" "three"}) (assert (= (kwapply (kwtest) mydict) mydict)) - (assert (= (kwapply (kwtest) ((fn [] {"one" "two"}))) {"one" "two"}))) + (assert (= (kwapply (kwtest) ((fn [] {"one" "two"}))) {"one" "two"})) + (assert (= (kwapply + (kwapply + (kwapply + (kwapply (kwtest) {"x" 4}) + {"x" 8}) + {"x" (- 3 2) "y" 2}) + {"y" 5 "z" 3}) + {"x" 1 "y" 5 "z" 3}))) +(defn test-apply [] + "NATIVE: test working with args and functions" + (defn sumit [a b c] (+ a b c)) + (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))) (defn test-dotted [] "NATIVE: test dotted invocation" From 83bb1513db59e72b362688b6082868d0d36676e7 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sat, 2 Nov 2013 20:11:18 +0100 Subject: [PATCH 2/6] Make apply api-compatible with python (args is not mandatory) --- hy/compiler.py | 40 ++++++++++++++++------------------ tests/native_tests/language.hy | 4 +++- 2 files changed, 22 insertions(+), 22 deletions(-) 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/tests/native_tests/language.hy b/tests/native_tests/language.hy index 4bf35d5..6521589 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -168,7 +168,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" From 59e51166fb8ac082ea749710c69653d3ff50a136 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sat, 2 Nov 2013 20:11:53 +0100 Subject: [PATCH 3/6] Allow calling kwapply with mixed names and dicts --- hy/core/macros.hy | 11 ++++++++--- tests/native_tests/language.hy | 16 +++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 9498b87..82eb342 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -122,10 +122,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/native_tests/language.hy b/tests/native_tests/language.hy index 6521589..0fedb67 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" From b8406dd920fb0d1d175091ca02b028705993650b Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sat, 2 Nov 2013 20:49:20 +0100 Subject: [PATCH 4/6] Bootstrap a macro error-reporting test file --- tests/compilers/test_error_reporting.py | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/compilers/test_error_reporting.py 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)") From 26b052c76e240adc22a422d5f08b266c2d880406 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sat, 2 Nov 2013 20:49:55 +0100 Subject: [PATCH 5/6] language.hy whitespace fix --- tests/native_tests/language.hy | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 0fedb67..1c22567 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -788,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 (= () []))) - From 0f525a691d556919d21349ae1009635ed9ddd622 Mon Sep 17 00:00:00 2001 From: Guillermo Vaya Date: Sun, 3 Nov 2013 11:11:11 +0100 Subject: [PATCH 6/6] removed unnecessary import --- hy/core/macros.hy | 1 - 1 file changed, 1 deletion(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 9498b87..509526a 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -25,7 +25,6 @@ ;;; These macros form the hy language ;;; They are automatically required in every module, except inside hy.core -(import [functools [reduce]]) (defmacro for [args &rest body] "shorthand for nested foreach loops: