]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Moved support functions after main function; added prototypes;
authorGuido van Rossum <guido@python.org>
Thu, 4 Apr 1991 10:40:29 +0000 (10:40 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 4 Apr 1991 10:40:29 +0000 (10:40 +0000)
Fixed 'needspace' hack to use a flag in the stdout file object;
added local and global variable lookup cases.

Python/ceval.c

index 5a9723fc27bde4b61324afcfc3b3bbe740b6cd34..badfcedd77d11801fa811a4cb52711c79f27b4da 100644 (file)
@@ -39,700 +39,164 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define TRACE
 #endif
 
-#ifdef TRACE
-static int
-prtrace(v, str)
-       object *v;
-       char *str;
-{
-       printf("%s ", str);
-       printobject(v, stdout, 0);
-       printf("\n");
-}
-#endif
+/* Forward declarations */
+/* XXX Need prototypes */
 
-static frameobject *current_frame;
+void flushline();
+static object *add();
+static object *sub();
+static object *mul();
+static object *divide();
+static object *rem();
+static object *neg();
+static object *pos();
+static object *not();
+static object *call_builtin();
+static object *call_function();
+static object *apply_subscript();
+static object *loop_subscript();
+static object *apply_slice();
+static object *cmp_outcome();
+static object *build_class();
+static int testbool();
+static int assign_subscript PROTO((object *, object *, object *));
+static int assign_slice PROTO((object *, object *, object *, object *));
+static int import_from PROTO((object *, object *, char *));
 
-object *
-getlocals()
-{
-       if (current_frame == NULL)
-               return NULL;
-       else
-               return current_frame->f_locals;
-}
 
-object *
-getglobals()
-{
-       if (current_frame == NULL)
-               return NULL;
-       else
-               return current_frame->f_globals;
-}
+static frameobject *current_frame;
 
-void
-printtraceback(fp)
-       FILE *fp;
-{
-       object *v = tb_fetch();
-       if (v != NULL) {
-               fprintf(fp, "Stack backtrace (innermost last):\n");
-               tb_print(v, fp);
-               DECREF(v);
-       }
-}
 
+/* Status code for main loop (reason for stack unwind) */
+
+enum why_code {
+               WHY_NOT,        /* No error */
+               WHY_EXCEPTION,  /* Exception occurred */
+               WHY_RERAISE,    /* Exception re-raised by 'finally' */
+               WHY_RETURN,     /* 'return' statement */
+               WHY_BREAK       /* 'break' statement */
+};
 
-/* XXX Mixing "print ...," and direct file I/O on stdin/stdout
-   XXX has some bad consequences.  The needspace flag should
-   XXX really be part of the file object. */
 
-static int needspace;
+/* Interpreter main loop */
 
-void
-flushline()
+object *
+eval_code(co, globals, locals, arg)
+       codeobject *co;
+       object *globals;
+       object *locals;
+       object *arg;
 {
-       FILE *fp = sysgetfile("stdout", stdout);
-       if (needspace) {
-               fprintf(fp, "\n");
-               needspace = 0;
-       }
-}
+       register unsigned char *next_instr;
+       register int opcode;    /* Current opcode */
+       register int oparg;     /* Current opcode argument, if any */
+       register object **stack_pointer;
+       register enum why_code why; /* Reason for block stack unwind */
+       register int err;       /* Error status -- nonzero if error */
+       register object *x;     /* Result object -- NULL if error */
+       register object *v;     /* Temporary objects popped off stack */
+       register object *w;
+       register object *u;
+       register object *t;
+       register frameobject *f; /* Current frame */
+       int lineno;             /* Current line number */
+       object *retval;         /* Return value iff why == WHY_RETURN */
+       char *name;             /* Name used by some instructions */
+       FILE *fp;               /* Used by print operations */
+#ifdef TRACE
+       int trace = dictlookup(globals, "__trace__") != NULL;
+#endif
 
+/* Code access macros */
 
-/* Test a value used as condition, e.g., in a for or if statement */
+#define GETCONST(i)    Getconst(f, i)
+#define GETNAME(i)     Getname(f, i)
+#define GETNAMEV(i)    Getnamev(f, i)
+#define FIRST_INSTR()  (GETUSTRINGVALUE(f->f_code->co_code))
+#define INSTR_OFFSET() (next_instr - FIRST_INSTR())
+#define NEXTOP()       (*next_instr++)
+#define NEXTARG()      (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
+#define JUMPTO(x)      (next_instr = FIRST_INSTR() + (x))
+#define JUMPBY(x)      (next_instr += (x))
 
-static int
-testbool(v)
-       object *v;
-{
-       if (is_intobject(v))
-               return getintvalue(v) != 0;
-       if (is_floatobject(v))
-               return getfloatvalue(v) != 0.0;
-       if (v->ob_type->tp_as_sequence != NULL)
-               return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0;
-       if (v->ob_type->tp_as_mapping != NULL)
-               return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0;
-       if (v == None)
-               return 0;
-       /* All other objects are 'true' */
-       return 1;
-}
+/* Stack manipulation macros */
 
-static object *
-add(v, w)
-       object *v, *w;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               v = (*v->ob_type->tp_as_number->nb_add)(v, w);
-       else if (v->ob_type->tp_as_sequence != NULL)
-               v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
-       else {
-               err_setstr(TypeError, "+ not supported by operands");
-               return NULL;
-       }
-       return v;
-}
+#define STACK_LEVEL()  (stack_pointer - f->f_valuestack)
+#define EMPTY()                (STACK_LEVEL() == 0)
+#define TOP()          (stack_pointer[-1])
+#define BASIC_PUSH(v)  (*stack_pointer++ = (v))
+#define BASIC_POP()    (*--stack_pointer)
 
-static object *
-sub(v, w)
-       object *v, *w;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               return (*v->ob_type->tp_as_number->nb_subtract)(v, w);
-       err_setstr(TypeError, "bad operand type(s) for -");
-       return NULL;
-}
+#ifdef TRACE
+#define PUSH(v)                (BASIC_PUSH(v), trace && prtrace(TOP(), "push"))
+#define POP()          (trace && prtrace(TOP(), "pop"), BASIC_POP())
+#else
+#define PUSH(v)                BASIC_PUSH(v)
+#define POP()          BASIC_POP()
+#endif
 
