mirror of
https://github.com/python/cpython.git
synced 2024-11-23 18:04:37 +08:00
keyword arguments and faster calls
This commit is contained in:
parent
11a3f0c2bc
commit
681d79aaf3
@ -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");
|
||||
|
839
Python/ceval.c
839
Python/ceval.c
File diff suppressed because it is too large
Load Diff
492
Python/compile.c
492
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);
|
||||
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 */
|
||||
/* 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)) {
|
||||
DECREF(consts);
|
||||
DECREF(names);
|
||||
err_badcall();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
for (i = gettuplesize(varnames); --i >= 0; ) {
|
||||
object *v = gettupleitem(varnames, i);
|
||||
if (v == NULL || !is_stringobject(v)) {
|
||||
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,11 +1617,69 @@ 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)
|
||||
|
||||
static void
|
||||
@ -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));
|
||||
}
|
||||
if (t != COMMA)
|
||||
break;
|
||||
else
|
||||
REQ(ch, COMMA);
|
||||
}
|
||||
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)
|
||||
break;
|
||||
t = TYPE(CHILD(n, i));
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user