From e65132c751adad3155ceef3cfcb4b5ef13c32ce7 Mon Sep 17 00:00:00 2001 From: Christian Weilbach Date: Sat, 30 Nov 2013 03:00:45 +0100 Subject: [PATCH 01/46] Set sys.argv default to [''] like Python does. --- hy/cmdline.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index 031eb33..899224c 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -228,7 +228,10 @@ def cmdline_handler(scriptname, argv): options = parser.parse_args(argv[1:]) # reset sys.argv like Python - sys.argv = options.args + if options.args and len(options.args) > 0: + sys.argv = options.args + else: # Python default + sys.argv = [''] if options.command: # User did "hy -c ..." From 46d77f69e65e3230cc6b76b7b5f006f100bb4214 Mon Sep 17 00:00:00 2001 From: Christian Weilbach Date: Mon, 24 Feb 2014 23:08:40 +0100 Subject: [PATCH 02/46] Fix disassembly, add butlast, profile --- hy/core/language.hy | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index 19e8486..30f5b76 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -32,6 +32,10 @@ (if (not (numeric? x)) (raise (TypeError (.format "{0!r} is not a number" x))))) +(defn butlast [coll] + "Returns coll except of last element." + (slice coll 0 (dec (len coll)))) + (defn coll? [coll] "Checks whether item is a collection" (and (iterable? coll) (not (string? coll)))) @@ -60,17 +64,24 @@ (- n 1)) (defn disassemble [tree &optional [codegen false]] - "Dump the python AST for a given Hy tree to standard output + "Return the python AST for a quoted Hy tree as a string. If the second argument is true, generate python code instead." (import astor) (import hy.compiler) (fake-source-positions tree) (setv compiled (hy.compiler.hy_compile tree (calling-module-name))) - (print ((if codegen + ((if codegen astor.codegen.to_source astor.dump) - compiled))) + compiled)) + +(defn profile [tree] + "Profile a quoted Hy tree." + (import cProfile) + (import re) + + (.run cProfile (disassemble tree true))) (defn distinct [coll] "Return a generator from the original collection with duplicates @@ -351,10 +362,11 @@ (import functools) (map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists)))) -(def *exports* '[calling-module-name coll? cons cons? cycle dec distinct - disassemble drop drop-while empty? even? every? first filter - flatten float? gensym identity inc instance? integer - integer? integer-char? iterable? iterate iterator? - list* macroexpand macroexpand-1 neg? nil? none? nth - numeric? odd? pos? remove repeat repeatedly rest second - some string string? take take-nth take-while zero? zipwith]) +(def *exports* '[butlast calling-module-name coll? cons cons? cycle dec + distinct disassemble profile drop drop-while empty? + even? every? first filter flatten float? gensym + identity inc instance? integer integer? integer-char? + iterable? iterate iterator? list* macroexpand + macroexpand-1 neg? nil? none? nth numeric? odd? pos? + remove repeat repeatedly rest second some string + string? take take-nth take-while zero? zipwith]) From 2e4b77267ecec32c2dec4da6e5b1c1dd79ac8a6c Mon Sep 17 00:00:00 2001 From: Christian Weilbach Date: Wed, 26 Feb 2014 00:03:42 +0100 Subject: [PATCH 03/46] Remove profile fn. https://github.com/hylang/hy/pull/522#issuecomment-35972534 --- hy/core/language.hy | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index 30f5b76..6629e57 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -76,13 +76,6 @@ astor.dump) compiled)) -(defn profile [tree] - "Profile a quoted Hy tree." - (import cProfile) - (import re) - - (.run cProfile (disassemble tree true))) - (defn distinct [coll] "Return a generator from the original collection with duplicates removed" From 1a6b484ccb25039c13444d4c1798da75c3781c91 Mon Sep 17 00:00:00 2001 From: Christian Weilbach Date: Sun, 2 Mar 2014 12:24:05 +0100 Subject: [PATCH 04/46] Remove profile export. --- hy/core/language.hy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index 6629e57..8377822 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -356,7 +356,7 @@ (map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists)))) (def *exports* '[butlast calling-module-name coll? cons cons? cycle dec - distinct disassemble profile drop drop-while empty? + distinct disassemble drop drop-while empty? even? every? first filter flatten float? gensym identity inc instance? integer integer? integer-char? iterable? iterate iterator? list* macroexpand From 774aad2ca8744473d3477588582a74b81b69402e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 11 Mar 2014 13:37:29 -0500 Subject: [PATCH 05/46] defmain macro; handles the whole if __name__ == __main__ / main function dance Example: (defmain [&rest args] (print "now we're having a fun time!") (print args)) Which outputs: $ hy test.hy now we're having a fun time! (['test.hy'],) Includes documentation and tests. --- docs/language/api.rst | 38 +++++++++++++++++++++++++++++++++++ hy/core/macros.hy | 15 ++++++++++++++ tests/resources/bin/main.hy | 5 +++++ tests/resources/bin/nomain.hy | 4 ++++ tests/test_bin.py | 24 ++++++++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 tests/resources/bin/main.hy create mode 100644 tests/resources/bin/nomain.hy diff --git a/docs/language/api.rst b/docs/language/api.rst index 57f6029..f9d21ad 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -441,6 +441,44 @@ symbols for function names as the first parameter, `defn-alias` and => (alias) "Hello!" + +defmain +------- + +.. versionadded:: 0.9.13 + +The `defmain` macro defines a main function that is immediately called +with sys.argv as arguments if and only if this file is being executed +as a script. In other words this: + +.. code-block:: clj + + (defmain [&rest args] + (do-something-with args)) + +is the equivalent of:: + + def main(*args): + do_something_with(args) + return 0 + + if __name__ == "__main__": + import sys + retval = main(*sys.arg) + + if isinstance(retval, int): + sys.exit(retval) + +Note, as you can see above, if you return an integer from this +function, this will be used as the exit status for your script. +(Python defaults to exit status 0 otherwise, which means everything's +okay!) + +(Since (sys.exit 0) is not run explicitly in case of a non-integer +return from defmain, it's good to put (defmain) as the last bit of +code in your file.) + + .. _defmacro: defmacro diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 531350e..33f74de 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -171,6 +171,21 @@ (let ~(HyList (map (fn [x] `[~x (gensym (slice '~x 2))]) syms)) ~@body)))) + +(defmacro defmain [args &rest body] + "Write a function named \"main\" and do the if __main__ dance" + (let [[retval (gensym)]] + `(do + (defn main [~@args] + ~@body) + + (when (= --name-- "__main__") + (import sys) + (setv ~retval (apply main sys.argv)) + (if (integer? ~retval) + (sys.exit ~retval)))))) + + (defmacro-alias [defn-alias defun-alias] [names lambda-list &rest body] "define one function with several names" (let [[main (first names)] diff --git a/tests/resources/bin/main.hy b/tests/resources/bin/main.hy new file mode 100644 index 0000000..fbf169f --- /dev/null +++ b/tests/resources/bin/main.hy @@ -0,0 +1,5 @@ +(defmain [&rest args] + (print args) + (print "Hello World") + (if (in "exit1" args) + 1)) diff --git a/tests/resources/bin/nomain.hy b/tests/resources/bin/nomain.hy new file mode 100644 index 0000000..ea559dd --- /dev/null +++ b/tests/resources/bin/nomain.hy @@ -0,0 +1,4 @@ +(print "This Should Still Works") + +(defn main [] + (print "This Should Not Work")) diff --git a/tests/test_bin.py b/tests/test_bin.py index eb0d595..f6fb11c 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -142,3 +142,27 @@ def test_bin_hy_builtins(): assert str(exit) == "Use (exit) or Ctrl-D (i.e. EOF) to exit" assert str(quit) == "Use (quit) or Ctrl-D (i.e. EOF) to exit" + + +def test_bin_hy_main(): + ret = run_cmd("hy tests/resources/bin/main.hy") + assert ret[0] == 0 + assert "Hello World" in ret[1] + + +def test_bin_hy_main_args(): + ret = run_cmd("hy tests/resources/bin/main.hy test 123") + assert ret[0] == 0 + assert "test" in ret[1] + assert "123" in ret[1] + + +def test_bin_hy_main_exitvalue(): + ret = run_cmd("hy tests/resources/bin/main.hy exit1") + assert ret[0] == 1 + + +def test_bin_hy_no_main(): + ret = run_cmd("hy tests/resources/bin/nomain.hy") + assert ret[0] == 0 + assert "This Should Still Work" in ret[1] From 0195de6545eba857927980f423adb7a2f37a5f7a Mon Sep 17 00:00:00 2001 From: maresp Date: Fri, 18 Apr 2014 02:45:05 +0200 Subject: [PATCH 06/46] fixed ap-map potential naming conflict --- hy/contrib/anaphoric.hy | 7 ++++--- tests/native_tests/contrib/anaphoric.hy | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hy/contrib/anaphoric.hy b/hy/contrib/anaphoric.hy index 2f37b47..5a6b236 100644 --- a/hy/contrib/anaphoric.hy +++ b/hy/contrib/anaphoric.hy @@ -46,9 +46,10 @@ (defmacro ap-map [form lst] "Yield elements evaluated in the form for each element in the list." - `(let [[f (lambda [it] ~form)]] - (for [v ~lst] - (yield (f v))))) + (let [[v (gensym 'v)] [f (gensym 'f)]] + `(let [[~f (lambda [it] ~form)]] + (for [~v ~lst] + (yield (~f ~v)))))) (defmacro ap-map-when [predfn rep lst] diff --git a/tests/native_tests/contrib/anaphoric.hy b/tests/native_tests/contrib/anaphoric.hy index 791b24c..3d67e82 100644 --- a/tests/native_tests/contrib/anaphoric.hy +++ b/tests/native_tests/contrib/anaphoric.hy @@ -54,7 +54,9 @@ (assert-equal (list (ap-map (* it 3) [1 2 3])) [3 6 9]) (assert-equal (list (ap-map (* it 3) [])) - [])) + []) + (assert-equal (let [[v 1] [f 1]] (list (ap-map (it v f) [(fn [a b] (+ a b))]))) + [2])) (defn test-ap-map-when [] "NATIVE: testing anaphoric map-when" From 21cff9d14ff3597a2f5275d31ca72dc155290524 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Mon, 21 Apr 2014 08:04:03 +0300 Subject: [PATCH 07/46] initial implementation for doto macro relates #567 --- hy/core/macros.hy | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index f20d0a7..548a81b 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -127,6 +127,16 @@ ret) +(defmacro doto [form &rest expressions] + (setv expressions (iter expressions)) + (defn build-form [form expression] + `(~(first expression) ~form ~@(rest expression))) + (setv result `()) + (for* [expression expressions] + (.append result (build-form form expression))) + `(do ~@result)) + + (defmacro ->> [head &rest rest] ;; TODO: fix the docstring by someone who understands this (setv ret head) From 8a5a1eea27311d6ed8623cf59d0986712f4a8a1a Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Mon, 21 Apr 2014 13:21:11 +0300 Subject: [PATCH 08/46] test for doto macro relates #567 --- tests/native_tests/core.hy | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index 15debf4..fec1316 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -478,3 +478,10 @@ (assert-equal (list res) [4 4 4]) (setv res (zipwith operator.sub [3 7 9] [1 2 4])) (assert-equal (list res) [2 5 5])) + +(defn test-doto [] + "NATIVE: testing doto macro" + (setv collection []) + (doto collection (.append 1) (.append 2) (.append 3)) + (assert-equal collection [1 2 3])) + From f4b67e8bd815c132fa4a602e80f9f21c57216878 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Mon, 21 Apr 2014 13:28:08 +0300 Subject: [PATCH 09/46] documentation for doto relates #567 --- docs/language/api.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/language/api.rst b/docs/language/api.rst index fe3575e..f5b1ac5 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -560,6 +560,27 @@ del => dic {} +doto +---- + +`doto` macro is used to make repetitive calls to an object easy. Following +example demonstrates this. + +.. code-block:: clj + + => (setv collection []) + => (doto collection (.append 1) (.append 2)) + => collection + [1 2] + +.. code-block:: clj + + => (setv collection []) + => (.append 1 collection) + => (.append 2 collection) + => collection + [1 2] + eval ---- From 834b0019a715f6351d53963f743361651cd60912 Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Mon, 21 Apr 2014 12:35:56 -0700 Subject: [PATCH 10/46] Fixing `doto` to be API compatible with Clojure's `doto` --- docs/language/api.rst | 22 ++++++++++------------ hy/core/macros.hy | 17 +++++++++-------- tests/native_tests/core.hy | 6 +++++- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index f5b1ac5..53b89a5 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -563,23 +563,21 @@ del doto ---- -`doto` macro is used to make repetitive calls to an object easy. Following -example demonstrates this. +`doto` macro is used to make a sequence of method calls for an object easy. + +.. code-block:: clj + + => (doto [] (.append 1) (.append 2) .reverse) + [2 1] .. code-block:: clj => (setv collection []) - => (doto collection (.append 1) (.append 2)) + => (.append collection 1) + => (.append collection 2) + => (.reverse collection) => collection - [1 2] - -.. code-block:: clj - - => (setv collection []) - => (.append 1 collection) - => (.append 2 collection) - => collection - [1 2] + [2 1] eval ---- diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 548a81b..29db215 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -128,14 +128,15 @@ (defmacro doto [form &rest expressions] - (setv expressions (iter expressions)) - (defn build-form [form expression] - `(~(first expression) ~form ~@(rest expression))) - (setv result `()) - (for* [expression expressions] - (.append result (build-form form expression))) - `(do ~@result)) - + "Performs a sequence of potentially mutating actions on an initial object, returning the resulting object after the sequence is performed" + (setv f (gensym)) + (defn build-form [expression] + (if (isinstance expression HyExpression) + `(~(first expression) ~f ~@(rest expression)) + `(~expression ~f))) + `(let [[~f ~form]] + ~@(map build-form expressions) + ~f)) (defmacro ->> [head &rest rest] ;; TODO: fix the docstring by someone who understands this diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index fec1316..c1ef191 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -483,5 +483,9 @@ "NATIVE: testing doto macro" (setv collection []) (doto collection (.append 1) (.append 2) (.append 3)) - (assert-equal collection [1 2 3])) + (assert-equal collection [1 2 3]) + (setv res (doto (set) (.add 2) (.add 1))) + (assert-equal res (set [1 2])) + (setv res (doto [] (.append 1) (.append 2) .reverse)) + (assert-equal res [2 1])) From 43f63e9ae7a6c479258e978fdb585a4fa8c6a5d2 Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Mon, 21 Apr 2014 13:17:40 -0700 Subject: [PATCH 11/46] Shortening docstring --- hy/core/macros.hy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 29db215..cc9d2b9 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -128,7 +128,8 @@ (defmacro doto [form &rest expressions] - "Performs a sequence of potentially mutating actions on an initial object, returning the resulting object after the sequence is performed" + "Performs a sequence of potentially mutating actions + on an initial object, returning the resulting object" (setv f (gensym)) (defn build-form [expression] (if (isinstance expression HyExpression) From 5c9a8f8975ea43d2b62c272aedd6c2f12d7f4eca Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Tue, 22 Apr 2014 08:56:44 -0700 Subject: [PATCH 12/46] Closes #573, restores 0.9.12 for loop behavior (and everyone wins!) --- hy/core/macros.hy | 7 ++----- tests/native_tests/language.hy | 8 ++++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index f20d0a7..6ae1cd7 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -52,11 +52,8 @@ ; basecase, let's just slip right in. `(for* [~@args] ~@body) ; otherwise, let's do some legit handling. - (let [[alist (slice args 0 nil 2)] - [ilist (slice args 1 nil 2)]] - `(do - (import itertools) - (for* [(, ~@alist) (itertools.product ~@ilist)] ~@body)))))) + (let [[alist (slice args 0 nil 2)]] + `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] ~@body))))) (defmacro with [args &rest body] diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index ccf81c5..c394891 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -29,7 +29,7 @@ (defn test-for-loop [] - "NATIVE: test for loops?" + "NATIVE: test for loops" (setv count 0) (for [x [1 2 3 4 5]] (setv count (+ count x))) @@ -38,7 +38,11 @@ (for [x [1 2 3 4 5] y [1 2 3 4 5]] (setv count (+ count x y))) - (assert (= count 150))) + (assert (= count 150)) + (assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y))))) + (list-comp y [x [[1] [2 3]] y x]))) + (assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z))))) + (list-comp z [x [[1] [2 3]] y x z (range 5)])))) (defn test-nasty-for-nesting [] From 41a8b6e09b176ebe151aa9b2f846ec2ea77a48fb Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Tue, 22 Apr 2014 09:17:16 -0700 Subject: [PATCH 13/46] Adding myself as an author --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e5b61cf..8bcae09 100644 --- a/AUTHORS +++ b/AUTHORS @@ -45,3 +45,4 @@ * kirbyfan64 * Brendan Curran-Johnson * Ivan Kozik +* Matthew Wampler-Doty From 92a1f17b36685154fd684e15b47e27ba65c8979d Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Tue, 22 Apr 2014 09:18:01 -0700 Subject: [PATCH 14/46] Adding myself as an author --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e5b61cf..8bcae09 100644 --- a/AUTHORS +++ b/AUTHORS @@ -45,3 +45,4 @@ * kirbyfan64 * Brendan Curran-Johnson * Ivan Kozik +* Matthew Wampler-Doty From f2f38a1cf82bc0374d28acdd4334ba9c1569baa9 Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Tue, 22 Apr 2014 16:47:42 -0700 Subject: [PATCH 15/46] Refactor for loop to use cond --- hy/core/macros.hy | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 6ae1cd7..537cfa4 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -31,31 +31,6 @@ [hy._compat [PY33 PY34]]) -(defmacro for [args &rest body] - "shorthand for nested for loops: - (for [x foo - y bar] - baz) -> - (for* [x foo] - (for* [y bar] - baz))" - - (if (odd? (len args)) - (macro-error args "`for' requires an even number of args.")) - - (if (empty? body) - (macro-error None "`for' requires a body to evaluate")) - - (if (empty? args) - `(do ~@body) - (if (= (len args) 2) - ; basecase, let's just slip right in. - `(for* [~@args] ~@body) - ; otherwise, let's do some legit handling. - (let [[alist (slice args 0 nil 2)]] - `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] ~@body))))) - - (defmacro with [args &rest body] "shorthand for nested for* loops: (with [[x foo] [y bar]] baz) -> @@ -113,6 +88,26 @@ root) +(defmacro for [args &rest body] + "shorthand for nested for loops: + (for [x foo + y bar] + baz) -> + (for* [x foo] + (for* [y bar] + baz))" + (cond + [(odd? (len args)) + (macro-error args "`for' requires an even number of args.")] + [(empty? body) + (macro-error None "`for' requires a body to evaluate")] + [(empty? args) `(do ~@body)] + [(= (len args) 2) `(for* [~@args] ~@body)] + [true + (let [[alist (slice args 0 nil 2)]] + `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] ~@body))])) + + (defmacro -> [head &rest rest] ;; TODO: fix the docstring by someone who understands this (setv ret head) From fa5f51e0f12e99b725cf5d7856506b259517c63e Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Fri, 25 Apr 2014 08:19:22 -0500 Subject: [PATCH 16/46] Adding Version Added 0.10.1 --- docs/language/api.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/language/api.rst b/docs/language/api.rst index 53b89a5..a7efde9 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -563,6 +563,8 @@ del doto ---- +.. versionadded:: 0.10.1 + `doto` macro is used to make a sequence of method calls for an object easy. .. code-block:: clj From 3a66a2d1bed27ee5d8a127dd7e55155b2afdc508 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Mon, 28 Apr 2014 21:09:06 +0300 Subject: [PATCH 17/46] document dict-comp and genexpr --- docs/language/api.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/language/api.rst b/docs/language/api.rst index fe3575e..0bbe021 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -271,6 +271,21 @@ however is called only for every other value in the list. (side-effect2 x))) +dict-comp +--------- + +`dict-comp` is used to create dictionaries. It takes two or three parameters. +The first two parameters are for controlling the return value +(key-value pair), while the third is used to select items from a sequence. The +fourth and optional parameter can be used to filter out some of the items in +the list based on a conditional expression. + +.. code-block:: clj + + => (dict-comp x (* x 2) [x (range 10)] (odd? x)) + {1: 2, 3: 6, 9: 18, 5: 10, 7: 14} + + do / progn ---------- @@ -629,6 +644,24 @@ normally. If the execution is halted with `break`, the `else` does not execute. loop finished +genexpr +------- + +`genexpr` is used to create generator expressions. It takes two or three parameters. +The first parameter is the expression controlling the return value, while +the second is used to select items from a list. The third and optional +parameter can be used to filter out some of the items in the list based on a +conditional expression. `genexpr` is similar to `list-comp`, except that it returns +an iterable that evaluates values one by one instead of evaluating them immediately. + +.. code-block:: clj + + => (def collection (range 10)) + => (def filtered (genexpr x [x collection] (even? x))) + => (list filtered) + [0, 2, 4, 6, 8] + + .. _gensym: gensym From 01fa9d6a3c0502a975c4253f16e09a47248b69de Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Mon, 28 Apr 2014 21:35:28 +0300 Subject: [PATCH 18/46] document set-comp --- docs/language/api.rst | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 0bbe021..e2b7d12 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -274,13 +274,13 @@ however is called only for every other value in the list. dict-comp --------- -`dict-comp` is used to create dictionaries. It takes two or three parameters. +`dict-comp` is used to create dictionaries. It takes three or four parameters. The first two parameters are for controlling the return value (key-value pair), while the third is used to select items from a sequence. The fourth and optional parameter can be used to filter out some of the items in -the list based on a conditional expression. +the sequence based on a conditional expression. -.. code-block:: clj +.. code-block:: hy => (dict-comp x (* x 2) [x (range 10)] (odd? x)) {1: 2, 3: 6, 9: 18, 5: 10, 7: 14} @@ -654,7 +654,7 @@ parameter can be used to filter out some of the items in the list based on a conditional expression. `genexpr` is similar to `list-comp`, except that it returns an iterable that evaluates values one by one instead of evaluating them immediately. -.. code-block:: clj +.. code-block:: hy => (def collection (range 10)) => (def filtered (genexpr x [x collection] (even? x))) @@ -1036,6 +1036,22 @@ element: [1, 2, 3, 4, 5, 6, 7, 8, 9] +set-comp +-------- + +`set-comp` is used to create sets. It takes two or three parameters. +The first parameter is for controlling the return value, while the second is +used to select items from a sequence. The third and optional parameter can be +used to filter out some of the items in the sequence based on a conditional +expression. + +.. code-block:: hy + + => (setv data [1 2 3 4 5 2 3 4 5 3 4 5]) + => (set-comp x [x data] (odd? x)) + {1, 3, 5} + + slice ----- From 7b5cb390abf271b5f40f18eee2c43da56c11c9c3 Mon Sep 17 00:00:00 2001 From: Matthew Wampler-Doty Date: Tue, 29 Apr 2014 09:22:55 -0500 Subject: [PATCH 19/46] `setv` no longer creates variables with '.' in their names FIXES #577 --- AUTHORS | 1 + hy/compiler.py | 21 +++++++++++---------- tests/native_tests/core.hy | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index 847740c..c83f5ff 100644 --- a/AUTHORS +++ b/AUTHORS @@ -46,3 +46,4 @@ * Brendan Curran-Johnson * Ivan Kozik * Allison Kaptur +* Matthew Wampler-Doty diff --git a/hy/compiler.py b/hy/compiler.py index 032a49a..353fb0d 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1751,18 +1751,19 @@ class HyASTCompiler(object): def _compile_assign(self, name, result, start_line, start_column): result = self.compile(result) - - if result.temp_variables and isinstance(name, HyString): - result.rename(name) - return result - ld_name = self.compile(name) - st_name = self._storeize(ld_name) - result += ast.Assign( - lineno=start_line, - col_offset=start_column, - targets=[st_name], value=result.force_expr) + if result.temp_variables \ + and isinstance(name, HyString) \ + and '.' not in name: + result.rename(name) + else: + st_name = self._storeize(ld_name) + result += ast.Assign( + lineno=start_line, + col_offset=start_column, + targets=[st_name], + value=result.force_expr) result += ld_name return result diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index 98e403d..c5c58d5 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -57,6 +57,34 @@ (try (do (dec None) (assert False)) (catch [e [TypeError]] (assert (in "not a number" (str e)))))) +(defn test-setv [] + "NATIVE: testing setv mutation" + (setv x 1) + (setv y 1) + (assert-equal x y) + (setv x (setv y 12)) + (assert-equal x 12) + (assert-equal y 12) + (setv x (setv y (fn [x] 9))) + (assert-equal (x y) 9) + (assert-equal (y x) 9) + (try (do (setv a.b 1) (assert False)) + (catch [e [NameError]] (assert (in "name 'a' is not defined" (str e))))) + (try (do (setv b.a (fn [x] x)) (assert False)) + (catch [e [NameError]] (assert (in "name 'b' is not defined" (str e))))) + (import itertools) + (setv foopermutations (fn [x] (itertools.permutations x))) + (setv p (set [(, 1 3 2) (, 3 2 1) (, 2 1 3) (, 3 1 2) (, 1 2 3) (, 2 3 1)])) + (assert-equal (set (itertools.permutations [1 2 3])) p) + (assert-equal (set (foopermutations [3 1 2])) p) + (setv permutations- itertools.permutations) + (setv itertools.permutations (fn [x] 9)) + (assert-equal (itertools.permutations p) 9) + (assert-equal (foopermutations foopermutations) 9) + (setv itertools.permutations permutations-) + (assert-equal (set (itertools.permutations [2 1 3])) p) + (assert-equal (set (foopermutations [2 3 1])) p)) + (defn test-distinct [] "NATIVE: testing the distinct function" (setv res (list (distinct [ 1 2 3 4 3 5 2 ]))) From d539f73d4d94f3ac07988f0ecebfd2bfee0f1073 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Fri, 2 May 2014 12:27:19 +0300 Subject: [PATCH 20/46] correct ..versionadded:: for defmain my mistake, should have spotted before merging and pushing --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 4501ebd..c40e405 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -445,7 +445,7 @@ symbols for function names as the first parameter, `defn-alias` and defmain ------- -.. versionadded:: 0.9.13 +.. versionadded:: 0.10.1 The `defmain` macro defines a main function that is immediately called with sys.argv as arguments if and only if this file is being executed From 909981dd23eb77d58fdbadbec5e182c15d933847 Mon Sep 17 00:00:00 2001 From: Kartik Mistry Date: Fri, 2 May 2014 21:28:42 +0530 Subject: [PATCH 21/46] Typo fixes in comments Signed-off-by: Kartik Mistry --- hy/__main__.py | 2 +- hy/compiler.py | 2 +- hy/errors.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hy/__main__.py b/hy/__main__.py index 70b300d..ff1405c 100644 --- a/hy/__main__.py +++ b/hy/__main__.py @@ -23,7 +23,7 @@ import imp import sys # This just mocks the normalish behavior of the Python interp. Helpful to aid -# with shiming existing apps that don't really "work" with Hy. +# with shimming existing apps that don't really "work" with Hy. # # You could say this script helps Hyjack a file. # diff --git a/hy/compiler.py b/hy/compiler.py index 032a49a..cfba54c 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1512,7 +1512,7 @@ class HyASTCompiler(object): def compile_require(self, expression): """ TODO: keep track of what we've imported in this run and then - "unimport" it after we've completed `thing' so that we don't polute + "unimport" it after we've completed `thing' so that we don't pollute other envs. """ expression.pop(0) diff --git a/hy/errors.py b/hy/errors.py index c839d83..439d493 100644 --- a/hy/errors.py +++ b/hy/errors.py @@ -28,7 +28,7 @@ import traceback class HyError(Exception): """ - Generic Hy error. All interal Exceptions will be subclassed from this + Generic Hy error. All internal Exceptions will be subclassed from this Exception. """ pass From f2beef6e702fc0f767aef75b5de0f639f683d9b1 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Fri, 2 May 2014 23:57:04 +0530 Subject: [PATCH 22/46] Move contributing from hacking docs to repo root A CONTRIBUTING.rst is added to the root of the repo, as Github automatically recognizes this for incoming PRs (ref: https://github.com/blog/1184-contributing-guidelines) Most of the information is directly borrowed from the existing hacking docs, which is restructured to refer to this file instead for contribution guidelines --- CONTRIBUTING.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ docs/hacking.rst | 22 +++------------------- 2 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 CONTRIBUTING.rst diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..2b69bbe --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,44 @@ +Contributions are welcome & greatly appreciated, every little bit +helps in making Hy more awesome. + +Pull requests are great! We love them, here is a quick guide: + +- Fork the repo, create a topic branch for a feature/fix. Avoid + making changes directly on the master branch + +- All incoming features should be accompanied with tests + +- Before you submit a PR, please run the tests and check your code + against the style guide. You can do both these things at once:: + + $ make d + +- Make commits into logical units, so that it is easier to track & + navigate later. Before submitting a PR, try squashing the commits + into changesets that are easy to come back to later. Also make sure + you don't leave spurious whitespace in the changesets, this avoids + creation of whitespace fix commits later. + +- As far as commit messages go, try to adhere to + the following: + + + Try sticking to the 50 character limit for the first line of git + commit messages + + + For more explanations etc. follow this up with a blank line and + continue describing the commit in detail + + +- Finally add yourself to the AUTHORS file (as a seperate commit), you + deserve it :) + +- All incoming changes need to be acked by 2 different members of + Hylang's core team. Additional review is clearly welcome, but we need + a minimum of 2 signoffs for any change. + +- If a core member is sending in a PR, please find 2 core members that doesn't + include the PR submitter. The idea here is that one can work with the PR + author, and a second acks the entire change set. + +- For documentation & other trivial changes, we're good to merge after one + ACK. We've got low coverage, so it'd be great to keep that barrier low. diff --git a/docs/hacking.rst b/docs/hacking.rst index 8b9ecc6..5fb3c0a 100644 --- a/docs/hacking.rst +++ b/docs/hacking.rst @@ -89,26 +89,10 @@ To build the docs in HTML:: Write docs---docs are good! Even this doc! -Core Development Rules -====================== - -Pull requests are good! - -Before you submit a PR, please run the tests and check your code against the style guide. You can do both these things at once:: - - $ make d - -All incoming changes need to be acked by 2 different members of Hylang's -core team. Additional review is clearly welcome, but we need a minimum of -2 signoffs for any change. - -If a core member is sending in a PR, please find 2 core members that don't -include the PR submitter. The idea here is that one can work with the PR -author, and a second acks the entire change set. - -If the change is adding documentation, feel free to just merge after one -ACK. We've got low coverage, so it'd be great to keep that barrier low. +Contributing +============ +.. include:: ../CONTRIBUTING.rst Core Team ========= From ec8d5aefe7335b18107d20fd9b3560fcd8cd7083 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Sun, 4 May 2014 17:28:08 -0400 Subject: [PATCH 23/46] Add dockerfile. --- Dockerfile | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7ec7336 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +# Base image +# +# VERSION 0.1 +FROM debian:unstable +MAINTAINER Paul R. Tagliamonte + +RUN apt-get update && apt-get install -y python3.4 python3-pip +ADD . /opt/hylang/hy +RUN python3.4 /usr/bin/pip3 install -e /opt/hylang/hy + +CMD ["hy"] From 4f74652c7391774b045a3c82ec79a70f720d90e0 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Mon, 5 May 2014 23:47:14 +0530 Subject: [PATCH 24/46] the mega typo fix commit Wow! much typos! such fix! --- CONTRIBUTING.rst | 2 +- NEWS | 12 ++++++------ README.md | 2 +- docs/language/api.rst | 4 ++-- docs/language/internals.rst | 2 +- docs/language/readermacros.rst | 2 +- docs/tutorial.rst | 2 +- eg/sunlight/party-count.hy | 2 +- hy/compiler.py | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2b69bbe..21d4186 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -29,7 +29,7 @@ Pull requests are great! We love them, here is a quick guide: continue describing the commit in detail -- Finally add yourself to the AUTHORS file (as a seperate commit), you +- Finally add yourself to the AUTHORS file (as a separate commit), you deserve it :) - All incoming changes need to be acked by 2 different members of diff --git a/NEWS b/NEWS index 0c01556..ed5c534 100644 --- a/NEWS +++ b/NEWS @@ -60,7 +60,7 @@ Changes from 0.9.12 * "clean" target added to Makefile * hy2py supports a bunch of commandline options to show AST, source etc. * Sub-object mangling: every identifier is split along the dots & mangled - seperately + separately [ Bug Fixes ] * Empty MacroExpansions work as expected @@ -88,7 +88,7 @@ Changes from Hy 0.9.11 what exactly was added. The biggest feature, Reader Macros, landed later - in the cycle, but were big enough to warrent a release on it's + in the cycle, but were big enough to warrant a release on its own. A huge thanks goes to Foxboron for implementing them and a massive hug goes out to olasd for providing ongoing reviews during the development. @@ -267,7 +267,7 @@ Changes from Hy 0.9.6 * UTF-8 encoded hy symbols are now hy_... rather than __hy_..., it's silly to prefex them as such. (PT) - * `j' is no longer always intepreted as a complex number; we use it much + * `j' is no longer always interpreted as a complex number; we use it much more as a symbol. (ND) * (decorate-with) has been moved to (with-decorate) (JD) * New (unless) macro (JD) @@ -286,7 +286,7 @@ Changes from Hy 0.9.6 and jd for making this happen. This solves just an insane number of bugs. (ND, PT, JD) * Eval no longer sucks with statements (ND) - * New magic binary flags / mis fixes with the hy intepreter + * New magic binary flags / mis fixes with the hy interpreter (WKG + @eigenhombre) @@ -311,7 +311,7 @@ Changes from Hy 0.9.5 =============== WARNING: WARNING: READ ME: READ ME: =================== From here on out, we will only support "future division" as part of hy. This is actually quite a pain for us, but it's going to be quite an - amazing feautre. + amazing feature. This also normalizes behavior from Py 2 --> Py 3. @@ -346,7 +346,7 @@ Changes from Hy 0.9.4 * Statements in the `fn' path early will not return anymore. (PT) * Added "not" as the inline "not" operator. It's advised to still - use "not-in" or "is-not" rather then nesting. (JD) + use "not-in" or "is-not" rather than nesting. (JD) * `let' macro added (PT) * Added "~" as the "invert" operator. (JD) * `catch' now accepts a new format: (JD) diff --git a/README.md b/README.md index bd66b81..4fbb802 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ OK, so, why? ------------ Well. Python is awesome. So awesome, that we have so many tools to alter the -languge in a *core* way, but we never use them. +language in a *core* way, but we never use them. Why? diff --git a/docs/language/api.rst b/docs/language/api.rst index 1d12c5a..d5949c8 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -1144,7 +1144,7 @@ Example usage ; Throw an IOError("foobar") -`throw` can acccept a single argument (an `Exception` class or instance), or +`throw` can accept a single argument (an `Exception` class or instance), or no arguments to re-raise the last Exception. @@ -1238,7 +1238,7 @@ while `while` form is used to execute a single or more blocks as long as a condition is being met. -The following example will output "hello world!" on screen indefinetely: +The following example will output "hello world!" on screen indefinitely: .. code-block:: clj diff --git a/docs/language/internals.rst b/docs/language/internals.rst index 47ddba1..43239c4 100644 --- a/docs/language/internals.rst +++ b/docs/language/internals.rst @@ -387,7 +387,7 @@ for a more complete description.) ``nif`` is an example, something like a numeri where based on the expression, one of the 3 forms is called depending on if the expression is positive, zero or negative. -A first pass might be someting like: +A first pass might be something like: .. code-block:: hy diff --git a/docs/language/readermacros.rst b/docs/language/readermacros.rst index 392feb6..4acfa18 100644 --- a/docs/language/readermacros.rst +++ b/docs/language/readermacros.rst @@ -70,4 +70,4 @@ and expression is passed to the correct function. .. warning:: Because of a limitation in Hy's lexer and parser, reader macros can't redefine defined syntax such as ``()[]{}``. This will most likely be - adressed in the future. + addressed in the future. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index a33ab28..998aa55 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -500,7 +500,7 @@ Let's take the classic: (loop (print (eval (read)))) -Rather then write it like that, we can write it as follows: +Rather than write it like that, we can write it as follows: .. code-block:: clj diff --git a/eg/sunlight/party-count.hy b/eg/sunlight/party-count.hy index 7e495dd..d54feec 100755 --- a/eg/sunlight/party-count.hy +++ b/eg/sunlight/party-count.hy @@ -1,6 +1,6 @@ #!/usr/bin/env hy ;; Copyright (c) Paul R. Tagliamonte , 2013 under the terms -;; of the Expat license, a copy of which you have should have recieved with +;; of the Expat license, a copy of which you should have received with ;; the source. (import sys) diff --git a/hy/compiler.py b/hy/compiler.py index cfba54c..444f68b 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1855,7 +1855,7 @@ class HyASTCompiler(object): ret, args, defaults, stararg, kwargs = self._parse_lambda_list(arglist) if PY34: - # Python 3.4+ requres that args are an ast.arg object, rather + # Python 3.4+ requires that args are an ast.arg object, rather # than an ast.Name or bare string. args = [ast.arg(arg=ast_str(x), annotation=None, # Fix me! From 18a6346d42988507962d260e88916fd40fec9850 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Fri, 2 May 2014 19:25:09 +0530 Subject: [PATCH 25/46] Display python version & platform at repl startup *hy/cmdline.py: At the repl startup the Python implementation & version is displayed along with the platform(os) information --- hy/cmdline.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index 6ccbb8f..a29d901 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -203,6 +203,7 @@ def run_file(filename): def run_repl(hr=None, spy=False): + import platform sys.ps1 = "=> " sys.ps2 = "... " @@ -210,10 +211,15 @@ def run_repl(hr=None, spy=False): if not hr: hr = HyREPL(spy) - hr.interact("{appname} {version}".format( - appname=hy.__appname__, - version=hy.__version__ - )) + hr.interact("{appname} {version} using " + "{py}({build}) {pyversion} on {os}".format( + appname=hy.__appname__, + version=hy.__version__, + py=platform.python_implementation(), + build=platform.python_build()[0], + pyversion=platform.python_version(), + os=platform.system() + )) return 0 From f326975d7c4b1f8cf45a37265a45e9c542925e76 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Tue, 13 May 2014 19:39:07 +0530 Subject: [PATCH 26/46] Make ci builds faster by splitting requirements Make travis builds faster by splitting requirements into requirements-travis.txt, which contains all the requirements necessary for running tests, documentation related packages are omitted and added as a part of requirements-dev.txt Additionally .travis.yml is modified to cache pip downloads, though this feature is yet to be rolled out for the free tier --- .travis.yml | 6 ++++-- requirements-dev.txt | 5 +---- requirements-travis.txt | 3 +++ 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 requirements-travis.txt diff --git a/.travis.yml b/.travis.yml index 22c320e..0009569 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,12 @@ python: - "3.2" - "3.3" - "3.4" +cache: + - $HOME/.pip-cache # command to install dependencies install: - - pip install -r requirements-dev.txt - - pip install coveralls + - pip install -r requirements-travis.txt --download-cache $HOME/.pip-cache + - pip install coveralls --download-cache $HOME/.pip-cache - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi # needs for running tests - pip install --allow-all-external -e . # command to run tests diff --git a/requirements-dev.txt b/requirements-dev.txt index 88a91e9..63b9481 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,11 +1,8 @@ +-r requirements-travis.txt # test tools nose tox -# code quality -flake8 -coverage - # documentation Pygments>=1.6 Sphinx diff --git a/requirements-travis.txt b/requirements-travis.txt new file mode 100644 index 0000000..80be0ce --- /dev/null +++ b/requirements-travis.txt @@ -0,0 +1,3 @@ +# code quality +flake8 +coverage From 15ad6cb998c423b000caa0256e395b405519e5e4 Mon Sep 17 00:00:00 2001 From: John MacKenzie Date: Tue, 6 May 2014 18:48:17 +0000 Subject: [PATCH 27/46] defmacro/g! and HyObject#startswith Currently, defmacro/g! doesn't respond well when it comes across a HyObject that doesn't respond to the instance method startswith (e.g. HyInteger, HyFloat, etc.). This updates defmacro/g! to be a little safer when searching for the gensyms it needs to create. --- hy/core/macros.hy | 2 +- tests/native_tests/native_macros.hy | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 8b46743..c6071ba 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -169,7 +169,7 @@ ~@body)) (defmacro defmacro/g! [name args &rest body] - (let [[syms (list (distinct (filter (fn [x] (.startswith x "g!")) (flatten body))))]] + (let [[syms (list (distinct (filter (fn [x] (and (hasattr x "startswith") (.startswith x "g!"))) (flatten body))))]] `(defmacro ~name [~@args] (let ~(HyList (map (fn [x] `[~x (gensym (slice '~x 2))]) syms)) ~@body)))) diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy index 571e824..848cd8f 100644 --- a/tests/native_tests/native_macros.hy +++ b/tests/native_tests/native_macros.hy @@ -188,7 +188,12 @@ (setv s2 (to_source _ast2)) (assert (in ":res_" s1)) (assert (in ":res_" s2)) - (assert (not (= s1 s2)))) + (assert (not (= s1 s2))) + + ;; defmacro/g! didn't like numbers initially because they + ;; don't have a startswith method and blew up during expansion + (setv macro2 "(defmacro/g! two-point-zero [] `(+ (float 1) 1.0))") + (assert (import_buffer_to_ast macro2 "foo"))) (defn test-if-not [] From a102a268a9bd33e8be81b35bebc73357119b020c Mon Sep 17 00:00:00 2001 From: Bertie Wheen Date: Sat, 17 May 2014 18:46:01 +0100 Subject: [PATCH 28/46] Rephrased confusing comment --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 28c13ba..8bcf285 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -305,7 +305,7 @@ Some example usage: Yeah, really! ;; assuming that (side-effect) is a function that we want to call for each - ;; and every value in the list, but which return values we do not care + ;; and every value in the list, but whose return value we do not care about => (list-comp (do (side-effect x) ... (if (< x 5) (* 2 x) ... (* 4 x))) From 02fa2511751ba2acb03cfb61ff0015b63f296956 Mon Sep 17 00:00:00 2001 From: Bertie Wheen Date: Sat, 17 May 2014 19:04:41 +0100 Subject: [PATCH 29/46] Minor typo Sorry for tiny commits :P --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 28c13ba..2521b95 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -416,7 +416,7 @@ Parameters may have following keywords in front of them: arguments may be specified after this one. The following code example defines a function that can be given 0 to n - numerical parameters. It then sums every odd number and substracts + numerical parameters. It then sums every odd number and subtracts every even number. .. code-block:: clj From 1da6d0af43958a63e5dfc088ebf6db30d6812d9f Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Fri, 23 May 2014 23:03:38 +0530 Subject: [PATCH 30/46] docs: fix decorator to reflect multiple decorators * docs/language/api.rst: the `with-decorator' builtin supports multiple decorators which it applies in order. Docs are updated to reflect this --- docs/language/api.rst | 45 +++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index f5d50b2..9097910 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -1293,23 +1293,48 @@ file is automatically closed after it has been processed. with-decorator -------------- -`with-decorator` is used to wrap a function with another. The function performing -decoration should accept a single value, the function being decorated and return -a new function. `with-decorator` takes two parameters, the function performing -decoration and the function being decorated. - -In the following example, `inc-decorator` is used to decorate function `addition` -with a function that takes two parameters and calls the decorated function with -values that are incremented by 1. When decorated `addition` is called with values -1 and 1, the end result will be 4 (1+1 + 1+1). +`with-decorator` is used to wrap a function with another. The function +performing decoration should accept a single value, the function being +decorated and return a new function. `with-decorator` takes a minimum +of two parameters, the function performing decoration and the function +being decorated. More than one decorator function can be applied, they +will be applied in order from outermost to innermost, ie. the first +decorator will be the outermost one & so on. Decorators with arguments +are called just like a function call. .. code-block:: clj - => (defn inc-decorator [func] + (with-decorator decorator-fun + (defn some-function [] ...) + + (with-decorator decorator1 decorator2 ... + (defn some-function [] ...) + + (with-decorator (decorator arg) .. + (defn some-function [] ...) + + + +In the following example, `inc-decorator` is used to decorate function +`addition` with a function that takes two parameters and calls the +decorated function with values that are incremented by 1. When +decorated `addition` is called with values 1 and 1, the end result +will be 4 (1+1 + 1+1). + +.. code-block:: clj + + => (defn inc-decorator [func] ... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1)))) + => (defn inc2-decorator [func] + ... (fn [value-1 value-2] (func (+ value-1 2) (+ value-2 2)))) + => (with-decorator inc-decorator (defn addition [a b] (+ a b))) => (addition 1 1) 4 + => (with-decorator inc2-decorator inc-decorator + ... (defn addition [a b] (+ a b))) + => (addition 1 1) + 8 .. _with-gensyms: From c2982a9ae34d2fe45d962d511f6210c168b7d186 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Thu, 15 May 2014 23:41:24 +0530 Subject: [PATCH 31/46] anaphoric: fix first & last when conditions fail * hy/contrib/anaphoric.hy: `ap-first` and `ap-last` now handle cases when failure happens for the predicate. Thanks to @tutorto for reporting this bug --- hy/contrib/anaphoric.hy | 18 ++++++++++-------- tests/native_tests/contrib/anaphoric.hy | 6 ++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/hy/contrib/anaphoric.hy b/hy/contrib/anaphoric.hy index 5a6b236..5000cbf 100644 --- a/hy/contrib/anaphoric.hy +++ b/hy/contrib/anaphoric.hy @@ -84,18 +84,20 @@ (defmacro ap-first [predfn lst] "Yield the first element that passes `predfn`" - `(let [[n (gensym)]] - (ap-each ~lst (when ~predfn (setv n it) (break))) - n)) + (with-gensyms [n] + `(let [[~n None]] + (ap-each ~lst (when ~predfn (setv ~n it) (break))) + ~n))) (defmacro ap-last [predfn lst] "Yield the last element that passes `predfn`" - `(let [[n (gensym)]] - (ap-each ~lst (none? n) - (when ~predfn - (setv n it))) - n)) + (with-gensyms [n] + `(let [[~n None]] + (ap-each ~lst (none? ~n) + (when ~predfn + (setv ~n it))) + ~n))) (defmacro ap-reduce [form lst &optional [initial-value None]] diff --git a/tests/native_tests/contrib/anaphoric.hy b/tests/native_tests/contrib/anaphoric.hy index 3d67e82..50281fa 100644 --- a/tests/native_tests/contrib/anaphoric.hy +++ b/tests/native_tests/contrib/anaphoric.hy @@ -87,12 +87,14 @@ (defn test-ap-first [] "NATIVE: testing anaphoric first" (assert-equal (ap-first (> it 5) (range 10)) 6) - (assert-equal (ap-first (even? it) [1 2 3 4]) 2)) + (assert-equal (ap-first (even? it) [1 2 3 4]) 2) + (assert-equal (ap-first (> it 10) (range 10)) None)) (defn test-ap-last [] "NATIVE: testing anaphoric last" (assert-equal (ap-last (> it 5) (range 10)) 9) - (assert-equal (ap-last (even? it) [1 2 3 4]) 4)) + (assert-equal (ap-last (even? it) [1 2 3 4]) 4) + (assert-equal (ap-last (> it 10) (range 10)) None)) (defn test-ap-reduce [] "NATIVE: testing anaphoric reduce" From 8e173937c358e3f53415b3df8ff163a3f524f6a5 Mon Sep 17 00:00:00 2001 From: James King Date: Fri, 16 May 2014 12:58:57 -0400 Subject: [PATCH 32/46] Add shadow.hy to core This new core module allows us to shadow the builtin Python operators so they may be passed to sequence functions that expect functions: => (map / [1 2 3 4 5]) [1.0, 0.5, 0.3333333333333333, 0.25] --- hy/core/__init__.py | 3 +- hy/core/language.hy | 19 ++++++----- hy/core/shadow.hy | 61 ++++++++++++++++++++++++++++++++++++ tests/native_tests/shadow.hy | 41 ++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 hy/core/shadow.hy create mode 100644 tests/native_tests/shadow.hy diff --git a/hy/core/__init__.py b/hy/core/__init__.py index d5349f3..be885ce 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -1,3 +1,4 @@ STDLIB = [ - "hy.core.language" + "hy.core.language", + "hy.core.shadow" ] diff --git a/hy/core/language.hy b/hy/core/language.hy index 262a45a..fe921b7 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -92,7 +92,8 @@ (setv map itertools.imap) (setv zip itertools.izip) (setv range xrange) - (setv input raw_input)) + (setv input raw_input) + (setv reduce reduce)) (do (setv reduce functools.reduce) (setv filterfalse itertools.filterfalse) @@ -331,10 +332,12 @@ (_numeric_check n) (= n 0)) -(def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct - disassemble drop drop-while empty? even? every? first filter - flatten float? gensym identity inc instance? integer - integer? integer-char? iterable? iterate iterator? keyword? - list* macroexpand macroexpand-1 map neg? nil? none? nth - numeric? odd? pos? range remove repeat repeatedly rest second - some string string? take take-nth take-while zero? zip zipwith]) +(def *exports* '[butlast calling-module-name coll? cons cons? cycle + dec distinct disassemble drop drop-while empty? even? + every? first filter flatten float? gensym identity + inc instance? integer integer? integer-char? + iterable? iterate iterator? keyword? list* + macroexpand macroexpand-1 map neg? nil? none? nth + numeric? odd? pos? range remove repeat repeatedly + rest reduce second some string string? take take-nth + take-while zero? zip zipwith]) diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy new file mode 100644 index 0000000..f59f0ca --- /dev/null +++ b/hy/core/shadow.hy @@ -0,0 +1,61 @@ +;; Copyright (c) 2014 Paul Tagliamonte +;; Copyright (c) 2014 James King + +;; 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. + +;;;; Hy shadow functions + +(import operator) + + +(defn + [&rest args] + "Shadow + operator for when we need to import / map it against something" + (if (= (len args) 0) + 0 + (sum args))) ; shortcut here. + + +(defn - [&rest args] + "Shadow - operator for when we need to import / map it against something" + (let [[count (len args)]] + (if (= count 0) + (raise (TypeError "Need at least 1 argument to subtract")) + (if (= count 1) + (- (get args 0)) + (reduce operator.sub args))))) + + +(defn * [&rest args] + "Shadow * operator for when we need to import / map it against something" + (if (= (len args) 0) + 1 ; identity + (reduce operator.mul args))) + + +(defn / [&rest args] + "Shadow / operator for when we need to import / map it against something" + (let [[count (len args)]] + (if (= count 0) + (raise (TypeError "Need at least 1 argument to divide")) + (if (= count 1) + (operator.truediv 1 (get args 0)) + (reduce operator.truediv args))))) + + +(setv *exports* ['+ '- '* '/]) diff --git a/tests/native_tests/shadow.hy b/tests/native_tests/shadow.hy new file mode 100644 index 0000000..362ac50 --- /dev/null +++ b/tests/native_tests/shadow.hy @@ -0,0 +1,41 @@ + + +(defn test-shadow-addition [] + "NATIVE: test shadow addition" + (let [[x +]] + (assert (= (x) 0)) + (assert (= (x 1 2 3 4) 10)) + (assert (= (x 1 2 3 4 5) 15)))) + + +(defn test-shadow-subtraction [] + "NATIVE: test shadow subtraction" + (let [[x -]] + (assert (try + (x) + (catch [TypeError] True) + (else (throw AssertionError)))) + (assert (= (x 1) -1)) + (assert (= (x 2 1) 1)) + (assert (= (x 2 1 1) 0)))) + + +(defn test-shadow-multiplication [] + "NATIVE: test shadow multiplication" + (let [[x *]] + (assert (= (x) 1)) + (assert (= (x 3) 3)) + (assert (= (x 3 3) 9)))) + + +(defn test-shadow-division [] + "NATIVE: test shadow division" + (let [[x /]] + (assert (try + (x) + (catch [TypeError] True) + (else (throw AssertionError)))) + (assert (= (x 1) 1)) + (assert (= (x 8 2) 4)) + (assert (= (x 8 2 2) 2)) + (assert (= (x 8 2 2 2) 1)))) From 277028cdd5990e5cde4a1bfdfe3434fdcec842a2 Mon Sep 17 00:00:00 2001 From: James King Date: Tue, 3 Jun 2014 21:36:49 -0400 Subject: [PATCH 33/46] Remove HyLambdaListKeyword from the parser It's not a syntactic element and doesn't belong in the parser. Parsing lambda lists is now handled by the compiler alone. --- hy/__init__.py | 1 - hy/compiler.py | 9 +++----- hy/lex/parser.py | 4 ---- hy/models/lambdalist.py | 39 ---------------------------------- tests/lex/test_lex.py | 9 -------- tests/native_tests/language.hy | 7 ++++++ tests/native_tests/quote.hy | 6 ------ 7 files changed, 10 insertions(+), 65 deletions(-) delete mode 100644 hy/models/lambdalist.py diff --git a/hy/__init__.py b/hy/__init__.py index f3a26a1..120a9d9 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -23,7 +23,6 @@ from hy.version import __version__, __appname__ # NOQA from hy.models.expression import HyExpression # NOQA -from hy.models.lambdalist import HyLambdaListKeyword # NOQA from hy.models.integer import HyInteger # NOQA from hy.models.keyword import HyKeyword # NOQA from hy.models.complex import HyComplex # NOQA diff --git a/hy/compiler.py b/hy/compiler.py index fa44676..d177138 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -24,7 +24,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.expression import HyExpression from hy.models.keyword import HyKeyword from hy.models.integer import HyInteger @@ -430,6 +429,7 @@ class HyASTCompiler(object): def _parse_lambda_list(self, exprs): """ Return FunctionDef parameter values from lambda list.""" + ll_keywords = ("&rest", "&optional", "&key", "&kwargs") ret = Result() args = [] defaults = [] @@ -439,10 +439,7 @@ class HyASTCompiler(object): for expr in exprs: - if isinstance(expr, HyLambdaListKeyword): - if expr not in expr._valid_types: - raise HyTypeError(expr, "{0} is not a valid " - "lambda-keyword.".format(repr(expr))) + if expr in ll_keywords: if expr == "&rest" and lambda_keyword is None: lambda_keyword = expr elif expr == "&optional": @@ -616,7 +613,7 @@ class HyASTCompiler(object): return imports, ret.replace(form), False - elif isinstance(form, (HySymbol, HyLambdaListKeyword)): + elif isinstance(form, HySymbol): return imports, HyExpression([HySymbol(name), HyString(form)]).replace(form), False diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 0f3a96a..30793f2 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -30,7 +30,6 @@ from hy.models.expression import HyExpression from hy.models.float import HyFloat from hy.models.integer import HyInteger from hy.models.keyword import HyKeyword -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.list import HyList from hy.models.string import HyString from hy.models.symbol import HySymbol @@ -271,9 +270,6 @@ def t_identifier(p): if obj.startswith(":"): return HyKeyword(obj) - if obj.startswith("&"): - return HyLambdaListKeyword(obj) - def mangle(p): if p.startswith("*") and p.endswith("*") and p not in ("*", "**"): p = p[1:-1].upper() diff --git a/hy/models/lambdalist.py b/hy/models/lambdalist.py deleted file mode 100644 index 1a38066..0000000 --- a/hy/models/lambdalist.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2013 James King -# -# 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 hy.models.string import HyString - - -class HyLambdaListKeyword(HyString): - """ - Hy LambdaListKeyword. Demarcates arguments in an argument list. - - (defun my-fun (x &rest xs &optional (foo "default string"))) - - becomes: - - def my_fun(x, *xs, foo="default string"): - pass - """ - - _valid_types = ["&rest", "&optional", "&key", "&kwargs"] - - def __init__(self, string): - self += string diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index 7ab30e5..ebf0404 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -21,7 +21,6 @@ from hy.models.expression import HyExpression from hy.models.integer import HyInteger -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.float import HyFloat from hy.models.complex import HyComplex from hy.models.symbol import HySymbol @@ -85,14 +84,6 @@ def test_lex_expression_integer(): assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])] -def test_lex_lambda_list_keyword(): - """ Make sure expressions can produce lambda list keywords """ - objs = tokenize("(x &rest xs)") - assert objs == [HyExpression([HySymbol("x"), - HyLambdaListKeyword("&rest"), - HySymbol("xs")])] - - def test_lex_symbols(): """ Make sure that symbols are valid expressions""" objs = tokenize("foo ") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 8bff65c..b655ba6 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -975,3 +975,10 @@ "NATIVE: test keyword quoting magic" (assert (= :foo "\ufdd0:foo")) (assert (= `:foo "\ufdd0:foo"))) + +(defn test-only-parse-lambda-list-in-defn [] + "NATIVE: test lambda lists are only parsed in defn" + (try + (foo [&rest spam] 1) + (catch [NameError] True) + (else (raise AssertionError)))) diff --git a/tests/native_tests/quote.hy b/tests/native_tests/quote.hy index 8900578..c1c0859 100644 --- a/tests/native_tests/quote.hy +++ b/tests/native_tests/quote.hy @@ -77,12 +77,6 @@ (assert (= q qq))) -(defn test-quote-lambdalistkeyword [] - "NATIVE: test quoting lambda list keywords" - (setv opt (quote &optional)) - (assert (isinstance opt hy.HyLambdaListKeyword)) - (assert (= (str opt) "&optional"))) - (defmacro doodle [&rest body] `(do ~@body)) From fb7c7e5794c1b4956528bd8e0a0f50f4305f8c3b Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 10:19:56 -0600 Subject: [PATCH 34/46] Fix #607, remove return from try when there is a generator inside Added the contains_yield attr to 'try' when the body it is wrapping contains 'yeild'. Should also address #600 and #563 --- hy/compiler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index d177138..a4297e8 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1,10 +1,10 @@ # -*- encoding: utf-8 -*- # -# Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013, 2014 Paul Tagliamonte # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Nicolas Dandrimont # Copyright (c) 2013 James King -# Copyright (c) 2013 Bob Tolbert +# Copyright (c) 2013, 2014 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -704,7 +704,8 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - returnable = Result(expr=expr_name, temp_variables=[expr_name, name]) + returnable = Result(expr=expr_name, temp_variables=[expr_name, name], + contains_yield=body.contains_yield) body += ast.Assign(targets=[name], value=body.force_expr, From ea5eba59165df74b36351c1acd54126e08b2ff5a Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 14:33:39 -0600 Subject: [PATCH 35/46] Second part of the fix for yield inside a try-finally As noted in #600, Python 3 allows a return inside a generator method, that raises a StopIteration and passes the return value inside the 'value' attr of the exception. To allow this behaviour we simple set 'contains_yield' while compiling 'yield', thus allowing a return statement, but only for Python 3. Then when compiling the try-except, we check for contains_yield to decide whether there will be a return. This allows code like: (defn gen [] (yield 3) "goodbye") to compile in both Py2 and Py3. The return value is simply ignored in Python 2. hy2py in Python 2 gives: def g(): yield 3L u'goodbye' while hy2py in Python 3 gives: def g(): yield 3 return 'goodbye' Turns out return in yield started in Python 3.3 --- hy/compiler.py | 5 ++++- tests/native_tests/language.hy | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index a4297e8..a82d89e 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -997,7 +997,10 @@ class HyASTCompiler(object): @checkargs(max=1) def compile_yield_expression(self, expr): expr.pop(0) - ret = Result(contains_yield=True) + if PY33: + ret = Result(contains_yield=False) + else: + ret = Result(contains_yield=True) value = None if expr != []: diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index b655ba6..7db5320 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -3,6 +3,7 @@ [sys :as systest]) (import sys) +(import [hy._compat [PY33 PY34]]) (defn test-sys-argv [] "NATIVE: test sys.argv" @@ -448,6 +449,29 @@ (for [y (gen)] (setv ret (+ ret y))) (assert (= ret 10))) +(defn test-yield-with-return [] + "NATIVE: test yield with return" + (defn gen [] (yield 3) "goodbye") + (if PY33 + (do (setv gg (gen)) + (assert (= 3 (next gg))) + (try (next gg) + (except [e StopIteration] (assert (hasattr e "value")) + (assert (= (getattr e "value") "goodbye"))))) + (do (setv gg (gen)) + (assert (= 3 (next gg))) + (try (next gg) + (except [e StopIteration] (assert (not (hasattr e "value")))))))) + + +(defn test-yield-in-try [] + "NATIVE: test yield in try" + (defn gen [] + (let [[x 1]] + (try (yield x) + (finally (print x))))) + (setv output (list (gen))) + (assert (= [1] output))) (defn test-first [] "NATIVE: test firsty things" From bd661a3ae8fa54c21166d3601e83d5a0c15d7967 Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 18:08:04 -0600 Subject: [PATCH 36/46] Fix hy2py output on Windows/Python 3 If there are Unicode symbols in the hy2py output (as in tests/native_test/language.hy) and the user is on Windows, and the user is using Python3 and the user doesn't have an appropriate codepage in the terminal for Unicode, then hy2py will fail at encoding the output. This fix makes sure that if encoding fails, the bytes output is shown instead of throwing an exception and failing completely. This also allows the hy2py tests to pass on Windows. If the user does activate an appropriate codepage, for example, chcp 65001 then the Unicode output will show correctly. Converted printing code to small function to eliminate some duplicate code --- hy/cmdline.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index a29d901..51417b2 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -47,7 +47,7 @@ from hy.models.expression import HyExpression from hy.models.string import HyString from hy.models.symbol import HySymbol -from hy._compat import builtins +from hy._compat import builtins, PY3 class HyQuitter(object): @@ -327,6 +327,7 @@ def hyc_main(): # entry point for cmd line script "hy2py" def hy2py_main(): + import platform module_name = "" options = dict(prog="hy2py", usage="%(prog)s [options] FILE", @@ -349,17 +350,42 @@ def hy2py_main(): if options.with_source: hst = import_file_to_hst(options.args[0]) - print(hst) + # need special printing on Windows in case the + # codepage doesn't support utf-8 characters + if PY3 and platform.system() == "Windows": + for h in hst: + try: + print(h) + except: + print(str(h).encode('utf-8')) + else: + print(hst) print() print() _ast = import_file_to_ast(options.args[0], module_name) if options.with_ast: - print(astor.dump(_ast)) + if PY3 and platform.system() == "Windows": + _print_for_windows(astor.dump(_ast)) + else: + print(astor.dump(_ast)) print() print() if not options.without_python: - print(astor.codegen.to_source(_ast)) + if PY3 and platform.system() == "Windows": + _print_for_windows(astor.codegen.to_source(_ast)) + else: + print(astor.codegen.to_source(_ast)) parser.exit(0) + + +# need special printing on Windows in case the +# codepage doesn't support utf-8 characters +def _print_for_windows(src): + for line in src.split("\n"): + try: + print(line) + except: + print(line.encode('utf-8')) From 16e908d56e4b73183a95880df358c1076c89be11 Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 29 Jun 2014 11:19:22 -0600 Subject: [PATCH 37/46] In order to fix #608, we need to know which symbols can't be assigned. Python has the keyword.iskeyword method we can leverage for Python keywords, but we also need to address Hy builtins like 'get' or 'slice'. And to make behavior compatible with Python 2 or 3, we also make a special case to prevent assignment to False, True or None as well as the Hy versions: false, true, null, and nil. For non-Hy modules, we also check to make sure the symbol is not part of the compiler. This allows shadow.hy to override "+" but prevents general use from re-defn-ing 'get' or 'do'. --- hy/compiler.py | 22 ++++++++++++++++++++++ tests/native_tests/language.hy | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/hy/compiler.py b/hy/compiler.py index a82d89e..b1fd266 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -47,6 +47,7 @@ import importlib import codecs import ast import sys +import keyword from collections import defaultdict @@ -73,6 +74,21 @@ def load_stdlib(): _stdlib[e] = module +# True, False and None included here since they +# are assignable in Python 2.* but become +# keywords in Python 3.* +def _is_hy_builtin(name, module_name): + extras = ['True', 'False', 'None', + 'true', 'false', 'nil', 'null'] + if name in extras or keyword.iskeyword(name): + return True + # for non-Hy modules, check for pre-existing name in + # _compile_table + if not module_name.startswith("hy."): + return name in _compile_table + return False + + _compile_table = {} @@ -1751,6 +1767,12 @@ class HyASTCompiler(object): def _compile_assign(self, name, result, start_line, start_column): + + str_name = "%s" % name + if _is_hy_builtin(str_name, self.module_name): + raise HyTypeError(name, + "Can't assign to a builtin: `%s'" % str_name) + result = self.compile(result) ld_name = self.compile(name) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 7db5320..b7888e2 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -28,6 +28,28 @@ (setv (get foo 0) 12) (assert (= (get foo 0) 12))) +(defn test-setv-builtin [] + "NATIVE: test that setv doesn't work on builtins" + (try (eval '(setv False 1)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv True 0)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv None 1)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv false 1)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv true 0)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv nil 1)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(setv null 1)) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(defn defclass [] (print "hello"))) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(defn get [] (print "hello"))) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) + (try (eval '(defn lambda [] (print "hello"))) + (catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))) (defn test-for-loop [] "NATIVE: test for loops" From c8c154f725fd31eadb5d907463fa0efcd557786d Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Thu, 10 Jul 2014 13:06:23 -0600 Subject: [PATCH 38/46] Update Dockerfile to use the "python:3" base image, which simplifies things --- Dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7ec7336..6e60ac8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,10 @@ # Base image # -# VERSION 0.1 -FROM debian:unstable +# VERSION 0.2 +FROM python:3 MAINTAINER Paul R. Tagliamonte -RUN apt-get update && apt-get install -y python3.4 python3-pip ADD . /opt/hylang/hy -RUN python3.4 /usr/bin/pip3 install -e /opt/hylang/hy +RUN pip3 install -e /opt/hylang/hy CMD ["hy"] From f94381b7e390e0c487184a559a173b644918f8b1 Mon Sep 17 00:00:00 2001 From: han semaj Date: Mon, 21 Jul 2014 23:01:18 +1200 Subject: [PATCH 39/46] Export filterfalse/input/zip_longest --- hy/core/language.hy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index fe921b7..0ecbe26 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -334,10 +334,10 @@ (def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct disassemble drop drop-while empty? even? - every? first filter flatten float? gensym identity - inc instance? integer integer? integer-char? + every? first filter filterfalse flatten float? gensym identity + inc input instance? integer integer? integer-char? iterable? iterate iterator? keyword? list* macroexpand macroexpand-1 map neg? nil? none? nth numeric? odd? pos? range remove repeat repeatedly rest reduce second some string string? take take-nth - take-while zero? zip zipwith]) + take-while zero? zip zip_longest zipwith]) From 2628653380b1431476479b27e6b749026efe1802 Mon Sep 17 00:00:00 2001 From: han semaj Date: Mon, 21 Jul 2014 23:07:59 +1200 Subject: [PATCH 40/46] Remove 'remove' (duplicate of 'filterfalse') --- hy/core/language.hy | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hy/core/language.hy b/hy/core/language.hy index 0ecbe26..d7ee3ec 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -111,6 +111,7 @@ (setv drop-while itertools.dropwhile) (setv take-while itertools.takewhile) (setv zipwith map) +(setv remove filterfalse) (defn drop [count coll] "Drop `count` elements from `coll` and yield back the rest" @@ -275,13 +276,6 @@ (_numeric_check n) (> n 0)) -(defn remove [pred coll] - "Return coll with elements removed that pass `pred`" - (let [[citer (iter coll)]] - (for* [val citer] - (if (not (pred val)) - (yield val))))) - (defn rest [coll] "Get all the elements of a coll, except the first." (drop 1 coll)) From 79a1ea6667f77cce08282089da5b3989039ef3e0 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Thu, 24 Jul 2014 20:51:43 -0400 Subject: [PATCH 41/46] *cough* From 45e0ff16ca9b3e1c91463dd8ece9fadc288d7d57 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Tue, 5 Aug 2014 00:10:14 +0530 Subject: [PATCH 42/46] Add a simple .mailmap file --- .mailmap | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..678f585 --- /dev/null +++ b/.mailmap @@ -0,0 +1,12 @@ +Paul R. Tagliamonte Paul Tagliamonte +Paul R. Tagliamonte Paul Tagliamonte +Paul R. Tagliamonte Paul Tagliamonte +Paul R. Tagliamonte Paul Tagliamonte +Morten Linderud Foxboron +Morten Linderud +James King agentultra +James King J Kenneth King +Abhishek L +Bob Tolbert Bob Tolbert +Guillermo Vaya Guillermo Vaya +Gergely Nagy Gergely Nagy \ No newline at end of file From f7675c829efe1a5f376d9eff49c112c0762264ac Mon Sep 17 00:00:00 2001 From: Foxboron Date: Thu, 24 Jul 2014 20:44:55 +0200 Subject: [PATCH 43/46] Added read and tests --- docs/language/core.rst | 26 ++++++++++++++++++++++++++ hy/core/language.hy | 21 ++++++++++++++++++++- tests/native_tests/language.hy | 27 +++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/docs/language/core.rst b/docs/language/core.rst index 42070cf..a51b488 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -862,6 +862,32 @@ Return an iterator of `x`, `fn(x)`, `fn(fn(x))`. [5, 25, 625, 390625, 152587890625] +.. _read-fn: + +read +---- + +Usage: ``(read [stdin eof])`` + +Reads the given form and parses it to hy. Takes optional argument +for a different stdin object or eof byte. Throws `EOFError` when +stdin is empty. + +.. code-block:: hy + => (read) + (+ 2 2) + ('+' 2 2) + => (eval (read)) + (+ 2 2) + 4 + => (import io) + => (def buffer (io.StringIO "(+ 2 2)\n(- 2 1)")) + => (eval (apply read [] {"stdin" buffer})) + 4 + => (eval (apply read [] {"stdin" buffer})) + 1 + + .. _remove-fn: remove diff --git a/hy/core/language.hy b/hy/core/language.hy index d7ee3ec..d6a3837 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -26,8 +26,10 @@ (import itertools) (import functools) (import collections) +(import sys) (import [hy._compat [long-type]]) ; long for python2, int for python3 (import [hy.models.cons [HyCons]]) +(import [hy.lex [LexException PrematureEndOfInput tokenize]]) (defn _numeric-check [x] @@ -326,12 +328,29 @@ (_numeric_check n) (= n 0)) +(defn read [&optional [stdin sys.stdin] + [eof ""]] + "Read from input and returns a tokenized string. + Can take a given input buffer to read from" + (def buff "") + (while true + (def inn (str (.read stdin 1))) + (if (= inn eof) + (throw (EOFError "Reached end of file" ))) + (setv buff (+ buff inn)) + (try + (def parsed (first (tokenize buff))) + (except [e [LexException PrematureEndOfInput IndexError]]) + (else (if parsed (break))))) + parsed) + + (def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct disassemble drop drop-while empty? even? every? first filter filterfalse flatten float? gensym identity inc input instance? integer integer? integer-char? iterable? iterate iterator? keyword? list* macroexpand macroexpand-1 map neg? nil? none? nth - numeric? odd? pos? range remove repeat repeatedly + numeric? odd? pos? range read remove repeat repeatedly rest reduce second some string string? take take-nth take-while zero? zip zip_longest zipwith]) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index b7888e2..9955394 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1028,3 +1028,30 @@ (foo [&rest spam] 1) (catch [NameError] True) (else (raise AssertionError)))) + +(defn test-read [] + "NATIVE: test that read takes something for stdin and reads" + (if-python2 + (import [StringIO [StringIO]]) + (import [io [StringIO]])) + (import [hy.models.expression [HyExpression]]) + + (def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)")) + (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 4)) + (assert (isinstance (apply read [] {"stdin" stdin-buffer}) HyExpression)) + + "Multiline test" + (def stdin-buffer (StringIO "(\n+\n41\n1\n)\n(-\n2\n1\n)")) + (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 42)) + (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 1)) + + "EOF test" + (def stdin-buffer (StringIO "(+ 2 2)")) + (apply read [] {"stdin" stdin-buffer}) + (try + (apply read [] {"stdin" stdin-buffer}) + (catch [e Exception] + (print e) + (assert (isinstance e EOFError))))) + + From d5668403aef3868bb4b328daa95ab965f3841efd Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Tue, 12 Aug 2014 23:44:35 +0530 Subject: [PATCH 44/46] Typo fix s/reprsntation/representation --- hy/models/complex.py | 2 +- hy/models/float.py | 2 +- hy/models/integer.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hy/models/complex.py b/hy/models/complex.py index 9647997..26ac863 100644 --- a/hy/models/complex.py +++ b/hy/models/complex.py @@ -23,7 +23,7 @@ from hy.models import HyObject class HyComplex(HyObject, complex): """ - Internal represntation of a Hy Complex. May raise a ValueError as if + Internal representation of a Hy Complex. May raise a ValueError as if complex(foo) was called, given HyComplex(foo). """ diff --git a/hy/models/float.py b/hy/models/float.py index 184c3a3..ffcf455 100644 --- a/hy/models/float.py +++ b/hy/models/float.py @@ -23,7 +23,7 @@ from hy.models import HyObject class HyFloat(HyObject, float): """ - Internal represntation of a Hy Float. May raise a ValueError as if + Internal representation of a Hy Float. May raise a ValueError as if float(foo) was called, given HyFloat(foo). """ diff --git a/hy/models/integer.py b/hy/models/integer.py index 0eacef7..614520f 100644 --- a/hy/models/integer.py +++ b/hy/models/integer.py @@ -24,7 +24,7 @@ from hy._compat import long_type class HyInteger(HyObject, long_type): """ - Internal represntation of a Hy Integer. May raise a ValueError as if + Internal representation of a Hy Integer. May raise a ValueError as if int(foo) was called, given HyInteger(foo). On python 2.x long will be used instead """ From c8adf9b726f166332a1f9462071f81724a24614f Mon Sep 17 00:00:00 2001 From: Foxboron Date: Thu, 14 Aug 2014 18:18:05 +0200 Subject: [PATCH 45/46] Renamed stdin -> from-file and removed apply from tests + docs --- docs/language/core.rst | 13 +++++++------ hy/core/language.hy | 4 ++-- tests/native_tests/language.hy | 13 ++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/language/core.rst b/docs/language/core.rst index a51b488..8b2fec1 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -867,11 +867,12 @@ Return an iterator of `x`, `fn(x)`, `fn(fn(x))`. read ---- -Usage: ``(read [stdin eof])`` +Usage: ``(read [from-file eof])`` -Reads the given form and parses it to hy. Takes optional argument -for a different stdin object or eof byte. Throws `EOFError` when -stdin is empty. +Reads the next hy expression from `from-file` (defaults to `sys.stdin`), and +can take a single byte as EOF (defaults to an empty string). +Raises an `EOFError` if `from-file` ends before a complete expression can be +parsed. .. code-block:: hy => (read) @@ -882,9 +883,9 @@ stdin is empty. 4 => (import io) => (def buffer (io.StringIO "(+ 2 2)\n(- 2 1)")) - => (eval (apply read [] {"stdin" buffer})) + => (eval (apply read [] {"from_file" buffer})) 4 - => (eval (apply read [] {"stdin" buffer})) + => (eval (apply read [] {"from_file" buffer})) 1 diff --git a/hy/core/language.hy b/hy/core/language.hy index d6a3837..3b208e6 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -328,13 +328,13 @@ (_numeric_check n) (= n 0)) -(defn read [&optional [stdin sys.stdin] +(defn read [&optional [from-file sys.stdin] [eof ""]] "Read from input and returns a tokenized string. Can take a given input buffer to read from" (def buff "") (while true - (def inn (str (.read stdin 1))) + (def inn (str (.read from-file 1))) (if (= inn eof) (throw (EOFError "Reached end of file" ))) (setv buff (+ buff inn)) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 9955394..cc104fa 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1037,21 +1037,20 @@ (import [hy.models.expression [HyExpression]]) (def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)")) - (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 4)) - (assert (isinstance (apply read [] {"stdin" stdin-buffer}) HyExpression)) + (assert (= (eval (read stdin-buffer)) 4)) + (assert (isinstance (read stdin-buffer) HyExpression)) "Multiline test" (def stdin-buffer (StringIO "(\n+\n41\n1\n)\n(-\n2\n1\n)")) - (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 42)) - (assert (= (eval (apply read [] {"stdin" stdin-buffer})) 1)) + (assert (= (eval (read stdin-buffer)) 42)) + (assert (= (eval (read stdin-buffer)) 1)) "EOF test" (def stdin-buffer (StringIO "(+ 2 2)")) - (apply read [] {"stdin" stdin-buffer}) + (read stdin-buffer) (try - (apply read [] {"stdin" stdin-buffer}) + (read stdin-buffer) (catch [e Exception] - (print e) (assert (isinstance e EOFError))))) From 3f1a24bfe3cca61eff1e87d7e40c65f31c12120a Mon Sep 17 00:00:00 2001 From: han semaj Date: Sun, 17 Aug 2014 14:53:57 +1200 Subject: [PATCH 46/46] Implement interleave and interpose --- docs/language/core.rst | 40 ++++++++++++++++++++++++++++++++++++++ hy/core/language.hy | 12 ++++++++++-- tests/native_tests/core.hy | 27 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/docs/language/core.rst b/docs/language/core.rst index 42070cf..e0785a0 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -290,6 +290,46 @@ either ``int`` or ``long``. For Python 3, this is ``int``. False +.. _interleave-fn: + +interleave +---------- + +.. versionadded:: 0.10.1 + +Usage: ``(interleave seq1 seq2 ...)`` + +Return an iterable of the first item in each of the sequences, then the second etc. + +.. code-block:: hy + + => (list (interleave (range 5) (range 100 105))) + [0, 100, 1, 101, 2, 102, 3, 103, 4, 104] + + => (list (interleave (range 1000000) "abc")) + [0, 'a', 1, 'b', 2, 'c'] + + +.. _interpose-fn: + +interpose +--------- + +.. versionadded:: 0.10.1 + +Usage: ``(interpose item seq)`` + +Return an iterable of the elements of the sequence separated by the item. + +.. code-block:: hy + + => (list (interpose "!" "abcd")) + ['a', '!', 'b', '!', 'c', '!', 'd'] + + => (list (interpose -1 (range 5))) + [0, -1, 1, -1, 2, -1, 3, -1, 4] + + .. _iterable?-fn: iterable? diff --git a/hy/core/language.hy b/hy/core/language.hy index d7ee3ec..e74bc8a 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -209,6 +209,14 @@ (catch [e ValueError] False) (catch [e TypeError] False))) +(defn interleave [&rest seqs] + "Return an iterable of the first item in each of seqs, then the second etc." + (itertools.chain.from_iterable (apply zip seqs))) + +(defn interpose [item seq] + "Return an iterable of the elements of seq separated by item" + (drop 1 (interleave (itertools.repeat item) seq))) + (defn iterable? [x] "Return true if x is iterable" (isinstance x collections.Iterable)) @@ -329,8 +337,8 @@ (def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct disassemble drop drop-while empty? even? every? first filter filterfalse flatten float? gensym identity - inc input instance? integer integer? integer-char? - iterable? iterate iterator? keyword? list* + inc input instance? integer integer? integer-char? interleave + interpose iterable? iterate iterator? keyword? list* macroexpand macroexpand-1 map neg? nil? none? nth numeric? odd? pos? range remove repeat repeatedly rest reduce second some string string? take take-nth diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index 3a3239a..a4042b6 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -266,6 +266,33 @@ (assert-false (integer-char? "foo")) (assert-false (integer-char? None))) +(defn test-interleave [] + "NATIVE: testing the interleave function" + ;; with more than 2 sequences + (assert-equal (list (take 9 (interleave (range 10) + (range 10 20) + (range 20 30)))) + [0 10 20 1 11 21 2 12 22]) + ;; with sequences of different length + (assert-equal (list (interleave (range 1000000) + (range 0 -3 -1))) + [0 0 1 -1 2 -2]) + ;; with infinite sequences + (import itertools) + (assert-equal (list (take 10 (interleave (itertools.count) + (itertools.count 100)))) + [0 100 1 101 2 102 3 103 4 104])) + +(defn test-interpose [] + "NATIVE: testing the interpose function" + ;; with a list + (assert-equal (list (interpose "!" ["a" "b" "c"])) + ["a" "!" "b" "!" "c"]) + ;; with an infinite sequence + (import itertools) + (assert-equal (list (take 7 (interpose -1 (itertools.count)))) + [0 -1 1 -1 2 -1 3])) + (defn test-iterable [] "NATIVE: testing iterable? function" ;; should work for a string