xref: /third_party/python/Python/future.c (revision 7db96d56)
1#include "Python.h"
2#include "pycore_ast.h"           // _PyAST_GetDocString()
3
4#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
5#define ERR_LATE_FUTURE \
6"from __future__ imports must occur at the beginning of the file"
7
8static int
9future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
10{
11    int i;
12
13    assert(s->kind == ImportFrom_kind);
14
15    asdl_alias_seq *names = s->v.ImportFrom.names;
16    for (i = 0; i < asdl_seq_LEN(names); i++) {
17        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
18        const char *feature = PyUnicode_AsUTF8(name->name);
19        if (!feature)
20            return 0;
21        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
22            continue;
23        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
24            continue;
25        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
26            continue;
27        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
28            continue;
29        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
30            continue;
31        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
32            continue;
33        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
34            continue;
35        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
36            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
37        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
38            continue;
39        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
40            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
41        } else if (strcmp(feature, "braces") == 0) {
42            PyErr_SetString(PyExc_SyntaxError,
43                            "not a chance");
44            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
45            return 0;
46        } else {
47            PyErr_Format(PyExc_SyntaxError,
48                         UNDEFINED_FUTURE_FEATURE, feature);
49            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
50            return 0;
51        }
52    }
53    return 1;
54}
55
56static int
57future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
58{
59    int i, done = 0, prev_line = 0;
60
61    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
62        return 1;
63
64    if (asdl_seq_LEN(mod->v.Module.body) == 0)
65        return 1;
66
67    /* A subsequent pass will detect future imports that don't
68       appear at the beginning of the file.  There's one case,
69       however, that is easier to handle here: A series of imports
70       joined by semi-colons, where the first import is a future
71       statement but some subsequent import has the future form
72       but is preceded by a regular import.
73    */
74
75    i = 0;
76    if (_PyAST_GetDocString(mod->v.Module.body) != NULL)
77        i++;
78
79    for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
80        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
81
82        if (done && s->lineno > prev_line)
83            return 1;
84        prev_line = s->lineno;
85
86        /* The tests below will return from this function unless it is
87           still possible to find a future statement.  The only things
88           that can precede a future statement are another future
89           statement and a doc string.
90        */
91
92        if (s->kind == ImportFrom_kind) {
93            identifier modname = s->v.ImportFrom.module;
94            if (modname &&
95                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
96                if (done) {
97                    PyErr_SetString(PyExc_SyntaxError,
98                                    ERR_LATE_FUTURE);
99                    PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
100                    return 0;
101                }
102                if (!future_check_features(ff, s, filename))
103                    return 0;
104                ff->ff_lineno = s->lineno;
105            }
106            else {
107                done = 1;
108            }
109        }
110        else {
111            done = 1;
112        }
113    }
114    return 1;
115}
116
117
118PyFutureFeatures *
119_PyFuture_FromAST(mod_ty mod, PyObject *filename)
120{
121    PyFutureFeatures *ff;
122
123    ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
124    if (ff == NULL) {
125        PyErr_NoMemory();
126        return NULL;
127    }
128    ff->ff_features = 0;
129    ff->ff_lineno = -1;
130
131    if (!future_parse(ff, mod, filename)) {
132        PyObject_Free(ff);
133        return NULL;
134    }
135    return ff;
136}
137