Allow returning inside a try / except. Closes #163
This commit is contained in:
parent
ceedc69b7d
commit
058197a24f
@ -557,8 +557,24 @@ class HyASTCompiler(object):
|
|||||||
# (try something…)
|
# (try something…)
|
||||||
body = self.compile(body)
|
body = self.compile(body)
|
||||||
|
|
||||||
# XXX we will likely want to make this a tempvar
|
var = self.get_anon_var()
|
||||||
body += body.expr_as_stmt()
|
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
|
body = body.stmts
|
||||||
if not body:
|
if not body:
|
||||||
body = [ast.Pass(lineno=expr.start_line,
|
body = [ast.Pass(lineno=expr.start_line,
|
||||||
@ -574,7 +590,7 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(e, "Empty list not allowed in `try'")
|
raise HyTypeError(e, "Empty list not allowed in `try'")
|
||||||
|
|
||||||
if e[0] in (HySymbol("except"), HySymbol("catch")):
|
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())
|
handlers.append(handler_results.stmts.pop())
|
||||||
elif e[0] == HySymbol("else"):
|
elif e[0] == HySymbol("else"):
|
||||||
if orelse:
|
if orelse:
|
||||||
@ -626,7 +642,7 @@ class HyASTCompiler(object):
|
|||||||
body=body,
|
body=body,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
orelse=orelse,
|
orelse=orelse,
|
||||||
finalbody=finalbody)
|
finalbody=finalbody) + returnable
|
||||||
|
|
||||||
if finalbody:
|
if finalbody:
|
||||||
if handlers:
|
if handlers:
|
||||||
@ -639,30 +655,39 @@ class HyASTCompiler(object):
|
|||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
body=body,
|
body=body,
|
||||||
orelse=orelse)],
|
orelse=orelse)],
|
||||||
finalbody=finalbody)
|
finalbody=finalbody) + returnable
|
||||||
|
|
||||||
return ret + ast.TryFinally(
|
return ret + ast.TryFinally(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
body=body,
|
body=body,
|
||||||
finalbody=finalbody)
|
finalbody=finalbody) + returnable
|
||||||
|
|
||||||
return ret + ast.TryExcept(
|
return ret + ast.TryExcept(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
body=body,
|
body=body,
|
||||||
orelse=orelse)
|
orelse=orelse) + returnable
|
||||||
|
|
||||||
@builds("catch")
|
|
||||||
@builds("except")
|
@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
|
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:
|
try:
|
||||||
exceptions = expr.pop(0)
|
exceptions = expr.pop(0)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
exceptions = HyList()
|
exceptions = HyList()
|
||||||
|
|
||||||
# exceptions catch should be either:
|
# exceptions catch should be either:
|
||||||
# [[list of exceptions]]
|
# [[list of exceptions]]
|
||||||
# or
|
# or
|
||||||
@ -673,6 +698,7 @@ class HyASTCompiler(object):
|
|||||||
# [exception]
|
# [exception]
|
||||||
# or
|
# or
|
||||||
# []
|
# []
|
||||||
|
|
||||||
if not isinstance(exceptions, HyList):
|
if not isinstance(exceptions, HyList):
|
||||||
raise HyTypeError(exceptions,
|
raise HyTypeError(exceptions,
|
||||||
"`%s' exceptions list is not a list" % catch)
|
"`%s' exceptions list is not a list" % catch)
|
||||||
@ -720,7 +746,10 @@ class HyASTCompiler(object):
|
|||||||
"`%s' needs a valid exception list" % catch)
|
"`%s' needs a valid exception list" % catch)
|
||||||
|
|
||||||
body = self._compile_branch(expr)
|
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.expr_as_stmt()
|
||||||
|
|
||||||
body = body.stmts
|
body = body.stmts
|
||||||
|
@ -151,6 +151,7 @@ def test_ast_good_catch():
|
|||||||
|
|
||||||
def test_ast_bad_catch():
|
def test_ast_bad_catch():
|
||||||
"Make sure AST can't compile invalid catch"
|
"Make sure AST can't compile invalid catch"
|
||||||
|
cant_compile("(catch 22)") # heh
|
||||||
cant_compile("(try (catch 1))")
|
cant_compile("(try (catch 1))")
|
||||||
cant_compile("(try (catch \"A\"))")
|
cant_compile("(try (catch \"A\"))")
|
||||||
cant_compile("(try (catch [1 3]))")
|
cant_compile("(try (catch [1 3]))")
|
||||||
@ -170,6 +171,7 @@ def test_ast_good_except():
|
|||||||
|
|
||||||
def test_ast_bad_except():
|
def test_ast_bad_except():
|
||||||
"Make sure AST can't compile invalid 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))")
|
||||||
cant_compile("(try 1 (except [1 3]))")
|
cant_compile("(try 1 (except [1 3]))")
|
||||||
cant_compile("(try 1 (except [x [FooBar] BarBar]))")
|
cant_compile("(try 1 (except [x [FooBar] BarBar]))")
|
||||||
|
@ -665,3 +665,7 @@
|
|||||||
(if (if 0 True False)
|
(if (if 0 True False)
|
||||||
42
|
42
|
||||||
43))))
|
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user