Allow returning inside a try / except. Closes #163

This commit is contained in:
Paul Tagliamonte 2013-05-08 20:00:09 -04:00
parent ceedc69b7d
commit 058197a24f
3 changed files with 45 additions and 10 deletions

View File

@ -557,8 +557,24 @@ class HyASTCompiler(object):
# (try something…)
body = self.compile(body)
# XXX we will likely want to make this a tempvar
body += body.expr_as_stmt()
var = self.get_anon_var()
name = ast.Name(id=ast_str(var), arg=ast_str(var),
ctx=ast.Store(),
lineno=expr.start_line,
col_offset=expr.start_column)
expr_name = ast.Name(id=ast_str(var), arg=ast_str(var),
ctx=ast.Load(),
lineno=expr.start_line,
col_offset=expr.start_column)
returnable = Result(expr=expr_name, temp_variables=[expr_name, name])
body += ast.Assign(targets=[name],
value=body.force_expr,
lineno=expr.start_line,
col_offset=expr.start_column)
body = body.stmts
if not body:
body = [ast.Pass(lineno=expr.start_line,
@ -574,7 +590,7 @@ class HyASTCompiler(object):
raise HyTypeError(e, "Empty list not allowed in `try'")
if e[0] in (HySymbol("except"), HySymbol("catch")):
handler_results += self.compile(e)
handler_results += self._compile_catch_expression(e, var)
handlers.append(handler_results.stmts.pop())
elif e[0] == HySymbol("else"):
if orelse:
@ -626,7 +642,7 @@ class HyASTCompiler(object):
body=body,
handlers=handlers,
orelse=orelse,
finalbody=finalbody)
finalbody=finalbody) + returnable
if finalbody:
if handlers:
@ -639,30 +655,39 @@ class HyASTCompiler(object):
handlers=handlers,
body=body,
orelse=orelse)],
finalbody=finalbody)
finalbody=finalbody) + returnable
return ret + ast.TryFinally(
lineno=expr.start_line,
col_offset=expr.start_column,
body=body,
finalbody=finalbody)
finalbody=finalbody) + returnable
return ret + ast.TryExcept(
lineno=expr.start_line,
col_offset=expr.start_column,
handlers=handlers,
body=body,
orelse=orelse)
orelse=orelse) + returnable
@builds("catch")
@builds("except")
def compile_catch_expression(self, expr):
@builds("catch")
def magic_internal_form(self, expr):
raise TypeError("Error: `%s' can't be used like that." % (expr[0]))
def _compile_catch_expression(self, expr, var):
catch = expr.pop(0) # catch
ret_name = ast.Name(id=ast_str(var), arg=ast_str(var),
ctx=ast.Store(),
lineno=expr.start_line,
col_offset=expr.start_column)
try:
exceptions = expr.pop(0)
except IndexError:
exceptions = HyList()
# exceptions catch should be either:
# [[list of exceptions]]
# or
@ -673,6 +698,7 @@ class HyASTCompiler(object):
# [exception]
# or
# []
if not isinstance(exceptions, HyList):
raise HyTypeError(exceptions,
"`%s' exceptions list is not a list" % catch)
@ -720,7 +746,10 @@ class HyASTCompiler(object):
"`%s' needs a valid exception list" % catch)
body = self._compile_branch(expr)
# XXX tempvar handling magic
body += ast.Assign(targets=[ret_name],
value=body.force_expr,
lineno=expr.start_line,
col_offset=expr.start_column)
body += body.expr_as_stmt()
body = body.stmts

View File

@ -151,6 +151,7 @@ def test_ast_good_catch():
def test_ast_bad_catch():
"Make sure AST can't compile invalid catch"
cant_compile("(catch 22)") # heh
cant_compile("(try (catch 1))")
cant_compile("(try (catch \"A\"))")
cant_compile("(try (catch [1 3]))")
@ -170,6 +171,7 @@ def test_ast_good_except():
def test_ast_bad_except():
"Make sure AST can't compile invalid except"
cant_compile("(except 1)")
cant_compile("(try 1 (except 1))")
cant_compile("(try 1 (except [1 3]))")
cant_compile("(try 1 (except [x [FooBar] BarBar]))")

View File

@ -665,3 +665,7 @@
(if (if 0 True False)
42
43))))
(defn test-try-except-return []
"NATIVE: test we can return from in a try except"
(assert ((fn [] (try xxx (except [NameError] (+ 1 1)))))) 2)