#include "Python.h" | |
#include "Python-ast.h" | |
#include "node.h" | |
#include "token.h" | |
#include "graminit.h" | |
#include "code.h" | |
#include "compile.h" | |
#include "symtable.h" | |
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" | |
#define ERR_LATE_FUTURE \ | |
"from __future__ imports must occur at the beginning of the file" | |
static int | |
future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) | |
{ | |
int i; | |
asdl_seq *names; | |
assert(s->kind == ImportFrom_kind); | |
names = s->v.ImportFrom.names; | |
for (i = 0; i < asdl_seq_LEN(names); i++) { | |
alias_ty name = (alias_ty)asdl_seq_GET(names, i); | |
const char *feature = PyString_AsString(name->name); | |
if (!feature) | |
return 0; | |
if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { | |
continue; | |
} else if (strcmp(feature, FUTURE_GENERATORS) == 0) { | |
continue; | |
} else if (strcmp(feature, FUTURE_DIVISION) == 0) { | |
ff->ff_features |= CO_FUTURE_DIVISION; | |
} else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { | |
ff->ff_features |= CO_FUTURE_ABSOLUTE_IMPORT; | |
} else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { | |
ff->ff_features |= CO_FUTURE_WITH_STATEMENT; | |
} else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { | |
ff->ff_features |= CO_FUTURE_PRINT_FUNCTION; | |
} else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { | |
ff->ff_features |= CO_FUTURE_UNICODE_LITERALS; | |
} else if (strcmp(feature, "braces") == 0) { | |
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; | |
} | |
static int | |
future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename) | |
{ | |
int i, found_docstring = 0, done = 0, prev_line = 0; | |
static PyObject *future; | |
if (!future) { | |
future = PyString_InternFromString("__future__"); | |
if (!future) | |
return 0; | |
} | |
if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) | |
return 1; | |
/* A subsequent pass will detect future imports that don't | |
appear at the beginning of the file. There's one case, | |
however, that is easier to handle here: A series of imports | |
joined by semi-colons, where the first import is a future | |
statement but some subsequent import has the future form | |
but is preceded by a regular import. | |
*/ | |
for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) { | |
stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); | |
if (done && s->lineno > prev_line) | |
return 1; | |
prev_line = s->lineno; | |
/* 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 (done) { | |
PyErr_SetString(PyExc_SyntaxError, | |
ERR_LATE_FUTURE); | |
PyErr_SyntaxLocation(filename, | |
s->lineno); | |
return 0; | |
} | |
if (!future_check_features(ff, s, filename)) | |
return 0; | |
ff->ff_lineno = s->lineno; | |
} | |
else | |
done = 1; | |
} | |
else if (s->kind == Expr_kind && !found_docstring) { | |
expr_ty e = s->v.Expr.value; | |
if (e->kind != Str_kind) | |
done = 1; | |
else | |
found_docstring = 1; | |
} | |
else | |
done = 1; | |
} | |
return 1; | |
} | |
PyFutureFeatures * | |
PyFuture_FromAST(mod_ty mod, const char *filename) | |
{ | |
PyFutureFeatures *ff; | |
ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures)); | |
if (ff == NULL) { | |
PyErr_NoMemory(); | |
return NULL; | |
} | |
ff->ff_features = 0; | |
ff->ff_lineno = -1; | |
if (!future_parse(ff, mod, filename)) { | |
PyObject_Free(ff); | |
return NULL; | |
} | |
return ff; | |
} |