-static object *
-mul(v, w)
-       object *v, *w;
-{
-       typeobject *tp;
-       if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
-               /* int*sequence -- swap v and w */
-               object *tmp = v;
-               v = w;
-               w = tmp;
+       f = newframeobject(
+                       current_frame,          /*back*/
+                       co,                     /*code*/
+                       globals,                /*globals*/
+                       locals,                 /*locals*/
+                       50,                     /*nvalues*/
+                       20);                    /*nblocks*/
+       if (f == NULL)
+               return NULL;
+       
+       current_frame = f;
+       
+       next_instr = GETUSTRINGVALUE(f->f_code->co_code);
+       
+       stack_pointer = f->f_valuestack;
+       
+       if (arg != NULL) {
+               INCREF(arg);
+               PUSH(arg);
        }
-       tp = v->ob_type;
-       if (tp->tp_as_number != NULL)
-               return (*tp->tp_as_number->nb_multiply)(v, w);
-       if (tp->tp_as_sequence != NULL) {
-               if (!is_intobject(w)) {
-                       err_setstr(TypeError,
-                               "can't multiply sequence with non-int");
-                       return NULL;
-               }
-               if (tp->tp_as_sequence->sq_repeat == NULL) {
-                       err_setstr(TypeError, "sequence does not support *");
-                       return NULL;
+       
+       why = WHY_NOT;
+       err = 0;
+       x = None;       /* Not a reference, just anything non-NULL */
+       lineno = -1;
+       
+       for (;;) {
+               static ticker;
+               
+               /* Do periodic things */
+               
+               if (--ticker < 0) {
+                       ticker = 100;
+                       if (intrcheck()) {
+                               err_set(KeyboardInterrupt);
+                               why = WHY_EXCEPTION;
+                               tb_here(f, INSTR_OFFSET(), lineno);
+                               goto on_error;
+                       }
                }
-               return (*tp->tp_as_sequence->sq_repeat)
-                                               (v, (int)getintvalue(w));
-       }
-       err_setstr(TypeError, "bad operand type(s) for *");
-       return NULL;
-}
-
-static object *
-divide(v, w)
-       object *v, *w;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               return (*v->ob_type->tp_as_number->nb_divide)(v, w);
-       err_setstr(TypeError, "bad operand type(s) for /");
-       return NULL;
-}
+               
+               /* Extract opcode and argument */
+               
+               opcode = NEXTOP();
+               if (HAS_ARG(opcode))
+                       oparg = NEXTARG();
 
-static object *
-rem(v, w)
-       object *v, *w;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               return (*v->ob_type->tp_as_number->nb_remainder)(v, w);
-       err_setstr(TypeError, "bad operand type(s) for %");
-       return NULL;
-}
-
-static object *
-neg(v)
-       object *v;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               return (*v->ob_type->tp_as_number->nb_negative)(v);
-       err_setstr(TypeError, "bad operand type(s) for unary -");
-       return NULL;
-}
-
-static object *
-pos(v)
-       object *v;
-{
-       if (v->ob_type->tp_as_number != NULL)
-               return (*v->ob_type->tp_as_number->nb_positive)(v);
-       err_setstr(TypeError, "bad operand type(s) for unary +");
-       return NULL;
-}
-
-static object *
-not(v)
-       object *v;
-{
-       int outcome = testbool(v);
-       object *w = outcome == 0 ? True : False;
-       INCREF(w);
-       return w;
-}
-
-static object *
-call_builtin(func, arg)
-       object *func;
-       object *arg;
-{
-       if (is_methodobject(func)) {
-               method meth = getmethod(func);
-               object *self = getself(func);
-               return (*meth)(self, arg);
-       }
-       if (is_classobject(func)) {
-               if (arg != NULL) {
-                       err_setstr(TypeError,
-                               "classobject() allows no arguments");
-                       return NULL;
-               }
-               return newclassmemberobject(func);
-       }
-       err_setstr(TypeError, "call of non-function");
-       return NULL;
-}
-
-static object *
-call_function(func, arg)
-       object *func;
-       object *arg;
-{
-       object *newarg = NULL;
-       object *newlocals, *newglobals;
-       object *co, *v;
-       
-       if (is_classmethodobject(func)) {
-               object *self = classmethodgetself(func);
-               func = classmethodgetfunc(func);
-               if (arg == NULL) {
-                       arg = self;
-               }
-               else {
-                       newarg = newtupleobject(2);
-                       if (newarg == NULL)
-                               return NULL;
-                       INCREF(self);
-                       INCREF(arg);
-                       settupleitem(newarg, 0, self);
-                       settupleitem(newarg, 1, arg);
-                       arg = newarg;
-               }
-       }
-       else {
-               if (!is_funcobject(func)) {
-                       err_setstr(TypeError, "call of non-function");
-                       return NULL;
-               }
-       }
-       
-       co = getfunccode(func);
-       if (co == NULL) {
-               XDECREF(newarg);
-               return NULL;
-       }
-       if (!is_codeobject(co)) {
-               fprintf(stderr, "XXX Bad code\n");
-               abort();
-       }
-       newlocals = newdictobject();
-       if (newlocals == NULL) {
-               XDECREF(newarg);
-               return NULL;
-       }
-       
-       newglobals = getfuncglobals(func);
-       INCREF(newglobals);
-       
-       v = eval_code((codeobject *)co, newglobals, newlocals, arg);
-       
-       DECREF(newlocals);
-       DECREF(newglobals);
-       
-       XDECREF(newarg);
-       
-       return v;
-}
-
-static object *
-apply_subscript(v, w)
-       object *v, *w;
-{
-       typeobject *tp = v->ob_type;
-       if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) {
-               err_setstr(TypeError, "unsubscriptable object");
-               return NULL;
-       }
-       if (tp->tp_as_sequence != NULL) {
-               int i;
-               if (!is_intobject(w)) {
-                       err_setstr(TypeError, "sequence subscript not int");
-                       return NULL;
-               }
-               i = getintvalue(w);
-               return (*tp->tp_as_sequence->sq_item)(v, i);
-       }
-       return (*tp->tp_as_mapping->mp_subscript)(v, w);
-}
-
-static object *
-loop_subscript(v, w)
-       object *v, *w;
-{
-       sequence_methods *sq = v->ob_type->tp_as_sequence;
-       int i, n;
-       if (sq == NULL) {
-               err_setstr(TypeError, "loop over non-sequence");
-               return NULL;
-       }
-       i = getintvalue(w);
-       n = (*sq->sq_length)(v);
-       if (i >= n)
-               return NULL; /* End of loop */
-       return (*sq->sq_item)(v, i);
-}
-
-static int
-slice_index(v, isize, pi)
-       object *v;
-       int isize;
-       int *pi;
-{
-       if (v != NULL) {
-               if (!is_intobject(v)) {
-                       err_setstr(TypeError, "slice index must be int");
-                       return -1;
-               }
-               *pi = getintvalue(v);
-               if (*pi < 0)
-                       *pi += isize;
-       }
-       return 0;
-}
-
-static object *
-apply_slice(u, v, w) /* return u[v:w] */
-       object *u, *v, *w;
-{
-       typeobject *tp = u->ob_type;
-       int ilow, ihigh, isize;
-       if (tp->tp_as_sequence == NULL) {
-               err_setstr(TypeError, "only sequences can be sliced");
-               return NULL;
-       }
-       ilow = 0;
-       isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
-       if (slice_index(v, isize, &ilow) != 0)
-               return NULL;
-       if (slice_index(w, isize, &ihigh) != 0)
-               return NULL;
-       return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh);
-}
-
-static int
-assign_subscript(w, key, v) /* w[key] = v */
-       object *w;
-       object *key;
-       object *v;
-{
-       typeobject *tp = w->ob_type;
-       sequence_methods *sq;
-       mapping_methods *mp;
-       int (*func)();
-       if ((sq = tp->tp_as_sequence) != NULL &&
-                       (func = sq->sq_ass_item) != NULL) {
-               if (!is_intobject(key)) {
-                       err_setstr(TypeError,
-                               "sequence subscript must be integer");
-                       return -1;
-               }
-               else
-                       return (*func)(w, (int)getintvalue(key), v);
-       }
-       else if ((mp = tp->tp_as_mapping) != NULL &&
-                       (func = mp->mp_ass_subscript) != NULL) {
-               return (*func)(w, key, v);
-       }
-       else {
-               err_setstr(TypeError,
-                               "can't assign to this subscripted object");
-               return -1;
-       }
-}
-
-static int
-assign_slice(u, v, w, x) /* u[v:w] = x */
-       object *u, *v, *w, *x;
-{
-       sequence_methods *sq = u->ob_type->tp_as_sequence;
-       int ilow, ihigh, isize;
-       if (sq == NULL) {
-               err_setstr(TypeError, "assign to slice of non-sequence");
-               return -1;
-       }
-       if (sq == NULL || sq->sq_ass_slice == NULL) {
-               err_setstr(TypeError, "unassignable slice");
-               return -1;
-       }
-       ilow = 0;
-       isize = ihigh = (*sq->sq_length)(u);
-       if (slice_index(v, isize, &ilow) != 0)
-               return -1;
-       if (slice_index(w, isize, &ihigh) != 0)
-               return -1;
-       return (*sq->sq_ass_slice)(u, ilow, ihigh, x);
-}
-
-static int
-cmp_exception(err, v)
-       object *err, *v;
-{
-       if (is_tupleobject(v)) {
-               int i, n;
-               n = gettuplesize(v);
-               for (i = 0; i < n; i++) {
-                       if (err == gettupleitem(v, i))
-                               return 1;
-               }
-               return 0;
-       }
-       return err == v;
-}
-
-static int
-cmp_member(v, w)
-       object *v, *w;
-{
-       int i, n, cmp;
-       object *x;
-       sequence_methods *sq;
-       /* Special case for char in string */
-       if (is_stringobject(w)) {
-               register char *s, *end;
-               register char c;
-               if (!is_stringobject(v) || getstringsize(v) != 1) {
-                       err_setstr(TypeError,
-                           "string member test needs char left operand");
-                       return -1;
-               }
-               c = getstringvalue(v)[0];
-               s = getstringvalue(w);
-               end = s + getstringsize(w);
-               while (s < end) {
-                       if (c == *s++)
-                               return 1;
-               }
-               return 0;
-       }
-       sq = w->ob_type->tp_as_sequence;
-       if (sq == NULL) {
-               err_setstr(TypeError,
-                       "'in' or 'not in' needs sequence right argument");
-               return -1;
-       }
-       n = (*sq->sq_length)(w);
-       for (i = 0; i < n; i++) {
-               x = (*sq->sq_item)(w, i);
-               cmp = cmpobject(v, x);
-               XDECREF(x);
-               if (cmp == 0)
-                       return 1;
-       }
-       return 0;
-}
-
-static object *
-cmp_outcome(op, v, w)
-       enum cmp_op op;
-       register object *v;
-       register object *w;
-{
-       register int cmp;
-       register int res = 0;
-       switch (op) {
-       case IS:
-       case IS_NOT:
-               res = (v == w);
-               if (op == IS_NOT)
-                       res = !res;
-               break;
-       case IN:
-       case NOT_IN:
-               res = cmp_member(v, w);
-               if (res < 0)
-                       return NULL;
-               if (op == NOT_IN)
-                       res = !res;
-               break;
-       case EXC_MATCH:
-               res = cmp_exception(v, w);
-               break;
-       default:
-               cmp = cmpobject(v, w);
-               switch (op) {
-               case LT: res = cmp <  0; break;
-               case LE: res = cmp <= 0; break;
-               case EQ: res = cmp == 0; break;
-               case NE: res = cmp != 0; break;
-               case GT: res = cmp >  0; break;
-               case GE: res = cmp >= 0; break;
-               /* XXX no default? (res is initialized to 0 though) */
-               }
-       }
-       v = res ? True : False;
-       INCREF(v);
-       return v;
-}
-
-static int
-import_from(locals, v, name)
-       object *locals;
-       object *v;
-       char *name;
-{
-       object *w, *x;
-       w = getmoduledict(v);
-       if (name[0] == '*') {
-               int i;
-               int n = getdictsize(w);
-               for (i = 0; i < n; i++) {
-                       name = getdictkey(w, i);
-                       if (name == NULL || name[0] == '_')
-                               continue;
-                       x = dictlookup(w, name);
-                       if (x == NULL) {
-                               /* XXX can't happen? */
-                               err_setstr(NameError, name);
-                               return -1;
-                       }
-                       if (dictinsert(locals, name, x) != 0)
-                               return -1;
-               }
-               return 0;
-       }
-       else {
-               x = dictlookup(w, name);
-               if (x == NULL) {
-                       err_setstr(NameError, name);
-                       return -1;
-               }
-               else
-                       return dictinsert(locals, name, x);
-       }
-}
-
-static object *
-build_class(v, w)
-       object *v; /* None or tuple containing base classes */
-       object *w; /* dictionary */
-{
-       if (is_tupleobject(v)) {
-               int i;
-               for (i = gettuplesize(v); --i >= 0; ) {
-                       object *x = gettupleitem(v, i);
-                       if (!is_classobject(x)) {
-                               err_setstr(TypeError,
-                                       "base is not a class object");
-                               return NULL;
-                       }
-               }
-       }
-       else {
-               v = NULL;
-       }
-       if (!is_dictobject(w)) {
-               err_setstr(SystemError, "build_class with non-dictionary");
-               return NULL;
-       }
-       return newclassobject(v, w);
-}
-
-
-/* Status code for main loop (reason for stack unwind) */
-
-enum why_code {
-               WHY_NOT,        /* No error */
-               WHY_EXCEPTION,  /* Exception occurred */
-               WHY_RERAISE,    /* Exception re-raised by 'finally' */
-               WHY_RETURN,     /* 'return' statement */
-               WHY_BREAK       /* 'break' statement */
-};
-
-/* Interpreter main loop */
-
-object *
-eval_code(co, globals, locals, arg)
-       codeobject *co;
-       object *globals;
-       object *locals;
-       object *arg;
-{
-       register unsigned char *next_instr;
-       register int opcode;    /* Current opcode */
-       register int oparg;     /* Current opcode argument, if any */
-       register object **stack_pointer;
-       register enum why_code why; /* Reason for block stack unwind */
-       register int err;       /* Error status -- nonzero if error */
-       register object *x;     /* Result object -- NULL if error */
-       register object *v;     /* Temporary objects popped off stack */
-       register object *w;
-       register object *u;
-       register object *t;
-       register frameobject *f; /* Current frame */
-       int lineno;             /* Current line number */
-       object *retval;         /* Return value iff why == WHY_RETURN */
-       char *name;             /* Name used by some instructions */
-       FILE *fp;               /* Used by print operations */
-#ifdef TRACE
-       int trace = dictlookup(globals, "__trace__") != NULL;
-#endif
-
-/* Code access macros */
-
-#define GETCONST(i)    Getconst(f, i)
-#define GETNAME(i)     Getname(f, i)
-#define GETNAMEV(i)    Getnamev(f, i)
-#define FIRST_INSTR()  (GETUSTRINGVALUE(f->f_code->co_code))
-#define INSTR_OFFSET() (next_instr - FIRST_INSTR())
-#define NEXTOP()       (*next_instr++)
-#define NEXTARG()      (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
-#define JUMPTO(x)      (next_instr = FIRST_INSTR() + (x))
-#define JUMPBY(x)      (next_instr += (x))
-
-/* Stack manipulation macros */
-
-#define STACK_LEVEL()  (stack_pointer - f->f_valuestack)
-#define EMPTY()                (STACK_LEVEL() == 0)
-#define TOP()          (stack_pointer[-1])
-#define BASIC_PUSH(v)  (*stack_pointer++ = (v))
-#define BASIC_POP()    (*--stack_pointer)
-
-#ifdef TRACE
-#define PUSH(v)                (BASIC_PUSH(v), trace && prtrace(TOP(), "push"))
-#define POP()          (trace && prtrace(TOP(), "pop"), BASIC_POP())
-#else
-#define PUSH(v)                BASIC_PUSH(v)
-#define POP()          BASIC_POP()
-#endif
-
-       f = newframeobject(
-                       current_frame,          /*back*/
-                       co,                     /*code*/
-                       globals,                /*globals*/
-                       locals,                 /*locals*/
-                       50,                     /*nvalues*/
-                       20);                    /*nblocks*/
-       if (f == NULL)
-               return NULL;
-       
-       current_frame = f;
-       
-       next_instr = GETUSTRINGVALUE(f->f_code->co_code);
-       
-       stack_pointer = f->f_valuestack;
-       
-       if (arg != NULL) {
-               INCREF(arg);
-               PUSH(arg);
-       }
-       
-       why = WHY_NOT;
-       err = 0;
-       x = None;       /* Not a reference, just anything non-NULL */
-       lineno = -1;
-       
-       for (;;) {
-               static ticker;
-               
-               /* Do periodic things */
-               
-               if (--ticker < 0) {
-                       ticker = 100;
-                       if (intrcheck()) {
-                               err_set(KeyboardInterrupt);
-                               why = WHY_EXCEPTION;
-                               tb_here(f, INSTR_OFFSET(), lineno);
-                               break;
-                       }
-               }
-               
-               /* Extract opcode and argument */
-               
-               opcode = NEXTOP();
-               if (HAS_ARG(opcode))
-                       oparg = NEXTARG();
-
-#ifdef TRACE
-               /* Instruction tracing */
-               
-               if (trace) {
-                       if (HAS_ARG(opcode)) {
-                               printf("%d: %d, %d\n",
-                                       (int) (INSTR_OFFSET() - 3),
-                                       opcode, oparg);
-                       }
-                       else {
-                               printf("%d: %d\n",
-                                       (int) (INSTR_OFFSET() - 1), opcode);
-                       }
-               }
-#endif
+#ifdef TRACE
+               /* Instruction tracing */
+               
+               if (trace) {
+                       if (HAS_ARG(opcode)) {
+                               printf("%d: %d, %d\n",
+                                       (int) (INSTR_OFFSET() - 3),
+                                       opcode, oparg);
+                       }
+                       else {
+                               printf("%d: %d\n",
+                                       (int) (INSTR_OFFSET() - 1), opcode);
+                       }
+               }
+#endif
 
                /* Main switch on opcode */
                
@@ -963,8 +427,9 @@ eval_code(co, globals, locals, arg)
                        /* Print value except if procedure result */
                        if (v != None) {
                                flushline();
+                               softspace(sysget("stdout"), 1);
                                printobject(v, fp, 0);
-                               fprintf(fp, "\n");
+                               flushline();
                        }
                        DECREF(v);
                        break;
@@ -972,20 +437,17 @@ eval_code(co, globals, locals, arg)
                case PRINT_ITEM:
                        v = POP();
                        fp = sysgetfile("stdout", stdout);
-                       if (needspace)
+                       if (softspace(sysget("stdout"), 1))
                                fprintf(fp, " ");
                        if (is_stringobject(v)) {
                                char *s = getstringvalue(v);
                                int len = getstringsize(v);
                                fwrite(s, 1, len, fp);
                                if (len > 0 && s[len-1] == '\n')
-                                       needspace = 0;
-                               else
-                                       needspace = 1;
+                                       softspace(sysget("stdout"), 0);
                        }
                        else {
                                printobject(v, fp, 0);
-                               needspace = 1;
                        }
                        DECREF(v);
                        break;
@@ -993,7 +455,7 @@ eval_code(co, globals, locals, arg)
                case PRINT_NEWLINE:
                        fp = sysgetfile("stdout", stdout);
                        fprintf(fp, "\n");
-                       needspace = 0;
+                       softspace(sysget("stdout"), 0);
                        break;
                
                case BREAK_LOOP:
@@ -1173,13 +635,40 @@ eval_code(co, globals, locals, arg)
                        x = dictlookup(f->f_locals, name);
                        if (x == NULL) {
                                x = dictlookup(f->f_globals, name);
-                               if (x == NULL)
+                               if (x == NULL) {
                                        x = getbuiltin(name);
+                                       if (x == NULL) {
+                                               err_setstr(NameError, name);
+                                               break;
+                                       }
+                               }
+                       }
+                       INCREF(x);
+                       PUSH(x);
+                       break;
+               
+               case LOAD_GLOBAL:
+                       name = GETNAME(oparg);
+                       x = dictlookup(f->f_globals, name);
+                       if (x == NULL) {
+                               x = getbuiltin(name);
+                               if (x == NULL) {
+                                       err_setstr(NameError, name);
+                                       break;
+                               }
                        }
-                       if (x == NULL)
+                       INCREF(x);
+                       PUSH(x);
+                       break;
+               
+               case LOAD_LOCAL:
+                       name = GETNAME(oparg);
+                       x = dictlookup(f->f_locals, name);
+                       if (x == NULL) {
                                err_setstr(NameError, name);
-                       else
-                               INCREF(x);
+                               break;
+                       }
+                       INCREF(x);
                        PUSH(x);
                        break;
                
@@ -1315,123 +804,679 @@ eval_code(co, globals, locals, arg)
                
                } /* switch */
 
-               
-               /* Quickly continue if no error occurred */
-               
-               if (why == WHY_NOT) {
-                       if (err == 0 && x != NULL)
-                               continue; /* Normal, fast path */
-                       why = WHY_EXCEPTION;
-                       x = None;
-                       err = 0;
+           on_error:
+               
+               /* Quickly continue if no error occurred */
+               
+               if (why == WHY_NOT) {
+                       if (err == 0 && x != NULL)
+                               continue; /* Normal, fast path */
+                       why = WHY_EXCEPTION;
+                       x = None;
+                       err = 0;
+               }
+
+#ifndef NDEBUG
+               /* Double-check exception status */
+               
+               if (why == WHY_EXCEPTION || why == WHY_RERAISE) {
+                       if (!err_occurred()) {
+                               fprintf(stderr, "XXX ghost error\n");
+                               err_setstr(SystemError, "ghost error");
+                               why = WHY_EXCEPTION;
+                       }
+               }
+               else {
+                       if (err_occurred()) {
+                               fprintf(stderr, "XXX undetected error\n");
+                               why = WHY_EXCEPTION;
+                       }
+               }
+#endif
+
+               /* Log traceback info if this is a real exception */
+               
+               if (why == WHY_EXCEPTION) {
+                       int lasti = INSTR_OFFSET() - 1;
+                       if (HAS_ARG(opcode))
+                               lasti -= 2;
+                       tb_here(f, lasti, lineno);
+               }
+               
+               /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
+               
+               if (why == WHY_RERAISE)
+                       why = WHY_EXCEPTION;
+
+               /* Unwind stacks if a (pseudo) exception occurred */
+               
+               while (why != WHY_NOT && f->f_iblock > 0) {
+                       block *b = pop_block(f);
+                       while (STACK_LEVEL() > b->b_level) {
+                               v = POP();
+                               XDECREF(v);
+                       }
+                       if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
+                               why = WHY_NOT;
+                               JUMPTO(b->b_handler);
+                               break;
+                       }
+                       if (b->b_type == SETUP_FINALLY ||
+                                       b->b_type == SETUP_EXCEPT &&
+                                       why == WHY_EXCEPTION) {
+                               if (why == WHY_EXCEPTION) {
+                                       object *exc, *val;
+                                       err_get(&exc, &val);
+                                       if (val == NULL) {
+                                               val = None;
+                                               INCREF(val);
+                                       }
+                                       v = tb_fetch();
+                                       /* Make the raw exception data
+                                          available to the handler,
+                                          so a program can emulate the
+                                          Python main loop.  Don't do
+                                          this for 'finally'. */
+                                       if (b->b_type == SETUP_EXCEPT) {
+#if 0 /* Oops, this breaks too many things */
+                                               sysset("exc_traceback", v);
+#endif
+                                               sysset("exc_value", val);
+                                               sysset("exc_type", exc);
+                                               err_clear();
+                                       }
+                                       PUSH(v);
+                                       PUSH(val);
+                                       PUSH(exc);
+                               }
+                               else {
+                                       if (why == WHY_RETURN)
+                                               PUSH(retval);
+                                       v = newintobject((long)why);
+                                       PUSH(v);
+                               }
+                               why = WHY_NOT;
+                               JUMPTO(b->b_handler);
+                               break;
+                       }
+               } /* unwind stack */
+
+               /* End the loop if we still have an error (or return) */
+               
+               if (why != WHY_NOT)
+                       break;
+               
+       } /* main loop */
+       
+       /* Pop remaining stack entries */
+       
+       while (!EMPTY()) {
+               v = POP();
+               XDECREF(v);
+       }
+       
+       /* Restore previous frame and release the current one */
+       
+       current_frame = f->f_back;
+       DECREF(f);
+       
+       if (why == WHY_RETURN)
+               return retval;
+       else
+               return NULL;
+}
+
+#ifdef TRACE
+static int
+prtrace(v, str)
+       object *v;
+       char *str;
+{
+       printf("%s ", str);
+       printobject(v, stdout, 0);
+       printf("\n");
+}
+#endif
+
+object *
+getlocals()
+{
+       if (current_frame == NULL)
+               return NULL;
+       else
+               return current_frame->f_locals;
+}
+
+object *
+getglobals()
+{
+       if (current_frame == NULL)
+               return NULL;
+       else
+               return current_frame->f_globals;
+}
+
+void
+printtraceback(fp)
+       FILE *fp;
+{
+       object *v = tb_fetch();
+       if (v != NULL) {
+               fprintf(fp, "Stack backtrace (innermost last):\n");
+               tb_print(v, fp);
+               DECREF(v);
+       }
+}
+
+
+void
+flushline()
+{
+       if (softspace(sysget("stdout"), 0))
+               fprintf(sysgetfile("stdout", stdout), "\n");
+}
+
+
+/* Test a value used as condition, e.g., in a for or if statement */
+
+static int
+testbool(v)
+       object *v;
+{
+       if (is_intobject(v))
+               return getintvalue(v) != 0;
+       if (is_floatobject(v))
+               return getfloatvalue(v) != 0.0;
+       if (v->ob_type->tp_as_sequence != NULL)
+               return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0;
+       if (v->ob_type->tp_as_mapping != NULL)
+               return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0;
+       if (v == None)
+               return 0;
+       /* All other objects are 'true' */
+       return 1;
+}
+
+static object *
+add(v, w)
+       object *v, *w;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               v = (*v->ob_type->tp_as_number->nb_add)(v, w);
+       else if (v->ob_type->tp_as_sequence != NULL)
+               v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
+       else {
+               err_setstr(TypeError, "+ not supported by operands");
+               return NULL;
+       }
+       return v;
+}
+
+static object *
+sub(v, w)
+       object *v, *w;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               return (*v->ob_type->tp_as_number->nb_subtract)(v, w);
+       err_setstr(TypeError, "bad operand type(s) for -");
+       return NULL;
+}
+
+static object *
+mul(v, w)
+       object *v, *w;
+{
+       typeobject *tp;
+       if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
+               /* int*sequence -- swap v and w */
+               object *tmp = v;
+               v = w;
+               w = tmp;
+       }
+       tp = v->ob_type;
+       if (tp->tp_as_number != NULL)
+               return (*tp->tp_as_number->nb_multiply)(v, w);
+       if (tp->tp_as_sequence != NULL) {
+               if (!is_intobject(w)) {
+                       err_setstr(TypeError,
+                               "can't multiply sequence with non-int");
+                       return NULL;
+               }
+               if (tp->tp_as_sequence->sq_repeat == NULL) {
+                       err_setstr(TypeError, "sequence does not support *");
+                       return NULL;
+               }
+               return (*tp->tp_as_sequence->sq_repeat)
+                                               (v, (int)getintvalue(w));
+       }
+       err_setstr(TypeError, "bad operand type(s) for *");
+       return NULL;
+}
+
+static object *
+divide(v, w)
+       object *v, *w;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               return (*v->ob_type->tp_as_number->nb_divide)(v, w);
+       err_setstr(TypeError, "bad operand type(s) for /");
+       return NULL;
+}
+
+static object *
+rem(v, w)
+       object *v, *w;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               return (*v->ob_type->tp_as_number->nb_remainder)(v, w);
+       err_setstr(TypeError, "bad operand type(s) for %");
+       return NULL;
+}
+
+static object *
+neg(v)
+       object *v;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               return (*v->ob_type->tp_as_number->nb_negative)(v);
+       err_setstr(TypeError, "bad operand type(s) for unary -");
+       return NULL;
+}
+
+static object *
+pos(v)
+       object *v;
+{
+       if (v->ob_type->tp_as_number != NULL)
+               return (*v->ob_type->tp_as_number->nb_positive)(v);
+       err_setstr(TypeError, "bad operand type(s) for unary +");
+       return NULL;
+}
+
+static object *
+not(v)
+       object *v;
+{
+       int outcome = testbool(v);
+       object *w = outcome == 0 ? True : False;
+       INCREF(w);
+       return w;
+}
+
+static object *
+call_builtin(func, arg)
+       object *func;
+       object *arg;
+{
+       if (is_methodobject(func)) {
+               method meth = getmethod(func);
+               object *self = getself(func);
+               return (*meth)(self, arg);
+       }
+       if (is_classobject(func)) {
+               if (arg != NULL) {
+                       err_setstr(TypeError,
+                               "classobject() allows no arguments");
+                       return NULL;
+               }
+               return newinstanceobject(func);
+       }
+       err_setstr(TypeError, "call of non-function");
+       return NULL;
+}
+
+static object *
+call_function(func, arg)
+       object *func;
+       object *arg;
+{
+       object *newarg = NULL;
+       object *newlocals, *newglobals;
+       object *co, *v;
+       
+       if (is_classmethodobject(func)) {
+               object *self = classmethodgetself(func);
+               func = classmethodgetfunc(func);
+               if (arg == NULL) {
+                       arg = self;
+               }
+               else {
+                       newarg = newtupleobject(2);
+                       if (newarg == NULL)
+                               return NULL;
+                       INCREF(self);
+                       INCREF(arg);
+                       settupleitem(newarg, 0, self);
+                       settupleitem(newarg, 1, arg);
+                       arg = newarg;
+               }
+       }
+       else {
+               if (!is_funcobject(func)) {
+                       err_setstr(TypeError, "call of non-function");
+                       return NULL;
+               }
+       }
+       
+       co = getfunccode(func);
+       if (co == NULL) {
+               XDECREF(newarg);
+               return NULL;
+       }
+       if (!is_codeobject(co)) {
+               fprintf(stderr, "XXX Bad code\n");
+               abort();
+       }
+       newlocals = newdictobject();
+       if (newlocals == NULL) {
+               XDECREF(newarg);
+               return NULL;
+       }
+       
+       newglobals = getfuncglobals(func);
+       INCREF(newglobals);
+       
+       v = eval_code((codeobject *)co, newglobals, newlocals, arg);
+       
+       DECREF(newlocals);
+       DECREF(newglobals);
+       
+       XDECREF(newarg);
+       
+       return v;
+}
+
+static object *
+apply_subscript(v, w)
+       object *v, *w;
+{
+       typeobject *tp = v->ob_type;
+       if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) {
+               err_setstr(TypeError, "unsubscriptable object");
+               return NULL;
+       }
+       if (tp->tp_as_sequence != NULL) {
+               int i;
+               if (!is_intobject(w)) {
+                       err_setstr(TypeError, "sequence subscript not int");
+                       return NULL;
+               }
+               i = getintvalue(w);
+               return (*tp->tp_as_sequence->sq_item)(v, i);
+       }
+       return (*tp->tp_as_mapping->mp_subscript)(v, w);
+}
+
+static object *
+loop_subscript(v, w)
+       object *v, *w;
+{
+       sequence_methods *sq = v->ob_type->tp_as_sequence;
+       int i, n;
+       if (sq == NULL) {
+               err_setstr(TypeError, "loop over non-sequence");
+               return NULL;
+       }
+       i = getintvalue(w);
+       n = (*sq->sq_length)(v);
+       if (i >= n)
+               return NULL; /* End of loop */
+       return (*sq->sq_item)(v, i);
+}
+
+static int
+slice_index(v, isize, pi)
+       object *v;
+       int isize;
+       int *pi;
+{
+       if (v != NULL) {
+               if (!is_intobject(v)) {
+                       err_setstr(TypeError, "slice index must be int");
+                       return -1;
+               }
+               *pi = getintvalue(v);
+               if (*pi < 0)
+                       *pi += isize;
+       }
+       return 0;
+}
+
+static object *
+apply_slice(u, v, w) /* return u[v:w] */
+       object *u, *v, *w;
+{
+       typeobject *tp = u->ob_type;
+       int ilow, ihigh, isize;
+       if (tp->tp_as_sequence == NULL) {
+               err_setstr(TypeError, "only sequences can be sliced");
+               return NULL;
+       }
+       ilow = 0;
+       isize = ihigh = (*tp->tp_as_sequence->sq_length)(u);
+       if (slice_index(v, isize, &ilow) != 0)
+               return NULL;
+       if (slice_index(w, isize, &ihigh) != 0)
+               return NULL;
+       return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh);
+}
+
+static int
+assign_subscript(w, key, v) /* w[key] = v */
+       object *w;
+       object *key;
+       object *v;
+{
+       typeobject *tp = w->ob_type;
+       sequence_methods *sq;
+       mapping_methods *mp;
+       int (*func)();
+       if ((sq = tp->tp_as_sequence) != NULL &&
+                       (func = sq->sq_ass_item) != NULL) {
+               if (!is_intobject(key)) {
+                       err_setstr(TypeError,
+                               "sequence subscript must be integer");
+                       return -1;
+               }
+               else
+                       return (*func)(w, (int)getintvalue(key), v);
+       }
+       else if ((mp = tp->tp_as_mapping) != NULL &&
+                       (func = mp->mp_ass_subscript) != NULL) {
+               return (*func)(w, key, v);
+       }
+       else {
+               err_setstr(TypeError,
+                               "can't assign to this subscripted object");
+               return -1;
+       }
+}
+
+static int
+assign_slice(u, v, w, x) /* u[v:w] = x */
+       object *u, *v, *w, *x;
+{
+       sequence_methods *sq = u->ob_type->tp_as_sequence;
+       int ilow, ihigh, isize;
+       if (sq == NULL) {
+               err_setstr(TypeError, "assign to slice of non-sequence");
+               return -1;
+       }
+       if (sq == NULL || sq->sq_ass_slice == NULL) {
+               err_setstr(TypeError, "unassignable slice");
+               return -1;
+       }
+       ilow = 0;
+       isize = ihigh = (*sq->sq_length)(u);
+       if (slice_index(v, isize, &ilow) != 0)
+               return -1;
+       if (slice_index(w, isize, &ihigh) != 0)
+               return -1;
+       return (*sq->sq_ass_slice)(u, ilow, ihigh, x);
+}
+
+static int
+cmp_exception(err, v)
+       object *err, *v;
+{
+       if (is_tupleobject(v)) {
+               int i, n;
+               n = gettuplesize(v);
+               for (i = 0; i < n; i++) {
+                       if (err == gettupleitem(v, i))
+                               return 1;
                }
+               return 0;
+       }
+       return err == v;
+}
 
