From 0aa9ee65ab66627c2d065d213090aec93e634ee9 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 10 Dec 1996 18:07:35 +0000 Subject: [PATCH] Moved the raise logic out of the main interpreter loop to a separate function. The raise logic has one additional feature: if you raise , where is not an instance, it will construct an instance using as argument. If is None, is instantiated without arguments. If is a tuple, it is used as the argument list. This feature is intended to make it easier to upgrade code from using string exceptions to using class exceptions; without this feature, you'd have to change every raise statement from ``raise X'' to ``raise X()'' and from ``raise X, y'' to ``raise X(y)''. The latter is still the recommended form (because it has no ambiguities about the number of arguments), but this change makes the transition less painful. --- Python/ceval.c | 187 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 60 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index cee606b5ead..7b7fdf0ac51 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -66,6 +66,7 @@ static object *eval_code2 PROTO((codeobject *, object **, int, object **, int, object *)); +static int do_raise PROTO((object *, object *, object *)); #ifdef LLTRACE static int prtrace PROTO((object *, char *)); #endif @@ -945,77 +946,20 @@ eval_code2(co, globals, locals, switch (oparg) { case 3: u = POP(); /* traceback */ - if (u == None) { - DECREF(u); - u = NULL; - } - else if (!PyTraceBack_Check(u)) { - err_setstr(TypeError, - "raise 3rd arg must be traceback or None"); - goto raise_error; - } /* Fallthrough */ case 2: v = POP(); /* value */ /* Fallthrough */ case 1: w = POP(); /* exc */ + why = do_raise(w, v, u); break; default: err_setstr(SystemError, "bad RAISE_VARARGS oparg"); - goto raise_error; - } - if (v == NULL) { - v = None; - INCREF(v); - } - /* A tuple is equivalent to its first element here */ - while (is_tupleobject(w) && gettuplesize(w) > 0) { - t = w; - w = GETTUPLEITEM(w, 0); - INCREF(w); - DECREF(t); - } - if (is_stringobject(w)) { - ; - } else if (is_classobject(w)) { - if (!is_instanceobject(v) - || !issubclass((object*)((instanceobject*)v)->in_class, - w)) { - err_setstr(TypeError, - "a class exception must have a value that is an instance of the class"); - goto raise_error; - } - } else if (is_instanceobject(w)) { - if (v != None) { - err_setstr(TypeError, - "an instance exception may not have a separate value"); - goto raise_error; - } - else { - DECREF(v); - v = w; - w = (object*) ((instanceobject*)w)->in_class; - INCREF(w); - } - } - else { - err_setstr(TypeError, - "exceptions must be strings, classes, or instances"); - goto raise_error; - } - err_restore(w, v, u); - if (u == NULL) why = WHY_EXCEPTION; - else - why = WHY_RERAISE; - break; - raise_error: - XDECREF(v); - XDECREF(w); - XDECREF(u); - why = WHY_EXCEPTION; + break; + } break; case LOAD_LOCALS: @@ -1874,6 +1818,129 @@ eval_code2(co, globals, locals, return retval; } +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static int +do_raise(type, value, tb) + object *type, *value, *tb; +{ + /* We support the following forms of raise: + raise , + raise , + raise , None + raise , + raise , None + raise , + raise , None + + An omitted second argument is the same as None. + + In addition, raise , is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == None) { + DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + err_setstr(TypeError, + "raise 3rd arg must be traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = None; + INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (is_tupleobject(type) && gettuplesize(type) > 0) { + object *tmp = type; + type = GETTUPLEITEM(type, 0); + INCREF(type); + DECREF(tmp); + } + + /* Now switch on the exception's type */ + if (is_stringobject(type)) { + ; + } + else if (is_classobject(type)) { + /* Raising a class. If the value is an instance, it + better be an instance of the class. If it is not, + it will be used to create an instance. */ + if (is_instanceobject(value)) { + object *inclass = (object*) + (((instanceobject*)value)->in_class); + if (!issubclass(inclass, type)) { + err_setstr(TypeError, + "raise , requires that is a member of "); + goto raise_error; + } + } + else { + /* Go instantiate the class */ + object *args, *res; + if (value == None) + args = mkvalue("()"); + else if (is_tupleobject(value)) { + INCREF(value); + args = value; + } + else + args = mkvalue("(O)", value); + if (args == NULL) + goto raise_error; + res = call_object(type, args); + DECREF(args); + if (res == NULL) + goto raise_error; + DECREF(value); + value = res; + } + } + else if (is_instanceobject(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != None) { + err_setstr(TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise , */ + DECREF(value); + value = type; + type = (object*) ((instanceobject*)type)->in_class; + INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + err_setstr(TypeError, + "exceptions must be strings, classes, or instances"); + goto raise_error; + } + err_restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + XDECREF(value); + XDECREF(type); + XDECREF(tb); + return WHY_EXCEPTION; +} + #ifdef LLTRACE static int prtrace(v, str)