Index: Python/graminit.c =================================================================== --- Python/graminit.c (revision 67008) +++ Python/graminit.c (working copy) @@ -669,14 +669,23 @@ static arc arcs_33_1[1] = { {21, 2}, }; -static arc arcs_33_2[2] = { +static arc arcs_33_2[3] = { {30, 1}, + {29, 3}, {0, 2}, }; -static state states_33[3] = { +static arc arcs_33_3[1] = { + {9, 4}, +}; +static arc arcs_33_4[1] = { + {0, 4}, +}; +static state states_33[5] = { {1, arcs_33_0}, {1, arcs_33_1}, - {2, arcs_33_2}, + {3, arcs_33_2}, + {1, arcs_33_3}, + {1, arcs_33_4}, }; static arc arcs_34_0[1] = { {83, 1}, @@ -684,14 +693,23 @@ static arc arcs_34_1[1] = { {21, 2}, }; -static arc arcs_34_2[2] = { +static arc arcs_34_2[3] = { {30, 1}, + {29, 3}, {0, 2}, }; -static state states_34[3] = { +static arc arcs_34_3[1] = { + {9, 4}, +}; +static arc arcs_34_4[1] = { + {0, 4}, +}; +static state states_34[5] = { {1, arcs_34_0}, {1, arcs_34_1}, - {2, arcs_34_2}, + {3, arcs_34_2}, + {1, arcs_34_3}, + {1, arcs_34_4}, }; static arc arcs_35_0[1] = { {84, 1}, @@ -1792,9 +1810,9 @@ "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {288, "dotted_name", 0, 2, states_32, "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, - {289, "global_stmt", 0, 3, states_33, + {289, "global_stmt", 0, 5, states_33, "\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000"}, - {290, "nonlocal_stmt", 0, 3, states_34, + {290, "nonlocal_stmt", 0, 5, states_34, "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000"}, {291, "assert_stmt", 0, 5, states_35, "\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"}, Index: Python/ast.c =================================================================== --- Python/ast.c (revision 67008) +++ Python/ast.c (working copy) @@ -2468,43 +2468,61 @@ static stmt_ty ast_for_global_stmt(struct compiling *c, const node *n) { - /* global_stmt: 'global' NAME (',' NAME)* */ + /* global_stmt: 'global' NAME (',' NAME)* ['=' testlist] */ identifier name; asdl_seq *s; - int i; + expr_ty value = NULL; + int i, num_names; REQ(n, global_stmt); - s = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (TYPE(CHILD(n, NCH(n) - 1)) == testlist) { + value = ast_for_testlist(c, CHILD(n, NCH(n) - 1)); + if (value == NULL) + return NULL; + num_names = NCH(n) - 2; + } + else + num_names = NCH(n); + s = asdl_seq_new(num_names / 2, c->c_arena); if (!s) return NULL; - for (i = 1; i < NCH(n); i += 2) { + for (i = 1; i < num_names; i += 2) { name = NEW_IDENTIFIER(CHILD(n, i)); if (!name) return NULL; asdl_seq_SET(s, i / 2, name); } - return Global(s, LINENO(n), n->n_col_offset, c->c_arena); + return Global(s, value, LINENO(n), n->n_col_offset, c->c_arena); } static stmt_ty ast_for_nonlocal_stmt(struct compiling *c, const node *n) { - /* nonlocal_stmt: 'nonlocal' NAME (',' NAME)* */ + /* nonlocal_stmt: 'nonlocal' NAME (',' NAME)* ['=' testlist] */ identifier name; asdl_seq *s; - int i; + expr_ty value = NULL; + int i, num_names; REQ(n, nonlocal_stmt); - s = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (TYPE(CHILD(n, NCH(n) - 1)) == testlist) { + value = ast_for_testlist(c, CHILD(n, NCH(n) - 1)); + if (value == NULL) + return NULL; + num_names = NCH(n) - 2; + } + else + num_names = NCH(n); + s = asdl_seq_new(num_names / 2, c->c_arena); if (!s) return NULL; - for (i = 1; i < NCH(n); i += 2) { + for (i = 1; i < num_names; i += 2) { name = NEW_IDENTIFIER(CHILD(n, i)); if (!name) return NULL; asdl_seq_SET(s, i / 2, name); } - return Nonlocal(s, LINENO(n), n->n_col_offset, c->c_arena); + return Nonlocal(s, value, LINENO(n), n->n_col_offset, c->c_arena); } static stmt_ty Index: Python/symtable.c =================================================================== --- Python/symtable.c (revision 67008) +++ Python/symtable.c (working copy) @@ -1167,6 +1167,8 @@ if (!symtable_add_def(st, name, DEF_GLOBAL)) return 0; } + if (s->v.Global.value) + VISIT(st, expr, s->v.Global.value); break; } case Nonlocal_kind: { @@ -1194,6 +1196,8 @@ if (!symtable_add_def(st, name, DEF_NONLOCAL)) return 0; } + if (s->v.Nonlocal.value) + VISIT(st, expr, s->v.Nonlocal.value); break; } case Expr_kind: Index: Python/compile.c =================================================================== --- Python/compile.c (revision 67008) +++ Python/compile.c (working copy) @@ -2342,7 +2342,34 @@ case ImportFrom_kind: return compiler_from_import(c, s); case Global_kind: + if (s->v.Global.value) { + VISIT(c, expr, s->v.Global.value); + n = asdl_seq_LEN(s->v.Global.names); + if (n > 1) + ADDOP_I(c, UNPACK_SEQUENCE, n); + for (i = 0; i < n; i++) { + if (!compiler_nameop(c, + asdl_seq_GET(s->v.Global.names, i), + Store) + ) + return 0; + } + } + break; case Nonlocal_kind: + if (s->v.Nonlocal.value) { + VISIT(c, expr, s->v.Nonlocal.value); + n = asdl_seq_LEN(s->v.Nonlocal.names); + if (n > 1) + ADDOP_I(c, UNPACK_SEQUENCE, n); + for (i = 0; i < n; i++) { + if (!compiler_nameop(c, + asdl_seq_GET(s->v.Nonlocal.names, i), + Store) + ) + return 0; + } + } break; case Expr_kind: if (c->c_interactive && c->c_nestlevel <= 1) { Index: Python/Python-ast.c =================================================================== --- Python/Python-ast.c (revision 67008) +++ Python/Python-ast.c (working copy) @@ -133,10 +133,12 @@ static PyTypeObject *Global_type; static char *Global_fields[]={ "names", + "value", }; static PyTypeObject *Nonlocal_type; static char *Nonlocal_fields[]={ "names", + "value", }; static PyTypeObject *Expr_type; static char *Expr_fields[]={ @@ -621,11 +623,29 @@ return 0; } +static int add_ast_fields() +{ + PyObject *empty_tuple, *d; + if (PyType_Ready(&AST_type) < 0) + return -1; + d = AST_type.tp_dict; + empty_tuple = PyTuple_New(0); + if (!empty_tuple || + PyDict_SetItemString(d, "_fields", empty_tuple) < 0 || + PyDict_SetItemString(d, "_attributes", empty_tuple) < 0) { + Py_XDECREF(empty_tuple); + return -1; + } + Py_DECREF(empty_tuple); + return 0; +} + static int init_types(void) { static int initialized; if (initialized) return 1; + if (add_ast_fields() < 0) return 0; mod_type = make_type("mod", &AST_type, NULL, 0); if (!mod_type) return 0; if (!add_attributes(mod_type, NULL, 0)) return 0; @@ -677,9 +697,9 @@ ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, 3); if (!ImportFrom_type) return 0; - Global_type = make_type("Global", stmt_type, Global_fields, 1); + Global_type = make_type("Global", stmt_type, Global_fields, 2); if (!Global_type) return 0; - Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 1); + Nonlocal_type = make_type("Nonlocal", stmt_type, Nonlocal_fields, 2); if (!Nonlocal_type) return 0; Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); if (!Expr_type) return 0; @@ -1332,7 +1352,8 @@ } stmt_ty -Global(asdl_seq * names, int lineno, int col_offset, PyArena *arena) +Global(asdl_seq * names, expr_ty value, int lineno, int col_offset, PyArena + *arena) { stmt_ty p; p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); @@ -1340,13 +1361,15 @@ return NULL; p->kind = Global_kind; p->v.Global.names = names; + p->v.Global.value = value; p->lineno = lineno; p->col_offset = col_offset; return p; } stmt_ty -Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena *arena) +Nonlocal(asdl_seq * names, expr_ty value, int lineno, int col_offset, PyArena + *arena) { stmt_ty p; p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); @@ -1354,6 +1377,7 @@ return NULL; p->kind = Nonlocal_kind; p->v.Nonlocal.names = names; + p->v.Nonlocal.value = value; p->lineno = lineno; p->col_offset = col_offset; return p; @@ -2491,6 +2515,11 @@ if (PyObject_SetAttrString(result, "names", value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_expr(o->v.Global.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); break; case Nonlocal_kind: result = PyType_GenericNew(Nonlocal_type, NULL, NULL); @@ -2500,6 +2529,11 @@ if (PyObject_SetAttrString(result, "names", value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_expr(o->v.Nonlocal.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); break; case Expr_kind: result = PyType_GenericNew(Expr_type, NULL, NULL); @@ -4493,6 +4527,7 @@ } if (PyObject_IsInstance(obj, (PyObject*)Global_type)) { asdl_seq* names; + expr_ty value; if (PyObject_HasAttrString(obj, "names")) { int res; @@ -4519,12 +4554,24 @@ PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); return 1; } - *out = Global(names, lineno, col_offset, arena); + if (PyObject_HasAttrString(obj, "value")) { + int res; + tmp = PyObject_GetAttrString(obj, "value"); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; + } + *out = Global(names, value, lineno, col_offset, arena); if (*out == NULL) goto failed; return 0; } if (PyObject_IsInstance(obj, (PyObject*)Nonlocal_type)) { asdl_seq* names; + expr_ty value; if (PyObject_HasAttrString(obj, "names")) { int res; @@ -4551,7 +4598,18 @@ PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); return 1; } - *out = Nonlocal(names, lineno, col_offset, arena); + if (PyObject_HasAttrString(obj, "value")) { + int res; + tmp = PyObject_GetAttrString(obj, "value"); + if (tmp == NULL) goto failed; + res = obj2ast_expr(tmp, &value, arena); + if (res != 0) goto failed; + Py_XDECREF(tmp); + tmp = NULL; + } else { + value = NULL; + } + *out = Nonlocal(names, value, lineno, col_offset, arena); if (*out == NULL) goto failed; return 0; } Index: Include/Python-ast.h =================================================================== --- Include/Python-ast.h (revision 67008) +++ Include/Python-ast.h (working copy) @@ -166,10 +166,12 @@ struct { asdl_seq *names; + expr_ty value; } Global; struct { asdl_seq *names; + expr_ty value; } Nonlocal; struct { @@ -442,12 +444,12 @@ #define ImportFrom(a0, a1, a2, a3, a4, a5) _Py_ImportFrom(a0, a1, a2, a3, a4, a5) stmt_ty _Py_ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int col_offset, PyArena *arena); -#define Global(a0, a1, a2, a3) _Py_Global(a0, a1, a2, a3) -stmt_ty _Py_Global(asdl_seq * names, int lineno, int col_offset, PyArena - *arena); -#define Nonlocal(a0, a1, a2, a3) _Py_Nonlocal(a0, a1, a2, a3) -stmt_ty _Py_Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena - *arena); +#define Global(a0, a1, a2, a3, a4) _Py_Global(a0, a1, a2, a3, a4) +stmt_ty _Py_Global(asdl_seq * names, expr_ty value, int lineno, int col_offset, + PyArena *arena); +#define Nonlocal(a0, a1, a2, a3, a4) _Py_Nonlocal(a0, a1, a2, a3, a4) +stmt_ty _Py_Nonlocal(asdl_seq * names, expr_ty value, int lineno, int + col_offset, PyArena *arena); #define Expr(a0, a1, a2, a3) _Py_Expr(a0, a1, a2, a3) stmt_ty _Py_Expr(expr_ty value, int lineno, int col_offset, PyArena *arena); #define Pass(a0, a1, a2) _Py_Pass(a0, a1, a2) Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 67008) +++ Grammar/Grammar (working copy) @@ -60,8 +60,8 @@ import_as_names: import_as_name (',' import_as_name)* [','] dotted_as_names: dotted_as_name (',' dotted_as_name)* dotted_name: NAME ('.' NAME)* -global_stmt: 'global' NAME (',' NAME)* -nonlocal_stmt: 'nonlocal' NAME (',' NAME)* +global_stmt: 'global' NAME (',' NAME)* ['=' testlist] +nonlocal_stmt: 'nonlocal' NAME (',' NAME)* ['=' testlist] assert_stmt: 'assert' test [',' test] compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated Index: Parser/Python.asdl =================================================================== --- Parser/Python.asdl (revision 67008) +++ Parser/Python.asdl (working copy) @@ -38,8 +38,8 @@ | Import(alias* names) | ImportFrom(identifier module, alias* names, int? level) - | Global(identifier* names) - | Nonlocal(identifier* names) + | Global(identifier* names, expr? value) + | Nonlocal(identifier* names, expr? value) | Expr(expr value) | Pass | Break | Continue Index: Lib/test/test_global.py =================================================================== --- Lib/test/test_global.py (revision 67008) +++ Lib/test/test_global.py (working copy) @@ -1,4 +1,4 @@ -"""Verify that warnings are issued for global statements following use.""" +"""Check the global statement.""" from test.support import run_unittest, check_syntax_error import unittest @@ -43,7 +43,14 @@ # this should work compile(prog_text_4, "", "exec") + def test_assign_global(self): + global x = 4 + self.assertEqual(x, 4) + global a, b = 3, 4 + self.assertEqual(a, 3) + self.assertEqual(b, 4) + def test_main(): run_unittest(GlobalTests) Index: Lib/test/test_scope.py =================================================================== --- Lib/test/test_scope.py (revision 67008) +++ Lib/test/test_scope.py (working copy) @@ -682,7 +682,22 @@ h = g() self.assertEqual(h(), 3) + def testAssignNonLocal(self): + x = 0 + y = 0 + def f(): + nonlocal x = 4 + f() + self.assertEqual(x, 4) + + def f(): + nonlocal x, y = 3, 4 + f() + self.assertEqual(x, 3) + self.assertEqual(y, 4) + + def test_main(): run_unittest(ScopeTests) Index: Lib/test/test_grammar.py =================================================================== --- Lib/test/test_grammar.py (revision 67010) +++ Lib/test/test_grammar.py (working copy) @@ -484,6 +484,10 @@ global a global a, b global one, two, three, four, five, six, seven, eight, nine, ten + global x = 3 + global h, g = 2, 4 + tup = (1, 2, 3) + global c, d, e = tup def testNonlocal(self): # 'nonlocal' NAME (',' NAME)* @@ -492,6 +496,9 @@ def f(): nonlocal x nonlocal x, y + nonlocal x = 3 + nonlocal x, y = 2, 3 + nonlocal x, y = tup def testAssert(self): # assert_stmt: 'assert' test [',' test]