Use model patterns for try
This commit is contained in:
parent
79c02514b9
commit
11f1c149ef
159
hy/compiler.py
159
hy/compiler.py
@ -6,7 +6,7 @@
|
||||
from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex,
|
||||
HyString, HyBytes, HySymbol, HyFloat, HyList, HySet,
|
||||
HyDict, HySequence, wrap_value)
|
||||
from hy.model_patterns import FORM, SYM, sym, brackets, whole, notpexpr, dolike
|
||||
from hy.model_patterns import FORM, SYM, sym, brackets, whole, notpexpr, dolike, pexpr
|
||||
from funcparserlib.parser import many, oneplus, maybe, NoParseError
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
|
||||
@ -802,52 +802,41 @@ class HyASTCompiler(object):
|
||||
|
||||
return ret
|
||||
|
||||
@builds("try")
|
||||
@checkargs(min=2)
|
||||
def compile_try_expression(self, expr):
|
||||
expr = copy.deepcopy(expr)
|
||||
expr.pop(0) # try
|
||||
|
||||
# (try something somethingelse…)
|
||||
body = []
|
||||
# Check against HyExpression and HySymbol to avoid incorrectly
|
||||
# matching [except ...] or ("except" ...)
|
||||
while expr and not (isinstance(expr[0], HyExpression)
|
||||
and isinstance(expr[0][0], HySymbol)
|
||||
and expr[0][0] in ("except", "else", "finally")):
|
||||
body.append(expr.pop(0))
|
||||
@special("try",
|
||||
[many(notpexpr("except", "else", "finally")),
|
||||
many(pexpr(sym("except"),
|
||||
brackets() | brackets(FORM) | brackets(SYM, FORM),
|
||||
many(FORM))),
|
||||
maybe(dolike("else")),
|
||||
maybe(dolike("finally"))])
|
||||
def compile_try_expression(self, expr, root, body, catchers, orelse, finalbody):
|
||||
body = self._compile_branch(body)
|
||||
|
||||
var = self.get_anon_var()
|
||||
name = asty.Name(expr, id=ast_str(var), ctx=ast.Store())
|
||||
expr_name = asty.Name(expr, id=ast_str(var), ctx=ast.Load())
|
||||
|
||||
returnable = Result(expr=expr_name, temp_variables=[expr_name, name],
|
||||
contains_yield=body.contains_yield)
|
||||
return_var = asty.Name(
|
||||
expr, id=ast_str(self.get_anon_var()), ctx=ast.Store())
|
||||
|
||||
handler_results = Result()
|
||||
handlers = []
|
||||
while expr and expr[0][0] == HySymbol("except"):
|
||||
handler_results += self._compile_catch_expression(expr.pop(0),
|
||||
name)
|
||||
for catcher in catchers:
|
||||
handler_results += self._compile_catch_expression(
|
||||
catcher, return_var, *catcher)
|
||||
handlers.append(handler_results.stmts.pop())
|
||||
orelse = []
|
||||
if expr and expr[0][0] == HySymbol("else"):
|
||||
orelse = self._compile_branch(expr.pop(0)[1:])
|
||||
orelse += asty.Assign(expr, targets=[name],
|
||||
|
||||
if orelse is None:
|
||||
orelse = []
|
||||
else:
|
||||
orelse = self._compile_branch(orelse)
|
||||
orelse += asty.Assign(expr, targets=[return_var],
|
||||
value=orelse.force_expr)
|
||||
orelse += orelse.expr_as_stmt()
|
||||
orelse = orelse.stmts
|
||||
finalbody = []
|
||||
if expr and expr[0][0] == HySymbol("finally"):
|
||||
finalbody = self._compile_branch(expr.pop(0)[1:])
|
||||
|
||||
if finalbody is None:
|
||||
finalbody = []
|
||||
else:
|
||||
finalbody = self._compile_branch(finalbody)
|
||||
finalbody += finalbody.expr_as_stmt()
|
||||
finalbody = finalbody.stmts
|
||||
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:
|
||||
@ -860,50 +849,45 @@ class HyASTCompiler(object):
|
||||
expr,
|
||||
"`try' must have an `except' or `finally' clause")
|
||||
|
||||
ret = handler_results
|
||||
|
||||
returnable = Result(
|
||||
expr=asty.Name(expr, id=return_var.id, ctx=ast.Load()),
|
||||
temp_variables=[return_var],
|
||||
contains_yield=body.contains_yield)
|
||||
body += body.expr_as_stmt() if orelse else asty.Assign(
|
||||
expr, targets=[name], value=body.force_expr)
|
||||
expr, targets=[return_var], value=body.force_expr)
|
||||
body = body.stmts or [asty.Pass(expr)]
|
||||
|
||||
if PY3:
|
||||
# Python 3.3 features a merge of TryExcept+TryFinally into Try.
|
||||
return ret + asty.Try(
|
||||
x = asty.Try(
|
||||
expr,
|
||||
body=body,
|
||||
handlers=handlers,
|
||||
orelse=orelse,
|
||||
finalbody=finalbody) + returnable
|
||||
|
||||
if finalbody:
|
||||
if handlers:
|
||||
return ret + asty.TryFinally(
|
||||
finalbody=finalbody)
|
||||
elif finalbody and handlers:
|
||||
x = asty.TryFinally(
|
||||
expr,
|
||||
body=[asty.TryExcept(
|
||||
expr,
|
||||
body=[asty.TryExcept(
|
||||
expr,
|
||||
handlers=handlers,
|
||||
body=body,
|
||||
orelse=orelse)],
|
||||
finalbody=finalbody) + returnable
|
||||
|
||||
return ret + asty.TryFinally(
|
||||
expr, body=body, finalbody=finalbody) + returnable
|
||||
|
||||
return ret + asty.TryExcept(
|
||||
expr, handlers=handlers, body=body, orelse=orelse) + returnable
|
||||
body=body,
|
||||
handlers=handlers,
|
||||
orelse=orelse)],
|
||||
finalbody=finalbody)
|
||||
elif finalbody:
|
||||
x = asty.TryFinally(
|
||||
expr, body=body, finalbody=finalbody)
|
||||
else:
|
||||
x = asty.TryExcept(
|
||||
expr, body=body, handlers=handlers, orelse=orelse)
|
||||
return handler_results + x + returnable
|
||||
|
||||
@builds("except")
|
||||
def magic_internal_form(self, expr):
|
||||
raise HyTypeError(expr,
|
||||
"Error: `%s' can't be used like that." % (expr[0]))
|
||||
|
||||
def _compile_catch_expression(self, expr, var):
|
||||
catch = expr.pop(0) # catch
|
||||
|
||||
if not expr:
|
||||
raise HyTypeError(expr, "`%s' missing exceptions list" % catch)
|
||||
exceptions = expr.pop(0)
|
||||
|
||||
def _compile_catch_expression(self, expr, var, exceptions, body):
|
||||
# exceptions catch should be either:
|
||||
# [[list of exceptions]]
|
||||
# or
|
||||
@ -915,61 +899,34 @@ class HyASTCompiler(object):
|
||||
# or
|
||||
# []
|
||||
|
||||
if not isinstance(exceptions, HyList):
|
||||
raise HyTypeError(exceptions,
|
||||
"`%s' exceptions list is not a list" % catch)
|
||||
if len(exceptions) > 2:
|
||||
raise HyTypeError(exceptions,
|
||||
"`%s' exceptions list is too long" % catch)
|
||||
|
||||
# [variable [list of exceptions]]
|
||||
# let's pop variable and use it as name
|
||||
name = None
|
||||
if len(exceptions) == 2:
|
||||
name = exceptions.pop(0)
|
||||
if not isinstance(name, HySymbol):
|
||||
raise HyTypeError(
|
||||
exceptions,
|
||||
"Exception storage target name must be a symbol.")
|
||||
name = exceptions[0]
|
||||
name = (ast_str(name) if PY3
|
||||
else self._storeize(name, self.compile(name)))
|
||||
|
||||
if PY3:
|
||||
# Python3 features a change where the Exception handler
|
||||
# moved the name from a Name() to a pure Python String type.
|
||||
#
|
||||
# We'll just make sure it's a pure "string", and let it work
|
||||
# it's magic.
|
||||
name = ast_str(name)
|
||||
else:
|
||||
# Python2 requires an ast.Name, set to ctx Store.
|
||||
name = self._storeize(name, self.compile(name))
|
||||
|
||||
exceptions_list = exceptions.pop(0) if exceptions else []
|
||||
|
||||
if isinstance(exceptions_list, list):
|
||||
exceptions_list = exceptions[-1] if exceptions else HyList()
|
||||
if isinstance(exceptions_list, HyList):
|
||||
if len(exceptions_list):
|
||||
# [FooBar BarFoo] → catch Foobar and BarFoo exceptions
|
||||
elts, _type, _ = self._compile_collect(exceptions_list)
|
||||
_type += asty.Tuple(expr, elts=elts, ctx=ast.Load())
|
||||
_type += asty.Tuple(exceptions_list, elts=elts, ctx=ast.Load())
|
||||
else:
|
||||
# [] → all exceptions caught
|
||||
_type = Result()
|
||||
elif isinstance(exceptions_list, HySymbol):
|
||||
_type = self.compile(exceptions_list)
|
||||
else:
|
||||
raise HyTypeError(exceptions,
|
||||
"`%s' needs a valid exception list" % catch)
|
||||
_type = self.compile(exceptions_list)
|
||||
|
||||
body = self._compile_branch(expr)
|
||||
body = self._compile_branch(body)
|
||||
body += asty.Assign(expr, targets=[var], value=body.force_expr)
|
||||
body += body.expr_as_stmt()
|
||||
|
||||
body = body.stmts
|
||||
if not body:
|
||||
body = [asty.Pass(expr)]
|
||||
|
||||
# use _type.expr to get a literal `None`
|
||||
return _type + asty.ExceptHandler(
|
||||
expr, type=_type.expr, name=name, body=body)
|
||||
expr, type=_type.expr, name=name,
|
||||
body=body.stmts or [asty.Pass(expr)])
|
||||
|
||||
@special("if*", [FORM, FORM, maybe(FORM)])
|
||||
def compile_if(self, expr, _, cond, body, orel_expr):
|
||||
|
Loading…
Reference in New Issue
Block a user