[Python-checkins] python/dist/src/Python future.c,2.12.2.2,2.12.2.3
jhylton@users.sourceforge.net
jhylton@users.sourceforge.net
Fri, 16 Aug 2002 13:19:55 -0700
Update of /cvsroot/python/python/dist/src/Python
In directory usw-pr-cvs1:/tmp/cvs-serv13783
Modified Files:
Tag: ast-branch
future.c
Log Message:
Rewrite future to use the AST.
Index: future.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/future.c,v
retrieving revision 2.12.2.2
retrieving revision 2.12.2.3
diff -C2 -d -r2.12.2.2 -r2.12.2.3
*** future.c 9 Jul 2002 13:22:01 -0000 2.12.2.2
--- future.c 16 Aug 2002 20:19:53 -0000 2.12.2.3
***************
*** 11,38 ****
#define FUTURE_IMPORT_STAR "future statement does not support import *"
- /* FUTURE_POSSIBLE() is provided to accomodate doc strings, which is
- the only statement that can occur before a future statement.
- */
- #define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
-
static int
! future_check_features(PyFutureFeatures *ff, node *n, char *filename)
{
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) {
continue;
--- 11,28 ----
#define FUTURE_IMPORT_STAR "future statement does not support import *"
static int
! future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
{
int i;
! const char *feature;
! asdl_seq *names;
! assert(s->kind == ImportFrom_kind);
! names = s->v.ImportFrom.names;
! for (i = 0; i < asdl_seq_LEN(names); i++) {
! feature = PyString_AsString(asdl_seq_get(names, i));
! if (!feature)
! return 0;
if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
continue;
***************
*** 44,247 ****
PyErr_SetString(PyExc_SyntaxError,
"not a chance");
! PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
! return -1;
} else {
PyErr_Format(PyExc_SyntaxError,
UNDEFINED_FUTURE_FEATURE, feature);
! PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
! return -1;
}
}
! return 0;
! }
!
! static void
! future_error(node *n, char *filename)
! {
! PyErr_SetString(PyExc_SyntaxError,
! "from __future__ imports must occur at the "
! "beginning of the file");
! PyErr_SyntaxLocation(filename, n->n_lineno);
}
! /* Relevant portions of the grammar:
!
! single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
! file_input: (NEWLINE | stmt)* ENDMARKER
! stmt: simple_stmt | compound_stmt
! simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
! small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt
! | import_stmt | global_stmt | exec_stmt | assert_stmt
! 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)*
! */
!
! /* future_parse() finds future statements at the beginnning of a
! module. The function calls itself recursively, rather than
! factoring out logic for different kinds of statements into
! different routines.
!
! Return values:
! -1 indicates an error occurred, e.g. unknown feature name
! 0 indicates no feature was found
! 1 indicates a feature was found
! */
!
! static int
! future_parse(PyFutureFeatures *ff, node *n, char *filename)
{
! int i, r;
! loop:
! switch (TYPE(n)) {
! case single_input:
! if (TYPE(CHILD(n, 0)) == simple_stmt) {
! n = CHILD(n, 0);
! goto loop;
! }
! return 0;
! case file_input:
! /* Check each statement in the file, starting with the
! first, and continuing until the first statement
! that isn't a future statement.
*/
- for (i = 0; i < NCH(n); i++) {
- node *ch = CHILD(n, i);
- if (TYPE(ch) == stmt) {
- r = future_parse(ff, ch, filename);
- /* Need to check both conditions below
- to accomodate doc strings, which
- causes r < 0.
- */
- if (r < 1 && !FUTURE_POSSIBLE(ff))
- return r;
- }
- }
- return 0;
! case simple_stmt:
! if (NCH(n) == 2) {
! REQ(CHILD(n, 0), small_stmt);
! n = CHILD(n, 0);
! goto loop;
! } else {
! /* Deal with the special case of a series of
! small statements on a single line. If a
! future statement follows some other
! statement, the SyntaxError is raised here.
! In all other cases, the symtable pass
! raises the exception.
! */
! int found = 0, end_of_future = 0;
!
! for (i = 0; i < NCH(n); i += 2) {
! if (TYPE(CHILD(n, i)) == small_stmt) {
! r = future_parse(ff, CHILD(n, i),
! filename);
! if (r < 1)
! end_of_future = 1;
! else {
! found = 1;
! if (end_of_future) {
! future_error(n,
! filename);
! return -1;
! }
! }
! }
}
-
- /* If we found one and only one, then the
- current lineno is legal.
- */
- if (found)
- ff->ff_last_lineno = n->n_lineno + 1;
else
- ff->ff_last_lineno = n->n_lineno;
-
- if (end_of_future && found)
return 1;
- else
- return 0;
- }
-
- case stmt:
- if (TYPE(CHILD(n, 0)) == simple_stmt) {
- n = CHILD(n, 0);
- goto loop;
- } else if (TYPE(CHILD(n, 0)) == expr_stmt) {
- n = CHILD(n, 0);
- goto loop;
- } else {
- REQ(CHILD(n, 0), compound_stmt);
- ff->ff_last_lineno = n->n_lineno;
- return 0;
}
!
! case small_stmt:
! n = CHILD(n, 0);
! goto loop;
!
! case import_stmt: {
! node *name;
!
! if (STR(CHILD(n, 0))[0] != 'f') { /* from */
! ff->ff_last_lineno = n->n_lineno;
! return 0;
! }
! name = CHILD(n, 1);
! if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
! return 0;
! if (future_check_features(ff, n, filename) < 0)
! return -1;
! ff->ff_last_lineno = n->n_lineno + 1;
! return 1;
! }
!
! /* The cases below -- all of them! -- are necessary to find
! and skip doc strings. */
! case expr_stmt:
! case testlist:
! case test:
! case and_test:
! case not_test:
! case comparison:
! case expr:
! case xor_expr:
! case and_expr:
! case shift_expr:
! case arith_expr:
! case term:
! case factor:
! case power:
! if (NCH(n) == 1) {
! n = CHILD(n, 0);
! goto loop;
! }
! break;
!
! case atom:
! if (TYPE(CHILD(n, 0)) == STRING
! && ff->ff_found_docstring == 0) {
! ff->ff_found_docstring = 1;
! return 0;
}
! ff->ff_last_lineno = n->n_lineno;
! return 0;
!
! default:
! ff->ff_last_lineno = n->n_lineno;
! return 0;
}
! return 0;
}
PyFutureFeatures *
! PyNode_Future(node *n, char *filename)
{
PyFutureFeatures *ff;
--- 34,94 ----
PyErr_SetString(PyExc_SyntaxError,
"not a chance");
! PyErr_SyntaxLocation(filename, s->lineno);
! return 0;
} else {
PyErr_Format(PyExc_SyntaxError,
UNDEFINED_FUTURE_FEATURE, feature);
! PyErr_SyntaxLocation(filename, s->lineno);
! return 0;
}
}
! return 1;
}
! int
! future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
{
! int i;
! static PyObject *future;
! if (!future) {
! future = PyString_InternFromString("__future__");
! if (!future)
! return 0;
! }
! if (mod->kind != Module_kind) /* XXX */
! return 1;
! for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
! stmt_ty s = asdl_seq_get(mod->v.Module.body, i);
! /* The tests below will return from this function unless it is
! still possible to find a future statement. The only things
! that can precede a future statement are another future
! statement and a doc string.
*/
! if (s->kind == ImportFrom_kind) {
! if (s->v.ImportFrom.module == future) {
! if (!future_check_features(ff, s, filename))
! return 0;
}
else
return 1;
}
! else if (s->kind == Expr_kind) {
! expr_ty e = s->v.Expr.value;
! if (e->kind != Str_kind)
! return 1;
}
! else
! return 1;
}
! return 1;
}
+
PyFutureFeatures *
! PyFuture_FromAST(mod_ty mod, const char *filename)
{
PyFutureFeatures *ff;
***************
*** 254,258 ****
ff->ff_features = 0;
! if (future_parse(ff, n, filename) < 0) {
PyMem_Free((void *)ff);
return NULL;
--- 101,105 ----
ff->ff_features = 0;
! if (!future_parse(ff, mod, filename)) {
PyMem_Free((void *)ff);
return NULL;