mirror of
https://github.com/python/cpython.git
synced 2025-10-21 22:22:48 +00:00
bpo-45292: [PEP-654] add except* (GH-29581)
This commit is contained in:
parent
850aefc2c6
commit
d60457a667
34 changed files with 7070 additions and 3332 deletions
229
Python/Python-ast.c
generated
229
Python/Python-ast.c
generated
|
@ -146,6 +146,7 @@ void _PyAST_Fini(PyInterpreterState *interp)
|
|||
Py_CLEAR(state->Sub_singleton);
|
||||
Py_CLEAR(state->Sub_type);
|
||||
Py_CLEAR(state->Subscript_type);
|
||||
Py_CLEAR(state->TryStar_type);
|
||||
Py_CLEAR(state->Try_type);
|
||||
Py_CLEAR(state->Tuple_type);
|
||||
Py_CLEAR(state->TypeIgnore_type);
|
||||
|
@ -486,6 +487,12 @@ static const char * const Try_fields[]={
|
|||
"orelse",
|
||||
"finalbody",
|
||||
};
|
||||
static const char * const TryStar_fields[]={
|
||||
"body",
|
||||
"handlers",
|
||||
"orelse",
|
||||
"finalbody",
|
||||
};
|
||||
static const char * const Assert_fields[]={
|
||||
"test",
|
||||
"msg",
|
||||
|
@ -1139,6 +1146,7 @@ init_types(struct ast_state *state)
|
|||
" | Match(expr subject, match_case* cases)\n"
|
||||
" | Raise(expr? exc, expr? cause)\n"
|
||||
" | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)\n"
|
||||
" | TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)\n"
|
||||
" | Assert(expr test, expr? msg)\n"
|
||||
" | Import(alias* names)\n"
|
||||
" | ImportFrom(identifier? module, alias* names, int? level)\n"
|
||||
|
@ -1254,6 +1262,10 @@ init_types(struct ast_state *state)
|
|||
state->Try_type = make_type(state, "Try", state->stmt_type, Try_fields, 4,
|
||||
"Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)");
|
||||
if (!state->Try_type) return 0;
|
||||
state->TryStar_type = make_type(state, "TryStar", state->stmt_type,
|
||||
TryStar_fields, 4,
|
||||
"TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)");
|
||||
if (!state->TryStar_type) return 0;
|
||||
state->Assert_type = make_type(state, "Assert", state->stmt_type,
|
||||
Assert_fields, 2,
|
||||
"Assert(expr test, expr? msg)");
|
||||
|
@ -2379,6 +2391,28 @@ _PyAST_Try(asdl_stmt_seq * body, asdl_excepthandler_seq * handlers,
|
|||
return p;
|
||||
}
|
||||
|
||||
stmt_ty
|
||||
_PyAST_TryStar(asdl_stmt_seq * body, asdl_excepthandler_seq * handlers,
|
||||
asdl_stmt_seq * orelse, asdl_stmt_seq * finalbody, int lineno,
|
||||
int col_offset, int end_lineno, int end_col_offset, PyArena
|
||||
*arena)
|
||||
{
|
||||
stmt_ty p;
|
||||
p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->kind = TryStar_kind;
|
||||
p->v.TryStar.body = body;
|
||||
p->v.TryStar.handlers = handlers;
|
||||
p->v.TryStar.orelse = orelse;
|
||||
p->v.TryStar.finalbody = finalbody;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
p->end_lineno = end_lineno;
|
||||
p->end_col_offset = end_col_offset;
|
||||
return p;
|
||||
}
|
||||
|
||||
stmt_ty
|
||||
_PyAST_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, int
|
||||
end_lineno, int end_col_offset, PyArena *arena)
|
||||
|
@ -4049,6 +4083,34 @@ ast2obj_stmt(struct ast_state *state, void* _o)
|
|||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case TryStar_kind:
|
||||
tp = (PyTypeObject *)state->TryStar_type;
|
||||
result = PyType_GenericNew(tp, NULL, NULL);
|
||||
if (!result) goto failed;
|
||||
value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.body, ast2obj_stmt);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->body, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.handlers,
|
||||
ast2obj_excepthandler);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->handlers, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.orelse,
|
||||
ast2obj_stmt);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->orelse, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.finalbody,
|
||||
ast2obj_stmt);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttr(result, state->finalbody, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case Assert_kind:
|
||||
tp = (PyTypeObject *)state->Assert_type;
|
||||
result = PyType_GenericNew(tp, NULL, NULL);
|
||||
|
@ -7477,6 +7539,170 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena*
|
|||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
tp = state->TryStar_type;
|
||||
isinstance = PyObject_IsInstance(obj, tp);
|
||||
if (isinstance == -1) {
|
||||
return 1;
|
||||
}
|
||||
if (isinstance) {
|
||||
asdl_stmt_seq* body;
|
||||
asdl_excepthandler_seq* handlers;
|
||||
asdl_stmt_seq* orelse;
|
||||
asdl_stmt_seq* finalbody;
|
||||
|
||||
if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (tmp == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from TryStar");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
Py_ssize_t len;
|
||||
Py_ssize_t i;
|
||||
if (!PyList_Check(tmp)) {
|
||||
PyErr_Format(PyExc_TypeError, "TryStar field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
|
||||
goto failed;
|
||||
}
|
||||
len = PyList_GET_SIZE(tmp);
|
||||
body = _Py_asdl_stmt_seq_new(len, arena);
|
||||
if (body == NULL) goto failed;
|
||||
for (i = 0; i < len; i++) {
|
||||
stmt_ty val;
|
||||
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
|
||||
Py_INCREF(tmp2);
|
||||
if (Py_EnterRecursiveCall(" while traversing 'TryStar' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_stmt(state, tmp2, &val, arena);
|
||||
Py_LeaveRecursiveCall();
|
||||
Py_DECREF(tmp2);
|
||||
if (res != 0) goto failed;
|
||||
if (len != PyList_GET_SIZE(tmp)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "TryStar field \"body\" changed size during iteration");
|
||||
goto failed;
|
||||
}
|
||||
asdl_seq_SET(body, i, val);
|
||||
}
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (tmp == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from TryStar");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
Py_ssize_t len;
|
||||
Py_ssize_t i;
|
||||
if (!PyList_Check(tmp)) {
|
||||
PyErr_Format(PyExc_TypeError, "TryStar field \"handlers\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
|
||||
goto failed;
|
||||
}
|
||||
len = PyList_GET_SIZE(tmp);
|
||||
handlers = _Py_asdl_excepthandler_seq_new(len, arena);
|
||||
if (handlers == NULL) goto failed;
|
||||
for (i = 0; i < len; i++) {
|
||||
excepthandler_ty val;
|
||||
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
|
||||
Py_INCREF(tmp2);
|
||||
if (Py_EnterRecursiveCall(" while traversing 'TryStar' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_excepthandler(state, tmp2, &val, arena);
|
||||
Py_LeaveRecursiveCall();
|
||||
Py_DECREF(tmp2);
|
||||
if (res != 0) goto failed;
|
||||
if (len != PyList_GET_SIZE(tmp)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "TryStar field \"handlers\" changed size during iteration");
|
||||
goto failed;
|
||||
}
|
||||
asdl_seq_SET(handlers, i, val);
|
||||
}
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (tmp == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from TryStar");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
Py_ssize_t len;
|
||||
Py_ssize_t i;
|
||||
if (!PyList_Check(tmp)) {
|
||||
PyErr_Format(PyExc_TypeError, "TryStar field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
|
||||
goto failed;
|
||||
}
|
||||
len = PyList_GET_SIZE(tmp);
|
||||
orelse = _Py_asdl_stmt_seq_new(len, arena);
|
||||
if (orelse == NULL) goto failed;
|
||||
for (i = 0; i < len; i++) {
|
||||
stmt_ty val;
|
||||
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
|
||||
Py_INCREF(tmp2);
|
||||
if (Py_EnterRecursiveCall(" while traversing 'TryStar' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_stmt(state, tmp2, &val, arena);
|
||||
Py_LeaveRecursiveCall();
|
||||
Py_DECREF(tmp2);
|
||||
if (res != 0) goto failed;
|
||||
if (len != PyList_GET_SIZE(tmp)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "TryStar field \"orelse\" changed size during iteration");
|
||||
goto failed;
|
||||
}
|
||||
asdl_seq_SET(orelse, i, val);
|
||||
}
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
if (tmp == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from TryStar");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
int res;
|
||||
Py_ssize_t len;
|
||||
Py_ssize_t i;
|
||||
if (!PyList_Check(tmp)) {
|
||||
PyErr_Format(PyExc_TypeError, "TryStar field \"finalbody\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp)));
|
||||
goto failed;
|
||||
}
|
||||
len = PyList_GET_SIZE(tmp);
|
||||
finalbody = _Py_asdl_stmt_seq_new(len, arena);
|
||||
if (finalbody == NULL) goto failed;
|
||||
for (i = 0; i < len; i++) {
|
||||
stmt_ty val;
|
||||
PyObject *tmp2 = PyList_GET_ITEM(tmp, i);
|
||||
Py_INCREF(tmp2);
|
||||
if (Py_EnterRecursiveCall(" while traversing 'TryStar' node")) {
|
||||
goto failed;
|
||||
}
|
||||
res = obj2ast_stmt(state, tmp2, &val, arena);
|
||||
Py_LeaveRecursiveCall();
|
||||
Py_DECREF(tmp2);
|
||||
if (res != 0) goto failed;
|
||||
if (len != PyList_GET_SIZE(tmp)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "TryStar field \"finalbody\" changed size during iteration");
|
||||
goto failed;
|
||||
}
|
||||
asdl_seq_SET(finalbody, i, val);
|
||||
}
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = _PyAST_TryStar(body, handlers, orelse, finalbody, lineno,
|
||||
col_offset, end_lineno, end_col_offset, arena);
|
||||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
tp = state->Assert_type;
|
||||
isinstance = PyObject_IsInstance(obj, tp);
|
||||
if (isinstance == -1) {
|
||||
|
@ -11687,6 +11913,9 @@ astmodule_exec(PyObject *m)
|
|||
if (PyModule_AddObjectRef(m, "Try", state->Try_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddObjectRef(m, "TryStar", state->TryStar_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddObjectRef(m, "Assert", state->Assert_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
|
25
Python/ast.c
25
Python/ast.c
|
@ -817,6 +817,31 @@ validate_stmt(struct validator *state, stmt_ty stmt)
|
|||
(!asdl_seq_LEN(stmt->v.Try.orelse) ||
|
||||
validate_stmts(state, stmt->v.Try.orelse));
|
||||
break;
|
||||
case TryStar_kind:
|
||||
if (!validate_body(state, stmt->v.TryStar.body, "TryStar"))
|
||||
return 0;
|
||||
if (!asdl_seq_LEN(stmt->v.TryStar.handlers) &&
|
||||
!asdl_seq_LEN(stmt->v.TryStar.finalbody)) {
|
||||
PyErr_SetString(PyExc_ValueError, "TryStar has neither except handlers nor finalbody");
|
||||
return 0;
|
||||
}
|
||||
if (!asdl_seq_LEN(stmt->v.TryStar.handlers) &&
|
||||
asdl_seq_LEN(stmt->v.TryStar.orelse)) {
|
||||
PyErr_SetString(PyExc_ValueError, "TryStar has orelse but no except handlers");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) {
|
||||
excepthandler_ty handler = asdl_seq_GET(stmt->v.TryStar.handlers, i);
|
||||
if ((handler->v.ExceptHandler.type &&
|
||||
!validate_expr(state, handler->v.ExceptHandler.type, Load)) ||
|
||||
!validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler"))
|
||||
return 0;
|
||||
}
|
||||
ret = (!asdl_seq_LEN(stmt->v.TryStar.finalbody) ||
|
||||
validate_stmts(state, stmt->v.TryStar.finalbody)) &&
|
||||
(!asdl_seq_LEN(stmt->v.TryStar.orelse) ||
|
||||
validate_stmts(state, stmt->v.TryStar.orelse));
|
||||
break;
|
||||
case Assert_kind:
|
||||
ret = validate_expr(state, stmt->v.Assert.test, Load) &&
|
||||
(!stmt->v.Assert.msg || validate_expr(state, stmt->v.Assert.msg, Load));
|
||||
|
|
|
@ -972,6 +972,12 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
|||
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.orelse);
|
||||
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.finalbody);
|
||||
break;
|
||||
case TryStar_kind:
|
||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.body);
|
||||
CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.TryStar.handlers);
|
||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.orelse);
|
||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.finalbody);
|
||||
break;
|
||||
case Assert_kind:
|
||||
CALL(astfold_expr, expr_ty, node_->v.Assert.test);
|
||||
CALL_OPT(astfold_expr, expr_ty, node_->v.Assert.msg);
|
||||
|
|
355
Python/ceval.c
355
Python/ceval.c
|
@ -37,6 +37,7 @@
|
|||
#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
/* For debugging the interpreter: */
|
||||
|
@ -95,6 +96,7 @@ static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyOb
|
|||
static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
|
||||
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
|
||||
static int check_except_type_valid(PyThreadState *tstate, PyObject* right);
|
||||
static int check_except_star_type_valid(PyThreadState *tstate, PyObject* right);
|
||||
static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs);
|
||||
static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int);
|
||||
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
|
||||
|
@ -1090,6 +1092,11 @@ fail:
|
|||
|
||||
|
||||
static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
|
||||
static PyObject *do_reraise_star(PyObject *excs, PyObject *orig);
|
||||
static int exception_group_match(
|
||||
PyObject *exc_type, PyObject* exc_value, PyObject *match_type,
|
||||
PyObject **match, PyObject **rest);
|
||||
|
||||
static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
|
@ -2727,6 +2734,7 @@ check_eval_breaker:
|
|||
type = exc_info->exc_type;
|
||||
value = exc_info->exc_value;
|
||||
traceback = exc_info->exc_traceback;
|
||||
|
||||
exc_info->exc_type = POP();
|
||||
exc_info->exc_value = POP();
|
||||
exc_info->exc_traceback = POP();
|
||||
|
@ -2791,6 +2799,36 @@ check_eval_breaker:
|
|||
goto exception_unwind;
|
||||
}
|
||||
|
||||
TARGET(PREP_RERAISE_STAR) {
|
||||
PyObject *excs = POP();
|
||||
assert(PyList_Check(excs));
|
||||
PyObject *orig = POP();
|
||||
|
||||
PyObject *val = do_reraise_star(excs, orig);
|
||||
Py_DECREF(excs);
|
||||
Py_DECREF(orig);
|
||||
|
||||
if (val == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *lasti_unused = Py_NewRef(_PyLong_GetZero());
|
||||
PUSH(lasti_unused);
|
||||
if (!Py_IsNone(val)) {
|
||||
PyObject *tb = PyException_GetTraceback(val);
|
||||
PUSH(tb ? tb : Py_NewRef(Py_None));
|
||||
PUSH(val);
|
||||
PUSH(Py_NewRef(Py_TYPE(val)));
|
||||
}
|
||||
else {
|
||||
// nothing to reraise
|
||||
PUSH(Py_NewRef(Py_None));
|
||||
PUSH(val);
|
||||
PUSH(Py_NewRef(Py_None));
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(END_ASYNC_FOR) {
|
||||
PyObject *exc = POP();
|
||||
PyObject *val = POP();
|
||||
|
@ -3922,6 +3960,83 @@ check_eval_breaker:
|
|||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(JUMP_IF_NOT_EG_MATCH) {
|
||||
PyObject *match_type = POP();
|
||||
PyObject *exc_type = TOP();
|
||||
PyObject *exc_value = SECOND();
|
||||
if (check_except_star_type_valid(tstate, match_type) < 0) {
|
||||
Py_DECREF(match_type);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *match = NULL, *rest = NULL;
|
||||
int res = exception_group_match(exc_type, exc_value,
|
||||
match_type, &match, &rest);
|
||||
Py_DECREF(match_type);
|
||||
if (res < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (match == NULL || rest == NULL) {
|
||||
assert(match == NULL);
|
||||
assert(rest == NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (Py_IsNone(match)) {
|
||||
Py_DECREF(match);
|
||||
Py_XDECREF(rest);
|
||||
/* no match - jump to target */
|
||||
JUMPTO(oparg);
|
||||
}
|
||||
else {
|
||||
|
||||
/* Total or partial match - update the stack from
|
||||
* [tb, val, exc]
|
||||
* to
|
||||
* [tb, rest, exc, tb, match, exc]
|
||||
* (rest can be Py_None)
|
||||
*/
|
||||
|
||||
|
||||
PyObject *type = TOP();
|
||||
PyObject *val = SECOND();
|
||||
PyObject *tb = THIRD();
|
||||
|
||||
if (!Py_IsNone(rest)) {
|
||||
/* tb remains the same */
|
||||
SET_TOP(Py_NewRef(Py_TYPE(rest)));
|
||||
SET_SECOND(Py_NewRef(rest));
|
||||
SET_THIRD(Py_NewRef(tb));
|
||||
}
|
||||
else {
|
||||
SET_TOP(Py_NewRef(Py_None));
|
||||
SET_SECOND(Py_NewRef(Py_None));
|
||||
SET_THIRD(Py_NewRef(Py_None));
|
||||
}
|
||||
/* Push match */
|
||||
|
||||
PUSH(Py_NewRef(tb));
|
||||
PUSH(Py_NewRef(match));
|
||||
PUSH(Py_NewRef(Py_TYPE(match)));
|
||||
|
||||
// set exc_info to the current match
|
||||
PyErr_SetExcInfo(
|
||||
Py_NewRef(Py_TYPE(match)),
|
||||
Py_NewRef(match),
|
||||
Py_NewRef(tb));
|
||||
|
||||
Py_DECREF(tb);
|
||||
Py_DECREF(val);
|
||||
Py_DECREF(type);
|
||||
|
||||
Py_DECREF(match);
|
||||
Py_DECREF(rest);
|
||||
}
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(JUMP_IF_NOT_EXC_MATCH) {
|
||||
PyObject *right = POP();
|
||||
ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND());
|
||||
|
@ -3931,17 +4046,12 @@ check_eval_breaker:
|
|||
Py_DECREF(right);
|
||||
goto error;
|
||||
}
|
||||
|
||||
int res = PyErr_GivenExceptionMatches(left, right);
|
||||
Py_DECREF(right);
|
||||
if (res > 0) {
|
||||
/* Exception matches -- Do nothing */;
|
||||
}
|
||||
else if (res == 0) {
|
||||
if (res == 0) {
|
||||
JUMPTO(oparg);
|
||||
}
|
||||
else {
|
||||
goto error;
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
@ -6127,6 +6237,196 @@ raise_error:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Logic for matching an exception in an except* clause (too
|
||||
complicated for inlining).
|
||||
*/
|
||||
|
||||
static int
|
||||
exception_group_match(PyObject *exc_type, PyObject* exc_value,
|
||||
PyObject *match_type, PyObject **match, PyObject **rest)
|
||||
{
|
||||
if (Py_IsNone(exc_type)) {
|
||||
assert(Py_IsNone(exc_value));
|
||||
*match = Py_NewRef(Py_None);
|
||||
*rest = Py_NewRef(Py_None);
|
||||
return 0;
|
||||
}
|
||||
assert(PyExceptionClass_Check(exc_type));
|
||||
assert(PyExceptionInstance_Check(exc_value));
|
||||
|
||||
if (PyErr_GivenExceptionMatches(exc_type, match_type)) {
|
||||
/* Full match of exc itself */
|
||||
bool is_eg = _PyBaseExceptionGroup_Check(exc_value);
|
||||
if (is_eg) {
|
||||
*match = Py_NewRef(exc_value);
|
||||
}
|
||||
else {
|
||||
/* naked exception - wrap it */
|
||||
PyObject *excs = PyTuple_Pack(1, exc_value);
|
||||
if (excs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyObject *wrapped = _PyExc_CreateExceptionGroup("", excs);
|
||||
Py_DECREF(excs);
|
||||
if (wrapped == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*match = wrapped;
|
||||
}
|
||||
*rest = Py_NewRef(Py_None);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* exc_value does not match match_type.
|
||||
* Check for partial match if it's an exception group.
|
||||
*/
|
||||
if (_PyBaseExceptionGroup_Check(exc_value)) {
|
||||
PyObject *pair = PyObject_CallMethod(exc_value, "split", "(O)",
|
||||
match_type);
|
||||
if (pair == NULL) {
|
||||
return -1;
|
||||
}
|
||||
assert(PyTuple_CheckExact(pair));
|
||||
assert(PyTuple_GET_SIZE(pair) == 2);
|
||||
*match = Py_NewRef(PyTuple_GET_ITEM(pair, 0));
|
||||
*rest = Py_NewRef(PyTuple_GET_ITEM(pair, 1));
|
||||
Py_DECREF(pair);
|
||||
return 0;
|
||||
}
|
||||
/* no match */
|
||||
*match = Py_NewRef(Py_None);
|
||||
*rest = Py_NewRef(Py_None);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Logic for the final raise/reraise of a try-except* contruct
|
||||
(too complicated for inlining).
|
||||
*/
|
||||
|
||||
static bool
|
||||
is_same_exception_metadata(PyObject *exc1, PyObject *exc2)
|
||||
{
|
||||
assert(PyExceptionInstance_Check(exc1));
|
||||
assert(PyExceptionInstance_Check(exc2));
|
||||
|
||||
PyObject *tb1 = PyException_GetTraceback(exc1);
|
||||
PyObject *ctx1 = PyException_GetContext(exc1);
|
||||
PyObject *cause1 = PyException_GetCause(exc1);
|
||||
PyObject *tb2 = PyException_GetTraceback(exc2);
|
||||
PyObject *ctx2 = PyException_GetContext(exc2);
|
||||
PyObject *cause2 = PyException_GetCause(exc2);
|
||||
|
||||
bool result = (Py_Is(tb1, tb2) &&
|
||||
Py_Is(ctx1, ctx2) &&
|
||||
Py_Is(cause1, cause2));
|
||||
|
||||
Py_XDECREF(tb1);
|
||||
Py_XDECREF(ctx1);
|
||||
Py_XDECREF(cause1);
|
||||
Py_XDECREF(tb2);
|
||||
Py_XDECREF(ctx2);
|
||||
Py_XDECREF(cause2);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
excs: a list of exceptions to raise/reraise
|
||||
orig: the original except that was caught
|
||||
|
||||
Calculates an exception group to raise. It contains
|
||||
all exceptions in excs, where those that were reraised
|
||||
have same nesting structure as in orig, and those that
|
||||
were raised (if any) are added as siblings in a new EG.
|
||||
|
||||
Returns NULL and sets an exception on failure.
|
||||
*/
|
||||
static PyObject *
|
||||
do_reraise_star(PyObject *excs, PyObject *orig)
|
||||
{
|
||||
assert(PyList_Check(excs));
|
||||
assert(PyExceptionInstance_Check(orig));
|
||||
|
||||
Py_ssize_t numexcs = PyList_GET_SIZE(excs);
|
||||
|
||||
if (numexcs == 0) {
|
||||
return Py_NewRef(Py_None);
|
||||
}
|
||||
|
||||
if (!_PyBaseExceptionGroup_Check(orig)) {
|
||||
/* a naked exception was caught and wrapped. Only one except* clause
|
||||
* could have executed,so there is at most one exception to raise.
|
||||
*/
|
||||
|
||||
assert(numexcs == 1 || (numexcs == 2 && PyList_GET_ITEM(excs, 1) == Py_None));
|
||||
|
||||
PyObject *e = PyList_GET_ITEM(excs, 0);
|
||||
assert(e != NULL);
|
||||
return Py_NewRef(e);
|
||||
}
|
||||
|
||||
|
||||
PyObject *raised_list = PyList_New(0);
|
||||
if (raised_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject* reraised_list = PyList_New(0);
|
||||
if (reraised_list == NULL) {
|
||||
Py_DECREF(raised_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now we are holding refs to raised_list and reraised_list */
|
||||
|
||||
PyObject *result = NULL;
|
||||
|
||||
/* Split excs into raised and reraised by comparing metadata with orig */
|
||||
for (Py_ssize_t i = 0; i < numexcs; i++) {
|
||||
PyObject *e = PyList_GET_ITEM(excs, i);
|
||||
assert(e != NULL);
|
||||
if (Py_IsNone(e)) {
|
||||
continue;
|
||||
}
|
||||
bool is_reraise = is_same_exception_metadata(e, orig);
|
||||
PyObject *append_list = is_reraise ? reraised_list : raised_list;
|
||||
if (PyList_Append(append_list, e) < 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *reraised_eg = _PyExc_ExceptionGroupProjection(orig, reraised_list);
|
||||
if (reraised_eg == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!Py_IsNone(reraised_eg)) {
|
||||
assert(is_same_exception_metadata(reraised_eg, orig));
|
||||
}
|
||||
|
||||
Py_ssize_t num_raised = PyList_GET_SIZE(raised_list);
|
||||
if (num_raised == 0) {
|
||||
result = reraised_eg;
|
||||
}
|
||||
else if (num_raised > 0) {
|
||||
int res = 0;
|
||||
if (!Py_IsNone(reraised_eg)) {
|
||||
res = PyList_Append(raised_list, reraised_eg);
|
||||
}
|
||||
Py_DECREF(reraised_eg);
|
||||
if (res < 0) {
|
||||
goto done;
|
||||
}
|
||||
result = _PyExc_CreateExceptionGroup("", raised_list);
|
||||
if (result == NULL) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
Py_XDECREF(raised_list);
|
||||
Py_XDECREF(reraised_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Iterate v argcnt times and store the results on the stack (via decreasing
|
||||
sp). Return 1 for success, 0 if error.
|
||||
|
||||
|
@ -7020,10 +7320,12 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
|
||||
"BaseException is not allowed"
|
||||
|
||||
#define CANNOT_EXCEPT_STAR_EG "catching ExceptionGroup with except* "\
|
||||
"is not allowed. Use except instead."
|
||||
|
||||
static int
|
||||
check_except_type_valid(PyThreadState *tstate, PyObject* right)
|
||||
{
|
||||
|
@ -7049,6 +7351,43 @@ check_except_type_valid(PyThreadState *tstate, PyObject* right)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_except_star_type_valid(PyThreadState *tstate, PyObject* right)
|
||||
{
|
||||
if (check_except_type_valid(tstate, right) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reject except *ExceptionGroup */
|
||||
|
||||
int is_subclass = 0;
|
||||
if (PyTuple_Check(right)) {
|
||||
Py_ssize_t length = PyTuple_GET_SIZE(right);
|
||||
for (Py_ssize_t i = 0; i < length; i++) {
|
||||
PyObject *exc = PyTuple_GET_ITEM(right, i);
|
||||
is_subclass = PyObject_IsSubclass(exc, PyExc_BaseExceptionGroup);
|
||||
if (is_subclass < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (is_subclass) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
is_subclass = PyObject_IsSubclass(right, PyExc_BaseExceptionGroup);
|
||||
if (is_subclass < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (is_subclass) {
|
||||
_PyErr_SetString(tstate, PyExc_TypeError,
|
||||
CANNOT_EXCEPT_STAR_EG);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args)
|
||||
{
|
||||
|
|
339
Python/compile.c
339
Python/compile.c
|
@ -175,7 +175,7 @@ compiler IR.
|
|||
|
||||
enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
|
||||
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER,
|
||||
ASYNC_COMPREHENSION_GENERATOR };
|
||||
EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR };
|
||||
|
||||
struct fblockinfo {
|
||||
enum fblocktype fb_type;
|
||||
|
@ -323,6 +323,7 @@ static int compiler_call_helper(struct compiler *c, int n,
|
|||
asdl_expr_seq *args,
|
||||
asdl_keyword_seq *keywords);
|
||||
static int compiler_try_except(struct compiler *, stmt_ty);
|
||||
static int compiler_try_star_except(struct compiler *, stmt_ty);
|
||||
static int compiler_set_qualname(struct compiler *);
|
||||
|
||||
static int compiler_sync_comprehension_generator(
|
||||
|
@ -1094,6 +1095,8 @@ stack_effect(int opcode, int oparg, int jump)
|
|||
return -1;
|
||||
case JUMP_IF_NOT_EXC_MATCH:
|
||||
return -1;
|
||||
case JUMP_IF_NOT_EG_MATCH:
|
||||
return jump > 0 ? -1 : 2;
|
||||
case IMPORT_NAME:
|
||||
return -1;
|
||||
case IMPORT_FROM:
|
||||
|
@ -1131,6 +1134,8 @@ stack_effect(int opcode, int oparg, int jump)
|
|||
* if an exception be raised. */
|
||||
return jump ? -1 + 4 : 0;
|
||||
|
||||
case PREP_RERAISE_STAR:
|
||||
return 2;
|
||||
case RERAISE:
|
||||
return -3;
|
||||
case PUSH_EXC_INFO:
|
||||
|
@ -1755,6 +1760,18 @@ find_ann(asdl_stmt_seq *stmts)
|
|||
find_ann(st->v.Try.finalbody) ||
|
||||
find_ann(st->v.Try.orelse);
|
||||
break;
|
||||
case TryStar_kind:
|
||||
for (j = 0; j < asdl_seq_LEN(st->v.TryStar.handlers); j++) {
|
||||
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
|
||||
st->v.TryStar.handlers, j);
|
||||
if (find_ann(handler->v.ExceptHandler.body)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
res = find_ann(st->v.TryStar.body) ||
|
||||
find_ann(st->v.TryStar.finalbody) ||
|
||||
find_ann(st->v.TryStar.orelse);
|
||||
break;
|
||||
default:
|
||||
res = 0;
|
||||
}
|
||||
|
@ -1816,6 +1833,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
|
|||
switch (info->fb_type) {
|
||||
case WHILE_LOOP:
|
||||
case EXCEPTION_HANDLER:
|
||||
case EXCEPTION_GROUP_HANDLER:
|
||||
case ASYNC_COMPREHENSION_GENERATOR:
|
||||
return 1;
|
||||
|
||||
|
@ -1919,6 +1937,10 @@ compiler_unwind_fblock_stack(struct compiler *c, int preserve_tos, struct fblock
|
|||
return 1;
|
||||
}
|
||||
struct fblockinfo *top = &c->u->u_fblock[c->u->u_nfblocks-1];
|
||||
if (top->fb_type == EXCEPTION_GROUP_HANDLER) {
|
||||
return compiler_error(
|
||||
c, "'break', 'continue' and 'return' cannot appear in an except* block");
|
||||
}
|
||||
if (loop != NULL && (top->fb_type == WHILE_LOOP || top->fb_type == FOR_LOOP)) {
|
||||
*loop = top;
|
||||
return 1;
|
||||
|
@ -3202,6 +3224,62 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_try_star_finally(struct compiler *c, stmt_ty s)
|
||||
{
|
||||
basicblock *body = compiler_new_block(c);
|
||||
if (body == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *end = compiler_new_block(c);
|
||||
if (!end) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *exit = compiler_new_block(c);
|
||||
if (!exit) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *cleanup = compiler_new_block(c);
|
||||
if (!cleanup) {
|
||||
return 0;
|
||||
}
|
||||
/* `try` block */
|
||||
ADDOP_JUMP(c, SETUP_FINALLY, end);
|
||||
compiler_use_next_block(c, body);
|
||||
if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.TryStar.finalbody)) {
|
||||
return 0;
|
||||
}
|
||||
if (s->v.TryStar.handlers && asdl_seq_LEN(s->v.TryStar.handlers)) {
|
||||
if (!compiler_try_star_except(c, s)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
VISIT_SEQ(c, stmt, s->v.TryStar.body);
|
||||
}
|
||||
ADDOP_NOLINE(c, POP_BLOCK);
|
||||
compiler_pop_fblock(c, FINALLY_TRY, body);
|
||||
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
|
||||
ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit);
|
||||
/* `finally` block */
|
||||
compiler_use_next_block(c, end);
|
||||
|
||||
UNSET_LOC(c);
|
||||
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
|
||||
ADDOP(c, PUSH_EXC_INFO);
|
||||
if (!compiler_push_fblock(c, FINALLY_END, end, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
|
||||
compiler_pop_fblock(c, FINALLY_END, end);
|
||||
ADDOP_I(c, RERAISE, 0);
|
||||
compiler_use_next_block(c, cleanup);
|
||||
ADDOP(c, POP_EXCEPT_AND_RERAISE);
|
||||
compiler_use_next_block(c, exit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Code generated for "try: S except E1 as V1: S1 except E2 as V2: S2 ...":
|
||||
(The contents of the value stack is shown in [], with the top
|
||||
|
@ -3360,6 +3438,253 @@ compiler_try_except(struct compiler *c, stmt_ty s)
|
|||
ADDOP(c, POP_EXCEPT_AND_RERAISE);
|
||||
compiler_use_next_block(c, orelse);
|
||||
VISIT_SEQ(c, stmt, s->v.Try.orelse);
|
||||
ADDOP_JUMP(c, JUMP_FORWARD, end);
|
||||
compiler_use_next_block(c, end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Code generated for "try: S except* E1 as V1: S1 except* E2 as V2: S2 ...":
|
||||
(The contents of the value stack is shown in [], with the top
|
||||
at the right; 'tb' is trace-back info, 'val' the exception instance,
|
||||
and 'typ' the exception's type.)
|
||||
|
||||
Value stack Label Instruction Argument
|
||||
[] SETUP_FINALLY L1
|
||||
[] <code for S>
|
||||
[] POP_BLOCK
|
||||
[] JUMP_FORWARD L0
|
||||
|
||||
[tb, val, typ] L1: DUP_TOP_TWO ) save a copy of the
|
||||
[tb, val, typ, orig, typ] POP_TOP ) original raised exception
|
||||
[tb, val, typ, orig] ROT_FOUR )
|
||||
[orig, tb, val, typ] BUILD_LIST ) list for raised/reraised
|
||||
[orig, tb, val, typ, res] ROT_FOUR ) exceptions ("result")
|
||||
|
||||
[orig, res, tb, val, typ] <evaluate E1> )
|
||||
[orig, res, tb, val, typ, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
|
||||
|
||||
[orig, res, tb, rest, typ, tb, match, typ] POP
|
||||
[orig, res, tb, rest, typ, tb, match] <assign to V1> (or POP if no V1)
|
||||
[orig, res, tb, rest, typ, tb] POP
|
||||
|
||||
[orig, res, tb, rest, typ] SETUP_FINALLY R1
|
||||
[orig, res, tb, rest, typ] <code for S1>
|
||||
[orig, res, tb, rest, typ] JUMP_FORWARD L2
|
||||
|
||||
[orig, res, tb, rest, typ, i, tb, v, t] R1: POP ) exception raised in except* body
|
||||
[orig, res, tb, rest, typ, i, tb, v] LIST_APPEND 6 ) add it to res
|
||||
[orig, res, tb, rest, typ, i, tb] POP
|
||||
[orig, res, tb, rest, typ, i] POP
|
||||
|
||||
[orig, res, tb, rest, typ] L2: <evaluate E2>
|
||||
.............................etc.......................
|
||||
|
||||
[orig, res, tb, rest, typ] Ln+1: POP ) add unhandled exception
|
||||
[orig, res, tb, rest] LIST_APPEND 2 ) to res (could be None)
|
||||
[orig, res, tb] POP
|
||||
|
||||
[orig, res] PREP_RERAISE_STAR
|
||||
[i, tb, val, typ] POP_JUMP_IF_TRUE RER
|
||||
[i, tb, val, typ] POP
|
||||
[i, tb, val] POP
|
||||
[i, tb] POP
|
||||
[i] POP
|
||||
[] JUMP_FORWARD L0
|
||||
|
||||
[i, tb, val, typ] RER: POP_EXCEPT_AND_RERAISE
|
||||
|
||||
[] L0: <next statement>
|
||||
*/
|
||||
static int
|
||||
compiler_try_star_except(struct compiler *c, stmt_ty s)
|
||||
{
|
||||
basicblock *body = compiler_new_block(c);
|
||||
if (body == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *except = compiler_new_block(c);
|
||||
if (except == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *orelse = compiler_new_block(c);
|
||||
if (orelse == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *end = compiler_new_block(c);
|
||||
if (end == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *cleanup = compiler_new_block(c);
|
||||
if (cleanup == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *reraise_star = compiler_new_block(c);
|
||||
if (reraise_star == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADDOP_JUMP(c, SETUP_FINALLY, except);
|
||||
compiler_use_next_block(c, body);
|
||||
if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
VISIT_SEQ(c, stmt, s->v.TryStar.body);
|
||||
compiler_pop_fblock(c, TRY_EXCEPT, body);
|
||||
ADDOP_NOLINE(c, POP_BLOCK);
|
||||
ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, orelse);
|
||||
Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers);
|
||||
compiler_use_next_block(c, except);
|
||||
|
||||
UNSET_LOC(c);
|
||||
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
|
||||
ADDOP(c, PUSH_EXC_INFO);
|
||||
/* Runtime will push a block here, so we need to account for that */
|
||||
if (!compiler_push_fblock(c, EXCEPTION_GROUP_HANDLER,
|
||||
NULL, NULL, "except handler")) {
|
||||
return 0;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
|
||||
s->v.TryStar.handlers, i);
|
||||
SET_LOC(c, handler);
|
||||
except = compiler_new_block(c);
|
||||
if (except == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (i == 0) {
|
||||
/* Push the original EG into the stack */
|
||||
/*
|
||||
[tb, val, exc] DUP_TOP_TWO
|
||||
[tb, val, exc, val, exc] POP_TOP
|
||||
[tb, val, exc, val] ROT_FOUR
|
||||
[val, tb, val, exc]
|
||||
*/
|
||||
ADDOP(c, DUP_TOP_TWO);
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP(c, ROT_FOUR);
|
||||
|
||||
/* create empty list for exceptions raised/reraise in the except* blocks */
|
||||
/*
|
||||
[val, tb, val, exc] BUILD_LIST
|
||||
[val, tb, val, exc, []] ROT_FOUR
|
||||
[val, [], tb, val, exc]
|
||||
*/
|
||||
ADDOP_I(c, BUILD_LIST, 0);
|
||||
ADDOP(c, ROT_FOUR);
|
||||
}
|
||||
if (handler->v.ExceptHandler.type) {
|
||||
VISIT(c, expr, handler->v.ExceptHandler.type);
|
||||
ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except);
|
||||
NEXT_BLOCK(c);
|
||||
}
|
||||
ADDOP(c, POP_TOP); // exc_type
|
||||
|
||||
basicblock *cleanup_end = compiler_new_block(c);
|
||||
if (cleanup_end == NULL) {
|
||||
return 0;
|
||||
}
|
||||
basicblock *cleanup_body = compiler_new_block(c);
|
||||
if (cleanup_body == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handler->v.ExceptHandler.name) {
|
||||
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
|
||||
}
|
||||
else {
|
||||
ADDOP(c, POP_TOP); // val
|
||||
}
|
||||
ADDOP(c, POP_TOP); // tb
|
||||
|
||||
/*
|
||||
try:
|
||||
# body
|
||||
except type as name:
|
||||
try:
|
||||
# body
|
||||
finally:
|
||||
name = None # in case body contains "del name"
|
||||
del name
|
||||
*/
|
||||
/* second try: */
|
||||
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end);
|
||||
compiler_use_next_block(c, cleanup_body);
|
||||
if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, handler->v.ExceptHandler.name))
|
||||
return 0;
|
||||
|
||||
/* second # body */
|
||||
VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
|
||||
compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body);
|
||||
/* name = None; del name; # Mark as artificial */
|
||||
UNSET_LOC(c);
|
||||
ADDOP(c, POP_BLOCK);
|
||||
if (handler->v.ExceptHandler.name) {
|
||||
ADDOP_LOAD_CONST(c, Py_None);
|
||||
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
|
||||
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
|
||||
}
|
||||
ADDOP_JUMP(c, JUMP_FORWARD, except);
|
||||
|
||||
/* except: */
|
||||
compiler_use_next_block(c, cleanup_end);
|
||||
|
||||
/* name = None; del name; # Mark as artificial */
|
||||
UNSET_LOC(c);
|
||||
|
||||
if (handler->v.ExceptHandler.name) {
|
||||
ADDOP_LOAD_CONST(c, Py_None);
|
||||
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
|
||||
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
|
||||
}
|
||||
|
||||
/* add exception raised to the res list */
|
||||
ADDOP(c, POP_TOP); // type
|
||||
ADDOP_I(c, LIST_APPEND, 6); // exc
|
||||
ADDOP(c, POP_TOP); // tb
|
||||
ADDOP(c, POP_TOP); // lasti
|
||||
|
||||
ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
|
||||
compiler_use_next_block(c, except);
|
||||
|
||||
if (i == n - 1) {
|
||||
/* Add exc to the list (if not None it's the unhandled part of the EG) */
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP_I(c, LIST_APPEND, 2);
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
|
||||
}
|
||||
}
|
||||
/* Mark as artificial */
|
||||
UNSET_LOC(c);
|
||||
compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NULL);
|
||||
basicblock *reraise = compiler_new_block(c);
|
||||
if (!reraise) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
compiler_use_next_block(c, reraise_star);
|
||||
ADDOP(c, PREP_RERAISE_STAR);
|
||||
ADDOP(c, DUP_TOP);
|
||||
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, reraise);
|
||||
NEXT_BLOCK(c);
|
||||
|
||||
/* Nothing to reraise - pop it */
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP(c, POP_TOP);
|
||||
ADDOP(c, POP_BLOCK);
|
||||
ADDOP(c, POP_EXCEPT);
|
||||
ADDOP_JUMP(c, JUMP_FORWARD, end);
|
||||
compiler_use_next_block(c, reraise);
|
||||
ADDOP(c, POP_BLOCK);
|
||||
ADDOP(c, POP_EXCEPT_AND_RERAISE);
|
||||
compiler_use_next_block(c, cleanup);
|
||||
ADDOP(c, POP_EXCEPT_AND_RERAISE);
|
||||
compiler_use_next_block(c, orelse);
|
||||
VISIT_SEQ(c, stmt, s->v.TryStar.orelse);
|
||||
ADDOP_JUMP(c, JUMP_FORWARD, end);
|
||||
compiler_use_next_block(c, end);
|
||||
return 1;
|
||||
}
|
||||
|
@ -3372,6 +3697,16 @@ compiler_try(struct compiler *c, stmt_ty s) {
|
|||
return compiler_try_except(c, s);
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_try_star(struct compiler *c, stmt_ty s)
|
||||
{
|
||||
if (s->v.TryStar.finalbody && asdl_seq_LEN(s->v.TryStar.finalbody)) {
|
||||
return compiler_try_star_finally(c, s);
|
||||
}
|
||||
else {
|
||||
return compiler_try_star_except(c, s);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_import_as(struct compiler *c, identifier name, identifier asname)
|
||||
|
@ -3634,6 +3969,8 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
|
|||
break;
|
||||
case Try_kind:
|
||||
return compiler_try(c, s);
|
||||
case TryStar_kind:
|
||||
return compiler_try_star(c, s);
|
||||
case Assert_kind:
|
||||
return compiler_assert(c, s);
|
||||
case Import_kind:
|
||||
|
|
6
Python/opcode_targets.h
generated
6
Python/opcode_targets.h
generated
|
@ -87,7 +87,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_SETUP_ANNOTATIONS,
|
||||
&&TARGET_YIELD_VALUE,
|
||||
&&TARGET_LOAD_CONST__LOAD_FAST,
|
||||
&&TARGET_STORE_FAST__STORE_FAST,
|
||||
&&TARGET_PREP_RERAISE_STAR,
|
||||
&&TARGET_POP_EXCEPT,
|
||||
&&TARGET_STORE_NAME,
|
||||
&&TARGET_DELETE_NAME,
|
||||
|
@ -122,11 +122,11 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_COPY,
|
||||
&&TARGET_JUMP_IF_NOT_EXC_MATCH,
|
||||
&&TARGET_BINARY_OP,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_STORE_FAST__STORE_FAST,
|
||||
&&TARGET_LOAD_FAST,
|
||||
&&TARGET_STORE_FAST,
|
||||
&&TARGET_DELETE_FAST,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_JUMP_IF_NOT_EG_MATCH,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_GEN_START,
|
||||
&&TARGET_RAISE_VARARGS,
|
||||
|
|
|
@ -1345,6 +1345,12 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
|||
VISIT_SEQ(st, excepthandler, s->v.Try.handlers);
|
||||
VISIT_SEQ(st, stmt, s->v.Try.finalbody);
|
||||
break;
|
||||
case TryStar_kind:
|
||||
VISIT_SEQ(st, stmt, s->v.TryStar.body);
|
||||
VISIT_SEQ(st, stmt, s->v.TryStar.orelse);
|
||||
VISIT_SEQ(st, excepthandler, s->v.TryStar.handlers);
|
||||
VISIT_SEQ(st, stmt, s->v.TryStar.finalbody);
|
||||
break;
|
||||
case Assert_kind:
|
||||
VISIT(st, expr, s->v.Assert.test);
|
||||
if (s->v.Assert.msg)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue