diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2007-04-15 12:05:43 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2007-04-15 12:05:43 (GMT) |
commit | 650f0d06d3574f843f52edd1126ddd9ebd6fac7d (patch) | |
tree | 9116cebfb4031d0ac3b2db7dc0e8c85d82751e59 /Python/ast.c | |
parent | 6ef6306dd62aa092539298ed69c7c6ffff568e2d (diff) | |
download | cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.zip cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.tar.gz cpython-650f0d06d3574f843f52edd1126ddd9ebd6fac7d.tar.bz2 |
Hide list comp variables and support set comprehensions
Diffstat (limited to 'Python/ast.c')
-rw-r--r-- | Python/ast.c | 366 |
1 files changed, 111 insertions, 255 deletions
diff --git a/Python/ast.c b/Python/ast.c index 777c00e..262ade3 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -27,7 +27,6 @@ static stmt_ty ast_for_stmt(struct compiling *, const node *); static asdl_seq *ast_for_suite(struct compiling *, const node *); static asdl_seq *ast_for_exprlist(struct compiling *, const node *, expr_context_ty); static expr_ty ast_for_testlist(struct compiling *, const node *); -static expr_ty ast_for_testlist_gexp(struct compiling *, const node *); /* Note different signature for ast_for_call */ static expr_ty ast_for_call(struct compiling *, const node *, expr_ty); @@ -41,6 +40,10 @@ static PyObject *parsestrplus(struct compiling *, const node *n, #define LINENO(n) ((n)->n_lineno) #endif +#define COMP_GENEXP 0 +#define COMP_LISTCOMP 1 +#define COMP_SETCOMP 2 + static identifier new_identifier(const char* n, PyArena *arena) { PyObject* id = PyString_InternFromString(n); @@ -231,7 +234,7 @@ PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename, case eval_input: { expr_ty testlist_ast; - /* XXX Why not gen_for here? */ + /* XXX Why not comp_for here? */ testlist_ast = ast_for_testlist(&c, CHILD(n, 0)); if (!testlist_ast) goto error; @@ -530,19 +533,14 @@ seq_for_testlist(struct compiling *c, const node *n) asdl_seq *seq; expr_ty expression; int i; - assert(TYPE(n) == testlist - || TYPE(n) == listmaker - || TYPE(n) == testlist_gexp - || TYPE(n) == testlist_safe - || TYPE(n) == testlist1 - ); + assert(TYPE(n) == testlist || TYPE(n) == testlist_comp); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) return NULL; for (i = 0; i < NCH(n); i += 2) { - assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); + assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == test_nocond); expression = ast_for_expr(c, CHILD(n, i)); if (!expression) @@ -1022,7 +1020,8 @@ ast_for_funcdef(struct compiling *c, const node *n) static expr_ty ast_for_lambdef(struct compiling *c, const node *n) { - /* lambdef: 'lambda' [varargslist] ':' test */ + /* lambdef: 'lambda' [varargslist] ':' test + lambdef_nocond: 'lambda' [varargslist] ':' test_nocond */ arguments_ty args; expr_ty expression; @@ -1067,190 +1066,34 @@ ast_for_ifexpr(struct compiling *c, const node *n) c->c_arena); } -/* XXX(nnorwitz): the listcomp and genexpr code should be refactored - so there is only a single version. Possibly for loops can also re-use - the code. -*/ - -/* Count the number of 'for' loop in a list comprehension. - - Helper for ast_for_listcomp(). -*/ - -static int -count_list_fors(const node *n) -{ - int n_fors = 0; - node *ch = CHILD(n, 1); - - count_list_for: - n_fors++; - REQ(ch, list_for); - if (NCH(ch) == 5) - ch = CHILD(ch, 4); - else - return n_fors; - count_list_iter: - REQ(ch, list_iter); - ch = CHILD(ch, 0); - if (TYPE(ch) == list_for) - goto count_list_for; - else if (TYPE(ch) == list_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); - goto count_list_iter; - } - else - return n_fors; - } - - /* Should never be reached */ - PyErr_SetString(PyExc_SystemError, "logic error in count_list_fors"); - return -1; -} - -/* Count the number of 'if' statements in a list comprehension. - - Helper for ast_for_listcomp(). -*/ - -static int -count_list_ifs(const node *n) -{ - int n_ifs = 0; - - count_list_iter: - REQ(n, list_iter); - if (TYPE(CHILD(n, 0)) == list_for) - return n_ifs; - n = CHILD(n, 0); - REQ(n, list_if); - n_ifs++; - if (NCH(n) == 2) - return n_ifs; - n = CHILD(n, 2); - goto count_list_iter; -} - -static expr_ty -ast_for_listcomp(struct compiling *c, const node *n) -{ - /* listmaker: test ( list_for | (',' test)* [','] ) - list_for: 'for' exprlist 'in' testlist_safe [list_iter] - list_iter: list_for | list_if - list_if: 'if' test [list_iter] - testlist_safe: test [(',' test)+ [',']] - */ - expr_ty elt; - asdl_seq *listcomps; - int i, n_fors; - node *ch; - - REQ(n, listmaker); - assert(NCH(n) > 1); - - elt = ast_for_expr(c, CHILD(n, 0)); - if (!elt) - return NULL; - - n_fors = count_list_fors(n); - if (n_fors == -1) - return NULL; - - listcomps = asdl_seq_new(n_fors, c->c_arena); - if (!listcomps) - return NULL; - - ch = CHILD(n, 1); - for (i = 0; i < n_fors; i++) { - comprehension_ty lc; - asdl_seq *t; - expr_ty expression; - node *for_ch; - - REQ(ch, list_for); - - for_ch = CHILD(ch, 1); - t = ast_for_exprlist(c, for_ch, Store); - if (!t) - return NULL; - expression = ast_for_testlist(c, CHILD(ch, 3)); - if (!expression) - return NULL; - - /* Check the # of children rather than the length of t, since - [x for x, in ... ] has 1 element in t, but still requires a Tuple. */ - if (NCH(for_ch) == 1) - lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, - c->c_arena); - else - lc = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, - c->c_arena), - expression, NULL, c->c_arena); - if (!lc) - return NULL; - - if (NCH(ch) == 5) { - int j, n_ifs; - asdl_seq *ifs; - - ch = CHILD(ch, 4); - n_ifs = count_list_ifs(ch); - if (n_ifs == -1) - return NULL; - - ifs = asdl_seq_new(n_ifs, c->c_arena); - if (!ifs) - return NULL; - - for (j = 0; j < n_ifs; j++) { - REQ(ch, list_iter); - ch = CHILD(ch, 0); - REQ(ch, list_if); - - asdl_seq_SET(ifs, j, ast_for_expr(c, CHILD(ch, 1))); - if (NCH(ch) == 3) - ch = CHILD(ch, 2); - } - /* on exit, must guarantee that ch is a list_for */ - if (TYPE(ch) == list_iter) - ch = CHILD(ch, 0); - lc->ifs = ifs; - } - asdl_seq_SET(listcomps, i, lc); - } - - return ListComp(elt, listcomps, LINENO(n), n->n_col_offset, c->c_arena); -} - /* - Count the number of 'for' loops in a generator expression. + Count the number of 'for' loops in a comprehension. - Helper for ast_for_genexp(). + Helper for ast_for_comprehension(). */ static int -count_gen_fors(const node *n) +count_comp_fors(const node *n) { int n_fors = 0; node *ch = CHILD(n, 1); - count_gen_for: + count_comp_for: n_fors++; - REQ(ch, gen_for); + REQ(ch, comp_for); if (NCH(ch) == 5) ch = CHILD(ch, 4); else return n_fors; - count_gen_iter: - REQ(ch, gen_iter); + count_comp_iter: + REQ(ch, comp_iter); ch = CHILD(ch, 0); - if (TYPE(ch) == gen_for) - goto count_gen_for; - else if (TYPE(ch) == gen_if) { + if (TYPE(ch) == comp_for) + goto count_comp_for; + else if (TYPE(ch) == comp_if) { if (NCH(ch) == 3) { ch = CHILD(ch, 2); - goto count_gen_iter; + goto count_comp_iter; } else return n_fors; @@ -1258,26 +1101,26 @@ count_gen_fors(const node *n) /* Should never be reached */ PyErr_SetString(PyExc_SystemError, - "logic error in count_gen_fors"); + "logic error in count_comp_fors"); return -1; } -/* Count the number of 'if' statements in a generator expression. +/* Count the number of 'if' statements in a comprehension. - Helper for ast_for_genexp(). + Helper for ast_for_comprehension(). */ static int -count_gen_ifs(const node *n) +count_comp_ifs(const node *n) { int n_ifs = 0; while (1) { - REQ(n, gen_iter); - if (TYPE(CHILD(n, 0)) == gen_for) + REQ(n, comp_iter); + if (TYPE(CHILD(n, 0)) == comp_for) return n_ifs; n = CHILD(n, 0); - REQ(n, gen_if); + REQ(n, comp_if); n_ifs++; if (NCH(n) == 2) return n_ifs; @@ -1285,40 +1128,38 @@ count_gen_ifs(const node *n) } } -/* TODO(jhylton): Combine with list comprehension code? */ static expr_ty -ast_for_genexp(struct compiling *c, const node *n) +ast_for_comprehension(struct compiling *c, const node *n, int type) { - /* testlist_gexp: test ( gen_for | (',' test)* [','] ) - argument: [test '='] test [gen_for] # Really [keyword '='] test */ + /* testlist_comp: test ( comp_for | (',' test)* [','] ) + argument: [test '='] test [comp_for] # Really [keyword '='] test */ expr_ty elt; - asdl_seq *genexps; + asdl_seq *comps; int i, n_fors; node *ch; - assert(TYPE(n) == (testlist_gexp) || TYPE(n) == (argument)); assert(NCH(n) > 1); elt = ast_for_expr(c, CHILD(n, 0)); if (!elt) return NULL; - n_fors = count_gen_fors(n); + n_fors = count_comp_fors(n); if (n_fors == -1) return NULL; - genexps = asdl_seq_new(n_fors, c->c_arena); - if (!genexps) + comps = asdl_seq_new(n_fors, c->c_arena); + if (!comps) return NULL; ch = CHILD(n, 1); for (i = 0; i < n_fors; i++) { - comprehension_ty ge; + comprehension_ty comp; asdl_seq *t; expr_ty expression; node *for_ch; - REQ(ch, gen_for); + REQ(ch, comp_for); for_ch = CHILD(ch, 1); t = ast_for_exprlist(c, for_ch, Store); @@ -1331,14 +1172,14 @@ ast_for_genexp(struct compiling *c, const node *n) /* Check the # of children rather than the length of t, since (x for x, in ...) has 1 element in t, but still requires a Tuple. */ if (NCH(for_ch) == 1) - ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, - NULL, c->c_arena); + comp = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, + NULL, c->c_arena); else - ge = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, - c->c_arena), - expression, NULL, c->c_arena); + comp = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + c->c_arena), + expression, NULL, c->c_arena); - if (!ge) + if (!comp) return NULL; if (NCH(ch) == 5) { @@ -1346,7 +1187,7 @@ ast_for_genexp(struct compiling *c, const node *n) asdl_seq *ifs; ch = CHILD(ch, 4); - n_ifs = count_gen_ifs(ch); + n_ifs = count_comp_ifs(ch); if (n_ifs == -1) return NULL; @@ -1355,9 +1196,9 @@ ast_for_genexp(struct compiling *c, const node *n) return NULL; for (j = 0; j < n_ifs; j++) { - REQ(ch, gen_iter); + REQ(ch, comp_iter); ch = CHILD(ch, 0); - REQ(ch, gen_if); + REQ(ch, comp_if); expression = ast_for_expr(c, CHILD(ch, 1)); if (!expression) @@ -1366,22 +1207,52 @@ ast_for_genexp(struct compiling *c, const node *n) if (NCH(ch) == 3) ch = CHILD(ch, 2); } - /* on exit, must guarantee that ch is a gen_for */ - if (TYPE(ch) == gen_iter) + /* on exit, must guarantee that ch is a comp_for */ + if (TYPE(ch) == comp_iter) ch = CHILD(ch, 0); - ge->ifs = ifs; + comp->ifs = ifs; } - asdl_seq_SET(genexps, i, ge); + asdl_seq_SET(comps, i, comp); } - - return GeneratorExp(elt, genexps, LINENO(n), n->n_col_offset, c->c_arena); + + if (type == COMP_GENEXP) + return GeneratorExp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena); + else if (type == COMP_LISTCOMP) + return ListComp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena); + else if (type == COMP_SETCOMP) + return SetComp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena); + else + /* Should never happen */ + return NULL; +} + +static expr_ty +ast_for_genexp(struct compiling *c, const node *n) +{ + assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument)); + return ast_for_comprehension(c, n, COMP_GENEXP); } static expr_ty +ast_for_listcomp(struct compiling *c, const node *n) +{ + assert(TYPE(n) == (testlist_comp)); + return ast_for_comprehension(c, n, COMP_LISTCOMP); +} + +static expr_ty +ast_for_setcomp(struct compiling *c, const node *n) +{ + assert(TYPE(n) == (dictorsetmaker)); + return ast_for_comprehension(c, n, COMP_SETCOMP); +} + + +static expr_ty ast_for_atom(struct compiling *c, const node *n) { - /* atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' - | '{' [dictsetmaker] '}' | NAME | NUMBER | STRING+ + /* atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' + | '{' [dictmaker|testlist_comp] '}' | NAME | NUMBER | STRING+ */ node *ch = CHILD(n, 0); int bytesmode = 0; @@ -1420,18 +1291,19 @@ ast_for_atom(struct compiling *c, const node *n) if (TYPE(ch) == yield_expr) return ast_for_expr(c, ch); - - if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == gen_for)) + + /* testlist_comp: test ( comp_for | (',' test)* [','] ) */ + if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == comp_for)) return ast_for_genexp(c, ch); - return ast_for_testlist_gexp(c, ch); + return ast_for_testlist(c, ch); case LSQB: /* list (or list comprehension) */ ch = CHILD(n, 1); if (TYPE(ch) == RSQB) return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); - REQ(ch, listmaker); + REQ(ch, testlist_comp); if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) { asdl_seq *elts = seq_for_testlist(c, ch); if (!elts) @@ -1442,27 +1314,32 @@ ast_for_atom(struct compiling *c, const node *n) else return ast_for_listcomp(c, ch); case LBRACE: { - /* dictsetmaker: test ':' test (',' test ':' test)* [','] | - * test (',' test)* [','] */ + /* dictorsetmaker: test ':' test (',' test ':' test)* [','] | + * test (gen_for | (',' test)* [',']) */ int i, size; asdl_seq *keys, *values; ch = CHILD(n, 1); - if (NCH(ch) == 1 || (NCH(ch) > 0 && STR(CHILD(ch, 1))[0] == ',')) { - /* it's a set */ + if (TYPE(ch) == RBRACE) { + /* it's an empty dict */ + return Dict(NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } else if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) { + /* it's a simple set */ size = (NCH(ch) + 1) / 2; /* +1 in case no trailing comma */ - keys = asdl_seq_new(size, c->c_arena); - if (!keys) + asdl_seq *elts = asdl_seq_new(size, c->c_arena); + if (!elts) return NULL; - for (i = 0; i < NCH(ch); i += 2) { expr_ty expression; expression = ast_for_expr(c, CHILD(ch, i)); if (!expression) return NULL; - asdl_seq_SET(keys, i / 2, expression); + asdl_seq_SET(elts, i / 2, expression); } - return Set(keys, LINENO(n), n->n_col_offset, c->c_arena); + return Set(elts, LINENO(n), n->n_col_offset, c->c_arena); + } else if (TYPE(CHILD(ch, 1)) == comp_for) { + /* it's a set comprehension */ + return ast_for_setcomp(c, ch); } else { /* it's a dict */ size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ @@ -1790,6 +1667,7 @@ ast_for_expr(struct compiling *c, const node *n) { /* handle the full range of simple expressions test: or_test ['if' or_test 'else' test] | lambdef + test_nocond: or_test | lambdef_nocond or_test: and_test ('or' and_test)* and_test: not_test ('and' not_test)* not_test: 'not' not_test | comparison @@ -1802,15 +1680,6 @@ ast_for_expr(struct compiling *c, const node *n) term: factor (('*'|'/'|'%'|'//') factor)* factor: ('+'|'-'|'~') factor | power power: atom trailer* ('**' factor)* - - As well as modified versions that exist for backward compatibility, - to explicitly allow: - [ x for x in lambda: 0, lambda: 1 ] - (which would be ambiguous without these extra rules) - - old_test: or_test | old_lambdef - old_lambdef: 'lambda' [vararglist] ':' old_test - */ asdl_seq *seq; @@ -1819,9 +1688,9 @@ ast_for_expr(struct compiling *c, const node *n) loop: switch (TYPE(n)) { case test: - case old_test: + case test_nocond: if (TYPE(CHILD(n, 0)) == lambdef || - TYPE(CHILD(n, 0)) == old_lambdef) + TYPE(CHILD(n, 0)) == lambdef_nocond) return ast_for_lambdef(c, CHILD(n, 0)); else if (NCH(n) > 1) return ast_for_ifexpr(c, n); @@ -1947,7 +1816,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) /* arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) - argument: [test '='] test [gen_for] # Really [keyword '='] test + argument: [test '='] test [comp_for] # Really [keyword '='] test */ int i, nargs, nkeywords, ngens; @@ -1965,7 +1834,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) if (TYPE(ch) == argument) { if (NCH(ch) == 1) nargs++; - else if (TYPE(CHILD(ch, 1)) == gen_for) + else if (TYPE(CHILD(ch, 1)) == comp_for) ngens++; else nkeywords++; @@ -2005,7 +1874,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) return NULL; asdl_seq_SET(args, nargs++, e); } - else if (TYPE(CHILD(ch, 1)) == gen_for) { + else if (TYPE(CHILD(ch, 1)) == comp_for) { e = ast_for_genexp(c, ch); if (!e) return NULL; @@ -2057,18 +1926,16 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) static expr_ty ast_for_testlist(struct compiling *c, const node* n) { - /* testlist_gexp: test (',' test)* [','] */ + /* testlist_comp: test (comp_for | (',' test)* [',']) */ /* testlist: test (',' test)* [','] */ - /* testlist_safe: test (',' test)+ [','] */ /* testlist1: test (',' test)* */ assert(NCH(n) > 0); - if (TYPE(n) == testlist_gexp) { + if (TYPE(n) == testlist_comp) { if (NCH(n) > 1) - assert(TYPE(CHILD(n, 1)) != gen_for); + assert(TYPE(CHILD(n, 1)) != comp_for); } else { assert(TYPE(n) == testlist || - TYPE(n) == testlist_safe || TYPE(n) == testlist1); } if (NCH(n) == 1) @@ -2081,17 +1948,6 @@ ast_for_testlist(struct compiling *c, const node* n) } } -static expr_ty -ast_for_testlist_gexp(struct compiling *c, const node* n) -{ - /* testlist_gexp: test ( gen_for | (',' test)* [','] ) */ - /* argument: test [ gen_for ] */ - assert(TYPE(n) == testlist_gexp || TYPE(n) == argument); - if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) - return ast_for_genexp(c, n); - return ast_for_testlist(c, n); -} - static stmt_ty ast_for_expr_stmt(struct compiling *c, const node *n) { |