diff --git a/hy/compiler.py b/hy/compiler.py index 50b2b7e..31fba2b 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1949,6 +1949,19 @@ class HyASTCompiler(object): raise HyTypeError(expression, "First argument to (fn) must be a list") ret, args, defaults, stararg, kwargs = self._parse_lambda_list(arglist) + for i, arg in enumerate(args): + if isinstance(arg, HyList): + # Destructuring argument + if not arg: + raise HyTypeError(arglist, + "Cannot destruct empty list") + args[i] = var = HySymbol(self.get_anon_var()) + expression = HyExpression([ + HyExpression([ + HyString("setv"), arg, var + ])] + ) + expression + expression = expression.replace(arg[0]) if PY34: # Python 3.4+ requires that args are an ast.arg object, rather diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy index e68c4ec..fed7d0f 100644 --- a/hy/core/shadow.hy +++ b/hy/core/shadow.hy @@ -61,4 +61,33 @@ (reduce operator.truediv args))))) -(setv *exports* ['+ '- '* '/]) +(defn comp-op [op args] + "Helper for shadow comparison operators" + (if (< (len args) 2) + (raise (TypeError "Need at least 2 arguments to compare")) + (reduce operator.and_ + (list-comp (op x y) + [(, x y) (zip args (slice args 1))])))) +(defn < [&rest args] + "Shadow < operator for when we need to import / map it against something" + (comp-op operator.lt args)) +(defn <= [&rest args] + "Shadow <= operator for when we need to import / map it against something" + (comp-op operator.le args)) +(defn = [&rest args] + "Shadow = operator for when we need to import / map it against something" + (comp-op operator.eq args)) +(defn != [&rest args] + "Shadow != operator for when we need to import / map it against something" + (comp-op operator.ne args)) +(defn >= [&rest args] + "Shadow >= operator for when we need to import / map it against something" + (comp-op operator.ge args)) +(defn > [&rest args] + "Shadow > operator for when we need to import / map it against something" + (comp-op operator.gt args)) + +; TODO figure out a way to shadow "is", "is_not", "and", "or" + + +(setv *exports* ['+ '- '* '/ '< '<= '= '!= '>= '>]) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 4a63b6b..01d6269 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -404,6 +404,12 @@ def test_ast_tuple(): assert type(code) == ast.Tuple +def test_argument_destructuring(): + """ Ensure argument destructuring compilers. """ + can_compile("(fn [[a b]] (print a b))") + cant_compile("(fn [[]] 0)") + + def test_lambda_list_keywords_rest(): """ Ensure we can compile functions with lambda list keywords.""" can_compile("(fn (x &rest xs) (print xs))") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 3fce18b..2d4a909 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1154,3 +1154,8 @@ (assert (= (identify-keywords 1 "bloo" :foo) ["other" "other" "keyword"]))) + +(defn test-argument-destr [] + "Make sure argument destructuring works" + (defn f [[a b] [c]] (, a b c)) + (assert (= (f [1 2] [3]) (, 1 2 3)))) diff --git a/tests/native_tests/shadow.hy b/tests/native_tests/shadow.hy index 54bf81e..ccc8631 100644 --- a/tests/native_tests/shadow.hy +++ b/tests/native_tests/shadow.hy @@ -50,3 +50,42 @@ (assert (= (x 8 2) 4)) (assert (= (x 8 2 2) 2)) (assert (= (x 8 2 2 2) 1)))) + + +(defn test-shadow-compare [] + "NATIVE: test shadow compare" + (for [x [< <= = != >= >]] + (assert (try + (x) + (catch [TypeError] True) + (else (throw AssertionError)))) + (assert (try + (x 1) + (catch [TypeError] True) + (else (throw AssertionError))))) + (for [(, x y) [[< >=] + [<= >] + [= !=]]] + (for [args [[1 2] + [2 1] + [1 1] + [2 2]]] + (assert (= (apply x args) (not (apply y args)))))) + (let [[s-lt <] + [s-gt >] + [s-le <=] + [s-ge >=] + [s-eq =] + [s-ne !=]] + (assert (apply s-lt [1 2 3])) + (assert (not (apply s-lt [3 2 1]))) + (assert (apply s-gt [3 2 1])) + (assert (not (apply s-gt [1 2 3]))) + (assert (apply s-le [1 1 2 2 3 3])) + (assert (not (apply s-le [1 1 2 2 1 1]))) + (assert (apply s-ge [3 3 2 2 1 1])) + (assert (not (apply s-ge [3 3 2 2 3 3]))) + (assert (apply s-eq [1 1 1 1 1])) + (assert (not (apply s-eq [1 1 2 1 1]))) + (assert (apply s-ne [1 2 3 4 5])) + (assert (not (apply s-ne [1 1 2 3 4])))))