summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1996-12-10 18:07:35 (GMT)
committerGuido van Rossum <guido@python.org>1996-12-10 18:07:35 (GMT)
commit0aa9ee65ab66627c2d065d213090aec93e634ee9 (patch)
treeee0ec8ac491f39baddc05994df998553714bcd2e
parent6c31a14de7b9a447fa476b773ae895b219f212e6 (diff)
downloadcpython-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.c187
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)