mirror of https://github.com/python/cpython
* Python/compile.c (com_argdefs, com_arglist): avoid referencing
CHILD(n,i) for i >= NCH(n)
This commit is contained in:
parent
3a24181837
commit
4ca6c9db81
465
Python/compile.c
465
Python/compile.c
|
@ -1,5 +1,5 @@
|
|||
/***********************************************************
|
||||
Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
|
||||
Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
|
||||
Amsterdam, The Netherlands.
|
||||
|
||||
All Rights Reserved
|
||||
|
@ -127,16 +127,16 @@ typeobject Codetype = {
|
|||
"code",
|
||||
sizeof(codeobject),
|
||||
0,
|
||||
code_dealloc, /*tp_dealloc*/
|
||||
(destructor)code_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
code_getattr, /*tp_getattr*/
|
||||
(getattrfunc)code_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
code_compare, /*tp_compare*/
|
||||
code_repr, /*tp_repr*/
|
||||
(cmpfunc)code_compare, /*tp_compare*/
|
||||
(reprfunc)code_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
code_hash, /*tp_hash*/
|
||||
(hashfunc)code_hash, /*tp_hash*/
|
||||
};
|
||||
|
||||
codeobject *
|
||||
|
@ -151,16 +151,37 @@ newcodeobject(code, consts, names, filename, name)
|
|||
int i;
|
||||
/* Check argument types */
|
||||
if (code == NULL || !is_stringobject(code) ||
|
||||
consts == NULL || !is_listobject(consts) ||
|
||||
names == NULL || !is_listobject(names) ||
|
||||
consts == NULL ||
|
||||
names == NULL ||
|
||||
name == NULL || !(is_stringobject(name) || name == None)) {
|
||||
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 */
|
||||
for (i = getlistsize(names); --i >= 0; ) {
|
||||
object *v = getlistitem(names, i);
|
||||
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;
|
||||
}
|
||||
|
@ -169,15 +190,17 @@ newcodeobject(code, consts, names, filename, name)
|
|||
if (co != NULL) {
|
||||
INCREF(code);
|
||||
co->co_code = (stringobject *)code;
|
||||
INCREF(consts);
|
||||
co->co_consts = consts;
|
||||
INCREF(names);
|
||||
co->co_names = names;
|
||||
INCREF(filename);
|
||||
co->co_filename = filename;
|
||||
INCREF(name);
|
||||
co->co_name = name;
|
||||
}
|
||||
else {
|
||||
DECREF(consts);
|
||||
DECREF(names);
|
||||
}
|
||||
return co;
|
||||
}
|
||||
|
||||
|
@ -194,6 +217,7 @@ struct compiling {
|
|||
int c_nexti; /* index into c_code */
|
||||
int c_errors; /* counts errors occurred */
|
||||
int c_infunction; /* set when compiling a function */
|
||||
int c_interactive; /* generating code for interactive command */
|
||||
int c_loops; /* counts nested loops */
|
||||
int c_begin; /* begin of current loop, for 'continue' */
|
||||
int c_block[MAXBLOCKS]; /* stack of block types */
|
||||
|
@ -249,6 +273,7 @@ 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_init(c, filename)
|
||||
|
@ -266,6 +291,7 @@ com_init(c, filename)
|
|||
c->c_nexti = 0;
|
||||
c->c_errors = 0;
|
||||
c->c_infunction = 0;
|
||||
c->c_interactive = 0;
|
||||
c->c_loops = 0;
|
||||
c->c_begin = 0;
|
||||
c->c_nblocks = 0;
|
||||
|
@ -462,20 +488,19 @@ static object *
|
|||
parsenumber(s)
|
||||
char *s;
|
||||
{
|
||||
extern long strtol PROTO((const char *, char **, int));
|
||||
extern unsigned long strtoul PROTO((const char *, char **, int));
|
||||
extern double strtod PROTO((const char *, char **));
|
||||
extern long mystrtol PROTO((const char *, char **, int));
|
||||
extern unsigned long mystrtoul PROTO((const char *, char **, int));
|
||||
extern double atof PROTO((const char *));
|
||||
char *end;
|
||||
long x;
|
||||
double xx;
|
||||
errno = 0;
|
||||
end = s + strlen(s) - 1;
|
||||
if (*end == 'l' || *end == 'L')
|
||||
return long_scan(s, 0);
|
||||
if (s[0] == '0')
|
||||
x = (long) strtoul(s, &end, 0);
|
||||
x = (long) mystrtoul(s, &end, 0);
|
||||
else
|
||||
x = strtol(s, &end, 0);
|
||||
x = mystrtol(s, &end, 0);
|
||||
if (*end == '\0') {
|
||||
if (errno != 0) {
|
||||
err_setstr(OverflowError,
|
||||
|
@ -484,22 +509,8 @@ parsenumber(s)
|
|||
}
|
||||
return newintobject(x);
|
||||
}
|
||||
errno = 0;
|
||||
xx = strtod(s, &end);
|
||||
if (*end == '\0') {
|
||||
#ifndef BROKEN_STRTOD
|
||||
/* Some strtod() versions (e.g., in older SunOS systems)
|
||||
set errno incorrectly; better to ignore overflows
|
||||
than not to be able to use float literals at all! */
|
||||
if (errno != 0) {
|
||||
err_setstr(OverflowError, "float literal too large");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return newfloatobject(xx);
|
||||
}
|
||||
err_setstr(SystemError, "bad number syntax?!?!");
|
||||
return NULL;
|
||||
/* XXX Huge floats may silently fail */
|
||||
return newfloatobject(atof(s));
|
||||
}
|
||||
|
||||
static object *
|
||||
|
@ -510,6 +521,7 @@ parsestr(s)
|
|||
int len;
|
||||
char *buf;
|
||||
char *p;
|
||||
char *end;
|
||||
int c;
|
||||
int quote = *s;
|
||||
if (quote != '\'' && quote != '\"') {
|
||||
|
@ -522,11 +534,20 @@ parsestr(s)
|
|||
err_badcall();
|
||||
return NULL;
|
||||
}
|
||||
if (len >= 4 && s[0] == quote && s[1] == quote) {
|
||||
s += 2;
|
||||
len -= 2;
|
||||
if (s[--len] != quote || s[--len] != quote) {
|
||||
err_badcall();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (strchr(s, '\\') == NULL)
|
||||
return newsizedstringobject(s, len);
|
||||
v = newsizedstringobject((char *)NULL, len);
|
||||
p = buf = getstringvalue(v);
|
||||
while (*s != '\0' && *s != quote) {
|
||||
end = s + len;
|
||||
while (s < end) {
|
||||
if (*s != '\\') {
|
||||
*p++ = *s++;
|
||||
continue;
|
||||
|
@ -534,6 +555,7 @@ parsestr(s)
|
|||
s++;
|
||||
switch (*s++) {
|
||||
/* XXX This assumes ASCII! */
|
||||
case '\n': break;
|
||||
case '\\': *p++ = '\\'; break;
|
||||
case '\'': *p++ = '\''; break;
|
||||
case '\"': *p++ = '\"'; break;
|
||||
|
@ -649,7 +671,14 @@ com_atom(c, n)
|
|||
com_addoparg(c, LOAD_CONST, i);
|
||||
break;
|
||||
case STRING:
|
||||
if ((v = parsestr(STR(ch))) == NULL) {
|
||||
if ((v = parsestr(STR(ch))) != NULL) {
|
||||
/* String literal concatenation */
|
||||
for (i = 1; i < NCH(n) && v != NULL; i++) {
|
||||
joinstring_decref(&v,
|
||||
parsestr(STR(CHILD(n, i))));
|
||||
}
|
||||
}
|
||||
if (v == NULL) {
|
||||
c->c_errors++;
|
||||
i = 255;
|
||||
}
|
||||
|
@ -1098,6 +1127,8 @@ 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);
|
||||
v = (object *) compile(CHILD(n, 0), c->c_filename);
|
||||
if (v == NULL) {
|
||||
c->c_errors++;
|
||||
|
@ -1109,6 +1140,8 @@ com_test(c, n)
|
|||
}
|
||||
com_addoparg(c, LOAD_CONST, i);
|
||||
com_addbyte(c, BUILD_FUNCTION);
|
||||
if (ndefs > 0)
|
||||
com_addoparg(c, SET_FUNC_ARGS, argcount);
|
||||
}
|
||||
else {
|
||||
int anchor = 0;
|
||||
|
@ -1355,7 +1388,10 @@ com_expr_stmt(c, n)
|
|||
REQ(n, expr_stmt); /* testlist ('=' testlist)* */
|
||||
com_node(c, CHILD(n, NCH(n)-1));
|
||||
if (NCH(n) == 1) {
|
||||
com_addbyte(c, PRINT_EXPR);
|
||||
if (c->c_interactive)
|
||||
com_addbyte(c, PRINT_EXPR);
|
||||
else
|
||||
com_addbyte(c, POP_TOP);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
|
@ -1625,25 +1661,7 @@ com_for_stmt(c, n)
|
|||
com_backpatch(c, break_anchor);
|
||||
}
|
||||
|
||||
/* Although 'execpt' and 'finally' clauses can be combined
|
||||
syntactically, they are compiled separately. In fact,
|
||||
try: S
|
||||
except E1: S1
|
||||
except E2: S2
|
||||
...
|
||||
finally: Sf
|
||||
is equivalent to
|
||||
try:
|
||||
try: S
|
||||
except E1: S1
|
||||
except E2: S2
|
||||
...
|
||||
finally: Sf
|
||||
meaning that the 'finally' clause is entered even if things
|
||||
go wrong again in an exception handler. Note that this is
|
||||
not the case for exception handlers: at most one is entered.
|
||||
|
||||
Code generated for "try: S finally: Sf" is as follows:
|
||||
/* Code generated for "try: S finally: Sf" is as follows:
|
||||
|
||||
SETUP_FINALLY L
|
||||
<code for S>
|
||||
|
@ -1710,86 +1728,97 @@ com_for_stmt(c, n)
|
|||
*/
|
||||
|
||||
static void
|
||||
com_try_stmt(c, n)
|
||||
com_try_except(c, n)
|
||||
struct compiling *c;
|
||||
node *n;
|
||||
{
|
||||
int except_anchor = 0;
|
||||
int end_anchor = 0;
|
||||
int else_anchor = 0;
|
||||
int i;
|
||||
node *ch;
|
||||
|
||||
com_addfwref(c, SETUP_EXCEPT, &except_anchor);
|
||||
block_push(c, SETUP_EXCEPT);
|
||||
com_node(c, CHILD(n, 2));
|
||||
com_addbyte(c, POP_BLOCK);
|
||||
block_pop(c, SETUP_EXCEPT);
|
||||
com_addfwref(c, JUMP_FORWARD, &else_anchor);
|
||||
com_backpatch(c, except_anchor);
|
||||
for (i = 3;
|
||||
i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
|
||||
i += 3) {
|
||||
/* except_clause: 'except' [expr [',' expr]] */
|
||||
if (except_anchor == 0) {
|
||||
err_setstr(SyntaxError,
|
||||
"default 'except:' must be last");
|
||||
c->c_errors++;
|
||||
break;
|
||||
}
|
||||
except_anchor = 0;
|
||||
com_addoparg(c, SET_LINENO, ch->n_lineno);
|
||||
if (NCH(ch) > 1) {
|
||||
com_addbyte(c, DUP_TOP);
|
||||
com_node(c, CHILD(ch, 1));
|
||||
com_addoparg(c, COMPARE_OP, EXC_MATCH);
|
||||
com_addfwref(c, JUMP_IF_FALSE, &except_anchor);
|
||||
com_addbyte(c, POP_TOP);
|
||||
}
|
||||
com_addbyte(c, POP_TOP);
|
||||
if (NCH(ch) > 3)
|
||||
com_assign(c, CHILD(ch, 3), 1/*assigning*/);
|
||||
else
|
||||
com_addbyte(c, POP_TOP);
|
||||
com_addbyte(c, POP_TOP);
|
||||
com_node(c, CHILD(n, i+2));
|
||||
com_addfwref(c, JUMP_FORWARD, &end_anchor);
|
||||
if (except_anchor) {
|
||||
com_backpatch(c, except_anchor);
|
||||
com_addbyte(c, POP_TOP);
|
||||
}
|
||||
}
|
||||
com_addbyte(c, END_FINALLY);
|
||||
com_backpatch(c, else_anchor);
|
||||
if (i < NCH(n))
|
||||
com_node(c, CHILD(n, i+2));
|
||||
com_backpatch(c, end_anchor);
|
||||
}
|
||||
|
||||
static void
|
||||
com_try_finally(c, n)
|
||||
struct compiling *c;
|
||||
node *n;
|
||||
{
|
||||
int finally_anchor = 0;
|
||||
int except_anchor = 0;
|
||||
REQ(n, try_stmt);
|
||||
/* 'try' ':' suite (except_clause ':' suite)*
|
||||
| 'try' ':' 'finally' ':' suite */
|
||||
node *ch;
|
||||
|
||||
/* XXX This can be simplified because except and finally can
|
||||
no longer be mixed in a single try statement */
|
||||
|
||||
if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) {
|
||||
/* Have a 'finally' clause */
|
||||
com_addfwref(c, SETUP_FINALLY, &finally_anchor);
|
||||
block_push(c, SETUP_FINALLY);
|
||||
}
|
||||
if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) {
|
||||
/* Have an 'except' clause */
|
||||
com_addfwref(c, SETUP_EXCEPT, &except_anchor);
|
||||
block_push(c, SETUP_EXCEPT);
|
||||
}
|
||||
com_addfwref(c, SETUP_FINALLY, &finally_anchor);
|
||||
block_push(c, SETUP_FINALLY);
|
||||
com_node(c, CHILD(n, 2));
|
||||
if (except_anchor) {
|
||||
int end_anchor = 0;
|
||||
int i;
|
||||
node *ch;
|
||||
com_addbyte(c, POP_BLOCK);
|
||||
block_pop(c, SETUP_EXCEPT);
|
||||
com_addfwref(c, JUMP_FORWARD, &end_anchor);
|
||||
com_backpatch(c, except_anchor);
|
||||
for (i = 3;
|
||||
i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause;
|
||||
i += 3) {
|
||||
/* except_clause: 'except' [expr [',' expr]] */
|
||||
if (except_anchor == 0) {
|
||||
err_setstr(SyntaxError,
|
||||
"default 'except:' must be last");
|
||||
c->c_errors++;
|
||||
break;
|
||||
}
|
||||
except_anchor = 0;
|
||||
com_addoparg(c, SET_LINENO, ch->n_lineno);
|
||||
if (NCH(ch) > 1) {
|
||||
com_addbyte(c, DUP_TOP);
|
||||
com_node(c, CHILD(ch, 1));
|
||||
com_addoparg(c, COMPARE_OP, EXC_MATCH);
|
||||
com_addfwref(c, JUMP_IF_FALSE, &except_anchor);
|
||||
com_addbyte(c, POP_TOP);
|
||||
}
|
||||
com_addbyte(c, POP_TOP);
|
||||
if (NCH(ch) > 3)
|
||||
com_assign(c, CHILD(ch, 3), 1/*assigning*/);
|
||||
else
|
||||
com_addbyte(c, POP_TOP);
|
||||
com_addbyte(c, POP_TOP);
|
||||
com_node(c, CHILD(n, i+2));
|
||||
com_addfwref(c, JUMP_FORWARD, &end_anchor);
|
||||
if (except_anchor) {
|
||||
com_backpatch(c, except_anchor);
|
||||
com_addbyte(c, POP_TOP);
|
||||
}
|
||||
}
|
||||
com_addbyte(c, END_FINALLY);
|
||||
com_backpatch(c, end_anchor);
|
||||
}
|
||||
if (finally_anchor) {
|
||||
node *ch;
|
||||
com_addbyte(c, POP_BLOCK);
|
||||
block_pop(c, SETUP_FINALLY);
|
||||
block_push(c, END_FINALLY);
|
||||
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
|
||||
com_backpatch(c, finally_anchor);
|
||||
ch = CHILD(n, NCH(n)-1);
|
||||
com_addoparg(c, SET_LINENO, ch->n_lineno);
|
||||
com_node(c, ch);
|
||||
com_addbyte(c, END_FINALLY);
|
||||
block_pop(c, END_FINALLY);
|
||||
}
|
||||
com_addbyte(c, POP_BLOCK);
|
||||
block_pop(c, SETUP_FINALLY);
|
||||
block_push(c, END_FINALLY);
|
||||
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
|
||||
com_backpatch(c, finally_anchor);
|
||||
ch = CHILD(n, NCH(n)-1);
|
||||
com_addoparg(c, SET_LINENO, ch->n_lineno);
|
||||
com_node(c, ch);
|
||||
com_addbyte(c, END_FINALLY);
|
||||
block_pop(c, END_FINALLY);
|
||||
}
|
||||
|
||||
static void
|
||||
com_try_stmt(c, n)
|
||||
struct compiling *c;
|
||||
node *n;
|
||||
{
|
||||
REQ(n, try_stmt);
|
||||
/* 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
|
||||
| 'try' ':' suite 'finally' ':' suite */
|
||||
if (TYPE(CHILD(n, 3)) != except_clause)
|
||||
com_try_finally(c, n);
|
||||
else
|
||||
com_try_except(c, n);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1830,6 +1859,72 @@ com_continue_stmt(c, n)
|
|||
XXX if we could pop the exception still on the stack */
|
||||
}
|
||||
|
||||
static int
|
||||
com_argdefs(c, n, argcount_return)
|
||||
struct compiling *c;
|
||||
node *n;
|
||||
int *argcount_return;
|
||||
{
|
||||
int i, nch, nargs, ndefs, star;
|
||||
if (TYPE(n) == lambdef) {
|
||||
/* lambdef: 'lambda' [varargslist] ':' test */
|
||||
n = CHILD(n, 1);
|
||||
}
|
||||
else {
|
||||
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ... */
|
||||
n = CHILD(n, 2);
|
||||
REQ(n, parameters); /* parameters: '(' [varargslist] ')' */
|
||||
n = CHILD(n, 1);
|
||||
}
|
||||
if (TYPE(n) != varargslist)
|
||||
return -1;
|
||||
/* varargslist:
|
||||
(fpdef ['=' test] ',')* '*' NAME |
|
||||
fpdef ['=' test] (',' fpdef ['=' test])* [','] */
|
||||
nch = NCH(n);
|
||||
if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) {
|
||||
star = 1;
|
||||
nch -= 2;
|
||||
}
|
||||
else
|
||||
star = 0;
|
||||
nargs = 0;
|
||||
ndefs = 0;
|
||||
for (i = 0; i < nch; i++) {
|
||||
int t;
|
||||
nargs++;
|
||||
i++;
|
||||
if (i >= nch)
|
||||
break;
|
||||
t = TYPE(CHILD(n, i));
|
||||
if (t == EQUAL) {
|
||||
i++;
|
||||
ndefs++;
|
||||
com_node(c, CHILD(n, i));
|
||||
i++;
|
||||
if (i >= nch)
|
||||
break;
|
||||
t = TYPE(CHILD(n, i));
|
||||
}
|
||||
else {
|
||||
/* Treat "(a=1, b)" as "(a=1, b=None)" */
|
||||
if (ndefs) {
|
||||
com_addoparg(c, LOAD_CONST,
|
||||
com_addconst(c, None));
|
||||
ndefs++;
|
||||
}
|
||||
}
|
||||
if (t != COMMA)
|
||||
break;
|
||||
}
|
||||
if (star)
|
||||
nargs ^= 0x4000;
|
||||
*argcount_return = nargs;
|
||||
if (ndefs > 0)
|
||||
com_addoparg(c, BUILD_TUPLE, ndefs);
|
||||
return ndefs;
|
||||
}
|
||||
|
||||
static void
|
||||
com_funcdef(c, n)
|
||||
struct compiling *c;
|
||||
|
@ -1842,8 +1937,12 @@ com_funcdef(c, n)
|
|||
c->c_errors++;
|
||||
else {
|
||||
int i = com_addconst(c, v);
|
||||
int argcount;
|
||||
int ndefs = com_argdefs(c, n, &argcount);
|
||||
com_addoparg(c, LOAD_CONST, i);
|
||||
com_addbyte(c, BUILD_FUNCTION);
|
||||
if (ndefs > 0)
|
||||
com_addoparg(c, SET_FUNC_ARGS, argcount);
|
||||
com_addopname(c, STORE_NAME, CHILD(n, 1));
|
||||
DECREF(v);
|
||||
}
|
||||
|
@ -2082,25 +2181,52 @@ com_arglist(c, n)
|
|||
struct compiling *c;
|
||||
node *n;
|
||||
{
|
||||
int i, nargs, op;
|
||||
int nch, op, nargs, i, t;
|
||||
REQ(n, varargslist);
|
||||
/* varargslist:
|
||||
(fpdef ',')* '*' NAME | fpdef (',' fpdef)* [','] */
|
||||
op = UNPACK_ARG;
|
||||
nargs = (NCH(n) + 1) / 2;
|
||||
for (i = 0; i < NCH(n); i += 2) {
|
||||
int t = TYPE(CHILD(n, i));
|
||||
if (t == STAR) {
|
||||
op = UNPACK_VARARG;
|
||||
nargs = i/2;
|
||||
(fpdef ['=' test] ',')* '*' NAME |
|
||||
fpdef ['=' test] (',' fpdef ['=' test])* [','] */
|
||||
nch = NCH(n);
|
||||
if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) {
|
||||
op = UNPACK_VARARG;
|
||||
nch -= 2;
|
||||
}
|
||||
else
|
||||
op = UNPACK_ARG;
|
||||
nargs = 0;
|
||||
for (i = 0; i < nch; i++) {
|
||||
nargs++;
|
||||
i++;
|
||||
if (i >= nch)
|
||||
break;
|
||||
t = TYPE(CHILD(n, i));
|
||||
if (t == EQUAL) {
|
||||
i += 2;
|
||||
if (i >= nch)
|
||||
break;
|
||||
t = TYPE(CHILD(n, i));
|
||||
}
|
||||
if (t != COMMA)
|
||||
break;
|
||||
}
|
||||
com_addoparg(c, op, nargs);
|
||||
for (i = 0; i < 2*nargs; i += 2)
|
||||
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));
|
||||
}
|
||||
if (t != COMMA)
|
||||
break;
|
||||
}
|
||||
if (op == UNPACK_VARARG)
|
||||
com_addopname(c, STORE_NAME, CHILD(n, 2*nargs+1));
|
||||
com_addopname(c, STORE_NAME, CHILD(n, nch+1));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2175,11 +2301,13 @@ compile_node(c, n)
|
|||
|
||||
case single_input: /* One interactive command */
|
||||
/* NEWLINE | simple_stmt | compound_stmt NEWLINE */
|
||||
c->c_interactive++;
|
||||
n = CHILD(n, 0);
|
||||
if (TYPE(n) != NEWLINE)
|
||||
com_node(c, n);
|
||||
com_addoparg(c, LOAD_CONST, com_addconst(c, None));
|
||||
com_addbyte(c, RETURN_VALUE);
|
||||
c->c_interactive--;
|
||||
break;
|
||||
|
||||
case file_input: /* A whole file, or built-in function exec() */
|
||||
|
@ -2222,23 +2350,21 @@ compile_node(c, n)
|
|||
instructions that refer to local variables with LOAD_FAST etc.
|
||||
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 and IMPORT_FROM
|
||||
instructions. This yields all local variables, including arguments,
|
||||
function definitions, class definitions and import statements.
|
||||
(We don't check DELETE_NAME instructions, since if there's no
|
||||
STORE_NAME the DELETE_NAME will surely fail.)
|
||||
|
||||
There is one problem: 'from foo import *' introduces local variables
|
||||
that we can't know while compiling. If this is the case, wo don't
|
||||
optimize at all (this rarely happens, since this form of import
|
||||
statement is mostly used at the module level).
|
||||
|
||||
Note that, because of this optimization, code like the following
|
||||
won't work:
|
||||
eval('x = 1')
|
||||
print x
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
NB: this modifies the string object co->co_code!
|
||||
*/
|
||||
|
||||
|
@ -2300,7 +2426,7 @@ optimize(c)
|
|||
}
|
||||
}
|
||||
|
||||
if (nlocals == 0 || dictlookup(locals, "*") != NULL) {
|
||||
if (dictlookup(locals, "*") != NULL) {
|
||||
/* Don't optimize anything */
|
||||
goto end;
|
||||
}
|
||||
|
@ -2315,7 +2441,26 @@ optimize(c)
|
|||
if (HAS_ARG(opcode))
|
||||
oparg = NEXTARG();
|
||||
if (opcode == RESERVE_FAST) {
|
||||
int i = com_addconst(c, locals);
|
||||
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;
|
||||
|
@ -2332,6 +2477,8 @@ optimize(c)
|
|||
v = dict2lookup(locals, name);
|
||||
if (v == NULL) {
|
||||
err_clear();
|
||||
if (opcode == LOAD_NAME)
|
||||
cur_instr[0] = LOAD_GLOBAL;
|
||||
continue;
|
||||
}
|
||||
i = getintvalue(v);
|
||||
|
|
Loading…
Reference in New Issue