Commit 18c95f72 authored by Jeremy Hylton's avatar Jeremy Hylton

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.
parent 639ddd98
...@@ -51,8 +51,8 @@ DL_IMPORT(int) PyCode_Addr2Line(PyCodeObject *, int); ...@@ -51,8 +51,8 @@ DL_IMPORT(int) PyCode_Addr2Line(PyCodeObject *, int);
/* Future feature support */ /* Future feature support */
typedef struct { typedef struct {
int ff_found_docstring;
int ff_last_lineno; int ff_last_lineno;
int ff_n_simple_stmt;
int ff_nested_scopes; int ff_nested_scopes;
} PyFutureFeatures; } PyFutureFeatures;
......
...@@ -64,6 +64,9 @@ int Py_OptimizeFlag = 0; ...@@ -64,6 +64,9 @@ int Py_OptimizeFlag = 0;
#define LOCAL_GLOBAL \ #define LOCAL_GLOBAL \
"name '%.400s' is a function paramter and declared global" "name '%.400s' is a function paramter and declared global"
#define LATE_FUTURE \
"from __future__ imports must occur at the beginning of the file"
#define MANGLE_LEN 256 #define MANGLE_LEN 256
#define OFF(x) offsetof(PyCodeObject, x) #define OFF(x) offsetof(PyCodeObject, x)
...@@ -605,6 +608,8 @@ com_free(struct compiling *c) ...@@ -605,6 +608,8 @@ com_free(struct compiling *c)
Py_XDECREF(c->c_freevars); Py_XDECREF(c->c_freevars);
Py_XDECREF(c->c_cellvars); Py_XDECREF(c->c_cellvars);
Py_XDECREF(c->c_lnotab); Py_XDECREF(c->c_lnotab);
if (c->c_future)
PyMem_Free((void *)c->c_future);
} }
static void static void
...@@ -1544,9 +1549,12 @@ com_argument(struct compiling *c, node *n, PyObject **pkeywords) ...@@ -1544,9 +1549,12 @@ com_argument(struct compiling *c, node *n, PyObject **pkeywords)
PyObject *v = PyString_InternFromString(STR(m)); PyObject *v = PyString_InternFromString(STR(m));
if (v != NULL && *pkeywords == NULL) if (v != NULL && *pkeywords == NULL)
*pkeywords = PyDict_New(); *pkeywords = PyDict_New();
if (v == NULL || *pkeywords == NULL) if (v == NULL)
c->c_errors++; c->c_errors++;
else { else if (*pkeywords == NULL) {
c->c_errors++;
Py_DECREF(v);
} else {
if (PyDict_GetItem(*pkeywords, v) != NULL) if (PyDict_GetItem(*pkeywords, v) != NULL)
com_error(c, PyExc_SyntaxError, com_error(c, PyExc_SyntaxError,
"duplicate keyword argument"); "duplicate keyword argument");
...@@ -3995,6 +4003,7 @@ symtable_build(struct compiling *c, node *n) ...@@ -3995,6 +4003,7 @@ symtable_build(struct compiling *c, node *n)
{ {
if ((c->c_symtable = symtable_init()) == NULL) if ((c->c_symtable = symtable_init()) == NULL)
return -1; return -1;
c->c_symtable->st_future = c->c_future;
if (c->c_future->ff_nested_scopes) if (c->c_future->ff_nested_scopes)
c->c_symtable->st_nested_scopes = 1; c->c_symtable->st_nested_scopes = 1;
c->c_symtable->st_filename = c->c_filename; c->c_symtable->st_filename = c->c_filename;
...@@ -4482,12 +4491,15 @@ symtable_add_def(struct symtable *st, char *name, int flag) ...@@ -4482,12 +4491,15 @@ symtable_add_def(struct symtable *st, char *name, int flag)
{ {
PyObject *s; PyObject *s;
char buffer[MANGLE_LEN]; char buffer[MANGLE_LEN];
int ret;
if (mangle(st->st_private, name, buffer, sizeof(buffer))) if (mangle(st->st_private, name, buffer, sizeof(buffer)))
name = buffer; name = buffer;
if ((s = PyString_InternFromString(name)) == NULL) if ((s = PyString_InternFromString(name)) == NULL)
return -1; return -1;
return symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag); ret = symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag);
Py_DECREF(s);
return ret;
} }
/* Must only be called with mangled names */ /* Must only be called with mangled names */
...@@ -4819,12 +4831,14 @@ symtable_global(struct symtable *st, node *n) ...@@ -4819,12 +4831,14 @@ symtable_global(struct symtable *st, node *n)
int flags; int flags;
flags = symtable_lookup(st, name); flags = symtable_lookup(st, name);
if (flags < 0)
continue;
if (flags && flags != DEF_GLOBAL) { if (flags && flags != DEF_GLOBAL) {
char buf[500]; char buf[500];
if (flags & DEF_PARAM) { if (flags & DEF_PARAM) {
PyErr_Format(PyExc_SyntaxError, PyErr_Format(PyExc_SyntaxError,
"name '%.400s' is local and global", "name '%.400s' is local and global",
PyString_AS_STRING(name)); name);
set_error_location(st->st_filename, set_error_location(st->st_filename,
st->st_cur->ste_lineno); st->st_cur->ste_lineno);
st->st_errors++; st->st_errors++;
...@@ -4873,6 +4887,18 @@ symtable_import(struct symtable *st, node *n) ...@@ -4873,6 +4887,18 @@ symtable_import(struct symtable *st, node *n)
import_as_name: NAME [NAME NAME] import_as_name: NAME [NAME NAME]
*/ */
if (STR(CHILD(n, 0))[0] == 'f') { /* from */ 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) {
PyErr_SetString(PyExc_SyntaxError,
LATE_FUTURE);
set_error_location(st->st_filename,
n->n_lineno);
st->st_errors++;
return;
}
}
if (TYPE(CHILD(n, 3)) == STAR) { if (TYPE(CHILD(n, 3)) == STAR) {
st->st_cur->ste_optimized |= OPT_IMPORT_STAR; st->st_cur->ste_optimized |= OPT_IMPORT_STAR;
} else { } else {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
#define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
static int static int
future_check_features(PyFutureFeatures *ff, node *n) future_check_features(PyFutureFeatures *ff, node *n)
{ {
...@@ -28,6 +30,15 @@ future_check_features(PyFutureFeatures *ff, node *n) ...@@ -28,6 +30,15 @@ future_check_features(PyFutureFeatures *ff, node *n)
return 0; 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: /* Relevant portions of the grammar:
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
...@@ -48,52 +59,82 @@ dotted_name: NAME ('.' NAME)* ...@@ -48,52 +59,82 @@ dotted_name: NAME ('.' NAME)*
*/ */
static int static int
future_parse(PyFutureFeatures *ff, node *n) future_parse(PyFutureFeatures *ff, node *n, char *filename)
{ {
int i, r, found; int i, r;
loop: loop:
/* fprintf(stderr, "future_parse(%d, %d, %s)\n", /* fprintf(stderr, "future_parse(%d, %d, %s, %d)\n",
TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n)); TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n),
n->n_lineno);
*/ */
switch (TYPE(n)) { switch (TYPE(n)) {
case file_input: case file_input:
for (i = 0; i < NCH(n); i++) { for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i); node *ch = CHILD(n, i);
if (TYPE(ch) == stmt) { if (TYPE(ch) == stmt) {
n = ch; r = future_parse(ff, ch, filename);
goto loop; if (!FUTURE_POSSIBLE(ff))
return r;
} }
} }
return 0; return 0;
case simple_stmt: case simple_stmt:
if (NCH(n) == 1) { if (NCH(n) == 2) {
REQ(CHILD(n, 0), small_stmt); REQ(CHILD(n, 0), small_stmt);
n = CHILD(n, 0); n = CHILD(n, 0);
goto loop; goto loop;
} } else {
found = 0; /* Deal with the special case of a series of
for (i = 0; i < NCH(n); ++i) small statements on a single line. If a
if (TYPE(CHILD(n, i)) == small_stmt) { future statement follows some other
r = future_parse(ff, CHILD(n, i)); statement, the SyntaxError is raised here.
if (r < 1) { In all other cases, the symtable pass
ff->ff_last_lineno = n->n_lineno; raises the exception.
ff->ff_n_simple_stmt = i; */
return r; int found = 0, end_of_future = 0;
} else
found++; 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; /* If we found one and only one, then the
else current lineno is legal.
return 0; */
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: case stmt:
if (TYPE(CHILD(n, 0)) == simple_stmt) { if (TYPE(CHILD(n, 0)) == simple_stmt) {
n = CHILD(n, 0); n = CHILD(n, 0);
goto loop; goto loop;
} else if (TYPE(CHILD(n, 0)) == expr_stmt) {
n = CHILD(n, 0);
goto loop;
} else { } else {
REQ(CHILD(n, 0), compound_stmt); REQ(CHILD(n, 0), compound_stmt);
ff->ff_last_lineno = n->n_lineno; ff->ff_last_lineno = n->n_lineno;
...@@ -119,10 +160,42 @@ future_parse(PyFutureFeatures *ff, node *n) ...@@ -119,10 +160,42 @@ future_parse(PyFutureFeatures *ff, node *n)
return 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: default:
ff->ff_last_lineno = n->n_lineno; ff->ff_last_lineno = n->n_lineno;
return 0; return 0;
} }
return 0;
} }
PyFutureFeatures * PyFutureFeatures *
...@@ -133,11 +206,11 @@ PyNode_Future(node *n, char *filename) ...@@ -133,11 +206,11 @@ PyNode_Future(node *n, char *filename)
ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures)); ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
if (ff == NULL) if (ff == NULL)
return NULL; return NULL;
ff->ff_last_lineno = 0; ff->ff_found_docstring = 0;
ff->ff_n_simple_stmt = -1; ff->ff_last_lineno = -1;
ff->ff_nested_scopes = 0; ff->ff_nested_scopes = 0;
if (future_parse(ff, n) < 0) { if (future_parse(ff, n, filename) < 0) {
PyMem_Free((void *)ff); PyMem_Free((void *)ff);
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment