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)))`,
|
||||
not `(** (** (** a b) c) d)`
|
||||
* `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
|
||||
* hy.core.reserved is now hy.extra.reserved
|
||||
|
||||
|
@ -1538,23 +1538,37 @@ or no arguments to re-raise the last ``Exception``.
|
||||
try
|
||||
---
|
||||
|
||||
The ``try`` form is used to start a ``try`` / ``except`` block. The form is
|
||||
used as follows:
|
||||
The ``try`` form is used to catch exceptions (``except``) and run cleanup
|
||||
actions (``finally``).
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(try
|
||||
(error-prone-function)
|
||||
(except [e ZeroDivisionError] (print "Division by zero"))
|
||||
(else (print "no errors"))
|
||||
(finally (print "all done")))
|
||||
(error-prone-function)
|
||||
(except [ZeroDivisionError]
|
||||
(print "Division by zero"))
|
||||
(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
|
||||
an ``else`` or ``finally`` block. If an error is raised with a matching except
|
||||
block during the execution of ``error-prone-function``, that ``except`` block
|
||||
will be executed. If no errors are raised, the ``else`` block is executed. The
|
||||
``finally`` block will be executed last regardless of whether or not an error
|
||||
was raised.
|
||||
The first argument of ``try`` is its body. (To put more than one form in the
|
||||
body, use ``do``.) Then comes any number of ``except`` clauses, then optionally
|
||||
an ``else`` clause, then optionally a ``finally`` clause. If an exception is
|
||||
raised with a matching ``except`` clause during the execution of the body, that
|
||||
``except`` clause will be executed. If no exceptions are raised, the ``else``
|
||||
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
|
||||
|
@ -786,13 +786,6 @@ class HyASTCompiler(object):
|
||||
returnable = Result(expr=expr_name, temp_variables=[expr_name, name],
|
||||
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):
|
||||
raise HyTypeError(expr, "Empty list not allowed in `try'")
|
||||
handler_results = Result()
|
||||
@ -803,13 +796,22 @@ class HyASTCompiler(object):
|
||||
handlers.append(handler_results.stmts.pop())
|
||||
orelse = []
|
||||
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 = []
|
||||
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[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'")
|
||||
|
||||
# Using (else) without (except) is verboten!
|
||||
@ -831,6 +833,14 @@ class HyASTCompiler(object):
|
||||
|
||||
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:
|
||||
# Python 3.3 features a merge of TryExcept+TryFinally into Try.
|
||||
return ret + ast.Try(
|
||||
@ -867,11 +877,6 @@ class HyASTCompiler(object):
|
||||
body=body,
|
||||
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")
|
||||
def magic_internal_form(self, expr):
|
||||
raise HyTypeError(expr,
|
||||
|
@ -1174,20 +1174,34 @@
|
||||
(assert (= foo 4)))
|
||||
|
||||
|
||||
#@(pytest.mark.xfail
|
||||
(defn test-try-else-return []
|
||||
"NATIVE: test that we can return from the `else` clause of a `try`"
|
||||
; https://github.com/hylang/hy/issues/798
|
||||
|
||||
(assert (= "ef" ((fn []
|
||||
(try (+ "a" "b")
|
||||
(except [NameError] (+ "c" "d"))
|
||||
(else (+ "e" "f")))))))
|
||||
|
||||
(setv foo
|
||||
(try (+ "A" "B")
|
||||
(except [NameError] (+ "C" "D"))
|
||||
(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 []
|
||||
"NATIVE: test requiring macros from python code"
|
||||
|
Loading…
Reference in New Issue
Block a user