summaryrefslogtreecommitdiff
path: root/Python/future.c
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2001-02-28 01:58:08 +0000
committerJeremy Hylton <jeremy@alum.mit.edu>2001-02-28 01:58:08 +0000
commit39e2f3f82499e2c06c092d38b77d554bee6f31e8 (patch)
treee37063c1c7bba98df17276b7afe4f972d51d0ae6 /Python/future.c
parent8e43cd79293d70ddb6728ef90335e442d96ce038 (diff)
downloadcpython-git-39e2f3f82499e2c06c092d38b77d554bee6f31e8.tar.gz
Presumed correct compiler pass for future statements
XXX still need to integrate into symtable API compile.h: Remove ff_n_simple_stmt; obsolete. Add ff_found_docstring used internally to skip one and only one string at the beginning of a module. compile.c: Add check for from __future__ imports to far into the file. In symtable_global() check for -1 returned from symtable_lookup(), which signifies name not defined. Add missing DECERF in symtable_add_def. Free c->c_future. future.c: Add special handling for multiple statements joined on a single line using one or more semicolons; this form can include an illegal future statement that would otherwise be hard to detect. Add support for detecting and skipping doc strings.
Diffstat (limited to 'Python/future.c')
-rw-r--r--Python/future.c123
1 files changed, 98 insertions, 25 deletions
diff --git a/Python/future.c b/Python/future.c
index f67abc978f..18bae1f9b9 100644
--- a/Python/future.c
+++ b/Python/future.c
@@ -7,6 +7,8 @@
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
+#define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
+
static int
future_check_features(PyFutureFeatures *ff, node *n)
{
@@ -28,6 +30,15 @@ future_check_features(PyFutureFeatures *ff, node *n)
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");
+ /* XXX set filename and lineno */
+}
+
/* Relevant portions of the grammar:
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
@@ -48,52 +59,82 @@ dotted_name: NAME ('.' NAME)*
*/
static int
-future_parse(PyFutureFeatures *ff, node *n)
+future_parse(PyFutureFeatures *ff, node *n, char *filename)
{
- int i, r, found;
+ int i, r;
loop:
-/* fprintf(stderr, "future_parse(%d, %d, %s)\n",
- TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n));
+/* fprintf(stderr, "future_parse(%d, %d, %s, %d)\n",
+ TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n),
+ n->n_lineno);
*/
+
switch (TYPE(n)) {
case file_input:
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == stmt) {
- n = ch;
- goto loop;
+ r = future_parse(ff, ch, filename);
+ if (!FUTURE_POSSIBLE(ff))
+ return r;
}
}
return 0;
case simple_stmt:
- if (NCH(n) == 1) {
+ if (NCH(n) == 2) {
REQ(CHILD(n, 0), small_stmt);
n = CHILD(n, 0);
goto loop;
- }
- found = 0;
- for (i = 0; i < NCH(n); ++i)
- if (TYPE(CHILD(n, i)) == small_stmt) {
- r = future_parse(ff, CHILD(n, i));
- if (r < 1) {
- ff->ff_last_lineno = n->n_lineno;
- ff->ff_n_simple_stmt = i;
- return r;
- } else
- found++;
+ } 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 (found)
- return 1;
- else
- return 0;
+
+ /* 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;
@@ -119,10 +160,42 @@ future_parse(PyFutureFeatures *ff, node *n)
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 *
@@ -133,11 +206,11 @@ PyNode_Future(node *n, char *filename)
ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
if (ff == NULL)
return NULL;
- ff->ff_last_lineno = 0;
- ff->ff_n_simple_stmt = -1;
+ ff->ff_found_docstring = 0;
+ ff->ff_last_lineno = -1;
ff->ff_nested_scopes = 0;
- if (future_parse(ff, n) < 0) {
+ if (future_parse(ff, n, filename) < 0) {
PyMem_Free((void *)ff);
return NULL;
}