summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c283
1 files changed, 276 insertions, 7 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 7bbcd62..15159f8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -744,11 +744,15 @@ static int com_add(struct compiling *, PyObject *, PyObject *, PyObject *);
static int com_addconst(struct compiling *, PyObject *);
static int com_addname(struct compiling *, PyObject *);
static void com_addopname(struct compiling *, int, node *);
+static void com_test(struct compiling *c, node *n);
static void com_list(struct compiling *, node *, int);
static void com_list_iter(struct compiling *, node *, node *, char *);
+static void com_gen_iter(struct compiling *, node *, node *);
static int com_argdefs(struct compiling *, node *);
static void com_assign(struct compiling *, node *, int, node *);
static void com_assign_name(struct compiling *, node *, int);
+static int com_make_closure(struct compiling *c, PyCodeObject *co);
+
static PyCodeObject *icompile(node *, struct compiling *);
static PyCodeObject *jcompile(node *, const char *, struct compiling *,
PyCompilerFlags *);
@@ -759,6 +763,7 @@ static node *get_rawdocstring(node *);
static int get_ref_type(struct compiling *, char *);
/* symtable operations */
+static int symtable_lookup(struct symtable *st, char *name);
static struct symtable *symtable_build(node *, PyFutureFeatures *,
const char *filename);
static int symtable_load_symbols(struct compiling *);
@@ -777,7 +782,10 @@ static void symtable_global(struct symtable *, node *);
static void symtable_import(struct symtable *, node *);
static void symtable_assign(struct symtable *, node *, int);
static void symtable_list_comprehension(struct symtable *, node *);
+static void symtable_generator_expression(struct symtable *, node *);
static void symtable_list_for(struct symtable *, node *);
+static void symtable_gen_for(struct symtable *, node *, int);
+static void symtable_gen_iter(struct symtable *, node *);
static int symtable_update_free_vars(struct symtable *);
static int symtable_undo_free(struct symtable *, PyObject *, PyObject *);
@@ -1589,7 +1597,7 @@ com_list_for(struct compiling *c, node *n, node *e, char *t)
int anchor = 0;
int save_begin = c->c_begin;
- /* list_iter: for v in expr [list_iter] */
+ /* list_for: for v in expr [list_iter] */
com_node(c, CHILD(n, 3)); /* expr */
com_addbyte(c, GET_ITER);
c->c_begin = c->c_nexti;
@@ -1606,6 +1614,52 @@ com_list_for(struct compiling *c, node *n, node *e, char *t)
}
static void
+com_gen_for(struct compiling *c, node *n, node *t, int is_outmost)
+{
+ int break_anchor = 0;
+ int anchor = 0;
+ int save_begin = c->c_begin;
+
+ REQ(n, gen_for);
+ /* gen_for: for v in test [gen_iter] */
+
+ com_addfwref(c, SETUP_LOOP, &break_anchor);
+ block_push(c, SETUP_LOOP);
+
+ if (is_outmost) {
+ com_addop_varname(c, VAR_LOAD, "[outmost-iterable]");
+ com_push(c, 1);
+ }
+ else {
+ com_node(c, CHILD(n, 3));
+ com_addbyte(c, GET_ITER);
+ }
+
+ c->c_begin = c->c_nexti;
+ com_set_lineno(c, c->c_last_line);
+ com_addfwref(c, FOR_ITER, &anchor);
+ com_push(c, 1);
+ com_assign(c, CHILD(n, 1), OP_ASSIGN, NULL);
+
+ if (NCH(n) == 5)
+ com_gen_iter(c, CHILD(n, 4), t);
+ else {
+ com_test(c, t);
+ com_addbyte(c, YIELD_VALUE);
+ com_pop(c, 1);
+ }
+
+ com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
+ c->c_begin = save_begin;
+
+ com_backpatch(c, anchor);
+ com_pop(c, 1); /* FOR_ITER has popped this */
+ com_addbyte(c, POP_BLOCK);
+ block_pop(c, SETUP_LOOP);
+ com_backpatch(c, break_anchor);
+}
+
+static void
com_list_if(struct compiling *c, node *n, node *e, char *t)
{
int anchor = 0;
@@ -1624,6 +1678,32 @@ com_list_if(struct compiling *c, node *n, node *e, char *t)
}
static void
+com_gen_if(struct compiling *c, node *n, node *t)
+{
+ /* gen_if: 'if' test [gen_iter] */
+ int anchor = 0;
+ int a=0;
+
+ com_node(c, CHILD(n, 1));
+ com_addfwref(c, JUMP_IF_FALSE, &a);
+ com_addbyte(c, POP_TOP);
+ com_pop(c, 1);
+
+ if (NCH(n) == 3)
+ com_gen_iter(c, CHILD(n, 2), t);
+ else {
+ com_test(c, t);
+ com_addbyte(c, YIELD_VALUE);
+ com_pop(c, 1);
+ }
+ com_addfwref(c, JUMP_FORWARD, &anchor);
+ com_backpatch(c, a);
+ /* We jump here with an extra entry which we now pop */
+ com_addbyte(c, POP_TOP);
+ com_backpatch(c, anchor);
+}
+
+static void
com_list_iter(struct compiling *c,
node *p, /* parent of list_iter node */
node *e, /* element expression node */
@@ -1655,6 +1735,28 @@ com_list_iter(struct compiling *c,
}
static void
+com_gen_iter(struct compiling *c, node *n, node *t)
+{
+ /* gen_iter: gen_for | gen_if */
+ node *ch;
+ REQ(n, gen_iter);
+
+ ch = CHILD(n, 0);
+
+ switch (TYPE(ch)) {
+ case gen_for:
+ com_gen_for(c, ch, t, 0);
+ break;
+ case gen_if:
+ com_gen_if(c, ch, t);
+ break;
+ default:
+ com_error(c, PyExc_SystemError,
+ "invalid gen_iter node type");
+ }
+}
+
+static void
com_list_comprehension(struct compiling *c, node *n)
{
/* listmaker: test list_for */
@@ -1689,6 +1791,52 @@ com_listmaker(struct compiling *c, node *n)
}
static void
+com_generator_expression(struct compiling *c, node *n)
+{
+ /* testlist_gexp: test gen_for */
+ /* argument: test gen_for */
+ PyCodeObject *co;
+
+ REQ(CHILD(n, 0), test);
+ REQ(CHILD(n, 1), gen_for);
+
+ symtable_enter_scope(c->c_symtable, "<genexpr>", TYPE(n),
+ n->n_lineno);
+ co = icompile(n, c);
+ symtable_exit_scope(c->c_symtable);
+
+ if (co == NULL)
+ c->c_errors++;
+ else {
+ int closure = com_make_closure(c, co);
+ int i = com_addconst(c, (PyObject *)co);
+
+ com_addoparg(c, LOAD_CONST, i);
+ com_push(c, 1);
+ if (closure)
+ com_addoparg(c, MAKE_CLOSURE, 0);
+ else
+ com_addoparg(c, MAKE_FUNCTION, 0);
+
+ com_test(c, CHILD(CHILD(n, 1), 3));
+ com_addbyte(c, GET_ITER);
+ com_addoparg(c, CALL_FUNCTION, 1);
+ com_pop(c, 1);
+
+ Py_DECREF(co);
+ }
+}
+
+static void
+com_testlist_gexp(struct compiling *c, node *n)
+{
+ /* testlist_gexp: test ( gen_for | (',' test)* [','] ) */
+ if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for)
+ com_generator_expression(c, n);
+ else com_list(c, n, 0);
+}
+
+static void
com_dictmaker(struct compiling *c, node *n)
{
int i;
@@ -1721,7 +1869,7 @@ com_atom(struct compiling *c, node *n)
com_push(c, 1);
}
else
- com_node(c, CHILD(n, 1));
+ com_testlist_gexp(c, CHILD(n, 1));
break;
case LSQB: /* '[' [listmaker] ']' */
if (TYPE(CHILD(n, 1)) == RSQB) {
@@ -1857,7 +2005,7 @@ static void
com_argument(struct compiling *c, node *n, PyObject **pkeywords)
{
node *m;
- REQ(n, argument); /* [test '='] test; really [keyword '='] test */
+ REQ(n, argument); /* [test '='] test [gen_for]; really [keyword '='] test */
if (NCH(n) == 1) {
if (*pkeywords != NULL) {
com_error(c, PyExc_SyntaxError,
@@ -1868,6 +2016,11 @@ com_argument(struct compiling *c, node *n, PyObject **pkeywords)
}
return;
}
+ if (NCH(n) == 2) {
+ com_generator_expression(c, n);
+ return;
+ }
+
m = n;
do {
m = CHILD(m, 0);
@@ -2723,7 +2876,8 @@ static void
com_assign_sequence(struct compiling *c, node *n, int assigning)
{
int i;
- if (TYPE(n) != testlist && TYPE(n) != listmaker)
+ if (TYPE(n) != testlist && TYPE(n) != testlist_gexp &&
+ TYPE(n) != listmaker)
REQ(n, exprlist);
if (assigning) {
i = (NCH(n)+1)/2;
@@ -2765,7 +2919,13 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
case exprlist:
case testlist:
case testlist1:
+ case testlist_gexp:
if (NCH(n) > 1) {
+ if (TYPE(CHILD(n, 1)) == gen_for) {
+ com_error(c, PyExc_SystemError,
+ "assign to generator expression not possible");
+ return;
+ }
if (assigning > OP_APPLY) {
com_error(c, PyExc_SyntaxError,
"augmented assign to tuple not possible");
@@ -4253,6 +4413,23 @@ compile_classdef(struct compiling *c, node *n)
}
static void
+compile_generator_expression(struct compiling *c, node *n)
+{
+ /* testlist_gexp: test gen_for */
+ /* argument: test gen_for */
+ REQ(CHILD(n, 0), test);
+ REQ(CHILD(n, 1), gen_for);
+
+ c->c_name = "<generator expression>";
+ com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1);
+
+ com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
+ com_push(c, 1);
+ com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
+}
+
+static void
compile_node(struct compiling *c, node *n)
{
com_set_lineno(c, n->n_lineno);
@@ -4300,6 +4477,11 @@ compile_node(struct compiling *c, node *n)
compile_classdef(c, n);
break;
+ case testlist_gexp: /* A generator expression */
+ case argument: /* A generator expression */
+ compile_generator_expression(c, n);
+ break;
+
default:
com_error(c, PyExc_SystemError,
"compile_node: unexpected node type");
@@ -4976,7 +5158,6 @@ symtable_load_symbols(struct compiling *c)
}
}
}
-
assert(PyDict_Size(c->c_freevars) == si.si_nfrees);
if (si.si_ncells > 1) { /* one cell is always in order */
@@ -5346,11 +5527,11 @@ look_for_yield(node *n)
return 0;
case yield_stmt:
- return 1;
+ return GENERATOR;
default:
if (look_for_yield(kid))
- return 1;
+ return GENERATOR;
}
}
return 0;
@@ -5494,6 +5675,18 @@ symtable_node(struct symtable *st, node *n)
if (TYPE(CHILD(n, i)) >= single_input)
symtable_node(st, CHILD(n, i));
break;
+ case arglist:
+ if (NCH(n) > 1)
+ for (i = 0; i < NCH(n); ++i) {
+ node *ch = CHILD(n, i);
+ if (TYPE(ch) == argument && NCH(ch) == 2 &&
+ TYPE(CHILD(ch, 1)) == gen_for) {
+ PyErr_SetString(PyExc_SyntaxError,
+ "invalid syntax");
+ symtable_error(st, n->n_lineno);
+ return;
+ }
+ }
/* The remaining cases fall through to default except in
special circumstances. This requires the individual cases
to be coded with great care, even though they look like
@@ -5504,6 +5697,11 @@ symtable_node(struct symtable *st, node *n)
n = CHILD(n, 2);
goto loop;
}
+ else if (TYPE(n) == argument && NCH(n) == 2 &&
+ TYPE(CHILD(n, 1)) == gen_for) {
+ symtable_generator_expression(st, n);
+ break;
+ }
/* fall through */
case listmaker:
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) {
@@ -5511,6 +5709,13 @@ symtable_node(struct symtable *st, node *n)
break;
}
/* fall through */
+ case testlist_gexp:
+ if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
+ symtable_generator_expression(st, n);
+ break;
+ }
+ /* fall through */
+
case atom:
if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
symtable_add_use(st, STR(CHILD(n, 0)));
@@ -5715,6 +5920,26 @@ symtable_list_comprehension(struct symtable *st, node *n)
}
static void
+symtable_generator_expression(struct symtable *st, node *n)
+{
+ /* testlist_gexp: test gen_for */
+ REQ(CHILD(n, 0), test);
+ REQ(CHILD(n, 1), gen_for);
+
+ symtable_enter_scope(st, "<genexpr>", TYPE(n), n->n_lineno);
+ st->st_cur->ste_generator = GENERATOR_EXPRESSION;
+
+ symtable_add_def(st, "[outmost-iterable]", DEF_PARAM);
+
+ symtable_gen_for(st, CHILD(n, 1), 1);
+ symtable_node(st, CHILD(n, 0));
+ symtable_exit_scope(st);
+
+ /* for outmost iterable precomputation */
+ symtable_node(st, CHILD(CHILD(n, 1), 3));
+}
+
+static void
symtable_list_for(struct symtable *st, node *n)
{
REQ(n, list_for);
@@ -5726,6 +5951,39 @@ symtable_list_for(struct symtable *st, node *n)
}
static void
+symtable_gen_for(struct symtable *st, node *n, int is_outmost)
+{
+ REQ(n, gen_for);
+
+ /* gen_for: for v in test [gen_iter] */
+ symtable_assign(st, CHILD(n, 1), 0);
+ if (is_outmost)
+ symtable_add_use(st, "[outmost-iterable]");
+ else
+ symtable_node(st, CHILD(n, 3));
+
+ if (NCH(n) == 5)
+ symtable_gen_iter(st, CHILD(n, 4));
+}
+
+static void
+symtable_gen_iter(struct symtable *st, node *n)
+{
+ REQ(n, gen_iter);
+
+ n = CHILD(n, 0);
+ if (TYPE(n) == gen_for)
+ symtable_gen_for(st, n, 0);
+ else {
+ REQ(n, gen_if);
+ symtable_node(st, CHILD(n, 1));
+
+ if (NCH(n) == 3)
+ symtable_gen_iter(st, CHILD(n, 2));
+ }
+}
+
+static void
symtable_import(struct symtable *st, node *n)
{
int i;
@@ -5813,6 +6071,17 @@ symtable_assign(struct symtable *st, node *n, int def_flag)
symtable_assign(st, CHILD(n, i), def_flag);
}
return;
+ case testlist_gexp:
+ if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) {
+ /* XXX This is an error, but the next pass
+ will catch it. */
+ return;
+ } else {
+ for (i = 0; i < NCH(n); i += 2)
+ symtable_assign(st, CHILD(n, i), def_flag);
+ }
+ return;
+
case exprlist:
case testlist:
case testlist1: