diff options
author | Guido van Rossum <guido@python.org> | 1990-11-18 17:27:39 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1990-11-18 17:27:39 (GMT) |
commit | 10dc2e8097e7a431367e72f46ddba91be93aa159 (patch) | |
tree | 21d30678e4b505163daa5083e0f4a4159e67f5c0 /Python/ceval.c | |
parent | d5b70f5bacb27f96cbdf7f304d88fe8ede2a72c9 (diff) | |
download | cpython-10dc2e8097e7a431367e72f46ddba91be93aa159.zip cpython-10dc2e8097e7a431367e72f46ddba91be93aa159.tar.gz cpython-10dc2e8097e7a431367e72f46ddba91be93aa159.tar.bz2 |
Initial revision
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 1560 |
1 files changed, 1560 insertions, 0 deletions
diff --git a/Python/ceval.c b/Python/ceval.c new file mode 100644 index 0000000..6a303ca --- /dev/null +++ b/Python/ceval.c @@ -0,0 +1,1560 @@ +/* Evaluate compiled expression nodes */ + +#include <stdio.h> +#include <ctype.h> +#include "string.h" + +#include "PROTO.h" +#include "object.h" +#include "objimpl.h" +#include "intobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "builtinobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "context.h" +#include "funcobject.h" +#include "classobject.h" +#include "token.h" +#include "graminit.h" +#include "run.h" +#include "import.h" +#include "support.h" +#include "sysmodule.h" +#include "compile.h" +#include "opcode.h" + +/* List access macros */ +#ifdef NDEBUG +#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i)) +#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i))) +#else +#define GETITEM(v, i) getlistitem((v), (i)) +#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i))) +#endif + +typedef struct { + int b_type; /* what kind of block this is */ + int b_handler; /* where to jump to find handler */ + int b_level; /* value stack level to pop to */ +} block; + +typedef struct _frame { + OB_HEAD + struct _frame *f_back; /* previous frame, or NULL */ + codeobject *f_code; /* code segment */ + object *f_locals; /* local symbol table (dictobject) */ + object *f_globals; /* global symbol table (dictobject) */ + object **f_valuestack; /* malloc'ed array */ + block *f_blockstack; /* malloc'ed array */ + int f_nvalues; /* size of f_valuestack */ + int f_nblocks; /* size of f_blockstack */ + int f_ivalue; /* index in f_valuestack */ + int f_iblock; /* index in f_blockstack */ + int f_nexti; /* index in f_code (next instruction) */ +} frameobject; + +#define is_frameobject(op) ((op)->ob_type == &Frametype) + +static void +frame_dealloc(f) + frameobject *f; +{ + XDECREF(f->f_back); + XDECREF(f->f_code); + XDECREF(f->f_locals); + XDECREF(f->f_globals); + XDEL(f->f_valuestack); + XDEL(f->f_blockstack); + DEL(f); +} +typeobject Frametype = { + OB_HEAD_INIT(&Typetype) + 0, + "frame", + sizeof(frameobject), + 0, + frame_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +static frameobject * newframeobject PROTO( + (frameobject *, codeobject *, object *, object *, int, int)); + +static frameobject * +newframeobject(back, code, locals, globals, nvalues, nblocks) + frameobject *back; + codeobject *code; + object *locals; + object *globals; + int nvalues; + int nblocks; +{ + frameobject *f; + if ((back != NULL && !is_frameobject(back)) || + code == NULL || !is_codeobject(code) || + locals == NULL || !is_dictobject(locals) || + globals == NULL || !is_dictobject(globals) || + nvalues < 0 || nblocks < 0) { + err_badcall(); + return NULL; + } + f = NEWOBJ(frameobject, &Frametype); + if (f != NULL) { + if (back) + INCREF(back); + f->f_back = back; + INCREF(code); + f->f_code = code; + INCREF(locals); + f->f_locals = locals; + INCREF(globals); + f->f_globals = globals; + f->f_valuestack = NEW(object *, nvalues+1); + f->f_blockstack = NEW(block, nblocks+1); + f->f_nvalues = nvalues; + f->f_nblocks = nblocks; + f->f_ivalue = f->f_iblock = f->f_nexti = 0; + if (f->f_valuestack == NULL || f->f_blockstack == NULL) { + err_nomem(); + DECREF(f); + f = NULL; + } + } + return f; +} + +#define Push(f, v) ((f)->f_valuestack[(f)->f_ivalue++] = (v)) +#define Pop(f) ((f)->f_valuestack[--(f)->f_ivalue]) +#define Top(f) ((f)->f_valuestack[(f)->f_ivalue-1]) +#define Empty(f) ((f)->f_ivalue == 0) +#define Full(f) ((f)->f_ivalue == (f)->f_nvalues) +#define Nextbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti++]) +#define Peekbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti]) +#define Prevbyte(f) (GETSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti-1]) +#define Jumpto(f, x) ((f)->f_nexti = (x)) +#define Jumpby(f, x) ((f)->f_nexti += (x)) +#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i))) +#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i))) + +/* Corresponding functions, for debugging */ + +static void +push(f, v) + frameobject *f; + object *v; +{ + if (Full(f)) { + printf("stack overflow\n"); + abort(); + } + Push(f, v); +} + +static object * +pop(f) + frameobject *f; +{ + if (Empty(f)) { + printf("stack underflow\n"); + abort(); + } + return Pop(f); +} + +static object * +top(f) + frameobject *f; +{ + if (Empty(f)) { + printf("stack underflow\n"); + abort(); + } + return Top(f); +} + +static int +nextbyte(f) + frameobject *f; +{ + stringobject *code = (f)->f_code->co_code; + if (f->f_nexti >= getstringsize((object *)code)) { + printf("ran off end of instructions\n"); + abort(); + } + return GETSTRINGVALUE(code)[f->f_nexti++]; +} + +/* Tracing versions */ + +static void +trace_push(f, v) + frameobject *f; + object *v; +{ + printf("\tpush "); + printobject(v, stdout, 0); + printf("\n"); + push(f, v); +} + +static object * +trace_pop(f) + frameobject *f; +{ + object *v; + v = pop(f); + printf("\tpop "); + printobject(v, stdout, 0); + printf("\n"); + return v; +} + +static object * +trace_top(f) + frameobject *f; +{ + object *v; + v = top(f); + printf("\ttop "); + printobject(v, stdout, 0); + printf("\n"); + return v; +} + +static int +trace_nextop(f) + frameobject *f; +{ + int op; + int arg; + + printf("%d: ", f->f_nexti); + op = nextbyte(f); + if (op < HAVE_ARGUMENT) + printf("op %3d\n", op); + else { + arg = Peekbyte(f); + printf("op %3d arg %3d\n", op, arg); + } + return op; +} + +/* Block management */ + +static void +setup_block(f, type, handler) + frameobject *f; + int type; + int handler; +{ + block *b; + if (f->f_iblock >= f->f_nblocks) { + printf("block stack overflow\n"); + abort(); + } + b = &f->f_blockstack[f->f_iblock++]; + b->b_type = type; + b->b_level = f->f_ivalue; + b->b_handler = handler + f->f_nexti; +} + +static block * +pop_block(f) + frameobject *f; +{ + block *b; + if (f->f_iblock <= 0) { + printf("block stack underflow\n"); + abort(); + } + b = &f->f_blockstack[--f->f_iblock]; + while (f->f_ivalue > b->b_level) { + object *v = Pop(f); + XDECREF(v); + } + return b; +} + + +/* 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; + +void +flushline() +{ + FILE *fp = sysgetfile("stdout", stdout); + if (needspace) { + fprintf(fp, "\n"); + needspace = 0; + } +} + +static object * +checkerror(ctx, v) + context *ctx; + object *v; +{ + if (v == NULL) + puterrno(ctx); + return v; +} + +static object * +add(ctx, v, w) + context *ctx; + 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 { + type_error(ctx, "+ not supported by operands"); + return NULL; + } + return checkerror(ctx, v); +} + +static object * +sub(ctx, v, w) + context *ctx; + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return checkerror(ctx, + (*v->ob_type->tp_as_number->nb_subtract)(v, w)); + type_error(ctx, "bad operand type(s) for -"); + return NULL; +} + +static object * +mul(ctx, v, w) + context *ctx; + 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 checkerror(ctx, (*tp->tp_as_number->nb_multiply)(v, w)); + if (tp->tp_as_sequence != NULL) { + if (!is_intobject(w)) { + type_error(ctx, "can't multiply sequence with non-int"); + return NULL; + } + if (tp->tp_as_sequence->sq_repeat == NULL) { + type_error(ctx, "sequence does not support *"); + return NULL; + } + return checkerror(ctx, (*tp->tp_as_sequence->sq_repeat) + (v, (int)getintvalue(w))); + } + type_error(ctx, "bad operand type(s) for *"); + return NULL; +} + +static object * +div(ctx, v, w) + context *ctx; + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return checkerror(ctx, + (*v->ob_type->tp_as_number->nb_divide)(v, w)); + type_error(ctx, "bad operand type(s) for /"); + return NULL; +} + +static object * +rem(ctx, v, w) + context *ctx; + object *v, *w; +{ + if (v->ob_type->tp_as_number != NULL) + return checkerror(ctx, + (*v->ob_type->tp_as_number->nb_remainder)(v, w)); + type_error(ctx, "bad operand type(s) for %"); + return NULL; +} + +static object * +neg(ctx, v) + context *ctx; + object *v; +{ + if (v->ob_type->tp_as_number != NULL) + return checkerror(ctx, + (*v->ob_type->tp_as_number->nb_negative)(v)); + type_error(ctx, "bad operand type(s) for unary -"); + return NULL; +} + +static object * +pos(ctx, v) + context *ctx; + object *v; +{ + if (v->ob_type->tp_as_number != NULL) + return checkerror(ctx, + (*v->ob_type->tp_as_number->nb_positive)(v)); + type_error(ctx, "bad operand type(s) for unary +"); + return NULL; +} + +static object * +not(ctx, v) + context *ctx; + object *v; +{ + int outcome = testbool(ctx, v); + if (ctx->ctx_exception) + return NULL; + return checkerror(ctx, newintobject((long) !outcome)); +} + +static object * +call_builtin(ctx, func, args) + context *ctx; + object *func; + object *args; +{ + if (is_builtinobject(func)) { + function funcptr = getbuiltinfunction(func); + return (*funcptr)(ctx, args); + } + if (is_methodobject(func)) { + method meth = getmethod(func); + object *self = getself(func); + return checkerror(ctx, (*meth)(self, args)); + } + if (is_classobject(func)) { + if (args != NULL) { + type_error(ctx, "classobject() allows no arguments"); + return NULL; + } + return checkerror(ctx, newclassmemberobject(func)); + } + type_error(ctx, "call of non-function"); + return NULL; +} + +static object *eval_compiled PROTO((context *, codeobject *, object *, int)); + +/* XXX Eventually, this should not call eval_compiled recursively + but create a new frame */ + +static object * +call_function(ctx, func, args) + context *ctx; + object *func; + object *args; +{ + object *newargs = NULL; + object *savelocals, *newlocals, *saveglobals; + object *c, *v; + + if (is_classmethodobject(func)) { + object *self = classmethodgetself(func); + func = classmethodgetfunc(func); + if (args == NULL) { + args = self; + } + else { + newargs = checkerror(ctx, newtupleobject(2)); + if (newargs == NULL) + return NULL; + INCREF(self); + INCREF(args); + settupleitem(newargs, 0, self); + settupleitem(newargs, 1, args); + args = newargs; + } + } + else { + if (!is_funcobject(func)) { + type_error(ctx, "call of non-function"); + return NULL; + } + } + + c = checkerror(ctx, getfunccode(func)); + if (c == NULL) { + XDECREF(newargs); + return NULL; + } + if (!is_codeobject(c)) { + printf("Bad code\n"); + abort(); + } + newlocals = checkerror(ctx, newdictobject()); + if (newlocals == NULL) { + XDECREF(newargs); + return NULL; + } + + savelocals = ctx->ctx_locals; + ctx->ctx_locals = newlocals; + saveglobals = ctx->ctx_globals; + ctx->ctx_globals = getfuncglobals(func); + + v = eval_compiled(ctx, (codeobject *)c, args, 1); + + DECREF(ctx->ctx_locals); + ctx->ctx_locals = savelocals; + ctx->ctx_globals = saveglobals; + + XDECREF(newargs); + + return v; +} + +static object * +apply_subscript(ctx, v, w) + context *ctx; + object *v, *w; +{ + typeobject *tp = v->ob_type; + if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) { + type_error(ctx, "unsubscriptable object"); + return NULL; + } + if (tp->tp_as_sequence != NULL) { + int i; + if (!is_intobject(w)) { + type_error(ctx, "sequence subscript not int"); + return NULL; + } + i = getintvalue(w); + return checkerror(ctx, (*tp->tp_as_sequence->sq_item)(v, i)); + } + return checkerror(ctx, (*tp->tp_as_mapping->mp_subscript)(v, w)); +} + +static object * +loop_subscript(ctx, v, w) + context *ctx; + object *v, *w; +{ + sequence_methods *sq = v->ob_type->tp_as_sequence; + int i, n; + if (sq == NULL) { + type_error(ctx, "loop over non-sequence"); + return NULL; + } + i = getintvalue(w); + n = (*sq->sq_length)(v); + if (i >= n) + return NULL; /* End of loop */ + return checkerror(ctx, (*sq->sq_item)(v, i)); +} + +static int +slice_index(ctx, v, isize, pi) + context *ctx; + object *v; + int isize; + int *pi; +{ + if (v != NULL) { + if (!is_intobject(v)) { + type_error(ctx, "slice index must be int"); + return 0; + } + *pi = getintvalue(v); + if (*pi < 0) + *pi += isize; + } + return 1; +} + +static object * +apply_slice(ctx, u, v, w) /* u[v:w] */ + context *ctx; + object *u, *v, *w; +{ + typeobject *tp = u->ob_type; + int ilow, ihigh, isize; + if (tp->tp_as_sequence == NULL) { + type_error(ctx, "only sequences can be sliced"); + return NULL; + } + ilow = 0; + isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); + if (!slice_index(ctx, v, isize, &ilow)) + return NULL; + if (!slice_index(ctx, w, isize, &ihigh)) + return NULL; + return checkerror(ctx, (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh)); +} +static void +assign_subscript(ctx, w, key, v) + context *ctx; + object *w; + object *key; + object *v; +{ + typeobject *tp = w->ob_type; + sequence_methods *sq; + mapping_methods *mp; + int (*func)(); + int err; + if ((sq = tp->tp_as_sequence) != NULL && + (func = sq->sq_ass_item) != NULL) { + if (!is_intobject(key)) { + type_error(ctx, "sequence subscript must be integer"); + return; + } + err = (*func)(w, (int)getintvalue(key), v); + } + else if ((mp = tp->tp_as_mapping) != NULL && + (func = mp->mp_ass_subscript) != NULL) { + err = (*func)(w, key, v); + } + else { + type_error(ctx, "can't assign to this subscripted object"); + return; + } + if (err != 0) + puterrno(ctx); +} + +static void +assign_slice(ctx, u, v, w, x) /* u[v:w] = x */ + context *ctx; + object *u, *v, *w, *x; +{ + typeobject *tp = u->ob_type; + int ilow, ihigh, isize; + if (tp->tp_as_sequence == NULL || + tp->tp_as_sequence->sq_ass_slice == NULL) { + type_error(ctx, "unassignable slice"); + return; + } + ilow = 0; + isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); + if (!slice_index(ctx, v, isize, &ilow)) + return; + if (!slice_index(ctx, w, isize, &ihigh)) + return; + if ((*tp->tp_as_sequence->sq_ass_slice)(u, ilow, ihigh, x) != 0) + puterrno(ctx); +} + +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 object * +cmp_outcome(ctx, op, v, w) + register context *ctx; + enum cmp_op op; + register object *v; + register object *w; +{ + register int cmp; + register int res = 0; + switch (op) { + case IN: + case NOT_IN: + cmp = cmp_member(ctx, v, w); + break; + case IS: + case IS_NOT: + cmp = (v == w); + break; + case EXC_MATCH: + cmp = cmp_exception(v, w); + break; + default: + cmp = cmp_values(ctx, v, w); + } + if (ctx->ctx_exception) + return NULL; + switch (op) { + case EXC_MATCH: + case IS: + case IN: res = cmp; break; + case IS_NOT: + case NOT_IN: res = !cmp; break; + 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? */ + } + v = res ? True : False; + INCREF(v); + return v; +} + +static object * +eval_compiled(ctx, co, arg, needvalue) + context *ctx; + codeobject *co; + object *arg; + int needvalue; +{ + frameobject *f; + register object *v; + register object *w; + register object *u; + register object *x; + char *name; + int n, i; + enum cmp_op op; + FILE *fp; +#ifndef NDEBUG + int trace = dictlookup(ctx->ctx_globals, "__trace") != NULL; +#endif + + f = newframeobject( + (frameobject *)NULL, /*back*/ + co, /*code*/ + ctx->ctx_locals, /*locals*/ + ctx->ctx_globals, /*globals*/ + 50, /*nvalues*/ + 20); /*nblocks*/ + if (f == NULL) { + puterrno(ctx); + return NULL; + } + +#define EMPTY() Empty(f) +#define FULL() Full(f) +#define GETCONST(i) Getconst(f, i) +#define GETNAME(i) Getname(f, i) +#define JUMPTO(x) Jumpto(f, x) +#define JUMPBY(x) Jumpby(f, x) + +#ifdef NDEBUG + +#define PUSH(v) Push(f, v) +#define TOP() Top(f) +#define POP() Pop(f) +#define NEXTOP() Nextbyte(f) +#define NEXTI() Nextbyte(f) + +#else + +#define PUSH(v) if(trace) trace_push(f, v); else push(f, v) +#define TOP() (trace ? trace_top(f) : top(f)) +#define POP() (trace ? trace_pop(f) : pop(f)) +#define NEXTOP() (trace ? trace_nextop(f) : nextbyte(f)) +#define NEXTI() (nextbyte(f)) + +#endif + + if (arg != NULL) { + INCREF(arg); + PUSH(arg); + } + + while (f->f_nexti < getstringsize((object *)f->f_code->co_code) && + !ctx->ctx_exception) { + + switch (NEXTOP()) { + + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + + case POP_TOP: + v = POP(); + DECREF(v); + break; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + break; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + break; + + case UNARY_POSITIVE: + v = POP(); + u = pos(ctx, v); + DECREF(v); + PUSH(u); + break; + + case UNARY_NEGATIVE: + v = POP(); + u = neg(ctx, v); + DECREF(v); + PUSH(u); + break; + + case UNARY_NOT: + v = POP(); + u = not(ctx, v); + DECREF(v); + PUSH(u); + break; + + case UNARY_CONVERT: + v = POP(); + u = checkerror(ctx, reprobject(v)); + DECREF(v); + PUSH(u); + break; + + case UNARY_CALL: + v = POP(); + if (is_classmemberobject(v) || is_funcobject(v)) + u = call_function(ctx, v, (object *)NULL); + else + u = call_builtin(ctx, v, (object *)NULL); + DECREF(v); + PUSH(u); + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + u = mul(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + u = div(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + u = rem(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + u = add(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + u = sub(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + u = apply_subscript(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case BINARY_CALL: + w = POP(); + v = POP(); + if (is_classmemberobject(v) || is_funcobject(v)) + u = call_function(ctx, v, w); + else + u = call_builtin(ctx, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case SLICE: + w = NULL; + v = NULL; + u = POP(); + x = apply_slice(ctx, u, v, w); + DECREF(u); + PUSH(x); + break; + + case SLICE+1: + w = NULL; + v = POP(); + u = POP(); + x = apply_slice(ctx, u, v, w); + DECREF(u); + DECREF(v); + PUSH(x); + break; + + case SLICE+2: + w = POP(); + v = NULL; + u = POP(); + x = apply_slice(ctx, u, v, w); + DECREF(u); + DECREF(w); + PUSH(x); + break; + + case SLICE+3: + w = POP(); + v = POP(); + u = POP(); + x = apply_slice(ctx, u, v, w); + DECREF(u); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case STORE_SLICE: + w = NULL; + v = NULL; + u = POP(); + x = POP(); + assign_slice(ctx, u, v, w, x); /* u[:] = x */ + DECREF(x); + DECREF(u); + break; + + case STORE_SLICE+1: + w = NULL; + v = POP(); + u = POP(); + x = POP(); + assign_slice(ctx, u, v, w, x); /* u[v:] = x */ + DECREF(x); + DECREF(u); + DECREF(v); + break; + + case STORE_SLICE+2: + w = POP(); + v = NULL; + u = POP(); + x = POP(); + assign_slice(ctx, u, v, w, x); /* u[:w] = x */ + DECREF(x); + DECREF(u); + DECREF(w); + break; + + case STORE_SLICE+3: + w = POP(); + v = POP(); + u = POP(); + x = POP(); + assign_slice(ctx, u, v, w, x); /* u[v:w] = x */ + DECREF(x); + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case DELETE_SLICE: + w = NULL; + v = NULL; + u = POP(); + x = NULL; + assign_slice(ctx, u, v, w, x); /* del u[:] */ + DECREF(u); + break; + + case DELETE_SLICE+1: + w = NULL; + v = POP(); + u = POP(); + x = NULL; + assign_slice(ctx, u, v, w, x); /* del u[v:] */ + DECREF(u); + DECREF(v); + break; + + case DELETE_SLICE+2: + w = POP(); + v = NULL; + u = POP(); + x = NULL; + assign_slice(ctx, u, v, w, x); /* del u[:w] */ + DECREF(u); + DECREF(w); + break; + + case DELETE_SLICE+3: + w = POP(); + v = POP(); + u = POP(); + x = NULL; + assign_slice(ctx, u, v, w, x); /* del u[v:w] */ + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + assign_subscript(ctx, v, w, u); + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + assign_subscript(ctx, v, w, (object *)NULL); + DECREF(v); + DECREF(w); + break; + + case PRINT_EXPR: + v = POP(); + fp = sysgetfile("stdout", stdout); + /* Print value except if procedure result */ + if (v != None) { + flushline(); + printobject(v, fp, 0); + fprintf(fp, "\n"); + } + DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + fp = sysgetfile("stdout", stdout); + if (needspace) + 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; + } + else { + printobject(v, fp, 0); + needspace = 1; + } + DECREF(v); + break; + + case PRINT_NEWLINE: + fp = sysgetfile("stdout", stdout); + fprintf(fp, "\n"); + needspace = 0; + break; + + case BREAK_LOOP: + raise_pseudo(ctx, BREAK_PSEUDO); + break; + + case RAISE_EXCEPTION: + v = POP(); + w = POP(); + if (!is_stringobject(w)) { + DECREF(v); + DECREF(v); + type_error(ctx, "exceptions must be strings"); + } + else { + raise_exception(ctx, w, v); + } + break; + + case RETURN_VALUE: + v = POP(); + raise_pseudo(ctx, RETURN_PSEUDO); + ctx->ctx_errval = v; + break; + + case REQUIRE_ARGS: + if (EMPTY()) + type_error(ctx, + "function expects argument(s)"); + break; + + case REFUSE_ARGS: + if (!EMPTY()) + type_error(ctx, + "function expects no argument(s)"); + break; + + case BUILD_FUNCTION: + v = POP(); + x = checkerror(ctx, newfuncobject(v, ctx->ctx_globals)); + DECREF(v); + PUSH(x); + break; + + case POP_BLOCK: + (void) pop_block(f); + break; + + case END_FINALLY: + v = POP(); + w = POP(); + if (is_intobject(v)) { + raise_pseudo(ctx, (int)getintvalue(v)); + DECREF(v); + if (w == None) + DECREF(w); + else + ctx->ctx_errval = w; + } + else if (is_stringobject(v)) + raise_exception(ctx, v, w); + else if (v == None) { + DECREF(v); + DECREF(w); + } + else { + sys_error(ctx, "'finally' pops bad exception"); + } + break; + + case STORE_NAME: + i = NEXTI(); + name = GETNAME(i); + v = POP(); + if (dictinsert(ctx->ctx_locals, name, v) != 0) + mem_error(ctx, "insert in symbol table"); + DECREF(v); + break; + + case DELETE_NAME: + i = NEXTI(); + name = GETNAME(i); + if (dictremove(ctx->ctx_locals, name) != 0) + name_error(ctx, name); + break; + + case UNPACK_TUPLE: + n = NEXTI(); + v = POP(); + if (!is_tupleobject(v)) { + type_error(ctx, "unpack non-tuple"); + } + else if (gettuplesize(v) != n) { + error(ctx, "unpack tuple of wrong size"); + } + else { + for (i = n; --i >= 0; ) { + w = gettupleitem(v, i); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case UNPACK_LIST: + n = NEXTI(); + v = POP(); + if (!is_listobject(v)) { + type_error(ctx, "unpack non-list"); + } + else if (getlistsize(v) != n) { + error(ctx, "unpack tuple of wrong size"); + } + else { + for (i = n; --i >= 0; ) { + w = getlistitem(v, i); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case STORE_ATTR: + i = NEXTI(); + name = GETNAME(i); + v = POP(); + u = POP(); + /* v.name = u */ + if (v->ob_type->tp_setattr == NULL) { + type_error(ctx, "object without writable attributes"); + } + else { + if ((*v->ob_type->tp_setattr)(v, name, u) != 0) + puterrno(ctx); + } + DECREF(v); + DECREF(u); + break; + + case DELETE_ATTR: + i = NEXTI(); + name = GETNAME(i); + v = POP(); + /* del v.name */ + if (v->ob_type->tp_setattr == NULL) { + type_error(ctx, + "object without writable attributes"); + } + else { + if ((*v->ob_type->tp_setattr) + (v, name, (object *)NULL) != 0) + puterrno(ctx); + } + DECREF(v); + break; + + case LOAD_CONST: + i = NEXTI(); + v = GETCONST(i); + INCREF(v); + PUSH(v); + break; + + case LOAD_NAME: + i = NEXTI(); + name = GETNAME(i); + v = dictlookup(ctx->ctx_locals, name); + if (v == NULL) { + v = dictlookup(ctx->ctx_globals, name); + if (v == NULL) + v = dictlookup(ctx->ctx_builtins, name); + } + if (v == NULL) + name_error(ctx, name); + /* XXX could optimize */ + else + INCREF(v); + PUSH(v); + break; + + case BUILD_TUPLE: + n = NEXTI(); + v = checkerror(ctx, newtupleobject(n)); + if (v != NULL) { + for (i = n; --i >= 0;) { + w = POP(); + settupleitem(v, i, w); + } + } + PUSH(v); + break; + + case BUILD_LIST: + n = NEXTI(); + v = checkerror(ctx, newlistobject(n)); + if (v != NULL) { + for (i = n; --i >= 0;) { + w = POP(); + setlistitem(v, i, w); + } + } + PUSH(v); + break; + + case BUILD_MAP: + (void) NEXTI(); + v = checkerror(ctx, newdictobject()); + PUSH(v); + break; + + case LOAD_ATTR: + i = NEXTI(); + name = GETNAME(i); + v = POP(); + if (v->ob_type->tp_getattr == NULL) { + type_error(ctx, "attribute-less object"); + u = NULL; + } + else { + u = checkerror(ctx, + (*v->ob_type->tp_getattr)(v, name)); + } + DECREF(v); + PUSH(u); + break; + + case COMPARE_OP: + op = NEXTI(); + w = POP(); + v = POP(); + u = cmp_outcome(ctx, op, v, w); + DECREF(v); + DECREF(w); + PUSH(u); + break; + + case IMPORT_NAME: + i = NEXTI(); + name = GETNAME(i); + u = import_module(ctx, name); + if (u != NULL) { + INCREF(u); + PUSH(u); + } + break; + + case IMPORT_FROM: + i = NEXTI(); + name = GETNAME(i); + v = TOP(); + w = getmoduledict(v); + x = dictlookup(w, name); + if (x == NULL) + name_error(ctx, name); + else if (dictinsert(ctx->ctx_locals, name, x) != 0) + puterrno(ctx); + break; + + /* WARNING! + Don't assign an expression containing NEXTI() directly + to nexti. This expands to "nexti = ... + *nexti++" + which has undefined evaluation order. On some machines + (e.g., mips!) the nexti++ is done after the assignment + to nexti. */ + + case JUMP_FORWARD: + n = NEXTI(); + JUMPBY(n); + break; + + case JUMP_IF_FALSE: + n = NEXTI(); + if (!testbool(ctx, TOP())) + JUMPBY(n); + break; + + case JUMP_IF_TRUE: + n = NEXTI(); + if (testbool(ctx, TOP())) + JUMPBY(n); + break; + + case JUMP_ABSOLUTE: + n = NEXTI(); + JUMPTO(n); + /* XXX Should check for interrupts more often? */ + if (intrcheck()) + intr_error(ctx); + break; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump n bytes */ + n = NEXTI(); + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + x = loop_subscript(ctx, v, w); + if (x != NULL) { + PUSH(v); + u = checkerror(ctx, + newintobject(getintvalue(w)+1)); + PUSH(u); + DECREF(w); + PUSH(x); + } + else { + DECREF(v); + DECREF(w); + JUMPBY(n); + } + break; + + case SETUP_LOOP: + n = NEXTI(); + setup_block(f, SETUP_LOOP, n); + break; + + case SETUP_EXCEPT: + n = NEXTI(); + setup_block(f, SETUP_EXCEPT, n); + break; + + case SETUP_FINALLY: + n = NEXTI(); + setup_block(f, SETUP_FINALLY, n); + break; + + default: + printf("opcode %d\n", Prevbyte(f)); + sys_error(ctx, "eval_compiled: unknown opcode"); + break; + + } + + /* Unwind block stack if an exception occurred */ + + while (ctx->ctx_exception && f->f_iblock > 0) { + block *b = pop_block(f); + if (b->b_type == SETUP_LOOP && + ctx->ctx_exception == BREAK_PSEUDO) { + clear_exception(ctx); + JUMPTO(b->b_handler); + break; + } + else if (b->b_type == SETUP_FINALLY || + b->b_type == SETUP_EXCEPT && + ctx->ctx_exception == CATCHABLE_EXCEPTION) { + v = ctx->ctx_errval; + if (v == NULL) + v = None; + INCREF(v); + PUSH(v); + v = ctx->ctx_error; + if (v == NULL) + v = newintobject(ctx->ctx_exception); + else + INCREF(v); + PUSH(v); + clear_exception(ctx); + JUMPTO(b->b_handler); + break; + } + } + } + + if (ctx->ctx_exception) { + while (!EMPTY()) { + v = POP(); + XDECREF(v); + } + v = NULL; + if (ctx->ctx_exception == RETURN_PSEUDO) { + if (needvalue) { + v = ctx->ctx_errval; + INCREF(v); + clear_exception(ctx); + } + else { + /* XXX Can detect this statically! */ + type_error(ctx, "unexpected return statement"); + } + } + } + else { + if (needvalue) + v = POP(); + else + v = NULL; + if (!EMPTY()) { + sys_error(ctx, "stack not cleaned up"); + XDECREF(v); + while (!EMPTY()) { + v = POP(); + XDECREF(v); + } + v = NULL; + } + } + +#undef EMPTY +#undef FULL +#undef GETCONST +#undef GETNAME +#undef JUMPTO +#undef JUMPBY + +#undef NEXTOP +#undef NEXTI +#undef POP +#undef TOP +#undef PUSH + + DECREF(f); + return v; + +} + +/* Provisional interface until everything is compilable */ + +#include "node.h" + +static object * +eval_or_exec(ctx, n, arg, needvalue) + context *ctx; + node *n; + object *arg; + int needvalue; +{ + object *v; + codeobject *co = compile(n); + if (co == NULL) { + puterrno(ctx); + return NULL; + } + v = eval_compiled(ctx, co, arg, needvalue); + DECREF(co); + return v; +} + +object * +eval_node(ctx, n) + context *ctx; + node *n; +{ + return eval_or_exec(ctx, n, (object *)NULL, 1/*needvalue*/); +} + +void +exec_node(ctx, n) + context *ctx; + node *n; +{ + (void) eval_or_exec(ctx, n, (object *)NULL, 0/*needvalue*/); +} |