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