]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
keyword arguments and faster calls
authorGuido van Rossum <guido@python.org>
Tue, 18 Jul 1995 14:51:37 +0000 (14:51 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 18 Jul 1995 14:51:37 +0000 (14:51 +0000)
Python/bltinmodule.c
Python/ceval.c
Python/compile.c
Python/import.c
Python/marshal.c
Python/pythonrun.c
Python/traceback.c

index 5103622d6c6d11d66e080174f19105b1e1e05169..0be037397ab60966d0b8287cd53cf8e6c6447ae5 100644 (file)
@@ -80,15 +80,20 @@ builtin_apply(self, args)
        object *self;
        object *args;
 {
-       object *func, *alist;
+       object *func, *alist, *kwdict = NULL;
 
-       if (!newgetargs(args, "OO:apply", &func, &alist))
+       if (!newgetargs(args, "O|OO:apply", &func, &alist, &kwdict))
                return NULL;
-       if (!is_tupleobject(alist)) {
+       if (alist != NULL && !is_tupleobject(alist)) {
                err_setstr(TypeError, "apply() 2nd argument must be tuple");
                return NULL;
        }
-       return call_object(func, alist);
+       if (kwdict != NULL && !is_dictobject(kwdict)) {
+               err_setstr(TypeError,
+                          "apply() 3rd argument must be dictionary");
+               return NULL;
+       }
+       return PyEval_CallObjectWithKeywords(func, alist, kwdict);
 }
 
 static object *
@@ -373,8 +378,7 @@ builtin_eval(self, args)
                        return NULL;
        }
        if (is_codeobject(cmd))
-               return eval_code((codeobject *) cmd, globals, locals,
-                                (object *)NULL, (object *)NULL);
+               return eval_code((codeobject *) cmd, globals, locals);
        if (!is_stringobject(cmd)) {
                err_setstr(TypeError,
                           "eval() argument 1 must be string or code object");
index a55451c3e467578afb62a8c444e32fe87f379be8..2b501c79e39e8fb84d0c6c49e79d69d8df1e7e2b 100644 (file)
@@ -24,6 +24,16 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* Execute compiled code */
 
+/* XXX TO DO:
+   XXX how to pass arguments to call_trace?
+   XXX access stuff can probably dereference NULL locals?
+   XXX need to extend apply() to be able to pass keyword args
+   XXX need to be able to call built-in functions with keyword args
+   XXX speed up searching for keywords by using a dictionary
+   XXX unknown keyword shouldn't raise KeyError?
+   XXX document it!
+   */
+
 #include "allobjects.h"
 
 #include "import.h"
@@ -58,6 +68,12 @@ extern int suppress_print; /* Declared in pythonrun.c, set in pythonmain.c */
 
 /* Forward declarations */
 
+static object *eval_code2 PROTO((codeobject *,
+                                object *, object *,
+                                object **, int,
+                                object **, int,
+                                object **, int,
+                                object *));
 #ifdef LLTRACE
 static int prtrace PROTO((object *, char *));
 #endif
@@ -78,8 +94,8 @@ static object *rshift PROTO((object *, object *));
 static object *and PROTO((object *, object *));
 static object *xor PROTO((object *, object *));
 static object *or PROTO((object *, object *));
-static object *call_builtin PROTO((object *, object *));
-static object *call_function PROTO((object *, object *));
+static object *call_builtin PROTO((object *, object *, object *));
+static object *call_function PROTO((object *, object *, object *));
 static object *apply_subscript PROTO((object *, object *));
 static object *loop_subscript PROTO((object *, object *));
 static int slice_index PROTO((object *, int, int *));
@@ -259,15 +275,38 @@ enum why_code {
 };
 
 
-/* Interpreter main loop */
+/* Backward compatible interface */
 
 object *
-eval_code(co, globals, locals, owner, arg)
+eval_code(co, globals, locals)
        codeobject *co;
        object *globals;
        object *locals;
+{
+       return eval_code2(co,
+                         globals, locals,
+                         (object **)NULL, 0,
+                         (object **)NULL, 0,
+                         (object **)NULL, 0,
+                         (object *)NULL);
+}
+
+
+/* Interpreter main loop */
+
+static object *
+eval_code2(co, globals, locals,
+          args, argcount, kws, kwcount, defs, defcount, owner)
+       codeobject *co;
+       object *globals;
+       object *locals;
+       object **args;
+       int argcount;
+       object **kws; /* length: 2*kwcount */
+       int kwcount;
+       object **defs;
+       int defcount;
        object *owner;
-       object *arg;
 {
        register unsigned char *next_instr;
        register int opcode;    /* Current opcode */
@@ -281,15 +320,14 @@ eval_code(co, globals, locals, owner, arg)
        register object *u;
        register object *t;
        register frameobject *f; /* Current frame */
-       register listobject *fastlocals = NULL;
-       object *retval;         /* Return value iff why == WHY_RETURN */
-       int needmerge = 0;      /* Set if need to merge locals back at end */
+       register object **fastlocals;
+       object *retval;         /* Return value */
        int defmode = 0;        /* Default access mode for new variables */
 #ifdef LLTRACE
        int lltrace;
 #endif
-#if defined( DEBUG ) || defined( LLTRACE )
-       /* Make it easier to find out where we are with dbx */
+#if defined(DEBUG) || defined(LLTRACE)
+       /* Make it easier to find out where we are with a debugger */
        char *filename = getstringvalue(co->co_filename);
 #endif
 
@@ -324,8 +362,14 @@ eval_code(co, globals, locals, owner, arg)
 #define POP()          BASIC_POP()
 #endif
 
-       if (globals == NULL || locals == NULL) {
-               err_setstr(SystemError, "eval_code: NULL globals or locals");
+/* Local variable macros */
+
+#define GETLOCAL(i)    (fastlocals[i])
+#define SETLOCAL(i, value)     do { XDECREF(GETLOCAL(i)); \
+                                    GETLOCAL(i) = value; } while (0)
+
+       if (globals == NULL) {
+               err_setstr(SystemError, "eval_code2: NULL globals");
                return NULL;
        }
 
@@ -343,9 +387,113 @@ eval_code(co, globals, locals, owner, arg)
                        20);                    /*nblocks*/
        if (f == NULL)
                return NULL;
-       
+
        current_frame = f;
 
+       if (co->co_nlocals > 0)
+               fastlocals = ((listobject *)f->f_fastlocals)->ob_item;
+
+       if (co->co_argcount > 0 ||
+           co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
+               int i;
+               int n = argcount;
+               object *kwdict = NULL;
+               if (co->co_flags & CO_VARKEYWORDS) {
+                       kwdict = newmappingobject();
+                       if (kwdict == NULL)
+                               goto fail;
+               }
+               if (argcount > co->co_argcount) {
+                       if (!(co->co_flags & CO_VARARGS)) {
+                               err_setstr(TypeError, "too many arguments");
+                               goto fail;
+                       }
+                       n = co->co_argcount;
+               }
+               for (i = 0; i < n; i++) {
+                       x = args[i];
+                       INCREF(x);
+                       SETLOCAL(i, x);
+               }
+               if (co->co_flags & CO_VARARGS) {
+                       u = newtupleobject(argcount - n);
+                       for (i = n; i < argcount; i++) {
+                               x = args[i];
+                               INCREF(x);
+                               SETTUPLEITEM(u, i-n, x);
+                       }
+                       SETLOCAL(co->co_argcount, u);
+               }
+               for (i = 0; i < kwcount; i++) {
+                       object *keyword = kws[2*i];
+                       object *value = kws[2*i + 1];
+                       int j;
+                       /* XXX slow -- speed up using dictionary? */
+                       for (j = 0; j < co->co_argcount; j++) {
+                               object *nm = GETTUPLEITEM(co->co_varnames, j);
+                               if (cmpobject(keyword, nm) == 0)
+                                       break;
+                       }
+                       if (j >= co->co_argcount) {
+                               if (kwdict == NULL) {
+                                       err_setval(KeyError/*XXX*/, keyword);
+                                       goto fail;
+                               }
+                               mappinginsert(kwdict, keyword, value);
+                       }
+                       else {
+                               if (GETLOCAL(j) != NULL) {
+                                       err_setstr(TypeError,
+                                               "keyword parameter redefined");
+                                       goto fail;
+                               }
+                               INCREF(value);
+                               SETLOCAL(j, value);
+                       }
+               }
+               if (argcount < co->co_argcount) {
+                       int m = co->co_argcount - defcount;
+                       for (i = argcount; i < m; i++) {
+                               if (GETLOCAL(i) == NULL) {
+                                       err_setstr(TypeError,
+                                                  "not enough arguments");
+                                       goto fail;
+                               }
+                       }
+                       if (n > m)
+                               i = n - m;
+                       else
+                               i = 0;
+                       for (; i < defcount; i++) {
+                               if (GETLOCAL(m+i) == NULL) {
+                                       object *def = defs[i];
+                                       INCREF(def);
+                                       SETLOCAL(m+i, def);
+                               }
+                       }
+               }
+               if (kwdict != NULL) {
+                       i = co->co_argcount;
+                       if (co->co_flags & CO_VARARGS)
+                               i++;
+                       SETLOCAL(i, kwdict);
+               }
+               if (0) {
+        fail:
+                       XDECREF(kwdict);
+                       goto fail2;
+               }
+       }
+       else {
+               if (argcount > 0 || kwcount > 0) {
+                       err_setstr(TypeError, "no arguments expected");
+ fail2:
+                       current_frame = f->f_back;
+                       DECREF(f);
+                       return NULL;
+               }
+       }
+
        if (sys_trace != NULL) {
                /* sys_trace, if defined, is a function that will
                   be called  on *every* entry to a code block.
@@ -359,7 +507,8 @@ eval_code(co, globals, locals, owner, arg)
                   depends on the situation.  The global trace function
                   (sys.trace) is also called whenever an exception
                   is detected. */
-               if (call_trace(&sys_trace, &f->f_trace, f, "call", arg)) {
+               if (call_trace(&sys_trace, &f->f_trace, f, "call",
+                              None/*XXX how to compute arguments now?*/)) {
                        /* Trace function raised an error */
                        current_frame = f->f_back;
                        DECREF(f);
@@ -370,7 +519,8 @@ eval_code(co, globals, locals, owner, arg)
        if (sys_profile != NULL) {
                /* Similar for sys_profile, except it needn't return
                   itself and isn't called for "line" events */
-               if (call_trace(&sys_profile, (object**)0, f, "call", arg)) {
+               if (call_trace(&sys_profile, (object**)0, f, "call",
+                              None/*XXX*/)) {
                        current_frame = f->f_back;
                        DECREF(f);
                        return NULL;
@@ -380,11 +530,6 @@ eval_code(co, globals, locals, owner, arg)
        next_instr = GETUSTRINGVALUE(f->f_code->co_code);
        stack_pointer = f->f_valuestack;
        
-       if (arg != NULL) {
-               INCREF(arg);
-               PUSH(arg);
-       }
-       
        why = WHY_NOT;
        err = 0;
        x = None;       /* Not a reference, just anything non-NULL */
@@ -522,14 +667,6 @@ eval_code(co, globals, locals, owner, arg)
                        DECREF(v);
                        PUSH(x);
                        break;
-               
-               case UNARY_CALL:
-                       v = POP();
-                       f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
-                       x = call_object(v, (object *)NULL);
-                       DECREF(v);
-                       PUSH(x);
-                       break;
                        
                case UNARY_INVERT:
                        v = POP();
@@ -592,16 +729,6 @@ eval_code(co, globals, locals, owner, arg)
                        PUSH(x);
                        break;
                
-               case BINARY_CALL:
-                       w = POP();
-                       v = POP();
-                       f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
-                       x = call_object(v, w);
-                       DECREF(v);
-                       DECREF(w);
-                       PUSH(x);
-                       break;
-               
                case BINARY_LSHIFT:
                        w = POP();
                        v = POP();
@@ -776,9 +903,6 @@ eval_code(co, globals, locals, owner, arg)
                        why = WHY_BREAK;
                        break;
 
-               case RAISE_EXCEPTION:
-                       oparg = 2;
-                       /* Fallthrough */
                case RAISE_VARARGS:
                        u = v = w = NULL;
                        switch (oparg) {
@@ -788,10 +912,7 @@ eval_code(co, globals, locals, owner, arg)
                                        DECREF(u);
                                        u = NULL;
                                }
-                               else if (strcmp(u->ob_type->tp_name,
-                                               "traceback") != 0) {
-                                       /* XXX traceback.h needs to define
-                                          is_traceback() */
+                               else if (!PyTraceback_Check(u)) {
                                        err_setstr(TypeError,
                                    "raise 3rd arg must be traceback or None");
                                        goto raise_error;
@@ -814,8 +935,8 @@ eval_code(co, globals, locals, owner, arg)
                        }
                        /* A tuple is equivalent to its first element here */
                        while (is_tupleobject(w) && gettuplesize(w) > 0) {
-                               object *t = w;
-                               w = GETTUPLEITEM(t, 0);
+                               t = w;
+                               w = GETTUPLEITEM(w, 0);
                                INCREF(w);
                                DECREF(t);
                        }
@@ -861,9 +982,12 @@ eval_code(co, globals, locals, owner, arg)
                        break;
                
                case LOAD_LOCALS:
-                       v = f->f_locals;
-                       INCREF(v);
-                       PUSH(v);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       INCREF(x);
+                       PUSH(x);
                        break;
                
                case RETURN_VALUE:
@@ -871,12 +995,6 @@ eval_code(co, globals, locals, owner, arg)
                        why = WHY_RETURN;
                        break;
 
-               case LOAD_GLOBALS:
-                       v = f->f_locals;
-                       INCREF(v);
-                       PUSH(v);
-                       break;
-
                case EXEC_STMT:
                        w = POP();
                        v = POP();
@@ -887,21 +1005,6 @@ eval_code(co, globals, locals, owner, arg)
                        DECREF(w);
                        break;
                
-               case BUILD_FUNCTION:
-                       v = POP();
-                       x = newfuncobject(v, f->f_globals);
-                       DECREF(v);
-                       PUSH(x);
-                       break;
-
-               case SET_FUNC_ARGS:
-                       v = POP(); /* The function */
-                       w = POP(); /* The argument list */
-                       err = setfuncargstuff(v, oparg, w);
-                       PUSH(v);
-                       DECREF(w);
-                       break;
-               
                case POP_BLOCK:
                        {
                                block *b = pop_block(f);
@@ -947,14 +1050,18 @@ eval_code(co, globals, locals, owner, arg)
                case STORE_NAME:
                        w = GETNAMEV(oparg);
                        v = POP();
-                       u = dict2lookup(f->f_locals, w);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       u = dict2lookup(x, w);
                        if (u == NULL) {
                                if (defmode != 0) {
                                        if (v != None)
                                                u = (object *)v->ob_type;
                                        else
                                                u = NULL;
-                                       x = newaccessobject(v, f->f_locals,
+                                       x = newaccessobject(v, x,
                                                            (typeobject *)u,
                                                            defmode);
                                        DECREF(v);
@@ -964,23 +1071,27 @@ eval_code(co, globals, locals, owner, arg)
                                }
                        }
                        else if (is_accessobject(u)) {
-                               err = setaccessvalue(u, f->f_locals, v);
+                               err = setaccessvalue(u, x, v);
                                DECREF(v);
                                break;
                        }
-                       err = dict2insert(f->f_locals, w, v);
+                       err = dict2insert(x, w, v);
                        DECREF(v);
                        break;
                
                case DELETE_NAME:
                        w = GETNAMEV(oparg);
-                       u = dict2lookup(f->f_locals, w);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       u = dict2lookup(x, w);
                        if (u != NULL && is_accessobject(u)) {
-                               err = setaccessvalue(u, f->f_locals,
+                               err = setaccessvalue(u, x,
                                                     (object *)NULL);
                                break;
                        }
-                       if ((err = dict2remove(f->f_locals, w)) != 0)
+                       if ((err = dict2remove(x, w)) != 0)
                                err_setval(NameError, w);
                        break;
 
@@ -988,74 +1099,6 @@ eval_code(co, globals, locals, owner, arg)
                default: switch (opcode) {
 #endif
                
-               case UNPACK_VARARG:
-                       if (EMPTY()) {
-                               err_setstr(TypeError,
-                                          "no argument list");
-                               why = WHY_EXCEPTION;
-                               break;
-                       }
-                       v = POP();
-                       if (!is_tupleobject(v)) {
-                               err_setstr(TypeError,
-                                          "bad argument list");
-                               why = WHY_EXCEPTION;
-                       }
-                       else if (gettuplesize(v) < oparg) {
-                               err_setstr(TypeError,
-                                       "not enough arguments");
-                               why = WHY_EXCEPTION;
-                       }
-                       else if (oparg == 0) {
-                               PUSH(v);
-                               break;
-                       }
-                       else {
-                               x = gettupleslice(v, oparg, gettuplesize(v));
-                               if (x != NULL) {
-                                       PUSH(x);
-                                       if (!CHECK_STACK(oparg)) {
-                                               x = NULL;
-                                               break;
-                                       }
-                                       for (; --oparg >= 0; ) {
-                                               w = GETTUPLEITEM(v, oparg);
-                                               INCREF(w);
-                                               PUSH(w);
-                                       }
-                               }
-                       }
-                       DECREF(v);
-                       break;
-               
-               case UNPACK_ARG:
-                       {
-                               int n;
-                               if (EMPTY()) {
-                                       err_setstr(TypeError,
-                                                  "no argument list");
-                                       why = WHY_EXCEPTION;
-                                       break;
-                               }
-                               v = POP();
-                               if (!is_tupleobject(v)) {
-                                       err_setstr(TypeError,
-                                                  "bad argument list");
-                                       why = WHY_EXCEPTION;
-                                       DECREF(v);
-                                       break;
-                               }
-                               n = gettuplesize(v);
-                               if (n != oparg) {
-                                       err_setstr(TypeError,
-                                               "arg count mismatch");
-                                       why = WHY_EXCEPTION;
-                                       DECREF(v);
-                                       break;
-                               }
-                               PUSH(v);
-                       }
-                       /* Fall through */
                case UNPACK_TUPLE:
                        v = POP();
                        if (!is_tupleobject(v)) {
@@ -1125,11 +1168,14 @@ eval_code(co, globals, locals, owner, arg)
                case STORE_GLOBAL:
                        w = GETNAMEV(oparg);
                        v = POP();
-                       u = dict2lookup(f->f_locals, w);
-                       if (u != NULL && is_accessobject(u)) {
-                               err = setaccessvalue(u, f->f_globals, v);
-                               DECREF(v);
-                               break;
+                       if (f->f_locals != NULL) {
+                               u = dict2lookup(f->f_locals, w);
+                               if (u != NULL && is_accessobject(u)) {
+                                       err = setaccessvalue(u, f->f_globals,
+                                                            v);
+                                       DECREF(v);
+                                       break;
+                               }
                        }
                        err = dict2insert(f->f_globals, w, v);
                        DECREF(v);
@@ -1137,11 +1183,13 @@ eval_code(co, globals, locals, owner, arg)
                
                case DELETE_GLOBAL:
                        w = GETNAMEV(oparg);
-                       u = dict2lookup(f->f_locals, w);
-                       if (u != NULL && is_accessobject(u)) {
-                               err = setaccessvalue(u, f->f_globals,
-                                                    (object *)NULL);
-                               break;
+                       if (f->f_locals != NULL) {
+                               u = dict2lookup(f->f_locals, w);
+                               if (u != NULL && is_accessobject(u)) {
+                                       err = setaccessvalue(u, f->f_globals,
+                                                            (object *)NULL);
+                                       break;
+                               }
                        }
                        if ((err = dict2remove(f->f_globals, w)) != 0)
                                err_setval(NameError, w);
@@ -1155,7 +1203,11 @@ eval_code(co, globals, locals, owner, arg)
                
                case LOAD_NAME:
                        w = GETNAMEV(oparg);
-                       x = dict2lookup(f->f_locals, w);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       x = dict2lookup(x, w);
                        if (x == NULL) {
                                err_clear();
                                x = dict2lookup(f->f_globals, w);
@@ -1198,10 +1250,15 @@ eval_code(co, globals, locals, owner, arg)
                                INCREF(x);
                        PUSH(x);
                        break;
-               
+
+#if 0
                case LOAD_LOCAL:
                        w = GETNAMEV(oparg);
-                       x = dict2lookup(f->f_locals, w);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       x = dict2lookup(x, w);
                        if (x == NULL) {
                                err_setval(NameError, w);
                                break;
@@ -1215,29 +1272,14 @@ eval_code(co, globals, locals, owner, arg)
                                INCREF(x);
                        PUSH(x);
                        break;
-
-               case RESERVE_FAST:
-                       x = GETCONST(oparg);
-                       if (x == None)
-                               break;
-                       if (x == NULL || !is_tupleobject(x)) {
-                               err_setstr(SystemError, "bad RESERVE_FAST");
-                               x = NULL;
-                               break;
-                       }
-                       XDECREF(f->f_fastlocals);
-                       XDECREF(f->f_localmap);
-                       INCREF(x);
-                       f->f_localmap = x;
-                       f->f_fastlocals = x = newlistobject(gettuplesize(x));
-                       fastlocals = (listobject *) x;
-                       break;
+#endif
 
                case LOAD_FAST:
-                       x = GETLISTITEM(fastlocals, oparg);
+                       x = GETLOCAL(oparg);
                        if (x == NULL) {
                                err_setval(NameError,
-                                          gettupleitem(f->f_localmap, oparg));
+                                          gettupleitem(co->co_varnames,
+                                                       oparg));
                                break;
                        }
                        if (is_accessobject(x)) {
@@ -1252,30 +1294,29 @@ eval_code(co, globals, locals, owner, arg)
 
                case STORE_FAST:
                        v = POP();
-                       w = GETLISTITEM(fastlocals, oparg);
+                       w = GETLOCAL(oparg);
                        if (w != NULL && is_accessobject(w)) {
                                err = setaccessvalue(w, f->f_locals, v);
                                DECREF(v);
                                break;
                        }
-                       GETLISTITEM(fastlocals, oparg) = v;
-                       XDECREF(w);
+                       SETLOCAL(oparg, v);
                        break;
 
                case DELETE_FAST:
-                       x = GETLISTITEM(fastlocals, oparg);
+                       x = GETLOCAL(oparg);
                        if (x == NULL) {
                                err_setval(NameError,
-                                          gettupleitem(f->f_localmap, oparg));
+                                          gettupleitem(co->co_varnames,
+                                                       oparg));
                                break;
                        }
-                       if (x != NULL && is_accessobject(x)) {
+                       if (is_accessobject(x)) {
                                err = setaccessvalue(x, f->f_locals,
                                                     (object *)NULL);
                                break;
                        }
-                       GETLISTITEM(fastlocals, oparg) = NULL;
-                       DECREF(x);
+                       SETLOCAL(oparg, NULL);
                        break;
                
                case BUILD_TUPLE:
@@ -1343,7 +1384,11 @@ eval_code(co, globals, locals, owner, arg)
                                        break;
                                }
                        }
-                       w = mkvalue("(OOOO)", w, f->f_globals, f->f_locals, u);
+                       w = mkvalue("(OOOO)",
+                                   w,
+                                   f->f_globals,
+                                   f->f_locals == NULL ? None : f->f_locals,
+                                   u);
                        DECREF(u);
                        if (w == NULL) {
                                x = NULL;
@@ -1358,7 +1403,11 @@ eval_code(co, globals, locals, owner, arg)
                        w = GETNAMEV(oparg);
                        v = TOP();
                        fast_2_locals(f);
-                       err = import_from(f->f_locals, v, w);
+                       if ((x = f->f_locals) == NULL) {
+                               err_setstr(SystemError, "no locals");
+                               break;
+                       }
+                       err = import_from(x, v, w);
                        locals_2_fast(f, 0);
                        break;
 
@@ -1447,12 +1496,6 @@ eval_code(co, globals, locals, owner, arg)
 
                case CALL_FUNCTION:
                {
-                       /* XXX To do:
-                          - fill in default arguments here
-                          - proper handling of keyword parameters
-                          - change eval_code interface to take an
-                            array of arguments instead of a tuple
-                          */
                        int na = oparg & 0xff;
                        int nk = (oparg>>8) & 0xff;
                        int n = na + 2*nk;
@@ -1460,75 +1503,120 @@ eval_code(co, globals, locals, owner, arg)
                        object *func = *pfunc;
                        object *self = NULL;
                        object *class = NULL;
-                       object *args;
                        f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
-                       INCREF(func);
                        if (is_instancemethodobject(func)) {
                                self = instancemethodgetself(func);
+                               class = instancemethodgetclass(func);
+                               func = instancemethodgetfunc(func);
+                               INCREF(func);
                                if (self != NULL) {
-                                       class = instancemethodgetclass(func);
-                                       DECREF(func);
-                                       func = instancemethodgetfunc(func);
-                                       INCREF(func);
                                        INCREF(self);
                                        DECREF(*pfunc);
                                        *pfunc = self;
                                        na++;
                                        n++;
                                }
+                               else {
+                                       /* Unbound methods must be
+                                          called with an instance of
+                                          the class (or a derived
+                                          class) as first argument */
+                                       if (na > 0 &&
+                                           (self = stack_pointer[-n])
+                                               != NULL &&
+                                           is_instanceobject(self) &&
+                                           issubclass(
+                                                   (object *)
+                                                   (((instanceobject *)self)
+                                                    ->in_class),
+                                                   class))
+                                               /* Handy-dandy */ ;
+                                       else {
+                                               err_setstr(TypeError,
+          "unbound method must be called with class instance 1st argument");
+                                               return NULL;
+                                       }
+                               }
+                       }
+                       else
+                               INCREF(func);
+                       if (is_funcobject(func)) {
+                               object *co = getfunccode(func);
+                               object *globals = getfuncglobals(func);
+                               object *argdefs = PyFunction_GetDefaults(func);
+                               object **d;
+                               int nd;
+                               if (argdefs != NULL) {
+                                       d = &GETTUPLEITEM(argdefs, 0);
+                                       nd = ((tupleobject *)argdefs)->ob_size;
+                               }
+                               else {
+                                       d = NULL;
+                                       nd = 0;
+                               }
+                               x = eval_code2(
+                                       (codeobject *)co,
+                                       globals, (object *)NULL,
+                                       stack_pointer-n, na,
+                                       stack_pointer-2*nk, nk,
+                                       d, nd,
+                                       class);
                        }
-                       args = newtupleobject(n);
-                       if (args == NULL)
-                               x = NULL;
                        else {
-                               while (--n >= 0) {
-                                       w = POP();
-                                       SETTUPLEITEM(args, n, w);
+                               object *args = newtupleobject(na);
+                               object *kwdict = NULL;
+                               if (args == NULL)
+                                       x = NULL;
+                               else if (nk > 0) {
+                                       err_setstr(SystemError,
+                       "calling built-in with keywords not yet implemented");
+                                       x = NULL;
                                }
-                               if (self == NULL)
-                                        POP();
-                               if (is_funcobject(func)) {
-                                       int argcount;
-                                       object *argdefs =
-                                           getfuncargstuff(func, &argcount);
-                                       if (argdefs == NULL) { /* Fast path */
-                                               object *co, *loc, *glob;
-                                               co = getfunccode(func);
-                                               loc = newdictobject();
-                                               if (loc == NULL) {
-                                                       x = NULL;
-                                                       DECREF(func);
-                                                       break;
-                                               }
-                                               glob = getfuncglobals(func);
-                                               INCREF(glob);
-                                               x = eval_code(
-                                                       (codeobject *)co,
-                                                       glob,
-                                                       loc,
-                                                       class,
-                                                       args);
-                                               DECREF(glob);
-                                               DECREF(loc);
-                                               DECREF(args);
-                                               DECREF(func);
-                                               PUSH(x);
-                                               break;
+                               else {
+                                       while (--na >= 0) {
+                                               w = POP();
+                                               SETTUPLEITEM(args, na, w);
                                        }
+                                       x = call_object(func, args);
+                                       DECREF(args);
                                }
-                               x = call_object(func, args);
-                               DECREF(args);
-                               PUSH(x);
                        }
                        DECREF(func);
+                       while (stack_pointer > pfunc) {
+                               w = POP();
+                               DECREF(w);
+                       }
+                       PUSH(x);
                        break;
                }
                
+               case MAKE_FUNCTION:
+                       v = POP(); /* code object */
+                       x = newfuncobject(v, f->f_globals);
+                       DECREF(v);
+                       /* XXX Maybe this should be a separate opcode? */
+                       if (x != NULL && oparg > 0) {
+                               v = newtupleobject(oparg);
+                               if (v == NULL) {
+                                       DECREF(x);
+                                       x = NULL;
+                                       break;
+                               }
+                               while (--oparg >= 0) {
+                                       w = POP();
+                                       SETTUPLEITEM(v, oparg, w);
+                               }
+                               err = PyFunction_SetDefaults(x, v);
+                               DECREF(v);
+                       }
+                       PUSH(x);
+                       break;
+               
                default:
                        fprintf(stderr,
                                "XXX lineno: %d, opcode: %d\n",
                                f->f_lineno, opcode);
-                       err_setstr(SystemError, "eval_code: unknown opcode");
+                       err_setstr(SystemError, "unknown opcode");
                        why = WHY_EXCEPTION;
                        break;
 
@@ -1543,8 +1631,15 @@ eval_code(co, globals, locals, owner, arg)
                /* Quickly continue if no error occurred */
                
                if (why == WHY_NOT) {
-                       if (err == 0 && x != NULL)
-                               continue; /* Normal, fast path */
+                       if (err == 0 && x != NULL) {
+#ifdef CHECKEXC
+                               if (err_occurred())
+                                       fprintf(stderr,
+                                               "XXX undetected error\n");
+                               else
+#endif
+                                       continue; /* Normal, fast path */
+                       }
                        why = WHY_EXCEPTION;
                        x = None;
                        err = 0;
@@ -1561,8 +1656,12 @@ eval_code(co, globals, locals, owner, arg)
                        }
                }
                else {
-                       if (err_occurred())
-                               fatal("XXX undetected error");
+                       if (err_occurred()) {
+                               fprintf(stderr,
+                                       "XXX undetected error (why=%d)\n",
+                                       why);
+                               why = WHY_EXCEPTION;
+                       }
                }
 #endif
 
@@ -1672,12 +1771,9 @@ eval_code(co, globals, locals, owner, arg)
        }
        
        /* Restore previous frame and release the current one */
-       
+
        current_frame = f->f_back;
        DECREF(f);
-
-       if (needmerge)
-               locals_2_fast(current_frame, 1);
        
        return retval;
 }
@@ -2134,38 +2230,66 @@ not(v)
 }
 
 
-/* External interface to call any callable object. The arg may be NULL. */
+/* External interface to call any callable object.
+   The arg must be a tuple or NULL. */
 
 object *
 call_object(func, arg)
        object *func;
        object *arg;
 {
-        binaryfunc call;
+       return PyEval_CallObjectWithKeywords(func, arg, (object *)NULL);
+}
+
+object *
+PyEval_CallObjectWithKeywords(func, arg, kw)
+       object *func;
+       object *arg;
+       object *kw;
+{
+        ternaryfunc call;
         object *result;
-        
+
+       if (arg == NULL)
+               arg = newtupleobject(0);
+       else if (!is_tupleobject(arg)) {
+               err_setstr(TypeError, "argument list must be a tuple");
+               return NULL;
+       }
+       else
+               INCREF(arg);
+
         if (call = func->ob_type->tp_call)
-                result = (*call)(func, arg);
+                result = (*call)(func, arg, kw);
         else if (is_instancemethodobject(func) || is_funcobject(func))
-               result = call_function(func, arg);
+               result = call_function(func, arg, kw);
        else
-               result = call_builtin(func, arg);
+               result = call_builtin(func, arg, kw);
 
+       DECREF(arg);
+       
         if (result == NULL && !err_occurred())
-               fatal("null result without error in call_object");
+               err_setstr(SystemError,
+                          "NULL result without error in call_object");
         
         return result;
 }
 
 static object *
-call_builtin(func, arg)
+call_builtin(func, arg, kw)
        object *func;
        object *arg;
+       object *kw;
 {
+       if (kw != NULL) {
+               err_setstr(SystemError,
+                       "calling built-in with keywords not yet implemented");
+               return NULL;
+       }
        if (is_methodobject(func)) {
                method meth = getmethod(func);
                object *self = getself(func);
-               if (!getvarargs(func) && arg != NULL && is_tupleobject(arg)) {
+               if (!getvarargs(func)) {
                        int size = gettuplesize(arg);
                        if (size == 1)
                                arg = GETTUPLEITEM(arg, 0);
@@ -2181,7 +2305,8 @@ call_builtin(func, arg)
                object *res, *call = getattr(func,"__call__");
                if (call == NULL) {
                        err_clear();
-                       err_setstr(AttributeError, "no __call__ method defined");
+                       err_setstr(AttributeError,
+                                  "no __call__ method defined");
                        return NULL;
                }
                res = call_object(call, arg);
@@ -2193,16 +2318,21 @@ call_builtin(func, arg)
 }
 
 static object *
-call_function(func, arg)
+call_function(func, arg, kw)
        object *func;
        object *arg;
+       object *kw;
 {
-       object *newarg = NULL;
-       object *newlocals, *newglobals;
-       object *class = NULL;
-       object *co, *v;
+       object *class = NULL; /* == owner */
        object *argdefs;
-       int     argcount;
+       object **d, **k;
+       int nk, nd;
+       object *result;
+       
+       if (kw != NULL && !is_dictobject(kw)) {
+               err_badcall();
+               return NULL;
+       }
        
        if (is_instancemethodobject(func)) {
                object *self = instancemethodgetself(func);
@@ -2211,48 +2341,36 @@ call_function(func, arg)
                if (self == NULL) {
                        /* Unbound methods must be called with an instance of
                           the class (or a derived class) as first argument */
-                       if (arg != NULL && is_tupleobject(arg) &&
-                           gettuplesize(arg) >= 1) {
+                       if (gettuplesize(arg) >= 1) {
                                self = GETTUPLEITEM(arg, 0);
                                if (self != NULL &&
                                    is_instanceobject(self) &&
                                    issubclass((object *)
                                      (((instanceobject *)self)->in_class),
                                               class))
-                                       /* self = self */ ;
+                                       /* Handy-dandy */ ;
                                else
                                        self = NULL;
                        }
                        if (self == NULL) {
                                err_setstr(TypeError,
-          "unbound method must be called with class instance argument");
+          "unbound method must be called with class instance 1st argument");
                                return NULL;
                        }
+                       INCREF(arg);
                }
                else {
-                       if (arg == NULL)
-                               argcount = 0;
-                       else if (is_tupleobject(arg))
-                               argcount = gettuplesize(arg);
-                       else
-                               argcount = 1;
-                       newarg = newtupleobject(argcount + 1);
+                       int argcount = gettuplesize(arg);
+                       object *newarg = newtupleobject(argcount + 1);
+                       int i;
                        if (newarg == NULL)
                                return NULL;
                        INCREF(self);
                        SETTUPLEITEM(newarg, 0, self);
-                       if (arg != NULL && !is_tupleobject(arg)) {
-                               INCREF(arg);
-                               SETTUPLEITEM(newarg, 1, arg);
-                       }
-                       else {
-                               int i;
-                               object *v;
-                               for (i = 0; i < argcount; i++) {
-                                       v = GETTUPLEITEM(arg, i);
-                                       XINCREF(v);
-                                       SETTUPLEITEM(newarg, i+1, v);
-                               }
+                       for (i = 0; i < argcount; i++) {
+                               object *v = GETTUPLEITEM(arg, i);
+                               XINCREF(v);
+                               SETTUPLEITEM(newarg, i+1, v);
                        }
                        arg = newarg;
                }
@@ -2262,65 +2380,51 @@ call_function(func, arg)
                        err_setstr(TypeError, "call of non-function");
                        return NULL;
                }
-       }
-
-       argdefs = getfuncargstuff(func, &argcount);
-       if (argdefs != NULL && arg != NULL && is_tupleobject(arg)) {
-               int actualcount, j;
-               /* Process default arguments */
-               if (argcount & 0x4000)
-                       argcount ^= 0x4000;
-               actualcount = gettuplesize(arg);
-               j = gettuplesize(argdefs) - (argcount - actualcount);
-               if (actualcount < argcount && j >= 0) {
-                       int i;
-                       object *v;
-                       if (newarg == NULL)
-                               INCREF(arg);
-                       newarg = newtupleobject(argcount);
-                       if (newarg == NULL) {
-                               DECREF(arg);
-                               return NULL;
-                       }
-                       for (i = 0; i < actualcount; i++) {
-                               v = GETTUPLEITEM(arg, i);
-                               XINCREF(v);
-                               SETTUPLEITEM(newarg, i, v);
-                       }
-                       for (; i < argcount; i++, j++) {
-                               v = GETTUPLEITEM(argdefs, j);
-                               XINCREF(v);
-                               SETTUPLEITEM(newarg, i, v);
-                       }
-                       DECREF(arg);
-                       arg = newarg;
-               }
+               INCREF(arg);
        }
        
-       co = getfunccode(func);
-       if (co == NULL) {
-               XDECREF(newarg);
-               return NULL;
+       argdefs = PyFunction_GetDefaults(func);
+       if (argdefs != NULL && is_tupleobject(argdefs)) {
+               d = &GETTUPLEITEM((tupleobject *)argdefs, 0);
+               nd = gettuplesize(argdefs);
        }
-       if (!is_codeobject(co))
-               fatal("XXX Bad code");
-       newlocals = newdictobject();
-       if (newlocals == NULL) {
-               XDECREF(newarg);
-               return NULL;
+       else {
+               d = NULL;
+               nd = 0;
        }
        
-       newglobals = getfuncglobals(func);
-       INCREF(newglobals);
-       
-       v = eval_code((codeobject *)co, newglobals, newlocals, class, arg);
+       if (kw != NULL) {
+               int pos, i;
+               nk = getmappingsize(kw);
+               k = NEW(object *, 2*nk);
+               if (k == NULL) {
+                       err_nomem();
+                       DECREF(arg);
+                       return NULL;
+               }
+               pos = i = 0;
+               while (mappinggetnext(kw, &pos, &k[i], &k[i+1]))
+                       i += 2;
+               nk = i/2;
+               /* XXX This is broken if the caller deletes dict items! */
+       }
+       else {
+               k = NULL;
+               nk = 0;
+       }
        
-       DECREF(newlocals);
-       DECREF(newglobals);
+       result = eval_code2(
+               (codeobject *)getfunccode(func),
+               getfuncglobals(func), (object *)NULL,
+               &GETTUPLEITEM(arg, 0), gettuplesize(arg),
+               k, nk,
+               d, nd,
+               class);
        
-       XDECREF(newarg);
+       DECREF(arg);
+       XDEL(k);
        
-       return v;
+       return result;
 }
 
 static object *
@@ -2690,21 +2794,9 @@ access_statement(name, vmode, f)
        int mode = getintvalue(vmode);
        object *value, *ac;
        typeobject *type;
-       int fastind, ret;
-       fastind = -1;
-       if (f->f_localmap == NULL)
-               value = dict2lookup(f->f_locals, name);
-       else {
-               object *map = f->f_localmap;
-               value = NULL;
-               for (fastind = gettuplesize(map); --fastind >= 0; ) {
-                       object *fname = GETTUPLEITEM(map, fastind);
-                       if (cmpobject(name, fname) == 0) {
-                               value = getlistitem(f->f_fastlocals, fastind);
-                               break;
-                       }
-               }
-       }
+       int ret;
+       fast_2_locals(f);
+       value = dict2lookup(f->f_locals, name);
        if (value && is_accessobject(value)) {
                err_setstr(AccessError, "can't override access");
                return -1;
@@ -2717,12 +2809,9 @@ access_statement(name, vmode, f)
        ac = newaccessobject(value, f->f_locals, type, mode);
        if (ac == NULL)
                return -1;
-       if (fastind >= 0)
-               ret = setlistitem(f->f_fastlocals, fastind, ac);
-       else {
-               ret = dict2insert(f->f_locals, name, ac);
-               DECREF(ac);
-       }
+       ret = mappinginsert(f->f_locals, name, ac);
+       DECREF(ac);
+       locals_2_fast(f, 0);
        return ret;
 }
 
@@ -2735,6 +2824,7 @@ exec_statement(prog, globals, locals)
        char *s;
        int n;
        object *v;
+       int plain = 0;
 
        if (is_tupleobject(prog) && globals == None && locals == None &&
            ((n = gettuplesize(prog)) == 2 || n == 3)) {
@@ -2746,8 +2836,10 @@ exec_statement(prog, globals, locals)
        }
        if (globals == None) {
                globals = getglobals();
-               if (locals == None)
+               if (locals == None) {
                        locals = getlocals();
+                       plain = 1;
+               }
        }
        else if (locals == None)
                locals = globals;
@@ -2766,8 +2858,7 @@ exec_statement(prog, globals, locals)
        if (dictlookup(globals, "__builtins__") == NULL)
                dictinsert(globals, "__builtins__", current_frame->f_builtins);
        if (is_codeobject(prog)) {
-               if (eval_code((codeobject *) prog, globals, locals,
-                                (object *)NULL, (object *)NULL) == NULL)
+               if (eval_code((codeobject *) prog, globals, locals) == NULL)
                        return -1;
                return 0;
        }
@@ -2783,13 +2874,16 @@ exec_statement(prog, globals, locals)
                err_setstr(ValueError, "embedded '\\0' in exec string");
                return -1;
        }
-       if ((v = run_string(s, file_input, globals, locals)) == NULL)
+       v = run_string(s, file_input, globals, locals);
+       if (v == NULL)
                return -1;
        DECREF(v);
+       if (plain)
+               locals_2_fast(current_frame, 0);
        return 0;
 }
 
-/* Hack for Ken Manheimer */
+/* Hack for newimp.py */
 static object *
 find_from_args(f, nexti)
        frameobject *f;
@@ -2812,7 +2906,8 @@ find_from_args(f, nexti)
                return NULL;
        
        do {
-               oparg = (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]);
+               oparg = (next_instr[1]<<8) + next_instr[0];
+               next_instr += 2;
                name = Getnamev(f, oparg);
                if (addlistitem(list, name) < 0) {
                        DECREF(list);
index df81f8f86fb511c99a92c1a04ac03e1b3f9e9f4e..9f15254aab0b2990413edf9396caaed961fbe9a1 100644 (file)
@@ -25,8 +25,14 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* Compile an expression node to intermediate code */
 
 /* XXX TO DO:
-   XXX Compute maximum needed stack sizes while compiling
+   XXX Compute maximum needed stack sizes while compiling;
+   XXX   then frame object can be one malloc and no stack checks are needed
+   XXX add __doc__ attribute == co_doc to code object attributes
+   XXX don't execute doc string
    XXX Generate simple jump for break/return outside 'try...finally'
+   XXX get rid of SET_LINENO instructions, use JAR's table trick
+   XXX   (need an option to put them back in, for debugger!)
+   XXX other JAR tricks?
 */
 
 #include "allobjects.h"
@@ -44,9 +50,13 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define OFF(x) offsetof(codeobject, x)
 
 static struct memberlist code_memberlist[] = {
+       {"co_argcount", T_INT,          OFF(co_argcount),       READONLY},
+       {"co_nlocals",  T_INT,          OFF(co_nlocals),        READONLY},
+       {"co_flags",    T_INT,          OFF(co_flags),          READONLY},
        {"co_code",     T_OBJECT,       OFF(co_code),           READONLY},
        {"co_consts",   T_OBJECT,       OFF(co_consts),         READONLY},
        {"co_names",    T_OBJECT,       OFF(co_names),          READONLY},
+       {"co_varnames", T_OBJECT,       OFF(co_varnames),       READONLY},
        {"co_filename", T_OBJECT,       OFF(co_filename),       READONLY},
        {"co_name",     T_OBJECT,       OFF(co_name),           READONLY},
        {NULL}  /* Sentinel */
@@ -69,6 +79,7 @@ code_dealloc(co)
        XDECREF(co->co_names);
        XDECREF(co->co_filename);
        XDECREF(co->co_name);
+       XDECREF(co->co_varnames);
        DEL(co);
 }
 
@@ -97,11 +108,19 @@ code_compare(co, cp)
        codeobject *co, *cp;
 {
        int cmp;
+       cmp = cp->co_argcount - cp->co_argcount;
+       if (cmp) return cmp;
+       cmp = cp->co_nlocals - cp->co_nlocals;
+       if (cmp) return cmp;
+       cmp = cp->co_flags - cp->co_flags;
+       if (cmp) return cmp;
        cmp = cmpobject((object *)co->co_code, (object *)cp->co_code);
        if (cmp) return cmp;
        cmp = cmpobject(co->co_consts, cp->co_consts);
        if (cmp) return cmp;
        cmp = cmpobject(co->co_names, cp->co_names);
+       if (cmp) return cmp;
+       cmp = cmpobject(co->co_varnames, cp->co_varnames);
        return cmp;
 }
 
@@ -109,14 +128,17 @@ static long
 code_hash(co)
        codeobject *co;
 {
-       long h, h1, h2, h3;
+       long h, h1, h2, h3, h4;
        h1 = hashobject((object *)co->co_code);
        if (h1 == -1) return -1;
        h2 = hashobject(co->co_consts);
        if (h2 == -1) return -1;
        h3 = hashobject(co->co_names);
        if (h3 == -1) return -1;
-       h = h1 ^ h2 ^ h3;
+       h4 = hashobject(co->co_varnames);
+       if (h4 == -1) return -1;
+       h = h1 ^ h2 ^ h3 ^ h4 ^
+               co->co_argcount ^ co->co_nlocals ^ co->co_flags;
        if (h == -1) h = -2;
        return h;
 }
@@ -140,67 +162,64 @@ typeobject Codetype = {
 };
 
 codeobject *
-newcodeobject(code, consts, names, filename, name)
+newcodeobject(argcount, nlocals, flags,
+             code, consts, names, varnames, filename, name)
+       int argcount;
+       int nlocals;
+       int flags;
        object *code;
        object *consts;
        object *names;
+       object *varnames;
        object *filename;
        object *name;
 {
        codeobject *co;
        int i;
        /* Check argument types */
-       if (code == NULL || !is_stringobject(code) ||
-               consts == NULL ||
-               names == NULL ||
-               name == NULL || !(is_stringobject(name) || name == None)) {
+       if (argcount < 0 || nlocals < 0 ||
+           code == NULL || !is_stringobject(code) ||
+           consts == NULL || !is_tupleobject(consts) ||
+           names == NULL || !is_tupleobject(names) ||
+           varnames == NULL || !is_tupleobject(varnames) ||
+           name == NULL || !is_stringobject(name) ||
+           filename == NULL || !is_stringobject(filename)) {
                err_badcall();
                return NULL;
        }
-       /* Allow two lists instead of two tuples */
-       if (is_listobject(consts) && is_listobject(names)) {
-               consts = listtuple(consts);
-               if (consts == NULL)
-                       return NULL;
-               names = listtuple(names);
-               if (names == NULL) {
-                       DECREF(consts);
+       /* Make sure names and varnames are all strings */
+       for (i = gettuplesize(names); --i >= 0; ) {
+               object *v = gettupleitem(names, i);
+               if (v == NULL || !is_stringobject(v)) {
+                       err_badcall();
                        return NULL;
                }
        }
-       else if (!is_tupleobject(consts) && !is_tupleobject(names)) {
-               err_badcall();
-               return NULL;
-       }
-       else {
-               INCREF(consts);
-               INCREF(names);
-       }
-       /* Make sure the list of names contains only strings */
-       for (i = gettuplesize(names); --i >= 0; ) {
-               object *v = gettupleitem(names, i);
+       for (i = gettuplesize(varnames); --i >= 0; ) {
+               object *v = gettupleitem(varnames, i);
                if (v == NULL || !is_stringobject(v)) {
-                       DECREF(consts);
-                       DECREF(names);
                        err_badcall();
                        return NULL;
                }
        }
        co = NEWOBJ(codeobject, &Codetype);
        if (co != NULL) {
+               co->co_argcount = argcount;
+               co->co_nlocals = nlocals;
+               co->co_flags = flags;
                INCREF(code);
                co->co_code = (stringobject *)code;
+               INCREF(consts);
                co->co_consts = consts;
+               INCREF(names);
                co->co_names = names;
+               INCREF(varnames);
+               co->co_varnames = varnames;
                INCREF(filename);
                co->co_filename = filename;
                INCREF(name);
                co->co_name = name;
        }
-       else {
-               DECREF(consts);
-               DECREF(names);
-       }
        return co;
 }
 
@@ -213,7 +232,12 @@ struct compiling {
        object *c_code;         /* string */
        object *c_consts;       /* list of objects */
        object *c_names;        /* list of strings (names) */
-       object *c_globals;      /* dictionary */
+       object *c_globals;      /* dictionary (value=None) */
+       object *c_locals;       /* dictionary (value=localID) */
+       object *c_varnames;     /* list (inverse of c_locals) */
+       int c_nlocals;          /* index of next local */
+       int c_argcount;         /* number of top-level arguments */
+       int c_flags;            /* same as co_flags */
        int c_nexti;            /* index into c_code */
        int c_errors;           /* counts errors occurred */
        int c_infunction;       /* set when compiling a function */
@@ -257,7 +281,7 @@ block_pop(c, type)
 }
 
 
-/* Prototypes */
+/* Prototype forward declarations */
 
 static int com_init PROTO((struct compiling *, char *));
 static void com_free PROTO((struct compiling *));
@@ -273,7 +297,8 @@ static int com_addconst PROTO((struct compiling *, object *));
 static int com_addname PROTO((struct compiling *, object *));
 static void com_addopname PROTO((struct compiling *, int, node *));
 static void com_list PROTO((struct compiling *, node *, int));
-static int com_argdefs PROTO((struct compiling *, node *, int *));
+static int com_argdefs PROTO((struct compiling *, node *));
+static int com_newlocal PROTO((struct compiling *, char *));
 
 static int
 com_init(c, filename)
@@ -288,6 +313,13 @@ com_init(c, filename)
                goto fail_1;
        if ((c->c_globals = newdictobject()) == NULL)
                goto fail_0;
+       if ((c->c_locals = newdictobject()) == NULL)
+               goto fail_00;
+       if ((c->c_varnames = newlistobject(0)) == NULL)
+               goto fail_000;
+       c->c_nlocals = 0;
+       c->c_argcount = 0;
+       c->c_flags = 0;
        c->c_nexti = 0;
        c->c_errors = 0;
        c->c_infunction = 0;
@@ -299,6 +331,10 @@ com_init(c, filename)
        c->c_name = "?";
        return 1;
        
+  fail_000:
+       DECREF(c->c_locals);
+  fail_00:
+       DECREF(c->c_globals);
   fail_0:
        DECREF(c->c_names);
   fail_1:
@@ -317,6 +353,8 @@ com_free(c)
        XDECREF(c->c_consts);
        XDECREF(c->c_names);
        XDECREF(c->c_globals);
+       XDECREF(c->c_locals);
+       XDECREF(c->c_varnames);
 }
 
 static void
@@ -333,6 +371,7 @@ com_addbyte(c, byte)
        int byte;
 {
        int len;
+       /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
        if (byte < 0 || byte > 255) {
                /*
                fprintf(stderr, "XXX compiling bad byte: %d\n", byte);
@@ -1221,8 +1260,7 @@ com_test(c, n)
        if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
                object *v;
                int i;
-               int argcount;
-               int ndefs = com_argdefs(c, CHILD(n, 0), &argcount);
+               int ndefs = com_argdefs(c, CHILD(n, 0));
                v = (object *) compile(CHILD(n, 0), c->c_filename);
                if (v == NULL) {
                        c->c_errors++;
@@ -1233,9 +1271,7 @@ com_test(c, n)
                        DECREF(v);
                }
                com_addoparg(c, LOAD_CONST, i);
-               com_addbyte(c, BUILD_FUNCTION);
-               if (ndefs > 0)
-                       com_addoparg(c, SET_FUNC_ARGS, argcount);
+               com_addoparg(c, MAKE_FUNCTION, ndefs);
        }
        else {
                int anchor = 0;
@@ -1537,16 +1573,12 @@ com_raise_stmt(c, n)
 {
        REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
        com_node(c, CHILD(n, 1));
-       if (NCH(n) > 3)
+       if (NCH(n) > 3) {
                com_node(c, CHILD(n, 3));
-       else
-               com_addoparg(c, LOAD_CONST, com_addconst(c, None));
-       if (NCH(n) > 5) {
-               com_node(c, CHILD(n, 5));
-               com_addoparg(c, RAISE_VARARGS, 3);
+               if (NCH(n) > 5)
+                       com_node(c, CHILD(n, 5));
        }
-       else
-               com_addbyte(c, RAISE_EXCEPTION);
+       com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
 }
 
 static void
@@ -1585,9 +1617,67 @@ com_global_stmt(c, n)
        REQ(n, global_stmt);
        /* 'global' NAME (',' NAME)* */
        for (i = 1; i < NCH(n); i += 2) {
-               if (dictinsert(c->c_globals, STR(CHILD(n, i)), None) != 0)
+               char *s = STR(CHILD(n, i));
+               if (dictlookup(c->c_locals, s) != NULL) {
+                       err_setstr(SyntaxError, "name is local and global");
+                       c->c_errors++;
+               }
+               else if (dictinsert(c->c_globals, s, None) != 0)
+                       c->c_errors++;
+       }
+}
+
+static int
+com_newlocal_o(c, nameval)
+       struct compiling *c;
+       object *nameval;
+{
+       int i;
+       object *ival;
+       if (getlistsize(c->c_varnames) != c->c_nlocals) {
+               /* This is usually caused by an error on a previous call */
+               if (c->c_errors == 0) {
+                       err_setstr(SystemError, "mixed up var name/index");
                        c->c_errors++;
+               }
+               return 0;
+       }
+       ival = newintobject(i = c->c_nlocals++);
+       if (ival == NULL)
+               c->c_errors++;
+       else if (mappinginsert(c->c_locals, nameval, ival) != 0)
+               c->c_errors++;
+       else if (addlistitem(c->c_varnames, nameval) != 0)
+               c->c_errors++;
+       XDECREF(ival);
+       return i;
+}
+
+static int
+com_addlocal_o(c, nameval)
+       struct compiling *c;
+       object *nameval;
+{
+       object *ival =  mappinglookup(c->c_locals, nameval);
+       if (ival != NULL)
+               return getintvalue(ival);
+       return com_newlocal_o(c, nameval);
+}
+
+static int
+com_newlocal(c, name)
+       struct compiling *c;
+       char *name;
+{
+       object *nameval = newstringobject(name);
+       int i;
+       if (nameval == NULL) {
+               c->c_errors++;
+               return 0;
        }
+       i = com_newlocal_o(c, nameval);
+       DECREF(nameval);
+       return i;
 }
 
 #define strequ(a, b) (strcmp((a), (b)) == 0)
@@ -2019,12 +2109,11 @@ com_continue_stmt(c, n)
 }
 
 static int
-com_argdefs(c, n, argcount_return)
+com_argdefs(c, n)
        struct compiling *c;
        node *n;
-       int *argcount_return;
 {
-       int i, nch, nargs, ndefs, star;
+       int i, nch, nargs, ndefs;
        if (TYPE(n) == lambdef) {
                /* lambdef: 'lambda' [varargslist] ':' test */
                n = CHILD(n, 1);
@@ -2036,14 +2125,13 @@ com_argdefs(c, n, argcount_return)
                n = CHILD(n, 1);
        }
        if (TYPE(n) != varargslist)
-                   return -1;
+                   return 0;
        /* varargslist:
-               (fpdef ['=' test] ',')* '*' NAME ....... |
+               (fpdef ['=' test] ',')* '*' ....... |
                fpdef ['=' test] (',' fpdef ['=' test])* [','] */
        nch = NCH(n);
        nargs = 0;
        ndefs = 0;
-       star = 0;
        for (i = 0; i < nch; i++) {
                int t;
                if (TYPE(CHILD(n, i)) == STAR)
@@ -2073,11 +2161,6 @@ com_argdefs(c, n, argcount_return)
                if (t != COMMA)
                        break;
        }
-       if (star)
-               nargs ^= 0x4000;
-       *argcount_return = nargs;
-       if (ndefs > 0)
-               com_addoparg(c, BUILD_TUPLE, ndefs);
        return ndefs;
 }
 
@@ -2093,12 +2176,9 @@ com_funcdef(c, n)
                c->c_errors++;
        else {
                int i = com_addconst(c, v);
-               int argcount;
-               int ndefs = com_argdefs(c, n, &argcount);
+               int ndefs = com_argdefs(c, n);
                com_addoparg(c, LOAD_CONST, i);
-               com_addbyte(c, BUILD_FUNCTION);
-               if (ndefs > 0)
-                       com_addoparg(c, SET_FUNC_ARGS, argcount);
+               com_addoparg(c, MAKE_FUNCTION, ndefs);
                com_addopname(c, STORE_NAME, CHILD(n, 1));
                DECREF(v);
        }
@@ -2145,8 +2225,8 @@ com_classdef(c, n)
        else {
                i = com_addconst(c, v);
                com_addoparg(c, LOAD_CONST, i);
-               com_addbyte(c, BUILD_FUNCTION);
-               com_addbyte(c, UNARY_CALL);
+               com_addoparg(c, MAKE_FUNCTION, 0);
+               com_addoparg(c, CALL_FUNCTION, 0);
                com_addbyte(c, BUILD_CLASS);
                com_addopname(c, STORE_NAME, CHILD(n, 1));
                DECREF(v);
@@ -2312,7 +2392,7 @@ com_fpdef(c, n)
        if (TYPE(CHILD(n, 0)) == LPAR)
                com_fplist(c, CHILD(n, 1));
        else
-               com_addopname(c, STORE_NAME, CHILD(n, 0));
+               com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
 }
 
 static void
@@ -2337,53 +2417,87 @@ com_arglist(c, n)
        struct compiling *c;
        node *n;
 {
-       int nch, op, nargs, i, t;
+       int nch, i;
+       int complex = 0;
        REQ(n, varargslist);
        /* varargslist:
-               (fpdef ['=' test] ',')* '*' NAME ..... |
-               fpdef ['=' test] (',' fpdef ['=' test])* [','] */
+               (fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */
        nch = NCH(n);
-       op = UNPACK_ARG;
-       nargs = 0;
+       /* Enter all arguments in table of locals */
        for (i = 0; i < nch; i++) {
-               if (TYPE(CHILD(n, i)) == STAR) {
-                       nch = i;
-                       if (TYPE(CHILD(n, i+1)) != STAR)
-                               op = UNPACK_VARARG;
+               node *ch = CHILD(n, i);
+               node *fp;
+               char *name;
+               if (TYPE(ch) == STAR)
                        break;
+               REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+               fp = CHILD(ch, 0);
+               if (TYPE(fp) == NAME)
+                       name = STR(fp);
+               else {
+                       name = "";
+                       complex= 1;
                }
-               nargs++;
-               i++;
-               if (i >= nch)
+               com_newlocal(c, name);
+               c->c_argcount++;
+               if (++i >= nch)
                        break;
-               t = TYPE(CHILD(n, i));
-               if (t == EQUAL) {
+               ch = CHILD(n, i);
+               if (TYPE(ch) == EQUAL)
                        i += 2;
-                       if (i >= nch)
-                               break;
-                       t = TYPE(CHILD(n, i));
+               else
+                       REQ(ch, COMMA);
+       }
+       /* Handle *arguments */
+       if (i < nch) {
+               node *ch;
+               ch = CHILD(n, i);
+               REQ(ch, STAR);
+               ch = CHILD(n, i+1);
+               if (TYPE(ch) == NAME) {
+                       c->c_flags |= CO_VARARGS;
+                       i += 3;
+                       com_newlocal(c, STR(ch));
                }
-               if (t != COMMA)
-                       break;
        }
-       com_addoparg(c, op, nargs);
-       for (i = 0; i < nch; i++) {
-               com_fpdef(c, CHILD(n, i));
-               i++;
-               if (i >= nch)
-                       break;
-               t = TYPE(CHILD(n, i));
-               if (t == EQUAL) {
-                       i += 2;
-                       if (i >= nch)
+       /* Handle **keywords */
+       if (i < nch) {
+               node *ch;
+               ch = CHILD(n, i);
+               REQ(ch, STAR);
+               ch = CHILD(n, i+1);
+               REQ(ch, STAR);
+               ch = CHILD(n, i+2);
+               REQ(ch, NAME);
+               c->c_flags |= CO_VARKEYWORDS;
+               com_newlocal(c, STR(ch));
+       }
+       if (complex) {
+               /* Generate code for complex arguments only after
+                  having counted the simple arguments */
+               int ilocal = 0;
+               for (i = 0; i < nch; i++) {
+                       node *ch = CHILD(n, i);
+                       node *fp;
+                       char *name;
+                       if (TYPE(ch) == STAR)
                                break;
-                       t = TYPE(CHILD(n, i));
+                       REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+                       fp = CHILD(ch, 0);
+                       if (TYPE(fp) != NAME) {
+                               com_addoparg(c, LOAD_FAST, ilocal);
+                               com_fpdef(c, ch);
+                       }
+                       ilocal++;
+                       if (++i >= nch)
+                               break;
+                       ch = CHILD(n, i);
+                       if (TYPE(ch) == EQUAL)
+                               i += 2;
+                       else
+                               REQ(ch, COMMA);
                }
-               if (t != COMMA)
-                       break;
        }
-       if (op == UNPACK_VARARG)
-               com_addopname(c, STORE_NAME, CHILD(n, nch+1));
 }
 
 static void
@@ -2424,12 +2538,11 @@ compile_funcdef(c, n)
                (void) com_addconst(c, doc);
                DECREF(doc);
        }
-       com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
+       else
+               (void) com_addconst(c, None); /* No docstring */
        ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
        ch = CHILD(ch, 1); /* ')' | varargslist */
-       if (TYPE(ch) == RPAR)
-               com_addoparg(c, UNPACK_ARG, 0);
-       else
+       if (TYPE(ch) == varargslist)
                com_arglist(c, ch);
        c->c_infunction = 1;
        com_node(c, CHILD(n, 4));
@@ -2444,21 +2557,18 @@ compile_lambdef(c, n)
        node *n;
 {
        node *ch;
-       REQ(n, lambdef); /* lambdef: 'lambda' [parameters] ':' test */
+       REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */
        c->c_name = "<lambda>";
 
        ch = CHILD(n, 1);
-       (void) com_addconst(c, None);
-       if (TYPE(ch) == COLON) {
-               com_addoparg(c, UNPACK_ARG, 0);
-               com_node(c, CHILD(n, 2));
-       }
-       else {
-               com_addoparg(c, RESERVE_FAST, com_addconst(c, None));
+       (void) com_addconst(c, None); /* No docstring */
+       if (TYPE(ch) == varargslist) {
                com_arglist(c, ch);
-               com_node(c, CHILD(n, 3));
+               ch = CHILD(n, 3);
        }
-
+       else
+               ch = CHILD(n, 2);
+       com_node(c, ch);
        com_addbyte(c, RETURN_VALUE);
 }
 
@@ -2544,34 +2654,31 @@ compile_node(c, n)
    The latter instructions are much faster because they don't need to
    look up the variable name in a dictionary.
 
-   To find all local variables, we check all STORE_NAME, IMPORT_FROM and
-   DELETE_NAME instructions.  This yields all local variables, including
-   arguments, function definitions, class definitions and import
-   statements.
+   To find all local variables, we check all STORE_NAME, IMPORT_FROM
+   and DELETE_NAME instructions.  This yields all local variables,
+   function definitions, class definitions and import statements.
+   Argument names have already been entered into the list by the
+   special processing for the argument list.
 
    All remaining LOAD_NAME instructions must refer to non-local (global
    or builtin) variables, so are replaced by LOAD_GLOBAL.
 
    There are two problems:  'from foo import *' and 'exec' may introduce
    local variables that we can't know while compiling.  If this is the
-   case, we don't optimize at all (this rarely happens, since exec is
-   rare, & this form of import statement is mostly used at the module
-   level).
+   case, we can still optimize bona fide locals (since those
+   statements will be surrounded by fast_2_locals() and
+   locals_2_fast()), but we can't change LOAD_NAME to LOAD_GLOBAL.
 
-   NB: this modifies the string object co->co_code!
-*/
+   NB: this modifies the string object c->c_code!  */
 
 static void
 optimize(c)
        struct compiling *c;
 {
        unsigned char *next_instr, *cur_instr;
-       object *locals;
-       int nlocals;
        int opcode;
        int oparg;
        object *name;
-       int fast_reserved;
        object *error_type, *error_value, *error_traceback;
        
 #define NEXTOP()       (*next_instr++)
@@ -2579,53 +2686,33 @@ optimize(c)
 #define GETITEM(v, i)  (getlistitem((v), (i)))
 #define GETNAMEOBJ(i)  (GETITEM(c->c_names, (i)))
        
-       locals = newdictobject();
-       if (locals == NULL) {
-               c->c_errors++;
-               return;
-       }
-       nlocals = 0;
-
        err_fetch(&error_type, &error_value, &error_traceback);
+
+       c->c_flags |= CO_OPTIMIZED;
        
        next_instr = (unsigned char *) getstringvalue(c->c_code);
        for (;;) {
                opcode = NEXTOP();
                if (opcode == STOP_CODE)
                        break;
-               if (opcode == EXEC_STMT)
-                       goto end; /* Don't optimize if exec present */
                if (HAS_ARG(opcode))
                        oparg = NEXTARG();
-               if (opcode == STORE_NAME || opcode == DELETE_NAME ||
-                   opcode == IMPORT_FROM) {
-                       object *v;
-                       name = GETNAMEOBJ(oparg);
-                       if (dict2lookup(locals, name) != NULL)
-                               continue;
-                       err_clear();
-                       v = newintobject(nlocals);
-                       if (v == NULL) {
-                               c->c_errors++;
-                               goto err;
-                       }
-                       nlocals++;
-                       if (dict2insert(locals, name, v) != 0) {
-                               DECREF(v);
-                               c->c_errors++;
-                               goto err;
-                       }
-                       DECREF(v);
+               switch (opcode) {
+               case STORE_NAME:
+               case DELETE_NAME:
+               case IMPORT_FROM:
+                       com_addlocal_o(c, GETNAMEOBJ(oparg));
+                       break;
+               case EXEC_STMT:
+                       c->c_flags &= ~CO_OPTIMIZED;
+                       break;
                }
        }
        
-       if (dictlookup(locals, "*") != NULL) {
-               /* Don't optimize anything */
-               goto end;
-       }
+       if (dictlookup(c->c_locals, "*") != NULL)
+               c->c_flags &= ~CO_OPTIMIZED;
        
        next_instr = (unsigned char *) getstringvalue(c->c_code);
-       fast_reserved = 0;
        for (;;) {
                cur_instr = next_instr;
                opcode = NEXTOP();
@@ -2633,45 +2720,17 @@ optimize(c)
                        break;
                if (HAS_ARG(opcode))
                        oparg = NEXTARG();
-               if (opcode == RESERVE_FAST) {
-                       int i;
-                       object *localmap = newtupleobject(nlocals);
-                       int pos;
-                       object *key, *value;
-                       if (localmap == NULL) { /* XXX mask error */
-                               err_clear();
-                               continue;
-                       }
-                       pos = 0;
-                       while (mappinggetnext(locals, &pos, &key, &value)) {
-                               int j;
-                               if (!is_intobject(value))
-                                       continue;
-                               j = getintvalue(value);
-                               if (0 <= j && j < nlocals) {
-                                       INCREF(key);
-                                       settupleitem(localmap, j, key);
-                               }
-                       }
-                       i = com_addconst(c, localmap);
-                       cur_instr[1] = i & 0xff;
-                       cur_instr[2] = (i>>8) & 0xff;
-                       fast_reserved = 1;
-                       DECREF(localmap);
-                       continue;
-               }
-               if (!fast_reserved)
-                       continue;
                if (opcode == LOAD_NAME ||
                    opcode == STORE_NAME ||
                    opcode == DELETE_NAME) {
                        object *v;
                        int i;
                        name = GETNAMEOBJ(oparg);
-                       v = dict2lookup(locals, name);
+                       v = dict2lookup(c->c_locals, name);
                        if (v == NULL) {
                                err_clear();
-                               if (opcode == LOAD_NAME)
+                               if (opcode == LOAD_NAME &&
+                                   (c->c_flags&CO_OPTIMIZED))
                                        cur_instr[0] = LOAD_GLOBAL;
                                continue;
                        }
@@ -2686,10 +2745,8 @@ optimize(c)
                }
        }
 
- end:
-       err_restore(error_type, error_value, error_traceback);
- err:
-       DECREF(locals);
+       if (c->c_errors == 0)
+               err_restore(error_type, error_value, error_traceback);
 }
 
 codeobject *
@@ -2703,18 +2760,35 @@ compile(n, filename)
                return NULL;
        compile_node(&sc, n);
        com_done(&sc);
-       if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0)
+       if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0) {
                optimize(&sc);
+               sc.c_flags |= CO_NEWLOCALS;
+       }
+       else if (TYPE(n) == classdef)
+               sc.c_flags |= CO_NEWLOCALS;
        co = NULL;
        if (sc.c_errors == 0) {
-               object *v, *w;
-               v = newstringobject(sc.c_filename);
-               w = newstringobject(sc.c_name);
-               if (v != NULL && w != NULL)
-                       co = newcodeobject(sc.c_code, sc.c_consts,
-                                          sc.c_names, v, w);
-               XDECREF(v);
-               XDECREF(w);
+               object *consts, *names, *varnames, *filename, *name;
+               consts = listtuple(sc.c_consts);
+               names = listtuple(sc.c_names);
+               varnames = listtuple(sc.c_varnames);
+               filename = newstringobject(sc.c_filename);
+               name = newstringobject(sc.c_name);
+               if (!err_occurred())
+                       co = newcodeobject(sc.c_argcount,
+                                          sc.c_nlocals,
+                                          sc.c_flags,
+                                          sc.c_code,
+                                          consts,
+                                          names,
+                                          varnames,
+                                          filename,
+                                          name);
+               XDECREF(consts);
+               XDECREF(names);
+               XDECREF(varnames);
+               XDECREF(filename);
+               XDECREF(name);
        }
        com_free(&sc);
        return co;
index 4239e1230f7354d8781a6596c12dbf9ed6b03728..4a4c3d4fa72525a437e14b299fb641f50ecff3da 100644 (file)
@@ -54,7 +54,7 @@ extern long getmtime(); /* In getmtime.c */
    Apple MPW compiler swaps their values, botching string constants */
 /* XXX Perhaps the magic number should be frozen and a version field
    added to the .pyc file header? */
-#define MAGIC (0x4127L | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (11913 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 object *import_modules; /* This becomes sys.modules */
 
@@ -159,7 +159,7 @@ exec_code_module(name, co)
                if (dictinsert(d, "__builtins__", getbuiltins()) != 0)
                        return NULL;
        }
-       v = eval_code((codeobject *)co, d, d, d, (object *)NULL);
+       v = eval_code((codeobject *)co, d, d); /* XXX owner? */
        if (v == NULL)
                return NULL;
        DECREF(v);
index 8c01020ddcadef0b9b6bef791ae45d98ad56b820..05265f58feef6624dd66ae5a8177b8f51e9e9a9b 100644 (file)
@@ -44,7 +44,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define TYPE_TUPLE     '('
 #define TYPE_LIST      '['
 #define TYPE_DICT      '{'
-#define TYPE_CODE      'C'
+#define TYPE_CODE      'c'
 #define TYPE_UNKNOWN   '?'
 
 typedef struct {
@@ -187,9 +187,13 @@ w_object(v, p)
        else if (is_codeobject(v)) {
                codeobject *co = (codeobject *)v;
                w_byte(TYPE_CODE, p);
+               w_short(co->co_argcount, p);
+               w_short(co->co_nlocals, p);
+               w_short(co->co_flags, p);
                w_object((object *)co->co_code, p);
                w_object(co->co_consts, p);
                w_object(co->co_names, p);
+               w_object(co->co_varnames, p);
                w_object(co->co_filename, p);
                w_object(co->co_name, p);
        }
@@ -374,14 +378,20 @@ r_object(p)
        
        case TYPE_CODE:
                {
+                       int argcount = r_short(p);
+                       int nlocals = r_short(p);
+                       int flags = r_short(p);
                        object *code = r_object(p);
                        object *consts = r_object(p);
                        object *names = r_object(p);
+                       object *varnames = r_object(p);
                        object *filename = r_object(p);
                        object *name = r_object(p);
                        if (!err_occurred()) {
-                               v = (object *) newcodeobject(code,
-                                               consts, names, filename, name);
+                               v = (object *) newcodeobject(
+                                       argcount, nlocals, flags, 
+                                       code, consts, names, varnames,
+                                       filename, name);
                        }
                        else
                                v = NULL;
index 2268c71ad483d165ad20bc3231d82d2336b7717f..f0875454e268ef6cc60a6ab1423c54dc503a1ef8 100644 (file)
@@ -430,7 +430,7 @@ run_node(n, filename, globals, locals)
        freetree(n);
        if (co == NULL)
                return NULL;
-       v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL);
+       v = eval_code(co, globals, locals);
        DECREF(co);
        return v;
 }
@@ -462,7 +462,7 @@ run_pyc_file(fp, filename, globals, locals)
                return NULL;
        }
        co = (codeobject *)v;
-       v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL);
+       v = eval_code(co, globals, locals);
        DECREF(co);
        return v;
 }
@@ -603,16 +603,9 @@ cleanup()
        object *exitfunc = sysget("exitfunc");
 
        if (exitfunc) {
-               object *arg;
                object *res;
                sysset("exitfunc", (object *)NULL);
-               arg = newtupleobject(0);
-               if (arg == NULL)
-                       res = NULL;
-               else {
-                       res = call_object(exitfunc, arg);
-                       DECREF(arg);
-               }
+               res = call_object(exitfunc, (object *)NULL);
                if (res == NULL) {
                        fprintf(stderr, "Error in sys.exitfunc:\n");
                        print_error();
index 1ab880a91e2704a7a13f49941d59313716110362..1f803da43b26613fd372b2e819f9fee18b229c67 100644 (file)
@@ -68,7 +68,10 @@ tb_dealloc(tb)
        DEL(tb);
 }
 
-static typeobject Tracebacktype = {
+#define Tracebacktype PyTraceback_Type
+#define is_tracebackobject PyTraceback_Check
+
+typeobject Tracebacktype = {
        OB_HEAD_INIT(&Typetype)
        0,
        "traceback",
@@ -85,8 +88,6 @@ static typeobject Tracebacktype = {
        0,              /*tp_as_mapping*/
 };
 
-#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype)
-
 static tracebackobject *
 newtracebackobject(next, frame, lasti, lineno)
        tracebackobject *next;