diff options
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 283 |
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: |