• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "Python.h"
2 #include "pycore_ast.h"           // _PyAST_GetDocString()
3 #include "pycore_symtable.h"      // _PyFutureFeatures
4 #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
5 
6 #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
7 
8 static int
future_check_features(_PyFutureFeatures * ff,stmt_ty s,PyObject * filename)9 future_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_RangedSyntaxLocationObject(filename,
45                                              name->lineno,
46                                              name->col_offset + 1,
47                                              name->end_lineno,
48                                              name->end_col_offset + 1);
49             return 0;
50         } else {
51             PyErr_Format(PyExc_SyntaxError,
52                          UNDEFINED_FUTURE_FEATURE, feature);
53             PyErr_RangedSyntaxLocationObject(filename,
54                                              name->lineno,
55                                              name->col_offset + 1,
56                                              name->end_lineno,
57                                              name->end_col_offset + 1);
58             return 0;
59         }
60     }
61     return 1;
62 }
63 
64 static int
future_parse(_PyFutureFeatures * ff,mod_ty mod,PyObject * filename)65 future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
66 {
67     if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) {
68         return 1;
69     }
70 
71     Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body);
72     if (n == 0) {
73         return 1;
74     }
75 
76     Py_ssize_t i = 0;
77     if (_PyAST_GetDocString(mod->v.Module.body) != NULL) {
78         i++;
79     }
80 
81     for (; i < n; i++) {
82         stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
83 
84         /* The only things that can precede a future statement
85          *  are another future statement and a doc string.
86          */
87 
88         if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) {
89             identifier modname = s->v.ImportFrom.module;
90             if (modname &&
91                 _PyUnicode_EqualToASCIIString(modname, "__future__")) {
92                 if (!future_check_features(ff, s, filename)) {
93                     return 0;
94                 }
95                 ff->ff_location = SRC_LOCATION_FROM_AST(s);
96             }
97             else {
98                 return 1;
99             }
100         }
101         else {
102             return 1;
103         }
104     }
105     return 1;
106 }
107 
108 
109 int
_PyFuture_FromAST(mod_ty mod,PyObject * filename,_PyFutureFeatures * ff)110 _PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff)
111 {
112     ff->ff_features = 0;
113     ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1};
114 
115     if (!future_parse(ff, mod, filename)) {
116         return 0;
117     }
118     return 1;
119 }
120