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 * `defreader` has been renamed to `defsharp`; what were previously called
"reader macros", which were never true reader macros, are now called "reader macros", which were never true reader macros, are now called
"sharp macros" "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 * 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 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 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 body = body.stmts
orelse = [] if not all(expr):
finalbody = [] raise HyTypeError(expr, "Empty list not allowed in `try'")
handlers = []
handler_results = Result() handler_results = Result()
handlers = []
for e in expr: while expr and expr[0][0] == HySymbol("except"):
if not len(e): handler_results += self._compile_catch_expression(expr.pop(0),
raise HyTypeError(e, "Empty list not allowed in `try'") name)
handlers.append(handler_results.stmts.pop())
if e[0] == HySymbol("except"): orelse = []
handler_results += self._compile_catch_expression(e, name) if expr and expr[0][0] == HySymbol("else"):
handlers.append(handler_results.stmts.pop()) orelse = self.try_except_helper(expr.pop(0), HySymbol("else"))
elif e[0] == HySymbol("else"): finalbody = []
orelse = self.try_except_helper(e, HySymbol("else"), orelse) if expr and expr[0][0] == HySymbol("finally"):
elif e[0] == HySymbol("finally"): finalbody = self.try_except_helper(expr.pop(0), HySymbol("finally"))
finalbody = self.try_except_helper(e, HySymbol("finally"), if expr:
finalbody) if expr[0][0] in ("except", "else", "finally"):
else: raise HyTypeError(expr, "Incorrect order of `except'/`else'/`finally' in `try'")
raise HyTypeError(e, "Unknown expression in `try'") raise HyTypeError(expr, "Unknown expression in `try'")
# Using (else) without (except) is verboten! # Using (else) without (except) is verboten!
if orelse and not handlers: if orelse and not handlers:
raise HyTypeError( raise HyTypeError(
e, expr,
"`try' cannot have `else' without `except'") "`try' cannot have `else' without `except'")
# (try) or (try BODY) # (try) or (try BODY)
@ -868,16 +867,10 @@ class HyASTCompiler(object):
body=body, body=body,
orelse=orelse) + returnable orelse=orelse) + returnable
def try_except_helper(self, hy_obj, symbol, accumulated): def try_except_helper(self, hy_obj, symbol):
if accumulated: x = self._compile_branch(hy_obj[1:])
raise HyTypeError( x += x.expr_as_stmt()
hy_obj, return x.stmts
"`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
@builds("except") @builds("except")
def magic_internal_form(self, expr): def magic_internal_form(self, expr):

View File

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