Index: Python/ast.c =================================================================== --- Python/ast.c (revision 56242) +++ Python/ast.c (working copy) @@ -428,6 +428,9 @@ case SetComp_kind: expr_name = "set comprehension"; break; + case DictComp_kind: + expr_name = "dict comprehension"; + break; case Dict_kind: case Set_kind: case Num_kind: @@ -1073,23 +1076,22 @@ count_comp_fors(const node *n) { int n_fors = 0; - node *ch = CHILD(n, 1); count_comp_for: n_fors++; - REQ(ch, comp_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_comp_iter: - REQ(ch, comp_iter); - ch = CHILD(ch, 0); - if (TYPE(ch) == comp_for) + REQ(n, comp_iter); + n = CHILD(n, 0); + if (TYPE(n) == comp_for) goto count_comp_for; - else if (TYPE(ch) == comp_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); + else if (TYPE(n) == comp_if) { + if (NCH(n) == 3) { + n = CHILD(n, 2); goto count_comp_iter; } else @@ -1125,22 +1127,12 @@ } } -static expr_ty -ast_for_comprehension(struct compiling *c, const node *n, int type) +static asdl_seq * +ast_for_comprehension(struct compiling *c, const node *n) { - /* testlist_comp: test ( comp_for | (',' test)* [','] ) - argument: [test '='] test [comp_for] # Really [keyword '='] test */ - expr_ty elt; + int i, n_fors; asdl_seq *comps; - int i, n_fors; - node *ch; - - assert(NCH(n) > 1); - - elt = ast_for_expr(c, CHILD(n, 0)); - if (!elt) - return NULL; - + n_fors = count_comp_fors(n); if (n_fors == -1) return NULL; @@ -1149,20 +1141,19 @@ if (!comps) return NULL; - ch = CHILD(n, 1); for (i = 0; i < n_fors; i++) { comprehension_ty comp; asdl_seq *t; expr_ty expression; node *for_ch; - REQ(ch, comp_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; @@ -1172,19 +1163,19 @@ comp = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, c->c_arena); else - comp = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + comp = comprehension(Tuple(t, Store, LINENO(n), n->n_col_offset, c->c_arena), expression, NULL, c->c_arena); 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_comp_ifs(ch); + n = CHILD(n, 4); + n_ifs = count_comp_ifs(n); if (n_ifs == -1) return NULL; @@ -1193,25 +1184,45 @@ return NULL; for (j = 0; j < n_ifs; j++) { - REQ(ch, comp_iter); - ch = CHILD(ch, 0); - REQ(ch, comp_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 comp_for */ - if (TYPE(ch) == comp_iter) - ch = CHILD(ch, 0); + /* 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(comps, i, comp); } + return comps; +} +static expr_ty +ast_for_itercomp(struct compiling *c, const node *n, int type) +{ + /* testlist_comp: test ( comp_for | (',' test)* [','] ) + argument: [test '='] test [comp_for] # Really [keyword '='] test */ + expr_ty elt; + asdl_seq *comps; + + 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_LISTCOMP) @@ -1224,24 +1235,48 @@ } 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_comprehension(c, n, COMP_GENEXP); + return ast_for_itercomp(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); + return ast_for_itercomp(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); + return ast_for_itercomp(c, n, COMP_SETCOMP); } @@ -1339,6 +1374,8 @@ } 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 */ Index: Python/symtable.c =================================================================== --- Python/symtable.c (revision 56242) +++ Python/symtable.c (working copy) @@ -174,6 +174,7 @@ static int symtable_visit_genexp(struct symtable *st, expr_ty s); static int symtable_visit_listcomp(struct symtable *st, expr_ty s); static int symtable_visit_setcomp(struct symtable *st, expr_ty s); +static int symtable_visit_dictcomp(struct symtable *st, expr_ty s); static int symtable_visit_arguments(struct symtable *st, arguments_ty); static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty); static int symtable_visit_alias(struct symtable *st, alias_ty); @@ -187,7 +188,7 @@ static identifier top = NULL, lambda = NULL, genexpr = NULL, - listcomp = NULL, setcomp = NULL, __class__ = NULL; + listcomp = NULL, setcomp = NULL, dictcomp = NULL, __class__ = NULL; #define GET_IDENTIFIER(VAR) \ ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR))) @@ -1277,6 +1278,10 @@ if (!symtable_visit_setcomp(st, e)) return 0; break; + case DictComp_kind: + if (!symtable_visit_dictcomp(st, e)) + return 0; + break; case Yield_kind: if (e->v.Yield.value) VISIT(st, expr, e->v.Yield.value); @@ -1528,8 +1533,8 @@ static int symtable_handle_comprehension(struct symtable *st, expr_ty e, - identifier scope_name, - asdl_seq *generators, expr_ty elt) + identifier scope_name, asdl_seq *generators, + expr_ty elt, expr_ty value) { int is_generator = (e->kind == GeneratorExp_kind); int needs_tmp = !is_generator; @@ -1557,6 +1562,8 @@ VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e); VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension, generators, 1, (void*)e); + if (value) + VISIT_IN_BLOCK(st, expr, value, (void*)e); VISIT_IN_BLOCK(st, expr, elt, (void*)e); return symtable_exit_block(st, (void *)e); } @@ -1566,7 +1573,7 @@ { return symtable_handle_comprehension(st, e, GET_IDENTIFIER(genexpr), e->v.GeneratorExp.generators, - e->v.GeneratorExp.elt); + e->v.GeneratorExp.elt, NULL); } static int @@ -1574,7 +1581,7 @@ { return symtable_handle_comprehension(st, e, GET_IDENTIFIER(listcomp), e->v.ListComp.generators, - e->v.ListComp.elt); + e->v.ListComp.elt, NULL); } static int @@ -1582,5 +1589,14 @@ { return symtable_handle_comprehension(st, e, GET_IDENTIFIER(setcomp), e->v.SetComp.generators, - e->v.SetComp.elt); + e->v.SetComp.elt, NULL); } + +static int +symtable_visit_dictcomp(struct symtable *st, expr_ty e) +{ + return symtable_handle_comprehension(st, e, GET_IDENTIFIER(dictcomp), + e->v.DictComp.generators, + e->v.DictComp.key, + e->v.DictComp.value); +} Index: Python/compile.c =================================================================== --- Python/compile.c (revision 56242) +++ Python/compile.c (working copy) @@ -42,6 +42,7 @@ #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 #define COMP_SETCOMP 2 +#define COMP_DICTCOMP 3 struct instr { unsigned i_jabs : 1; @@ -2753,7 +2754,7 @@ static int compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, asdl_seq *generators, int gen_index, - expr_ty elt, int type) + expr_ty elt, expr_ty val, int type) { /* generate code for the iterator, then each of the ifs, and then write to the element */ @@ -2801,7 +2802,7 @@ if (++gen_index < asdl_seq_LEN(generators)) if (!compiler_comprehension_generator(c, tmpname, generators, gen_index, - elt, type)) + elt, val, type)) return 0; /* only append after the last for generator */ @@ -2825,6 +2826,17 @@ VISIT(c, expr, elt); ADDOP(c, SET_ADD); break; + case COMP_DICTCOMP: + if (!compiler_nameop(c, tmpname, Load)) + return 0; + /* With 'd[k] = v', v is evaluated before k, so we do + the same. STORE_SUBSCR requires (item, map, key), + so we still end up ROTing once. */ + VISIT(c, expr, val); + ADDOP(c, ROT_TWO); + VISIT(c, expr, elt); + ADDOP(c, STORE_SUBSCR); + break; default: return 0; } @@ -2846,7 +2858,7 @@ static int compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, - asdl_seq *generators, expr_ty elt) + asdl_seq *generators, expr_ty elt, expr_ty val) { PyCodeObject *co = NULL; identifier tmp = NULL; @@ -2859,18 +2871,34 @@ goto error; if (type != COMP_GENEXP) { + int op; tmp = compiler_new_tmpname(c); if (!tmp) goto error_in_scope; + switch (type) { + case COMP_LISTCOMP: + op = BUILD_LIST; + break; + 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, (type == COMP_LISTCOMP ? - BUILD_LIST : BUILD_SET), 0); + ADDOP_I(c, op, 0); ADDOP(c, DUP_TOP); if (!compiler_nameop(c, tmp, Store)) goto error_in_scope; } - if (!compiler_comprehension_generator(c, tmp, generators, 0, elt, type)) + if (!compiler_comprehension_generator(c, tmp, generators, 0, elt, + val, type)) goto error_in_scope; if (type != COMP_GENEXP) { @@ -2911,7 +2939,7 @@ assert(e->kind == GeneratorExp_kind); return compiler_comprehension(c, e, COMP_GENEXP, name, e->v.GeneratorExp.generators, - e->v.GeneratorExp.elt); + e->v.GeneratorExp.elt, NULL); } static int @@ -2926,7 +2954,7 @@ assert(e->kind == ListComp_kind); return compiler_comprehension(c, e, COMP_LISTCOMP, name, e->v.ListComp.generators, - e->v.ListComp.elt); + e->v.ListComp.elt, NULL); } static int @@ -2941,11 +2969,27 @@ assert(e->kind == SetComp_kind); return compiler_comprehension(c, e, COMP_SETCOMP, name, e->v.SetComp.generators, - e->v.SetComp.elt); + e->v.SetComp.elt, NULL); } static int +compiler_dictcomp(struct compiler *c, expr_ty e) +{ + static identifier name; + if (!name) { + name = PyString_FromString(""); + 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 compiler_visit_keyword(struct compiler *c, keyword_ty k) { ADDOP_O(c, LOAD_CONST, k->arg, consts); @@ -3172,6 +3216,8 @@ return compiler_listcomp(c, e); case SetComp_kind: return compiler_setcomp(c, e); + case DictComp_kind: + return compiler_dictcomp(c, e); case Yield_kind: if (c->u->u_ste->ste_type != FunctionBlock) return compiler_error(c, "'yield' outside function"); Index: Python/Python-ast.c =================================================================== --- Python/Python-ast.c (revision 56242) +++ Python/Python-ast.c (working copy) @@ -198,6 +198,12 @@ "elt", "generators", }; +static PyTypeObject *DictComp_type; +static char *DictComp_fields[]={ + "key", + "value", + "generators", +}; static PyTypeObject *GeneratorExp_type; static char *GeneratorExp_fields[]={ "elt", @@ -551,6 +557,8 @@ if (!ListComp_type) return 0; SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); if (!SetComp_type) return 0; + DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3); + if (!DictComp_type) return 0; GeneratorExp_type = make_type("GeneratorExp", expr_type, GeneratorExp_fields, 2); if (!GeneratorExp_type) return 0; @@ -1445,6 +1453,33 @@ } expr_ty +DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena) +{ + expr_ty p; + if (!key) { + PyErr_SetString(PyExc_ValueError, + "field key is required for DictComp"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for DictComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = DictComp_kind; + p->v.DictComp.key = key; + p->v.DictComp.value = value; + p->v.DictComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { @@ -2479,6 +2514,26 @@ goto failed; Py_DECREF(value); break; + case DictComp_kind: + result = PyType_GenericNew(DictComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.DictComp.key); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "key", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.DictComp.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.DictComp.generators, + ast2obj_comprehension); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "generators", value) == -1) + goto failed; + Py_DECREF(value); + break; case GeneratorExp_kind: result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); if (!result) goto failed; @@ -3186,6 +3241,8 @@ return; if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) return; + if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) + return; if (PyDict_SetItemString(d, "GeneratorExp", (PyObject*)GeneratorExp_type) < 0) return; if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return; Index: Include/Python-ast.h =================================================================== --- Include/Python-ast.h (revision 56242) +++ Include/Python-ast.h (working copy) @@ -184,11 +184,11 @@ enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, - SetComp_kind=9, GeneratorExp_kind=10, Yield_kind=11, - Compare_kind=12, Call_kind=13, Num_kind=14, Str_kind=15, - Bytes_kind=16, Ellipsis_kind=17, Attribute_kind=18, - Subscript_kind=19, Starred_kind=20, Name_kind=21, - List_kind=22, Tuple_kind=23}; + SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, + Yield_kind=12, Compare_kind=13, Call_kind=14, Num_kind=15, + Str_kind=16, Bytes_kind=17, Ellipsis_kind=18, + Attribute_kind=19, Subscript_kind=20, Starred_kind=21, + Name_kind=22, List_kind=23, Tuple_kind=24}; struct _expr { enum _expr_kind kind; union { @@ -239,6 +239,12 @@ } SetComp; struct { + expr_ty key; + expr_ty value; + asdl_seq *generators; + } DictComp; + + struct { expr_ty elt; asdl_seq *generators; } GeneratorExp; @@ -470,6 +476,9 @@ #define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4) expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena); +#define DictComp(a0, a1, a2, a3, a4, a5) _Py_DictComp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int + lineno, int col_offset, PyArena *arena); #define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4) expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena); Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 56242) +++ Grammar/Grammar (working copy) @@ -108,7 +108,7 @@ sliceop: ':' [test] exprlist: star_expr (',' star_expr)* [','] testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (',' test ':' test)* [',']) | +dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | (test (comp_for | (',' test)* [','])) ) classdef: 'class' NAME ['(' [arglist] ')'] ':' suite Index: Parser/Python.asdl =================================================================== --- Parser/Python.asdl (revision 56242) +++ Parser/Python.asdl (working copy) @@ -57,7 +57,8 @@ | Dict(expr* keys, expr* values) | Set(expr* elts) | ListComp(expr elt, comprehension* generators) - | SetComp(expr elt, comprehension* generators) + | SetComp(expr elt, comprehension* generators) + | DictComp(expr key, expr value, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators) -- the grammar constrains where yield expressions can occur | Yield(expr? value)