diff --git a/docs/language/api.rst b/docs/language/api.rst index 57f6029..2250760 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -1227,6 +1227,20 @@ infinite series without consuming infinite amount of memory. => (list-comp x [x (take 15 (random-numbers 1 50))])]) [7, 41, 6, 22, 32, 17, 5, 38, 18, 38, 17, 14, 23, 23, 19] + +yield-from +---------- + +.. versionadded:: 0.9.13 + +**PYTHON 3.3 AND UP ONLY!** + +`yield-from` is used to call a subgenerator. This is useful if you +want your coroutine to be able to delegate its processes to another +coroutine, say if using something fancy like +`asyncio `_. + + .. _zipwith: zipwith diff --git a/hy/compiler.py b/hy/compiler.py index dbb4782..2122ea9 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1017,6 +1017,28 @@ class HyASTCompiler(object): return ret + @builds("yield_from") + @checkargs(max=1) + def compile_yield_from_expression(self, expr): + if not PY33: + raise HyCompileError( + "yield-from only supported in python 3.3+!") + + expr.pop(0) + ret = Result(contains_yield=True) + + value = None + if expr != []: + ret += self.compile(expr.pop(0)) + value = ret.force_expr + + ret += ast.YieldFrom( + value=value, + lineno=expr.start_line, + col_offset=expr.start_column) + + return ret + @builds("import") def compile_import_expression(self, expr): def _compile_import(expr, module, names=None, importer=ast.Import): diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 531350e..69567cf 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -27,8 +27,8 @@ (import [hy.models.list [HyList]] - [hy.models.symbol [HySymbol]]) - + [hy.models.symbol [HySymbol]] + [hy._compat [PY33 PY34]]) (defmacro for [args &rest body] @@ -155,12 +155,6 @@ `(if-not ~test (do ~@body))) -(defmacro yield-from [iterable] - "Yield all the items from iterable" - (let [[x (gensym)]] - `(for* [~x ~iterable] - (yield ~x)))) - (defmacro with-gensyms [args &rest body] `(let ~(HyList (map (fn [x] `[~x (gensym '~x)]) args)) ~@body)) diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy index 5bdf821..18dd588 100644 --- a/tests/native_tests/native_macros.hy +++ b/tests/native_tests/native_macros.hy @@ -1,3 +1,6 @@ +(import [hy._compat [PY33]]) +(import [hy.errors [HyCompileError]]) + (defmacro rev [&rest body] "Execute the `body` statements in reverse" (quasiquote (do (unquote-splice (list (reversed body)))))) @@ -99,11 +102,18 @@ (defn test-yield-from [] "NATIVE: testing yield from" - (defn yield-from-test [] - (for* [i (range 3)] - (yield i)) - (yield-from [1 2 3])) - (assert (= (list (yield-from-test)) [0 1 2 1 2 3]))) + + (try + (eval + '(do (defn yield-from-test [] + (for* [i (range 3)] + (yield i)) + (yield-from [1 2 3])) + (assert (= (list (yield-from-test)) [0 1 2 1 2 3])))) + (catch [e HyCompileError] + ;; Yup, this should happen on non-Python3.3 thingies + (assert (not PY33))) + (else (assert PY33)))) (defn test-if-python2 [] (import sys)