Merge pull request #1338 from Kodiologist/with-tempvar
Initialize the return variable of `with`
This commit is contained in:
commit
e8d7a6bc37
2
NEWS
2
NEWS
@ -27,6 +27,8 @@ Changes from 0.13.0
|
|||||||
* `exec` now works under Python 2
|
* `exec` now works under Python 2
|
||||||
* No TypeError from multi-arity defn returning values evaluating to None
|
* No TypeError from multi-arity defn returning values evaluating to None
|
||||||
* try form now possible in defmacro/deftag
|
* try form now possible in defmacro/deftag
|
||||||
|
* Fixed a crash when `with` suppresses an exception. `with` now returns
|
||||||
|
`None` in this case.
|
||||||
|
|
||||||
[ Misc. Improvements ]
|
[ Misc. Improvements ]
|
||||||
* `read`, `read_str`, and `eval` are exposed and documented as top-level
|
* `read`, `read_str`, and `eval` are exposed and documented as top-level
|
||||||
|
@ -1678,6 +1678,13 @@ screen. The file is automatically closed after it has been processed.
|
|||||||
|
|
||||||
(with [f (open "NEWS")] (print (.read f)))
|
(with [f (open "NEWS")] (print (.read f)))
|
||||||
|
|
||||||
|
``with`` returns the value of its last form, unless it suppresses an exception
|
||||||
|
(because the context manager's ``__exit__`` method returned true), in which
|
||||||
|
case it returns ``None``. So, the previous example could also be written
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(print (with [f (open "NEWS")] (.read f)))
|
||||||
|
|
||||||
with-decorator
|
with-decorator
|
||||||
--------------
|
--------------
|
||||||
|
@ -1452,29 +1452,36 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
"with expects a list, received `{0}'".format(
|
"with expects a list, received `{0}'".format(
|
||||||
type(args).__name__))
|
type(args).__name__))
|
||||||
if len(args) < 1:
|
if len(args) not in (1, 2):
|
||||||
raise HyTypeError(expr, "with needs [[arg (expr)]] or [[(expr)]]]")
|
raise HyTypeError(expr, "with needs [arg (expr)] or [(expr)]")
|
||||||
|
|
||||||
args.reverse()
|
|
||||||
ctx = self.compile(args.pop(0))
|
|
||||||
|
|
||||||
thing = None
|
thing = None
|
||||||
if args != []:
|
if len(args) == 2:
|
||||||
thing = self._storeize(args[0], self.compile(args.pop(0)))
|
thing = self._storeize(args[0], self.compile(args.pop(0)))
|
||||||
|
ctx = self.compile(args.pop(0))
|
||||||
|
|
||||||
body = self._compile_branch(expr)
|
body = self._compile_branch(expr)
|
||||||
|
|
||||||
|
# Store the result of the body in a tempvar
|
||||||
var = self.get_anon_var()
|
var = self.get_anon_var()
|
||||||
name = ast.Name(id=ast_str(var), arg=ast_str(var),
|
name = ast.Name(id=ast_str(var), arg=ast_str(var),
|
||||||
ctx=ast.Store(),
|
ctx=ast.Store(),
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column)
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
# Store the result of the body in a tempvar
|
|
||||||
body += ast.Assign(targets=[name],
|
body += ast.Assign(targets=[name],
|
||||||
value=body.force_expr,
|
value=body.force_expr,
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column)
|
col_offset=expr.start_column)
|
||||||
|
# Initialize the tempvar to None in case the `with` exits
|
||||||
|
# early with an exception.
|
||||||
|
initial_assign = ast.Assign(targets=[name],
|
||||||
|
value=ast.Name(
|
||||||
|
id=ast_str("None"),
|
||||||
|
ctx=ast.Load(),
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column),
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
the_with = ast.With(context_expr=ctx.force_expr,
|
the_with = ast.With(context_expr=ctx.force_expr,
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
@ -1486,7 +1493,7 @@ class HyASTCompiler(object):
|
|||||||
the_with.items = [ast.withitem(context_expr=ctx.force_expr,
|
the_with.items = [ast.withitem(context_expr=ctx.force_expr,
|
||||||
optional_vars=thing)]
|
optional_vars=thing)]
|
||||||
|
|
||||||
ret = ctx + the_with
|
ret = Result(stmts = [initial_assign]) + ctx + the_with
|
||||||
ret.contains_yield = ret.contains_yield or body.contains_yield
|
ret.contains_yield = ret.contains_yield or body.contains_yield
|
||||||
# And make our expression context our temp variable
|
# And make our expression context our temp variable
|
||||||
expr_name = ast.Name(id=ast_str(var), arg=ast_str(var),
|
expr_name = ast.Name(id=ast_str(var), arg=ast_str(var),
|
||||||
@ -1494,7 +1501,10 @@ class HyASTCompiler(object):
|
|||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column)
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
ret += Result(expr=expr_name, temp_variables=[expr_name, name])
|
ret += Result(expr=expr_name)
|
||||||
|
# We don't give the Result any temp_vars because we don't want
|
||||||
|
# Result.rename to touch `name`. Otherwise, initial_assign will
|
||||||
|
# clobber any preexisting value of the renamed-to variable.
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -34,12 +34,37 @@
|
|||||||
(assert (= t2 2))
|
(assert (= t2 2))
|
||||||
(assert (= t3 3))))
|
(assert (= t3 3))))
|
||||||
|
|
||||||
(defn test-quince-with []
|
(defn test-quince-with []
|
||||||
"NATIVE: test four withs, one with no args"
|
"NATIVE: test four withs, one with no args"
|
||||||
(with [t1 (WithTest 1)
|
(with [t1 (WithTest 1)
|
||||||
t2 (WithTest 2)
|
t2 (WithTest 2)
|
||||||
t3 (WithTest 3)
|
t3 (WithTest 3)
|
||||||
_ (WithTest 4)]
|
_ (WithTest 4)]
|
||||||
(assert (= t1 1))
|
(assert (= t1 1))
|
||||||
(assert (= t2 2))
|
(assert (= t2 2))
|
||||||
(assert (= t3 3))))
|
(assert (= t3 3))))
|
||||||
|
|
||||||
|
(defclass SuppressZDE [object]
|
||||||
|
(defn --enter-- [self])
|
||||||
|
(defn --exit-- [self exc-type exc-value traceback]
|
||||||
|
(and (not (none? exc-type)) (issubclass exc-type ZeroDivisionError))))
|
||||||
|
|
||||||
|
(defn test-exception-suppressing-with []
|
||||||
|
; https://github.com/hylang/hy/issues/1320
|
||||||
|
|
||||||
|
(setv x (with [(SuppressZDE)] 5))
|
||||||
|
(assert (= x 5))
|
||||||
|
|
||||||
|
(setv y (with [(SuppressZDE)] (/ 1 0)))
|
||||||
|
(assert (none? y))
|
||||||
|
|
||||||
|
(setv z (with [(SuppressZDE)] (/ 1 0) 5))
|
||||||
|
(assert (none? z))
|
||||||
|
|
||||||
|
(defn f [] (with [(SuppressZDE)] (/ 1 0)))
|
||||||
|
(assert (none? (f)))
|
||||||
|
|
||||||
|
(setv w 7 l [])
|
||||||
|
(setv w (with [(SuppressZDE)] (.append l w) (/ 1 0) 5))
|
||||||
|
(assert (none? w))
|
||||||
|
(assert (= l [7])))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user