diff --git a/NEWS b/NEWS index b2a7106..2a26aed 100644 --- a/NEWS +++ b/NEWS @@ -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 [ Syntax Fixes ] diff --git a/hy/compiler.py b/hy/compiler.py index 962b535..39804a2 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -216,6 +216,7 @@ class HyASTCompiler(object): expr.start_line, expr.start_column) + orelse = [] if len(expr) == 0: # (try) or (try body) handlers = [ast.ExceptHandler( @@ -226,8 +227,27 @@ class HyASTCompiler(object): body=[ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)])] else: - # (try body except except…) - handlers = [self.compile(s) for s in expr] + handlers = [] + 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( lineno=expr.start_line, @@ -235,7 +255,7 @@ class HyASTCompiler(object): body=body, handlers=handlers, finalbody=[], - orelse=[]) + orelse=orelse) @builds("catch") @builds("except") diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 0f8a5d1..0bed73f 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -118,8 +118,16 @@ def test_ast_good_try(): "Make sure AST can compile valid try" hy_compile(tokenize("(try)")) hy_compile(tokenize("(try 1)")) - hy_compile(tokenize("(try 1 bla)")) - hy_compile(tokenize("(try 1 bla bla)")) + hy_compile(tokenize("(try 1 (except) (else 1))")) + 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(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index a47a525..c835605 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -255,7 +255,39 @@ (print foobar42ofthebaz) (catch [] (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 [] "NATIVE: Test earmuffs"