mirror of
https://github.com/python/cpython.git
synced 2025-09-05 16:31:16 +00:00
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.
This commit is contained in:
parent
8e43cd7929
commit
39e2f3f824
3 changed files with 129 additions and 30 deletions
123
Python/future.c
123
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue