Introduce for/a* and for/a expressions
This commit is contained in:
parent
783d53ecb7
commit
1e4ad3167b
@ -1,7 +1,7 @@
|
||||
import _pytest
|
||||
import hy
|
||||
import os
|
||||
from hy._compat import PY3, PY35
|
||||
from hy._compat import PY3, PY35, PY36
|
||||
|
||||
NATIVE_TESTS = os.path.join("", "tests", "native_tests", "")
|
||||
|
||||
@ -10,7 +10,8 @@ def pytest_collect_file(parent, path):
|
||||
and NATIVE_TESTS in path.dirname + os.sep
|
||||
and path.basename != "__init__.hy"
|
||||
and not ("py3_only" in path.basename and not PY3)
|
||||
and not ("py35_only" in path.basename and not PY35)):
|
||||
and not ("py35_only" in path.basename and not PY35)
|
||||
and not ("py36_only" in path.basename and not PY36)):
|
||||
m = _pytest.python.pytest_pycollect_makemodule(path, parent)
|
||||
# Spoof the module name to avoid hitting an assertion in pytest.
|
||||
m.name = m.name[:-len(".hy")] + ".py"
|
||||
|
@ -22,6 +22,7 @@ import sys
|
||||
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
PY35 = sys.version_info >= (3, 5)
|
||||
PY36 = sys.version_info >= (3, 6)
|
||||
|
||||
str_type = str if PY3 else unicode # NOQA
|
||||
bytes_type = bytes if PY3 else str # NOQA
|
||||
|
@ -1830,16 +1830,16 @@ class HyASTCompiler(object):
|
||||
return result
|
||||
|
||||
@builds("for*")
|
||||
@builds("for/a*", iff=PY35)
|
||||
@checkargs(min=1)
|
||||
def compile_for_expression(self, expression):
|
||||
expression.pop(0) # for
|
||||
root = expression.pop(0)
|
||||
|
||||
args = expression.pop(0)
|
||||
|
||||
if not isinstance(args, HyList):
|
||||
raise HyTypeError(expression,
|
||||
"`for` expects a list, received `{0}`".format(
|
||||
type(args).__name__))
|
||||
"`{0}` expects a list, received `{1}`".format(
|
||||
root, type(args).__name__))
|
||||
|
||||
try:
|
||||
target_name, iterable = args
|
||||
@ -1864,11 +1864,12 @@ class HyASTCompiler(object):
|
||||
body = self._compile_branch(expression)
|
||||
body += body.expr_as_stmt()
|
||||
|
||||
ret += asty.For(expression,
|
||||
target=target,
|
||||
iter=ret.force_expr,
|
||||
body=body.stmts,
|
||||
orelse=orel.stmts)
|
||||
node = asty.For if root == 'for*' else asty.AsyncFor
|
||||
ret += node(expression,
|
||||
target=target,
|
||||
iter=ret.force_expr,
|
||||
body=body.stmts,
|
||||
orelse=orel.stmts)
|
||||
|
||||
ret.contains_yield = body.contains_yield
|
||||
|
||||
|
@ -108,11 +108,7 @@ used as the result."
|
||||
root)))
|
||||
|
||||
|
||||
(defmacro for [args &rest body]
|
||||
"Build a for-loop with `args` as a [element coll] bracket pair and run `body`.
|
||||
|
||||
Args may contain multiple pairs, in which case it executes a nested for-loop
|
||||
in order of the given pairs."
|
||||
(defmacro _for [node args &rest body]
|
||||
(setv body (list body))
|
||||
(if (empty? body)
|
||||
(macro-error None "`for' requires a body to evaluate"))
|
||||
@ -124,10 +120,26 @@ in order of the given pairs."
|
||||
(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 ~@belse)
|
||||
(= (len args) 2) `(for* [~@args] (do ~@body) ~@belse)
|
||||
(= (len args) 2) `(~node [~@args] (do ~@body) ~@belse)
|
||||
(do
|
||||
(setv alist (cut args 0 None 2))
|
||||
`(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))))
|
||||
`(~node [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))))
|
||||
|
||||
|
||||
(defmacro for [args &rest body]
|
||||
"Build a for-loop with `args` as a [element coll] bracket pair and run `body`.
|
||||
|
||||
Args may contain multiple pairs, in which case it executes a nested for-loop
|
||||
in order of the given pairs."
|
||||
`(_for for* ~args ~@body))
|
||||
|
||||
|
||||
(defmacro for/a [args &rest body]
|
||||
"Build a for/a-loop with `args` as a [element coll] bracket pair and run `body`.
|
||||
|
||||
Args may contain multiple pairs, in which case it executes a nested for/a-loop
|
||||
in order of the given pairs."
|
||||
`(_for for/a* ~args ~@body))
|
||||
|
||||
|
||||
(defmacro -> [head &rest rest]
|
||||
|
39
tests/native_tests/py36_only_tests.hy
Normal file
39
tests/native_tests/py36_only_tests.hy
Normal file
@ -0,0 +1,39 @@
|
||||
;; Copyright 2017 the authors.
|
||||
;; This file is part of Hy, which is free software licensed under the Expat
|
||||
;; license. See the LICENSE.
|
||||
|
||||
;; Tests where the emitted code relies on Python ≥3.6.
|
||||
;; conftest.py skips this file when running on Python <3.6.
|
||||
|
||||
(import [asyncio [get-event-loop sleep]])
|
||||
|
||||
|
||||
(defn run-coroutine [coro]
|
||||
"Run a coroutine until its done in the default event loop."""
|
||||
(.run_until_complete (get-event-loop) (coro)))
|
||||
|
||||
|
||||
(defn test-for/a []
|
||||
(defn/a numbers []
|
||||
(for [i [1 2]]
|
||||
(yield i)))
|
||||
|
||||
(run-coroutine
|
||||
(fn/a []
|
||||
(setv x 0)
|
||||
(for/a [a (numbers)]
|
||||
(setv x (+ x a)))
|
||||
(assert (= x 3)))))
|
||||
|
||||
(defn test-for/a-else []
|
||||
(defn/a numbers []
|
||||
(for [i [1 2]]
|
||||
(yield i)))
|
||||
|
||||
(run-coroutine
|
||||
(fn/a []
|
||||
(setv x 0)
|
||||
(for/a [a (numbers)]
|
||||
(setv x (+ x a))
|
||||
(else (setv x (+ x 50))))
|
||||
(assert (= x 53)))))
|
Loading…
x
Reference in New Issue
Block a user