diff options
author | Guido van Rossum <guido@python.org> | 1996-12-10 18:07:35 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1996-12-10 18:07:35 (GMT) |
commit | 0aa9ee65ab66627c2d065d213090aec93e634ee9 (patch) | |
tree | ee0ec8ac491f39baddc05994df998553714bcd2e | |
parent | 6c31a14de7b9a447fa476b773ae895b219f212e6 (diff) | |
download | cpython-0aa9ee65ab66627c2d065d213090aec93e634ee9.zip cpython-0aa9ee65ab66627c2d065d213090aec93e634ee9.tar.gz cpython-0aa9ee65ab66627c2d065d213090aec93e634ee9.tar.bz2 |
Moved the raise logic out of the main interpreter loop to a separate function.
The raise logic has one additional feature: if you raise <class>,
<value> where <value> is not an instance, it will construct an
instance using <value> as argument. If <value> is None, <class> is
instantiated without arguments. If <value> 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.
-rw-r--r-- | Python/ceval.c | 187 |
1 files changed, 127 insertions, 60 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index cee606b..7b7fdf0 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 <class>, <classinstance> + raise <class>, <argument tuple> + raise <class>, None + raise <class>, <argument> + raise <classinstance>, None + raise <string>, <object> + raise <string>, None + + An omitted second argument is the same as None. + + In addition, raise <tuple>, <anything> 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 <class>, <instance> requires that <instance> is a member of <class>"); + 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 <class>, <instance> */ + 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) |