Enforce the standard order of try elements

This commit is contained in:
Kodi Arfer 2017-05-13 18:52:59 -04:00 committed by Ryan Gonzalez
parent 0d2749d5cd
commit 81d89c9d12
3 changed files with 31 additions and 32 deletions

4
NEWS
View File

@ -8,6 +8,10 @@ Changes from 0.12.1
* `defreader` has been renamed to `defsharp`; what were previously called
"reader macros", which were never true reader macros, are now called
"sharp macros"
* `try` now enforces the usual Python order for its elements (`else` must
follow all `except`s, and `finally` must come last). This is only a
syntactic change; the elements were already run in Python order even when
defined out of order.
* Importing or executing a Hy file automatically byte-compiles it, or loads
a byte-compiled version if it exists and is up to date. This brings big
speed boosts, even for one-liners, because Hy no longer needs to recompile

View File

@ -793,30 +793,29 @@ class HyASTCompiler(object):
body = body.stmts
orelse = []
finalbody = []
handlers = []
if not all(expr):
raise HyTypeError(expr, "Empty list not allowed in `try'")
handler_results = Result()
for e in expr:
if not len(e):
raise HyTypeError(e, "Empty list not allowed in `try'")
if e[0] == HySymbol("except"):
handler_results += self._compile_catch_expression(e, name)
handlers = []
while expr and expr[0][0] == HySymbol("except"):
handler_results += self._compile_catch_expression(expr.pop(0),
name)
handlers.append(handler_results.stmts.pop())
elif e[0] == HySymbol("else"):
orelse = self.try_except_helper(e, HySymbol("else"), orelse)
elif e[0] == HySymbol("finally"):
finalbody = self.try_except_helper(e, HySymbol("finally"),
finalbody)
else:
raise HyTypeError(e, "Unknown expression in `try'")
orelse = []
if expr and expr[0][0] == HySymbol("else"):
orelse = self.try_except_helper(expr.pop(0), HySymbol("else"))
finalbody = []
if expr and expr[0][0] == HySymbol("finally"):
finalbody = self.try_except_helper(expr.pop(0), HySymbol("finally"))
if expr:
if expr[0][0] in ("except", "else", "finally"):
raise HyTypeError(expr, "Incorrect order of `except'/`else'/`finally' in `try'")
raise HyTypeError(expr, "Unknown expression in `try'")
# Using (else) without (except) is verboten!
if orelse and not handlers:
raise HyTypeError(
e,
expr,
"`try' cannot have `else' without `except'")
# (try) or (try BODY)
@ -868,16 +867,10 @@ class HyASTCompiler(object):
body=body,
orelse=orelse) + returnable
def try_except_helper(self, hy_obj, symbol, accumulated):
if accumulated:
raise HyTypeError(
hy_obj,
"`try' cannot have more than one `%s'" % symbol)
else:
accumulated = self._compile_branch(hy_obj[1:])
accumulated += accumulated.expr_as_stmt()
accumulated = accumulated.stmts
return accumulated
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):

View File

@ -116,12 +116,11 @@ def test_ast_good_try():
can_compile("(try)")
can_compile("(try 1)")
can_compile("(try 1 (except) (else 1))")
can_compile("(try 1 (else 1) (except))")
can_compile("(try 1 (finally 1) (except))")
can_compile("(try 1 (finally 1))")
can_compile("(try 1 (except) (finally 1))")
can_compile("(try 1 (except) (finally 1) (else 1))")
can_compile("(try 1 (except [x]) (except [y]) (finally 1))")
can_compile("(try 1 (except) (else 1) (finally 1))")
can_compile("(try 1 (except [x]) (except [y]) (else 1) (finally 1))")
def test_ast_bad_try():
@ -130,6 +129,9 @@ def test_ast_bad_try():
cant_compile("(try 1 bla bla)")
cant_compile("(try (do) (else 1) (else 2))")
cant_compile("(try 1 (else 1))")
cant_compile("(try 1 (else 1) (except))")
cant_compile("(try 1 (finally 1) (except))")
cant_compile("(try 1 (except) (finally 1) (else 1))")
def test_ast_good_except():