Commit a4adedee authored by Guido van Rossum's avatar Guido van Rossum

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.
parent e1622b36
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment