Commit 3b7073d2 authored by Guido van Rossum's avatar Guido van Rossum

keyword arguments and faster calls

parent baea1c3b
......@@ -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");
......
......@@ -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;
}
......@@ -346,6 +390,110 @@ eval_code(co, globals, locals, owner, arg)
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 */
......@@ -523,14 +668,6 @@ eval_code(co, globals, locals, owner, arg)
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();
x = invert(v);
......@@ -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,24 +1168,29 @@ eval_code(co, globals, locals, owner, arg)
case STORE_GLOBAL:
w = GETNAMEV(oparg);
v = POP();
if (f->f_locals != NULL) {
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
err = setaccessvalue(u, f->f_globals, v);
err = setaccessvalue(u, f->f_globals,
v);
DECREF(v);
break;
}
}
err = dict2insert(f->f_globals, w, v);
DECREF(v);
break;
case DELETE_GLOBAL:
w = GETNAMEV(oparg);
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);
break;
......@@ -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);
......@@ -1199,9 +1251,14 @@ eval_code(co, globals, locals, owner, arg)
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);
if (self != NULL) {
class = instancemethodgetclass(func);
DECREF(func);
func = instancemethodgetfunc(func);
INCREF(func);
if (self != NULL) {
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;
}
}
args = newtupleobject(n);
}
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);
}
else {
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;
}
else {
while (--n >= 0) {
while (--na >= 0) {
w = POP();
SETTUPLEITEM(args, n, w);
SETTUPLEITEM(args, na, w);
}
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);
x = call_object(func, args);
DECREF(args);
}
}
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;
}
x = call_object(func, args);
DECREF(args);
PUSH(x);
while (--oparg >= 0) {
w = POP();
SETTUPLEITEM(v, oparg, w);
}
DECREF(func);
break;
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)
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
......@@ -1676,9 +1775,6 @@ eval_code(co, globals, locals, owner, arg)
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,49 +2341,37 @@ 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);
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;
argdefs = PyFunction_GetDefaults(func);
if (argdefs != NULL && is_tupleobject(argdefs)) {
d = &GETTUPLEITEM((tupleobject *)argdefs, 0);
nd = gettuplesize(argdefs);
}
else {
d = NULL;
nd = 0;
}
co = getfunccode(func);
if (co == NULL) {
XDECREF(newarg);
if (kw != NULL) {
int pos, i;
nk = getmappingsize(kw);
k = NEW(object *, 2*nk);
if (k == NULL) {
err_nomem();
DECREF(arg);
return NULL;
}
if (!is_codeobject(co))
fatal("XXX Bad code");
newlocals = newdictobject();
if (newlocals == NULL) {
XDECREF(newarg);
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;
}
newglobals = getfuncglobals(func);
INCREF(newglobals);
v = eval_code((codeobject *)co, newglobals, newlocals, class, arg);
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)
int ret;
fast_2_locals(f);
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;
}
}
}
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);
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);
......
......@@ -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);
return NULL;
}
}
else if (!is_tupleobject(consts) && !is_tupleobject(names)) {
/* 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 {
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) {
if (NCH(n) > 5)
com_node(c, CHILD(n, 5));
com_addoparg(c, RAISE_VARARGS, 3);
}
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);
}
if (t != COMMA)
break;
/* 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));
}
com_addoparg(c, op, nargs);
}
/* 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++) {
com_fpdef(c, CHILD(n, i));
i++;
if (i >= nch)
break;
t = TYPE(CHILD(n, i));
if (t == EQUAL) {
i += 2;
if (i >= nch)
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);
}
if (t != COMMA)
ilocal++;
if (++i >= nch)
break;
ch = CHILD(n, i);
if (TYPE(ch) == EQUAL)
i += 2;
else
REQ(ch, COMMA);
}
}
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:
if (c->c_errors == 0)
err_restore(error_type, error_value, error_traceback);
err:
DECREF(locals);
}
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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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();
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment