summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
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 /Python/ceval.c
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.
Diffstat (limited to 'Python/ceval.c')
-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)