summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1995-07-18 14:51:37 (GMT)
committerGuido van Rossum <guido@python.org>1995-07-18 14:51:37 (GMT)
commit681d79aaf397850778608f35585d091fa7fe370a (patch)
tree3d45bd9b84777931bba732abd1dbba484e2a64c1
parent11a3f0c2bca1a8fdea396b989559f25fbc6fe65e (diff)
downloadcpython-681d79aaf397850778608f35585d091fa7fe370a.zip
cpython-681d79aaf397850778608f35585d091fa7fe370a.tar.gz
cpython-681d79aaf397850778608f35585d091fa7fe370a.tar.bz2
keyword arguments and faster calls
-rw-r--r--Python/bltinmodule.c16
-rw-r--r--Python/ceval.c823
-rw-r--r--Python/compile.c486
-rw-r--r--Python/import.c4
-rw-r--r--Python/marshal.c16
-rw-r--r--Python/pythonrun.c13
-rw-r--r--Python/traceback.c7
7 files changed, 771 insertions, 594 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 5103622..0be0373 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -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");
diff --git a/Python/ceval.c b/Python/ceval.c
index a55451c..2b501c79 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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);
diff --git a/Python/compile.c b/Python/compile.c
index df81f8f..9f15254 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -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;
diff --git a/Python/import.c b/Python/import.c
index 4239e12..4a4c3d4 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -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);
diff --git a/Python/marshal.c b/Python/marshal.c
index 8c01020..05265f5 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -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;
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 2268c71..f087545 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -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();
diff --git a/Python/traceback.c b/Python/traceback.c
index 1ab880a..1f803da 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -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;