-#ifndef NDEBUG
-               /* Double-check exception status */
-               
-               if (why == WHY_EXCEPTION || why == WHY_RERAISE) {
-                       if (!err_occurred()) {
-                               fprintf(stderr, "XXX ghost error\n");
-                               err_setstr(SystemError, "ghost error");
-                               why = WHY_EXCEPTION;
-                       }
+static int
+cmp_member(v, w)
+       object *v, *w;
+{
+       int i, n, cmp;
+       object *x;
+       sequence_methods *sq;
+       /* Special case for char in string */
+       if (is_stringobject(w)) {
+               register char *s, *end;
+               register char c;
+               if (!is_stringobject(v) || getstringsize(v) != 1) {
+                       err_setstr(TypeError,
+                           "string member test needs char left operand");
+                       return -1;
                }
-               else {
-                       if (err_occurred()) {
-                               fprintf(stderr, "XXX undetected error\n");
-                               why = WHY_EXCEPTION;
-                       }
+               c = getstringvalue(v)[0];
+               s = getstringvalue(w);
+               end = s + getstringsize(w);
+               while (s < end) {
+                       if (c == *s++)
+                               return 1;
                }
-#endif
+               return 0;
+       }
+       sq = w->ob_type->tp_as_sequence;
+       if (sq == NULL) {
+               err_setstr(TypeError,
+                       "'in' or 'not in' needs sequence right argument");
+               return -1;
+       }
+       n = (*sq->sq_length)(w);
+       for (i = 0; i < n; i++) {
+               x = (*sq->sq_item)(w, i);
+               cmp = cmpobject(v, x);
+               XDECREF(x);
+               if (cmp == 0)
+                       return 1;
+       }
+       return 0;
+}
 
-               /* Log traceback info if this is a real exception */
-               
-               if (why == WHY_EXCEPTION) {
-                       int lasti = INSTR_OFFSET() - 1;
-                       if (HAS_ARG(opcode))
-                               lasti -= 2;
-                       tb_here(f, lasti, lineno);
+static object *
+cmp_outcome(op, v, w)
+       enum cmp_op op;
+       register object *v;
+       register object *w;
+{
+       register int cmp;
+       register int res = 0;
+       switch (op) {
+       case IS:
+       case IS_NOT:
+               res = (v == w);
+               if (op == IS_NOT)
+                       res = !res;
+               break;
+       case IN:
+       case NOT_IN:
+               res = cmp_member(v, w);
+               if (res < 0)
+                       return NULL;
+               if (op == NOT_IN)
+                       res = !res;
+               break;
+       case EXC_MATCH:
+               res = cmp_exception(v, w);
+               break;
+       default:
+               cmp = cmpobject(v, w);
+               switch (op) {
+               case LT: res = cmp <  0; break;
+               case LE: res = cmp <= 0; break;
+               case EQ: res = cmp == 0; break;
+               case NE: res = cmp != 0; break;
+               case GT: res = cmp >  0; break;
+               case GE: res = cmp >= 0; break;
+               /* XXX no default? (res is initialized to 0 though) */
                }
-               
-               /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */
-               
-               if (why == WHY_RERAISE)
-                       why = WHY_EXCEPTION;
+       }
+       v = res ? True : False;
+       INCREF(v);
+       return v;
+}
 
-               /* Unwind stacks if a (pseudo) exception occurred */
-               
-               while (why != WHY_NOT && f->f_iblock > 0) {
-                       block *b = pop_block(f);
-                       while (STACK_LEVEL() > b->b_level) {
-                               v = POP();
-                               XDECREF(v);
-                       }
-                       if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
-                               why = WHY_NOT;
-                               JUMPTO(b->b_handler);
-                               break;
-                       }
-                       if (b->b_type == SETUP_FINALLY ||
-                                       b->b_type == SETUP_EXCEPT &&
-                                       why == WHY_EXCEPTION) {
-                               if (why == WHY_EXCEPTION) {
-                                       object *exc, *val;
-                                       err_get(&exc, &val);
-                                       if (val == NULL) {
-                                               val = None;
-                                               INCREF(val);
-                                       }
-                                       v = tb_fetch();
-                                       /* Make the raw exception data
-                                          available to the handler,
-                                          so a program can emulate the
-                                          Python main loop.  Don't do
-                                          this for 'finally'. */
-                                       if (b->b_type == SETUP_EXCEPT) {
-#if 0 /* Oops, this breaks too many things */
-                                               sysset("exc_traceback", v);
-#endif
-                                               sysset("exc_value", val);
-                                               sysset("exc_type", exc);
-                                               err_clear();
-                                       }
-                                       PUSH(v);
-                                       PUSH(val);
-                                       PUSH(exc);
-                               }
-                               else {
-                                       if (why == WHY_RETURN)
-                                               PUSH(retval);
-                                       v = newintobject((long)why);
-                                       PUSH(v);
-                               }
-                               why = WHY_NOT;
-                               JUMPTO(b->b_handler);
-                               break;
+/* XXX This function should use dict2 variants (change interface!) */
+
+static int
+import_from(locals, v, name)
+       object *locals;
+       object *v;
+       char *name;
+{
+       object *w, *x;
+       w = getmoduledict(v);
+       if (name[0] == '*') {
+               int i;
+               int n = getdictsize(w);
+               for (i = 0; i < n; i++) {
+                       name = getdictkey(w, i);
+                       if (name == NULL || name[0] == '_')
+                               continue;
+                       x = dictlookup(w, name);
+                       if (x == NULL) {
+                               /* XXX can't happen? */
+                               err_setstr(NameError, name);
+                               return -1;
                        }
-               } /* unwind stack */
+                       if (dictinsert(locals, name, x) != 0)
+                               return -1;
+               }
+               return 0;
+       }
+       else {
+               x = dictlookup(w, name);
+               if (x == NULL) {
+                       err_setstr(NameError, name);
+                       return -1;
+               }
+               else
+                       return dictinsert(locals, name, x);
+       }
+}
 
-               /* End the loop if we still have an error (or return) */
-               
-               if (why != WHY_NOT)
-                       break;
-               
-       } /* main loop */
-       
-       /* Pop remaining stack entries */
-       
-       while (!EMPTY()) {
-               v = POP();
-               XDECREF(v);
+static object *
+build_class(v, w)
+       object *v; /* None or tuple containing base classes */
+       object *w; /* dictionary */
+{
+       if (is_tupleobject(v)) {
+               int i;
+               for (i = gettuplesize(v); --i >= 0; ) {
+                       object *x = gettupleitem(v, i);
+                       if (!is_classobject(x)) {
+                               err_setstr(TypeError,
+                                       "base is not a class object");
+                               return NULL;
+                       }
+               }
        }
-       
-       /* Restore previous frame and release the current one */
-       
-       current_frame = f->f_back;
-       DECREF(f);
-       
-       if (why == WHY_RETURN)
-               return retval;
-       else
+       else {
+               v = NULL;
+       }
+       if (!is_dictobject(w)) {
+               err_setstr(SystemError, "build_class with non-dictionary");
                return NULL;
+       }
+       return newclassobject(v, w);
 }