summaryrefslogtreecommitdiff
path: root/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c637
1 files changed, 310 insertions, 327 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 6650504ec0..119c60f9b2 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -39,6 +39,10 @@ int Py_OptimizeFlag = 0;
#define DEFAULT_CODE_SIZE 128
#define DEFAULT_LNOTAB_SIZE 16
+#define COMP_GENEXP 0
+#define COMP_SETCOMP 1
+#define COMP_DICTCOMP 2
+
struct instr {
unsigned i_jabs : 1;
unsigned i_jrel : 1;
@@ -111,7 +115,6 @@ struct compiler_unit {
members, you can reach all early allocated blocks. */
basicblock *u_blocks;
basicblock *u_curblock; /* pointer to current block */
- int u_tmpname; /* temporary variables for list comps */
int u_nfblocks;
struct fblockinfo u_fblock[CO_MAXBLOCKS];
@@ -140,7 +143,6 @@ struct compiler {
struct compiler_unit *u; /* compiler state for current block */
PyObject *c_stack; /* Python list holding compiler_unit ptrs */
- char *c_encoding; /* source encoding (a borrowed reference) */
PyArena *c_arena; /* pointer to memory allocation arena */
};
@@ -179,6 +181,8 @@ static int compiler_with(struct compiler *, stmt_ty);
static PyCodeObject *assemble(struct compiler *, int addNone);
static PyObject *__doc__;
+#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit"
+
PyObject *
_Py_Mangle(PyObject *privateobj, PyObject *ident)
{
@@ -282,9 +286,6 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags,
goto finally;
}
- /* XXX initialize to NULL for now, need to handle */
- c.c_encoding = NULL;
-
co = compiler_mod(&c, mod);
finally:
@@ -472,7 +473,6 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
}
u->u_blocks = NULL;
- u->u_tmpname = 0;
u->u_nfblocks = 0;
u->u_firstlineno = lineno;
u->u_lineno = 0;
@@ -492,13 +492,13 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
/* Push the old compiler_unit on the stack. */
if (c->u) {
- PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL);
- if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) {
- Py_XDECREF(wrapper);
+ PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL);
+ if (!capsule || PyList_Append(c->c_stack, capsule) < 0) {
+ Py_XDECREF(capsule);
compiler_unit_free(u);
return 0;
}
- Py_DECREF(wrapper);
+ Py_DECREF(capsule);
u->u_private = c->u->u_private;
Py_XINCREF(u->u_private);
}
@@ -515,15 +515,15 @@ static void
compiler_exit_scope(struct compiler *c)
{
int n;
- PyObject *wrapper;
+ PyObject *capsule;
c->c_nestlevel--;
compiler_unit_free(c->u);
/* Restore c->u to the parent unit. */
n = PyList_GET_SIZE(c->c_stack) - 1;
if (n >= 0) {
- wrapper = PyList_GET_ITEM(c->c_stack, n);
- c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
+ capsule = PyList_GET_ITEM(c->c_stack, n);
+ c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
assert(c->u);
/* we are deleting from a list so this really shouldn't fail */
if (PySequence_DelItem(c->c_stack, n) < 0)
@@ -535,18 +535,6 @@ compiler_exit_scope(struct compiler *c)
}
-/* Allocate a new "anonymous" local variable.
- Used by list comprehensions and with statements.
-*/
-
-static PyObject *
-compiler_new_tmpname(struct compiler *c)
-{
- char tmpname[256];
- PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname);
- return PyString_FromString(tmpname);
-}
-
/* Allocate a new block and return a pointer to it.
Returns NULL on error.
*/
@@ -692,7 +680,11 @@ opcode_stack_effect(int opcode, int oparg)
case UNARY_INVERT:
return 0;
+ case SET_ADD:
case LIST_APPEND:
+ return -1;
+
+ case MAP_ADD:
return -2;
case BINARY_POWER:
@@ -710,13 +702,13 @@ opcode_stack_effect(int opcode, int oparg)
return -1;
case SLICE+0:
- return 1;
- case SLICE+1:
return 0;
+ case SLICE+1:
+ return -1;
case SLICE+2:
- return 0;
- case SLICE+3:
return -1;
+ case SLICE+3:
+ return -2;
case STORE_SLICE+0:
return -2;
@@ -778,6 +770,8 @@ opcode_stack_effect(int opcode, int oparg)
return -1;
case BREAK_LOOP:
return 0;
+ case SETUP_WITH:
+ return 4;
case WITH_CLEANUP:
return -1; /* XXX Sometimes more */
case LOAD_LOCALS:
@@ -794,7 +788,8 @@ opcode_stack_effect(int opcode, int oparg)
case POP_BLOCK:
return 0;
case END_FINALLY:
- return -1; /* or -2 or -3 if exception occurred */
+ return -3; /* or -1 or -2 if no exception occurred or
+ return/break/continue */
case BUILD_CLASS:
return -2;
@@ -805,7 +800,7 @@ opcode_stack_effect(int opcode, int oparg)
case UNPACK_SEQUENCE:
return oparg-1;
case FOR_ITER:
- return 1;
+ return 1; /* or -1, at end of iterator */
case STORE_ATTR:
return -2;
@@ -823,6 +818,7 @@ opcode_stack_effect(int opcode, int oparg)
return 1;
case BUILD_TUPLE:
case BUILD_LIST:
+ case BUILD_SET:
return 1-oparg;
case BUILD_MAP:
return 1;
@@ -831,26 +827,29 @@ opcode_stack_effect(int opcode, int oparg)
case COMPARE_OP:
return -1;
case IMPORT_NAME:
- return 0;
+ return -1;
case IMPORT_FROM:
return 1;
case JUMP_FORWARD:
- case JUMP_IF_FALSE:
- case JUMP_IF_TRUE:
+ case JUMP_IF_TRUE_OR_POP: /* -1 if jump not taken */
+ case JUMP_IF_FALSE_OR_POP: /* "" */
case JUMP_ABSOLUTE:
return 0;
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE:
+ return -1;
+
case LOAD_GLOBAL:
return 1;
case CONTINUE_LOOP:
return 0;
case SETUP_LOOP:
- return 0;
case SETUP_EXCEPT:
case SETUP_FINALLY:
- return 3; /* actually pushed by an exception */
+ return 0;
case LOAD_FAST:
return 1;
@@ -879,7 +878,7 @@ opcode_stack_effect(int opcode, int oparg)
return -1;
case MAKE_CLOSURE:
- return -oparg;
+ return -oparg-1;
case LOAD_CLOSURE:
return 1;
case LOAD_DEREF:
@@ -1246,7 +1245,7 @@ get_ref_type(struct compiler *c, PyObject *name)
char buf[350];
PyOS_snprintf(buf, sizeof(buf),
"unknown scope for %.100s in %.100s(%s) in %s\n"
- "symbols: %s\nlocals: %s\nglobals: %s\n",
+ "symbols: %s\nlocals: %s\nglobals: %s",
PyString_AS_STRING(name),
PyString_AS_STRING(c->u->u_name),
PyObject_REPR(c->u->u_ste->ste_id),
@@ -1491,12 +1490,10 @@ compiler_ifexp(struct compiler *c, expr_ty e)
if (next == NULL)
return 0;
VISIT(c, expr, e->v.IfExp.test);
- ADDOP_JREL(c, JUMP_IF_FALSE, next);
- ADDOP(c, POP_TOP);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
VISIT(c, expr, e->v.IfExp.body);
ADDOP_JREL(c, JUMP_FORWARD, end);
compiler_use_next_block(c, next);
- ADDOP(c, POP_TOP);
VISIT(c, expr, e->v.IfExp.orelse);
compiler_use_next_block(c, end);
return 1;
@@ -1524,9 +1521,19 @@ compiler_lambda(struct compiler *c, expr_ty e)
/* unpack nested arguments */
compiler_arguments(c, args);
+ /* Make None the first constant, so the lambda can't have a
+ docstring. */
+ if (compiler_add_o(c, c->u->u_consts, Py_None) < 0)
+ return 0;
+
c->u->u_argcount = asdl_seq_LEN(args->args);
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
- ADDOP_IN_SCOPE(c, RETURN_VALUE);
+ if (c->u->u_ste->ste_generator) {
+ ADDOP_IN_SCOPE(c, POP_TOP);
+ }
+ else {
+ ADDOP_IN_SCOPE(c, RETURN_VALUE);
+ }
co = assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL)
@@ -1584,9 +1591,6 @@ compiler_if(struct compiler *c, stmt_ty s)
end = compiler_new_block(c);
if (end == NULL)
return 0;
- next = compiler_new_block(c);
- if (next == NULL)
- return 0;
constant = expr_constant(s->v.If.test);
/* constant = 0: "if 0"
@@ -1598,15 +1602,21 @@ compiler_if(struct compiler *c, stmt_ty s)
} else if (constant == 1) {
VISIT_SEQ(c, stmt, s->v.If.body);
} else {
+ if (s->v.If.orelse) {
+ next = compiler_new_block(c);
+ if (next == NULL)
+ return 0;
+ }
+ else
+ next = end;
VISIT(c, expr, s->v.If.test);
- ADDOP_JREL(c, JUMP_IF_FALSE, next);
- ADDOP(c, POP_TOP);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, next);
VISIT_SEQ(c, stmt, s->v.If.body);
ADDOP_JREL(c, JUMP_FORWARD, end);
- compiler_use_next_block(c, next);
- ADDOP(c, POP_TOP);
- if (s->v.If.orelse)
+ if (s->v.If.orelse) {
+ compiler_use_next_block(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
+ }
}
compiler_use_next_block(c, end);
return 1;
@@ -1628,9 +1638,6 @@ compiler_for(struct compiler *c, stmt_ty s)
VISIT(c, expr, s->v.For.iter);
ADDOP(c, GET_ITER);
compiler_use_next_block(c, start);
- /* for expressions must be traced on each iteration,
- so we need to set an extra line number. */
- c->u->u_lineno_set = false;
ADDOP_JREL(c, FOR_ITER, cleanup);
VISIT(c, expr, s->v.For.target);
VISIT_SEQ(c, stmt, s->v.For.body);
@@ -1676,12 +1683,8 @@ compiler_while(struct compiler *c, stmt_ty s)
if (!compiler_push_fblock(c, LOOP, loop))
return 0;
if (constant == -1) {
- /* while expressions must be traced on each iteration,
- so we need to set an extra line number. */
- c->u->u_lineno_set = false;
VISIT(c, expr, s->v.While.test);
- ADDOP_JREL(c, JUMP_IF_FALSE, anchor);
- ADDOP(c, POP_TOP);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor);
}
VISIT_SEQ(c, stmt, s->v.While.body);
ADDOP_JABS(c, JUMP_ABSOLUTE, loop);
@@ -1692,7 +1695,6 @@ compiler_while(struct compiler *c, stmt_ty s)
if (constant == -1) {
compiler_use_next_block(c, anchor);
- ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK);
}
compiler_pop_fblock(c, LOOP, loop);
@@ -1813,20 +1815,17 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
[tb, val, exc] L1: DUP )
[tb, val, exc, exc] <evaluate E1> )
[tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1
- [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 )
- [tb, val, exc, 1] POP )
+ [tb, val, exc, 1-or-0] POP_JUMP_IF_FALSE L2 )
[tb, val, exc] POP
[tb, val] <assign to V1> (or POP if no V1)
[tb] POP
[] <code for S1>
JUMP_FORWARD L0
- [tb, val, exc, 0] L2: POP
- [tb, val, exc] DUP
+ [tb, val, exc] L2: DUP
.............................etc.......................
- [tb, val, exc, 0] Ln+1: POP
- [tb, val, exc] END_FINALLY # re-raise exception
+ [tb, val, exc] Ln+1: END_FINALLY # re-raise exception
[] L0: <next statement>
@@ -1868,8 +1867,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP(c, DUP_TOP);
VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH);
- ADDOP_JREL(c, JUMP_IF_FALSE, except);
- ADDOP(c, POP_TOP);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, except);
}
ADDOP(c, POP_TOP);
if (handler->v.ExceptHandler.name) {
@@ -1882,8 +1880,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
ADDOP_JREL(c, JUMP_FORWARD, end);
compiler_use_next_block(c, except);
- if (handler->v.ExceptHandler.type)
- ADDOP(c, POP_TOP);
}
ADDOP(c, END_FINALLY);
compiler_use_next_block(c, orelse);
@@ -1982,6 +1978,13 @@ compiler_from_import(struct compiler *c, stmt_ty s)
PyObject *names = PyTuple_New(n);
PyObject *level;
+ static PyObject *empty_string;
+
+ if (!empty_string) {
+ empty_string = PyString_FromString("");
+ if (!empty_string)
+ return 0;
+ }
if (!names)
return 0;
@@ -2004,23 +2007,24 @@ compiler_from_import(struct compiler *c, stmt_ty s)
PyTuple_SET_ITEM(names, i, alias->name);
}
- if (s->lineno > c->c_future->ff_lineno) {
- if (!strcmp(PyString_AS_STRING(s->v.ImportFrom.module),
- "__future__")) {
- Py_DECREF(level);
- Py_DECREF(names);
- return compiler_error(c,
- "from __future__ imports must occur "
- "at the beginning of the file");
-
- }
+ if (s->lineno > c->c_future->ff_lineno && s->v.ImportFrom.module &&
+ !strcmp(PyString_AS_STRING(s->v.ImportFrom.module), "__future__")) {
+ Py_DECREF(level);
+ Py_DECREF(names);
+ return compiler_error(c, "from __future__ imports must occur "
+ "at the beginning of the file");
}
ADDOP_O(c, LOAD_CONST, level, consts);
Py_DECREF(level);
ADDOP_O(c, LOAD_CONST, names, consts);
Py_DECREF(names);
- ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names);
+ if (s->v.ImportFrom.module) {
+ ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names);
+ }
+ else {
+ ADDOP_NAME(c, IMPORT_NAME, empty_string, names);
+ }
for (i = 0; i < n; i++) {
alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i);
identifier store_name;
@@ -2071,18 +2075,14 @@ compiler_assert(struct compiler *c, stmt_ty s)
end = compiler_new_block(c);
if (end == NULL)
return 0;
- ADDOP_JREL(c, JUMP_IF_TRUE, end);
- ADDOP(c, POP_TOP);
+ ADDOP_JABS(c, POP_JUMP_IF_TRUE, end);
ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
if (s->v.Assert.msg) {
VISIT(c, expr, s->v.Assert.msg);
- ADDOP_I(c, RAISE_VARARGS, 2);
- }
- else {
- ADDOP_I(c, RAISE_VARARGS, 1);
+ ADDOP_I(c, CALL_FUNCTION, 1);
}
+ ADDOP_I(c, RAISE_VARARGS, 1);
compiler_use_next_block(c, end);
- ADDOP(c, POP_TOP);
return 1;
}
@@ -2336,12 +2336,6 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
PyObject *mangled;
/* XXX AugStore isn't used anywhere! */
- /* First check for assignment to __debug__. Param? */
- if ((ctx == Store || ctx == AugStore || ctx == Del)
- && !strcmp(PyString_AS_STRING(name), "__debug__")) {
- return compiler_error(c, "can not assign to __debug__");
- }
-
mangled = _Py_Mangle(c->u->u_private, name);
if (!mangled)
return 0;
@@ -2466,9 +2460,9 @@ compiler_boolop(struct compiler *c, expr_ty e)
assert(e->kind == BoolOp_kind);
if (e->v.BoolOp.op == And)
- jumpi = JUMP_IF_FALSE;
+ jumpi = JUMP_IF_FALSE_OR_POP;
else
- jumpi = JUMP_IF_TRUE;
+ jumpi = JUMP_IF_TRUE_OR_POP;
end = compiler_new_block(c);
if (end == NULL)
return 0;
@@ -2477,8 +2471,7 @@ compiler_boolop(struct compiler *c, expr_ty e)
assert(n >= 0);
for (i = 0; i < n; ++i) {
VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i));
- ADDOP_JREL(c, jumpi, end);
- ADDOP(c, POP_TOP)
+ ADDOP_JABS(c, jumpi, end);
}
VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n));
compiler_use_next_block(c, end);
@@ -2536,9 +2529,8 @@ compiler_compare(struct compiler *c, expr_ty e)
ADDOP_I(c, COMPARE_OP,
cmpop((cmpop_ty)(asdl_seq_GET(
e->v.Compare.ops, i - 1))));
- ADDOP_JREL(c, JUMP_IF_FALSE, cleanup);
+ ADDOP_JABS(c, JUMP_IF_FALSE_OR_POP, cleanup);
NEXT_BLOCK(c);
- ADDOP(c, POP_TOP);
if (i < (n - 1))
VISIT(c, expr,
(expr_ty)asdl_seq_GET(e->v.Compare.comparators, i));
@@ -2597,9 +2589,8 @@ compiler_call(struct compiler *c, expr_ty e)
}
static int
-compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
- asdl_seq *generators, int gen_index,
- expr_ty elt)
+compiler_listcomp_generator(struct compiler *c, asdl_seq *generators,
+ int gen_index, expr_ty elt)
{
/* generate code for the iterator, then each of the ifs,
and then write to the element */
@@ -2630,37 +2621,24 @@ compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
for (i = 0; i < n; i++) {
expr_ty e = (expr_ty)asdl_seq_GET(l->ifs, i);
VISIT(c, expr, e);
- ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
NEXT_BLOCK(c);
- ADDOP(c, POP_TOP);
}
if (++gen_index < asdl_seq_LEN(generators))
- if (!compiler_listcomp_generator(c, tmpname,
- generators, gen_index, elt))
+ if (!compiler_listcomp_generator(c, generators, gen_index, elt))
return 0;
/* only append after the last for generator */
if (gen_index >= asdl_seq_LEN(generators)) {
- if (!compiler_nameop(c, tmpname, Load))
- return 0;
VISIT(c, expr, elt);
- ADDOP(c, LIST_APPEND);
+ ADDOP_I(c, LIST_APPEND, gen_index+1);
compiler_use_next_block(c, skip);
}
- for (i = 0; i < n; i++) {
- ADDOP_I(c, JUMP_FORWARD, 1);
- if (i == 0)
- compiler_use_next_block(c, if_cleanup);
- ADDOP(c, POP_TOP);
- }
+ compiler_use_next_block(c, if_cleanup);
ADDOP_JABS(c, JUMP_ABSOLUTE, start);
compiler_use_next_block(c, anchor);
- /* delete the temporary list name added to locals */
- if (gen_index == 1)
- if (!compiler_nameop(c, tmpname, Del))
- return 0;
return 1;
}
@@ -2668,49 +2646,49 @@ compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
static int
compiler_listcomp(struct compiler *c, expr_ty e)
{
- identifier tmp;
- int rc = 0;
- asdl_seq *generators = e->v.ListComp.generators;
-
assert(e->kind == ListComp_kind);
- tmp = compiler_new_tmpname(c);
- if (!tmp)
- return 0;
ADDOP_I(c, BUILD_LIST, 0);
- ADDOP(c, DUP_TOP);
- if (compiler_nameop(c, tmp, Store))
- rc = compiler_listcomp_generator(c, tmp, generators, 0,
- e->v.ListComp.elt);
- Py_DECREF(tmp);
- return rc;
-}
+ return compiler_listcomp_generator(c, e->v.ListComp.generators, 0,
+ e->v.ListComp.elt);
+}
+
+/* Dict and set comprehensions and generator expressions work by creating a
+ nested function to perform the actual iteration. This means that the
+ iteration variables don't leak into the current scope.
+ The defined function is called immediately following its definition, with the
+ result of that call being the result of the expression.
+ The LC/SC version returns the populated container, while the GE version is
+ flagged in symtable.c as a generator, so it returns the generator object
+ when the function is called.
+ This code *knows* that the loop cannot contain break, continue, or return,
+ so it cheats and skips the SETUP_LOOP/POP_BLOCK steps used in normal loops.
+
+ Possible cleanups:
+ - iterate over the generator sequence instead of using recursion
+*/
static int
-compiler_genexp_generator(struct compiler *c,
- asdl_seq *generators, int gen_index,
- expr_ty elt)
+compiler_comprehension_generator(struct compiler *c,
+ asdl_seq *generators, int gen_index,
+ expr_ty elt, expr_ty val, int type)
{
/* generate code for the iterator, then each of the ifs,
and then write to the element */
- comprehension_ty ge;
- basicblock *start, *anchor, *skip, *if_cleanup, *end;
+ comprehension_ty gen;
+ basicblock *start, *anchor, *skip, *if_cleanup;
int i, n;
start = compiler_new_block(c);
skip = compiler_new_block(c);
if_cleanup = compiler_new_block(c);
anchor = compiler_new_block(c);
- end = compiler_new_block(c);
if (start == NULL || skip == NULL || if_cleanup == NULL ||
- anchor == NULL || end == NULL)
+ anchor == NULL)
return 0;
- ge = (comprehension_ty)asdl_seq_GET(generators, gen_index);
- ADDOP_JREL(c, SETUP_LOOP, end);
- if (!compiler_push_fblock(c, LOOP, start))
- return 0;
+ gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
if (gen_index == 0) {
/* Receive outermost iter as an implicit argument */
@@ -2719,84 +2697,164 @@ compiler_genexp_generator(struct compiler *c,
}
else {
/* Sub-iter - calculate on the fly */
- VISIT(c, expr, ge->iter);
+ VISIT(c, expr, gen->iter);
ADDOP(c, GET_ITER);
}
compiler_use_next_block(c, start);
ADDOP_JREL(c, FOR_ITER, anchor);
NEXT_BLOCK(c);
- VISIT(c, expr, ge->target);
+ VISIT(c, expr, gen->target);
/* XXX this needs to be cleaned up...a lot! */
- n = asdl_seq_LEN(ge->ifs);
+ n = asdl_seq_LEN(gen->ifs);
for (i = 0; i < n; i++) {
- expr_ty e = (expr_ty)asdl_seq_GET(ge->ifs, i);
+ expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i);
VISIT(c, expr, e);
- ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup);
+ ADDOP_JABS(c, POP_JUMP_IF_FALSE, if_cleanup);
NEXT_BLOCK(c);
- ADDOP(c, POP_TOP);
}
if (++gen_index < asdl_seq_LEN(generators))
- if (!compiler_genexp_generator(c, generators, gen_index, elt))
- return 0;
+ if (!compiler_comprehension_generator(c,
+ generators, gen_index,
+ elt, val, type))
+ return 0;
- /* only append after the last 'for' generator */
+ /* only append after the last for generator */
if (gen_index >= asdl_seq_LEN(generators)) {
- VISIT(c, expr, elt);
- ADDOP(c, YIELD_VALUE);
- ADDOP(c, POP_TOP);
+ /* comprehension specific code */
+ switch (type) {
+ case COMP_GENEXP:
+ VISIT(c, expr, elt);
+ ADDOP(c, YIELD_VALUE);
+ ADDOP(c, POP_TOP);
+ break;
+ case COMP_SETCOMP:
+ VISIT(c, expr, elt);
+ ADDOP_I(c, SET_ADD, gen_index + 1);
+ break;
+ case COMP_DICTCOMP:
+ /* With 'd[k] = v', v is evaluated before k, so we do
+ the same. */
+ VISIT(c, expr, val);
+ VISIT(c, expr, elt);
+ ADDOP_I(c, MAP_ADD, gen_index + 1);
+ break;
+ default:
+ return 0;
+ }
compiler_use_next_block(c, skip);
}
- for (i = 0; i < n; i++) {
- ADDOP_I(c, JUMP_FORWARD, 1);
- if (i == 0)
- compiler_use_next_block(c, if_cleanup);
-
- ADDOP(c, POP_TOP);
- }
+ compiler_use_next_block(c, if_cleanup);
ADDOP_JABS(c, JUMP_ABSOLUTE, start);
compiler_use_next_block(c, anchor);
- ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, LOOP, start);
- compiler_use_next_block(c, end);
return 1;
}
static int
-compiler_genexp(struct compiler *c, expr_ty e)
+compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
+ asdl_seq *generators, expr_ty elt, expr_ty val)
{
- static identifier name;
- PyCodeObject *co;
- expr_ty outermost_iter = ((comprehension_ty)
- (asdl_seq_GET(e->v.GeneratorExp.generators,
- 0)))->iter;
+ PyCodeObject *co = NULL;
+ expr_ty outermost_iter;
- if (!name) {
- name = PyString_FromString("<genexpr>");
- if (!name)
- return 0;
- }
+ outermost_iter = ((comprehension_ty)
+ asdl_seq_GET(generators, 0))->iter;
if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
- return 0;
- compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0,
- e->v.GeneratorExp.elt);
+ goto error;
+
+ if (type != COMP_GENEXP) {
+ int op;
+ switch (type) {
+ case COMP_SETCOMP:
+ op = BUILD_SET;
+ break;
+ case COMP_DICTCOMP:
+ op = BUILD_MAP;
+ break;
+ default:
+ PyErr_Format(PyExc_SystemError,
+ "unknown comprehension type %d", type);
+ goto error_in_scope;
+ }
+
+ ADDOP_I(c, op, 0);
+ }
+
+ if (!compiler_comprehension_generator(c, generators, 0, elt,
+ val, type))
+ goto error_in_scope;
+
+ if (type != COMP_GENEXP) {
+ ADDOP(c, RETURN_VALUE);
+ }
+
co = assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL)
- return 0;
+ goto error;
- compiler_make_closure(c, co, 0);
+ if (!compiler_make_closure(c, co, 0))
+ goto error;
Py_DECREF(co);
VISIT(c, expr, outermost_iter);
ADDOP(c, GET_ITER);
ADDOP_I(c, CALL_FUNCTION, 1);
-
return 1;
+error_in_scope:
+ compiler_exit_scope(c);
+error:
+ Py_XDECREF(co);
+ return 0;
+}
+
+static int
+compiler_genexp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<genexpr>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == GeneratorExp_kind);
+ return compiler_comprehension(c, e, COMP_GENEXP, name,
+ e->v.GeneratorExp.generators,
+ e->v.GeneratorExp.elt, NULL);
+}
+
+static int
+compiler_setcomp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<setcomp>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == SetComp_kind);
+ return compiler_comprehension(c, e, COMP_SETCOMP, name,
+ e->v.SetComp.generators,
+ e->v.SetComp.elt, NULL);
+}
+
+static int
+compiler_dictcomp(struct compiler *c, expr_ty e)
+{
+ static identifier name;
+ if (!name) {
+ name = PyString_FromString("<dictcomp>");
+ if (!name)
+ return 0;
+ }
+ assert(e->kind == DictComp_kind);
+ return compiler_comprehension(c, e, COMP_DICTCOMP, name,
+ e->v.DictComp.generators,
+ e->v.DictComp.key, e->v.DictComp.value);
}
static int
@@ -2859,81 +2917,35 @@ expr_constant(expr_ty e)
static int
compiler_with(struct compiler *c, stmt_ty s)
{
- static identifier enter_attr, exit_attr;
basicblock *block, *finally;
- identifier tmpvalue = NULL;
assert(s->kind == With_kind);
- if (!enter_attr) {
- enter_attr = PyString_InternFromString("__enter__");
- if (!enter_attr)
- return 0;
- }
- if (!exit_attr) {
- exit_attr = PyString_InternFromString("__exit__");
- if (!exit_attr)
- return 0;
- }
-
block = compiler_new_block(c);
finally = compiler_new_block(c);
if (!block || !finally)
return 0;
- if (s->v.With.optional_vars) {
- /* Create a temporary variable to hold context.__enter__().
- We need to do this rather than preserving it on the stack
- because SETUP_FINALLY remembers the stack level.
- We need to do the assignment *inside* the try/finally
- so that context.__exit__() is called when the assignment
- fails. But we need to call context.__enter__() *before*
- the try/finally so that if it fails we won't call
- context.__exit__().
- */
- tmpvalue = compiler_new_tmpname(c);
- if (tmpvalue == NULL)
- return 0;
- PyArena_AddPyObject(c->c_arena, tmpvalue);
- }
-
/* Evaluate EXPR */
VISIT(c, expr, s->v.With.context_expr);
+ ADDOP_JREL(c, SETUP_WITH, finally);
- /* Squirrel away context.__exit__ by stuffing it under context */
- ADDOP(c, DUP_TOP);
- ADDOP_O(c, LOAD_ATTR, exit_attr, names);
- ADDOP(c, ROT_TWO);
-
- /* Call context.__enter__() */
- ADDOP_O(c, LOAD_ATTR, enter_attr, names);
- ADDOP_I(c, CALL_FUNCTION, 0);
-
- if (s->v.With.optional_vars) {
- /* Store it in tmpvalue */
- if (!compiler_nameop(c, tmpvalue, Store))
- return 0;
- }
- else {
- /* Discard result from context.__enter__() */
- ADDOP(c, POP_TOP);
- }
-
- /* Start the try block */
- ADDOP_JREL(c, SETUP_FINALLY, finally);
-
+ /* SETUP_WITH pushes a finally block. */
compiler_use_next_block(c, block);
+ /* Note that the block is actually called SETUP_WITH in ceval.c, but
+ functions the same as SETUP_FINALLY except that exceptions are
+ normalized. */
if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
return 0;
}
if (s->v.With.optional_vars) {
- /* Bind saved result of context.__enter__() to VAR */
- if (!compiler_nameop(c, tmpvalue, Load) ||
- !compiler_nameop(c, tmpvalue, Del))
- return 0;
VISIT(c, expr, s->v.With.optional_vars);
}
+ else {
+ /* Discard result from context.__enter__() */
+ ADDOP(c, POP_TOP);
+ }
/* BLOCK code */
VISIT_SEQ(c, stmt, s->v.With.body);
@@ -2997,8 +3009,17 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
ADDOP(c, STORE_MAP);
}
break;
+ case Set_kind:
+ n = asdl_seq_LEN(e->v.Set.elts);
+ VISIT_SEQ(c, expr, e->v.Set.elts);
+ ADDOP_I(c, BUILD_SET, n);
+ break;
case ListComp_kind:
return compiler_listcomp(c, e);
+ case SetComp_kind:
+ return compiler_setcomp(c, e);
+ case DictComp_kind:
+ return compiler_dictcomp(c, e);
case GeneratorExp_kind:
return compiler_genexp(c, e);
case Yield_kind:
@@ -3423,7 +3444,7 @@ dfs(struct compiler *c, basicblock *b, struct assembler *a)
static int
stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
{
- int i;
+ int i, target_depth;
struct instr *instr;
if (b->b_seen || b->b_startdepth >= depth)
return maxdepth;
@@ -3436,8 +3457,17 @@ stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
maxdepth = depth;
assert(depth >= 0); /* invalid code or bug in stackdepth() */
if (instr->i_jrel || instr->i_jabs) {
+ target_depth = depth;
+ if (instr->i_opcode == FOR_ITER) {
+ target_depth = depth-2;
+ } else if (instr->i_opcode == SETUP_FINALLY ||
+ instr->i_opcode == SETUP_EXCEPT) {
+ target_depth = depth+3;
+ if (target_depth > maxdepth)
+ maxdepth = target_depth;
+ }
maxdepth = stackdepth_walk(c, instr->i_target,
- depth, maxdepth);
+ target_depth, maxdepth);
if (instr->i_opcode == JUMP_ABSOLUTE ||
instr->i_opcode == JUMP_FORWARD) {
goto out; /* remaining code is dead */
@@ -3525,51 +3555,9 @@ blocksize(basicblock *b)
return size;
}
-/* All about a_lnotab.
-
-c_lnotab is an array of unsigned bytes disguised as a Python string.
-It is used to map bytecode offsets to source code line #s (when needed
-for tracebacks).
-
-The array is conceptually a list of
- (bytecode offset increment, line number increment)
-pairs. The details are important and delicate, best illustrated by example:
-
- byte code offset source code line number
- 0 1
- 6 2
- 50 7
- 350 307
- 361 308
-
-The first trick is that these numbers aren't stored, only the increments
-from one row to the next (this doesn't really work, but it's a start):
-
- 0, 1, 6, 1, 44, 5, 300, 300, 11, 1
-
-The second trick is that an unsigned byte can't hold negative values, or
-values larger than 255, so (a) there's a deep assumption that byte code
-offsets and their corresponding line #s both increase monotonically, and (b)
-if at least one column jumps by more than 255 from one row to the next, more
-than one pair is written to the table. In case #b, there's no way to know
-from looking at the table later how many were written. That's the delicate
-part. A user of c_lnotab desiring to find the source line number
-corresponding to a bytecode address A should do something like this
-
- lineno = addr = 0
- for addr_incr, line_incr in c_lnotab:
- addr += addr_incr
- if addr > A:
- return lineno
- lineno += line_incr
-
-In order for this to work, when the addr field increments by more than 255,
-the line # increment in each pair generated must be 0 until the remaining addr
-increment is < 256. So, in the example above, assemble_lnotab (it used
-to be called com_set_lineno) should not (as was actually done until 2.2)
-expand 300, 300 to 255, 255, 45, 45,
- but to 255, 0, 45, 255, 0, 45.
-*/
+/* Appends a pair to the end of the line number table, a_lnotab, representing
+ the instruction's bytecode offset and line number. See
+ Objects/lnotab_notes.txt for the description of the line number table. */
static int
assemble_lnotab(struct assembler *a, struct instr *i)
@@ -3711,49 +3699,47 @@ static void
assemble_jump_offsets(struct assembler *a, struct compiler *c)
{
basicblock *b;
- int bsize, totsize, extended_arg_count, last_extended_arg_count = 0;
+ int bsize, totsize, extended_arg_count = 0, last_extended_arg_count;
int i;
/* Compute the size of each block and fixup jump args.
Replace block pointer with position in bytecode. */
-start:
- totsize = 0;
- for (i = a->a_nblocks - 1; i >= 0; i--) {
- b = a->a_postorder[i];
- bsize = blocksize(b);
- b->b_offset = totsize;
- totsize += bsize;
- }
- extended_arg_count = 0;
- for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
- bsize = b->b_offset;
- for (i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
- /* Relative jumps are computed relative to
- the instruction pointer after fetching
- the jump instruction.
- */
- bsize += instrsize(instr);
- if (instr->i_jabs)
- instr->i_oparg = instr->i_target->b_offset;
- else if (instr->i_jrel) {
- int delta = instr->i_target->b_offset - bsize;
- instr->i_oparg = delta;
+ do {
+ totsize = 0;
+ for (i = a->a_nblocks - 1; i >= 0; i--) {
+ b = a->a_postorder[i];
+ bsize = blocksize(b);
+ b->b_offset = totsize;
+ totsize += bsize;
+ }
+ last_extended_arg_count = extended_arg_count;
+ extended_arg_count = 0;
+ for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
+ bsize = b->b_offset;
+ for (i = 0; i < b->b_iused; i++) {
+ struct instr *instr = &b->b_instr[i];
+ /* Relative jumps are computed relative to
+ the instruction pointer after fetching
+ the jump instruction.
+ */
+ bsize += instrsize(instr);
+ if (instr->i_jabs)
+ instr->i_oparg = instr->i_target->b_offset;
+ else if (instr->i_jrel) {
+ int delta = instr->i_target->b_offset - bsize;
+ instr->i_oparg = delta;
+ }
+ else
+ continue;
+ if (instr->i_oparg > 0xffff)
+ extended_arg_count++;
}
- else
- continue;
- if (instr->i_oparg > 0xffff)
- extended_arg_count++;
}
- }
/* XXX: This is an awful hack that could hurt performance, but
on the bright side it should work until we come up
with a better solution.
- In the meantime, should the goto be dropped in favor
- of a loop?
-
The issue is that in the first loop blocksize() is called
which calls instrsize() which requires i_oparg be set
appropriately. There is a bootstrap problem because
@@ -3764,10 +3750,7 @@ start:
ones in jump instructions. So this should converge
fairly quickly.
*/
- if (last_extended_arg_count != extended_arg_count) {
- last_extended_arg_count = extended_arg_count;
- goto start;
- }
+ } while (last_extended_arg_count != extended_arg_count);
}
static PyObject *
@@ -3781,6 +3764,8 @@ dict_keys_inorder(PyObject *dict, int offset)
return NULL;
while (PyDict_Next(dict, &pos, &k, &v)) {
i = PyInt_AS_LONG(v);
+ /* The keys of the dictionary are tuples. (see compiler_add_o)
+ The object we want is always first, though. */
k = PyTuple_GET_ITEM(k, 0);
Py_INCREF(k);
assert((i - offset) < size);
@@ -3804,13 +3789,11 @@ compute_code_flags(struct compiler *c)
flags |= CO_NESTED;
if (ste->ste_generator)
flags |= CO_GENERATOR;
+ if (ste->ste_varargs)
+ flags |= CO_VARARGS;
+ if (ste->ste_varkeywords)
+ flags |= CO_VARKEYWORDS;
}
- if (ste->ste_varargs)
- flags |= CO_VARARGS;
- if (ste->ste_varkeywords)
- flags |= CO_VARKEYWORDS;
- if (ste->ste_generator)
- flags |= CO_GENERATOR;
/* (Only) inherit compilerflags in PyCF_MASK */
flags |= (c->c_flags->cf_flags & PyCF_MASK);