diff options
author | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-11 22:36:12 (GMT) |
---|---|---|
committer | Alexandre Vassalotti <alexandre@peadrop.com> | 2010-01-11 22:36:12 (GMT) |
commit | b646547bb45fe1df6abefd94f892c633798d91d2 (patch) | |
tree | ef1add045741d309129266726f5ba45562184091 /Python/ast.c | |
parent | 0ca7452794bef03b66f56cc996a73cac066d0ec1 (diff) | |
download | cpython-b646547bb45fe1df6abefd94f892c633798d91d2.zip cpython-b646547bb45fe1df6abefd94f892c633798d91d2.tar.gz cpython-b646547bb45fe1df6abefd94f892c633798d91d2.tar.bz2 |
Issue #2333: Backport set and dict comprehensions syntax.
Diffstat (limited to 'Python/ast.c')
-rw-r--r-- | Python/ast.c | 235 |
1 files changed, 149 insertions, 86 deletions
diff --git a/Python/ast.c b/Python/ast.c index 01d1f7a..c76014a 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -31,7 +31,7 @@ static asdl_seq *ast_for_exprlist(struct compiling *, const node *, expr_context_ty); static expr_ty ast_for_testlist(struct compiling *, const node *); static stmt_ty ast_for_classdef(struct compiling *, const node *, asdl_seq *); -static expr_ty ast_for_testlist_gexp(struct compiling *, const node *); +static expr_ty ast_for_testlist_comp(struct compiling *, const node *); /* Note different signature for ast_for_call */ static expr_ty ast_for_call(struct compiling *, const node *, expr_ty); @@ -44,6 +44,9 @@ static PyObject *parsestrplus(struct compiling *, const node *n); #define LINENO(n) ((n)->n_lineno) #endif +#define COMP_GENEXP 0 +#define COMP_SETCOMP 1 + static identifier new_identifier(const char* n, PyArena *arena) { PyObject* id = PyString_InternFromString(n); @@ -268,7 +271,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; @@ -430,6 +433,12 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n) case ListComp_kind: expr_name = "list comprehension"; break; + case SetComp_kind: + expr_name = "set comprehension"; + break; + case DictComp_kind: + expr_name = "dict comprehension"; + break; case Dict_kind: case Num_kind: case Str_kind: @@ -573,7 +582,7 @@ seq_for_testlist(struct compiling *c, const node *n) int i; assert(TYPE(n) == testlist || TYPE(n) == listmaker || - TYPE(n) == testlist_gexp || + TYPE(n) == testlist_comp || TYPE(n) == testlist_safe || TYPE(n) == testlist1); @@ -1150,60 +1159,60 @@ ast_for_listcomp(struct compiling *c, const node *n) 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(struct compiling *c, const node *n) +count_comp_fors(struct compiling *c, const node *n) { int n_fors = 0; - node *ch = CHILD(n, 1); - count_gen_for: + count_comp_for: n_fors++; - REQ(ch, gen_for); - if (NCH(ch) == 5) - ch = CHILD(ch, 4); + REQ(n, comp_for); + if (NCH(n) == 5) + n = CHILD(n, 4); else return n_fors; - count_gen_iter: - REQ(ch, gen_iter); - ch = CHILD(ch, 0); - if (TYPE(ch) == gen_for) - goto count_gen_for; - else if (TYPE(ch) == gen_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); - goto count_gen_iter; + count_comp_iter: + REQ(n, comp_iter); + n = CHILD(n, 0); + if (TYPE(n) == comp_for) + goto count_comp_for; + else if (TYPE(n) == comp_if) { + if (NCH(n) == 3) { + n = CHILD(n, 2); + goto count_comp_iter; } else return n_fors; } - + /* 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(struct compiling *c, const node *n) +count_comp_ifs(struct compiling *c, 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; @@ -1211,46 +1220,33 @@ count_gen_ifs(struct compiling *c, const node *n) } } -/* TODO(jhylton): Combine with list comprehension code? */ -static expr_ty -ast_for_genexp(struct compiling *c, const node *n) +static asdl_seq * +ast_for_comprehension(struct compiling *c, const node *n) { - /* testlist_gexp: test ( gen_for | (',' test)* [','] ) - argument: [test '='] test [gen_for] # Really [keyword '='] test */ - expr_ty elt; - asdl_seq *genexps; 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(c, n); + asdl_seq *comps; + + n_fors = count_comp_fors(c, 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, first; node *for_ch; - REQ(ch, gen_for); + REQ(n, comp_for); - for_ch = CHILD(ch, 1); + for_ch = CHILD(n, 1); t = ast_for_exprlist(c, for_ch, Store); if (!t) return NULL; - expression = ast_for_expr(c, CHILD(ch, 3)); + expression = ast_for_expr(c, CHILD(n, 3)); if (!expression) return NULL; @@ -1258,21 +1254,20 @@ ast_for_genexp(struct compiling *c, const node *n) (x for x, in ...) has 1 element in t, but still requires a Tuple. */ first = (expr_ty)asdl_seq_GET(t, 0); if (NCH(for_ch) == 1) - ge = comprehension(first, expression, NULL, c->c_arena); + comp = comprehension(first, expression, NULL, c->c_arena); else - ge = comprehension(Tuple(t, Store, first->lineno, first->col_offset, + comp = comprehension(Tuple(t, Store, first->lineno, first->col_offset, c->c_arena), expression, NULL, c->c_arena); - - if (!ge) + if (!comp) return NULL; - if (NCH(ch) == 5) { + if (NCH(n) == 5) { int j, n_ifs; asdl_seq *ifs; - ch = CHILD(ch, 4); - n_ifs = count_gen_ifs(c, ch); + n = CHILD(n, 4); + n_ifs = count_comp_ifs(c, n); if (n_ifs == -1) return NULL; @@ -1281,32 +1276,94 @@ ast_for_genexp(struct compiling *c, const node *n) return NULL; for (j = 0; j < n_ifs; j++) { - REQ(ch, gen_iter); - ch = CHILD(ch, 0); - REQ(ch, gen_if); + REQ(n, comp_iter); + n = CHILD(n, 0); + REQ(n, comp_if); - expression = ast_for_expr(c, CHILD(ch, 1)); + expression = ast_for_expr(c, CHILD(n, 1)); if (!expression) return NULL; asdl_seq_SET(ifs, j, expression); - if (NCH(ch) == 3) - ch = CHILD(ch, 2); + if (NCH(n) == 3) + n = CHILD(n, 2); } - /* on exit, must guarantee that ch is a gen_for */ - if (TYPE(ch) == gen_iter) - ch = CHILD(ch, 0); - ge->ifs = ifs; + /* on exit, must guarantee that n is a comp_for */ + if (TYPE(n) == comp_iter) + n = CHILD(n, 0); + comp->ifs = ifs; } - asdl_seq_SET(genexps, i, ge); + asdl_seq_SET(comps, i, comp); } + return comps; +} + +static expr_ty +ast_for_itercomp(struct compiling *c, const node *n, int type) +{ + expr_ty elt; + asdl_seq *comps; - return GeneratorExp(elt, genexps, LINENO(n), n->n_col_offset, c->c_arena); + assert(NCH(n) > 1); + + elt = ast_for_expr(c, CHILD(n, 0)); + if (!elt) + return NULL; + + comps = ast_for_comprehension(c, CHILD(n, 1)); + if (!comps) + return NULL; + + if (type == COMP_GENEXP) + return GeneratorExp(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_dictcomp(struct compiling *c, const node *n) +{ + expr_ty key, value; + asdl_seq *comps; + + assert(NCH(n) > 3); + REQ(CHILD(n, 1), COLON); + + key = ast_for_expr(c, CHILD(n, 0)); + if (!key) + return NULL; + + value = ast_for_expr(c, CHILD(n, 2)); + if (!value) + return NULL; + + comps = ast_for_comprehension(c, CHILD(n, 3)); + if (!comps) + return NULL; + + return DictComp(key, value, comps, LINENO(n), n->n_col_offset, c->c_arena); +} + +static expr_ty +ast_for_genexp(struct compiling *c, const node *n) +{ + assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument)); + return ast_for_itercomp(c, n, COMP_GENEXP); +} + +static expr_ty +ast_for_setcomp(struct compiling *c, const node *n) +{ + assert(TYPE(n) == (dictorsetmaker)); + return ast_for_itercomp(c, n, COMP_SETCOMP); } static expr_ty ast_for_atom(struct compiling *c, const node *n) { - /* atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' + /* atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+ */ node *ch = CHILD(n, 0); @@ -1365,7 +1422,7 @@ ast_for_atom(struct compiling *c, const node *n) if (TYPE(ch) == yield_expr) return ast_for_expr(c, ch); - return ast_for_testlist_gexp(c, ch); + return ast_for_testlist_comp(c, ch); case LSQB: /* list (or list comprehension) */ ch = CHILD(n, 1); @@ -1383,8 +1440,9 @@ ast_for_atom(struct compiling *c, const node *n) else return ast_for_listcomp(c, ch); case LBRACE: { - /* dictorsetmaker: test ':' test (',' test ':' test)* [','] | - * test (',' test)* [',']) + /* dictorsetmaker: + * (test ':' test (comp_for | (',' test ':' test)* [','])) | + * (test (comp_for | (',' test)* [','])) */ int i, size; asdl_seq *keys, *values; @@ -1408,6 +1466,11 @@ ast_for_atom(struct compiling *c, const node *n) asdl_seq_SET(elts, i / 2, expression); } 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 if (NCH(ch) > 3 && TYPE(CHILD(ch, 3)) == comp_for) { + return ast_for_dictcomp(c, ch); } else { /* it's a dict */ size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ @@ -1916,7 +1979,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; @@ -1934,7 +1997,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++; @@ -1979,7 +2042,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; @@ -2049,14 +2112,14 @@ 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 (',' 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 || @@ -2074,12 +2137,12 @@ ast_for_testlist(struct compiling *c, const node* n) } static expr_ty -ast_for_testlist_gexp(struct compiling *c, const node* n) +ast_for_testlist_comp(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) + /* testlist_comp: test ( comp_for | (',' test)* [','] ) */ + /* argument: test [ comp_for ] */ + assert(TYPE(n) == testlist_comp || TYPE(n) == argument); + if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == comp_for) return ast_for_genexp(c, n); return ast_for_testlist(c, n); } |