Return from the else
clause of a try
form
I overhauled the documentation of `try` while I was editing it.
This commit is contained in:
parent
81d89c9d12
commit
dffa2811e6
3
NEWS
3
NEWS
@ -26,6 +26,9 @@ Changes from 0.12.1
|
|||||||
* `(** a b c d)` is now equivalent to `(** a (** b (** c d)))`,
|
* `(** a b c d)` is now equivalent to `(** a (** b (** c d)))`,
|
||||||
not `(** (** (** a b) c) d)`
|
not `(** (** (** a b) c) d)`
|
||||||
* `setv` always returns None
|
* `setv` always returns None
|
||||||
|
* When a `try` form executes an `else` clause, the return value for the
|
||||||
|
`try` form is taken from `else` instead of the `try` body. For example,
|
||||||
|
`(try 1 (except [ValueError] 2) (else 3))` returns `3`.
|
||||||
* xor: If exactly one argument is true, return it
|
* xor: If exactly one argument is true, return it
|
||||||
* hy.core.reserved is now hy.extra.reserved
|
* hy.core.reserved is now hy.extra.reserved
|
||||||
|
|
||||||
|
@ -1538,23 +1538,37 @@ or no arguments to re-raise the last ``Exception``.
|
|||||||
try
|
try
|
||||||
---
|
---
|
||||||
|
|
||||||
The ``try`` form is used to start a ``try`` / ``except`` block. The form is
|
The ``try`` form is used to catch exceptions (``except``) and run cleanup
|
||||||
used as follows:
|
actions (``finally``).
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
(try
|
(try
|
||||||
(error-prone-function)
|
(error-prone-function)
|
||||||
(except [e ZeroDivisionError] (print "Division by zero"))
|
(except [ZeroDivisionError]
|
||||||
(else (print "no errors"))
|
(print "Division by zero"))
|
||||||
(finally (print "all done")))
|
(except [[IndexError KeyboardInterrupt]]
|
||||||
|
(print "Index error or Ctrl-C"))
|
||||||
|
(except [e ValueError]
|
||||||
|
(print "ValueError:" (repr e)))
|
||||||
|
(except [e [TabError PermissionError ReferenceError]]
|
||||||
|
(print "Some sort of error:" (repr e)))
|
||||||
|
(else
|
||||||
|
(print "No errors"))
|
||||||
|
(finally
|
||||||
|
(print "All done")))
|
||||||
|
|
||||||
``try`` must contain at least one ``except`` block, and may optionally include
|
The first argument of ``try`` is its body. (To put more than one form in the
|
||||||
an ``else`` or ``finally`` block. If an error is raised with a matching except
|
body, use ``do``.) Then comes any number of ``except`` clauses, then optionally
|
||||||
block during the execution of ``error-prone-function``, that ``except`` block
|
an ``else`` clause, then optionally a ``finally`` clause. If an exception is
|
||||||
will be executed. If no errors are raised, the ``else`` block is executed. The
|
raised with a matching ``except`` clause during the execution of the body, that
|
||||||
``finally`` block will be executed last regardless of whether or not an error
|
``except`` clause will be executed. If no exceptions are raised, the ``else``
|
||||||
was raised.
|
clause is executed. The ``finally`` clause will be executed last regardless of
|
||||||
|
whether an exception was raised.
|
||||||
|
|
||||||
|
The return value of ``try`` is the last form of the ``except`` clause that was
|
||||||
|
run, or the last form of ``else`` if no exception was raised, or the ``try``
|
||||||
|
body if there is no ``else`` clause.
|
||||||
|
|
||||||
|
|
||||||
unless
|
unless
|
||||||
|
@ -786,13 +786,6 @@ class HyASTCompiler(object):
|
|||||||
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)
|
contains_yield=body.contains_yield)
|
||||||
|
|
||||||
body += ast.Assign(targets=[name],
|
|
||||||
value=body.force_expr,
|
|
||||||
lineno=expr.start_line,
|
|
||||||
col_offset=expr.start_column)
|
|
||||||
|
|
||||||
body = body.stmts
|
|
||||||
|
|
||||||
if not all(expr):
|
if not all(expr):
|
||||||
raise HyTypeError(expr, "Empty list not allowed in `try'")
|
raise HyTypeError(expr, "Empty list not allowed in `try'")
|
||||||
handler_results = Result()
|
handler_results = Result()
|
||||||
@ -803,13 +796,22 @@ class HyASTCompiler(object):
|
|||||||
handlers.append(handler_results.stmts.pop())
|
handlers.append(handler_results.stmts.pop())
|
||||||
orelse = []
|
orelse = []
|
||||||
if expr and expr[0][0] == HySymbol("else"):
|
if expr and expr[0][0] == HySymbol("else"):
|
||||||
orelse = self.try_except_helper(expr.pop(0), HySymbol("else"))
|
orelse = self._compile_branch(expr.pop(0)[1:])
|
||||||
|
orelse += ast.Assign(targets=[name],
|
||||||
|
value=orelse.force_expr,
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)
|
||||||
|
orelse += orelse.expr_as_stmt()
|
||||||
|
orelse = orelse.stmts
|
||||||
finalbody = []
|
finalbody = []
|
||||||
if expr and expr[0][0] == HySymbol("finally"):
|
if expr and expr[0][0] == HySymbol("finally"):
|
||||||
finalbody = self.try_except_helper(expr.pop(0), HySymbol("finally"))
|
finalbody = self._compile_branch(expr.pop(0)[1:])
|
||||||
|
finalbody += finalbody.expr_as_stmt()
|
||||||
|
finalbody = finalbody.stmts
|
||||||
if expr:
|
if expr:
|
||||||
if expr[0][0] in ("except", "else", "finally"):
|
if expr[0][0] in ("except", "else", "finally"):
|
||||||
raise HyTypeError(expr, "Incorrect order of `except'/`else'/`finally' in `try'")
|
raise HyTypeError(expr, "Incorrect order "
|
||||||
|
"of `except'/`else'/`finally' in `try'")
|
||||||
raise HyTypeError(expr, "Unknown expression in `try'")
|
raise HyTypeError(expr, "Unknown expression in `try'")
|
||||||
|
|
||||||
# Using (else) without (except) is verboten!
|
# Using (else) without (except) is verboten!
|
||||||
@ -831,6 +833,14 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
ret = handler_results
|
ret = handler_results
|
||||||
|
|
||||||
|
body += body.expr_as_stmt() if orelse else ast.Assign(
|
||||||
|
targets=[name],
|
||||||
|
value=body.force_expr,
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)
|
||||||
|
body = body.stmts or [ast.Pass(lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)]
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
# Python 3.3 features a merge of TryExcept+TryFinally into Try.
|
# Python 3.3 features a merge of TryExcept+TryFinally into Try.
|
||||||
return ret + ast.Try(
|
return ret + ast.Try(
|
||||||
@ -867,11 +877,6 @@ class HyASTCompiler(object):
|
|||||||
body=body,
|
body=body,
|
||||||
orelse=orelse) + returnable
|
orelse=orelse) + returnable
|
||||||
|
|
||||||
def try_except_helper(self, hy_obj, symbol):
|
|
||||||
x = self._compile_branch(hy_obj[1:])
|
|
||||||
x += x.expr_as_stmt()
|
|
||||||
return x.stmts
|
|
||||||
|
|
||||||
@builds("except")
|
@builds("except")
|
||||||
def magic_internal_form(self, expr):
|
def magic_internal_form(self, expr):
|
||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
|
@ -1174,20 +1174,34 @@
|
|||||||
(assert (= foo 4)))
|
(assert (= foo 4)))
|
||||||
|
|
||||||
|
|
||||||
#@(pytest.mark.xfail
|
|
||||||
(defn test-try-else-return []
|
(defn test-try-else-return []
|
||||||
"NATIVE: test that we can return from the `else` clause of a `try`"
|
"NATIVE: test that we can return from the `else` clause of a `try`"
|
||||||
; https://github.com/hylang/hy/issues/798
|
; https://github.com/hylang/hy/issues/798
|
||||||
|
|
||||||
(assert (= "ef" ((fn []
|
(assert (= "ef" ((fn []
|
||||||
(try (+ "a" "b")
|
(try (+ "a" "b")
|
||||||
(except [NameError] (+ "c" "d"))
|
(except [NameError] (+ "c" "d"))
|
||||||
(else (+ "e" "f")))))))
|
(else (+ "e" "f")))))))
|
||||||
|
|
||||||
(setv foo
|
(setv foo
|
||||||
(try (+ "A" "B")
|
(try (+ "A" "B")
|
||||||
(except [NameError] (+ "C" "D"))
|
(except [NameError] (+ "C" "D"))
|
||||||
(else (+ "E" "F"))))
|
(else (+ "E" "F"))))
|
||||||
(assert (= foo "EF"))))
|
(assert (= foo "EF"))
|
||||||
|
|
||||||
|
; Check that the lvalue isn't assigned in the main `try` body
|
||||||
|
; there's an `else`.
|
||||||
|
(setv x 1)
|
||||||
|
(setv y 0)
|
||||||
|
(setv x
|
||||||
|
(try (+ "G" "H")
|
||||||
|
(except [NameError] (+ "I" "J"))
|
||||||
|
(else
|
||||||
|
(setv y 1)
|
||||||
|
(assert (= x 1))
|
||||||
|
(+ "K" "L"))))
|
||||||
|
(assert (= x "KL"))
|
||||||
|
(assert (= y 1)))
|
||||||
|
|
||||||
(defn test-require []
|
(defn test-require []
|
||||||
"NATIVE: test requiring macros from python code"
|
"NATIVE: test requiring macros from python code"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user