Index: Python/compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.314 diff -u -c -r2.314 compile.c *** Python/compile.c 6 Aug 2004 19:46:34 -0000 2.314 --- Python/compile.c 9 Aug 2004 04:01:38 -0000 *************** *** 3333,3374 **** static void com_import_stmt(struct compiling *c, node *n) { int i; REQ(n, import_stmt); ! /* 'import' dotted_name (',' dotted_name)* | ! 'from' dotted_name 'import' ('*' | NAME (',' NAME)*) */ ! if (STR(CHILD(n, 0))[0] == 'f') { PyObject *tup; - /* 'from' dotted_name 'import' ... */ REQ(CHILD(n, 1), dotted_name); ! ! if (TYPE(CHILD(n, 3)) == STAR) { tup = Py_BuildValue("(s)", "*"); ! } else { ! tup = PyTuple_New((NCH(n) - 2)/2); ! for (i = 3; i < NCH(n); i += 2) { ! PyTuple_SET_ITEM(tup, (i-3)/2, PyString_FromString(STR( ! CHILD(CHILD(n, i), 0)))); } } com_addoparg(c, LOAD_CONST, com_addconst(c, tup)); Py_DECREF(tup); com_push(c, 1); com_addopname(c, IMPORT_NAME, CHILD(n, 1)); ! if (TYPE(CHILD(n, 3)) == STAR) com_addbyte(c, IMPORT_STAR); else { ! for (i = 3; i < NCH(n); i += 2) ! com_from_import(c, CHILD(n, i)); com_addbyte(c, POP_TOP); } com_pop(c, 1); } else { ! /* 'import' ... */ ! for (i = 1; i < NCH(n); i += 2) { ! node *subn = CHILD(n, i); REQ(subn, dotted_as_name); com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); com_push(c, 1); --- 3333,3379 ---- static void com_import_stmt(struct compiling *c, node *n) { + node *nn; int i; REQ(n, import_stmt); ! n = CHILD(n, 0); ! /* import_stmt: just_import | from_import */ ! if (TYPE(n) == from_import) { ! /* from_import: 'from' dotted_name 'import' ('*' | '(' '*' ')' ! | '(' import_as_names ')' | import_as_names) */ PyObject *tup; REQ(CHILD(n, 1), dotted_name); ! nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); ! if (TYPE(nn) == STAR) tup = Py_BuildValue("(s)", "*"); ! else { ! REQ(nn, import_as_names); ! tup = PyTuple_New((NCH(nn) + 1) / 2); ! for (i = 0; i < NCH(nn); i += 2) { ! PyTuple_SET_ITEM(tup, i / 2, PyString_FromString(STR( ! CHILD(CHILD(nn, i), 0)))); } } com_addoparg(c, LOAD_CONST, com_addconst(c, tup)); Py_DECREF(tup); com_push(c, 1); com_addopname(c, IMPORT_NAME, CHILD(n, 1)); ! if (TYPE(nn) == STAR) com_addbyte(c, IMPORT_STAR); else { ! for (i = 0; i < NCH(nn); i += 2) ! com_from_import(c, CHILD(nn, i)); com_addbyte(c, POP_TOP); } com_pop(c, 1); } else { ! /* 'import' ('(' dotted_as_names ')' | dotted_as_names)*/ ! nn = CHILD(n, 1 + (TYPE(CHILD(n, 1)) == LPAR)); ! REQ(nn, dotted_as_names); ! for (i = 0; i < NCH(nn); i += 2) { ! node *subn = CHILD(nn, i); REQ(subn, dotted_as_name); com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); com_push(c, 1); *************** *** 6131,6144 **** static void symtable_import(struct symtable *st, node *n) { int i; ! /* import_stmt: 'import' dotted_as_name (',' dotted_as_name)* ! | 'from' dotted_name 'import' ! ('*' | import_as_name (',' import_as_name)*) ! import_as_name: NAME [NAME NAME] ! */ ! if (STR(CHILD(n, 0))[0] == 'f') { /* from */ node *dotname = CHILD(n, 1); if (strcmp(STR(CHILD(dotname, 0)), "__future__") == 0) { /* check for bogus imports */ if (n->n_lineno >= st->st_future->ff_last_lineno) { --- 6136,6150 ---- static void symtable_import(struct symtable *st, node *n) { + node *nn; int i; ! /* import_stmt: just_import | from_import */ ! n = CHILD(n, 0); ! if (TYPE(n) == from_import) { ! /* from_import: 'from' dotted_name 'import' ('*' | '(' '*' ')' ! | '(' import_as_names ')' | import_as_names) */ node *dotname = CHILD(n, 1); + REQ(dotname, dotted_name); if (strcmp(STR(CHILD(dotname, 0)), "__future__") == 0) { /* check for bogus imports */ if (n->n_lineno >= st->st_future->ff_last_lineno) { *************** *** 6148,6154 **** return; } } ! if (TYPE(CHILD(n, 3)) == STAR) { if (st->st_cur->ste_type != TYPE_MODULE) { if (symtable_warn(st, "import * only allowed at module level") < 0) --- 6154,6161 ---- return; } } ! nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); ! if (TYPE(nn) == STAR) { if (st->st_cur->ste_type != TYPE_MODULE) { if (symtable_warn(st, "import * only allowed at module level") < 0) *************** *** 6157,6164 **** st->st_cur->ste_optimized |= OPT_IMPORT_STAR; st->st_cur->ste_opt_lineno = n->n_lineno; } else { ! for (i = 3; i < NCH(n); i += 2) { ! node *c = CHILD(n, i); if (NCH(c) > 1) /* import as */ symtable_assign(st, CHILD(c, 2), DEF_IMPORT); --- 6164,6172 ---- st->st_cur->ste_optimized |= OPT_IMPORT_STAR; st->st_cur->ste_opt_lineno = n->n_lineno; } else { ! REQ(nn, import_as_names); ! for (i = 0; i < NCH(nn); i += 2) { ! node *c = CHILD(nn, i); if (NCH(c) > 1) /* import as */ symtable_assign(st, CHILD(c, 2), DEF_IMPORT); *************** *** 6167,6176 **** DEF_IMPORT); } } ! } else { ! for (i = 1; i < NCH(n); i += 2) { ! symtable_assign(st, CHILD(n, i), DEF_IMPORT); ! } } } --- 6175,6186 ---- DEF_IMPORT); } } ! } else { ! /* 'import' ('(' dotted_as_names ')' | dotted_as_names)*/ ! nn = CHILD(n, 1 + (TYPE(CHILD(n, 1)) == LPAR)); ! REQ(nn, dotted_as_names); ! for (i = 0; i < NCH(nn); i += 2) ! symtable_assign(st, CHILD(nn, i), DEF_IMPORT); } } Index: Python/future.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/future.c,v retrieving revision 2.13 diff -u -c -r2.13 future.c *** Python/future.c 11 Dec 2002 14:04:59 -0000 2.13 --- Python/future.c 9 Aug 2004 04:01:38 -0000 *************** *** 18,35 **** { int i; char *feature; ! node *ch; ! REQ(n, import_stmt); /* must by from __future__ import ... */ ! ! for (i = 3; i < NCH(n); i += 2) { ! ch = CHILD(n, i); ! if (TYPE(ch) == STAR) { ! PyErr_SetString(PyExc_SyntaxError, ! FUTURE_IMPORT_STAR); ! PyErr_SyntaxLocation(filename, ch->n_lineno); ! return -1; ! } REQ(ch, import_as_name); feature = STR(CHILD(ch, 0)); if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { --- 18,35 ---- { int i; char *feature; ! node *ch, *nn; ! REQ(n, from_import); ! nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR)); ! if (TYPE(nn) == STAR) { ! PyErr_SetString(PyExc_SyntaxError, FUTURE_IMPORT_STAR); ! PyErr_SyntaxLocation(filename, nn->n_lineno); ! return -1; ! } ! REQ(nn, import_as_names); ! for (i = 0; i < NCH(nn); i += 2) { ! ch = CHILD(nn, i); REQ(ch, import_as_name); feature = STR(CHILD(ch, 0)); if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { *************** *** 188,194 **** case import_stmt: { node *name; ! if (STR(CHILD(n, 0))[0] != 'f') { /* from */ ff->ff_last_lineno = n->n_lineno; return 0; } --- 188,195 ---- case import_stmt: { node *name; ! n = CHILD(n, 0); ! if (TYPE(n) != from_import) { ff->ff_last_lineno = n->n_lineno; return 0; } Index: Grammar/Grammar =================================================================== RCS file: /cvsroot/python/python/dist/src/Grammar/Grammar,v retrieving revision 1.50 diff -u -c -r1.50 Grammar *** Grammar/Grammar 2 Aug 2004 06:09:53 -0000 1.50 --- Grammar/Grammar 9 Aug 2004 04:01:38 -0000 *************** *** 51,59 **** return_stmt: 'return' [testlist] yield_stmt: 'yield' testlist raise_stmt: 'raise' [test [',' test [',' test]]] ! import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*) import_as_name: NAME [NAME NAME] dotted_as_name: dotted_name [NAME NAME] dotted_name: NAME ('.' NAME)* global_stmt: 'global' NAME (',' NAME)* exec_stmt: 'exec' expr ['in' test [',' test]] --- 51,63 ---- return_stmt: 'return' [testlist] yield_stmt: 'yield' testlist raise_stmt: 'raise' [test [',' test [',' test]]] ! import_stmt: just_import | from_import ! just_import: 'import' ('(' dotted_as_names ')' | dotted_as_names) ! from_import: 'from' dotted_name 'import' ('*' | '(' '*' ')' | '(' import_as_names ')' | import_as_names) import_as_name: NAME [NAME NAME] dotted_as_name: dotted_name [NAME NAME] + 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)* exec_stmt: 'exec' expr ['in' test [',' test]] Index: Lib/test/test_compile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_compile.py,v retrieving revision 1.22 diff -u -c -r1.22 test_compile.py *** Lib/test/test_compile.py 2 Aug 2004 08:30:07 -0000 1.22 --- Lib/test/test_compile.py 9 Aug 2004 04:01:39 -0000 *************** *** 211,216 **** --- 211,263 ---- self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single') self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') + def test_import(self): + # These should pass + exec ''' + from __future__ import (nested_scopes, generators) + import sys + import (os, + sys) + from sys import (stdin, stderr, + stdout) + from keyword import (*)''' + # These should fail + try: + exec 'from (sys) import stdin' + self.fail("parens not allowed around single dotted_name") + except SyntaxError: + pass + try: + exec 'import (os), (sys)' + self.fail("entire name list must be enclosed in parens") + except SyntaxError: + pass + try: + exec 'import ((os), (sys))' + self.fail("subparens not allowed") + except SyntaxError: + pass + try: + exec 'import sys)' + self.fail("mismatched parens") + except SyntaxError: + pass + try: + exec 'from sys import stdin)' + self.fail("mismatched parens") + except SyntaxError: + pass + try: + exec 'import (os,)' + self.fail("not a tuple") + except SyntaxError: + pass + try: + exec 'from __future__ import nested_scopes)' + self.fail("mismatched parens in __future__"); + except SyntaxError: + pass + def test_main(): test_support.run_unittest(TestSpecifics) Index: Lib/test/test_grammar.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_grammar.py,v retrieving revision 1.50 diff -u -c -r1.50 test_grammar.py *** Lib/test/test_grammar.py 19 May 2004 08:20:09 -0000 1.50 --- Lib/test/test_grammar.py 9 Aug 2004 04:01:42 -0000 *************** *** 417,428 **** try: raise KeyboardInterrupt except KeyboardInterrupt: pass ! print 'import_stmt' # 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*) import sys import time, sys from time import time from sys import * from sys import path, argv print 'global_stmt' # 'global' NAME (',' NAME)* def f(): --- 417,434 ---- try: raise KeyboardInterrupt except KeyboardInterrupt: pass ! print 'just_import' # 'import' ('(' dotted_as_names ')' | dotted_as_names) import sys + import (sys) import time, sys + import (time, sys) + print 'from_import' # 'from' dotted_name 'import' ('*' | '(' '*' ')' | '(' import_as_names ')' | import_as_names) from time import time + from time import (time) from sys import * + from sys import (*) from sys import path, argv + from sys import (path, argv) print 'global_stmt' # 'global' NAME (',' NAME)* def f(): Index: Lib/test/output/test_grammar =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/output/test_grammar,v retrieving revision 1.20 diff -u -c -r1.20 test_grammar *** Lib/test/output/test_grammar 21 May 2003 17:34:49 -0000 1.20 --- Lib/test/output/test_grammar 9 Aug 2004 04:01:42 -0000 *************** *** 35,41 **** testing continue and break in try/except in loop return_stmt raise_stmt ! import_stmt global_stmt exec_stmt assert_stmt --- 35,42 ---- testing continue and break in try/except in loop return_stmt raise_stmt ! just_import ! from_import global_stmt exec_stmt assert_stmt