compiler: add else' support in try'

This is a bit tricky, since we'll also have to support `finally' in the end,
I've introduced an Else statement on my own to be able to recognize it.

This fixes #74

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2013-04-08 15:58:43 +02:00
parent 48d5a0abc0
commit f8131d3c36
4 changed files with 76 additions and 6 deletions

10
NEWS
View File

@ -1,3 +1,13 @@
Changes from Hy 0.9.4
[ Syntax Fixes ]
* `try' now accepts `else': (JD)
(try BODY
(except [] BODY)
(else BODY))
Changes from Hy 0.9.4 Changes from Hy 0.9.4
[ Syntax Fixes ] [ Syntax Fixes ]

View File

@ -199,6 +199,7 @@ class HyASTCompiler(object):
expr.start_line, expr.start_line,
expr.start_column) expr.start_column)
orelse = []
if len(expr) == 0: if len(expr) == 0:
# (try) or (try body) # (try) or (try body)
handlers = [ast.ExceptHandler( handlers = [ast.ExceptHandler(
@ -209,8 +210,27 @@ class HyASTCompiler(object):
body=[ast.Pass(lineno=expr.start_line, body=[ast.Pass(lineno=expr.start_line,
col_offset=expr.start_column)])] col_offset=expr.start_column)])]
else: else:
# (try body except except…) handlers = []
handlers = [self.compile(s) for s in expr] for e in expr:
if not len(e):
raise TypeError("Empty list not allowed in `try'")
if e[0] in (HySymbol("except"), HySymbol("catch")):
handlers.append(self.compile(e))
elif e[0] == HySymbol("else"):
if orelse:
raise TypeError(
"`try' cannot have more than one `else'")
else:
orelse = self._code_branch(self.compile(e[1:]),
e.start_line,
e.start_column)
else:
raise TypeError("Unknown expression in `try'")
if handlers == []:
raise TypeError(
"`try' must have at least `except' or `finally'")
return Try( return Try(
lineno=expr.start_line, lineno=expr.start_line,
@ -218,7 +238,7 @@ class HyASTCompiler(object):
body=body, body=body,
handlers=handlers, handlers=handlers,
finalbody=[], finalbody=[],
orelse=[]) orelse=orelse)
@builds("catch") @builds("catch")
@builds("except") @builds("except")

View File

@ -116,8 +116,16 @@ def test_ast_good_try():
"Make sure AST can compile valid try" "Make sure AST can compile valid try"
hy_compile(tokenize("(try)")) hy_compile(tokenize("(try)"))
hy_compile(tokenize("(try 1)")) hy_compile(tokenize("(try 1)"))
hy_compile(tokenize("(try 1 bla)")) hy_compile(tokenize("(try 1 (except) (else 1))"))
hy_compile(tokenize("(try 1 bla bla)")) hy_compile(tokenize("(try 1 (else 1) (except))"))
def test_ast_bad_try():
"Make sure AST can't compile invalid try"
cant_compile("(try 1 bla)")
cant_compile("(try 1 bla bla)")
cant_compile("(try (do) (else 1) (else 2))")
cant_compile("(try 1 (else 1))")
def test_ast_good_catch(): def test_ast_good_catch():

View File

@ -235,7 +235,39 @@
(print foobar42ofthebaz) (print foobar42ofthebaz)
(catch [] (catch []
(setv foobar42ofthebaz 42) (setv foobar42ofthebaz 42)
(assert (= foobar42ofthebaz 42))))) (assert (= foobar42ofthebaz 42))))
(let [[passed false]]
(try
(try (pass) (except) (else (bla)))
(except [NameError] (setv passed true)))
(assert passed))
(let [[x 0]]
(try
(raise IOError)
(except [IOError]
(setv x 45))
(else (setv x 44)))
(assert (= x 45)))
(let [[x 0]]
(try
(raise KeyError)
(except []
(setv x 45))
(else (setv x 44)))
(assert (= x 45)))
(let [[x 0]]
(try
(try
(raise KeyError)
(except [IOError]
(setv x 45))
(else (setv x 44)))
(except))
(assert (= x 0))))
(defn test-earmuffs [] (defn test-earmuffs []
"NATIVE: Test earmuffs" "NATIVE: Test earmuffs"