Introduce with/a* and with/a expressions

This commit is contained in:
Simon Gomizelj 2017-12-30 17:25:26 -05:00
parent 2ffaa8e5be
commit 783d53ecb7
3 changed files with 84 additions and 18 deletions

View File

@ -1309,17 +1309,19 @@ class HyASTCompiler(object):
return ret + fn
@builds("with*")
@builds("with/a*", iff=PY35)
@checkargs(min=2)
def compile_with_expression(self, expr):
expr.pop(0) # with*
root = expr.pop(0)
args = expr.pop(0)
if not isinstance(args, HyList):
raise HyTypeError(expr,
"with expects a list, received `{0}'".format(
type(args).__name__))
"{0} expects a list, received `{1}'".format(
root, type(args).__name__))
if len(args) not in (1, 2):
raise HyTypeError(expr, "with needs [arg (expr)] or [(expr)]")
raise HyTypeError(expr,
"{0} needs [arg (expr)] or [(expr)]".format(root))
thing = None
if len(args) == 2:
@ -1338,10 +1340,11 @@ class HyASTCompiler(object):
expr, targets=[name], value=asty.Name(
expr, id=ast_str("None"), ctx=ast.Load()))
the_with = asty.With(expr,
context_expr=ctx.force_expr,
optional_vars=thing,
body=body.stmts)
node = asty.With if root == "with*" else asty.AsyncWith
the_with = node(expr,
context_expr=ctx.force_expr,
optional_vars=thing,
body=body.stmts)
if PY3:
the_with.items = [ast.withitem(context_expr=ctx.force_expr,

View File

@ -43,6 +43,19 @@ be associated in pairs."
other-kvs))]))))
(defmacro _with [node args &rest body]
(if (not (empty? args))
(do
(if (>= (len args) 2)
(do
(setv p1 (.pop args 0)
p2 (.pop args 0)
primary [p1 p2])
`(~node [~@primary] (_with ~node ~args ~@body)))
`(~node [~@args] ~@body)))
`(do ~@body)))
(defmacro with [args &rest body]
"Wrap execution of `body` within a context manager given as bracket `args`.
@ -51,16 +64,18 @@ Shorthand for nested with* loops:
(with* [x foo]
(with* [y bar]
baz))."
(if (not (empty? args))
(do
(if (>= (len args) 2)
(do
(setv p1 (.pop args 0)
p2 (.pop args 0)
primary [p1 p2])
`(with* [~@primary] (with ~args ~@body)))
`(with* [~@args] ~@body)))
`(do ~@body)))
`(_with with* ~args ~@body))
(defmacro with/a [args &rest body]
"Wrap execution of `body` with/ain a context manager given as bracket `args`.
Shorthand for nested with/a* loops:
(with/a [x foo y bar] baz) ->
(with/a* [x foo]
(with/a* [y bar]
baz))."
`(_with with/a* ~args ~@body))
(defmacro cond [&rest branches]

View File

@ -43,3 +43,51 @@
(await (sleep 0))
[1 2 3])
(assert (= (run-coroutine coro-test) [1 2 3])))
(defclass AsyncWithTest []
(defn --init-- [self val]
(setv self.val val)
None)
(defn/a --aenter-- [self]
self.val)
(defn/a --aexit-- [self tyle value traceback]
(setv self.val None)))
(defn test-single-with/a []
(run-coroutine
(fn/a []
(with/a [t (AsyncWithTest 1)]
(assert (= t 1))))))
(defn test-two-with/a []
(run-coroutine
(fn/a []
(with/a [t1 (AsyncWithTest 1)
t2 (AsyncWithTest 2)]
(assert (= t1 1))
(assert (= t2 2))))))
(defn test-thrice-with/a []
(run-coroutine
(fn/a []
(with/a [t1 (AsyncWithTest 1)
t2 (AsyncWithTest 2)
t3 (AsyncWithTest 3)]
(assert (= t1 1))
(assert (= t2 2))
(assert (= t3 3))))))
(defn test-quince-with/a []
(run-coroutine
(fn/a []
(with/a [t1 (AsyncWithTest 1)
t2 (AsyncWithTest 2)
t3 (AsyncWithTest 3)
_ (AsyncWithTest 4)]
(assert (= t1 1))
(assert (= t2 2))
(assert (= t3 3))))))