From 374a92261b191df619f7bcbde104eeda5edede2d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 4 Apr 1991 10:40:29 +0000 Subject: Moved support functions after main function; added prototypes; Fixed 'needspace' hack to use a flag in the stdout file object; added local and global variable lookup cases. --- Python/ceval.c | 1635 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 840 insertions(+), 795 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 5a9723f..badfced 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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); } -- cgit v0.12