diff options
author | Guido van Rossum <guido@python.org> | 1990-12-20 15:06:42 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1990-12-20 15:06:42 (GMT) |
commit | 3f5da24ea304e674a9abbdcffc4d671e32aa70f1 (patch) | |
tree | e932e31cb9381f40b7c87c377638216c043b5cfc /Python | |
parent | 226d79eb4a776dd54c9e4544b17deaf928bcef3a (diff) | |
download | cpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.zip cpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.tar.gz cpython-3f5da24ea304e674a9abbdcffc4d671e32aa70f1.tar.bz2 |
"Compiling" version
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bltinmodule.c | 535 | ||||
-rw-r--r-- | Python/ceval.c | 1468 | ||||
-rw-r--r-- | Python/compile.c | 197 | ||||
-rw-r--r-- | Python/errors.c | 83 | ||||
-rw-r--r-- | Python/graminit.c | 2 | ||||
-rw-r--r-- | Python/import.c | 290 | ||||
-rw-r--r-- | Python/modsupport.c | 41 | ||||
-rw-r--r-- | Python/pythonmain.c | 395 | ||||
-rw-r--r-- | Python/structmember.c | 134 | ||||
-rw-r--r-- | Python/sysmodule.c | 199 | ||||
-rw-r--r-- | Python/traceback.c | 193 |
11 files changed, 2229 insertions, 1308 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c new file mode 100644 index 0000000..dc88581 --- /dev/null +++ b/Python/bltinmodule.c @@ -0,0 +1,535 @@ +/* Built-in functions */ + +#include "allobjects.h" + +#include "node.h" +#include "graminit.h" +#include "errcode.h" +#include "sysmodule.h" +#include "builtinmodule.h" +#include "import.h" +#include "pythonrun.h" +#include "compile.h" /* For ceval.h */ +#include "ceval.h" +#include "modsupport.h" + +static object * +builtin_abs(self, v) + object *self; + object *v; +{ + /* XXX This should be a method in the as_number struct in the type */ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + long x = getintvalue(v); + if (x < 0) + x = -x; + return newintobject(x); + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + if (x < 0) + x = -x; + return newfloatobject(x); + } + err_setstr(TypeError, "abs() argument must be float or int"); + return NULL; +} + +static object * +builtin_chr(self, v) + object *self; + object *v; +{ + long x; + char s[1]; + if (v == NULL || !is_intobject(v)) { + err_setstr(TypeError, "chr() must have int argument"); + return NULL; + } + x = getintvalue(v); + if (x < 0 || x >= 256) { + err_setstr(RuntimeError, "chr() arg not in range(256)"); + return NULL; + } + s[0] = x; + return newsizedstringobject(s, 1); +} + +static object * +builtin_dir(self, v) + object *self; + object *v; +{ + object *d; + if (v == NULL) { + d = getlocals(); + } + else { + if (!is_moduleobject(v)) { + err_setstr(TypeError, + "dir() argument, must be module or absent"); + return NULL; + } + d = getmoduledict(v); + } + v = getdictkeys(d); + if (sortlist(v) != 0) { + DECREF(v); + v = NULL; + } + return v; +} + +static object * +builtin_divmod(self, v) + object *self; + object *v; +{ + object *x, *y; + long xi, yi, xdivy, xmody; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + x = gettupleitem(v, 0); + y = gettupleitem(v, 1); + if (!is_intobject(x) || !is_intobject(y)) { + err_setstr(TypeError, "divmod() requires 2 int arguments"); + return NULL; + } + xi = getintvalue(x); + yi = getintvalue(y); + if (yi == 0) { + err_setstr(TypeError, "divmod() division by zero"); + return NULL; + } + if (yi < 0) { + xdivy = -xi / -yi; + } + else { + xdivy = xi / yi; + } + xmody = xi - xdivy*yi; + if (xmody < 0 && yi > 0 || xmody > 0 && yi < 0) { + xmody += yi; + xdivy -= 1; + } + v = newtupleobject(2); + x = newintobject(xdivy); + y = newintobject(xmody); + if (v == NULL || x == NULL || y == NULL || + settupleitem(v, 0, x) != 0 || + settupleitem(v, 1, y) != 0) { + XDECREF(v); + XDECREF(x); + XDECREF(y); + return NULL; + } + return v; +} + +static object * +exec_eval(v, start) + object *v; + int start; +{ + object *str = NULL, *globals = NULL, *locals = NULL; + int n; + if (v != NULL) { + if (is_stringobject(v)) + str = v; + else if (is_tupleobject(v) && + ((n = gettuplesize(v)) == 2 || n == 3)) { + str = gettupleitem(v, 0); + globals = gettupleitem(v, 1); + if (n == 3) + locals = gettupleitem(v, 2); + } + } + if (str == NULL || !is_stringobject(str) || + globals != NULL && !is_dictobject(globals) || + locals != NULL && !is_dictobject(locals)) { + err_setstr(TypeError, + "exec/eval arguments must be string[,dict[,dict]]"); + return NULL; + } + return run_string(getstringvalue(str), start, globals, locals); +} + +static object * +builtin_eval(self, v) + object *self; + object *v; +{ + return exec_eval(v, eval_input); +} + +static object * +builtin_exec(self, v) + object *self; + object *v; +{ + return exec_eval(v, file_input); +} + +static object * +builtin_float(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_floatobject(v)) { + INCREF(v); + return v; + } + else if (is_intobject(v)) { + long x = getintvalue(v); + return newfloatobject((double)x); + } + err_setstr(TypeError, "float() argument must be float or int"); + return NULL; +} + +static object * +builtin_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + node *n; + int err; + object *m, *d; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + m = add_module("__main__"); + d = getmoduledict(m); + return run_file(in, "<stdin>", expr_input, d, d); +} + +static object * +builtin_int(self, v) + object *self; + object *v; +{ + if (v == NULL) { + /* */ + } + else if (is_intobject(v)) { + INCREF(v); + return v; + } + else if (is_floatobject(v)) { + double x = getfloatvalue(v); + return newintobject((long)x); + } + err_setstr(TypeError, "int() argument must be float or int"); + return NULL; +} + +static object * +builtin_len(self, v) + object *self; + object *v; +{ + long len; + typeobject *tp; + if (v == NULL) { + err_setstr(TypeError, "len() without argument"); + return NULL; + } + tp = v->ob_type; + if (tp->tp_as_sequence != NULL) { + len = (*tp->tp_as_sequence->sq_length)(v); + } + else if (tp->tp_as_mapping != NULL) { + len = (*tp->tp_as_mapping->mp_length)(v); + } + else { + err_setstr(TypeError, "len() of unsized object"); + return NULL; + } + return newintobject(len); +} + +static object * +min_max(v, sign) + object *v; + int sign; +{ + int i, n, cmp; + object *w, *x; + sequence_methods *sq; + if (v == NULL) { + err_setstr(TypeError, "min() or max() without argument"); + return NULL; + } + sq = v->ob_type->tp_as_sequence; + if (sq == NULL) { + err_setstr(TypeError, "min() or max() of non-sequence"); + return NULL; + } + n = (*sq->sq_length)(v); + if (n == 0) { + err_setstr(RuntimeError, "min() or max() of empty sequence"); + return NULL; + } + w = (*sq->sq_item)(v, 0); /* Implies INCREF */ + for (i = 1; i < n; i++) { + x = (*sq->sq_item)(v, i); /* Implies INCREF */ + cmp = cmpobject(x, w); + if (cmp * sign > 0) { + DECREF(w); + w = x; + } + else + DECREF(x); + } + return w; +} + +static object * +builtin_min(self, v) + object *self; + object *v; +{ + return min_max(v, -1); +} + +static object * +builtin_max(self, v) + object *self; + object *v; +{ + return min_max(v, 1); +} + +static object * +builtin_open(self, v) + object *self; + object *v; +{ + object *name, *mode; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2 || + !is_stringobject(name = gettupleitem(v, 0)) || + !is_stringobject(mode = gettupleitem(v, 1))) { + err_setstr(TypeError, "open() requires 2 string arguments"); + return NULL; + } + v = newfileobject(getstringvalue(name), getstringvalue(mode)); + return v; +} + +static object * +builtin_ord(self, v) + object *self; + object *v; +{ + if (v == NULL || !is_stringobject(v)) { + err_setstr(TypeError, "ord() must have string argument"); + return NULL; + } + if (getstringsize(v) != 1) { + err_setstr(RuntimeError, "ord() arg must have length 1"); + return NULL; + } + return newintobject((long)(getstringvalue(v)[0] & 0xff)); +} + +static object * +builtin_range(self, v) + object *self; + object *v; +{ + static char *errmsg = "range() requires 1-3 int arguments"; + int i, n; + long ilow, ihigh, istep; + if (v != NULL && is_intobject(v)) { + ilow = 0; ihigh = getintvalue(v); istep = 1; + } + else if (v == NULL || !is_tupleobject(v)) { + err_setstr(TypeError, errmsg); + return NULL; + } + else { + n = gettuplesize(v); + if (n < 1 || n > 3) { + err_setstr(TypeError, errmsg); + return NULL; + } + for (i = 0; i < n; i++) { + if (!is_intobject(gettupleitem(v, i))) { + err_setstr(TypeError, errmsg); + return NULL; + } + } + if (n == 3) { + istep = getintvalue(gettupleitem(v, 2)); + --n; + } + else + istep = 1; + ihigh = getintvalue(gettupleitem(v, --n)); + if (n > 0) + ilow = getintvalue(gettupleitem(v, 0)); + else + ilow = 0; + } + if (istep == 0) { + err_setstr(RuntimeError, "zero step for range()"); + return NULL; + } + /* XXX ought to check overflow of subtraction */ + if (istep > 0) + n = (ihigh - ilow + istep - 1) / istep; + else + n = (ihigh - ilow + istep + 1) / istep; + if (n < 0) + n = 0; + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { + object *w = newintobject(ilow); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + ilow += istep; + } + return v; +} + +static object * +builtin_raw_input(self, v) + object *self; + object *v; +{ + FILE *in = sysgetfile("stdin", stdin); + FILE *out = sysgetfile("stdout", stdout); + char *p; + int err; + int n = 1000; + flushline(); + if (v != NULL) + printobject(v, out, PRINT_RAW); + v = newsizedstringobject((char *)NULL, n); + if (v != NULL) { + if ((err = fgets_intr(getstringvalue(v), n+1, in)) != E_OK) { + err_input(err); + DECREF(v); + return NULL; + } + else { + n = strlen(getstringvalue(v)); + if (n > 0 && getstringvalue(v)[n-1] == '\n') + n--; + resizestring(&v, n); + } + } + return v; +} + +static object * +builtin_reload(self, v) + object *self; + object *v; +{ + return reload_module(v); +} + +static object * +builtin_type(self, v) + object *self; + object *v; +{ + if (v == NULL) { + err_setstr(TypeError, "type() requres an argument"); + return NULL; + } + v = (object *)v->ob_type; + INCREF(v); + return v; +} + +static struct methodlist builtin_methods[] = { + {"abs", builtin_abs}, + {"chr", builtin_chr}, + {"dir", builtin_dir}, + {"divmod", builtin_divmod}, + {"eval", builtin_eval}, + {"exec", builtin_exec}, + {"float", builtin_float}, + {"input", builtin_input}, + {"int", builtin_int}, + {"len", builtin_len}, + {"min", builtin_min}, + {"max", builtin_max}, + {"open", builtin_open}, /* XXX move to OS module */ + {"ord", builtin_ord}, + {"range", builtin_range}, + {"raw_input", builtin_raw_input}, + {"reload", builtin_reload}, + {"type", builtin_type}, + {NULL, NULL}, +}; + +static object *builtin_dict; + +object * +getbuiltin(name) + char *name; +{ + return dictlookup(builtin_dict, name); +} + +/* Predefined exceptions */ + +object *RuntimeError; +object *EOFError; +object *TypeError; +object *MemoryError; +object *NameError; +object *SystemError; +object *KeyboardInterrupt; + +static object * +newstdexception(name, message) + char *name, *message; +{ + object *v = newstringobject(message); + if (v == NULL || dictinsert(builtin_dict, name, v) != 0) + fatal("no mem for new standard exception"); + return v; +} + +static void +initerrors() +{ + RuntimeError = newstdexception("RuntimeError", "run-time error"); + EOFError = newstdexception("EOFError", "end-of-file read"); + TypeError = newstdexception("TypeError", "type error"); + MemoryError = newstdexception("MemoryError", "out of memory"); + NameError = newstdexception("NameError", "undefined name"); + SystemError = newstdexception("SystemError", "system error"); + KeyboardInterrupt = + newstdexception("KeyboardInterrupt", "keyboard interrupt"); +} + +void +initbuiltin() +{ + object *m; + m = initmodule("builtin", builtin_methods); + builtin_dict = getmoduledict(m); + INCREF(builtin_dict); + initerrors(); + (void) dictinsert(builtin_dict, "None", None); +} diff --git a/Python/ceval.c b/Python/ceval.c index 0074cd0..5c9548d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1,309 +1,62 @@ -/* Evaluate compiled expression nodes */ +/* Execute compiled code */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" +#include "allobjects.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 "frameobject.h" +#include "ceval.h" #include "opcode.h" +#include "builtinmodule.h" +#include "traceback.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))) +#ifndef NDEBUG +#define TRACE #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 GETUSTRINGVALUE(s) ((unsigned char *)GETSTRINGVALUE(s)) - -#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) (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti++]) -#define Peekbyte(f) (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti]) -#define Peekint(f) \ - (GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti] + \ - GETUSTRINGVALUE((f)->f_code->co_code)[(f)->f_nexti+1]) -#define Prevbyte(f) (GETUSTRINGVALUE((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 GETUSTRINGVALUE(code)[f->f_nexti++]; -} - +#ifdef TRACE static int -nextint(f) - frameobject *f; -{ - int a, b; -#ifdef NDEBUG - a = Nextbyte(f); - b = Nextbyte(f); -#else - a = nextbyte(f); - b = nextbyte(f); -#endif - return a + (b << 8); -} - -/* Tracing versions */ - -static void -trace_push(f, v) - frameobject *f; +prtrace(v, str) object *v; + char *str; { - printf("\tpush "); + printf("%s ", str); 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; } +#endif -static object * -trace_top(f) - frameobject *f; -{ - object *v; - v = top(f); - printf("\ttop "); - printobject(v, stdout, 0); - printf("\n"); - return v; -} +static frameobject *current_frame; -static int -trace_nextop(f) - frameobject *f; +object * +getlocals() { - int op; - int arg; - - printf("%d: ", f->f_nexti); - op = nextbyte(f); - if (op < HAVE_ARGUMENT) - printf("op %3d\n", op); - else { - arg = Peekint(f); - printf("op %d arg %d\n", op, arg); - } - return op; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_locals; } -/* Block management */ - -static void -setup_block(f, type, handler) - frameobject *f; - int type; - int handler; +object * +getglobals() { - 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; + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; } -static block * -pop_block(f) - frameobject *f; +void +printtraceback(fp) + FILE *fp; { - 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); + object *v = tb_fetch(); + if (v != NULL) { + fprintf(fp, "Stack backtrace (innermost last):\n"); + tb_print(v, fp); + DECREF(v); } - return b; } @@ -323,19 +76,29 @@ flushline() } } -static object * -checkerror(ctx, v) - context *ctx; + +/* Test a value used as condition, e.g., in a for or if statement */ + +static int +testbool(v) object *v; { - if (v == NULL) - puterrno(ctx); - return 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(ctx, v, w) - context *ctx; +add(v, w) object *v, *w; { if (v->ob_type->tp_as_number != NULL) @@ -343,27 +106,24 @@ add(ctx, 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"); + err_setstr(TypeError, "+ not supported by operands"); return NULL; } - return checkerror(ctx, v); + return v; } static object * -sub(ctx, v, w) - context *ctx; +sub(v, w) 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 (*v->ob_type->tp_as_number->nb_subtract)(v, w); + err_setstr(TypeError, "bad operand type(s) for -"); return NULL; } static object * -mul(ctx, v, w) - context *ctx; +mul(v, w) object *v, *w; { typeobject *tp; @@ -375,259 +135,234 @@ mul(ctx, v, w) } tp = v->ob_type; if (tp->tp_as_number != NULL) - return checkerror(ctx, (*tp->tp_as_number->nb_multiply)(v, w)); + return (*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"); + err_setstr(TypeError, + "can't multiply sequence with non-int"); return NULL; } if (tp->tp_as_sequence->sq_repeat == NULL) { - type_error(ctx, "sequence does not support *"); + err_setstr(TypeError, "sequence does not support *"); return NULL; } - return checkerror(ctx, (*tp->tp_as_sequence->sq_repeat) - (v, (int)getintvalue(w))); + return (*tp->tp_as_sequence->sq_repeat) + (v, (int)getintvalue(w)); } - type_error(ctx, "bad operand type(s) for *"); + err_setstr(TypeError, "bad operand type(s) for *"); return NULL; } static object * -div(ctx, v, w) - context *ctx; +div(v, w) 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 (*v->ob_type->tp_as_number->nb_divide)(v, w); + err_setstr(TypeError, "bad operand type(s) for /"); return NULL; } static object * -rem(ctx, v, w) - context *ctx; +rem(v, w) 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 (*v->ob_type->tp_as_number->nb_remainder)(v, w); + err_setstr(TypeError, "bad operand type(s) for %"); return NULL; } static object * -neg(ctx, v) - context *ctx; +neg(v) 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 (*v->ob_type->tp_as_number->nb_negative)(v); + err_setstr(TypeError, "bad operand type(s) for unary -"); return NULL; } static object * -pos(ctx, v) - context *ctx; +pos(v) 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 (*v->ob_type->tp_as_number->nb_positive)(v); + err_setstr(TypeError, "bad operand type(s) for unary +"); return NULL; } static object * -not(ctx, v) - context *ctx; +not(v) object *v; { - int outcome = testbool(ctx, v); - if (ctx->ctx_exception) - return NULL; - return checkerror(ctx, newintobject((long) !outcome)); + int outcome = testbool(v); + object *w = outcome == 0 ? True : False; + INCREF(w); + return w; } static object * -call_builtin(ctx, func, args) - context *ctx; +call_builtin(func, arg) object *func; - object *args; + object *arg; { - 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)); + return (*meth)(self, arg); } if (is_classobject(func)) { - if (args != NULL) { - type_error(ctx, "classobject() allows no arguments"); + if (arg != NULL) { + err_setstr(TypeError, + "classobject() allows no arguments"); return NULL; } - return checkerror(ctx, newclassmemberobject(func)); + return newclassmemberobject(func); } - type_error(ctx, "call of non-function"); + err_setstr(TypeError, "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; +call_function(func, arg) object *func; - object *args; + object *arg; { - object *newargs = NULL; - object *savelocals, *newlocals, *saveglobals; - object *c, *v; + object *newarg = NULL; + object *newlocals, *newglobals; + object *co, *v; if (is_classmethodobject(func)) { object *self = classmethodgetself(func); func = classmethodgetfunc(func); - if (args == NULL) { - args = self; + if (arg == NULL) { + arg = self; } else { - newargs = checkerror(ctx, newtupleobject(2)); - if (newargs == NULL) + newarg = newtupleobject(2); + if (newarg == NULL) return NULL; INCREF(self); - INCREF(args); - settupleitem(newargs, 0, self); - settupleitem(newargs, 1, args); - args = newargs; + INCREF(arg); + settupleitem(newarg, 0, self); + settupleitem(newarg, 1, arg); + arg = newarg; } } else { if (!is_funcobject(func)) { - type_error(ctx, "call of non-function"); + err_setstr(TypeError, "call of non-function"); return NULL; } } - c = checkerror(ctx, getfunccode(func)); - if (c == NULL) { - XDECREF(newargs); + co = getfunccode(func); + if (co == NULL) { + XDECREF(newarg); return NULL; } - if (!is_codeobject(c)) { - printf("Bad code\n"); + if (!is_codeobject(co)) { + fprintf(stderr, "XXX Bad code\n"); abort(); } - newlocals = checkerror(ctx, newdictobject()); + newlocals = newdictobject(); if (newlocals == NULL) { - XDECREF(newargs); + XDECREF(newarg); return NULL; } - savelocals = ctx->ctx_locals; - ctx->ctx_locals = newlocals; - saveglobals = ctx->ctx_globals; - ctx->ctx_globals = getfuncglobals(func); + newglobals = getfuncglobals(func); + INCREF(newglobals); - v = eval_compiled(ctx, (codeobject *)c, args, 1); + v = eval_code((codeobject *)co, newglobals, newlocals, arg); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = savelocals; - ctx->ctx_globals = saveglobals; + DECREF(newlocals); + DECREF(newglobals); - XDECREF(newargs); + XDECREF(newarg); return v; } static object * -apply_subscript(ctx, v, w) - context *ctx; +apply_subscript(v, w) object *v, *w; { typeobject *tp = v->ob_type; if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) { - type_error(ctx, "unsubscriptable object"); + err_setstr(TypeError, "unsubscriptable object"); return NULL; } if (tp->tp_as_sequence != NULL) { int i; if (!is_intobject(w)) { - type_error(ctx, "sequence subscript not int"); + err_setstr(TypeError, "sequence subscript not int"); return NULL; } i = getintvalue(w); - return checkerror(ctx, (*tp->tp_as_sequence->sq_item)(v, i)); + return (*tp->tp_as_sequence->sq_item)(v, i); } - return checkerror(ctx, (*tp->tp_as_mapping->mp_subscript)(v, w)); + return (*tp->tp_as_mapping->mp_subscript)(v, w); } static object * -loop_subscript(ctx, v, w) - context *ctx; +loop_subscript(v, w) 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"); + 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 checkerror(ctx, (*sq->sq_item)(v, i)); + return (*sq->sq_item)(v, i); } static int -slice_index(ctx, v, isize, pi) - context *ctx; +slice_index(v, isize, pi) object *v; int isize; int *pi; { if (v != NULL) { if (!is_intobject(v)) { - type_error(ctx, "slice index must be int"); - return 0; + err_setstr(TypeError, "slice index must be int"); + return -1; } *pi = getintvalue(v); if (*pi < 0) *pi += isize; } - return 1; + return 0; } static object * -apply_slice(ctx, u, v, w) /* u[v:w] */ - context *ctx; +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) { - type_error(ctx, "only sequences can be sliced"); + err_setstr(TypeError, "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)) + if (slice_index(v, isize, &ilow) != 0) return NULL; - if (!slice_index(ctx, w, isize, &ihigh)) + if (slice_index(w, isize, &ihigh) != 0) return NULL; - return checkerror(ctx, (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh)); + return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh); } -static void -assign_subscript(ctx, w, key, v) - context *ctx; + +static int +assign_subscript(w, key, v) /* w[key] = v */ object *w; object *key; object *v; @@ -636,47 +371,48 @@ assign_subscript(ctx, w, key, v) 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_setstr(TypeError, + "sequence subscript must be integer"); + return -1; } - err = (*func)(w, (int)getintvalue(key), v); + else + return (*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); + return (*func)(w, key, v); } else { - type_error(ctx, "can't assign to this subscripted object"); - return; + err_setstr(TypeError, + "can't assign to this subscripted object"); + return -1; } - if (err != 0) - puterrno(ctx); } -static void -assign_slice(ctx, u, v, w, x) /* u[v:w] = x */ - context *ctx; +static int +assign_slice(u, v, w, x) /* u[v:w] = x */ object *u, *v, *w, *x; { - typeobject *tp = u->ob_type; + sequence_methods *sq = u->ob_type->tp_as_sequence; int ilow, ihigh, isize; - if (tp->tp_as_sequence == NULL || - tp->tp_as_sequence->sq_ass_slice == NULL) { - type_error(ctx, "unassignable slice"); - return; + 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 = (*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); + 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 @@ -695,9 +431,50 @@ cmp_exception(err, v) 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(ctx, op, v, w) - register context *ctx; +cmp_outcome(op, v, w) enum cmp_op op; register object *v; register object *w; @@ -705,44 +482,43 @@ cmp_outcome(ctx, op, v, 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); + 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: - cmp = cmp_exception(v, w); + res = 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? */ + 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 void -import_from(ctx, v, name) - context *ctx; +static int +import_from(locals, v, name) + object *locals; object *v; char *name; { @@ -758,27 +534,27 @@ import_from(ctx, v, name) x = dictlookup(w, name); if (x == NULL) { /* XXX can't happen? */ - name_error(ctx, name); - break; - } - if (dictinsert(ctx->ctx_locals, name, x) != 0) { - puterrno(ctx); - break; + err_setstr(NameError, name); + return -1; } + if (dictinsert(locals, name, x) != 0) + return -1; } + return 0; } else { x = dictlookup(w, name); - if (x == NULL) - name_error(ctx, name); - else if (dictinsert(ctx->ctx_locals, name, x) != 0) - puterrno(ctx); + if (x == NULL) { + err_setstr(NameError, name); + return -1; + } + else + return dictinsert(locals, name, x); } } static object * -build_class(ctx, v, w) - context *ctx; +build_class(v, w) object *v; /* None or tuple containing base classes */ object *w; /* dictionary */ { @@ -787,7 +563,8 @@ build_class(ctx, v, w) for (i = gettuplesize(v); --i >= 0; ) { object *x = gettupleitem(v, i); if (!is_classobject(x)) { - type_error(ctx, "base is not a class object"); + err_setstr(TypeError, + "base is not a class object"); return NULL; } } @@ -796,85 +573,152 @@ build_class(ctx, v, w) v = NULL; } if (!is_dictobject(w)) { - sys_error(ctx, "build_class with non-dictionary"); + err_setstr(SystemError, "build_class with non-dictionary"); return NULL; } - return checkerror(ctx, newclassobject(v, w)); + return newclassobject(v, w); } -static object * -eval_compiled(ctx, co, arg, needvalue) - context *ctx; + +/* 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; - int needvalue; { - frameobject *f; - register object *v; + 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 *x; - char *name; - int i, op; - FILE *fp; -#ifndef NDEBUG - int trace = dictlookup(ctx->ctx_globals, "__trace") != NULL; + 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 - 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; - } +/* Code access macros */ -#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 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) 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 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); } - while (f->f_nexti < getstringsize((object *)f->f_code->co_code) && - !ctx->ctx_exception) { -#ifdef NDEBUG - op = Nextbyte(f); -#else - op = trace ? trace_nextop(f) : nextbyte(f); + 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 - if (op >= HAVE_ARGUMENT) - i = nextint(f); - switch (op) { + + /* Main switch on opcode */ - case DUP_TOP: - v = TOP(); - INCREF(v); - PUSH(v); - break; + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ case POP_TOP: v = POP(); @@ -897,125 +741,130 @@ eval_compiled(ctx, co, arg, needvalue) PUSH(w); break; + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + case UNARY_POSITIVE: v = POP(); - u = pos(ctx, v); + x = pos(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_NEGATIVE: v = POP(); - u = neg(ctx, v); + x = neg(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_NOT: v = POP(); - u = not(ctx, v); + x = not(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_CONVERT: v = POP(); - u = checkerror(ctx, reprobject(v)); + x = reprobject(v); DECREF(v); - PUSH(u); + PUSH(x); break; case UNARY_CALL: v = POP(); if (is_classmethodobject(v) || is_funcobject(v)) - u = call_function(ctx, v, (object *)NULL); + x = call_function(v, (object *)NULL); else - u = call_builtin(ctx, v, (object *)NULL); + x = call_builtin(v, (object *)NULL); DECREF(v); - PUSH(u); + PUSH(x); break; case BINARY_MULTIPLY: w = POP(); v = POP(); - u = mul(ctx, v, w); + x = mul(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_DIVIDE: w = POP(); v = POP(); - u = div(ctx, v, w); + x = div(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_MODULO: w = POP(); v = POP(); - u = rem(ctx, v, w); + x = rem(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_ADD: w = POP(); v = POP(); - u = add(ctx, v, w); + x = add(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_SUBTRACT: w = POP(); v = POP(); - u = sub(ctx, v, w); + x = sub(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_SUBSCR: w = POP(); v = POP(); - u = apply_subscript(ctx, v, w); + x = apply_subscript(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case BINARY_CALL: w = POP(); v = POP(); if (is_classmethodobject(v) || is_funcobject(v)) - u = call_function(ctx, v, w); + x = call_function(v, w); else - u = call_builtin(ctx, v, w); + x = call_builtin(v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case SLICE+0: case SLICE+1: case SLICE+2: case SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = apply_slice(ctx, u, v, w); + x = apply_slice(u, v, w); DECREF(u); XDECREF(v); XDECREF(w); @@ -1026,19 +875,18 @@ eval_compiled(ctx, co, arg, needvalue) case STORE_SLICE+1: case STORE_SLICE+2: case STORE_SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-STORE_SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-STORE_SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = POP(); - assign_slice(ctx, u, v, w, x); /* u[v:w] = x */ - DECREF(x); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + DECREF(t); DECREF(u); XDECREF(v); XDECREF(w); @@ -1048,18 +896,17 @@ eval_compiled(ctx, co, arg, needvalue) case DELETE_SLICE+1: case DELETE_SLICE+2: case DELETE_SLICE+3: - op -= SLICE; - if (op & 2) + if ((opcode-DELETE_SLICE) & 2) w = POP(); else w = NULL; - if (op & 1) + if ((opcode-DELETE_SLICE) & 1) v = POP(); else v = NULL; u = POP(); - x = NULL; - assign_slice(ctx, u, v, w, x); /* del u[v:w] */ + err = assign_slice(u, v, w, (object *)NULL); + /* del u[v:w] */ DECREF(u); XDECREF(v); XDECREF(w); @@ -1070,7 +917,7 @@ eval_compiled(ctx, co, arg, needvalue) v = POP(); u = POP(); /* v[w] = u */ - assign_subscript(ctx, v, w, u); + err = assign_subscript(v, w, u); DECREF(u); DECREF(v); DECREF(w); @@ -1080,7 +927,7 @@ eval_compiled(ctx, co, arg, needvalue) w = POP(); v = POP(); /* del v[w] */ - assign_subscript(ctx, v, w, (object *)NULL); + err = assign_subscript(v, w, (object *)NULL); DECREF(v); DECREF(w); break; @@ -1125,113 +972,126 @@ eval_compiled(ctx, co, arg, needvalue) break; case BREAK_LOOP: - raise_pseudo(ctx, BREAK_PSEUDO); + why = WHY_BREAK; 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); - } + if (!is_stringobject(w)) + err_setstr(TypeError, + "exceptions must be strings"); + else + err_setval(w, v); + DECREF(v); + DECREF(w); + why = WHY_EXCEPTION; break; case LOAD_LOCALS: - v = ctx->ctx_locals; + v = f->f_locals; INCREF(v); PUSH(v); break; case RETURN_VALUE: - v = POP(); - raise_pseudo(ctx, RETURN_PSEUDO); - ctx->ctx_errval = v; + retval = POP(); + why = WHY_RETURN; break; case REQUIRE_ARGS: - if (EMPTY()) - type_error(ctx, + if (EMPTY()) { + err_setstr(TypeError, "function expects argument(s)"); + why = WHY_EXCEPTION; + } break; case REFUSE_ARGS: - if (!EMPTY()) - type_error(ctx, + if (!EMPTY()) { + err_setstr(TypeError, "function expects no argument(s)"); + why = WHY_EXCEPTION; + } break; case BUILD_FUNCTION: v = POP(); - x = checkerror(ctx, newfuncobject(v, ctx->ctx_globals)); + x = newfuncobject(v, f->f_globals); DECREF(v); PUSH(x); break; case POP_BLOCK: - (void) pop_block(f); + { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + DECREF(v); + } + } 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; + why = (enum why_code) getintvalue(v); + if (why == WHY_RETURN) + retval = POP(); } - else if (is_stringobject(v)) - raise_exception(ctx, v, w); - else if (v == None) { - DECREF(v); + else if (is_stringobject(v)) { + w = POP(); + err_setval(v, w); + DECREF(w); + w = POP(); + tb_store(w); DECREF(w); + why = WHY_RERAISE; } - else { - sys_error(ctx, "'finally' pops bad exception"); + else if (v != None) { + err_setstr(SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; } + DECREF(v); break; case BUILD_CLASS: w = POP(); v = POP(); - x = build_class(ctx, v, w); + x = build_class(v, w); PUSH(x); DECREF(v); DECREF(w); break; case STORE_NAME: - name = GETNAME(i); + name = GETNAME(oparg); v = POP(); - if (dictinsert(ctx->ctx_locals, name, v) != 0) - mem_error(ctx, "insert in symbol table"); + err = dictinsert(f->f_locals, name, v); DECREF(v); break; case DELETE_NAME: - name = GETNAME(i); - if (dictremove(ctx->ctx_locals, name) != 0) - name_error(ctx, name); + name = GETNAME(oparg); + if ((err = dictremove(f->f_locals, name)) != 0) + err_setstr(NameError, name); break; case UNPACK_TUPLE: v = POP(); if (!is_tupleobject(v)) { - type_error(ctx, "unpack non-tuple"); + err_setstr(TypeError, "unpack non-tuple"); + why = WHY_EXCEPTION; } - else if (gettuplesize(v) != i) { - error(ctx, "unpack tuple of wrong size"); + else if (gettuplesize(v) != oparg) { + err_setstr(RuntimeError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; } else { - for (; --i >= 0; ) { - w = gettupleitem(v, i); + for (; --oparg >= 0; ) { + w = gettupleitem(v, oparg); INCREF(w); PUSH(w); } @@ -1242,14 +1102,17 @@ eval_compiled(ctx, co, arg, needvalue) case UNPACK_LIST: v = POP(); if (!is_listobject(v)) { - type_error(ctx, "unpack non-list"); + err_setstr(TypeError, "unpack non-list"); + why = WHY_EXCEPTION; } - else if (getlistsize(v) != i) { - error(ctx, "unpack tuple of wrong size"); + else if (getlistsize(v) != oparg) { + err_setstr(RuntimeError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; } else { - for (; --i >= 0; ) { - w = getlistitem(v, i); + for (; --oparg >= 0; ) { + w = getlistitem(v, oparg); INCREF(w); PUSH(w); } @@ -1258,144 +1121,120 @@ eval_compiled(ctx, co, arg, needvalue) break; case STORE_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); 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); - } + err = setattr(v, name, u); /* v.name = u */ DECREF(v); DECREF(u); break; case DELETE_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); 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); - } + err = setattr(v, name, (object *)NULL); + /* del v.name */ DECREF(v); break; case LOAD_CONST: - v = GETCONST(i); - INCREF(v); - PUSH(v); + x = GETCONST(oparg); + INCREF(x); + PUSH(x); break; case LOAD_NAME: - 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); + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + x = dictlookup(f->f_globals, name); + if (x == NULL) + x = getbuiltin(name); } - if (v == NULL) - name_error(ctx, name); - /* XXX could optimize */ + if (x == NULL) + err_setstr(NameError, name); else - INCREF(v); - PUSH(v); + INCREF(x); + PUSH(x); break; case BUILD_TUPLE: - v = checkerror(ctx, newtupleobject(i)); - if (v != NULL) { - for (; --i >= 0;) { + x = newtupleobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { w = POP(); - settupleitem(v, i, w); + err = settupleitem(x, oparg, w); + if (err != 0) + break; } + PUSH(x); } - PUSH(v); break; case BUILD_LIST: - v = checkerror(ctx, newlistobject(i)); - if (v != NULL) { - for (; --i >= 0;) { + x = newlistobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { w = POP(); - setlistitem(v, i, w); + err = setlistitem(x, oparg, w); + if (err != 0) + break; } + PUSH(x); } - PUSH(v); break; case BUILD_MAP: - v = checkerror(ctx, newdictobject()); - PUSH(v); + x = newdictobject(); + PUSH(x); break; case LOAD_ATTR: - name = GETNAME(i); + name = GETNAME(oparg); 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)); - } + x = getattr(v, name); DECREF(v); - PUSH(u); + PUSH(x); break; case COMPARE_OP: w = POP(); v = POP(); - u = cmp_outcome(ctx, (enum cmp_op)i, v, w); + x = cmp_outcome((enum cmp_op)oparg, v, w); DECREF(v); DECREF(w); - PUSH(u); + PUSH(x); break; case IMPORT_NAME: - name = GETNAME(i); - u = import_module(ctx, name); - if (u != NULL) { - INCREF(u); - PUSH(u); - } + name = GETNAME(oparg); + x = import_module(name); + XINCREF(x); + PUSH(x); break; case IMPORT_FROM: - name = GETNAME(i); + name = GETNAME(oparg); v = TOP(); - import_from(ctx, v, name); + err = import_from(f->f_locals, v, name); break; case JUMP_FORWARD: - JUMPBY(i); + JUMPBY(oparg); break; case JUMP_IF_FALSE: - if (!testbool(ctx, TOP())) - JUMPBY(i); + if (!testbool(TOP())) + JUMPBY(oparg); break; case JUMP_IF_TRUE: - if (testbool(ctx, TOP())) - JUMPBY(i); + if (testbool(TOP())) + JUMPBY(oparg); break; case JUMP_ABSOLUTE: - JUMPTO(i); - /* XXX Should check for interrupts more often? */ - if (intrcheck()) - intr_error(ctx); + JUMPTO(oparg); break; case FOR_LOOP: @@ -1406,157 +1245,168 @@ eval_compiled(ctx, co, arg, needvalue) s, i are popped, and we jump */ w = POP(); /* Loop index */ v = POP(); /* Sequence object */ - x = loop_subscript(ctx, v, w); - if (x != NULL) { + u = loop_subscript(v, w); + if (u != NULL) { PUSH(v); - u = checkerror(ctx, - newintobject(getintvalue(w)+1)); - PUSH(u); - DECREF(w); + x = newintobject(getintvalue(w)+1); PUSH(x); + DECREF(w); + PUSH(u); } else { DECREF(v); DECREF(w); - JUMPBY(i); + /* A NULL can mean "s exhausted" + but also an error: */ + if (err_occurred()) + why = WHY_EXCEPTION; + else + JUMPBY(oparg); } break; case SETUP_LOOP: - setup_block(f, SETUP_LOOP, i); - break; - case SETUP_EXCEPT: - setup_block(f, SETUP_EXCEPT, i); + case SETUP_FINALLY: + setup_block(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); break; - case SETUP_FINALLY: - setup_block(f, SETUP_FINALLY, i); + case SET_LINENO: +#ifdef TRACE + if (trace) + printf("--- Line %d ---\n", oparg); +#endif + lineno = oparg; break; default: - printf("opcode %d\n", op); - sys_error(ctx, "eval_compiled: unknown opcode"); + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + lineno, opcode); + err_setstr(SystemError, "eval_code: unknown opcode"); + why = WHY_EXCEPTION; break; + } /* 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; } + +#ifndef NDEBUG + /* Double-check exception status */ - /* Unwind block stack if an exception occurred */ + 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 */ - while (ctx->ctx_exception && f->f_iblock > 0) { + 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); - if (b->b_type == SETUP_LOOP && - ctx->ctx_exception == BREAK_PSEUDO) { - clear_exception(ctx); + 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; } - 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); + 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 */ - 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; - } + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + XDECREF(v); } - -#undef EMPTY -#undef FULL -#undef GETCONST -#undef GETNAME -#undef JUMPTO -#undef JUMPBY - -#undef POP -#undef TOP -#undef PUSH + /* Restore previous frame and release the current one */ + + current_frame = f->f_back; 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); - freenode(n); /* XXX A rather strange place to do this! */ - if (co == NULL) { - puterrno(ctx); + + if (why == WHY_RETURN) + return retval; + else 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*/); } diff --git a/Python/compile.c b/Python/compile.c index 2f5fd69..87acf39 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1,31 +1,49 @@ /* Compile an expression node to intermediate code */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" - -#include "PROTO.h" -#include "object.h" -#include "objimpl.h" -#include "intobject.h" -#include "floatobject.h" -#include "stringobject.h" -#include "listobject.h" +/* XXX TO DO: + XXX Compute maximum needed stack sizes while compiling + XXX Generate simple jump for break/return outside 'try...finally' + XXX Include function name in code (and module names?) +*/ + +#include "allobjects.h" + #include "node.h" #include "token.h" #include "graminit.h" -#include "errors.h" #include "compile.h" #include "opcode.h" +#include "structmember.h" + +#include <ctype.h> + +#define OFF(x) offsetof(codeobject, x) + +static struct memberlist code_memberlist[] = { + {"co_code", T_OBJECT, OFF(co_code)}, + {"co_consts", T_OBJECT, OFF(co_consts)}, + {"co_names", T_OBJECT, OFF(co_names)}, + {"co_filename", T_OBJECT, OFF(co_filename)}, + {NULL} /* Sentinel */ +}; + +static object * +code_getattr(co, name) + codeobject *co; + char *name; +{ + return getmember((char *)co, code_memberlist, name); +} static void -code_dealloc(c) - codeobject *c; +code_dealloc(co) + codeobject *co; { - XDECREF(c->co_code); - XDECREF(c->co_consts); - XDECREF(c->co_names); - DEL(c); + XDECREF(co->co_code); + XDECREF(co->co_consts); + XDECREF(co->co_names); + XDECREF(co->co_filename); + DEL(co); } typeobject Codetype = { @@ -36,7 +54,7 @@ typeobject Codetype = { 0, code_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - 0, /*tp_getattr*/ + code_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ @@ -45,13 +63,14 @@ typeobject Codetype = { 0, /*tp_as_mapping*/ }; -static codeobject *newcodeobject PROTO((object *, object *, object *)); +static codeobject *newcodeobject PROTO((object *, object *, object *, char *)); static codeobject * -newcodeobject(code, consts, names) +newcodeobject(code, consts, names, filename) object *code; object *consts; object *names; + char *filename; { codeobject *co; int i; @@ -78,6 +97,10 @@ newcodeobject(code, consts, names) co->co_consts = consts; INCREF(names); co->co_names = names; + if ((co->co_filename = newstringobject(filename)) == NULL) { + DECREF(co); + co = NULL; + } } return co; } @@ -90,10 +113,13 @@ struct compiling { object *c_names; /* list of strings (names) */ int c_nexti; /* index into c_code */ int c_errors; /* counts errors occurred */ + int c_infunction; /* set when compiling a function */ + int c_loops; /* counts nested loops */ + char *c_filename; /* filename of current node */ }; /* Prototypes */ -static int com_init PROTO((struct compiling *)); +static int com_init PROTO((struct compiling *, char *)); static void com_free PROTO((struct compiling *)); static void com_done PROTO((struct compiling *)); static void com_node PROTO((struct compiling *, struct _node *)); @@ -108,8 +134,9 @@ static int com_addname PROTO((struct compiling *, object *)); static void com_addopname PROTO((struct compiling *, int, node *)); static int -com_init(c) +com_init(c, filename) struct compiling *c; + char *filename; { if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL) goto fail_3; @@ -119,6 +146,9 @@ com_init(c) goto fail_1; c->c_nexti = 0; c->c_errors = 0; + c->c_infunction = 0; + c->c_loops = 0; + c->c_filename = filename; return 1; fail_1: @@ -153,6 +183,8 @@ com_addbyte(c, byte) { int len; if (byte < 0 || byte > 255) { + fprintf(stderr, "XXX compiling bad byte: %d\n", byte); + abort(); err_setstr(SystemError, "com_addbyte: byte out of range"); c->c_errors++; } @@ -1076,6 +1108,10 @@ com_return_stmt(c, n) node *n; { REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */ + if (!c->c_infunction) { + err_setstr(TypeError, "'return' outside function"); + c->c_errors++; + } if (NCH(n) == 2) com_addoparg(c, LOAD_CONST, com_addconst(c, None)); else @@ -1134,6 +1170,9 @@ com_if_stmt(c, n) /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ for (i = 0; i+3 < NCH(n); i+=4) { int a = 0; + node *ch = CHILD(n, i+1); + if (i > 0) + com_addoparg(c, SET_LINENO, ch->n_lineno); com_node(c, CHILD(n, i+1)); com_addfwref(c, JUMP_IF_FALSE, &a); com_addbyte(c, POP_TOP); @@ -1158,10 +1197,13 @@ com_while_stmt(c, n) REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ com_addfwref(c, SETUP_LOOP, &break_anchor); begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); com_node(c, CHILD(n, 1)); com_addfwref(c, JUMP_IF_FALSE, &anchor); com_addbyte(c, POP_TOP); + c->c_loops++; com_node(c, CHILD(n, 3)); + c->c_loops--; com_addoparg(c, JUMP_ABSOLUTE, begin); com_backpatch(c, anchor); com_addbyte(c, POP_TOP); @@ -1190,9 +1232,12 @@ com_for_stmt(c, n) com_addoparg(c, LOAD_CONST, com_addconst(c, v)); XDECREF(v); begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); com_addfwref(c, FOR_LOOP, &anchor); com_assign(c, CHILD(n, 1), 1/*assigning*/); + c->c_loops++; com_node(c, CHILD(n, 5)); + c->c_loops--; com_addoparg(c, JUMP_ABSOLUTE, begin); com_backpatch(c, anchor); com_addbyte(c, POP_BLOCK); @@ -1225,7 +1270,6 @@ com_for_stmt(c, n) <code for S> POP_BLOCK LOAD_CONST <nil> - LOAD_CONST <nil> L: <code for Sf> END_FINALLY @@ -1242,13 +1286,9 @@ com_for_stmt(c, n) stack until its level is the same as indicated on the block stack. (The label is ignored.) END_FINALLY: - Pops two entries from the *value* stack and re-raises - the exception they specify. If the top entry is nil, - no exception is raised. If it is a number, a pseudo - exception is raised ('return' or 'break'). Otherwise, - a real exception (specified by a string) is raised. - The second entry popped from the is the value that goes - with the exception (or the return value). + Pops a variable number of entries from the *value* stack + and re-raises the exception they specify. The number of + entries popped depends on the (pseudo) exception type. The block stack is unwound when an exception is raised: when a SETUP_FINALLY entry is found, the exception is pushed @@ -1257,6 +1297,9 @@ com_for_stmt(c, n) stack. Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": + (The contents of the value stack is shown in [], with the top + at the right; 'tb' is trace-back info, 'val' the exception's + associated value, and 'exc' the exception.) Value stack Label Instruction Argument [] SETUP_EXCEPT L1 @@ -1264,22 +1307,23 @@ com_for_stmt(c, n) [] POP_BLOCK [] JUMP_FORWARD L0 - [val, exc] L1: DUP - [val, exc, exc] <evaluate E1> - [val, exc, exc, E1] COMPARE_OP EXC_MATCH - [val, exc, 1-or-0] JUMP_IF_FALSE L2 - [val, exc, 1] POP - [val, exc] POP - [val] <assign to V1> + [tb, val, exc] L1: DUP ) + [tb, val, exc, exc] <evaluate E1> ) + [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 + [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) + [tb, val, exc, 1] POP ) + [tb, val, exc] POP + [tb, val] <assign to V1> (or POP if no V1) + [tb] POP [] <code for S1> JUMP_FORWARD L0 - [val, exc, 0] L2: POP - [val, exc] DUP + [tb, val, exc, 0] L2: POP + [tb, val, exc] DUP .............................etc....................... - [val, exc, 0] Ln+1: POP - [val, exc] END_FINALLY # re-raise exception + [tb, val, exc, 0] Ln+1: POP + [tb, val, exc] END_FINALLY # re-raise exception [] L0: <next statement> @@ -1323,6 +1367,7 @@ com_try_stmt(c, n) break; } except_anchor = 0; + com_addoparg(c, SET_LINENO, ch->n_lineno); if (NCH(ch) > 1) { com_addbyte(c, DUP_TOP); com_node(c, CHILD(ch, 1)); @@ -1335,6 +1380,7 @@ com_try_stmt(c, n) com_assign(c, CHILD(ch, 3), 1/*assigning*/); else com_addbyte(c, POP_TOP); + com_addbyte(c, POP_TOP); com_node(c, CHILD(n, i+2)); com_addfwref(c, JUMP_FORWARD, &end_anchor); if (except_anchor) { @@ -1346,11 +1392,13 @@ com_try_stmt(c, n) com_backpatch(c, end_anchor); } if (finally_anchor) { + node *ch; com_addbyte(c, POP_BLOCK); com_addoparg(c, LOAD_CONST, com_addconst(c, None)); - com_addoparg(c, LOAD_CONST, com_addconst(c, None)); com_backpatch(c, finally_anchor); - com_node(c, CHILD(n, NCH(n)-1)); + ch = CHILD(n, NCH(n)-1); + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, ch); com_addbyte(c, END_FINALLY); } } @@ -1382,7 +1430,7 @@ com_funcdef(c, n) { object *v; REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ - v = (object *)compile(n); + v = (object *)compile(n, c->c_filename); if (v == NULL) c->c_errors++; else { @@ -1426,7 +1474,7 @@ com_classdef(c, n) com_bases(c, CHILD(n, 4)); else com_addoparg(c, LOAD_CONST, com_addconst(c, None)); - v = (object *)compile(n); + v = (object *)compile(n, c->c_filename); if (v == NULL) c->c_errors++; else { @@ -1459,9 +1507,13 @@ com_node(c, n) /* Trivial parse tree nodes */ case stmt: - case simple_stmt: case flow_stmt: + com_node(c, CHILD(n, 0)); + break; + + case simple_stmt: case compound_stmt: + com_addoparg(c, SET_LINENO, n->n_lineno); com_node(c, CHILD(n, 0)); break; @@ -1479,6 +1531,10 @@ com_node(c, n) case pass_stmt: break; case break_stmt: + if (c->c_loops == 0) { + err_setstr(TypeError, "'break' outside loop"); + c->c_errors++; + } com_addbyte(c, BREAK_LOOP); break; case return_stmt: @@ -1608,48 +1664,50 @@ compile_funcdef(c, n) com_addbyte(c, REQUIRE_ARGS); com_fplist(c, ch); } + c->c_infunction = 1; com_node(c, CHILD(n, 4)); + c->c_infunction = 0; com_addoparg(c, LOAD_CONST, com_addconst(c, None)); com_addbyte(c, RETURN_VALUE); } static void -compile_classdef(c, n) - struct compiling *c; - node *n; -{ - node *ch; - REQ(n, classdef); - /* - classdef: 'class' NAME parameters ['=' baselist] ':' suite - */ - com_addbyte(c, REFUSE_ARGS); - com_node(c, CHILD(n, NCH(n)-1)); - com_addbyte(c, LOAD_LOCALS); - com_addbyte(c, RETURN_VALUE); -} - -static void compile_node(c, n) struct compiling *c; node *n; { + com_addoparg(c, SET_LINENO, n->n_lineno); + switch (TYPE(n)) { case single_input: /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ + com_addbyte(c, REFUSE_ARGS); n = CHILD(n, 0); if (TYPE(n) != NEWLINE) com_node(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); break; case file_input: + com_addbyte(c, REFUSE_ARGS); com_file_input(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); break; case expr_input: + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + case eval_input: + com_addbyte(c, REFUSE_ARGS); com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); break; case funcdef: @@ -1657,7 +1715,11 @@ compile_node(c, n) break; case classdef: - compile_classdef(c, n); + /* 'class' NAME parameters ['=' baselist] ':' suite */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, NCH(n)-1)); + com_addbyte(c, LOAD_LOCALS); + com_addbyte(c, RETURN_VALUE); break; default: @@ -1668,17 +1730,18 @@ compile_node(c, n) } codeobject * -compile(n) +compile(n, filename) node *n; + char *filename; { struct compiling sc; codeobject *co; - if (!com_init(&sc)) + if (!com_init(&sc, filename)) return NULL; compile_node(&sc, n); com_done(&sc); if (sc.c_errors == 0) - co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names); + co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename); else co = NULL; com_free(&sc); diff --git a/Python/errors.c b/Python/errors.c index 8ddde51..7424b0c 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -11,12 +11,11 @@ return value and then calls puterrno(ctx) to turn the errno value into a true exception. Problems with this approach are: - it used standard errno values to indicate Python-specific errors, - but this means that when such an error code is reported by UNIX the - user gets a confusing message + but this means that when such an error code is reported by a system + call (e.g., in module posix), the user gets a confusing message - errno is a global variable, which makes extensions to a multi- threading environment difficult; e.g., in IRIX, multi-threaded - programs must use the function getoserror() (sp.?) instead of - looking in errno + programs must use the function oserror() instead of looking in errno - there is no portable way to add new error numbers for specic situations -- the value space for errno is reserved to the OS, yet the way to turn module-specific errors into a module-specific @@ -25,21 +24,18 @@ error. The new interface solves all these problems. To return an error, a - built-in function calls err_set(exception), err_set(valexception, + built-in function calls err_set(exception), err_setval(exception, value) or err_setstr(exception, string), and returns NULL. These functions save the value for later use by puterrno(). To adapt this scheme to a multi-threaded environment, only the implementation of err_setval() has to be changed. */ -#include <stdio.h> +#include "errno.h" -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "errors.h" +#include "allobjects.h" + +#include "errcode.h" extern char *strerror PROTO((int)); @@ -53,16 +49,12 @@ err_setval(exception, value) object *exception; object *value; { - if (last_exception != NULL) - DECREF(last_exception); - if (exception != NULL) - INCREF(exception); + XDECREF(last_exception); + XINCREF(exception); last_exception = exception; - if (last_exc_val != NULL) - DECREF(last_exc_val); - if (value != NULL) - INCREF(value); + XDECREF(last_exc_val); + XINCREF(value); last_exc_val = value; } @@ -80,8 +72,7 @@ err_setstr(exception, string) { object *value = newstringobject(string); err_setval(exception, value); - if (value != NULL) - DECREF(value); + XDECREF(value); } int @@ -104,14 +95,10 @@ err_get(p_exc, p_val) void err_clear() { - if (last_exception != NULL) { - DECREF(last_exception); - last_exception = NULL; - } - if (last_exc_val != NULL) { - DECREF(last_exc_val); - last_exc_val = NULL; - } + XDECREF(last_exception); + last_exception = NULL; + XDECREF(last_exc_val); + last_exc_val = NULL; } /* Convenience functions to set a type error exception and return 0 */ @@ -126,7 +113,7 @@ err_badarg() object * err_nomem() { - err_setstr(MemoryError, "in built-in function"); + err_set(MemoryError); return NULL; } @@ -140,8 +127,7 @@ err_errno(exc) settupleitem(v, 1, newstringobject(strerror(errno))); } err_setval(exc, v); - if (v != NULL) - DECREF(v); + XDECREF(v); return NULL; } @@ -150,3 +136,34 @@ err_badcall() { err_setstr(SystemError, "bad argument to internal function"); } + +/* Set the error appropriate to the given input error code (see errcode.h) */ + +void +err_input(err) + int err; +{ + switch (err) { + case E_DONE: + case E_OK: + break; + case E_SYNTAX: + err_setstr(RuntimeError, "syntax error"); + break; + case E_TOKEN: + err_setstr(RuntimeError, "illegal token"); + break; + case E_INTR: + err_set(KeyboardInterrupt); + break; + case E_NOMEM: + err_nomem(); + break; + case E_EOF: + err_set(EOFError); + break; + default: + err_setstr(RuntimeError, "unknown input error"); + break; + } +} diff --git a/Python/graminit.c b/Python/graminit.c index c5ea23e..375a239 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -1,4 +1,4 @@ -#include "PROTO.h" +#include "pgenheaders.h" #include "grammar.h" static arc arcs_0_0[3] = { {2, 1}, diff --git a/Python/import.c b/Python/import.c index fd912ba..f4b4ca9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,153 +1,67 @@ /* Module definition and import implementation */ -#include <stdio.h> -#include "string.h" +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "moduleobject.h" #include "node.h" -#include "context.h" #include "token.h" #include "graminit.h" -#include "run.h" -#include "support.h" #include "import.h" #include "errcode.h" #include "sysmodule.h" +#include "pythonrun.h" -/* Define pathname separator and delimiter in $PYTHONPATH */ +/* Define pathname separator used in file names */ #ifdef THINK_C #define SEP ':' -#define DELIM ' ' #endif #ifndef SEP #define SEP '/' #endif -#ifndef DELIM -#define DELIM ':' -#endif +static object *modules; + +/* Initialization */ void initimport() { - object *v; - if ((v = newdictobject()) == NULL) - fatal("no mem for module table"); - if (sysset("modules", v) != 0) - fatal("can't assign sys.modules"); - DECREF(v); + if ((modules = newdictobject()) == NULL) + fatal("no mem for dictionary of modules"); } object * -new_module(name) +get_modules() +{ + return modules; +} + +object * +add_module(name) char *name; { object *m; - object *mtab; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - errno = EBADF; - return NULL; - } + if ((m = dictlookup(modules, name)) != NULL && is_moduleobject(m)) + return m; m = newmoduleobject(name); if (m == NULL) return NULL; - if (dictinsert(mtab, name, m) != 0) { + if (dictinsert(modules, name, m) != 0) { DECREF(m); return NULL; } + DECREF(m); /* Yes, it still exists, in modules! */ return m; } -static void -use_module(ctx, d) - context *ctx; - object *d; -{ - INCREF(d); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = d; - INCREF(d); - DECREF(ctx->ctx_globals); - ctx->ctx_globals = d; -} - -static void -define_module(ctx, name) - context *ctx; - char *name; -{ - object *m; - m = new_module(name); - if (m == NULL) { - puterrno(ctx); - return; - } - use_module(ctx, getmoduledict(m)); - DECREF(m); -} - -static object * -parsepath(path, delim) - char *path; - int delim; -{ - int i, n; - char *p; - object *v, *w; - - n = 1; - p = path; - while ((p = strchr(p, delim)) != NULL) { - n++; - p++; - } - v = newlistobject(n); - if (v == NULL) - return NULL; - for (i = 0; ; i++) { - p = strchr(path, delim); - if (p == NULL) - p = strchr(path, '\0'); /* End of string */ - w = newsizedstringobject(path, (int) (p - path)); - if (w == NULL) { - DECREF(v); - return NULL; - } - setlistitem(v, i, w); - if (*p == '\0') - break; - path = p+1; - } - return v; -} - -void -setpythonpath(path) - char *path; -{ - object *v; - if ((v = parsepath(path, DELIM)) != NULL) { - if (sysset("path", v) != 0) - fatal("can't assign sys.path"); - DECREF(v); - } -} - static FILE * -open_module(name, suffix) +open_module(name, suffix, namebuf) char *name; char *suffix; + char *namebuf; /* XXX No buffer overflow checks! */ { object *path; - char namebuf[256]; FILE *fp; path = sysget("path"); @@ -169,8 +83,8 @@ open_module(name, suffix) len = getstringsize(v); if (len > 0 && namebuf[len-1] != SEP) namebuf[len++] = SEP; - strcpy(namebuf+len, name); /* XXX check for overflow */ - strcat(namebuf, suffix); /* XXX ditto */ + strcpy(namebuf+len, name); + strcat(namebuf, suffix); fp = fopen(namebuf, "r"); if (fp != NULL) break; @@ -180,119 +94,113 @@ open_module(name, suffix) } static object * -load_module(ctx, name) - context *ctx; +get_module(m, name, m_ret) + /*module*/object *m; char *name; + object **m_ret; { - object *m; - char **p; + object *d; FILE *fp; node *n; int err; - object *mtab; - object *save_locals, *save_globals; + char namebuf[256]; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - errno = EBADF; - return NULL; - } - fp = open_module(name, ".py"); + fp = open_module(name, ".py", namebuf); if (fp == NULL) { - name_error(ctx, name); + if (m == NULL) + err_setstr(NameError, name); + else + err_setstr(RuntimeError, "no module source file"); return NULL; } - err = parseinput(fp, file_input, &n); + err = parse_file(fp, namebuf, file_input, &n); fclose(fp); if (err != E_DONE) { - input_error(ctx, err); - return NULL; - } - save_locals = ctx->ctx_locals; - INCREF(save_locals); - save_globals = ctx->ctx_globals; - INCREF(save_globals); - define_module(ctx, name); - exec_node(ctx, n); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = save_locals; - DECREF(ctx->ctx_globals); - ctx->ctx_globals = save_globals; - /* XXX need to free the tree n here; except referenced defs */ - if (ctx->ctx_exception) { - dictremove(mtab, name); /* Undefine the module */ + err_input(err); return NULL; } - m = dictlookup(mtab, name); if (m == NULL) { - error(ctx, "module not defined after loading"); - return NULL; + m = add_module(name); + if (m == NULL) { + freetree(n); + return NULL; + } + *m_ret = m; } + d = getmoduledict(m); + return run_node(n, namebuf, d, d); +} + +static object * +load_module(name) + char *name; +{ + object *m, *v; + v = get_module((object *)NULL, name, &m); + if (v == NULL) + return NULL; + DECREF(v); return m; } object * -import_module(ctx, name) - context *ctx; +import_module(name) char *name; { object *m; - object *mtab; - mtab = sysget("modules"); - if (mtab == NULL || !is_dictobject(mtab)) { - error(ctx, "bad sys.modules"); - return NULL; - } - if ((m = dictlookup(mtab, name)) == NULL) { - m = load_module(ctx, name); - } + if ((m = dictlookup(modules, name)) == NULL) + m = load_module(name); return m; } object * -reload_module(ctx, m) - context *ctx; +reload_module(m) object *m; { - char *name; - FILE *fp; - node *n; - int err; - object *d; - object *save_locals, *save_globals; if (m == NULL || !is_moduleobject(m)) { - type_error(ctx, "reload() argument must be module"); + err_setstr(TypeError, "reload() argument must be module"); return NULL; } - /* XXX Ought to check for builtin module */ - name = getmodulename(m); - fp = open_module(name, ".py"); - if (fp == NULL) { - error(ctx, "reload() cannot find module source file"); - return NULL; + /* XXX Ought to check for builtin modules -- can't reload these... */ + return get_module(m, getmodulename(m), (object **)NULL); +} + +static void +cleardict(d) + object *d; +{ + int i; + for (i = getdictsize(d); --i >= 0; ) { + char *k; + k = getdictkey(d, i); + if (k != NULL) + (void) dictremove(d, k); } - err = parseinput(fp, file_input, &n); - fclose(fp); - if (err != E_DONE) { - input_error(ctx, err); - return NULL; +} + +void +doneimport() +{ + if (modules != NULL) { + int i; + /* Explicitly erase all modules; this is the safest way + to get rid of at least *some* circular dependencies */ + for (i = getdictsize(modules); --i >= 0; ) { + char *k; + k = getdictkey(modules, i); + if (k != NULL) { + object *m; + m = dictlookup(modules, k); + if (m != NULL && is_moduleobject(m)) { + object *d; + d = getmoduledict(m); + if (d != NULL && is_dictobject(d)) { + cleardict(d); + } + } + } + } + cleardict(modules); } - d = newdictobject(); - if (d == NULL) - return NULL; - setmoduledict(m, d); - save_locals = ctx->ctx_locals; - INCREF(save_locals); - save_globals = ctx->ctx_globals; - INCREF(save_globals); - use_module(ctx, d); - exec_node(ctx, n); - DECREF(ctx->ctx_locals); - ctx->ctx_locals = save_locals; - DECREF(ctx->ctx_globals); - ctx->ctx_globals = save_globals; - if (ctx->ctx_exception) - return NULL; - INCREF(None); - return None; + DECREF(modules); } diff --git a/Python/modsupport.c b/Python/modsupport.c index 159f98e..3b195ba 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -1,36 +1,8 @@ /* Module support implementation */ -#include <stdio.h> - -#include "PROTO.h" -#include "object.h" -#include "intobject.h" -#include "stringobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "methodobject.h" -#include "moduleobject.h" +#include "allobjects.h" #include "modsupport.h" #include "import.h" -#include "errors.h" - - -/* Find a method in a module's method table. - Usually called from a module's getattr method. */ - -object * -findmethod(ml, op, name) - struct methodlist *ml; - object *op; - char *name; -{ - for (; ml->ml_name != NULL; ml++) { - if (strcmp(name, ml->ml_name) == 0) - return newmethodobject(ml->ml_name, ml->ml_meth, op); - } - err_setstr(NameError, name); - return NULL; -} object * @@ -40,21 +12,24 @@ initmodule(name, methods) { object *m, *d, *v; struct methodlist *ml; - if ((m = new_module(name)) == NULL) { + char namebuf[256]; + if ((m = add_module(name)) == NULL) { fprintf(stderr, "initializing module: %s\n", name); fatal("can't create a module"); } d = getmoduledict(m); for (ml = methods; ml->ml_name != NULL; ml++) { - v = newmethodobject(ml->ml_name, ml->ml_meth, (object *)NULL); + sprintf(namebuf, "%s.%s", name, ml->ml_name); + v = newmethodobject(strdup(namebuf), ml->ml_meth, + (object *)NULL); + /* XXX The strdup'ed memory is never freed */ if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) { fprintf(stderr, "initializing module: %s\n", name); fatal("can't initialize module"); } DECREF(v); } - DECREF(m); - return m; /* Yes, it still exists, in sys.modules... */ + return m; } diff --git a/Python/pythonmain.c b/Python/pythonmain.c index ffff0ae..f095cdd 100644 --- a/Python/pythonmain.c +++ b/Python/pythonmain.c @@ -1,24 +1,25 @@ /* Python interpreter main program */ -#include <stdio.h> -#include <ctype.h> -#include "string.h" +#include "allobjects.h" -extern char *getpythonpath(); - -#include "PROTO.h" #include "grammar.h" #include "node.h" #include "parsetok.h" #include "graminit.h" #include "errcode.h" -#include "object.h" -#include "stringobject.h" #include "sysmodule.h" +#include "compile.h" +#include "ceval.h" +#include "pythonrun.h" +#include "import.h" + +extern char *getpythonpath(); extern grammar gram; /* From graminit.c */ -int debugging; +#ifdef DEBUG +int debugging; /* Needed by parser.c */ +#endif main(argc, argv) int argc; @@ -26,15 +27,12 @@ main(argc, argv) { char *filename = NULL; FILE *fp = stdin; - int ret; - - initargs(&argc, &argv); - initintr(); /* For intrcheck() */ + initargs(&argc, &argv); if (argc > 1 && strcmp(argv[1], "-") != 0) filename = argv[1]; - + if (filename != NULL) { if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "python: can't open file '%s'\n", @@ -43,89 +41,339 @@ main(argc, argv) } } - /* XXX what is the ideal initialization order? */ - /* XXX exceptions are initialized by initrun but this - may be too late */ + initall(); + + setpythonpath(getpythonpath()); + setpythonargv(argc-1, argv+1); + + goaway(run(fp, filename == NULL ? "<stdin>" : filename)); + /*NOTREACHED*/ +} + +/* Initialize all */ + +void +initall() +{ + static int inited; + + if (inited) + return; + + initimport(); - initsys(argc-1, argv+1); + initbuiltin(); /* Also initializes builtin exceptions */ + initsys(); inittime(); initmath(); - setpythonpath(getpythonpath()); + initcalls(); /* Configuration-dependent initializations */ - initrun(); - initcalls(); + initintr(); /* For intrcheck() */ - if (!isatty(fileno(fp))) { - ret = runfile(fp, file_input, (char *)NULL, (char *)NULL); + inited = 1; +} + +/* Parse input from a file and execute it */ + +int +run(fp, filename) + FILE *fp; + char *filename; +{ + if (filename == NULL) + filename = "???"; + if (isatty(fileno(fp))) + return run_tty_loop(fp, filename); + else + return run_script(fp, filename); +} + +int +run_tty_loop(fp, filename) + FILE *fp; + char *filename; +{ + object *v; + int ret; + v = sysget("ps1"); + if (v == NULL) { + sysset("ps1", v = newstringobject(">>> ")); + XDECREF(v); + } + v = sysget("ps2"); + if (v == NULL) { + sysset("ps2", v = newstringobject("... ")); + XDECREF(v); + } + for (;;) { + ret = run_tty_1(fp, filename); +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + if (ret == E_EOF) + return 0; + /* + if (ret == E_NOMEM) + return -1; + */ + } +} + +int +run_tty_1(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v, *w; + node *n; + char *ps1, *ps2; + int err; + v = sysget("ps1"); + w = sysget("ps2"); + if (v != NULL && is_stringobject(v)) { + INCREF(v); + ps1 = getstringvalue(v); } else { - object *v, *w; - sysset("ps1", v = newstringobject(">>> ")); - sysset("ps2", w = newstringobject("... ")); - DECREF(v); - DECREF(w); - for (;;) { - char *ps1 = NULL, *ps2 = NULL; - v = sysget("ps1"); - w = sysget("ps2"); - if (v != NULL && is_stringobject(v)) { - INCREF(v); - ps1 = getstringvalue(v); - } - else - v = NULL; - if (w != NULL && is_stringobject(w)) { - INCREF(w); - ps2 = getstringvalue(w); - } - else - w = NULL; - ret = runfile(fp, single_input, ps1, ps2); - if (v != NULL) - DECREF(v); - if (w != NULL) - DECREF(w); - if (ret == E_EOF || ret == E_NOMEM) - break; - } + v = NULL; + ps1 = ""; } - goaway(ret == E_DONE || ret == E_EOF ? 0 : 1); - /*NOTREACHED*/ + if (w != NULL && is_stringobject(w)) { + INCREF(w); + ps2 = getstringvalue(w); + } + else { + w = NULL; + ps2 = ""; + } + err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n); + XDECREF(v); + XDECREF(w); + if (err == E_EOF) + return E_EOF; + if (err != E_DONE) { + err_input(err); + print_error(); + return err; + } + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_node(n, filename, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +int +run_script(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v; + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_file(fp, filename, file_input, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +void +print_error() +{ + object *exception, *v; + err_get(&exception, &v); + fprintf(stderr, "Unhandled exception: "); + printobject(exception, stderr, PRINT_RAW); + if (v != NULL && v != None) { + fprintf(stderr, ": "); + printobject(v, stderr, PRINT_RAW); + } + fprintf(stderr, "\n"); + XDECREF(exception); + XDECREF(v); + printtraceback(stderr); +} + +object * +run_string(str, start, globals, locals) + char *str; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_string(str, start, &n); + return run_err_node(err, n, "<string>", globals, locals); +} + +object * +run_file(fp, filename, start, globals, locals) + FILE *fp; + char *filename; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_file(fp, filename, start, &n); + return run_err_node(err, n, filename, globals, locals); +} + +object * +run_err_node(err, n, filename, globals, locals) + int err; + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (err != E_DONE) { + err_input(err); + return NULL; + } + return run_node(n, filename, globals, locals); +} + +object * +run_node(n, filename, globals, locals) + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (globals == NULL) { + globals = getglobals(); + if (locals == NULL) + locals = getlocals(); + } + else { + if (locals == NULL) + locals = globals; + } + return eval_node(n, filename, globals, locals); +} + +object * +eval_node(n, filename, globals, locals) + node *n; + char *filename; + object *globals; + object *locals; +{ + codeobject *co; + object *v; + co = compile(n, filename); + freetree(n); + if (co == NULL) + return NULL; + v = eval_code(co, globals, locals, (object *)NULL); + DECREF(co); + return v; +} + +/* Simplified interface to parsefile */ + +int +parse_file(fp, filename, start, n_ret) + FILE *fp; + char *filename; + int start; + node **n_ret; +{ + return parsefile(fp, filename, &gram, start, + (char *)0, (char *)0, n_ret); +} + +/* Simplified interface to parsestring */ + +int +parse_string(str, start, n_ret) + char *str; + int start; + node **n_ret; +{ + int err = parsestring(str, &gram, start, n_ret); + /* Don't confuse early end of string with early end of input */ + if (err == E_EOF) + err = E_SYNTAX; + return err; +} + +/* Print fatal error message and abort */ + +void +fatal(msg) + char *msg; +{ + fprintf(stderr, "Fatal error: %s\n", msg); + abort(); } +/* Clean up and exit */ + +void goaway(sts) int sts; { + flushline(); + + /* XXX Call doneimport() before donecalls(), since donecalls() + calls wdone(), and doneimport() may close windows */ + doneimport(); + donecalls(); + + err_clear(); + +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + #ifdef THINK_C if (sts == 0) Click_On(0); #endif - closerun(); - donecalls(); + +#ifdef TRACE_REFS + if (askyesno("Print left references?")) { +#ifdef THINK_C + Click_On(1); +#endif + printrefs(stderr); + } +#endif /* TRACE_REFS */ + exit(sts); /*NOTREACHED*/ } -/* Parse input from a file and execute it */ - -static int -runfile(fp, start, ps1, ps2) - FILE *fp; - int start; - char *ps1, *ps2; +static +finaloutput() { - node *n; - int ret; - ret = parsefile(fp, &gram, start, ps1, ps2, &n); - if (ret != E_DONE) - return ret; - return execute(n) == 0 ? E_DONE : E_ERROR; +#ifdef TRACE_REFS + if (!askyesno("Print left references?")) + return; +#ifdef THINK_C + Click_On(1); +#endif /* THINK_C */ + printrefs(stderr); +#endif /* TRACE_REFS */ } /* Ask a yes/no question */ -int +static int askyesno(prompt) char *prompt; { @@ -151,15 +399,14 @@ isatty(fd) #endif -/* WISH LIST +/* XXX WISH LIST - - improved per-module error handling; different use of errno - possible new types: - iterator (for range, keys, ...) - improve interpreter error handling, e.g., true tracebacks - - release parse trees when no longer needed (make them objects?) - - faster parser (for long modules) - save precompiled modules on file? - fork threads, locking - allow syntax extensions */ + +/* "Floccinaucinihilipilification" */ diff --git a/Python/structmember.c b/Python/structmember.c new file mode 100644 index 0000000..42c563e --- /dev/null +++ b/Python/structmember.c @@ -0,0 +1,134 @@ +/* Map C struct members to Python object attributes */ + +#include "allobjects.h" + +#include "structmember.h" + +object * +getmember(addr, mlist, name) + char *addr; + struct memberlist *mlist; + char *name; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + object *v; + addr += l->offset; + switch (l->type) { + case T_SHORT: + v = newintobject((long) *(short*)addr); + break; + case T_INT: + v = newintobject((long) *(int*)addr); + break; + case T_LONG: + v = newintobject(*(long*)addr); + break; + case T_FLOAT: + v = newfloatobject((double)*(float*)addr); + break; + case T_DOUBLE: + v = newfloatobject(*(double*)addr); + break; + case T_STRING: + if (*(char**)addr == NULL) { + INCREF(None); + v = None; + } + else + v = newstringobject(*(char**)addr); + break; + case T_OBJECT: + v = *(object **)addr; + if (v == NULL) + v = None; + INCREF(v); + break; + default: + err_setstr(SystemError, "bad memberlist type"); + v = NULL; + } + return v; + } + } + + err_setstr(NameError, name); + return NULL; +} + +int +setmember(addr, mlist, name, v) + char *addr; + struct memberlist *mlist; + char *name; + object *v; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + if (l->readonly || l->type == T_STRING) { + err_setstr(RuntimeError, "readonly attribute"); + return -1; + } + addr += l->offset; + switch (l->type) { + case T_SHORT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(short*)addr = getintvalue(v); + break; + case T_INT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(int*)addr = getintvalue(v); + break; + case T_LONG: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(long*)addr = getintvalue(v); + break; + case T_FLOAT: + if (is_intobject(v)) + *(float*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(float*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_DOUBLE: + if (is_intobject(v)) + *(double*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(double*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_OBJECT: + XDECREF(*(object **)addr); + XINCREF(v); + *(object **)addr = v; + break; + default: + err_setstr(SystemError, "bad memberlist type"); + return -1; + } + return 0; + } + } + + err_setstr(NameError, name); + return NULL; +} diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f276fb4..5cc1d96 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3,31 +3,31 @@ /* Various bits of information used by the interpreter are collected in module 'sys'. +Function member: +- exit(sts): call (C, POSIX) exit(sts) Data members: - stdin, stdout, stderr: standard file objects -- ps1, ps2: primary and secondary prompts (strings) -- path: module search path (list of strings) - modules: the table of modules (dictionary) -Function members: -- exit(sts): call exit() +- path: module search path (list of strings) +- argv: script arguments (list of strings) +- ps1, ps2: optional primary and secondary prompts (strings) */ -#include <stdio.h> +#include "allobjects.h" -#include "PROTO.h" -#include "object.h" -#include "stringobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "fileobject.h" -#include "moduleobject.h" #include "sysmodule.h" -#include "node.h" /* For context.h */ -#include "context.h" /* For import.h */ #include "import.h" -#include "methodobject.h" #include "modsupport.h" -#include "errors.h" + +/* Define delimiter used in $PYTHONPATH */ + +#ifdef THINK_C +#define DELIM ' ' +#endif + +#ifndef DELIM +#define DELIM ':' +#endif static object *sysdict; @@ -64,34 +64,6 @@ sysset(name, v) } static object * -makeargv(argc, argv) - int argc; - char **argv; -{ - int i; - object *av, *v; - if (argc < 0 || argv == NULL) - argc = 0; - av = newlistobject(argc); - if (av != NULL) { - for (i = 0; i < argc; i++) { - v = newstringobject(argv[i]); - if (v == NULL) { - DECREF(av); - av = NULL; - break; - } - setlistitem(av, i, v); - } - } - if (av == NULL) - fatal("no mem for sys.argv"); - return av; -} - -/* sys.exit method */ - -static object * sys_exit(self, args) object *self; object *args; @@ -104,88 +76,115 @@ sys_exit(self, args) /* NOTREACHED */ } +static struct methodlist sys_methods[] = { + {"exit", sys_exit}, + {NULL, NULL} /* sentinel */ +}; + static object *sysin, *sysout, *syserr; void -initsys(argc, argv) - int argc; - char **argv; +initsys() { - object *v; - object *exit; - if ((sysdict = newdictobject()) == NULL) - fatal("can't create sys dict"); + object *m = initmodule("sys", sys_methods); + sysdict = getmoduledict(m); + INCREF(sysdict); /* NB keep an extra ref to the std files to avoid closing them when the user deletes them */ + /* XXX File objects should have a "don't close" flag instead */ sysin = newopenfileobject(stdin, "<stdin>", "r"); sysout = newopenfileobject(stdout, "<stdout>", "w"); syserr = newopenfileobject(stderr, "<stderr>", "w"); - v = makeargv(argc, argv); - exit = newmethodobject("exit", sys_exit, (object *)NULL); if (err_occurred()) - fatal("can't create sys.* objects"); + fatal("can't create sys.std* file objects"); dictinsert(sysdict, "stdin", sysin); dictinsert(sysdict, "stdout", sysout); dictinsert(sysdict, "stderr", syserr); - dictinsert(sysdict, "argv", v); - dictinsert(sysdict, "exit", exit); + dictinsert(sysdict, "modules", get_modules()); if (err_occurred()) fatal("can't insert sys.* objects in sys dict"); - DECREF(exit); - DECREF(v); - /* The other symbols are added elsewhere */ - - /* Only now can we initialize the import stuff, after which - we can turn ourselves into a module */ - initimport(); - if ((v = new_module("sys")) == NULL) - fatal("can't create sys module"); - if (setmoduledict(v, sysdict) != 0) - fatal("can't assign sys dict to sys module"); - DECREF(v); } -static void -cleardict(d) - object *d; +static object * +makepathobject(path, delim) + char *path; + int delim; { - int i; - for (i = getdictsize(d); --i >= 0; ) { - char *k; - k = getdictkey(d, i); - if (k != NULL) { - (void) dictremove(d, k); + int i, n; + char *p; + object *v, *w; + + n = 1; + p = path; + while ((p = strchr(p, delim)) != NULL) { + n++; + p++; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; ; i++) { + p = strchr(path, delim); + if (p == NULL) + p = strchr(path, '\0'); /* End of string */ + w = newsizedstringobject(path, (int) (p - path)); + if (w == NULL) { + DECREF(v); + return NULL; } + setlistitem(v, i, w); + if (*p == '\0') + break; + path = p+1; } + return v; } void -closesys() +setpythonpath(path) + char *path; { - object *modules; - modules = sysget("modules"); - if (modules != NULL && is_dictobject(modules)) { + object *v; + if ((v = makepathobject(path, DELIM)) == NULL) + fatal("can't create sys.path"); + if (sysset("path", v) != 0) + fatal("can't assign sys.path"); + DECREF(v); +} + +static object * +makeargvobject(argc, argv) + int argc; + char **argv; +{ + object *av; + if (argc < 0 || argv == NULL) + argc = 0; + av = newlistobject(argc); + if (av != NULL) { int i; - /* Explicitly erase all modules; this is the safest way - to get rid of at least *some* circular dependencies */ - INCREF(modules); - for (i = getdictsize(modules); --i >= 0; ) { - char *k; - k = getdictkey(modules, i); - if (k != NULL) { - object *m; - m = dictlookup(modules, k); - if (m != NULL && is_moduleobject(m)) { - object *d; - d = getmoduledict(m); - if (d != NULL && is_dictobject(d)) { - cleardict(d); - } - } + for (i = 0; i < argc; i++) { + object *v = newstringobject(argv[i]); + if (v == NULL) { + DECREF(av); + av = NULL; + break; } + setlistitem(av, i, v); } - cleardict(modules); - DECREF(modules); } - DECREF(sysdict); + return av; +} + +void +setpythonargv(argc, argv) + int argc; + char **argv; +{ + object *av = makeargvobject(argc, argv); + if (av == NULL) + fatal("no mem for sys.argv"); + if (sysset("argv", av) != 0) + fatal("can't assign sys.argv"); + DECREF(av); } diff --git a/Python/traceback.c b/Python/traceback.c new file mode 100644 index 0000000..f32dcf6 --- /dev/null +++ b/Python/traceback.c @@ -0,0 +1,193 @@ +/* Traceback implementation */ + +#include "allobjects.h" + +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#include "structmember.h" + +typedef struct _tracebackobject { + OB_HEAD + struct _tracebackobject *tb_next; + frameobject *tb_frame; + int tb_lasti; + int tb_lineno; +} tracebackobject; + +#define OFF(x) offsetof(tracebackobject, x) + +static struct memberlist tb_memberlist[] = { + {"tb_next", T_OBJECT, OFF(tb_next)}, + {"tb_frame", T_OBJECT, OFF(tb_frame)}, + {"tb_lasti", T_INT, OFF(tb_lasti)}, + {"tb_lineno", T_INT, OFF(tb_lineno)}, + {NULL} /* Sentinel */ +}; + +static object * +tb_getattr(tb, name) + tracebackobject *tb; + char *name; +{ + return getmember((char *)tb, tb_memberlist, name); +} + +static void +tb_dealloc(tb) + tracebackobject *tb; +{ + XDECREF(tb->tb_next); + XDECREF(tb->tb_frame); + DEL(tb); +} + +static typeobject Tracebacktype = { + OB_HEAD_INIT(&Typetype) + 0, + "traceback", + sizeof(tracebackobject), + 0, + tb_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + tb_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype) + +static tracebackobject * +newtracebackobject(next, frame, lasti, lineno) + tracebackobject *next; + frameobject *frame; + int lasti, lineno; +{ + tracebackobject *tb; + if ((next != NULL && !is_tracebackobject(next)) || + frame == NULL || !is_frameobject(frame)) { + err_badcall(); + return NULL; + } + tb = NEWOBJ(tracebackobject, &Tracebacktype); + if (tb != NULL) { + XINCREF(next); + tb->tb_next = next; + XINCREF(frame); + tb->tb_frame = frame; + tb->tb_lasti = lasti; + tb->tb_lineno = lineno; + } + return tb; +} + +static tracebackobject *tb_current = NULL; + +int +tb_here(frame, lasti, lineno) + frameobject *frame; + int lasti; + int lineno; +{ + tracebackobject *tb; + tb = newtracebackobject(tb_current, frame, lasti, lineno); + if (tb == NULL) + return -1; + XDECREF(tb_current); + tb_current = tb; + return 0; +} + +object * +tb_fetch() +{ + object *v; + v = (object *)tb_current; + tb_current = NULL; + return v; +} + +int +tb_store(v) + object *v; +{ + if (v != NULL && !is_tracebackobject(v)) { + err_badcall(); + return -1; + } + XDECREF(tb_current); + XINCREF(v); + tb_current = (tracebackobject *)v; + return 0; +} + +static void +tb_displayline(fp, filename, lineno) + FILE *fp; + char *filename; + int lineno; +{ + FILE *xfp; + char buf[1000]; + int i; + if (filename[0] == '<' && filename[strlen(filename)-1] == '>') + return; + xfp = fopen(filename, "r"); + if (xfp == NULL) { + fprintf(fp, " (cannot open \"%s\")\n", filename); + return; + } + for (i = 0; i < lineno; i++) { + if (fgets(buf, sizeof buf, xfp) == NULL) + break; + } + if (i == lineno) { + char *p = buf; + while (*p == ' ' || *p == '\t') + p++; + fprintf(fp, " %s", p); + if (strchr(p, '\n') == NULL) + fprintf(fp, "\n"); + } + fclose(xfp); +} + +static void +tb_printinternal(tb, fp) + tracebackobject *tb; + FILE *fp; +{ + while (tb != NULL) { + if (intrcheck()) { + fprintf(fp, "[interrupted]\n"); + break; + } + fprintf(fp, " File \""); + printobject(tb->tb_frame->f_code->co_filename, fp, PRINT_RAW); + fprintf(fp, "\", line %d\n", tb->tb_lineno); + tb_displayline(fp, + getstringvalue(tb->tb_frame->f_code->co_filename), + tb->tb_lineno); + tb = tb->tb_next; + } +} + +int +tb_print(v, fp) + object *v; + FILE *fp; +{ + if (v == NULL) + return 0; + if (!is_tracebackobject(v)) { + err_badcall(); + return -1; + } + sysset("last_traceback", v); + tb_printinternal((tracebackobject *)v, fp); + return 0; +} |