/src/cpython/Python/future.c
Line | Count | Source |
1 | | #include "Python.h" |
2 | | #include "pycore_ast.h" // _PyAST_GetDocString() |
3 | | #include "pycore_pyerrors.h" // _Py_CalculateSuggestions() |
4 | | #include "pycore_symtable.h" // _PyFutureFeatures |
5 | | #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() |
6 | | |
7 | 111 | #define UNDEFINED_FUTURE_FEATURE "future feature '%.100s' is not defined" |
8 | | |
9 | | static int |
10 | | future_check_features(_PyFutureFeatures *ff, stmt_ty s, PyObject *filename) |
11 | 532 | { |
12 | 532 | Py_ssize_t i; |
13 | | |
14 | 532 | assert(s->kind == ImportFrom_kind); |
15 | | |
16 | 532 | asdl_alias_seq *names = s->v.ImportFrom.names; |
17 | 986 | for (i = 0; i < asdl_seq_LEN(names); i++) { |
18 | 565 | alias_ty name = (alias_ty)asdl_seq_GET(names, i); |
19 | 565 | const char *feature = PyUnicode_AsUTF8(name->name); |
20 | 565 | if (!feature) |
21 | 0 | return 0; |
22 | 565 | if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { |
23 | 73 | continue; |
24 | 492 | } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { |
25 | 12 | continue; |
26 | 480 | } else if (strcmp(feature, FUTURE_DIVISION) == 0) { |
27 | 70 | continue; |
28 | 410 | } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { |
29 | 77 | continue; |
30 | 333 | } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { |
31 | 11 | continue; |
32 | 322 | } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { |
33 | 10 | continue; |
34 | 312 | } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { |
35 | 28 | continue; |
36 | 284 | } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) { |
37 | 66 | ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL; |
38 | 218 | } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) { |
39 | 18 | continue; |
40 | 200 | } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) { |
41 | 89 | ff->ff_features |= CO_FUTURE_ANNOTATIONS; |
42 | 111 | } else if (strcmp(feature, "braces") == 0) { |
43 | 0 | PyErr_SetString(PyExc_SyntaxError, |
44 | 0 | "not a chance"); |
45 | 0 | PyErr_RangedSyntaxLocationObject(filename, |
46 | 0 | name->lineno, |
47 | 0 | name->col_offset + 1, |
48 | 0 | name->end_lineno, |
49 | 0 | name->end_col_offset + 1); |
50 | 0 | return 0; |
51 | 111 | } else { |
52 | | // Keep this list in sync with the feature checks above. |
53 | 111 | PyObject *future_features = Py_BuildValue("[ssssssssss]", |
54 | 111 | FUTURE_NESTED_SCOPES, |
55 | 111 | FUTURE_GENERATORS, |
56 | 111 | FUTURE_DIVISION, |
57 | 111 | FUTURE_ABSOLUTE_IMPORT, |
58 | 111 | FUTURE_WITH_STATEMENT, |
59 | 111 | FUTURE_PRINT_FUNCTION, |
60 | 111 | FUTURE_UNICODE_LITERALS, |
61 | 111 | FUTURE_BARRY_AS_BDFL, |
62 | 111 | FUTURE_GENERATOR_STOP, |
63 | 111 | FUTURE_ANNOTATIONS); |
64 | 111 | PyObject *suggestion = NULL; |
65 | 111 | if (future_features != NULL) { |
66 | 111 | suggestion = _Py_CalculateSuggestions(future_features, |
67 | 111 | name->name); |
68 | 111 | } |
69 | 111 | if (suggestion != NULL) { |
70 | 25 | PyErr_Format(PyExc_SyntaxError, |
71 | 25 | UNDEFINED_FUTURE_FEATURE ". Did you mean: %R?", |
72 | 25 | feature, suggestion); |
73 | 25 | Py_DECREF(suggestion); |
74 | 25 | } |
75 | 86 | else { |
76 | | // Do not fail on missing suggestion, |
77 | | // just show the default message. |
78 | 86 | PyErr_Format(PyExc_SyntaxError, |
79 | 86 | UNDEFINED_FUTURE_FEATURE, |
80 | 86 | feature); |
81 | 86 | } |
82 | 111 | Py_XDECREF(future_features); |
83 | 111 | PyErr_RangedSyntaxLocationObject(filename, |
84 | 111 | name->lineno, |
85 | 111 | name->col_offset + 1, |
86 | 111 | name->end_lineno, |
87 | 111 | name->end_col_offset + 1); |
88 | 111 | return 0; |
89 | 111 | } |
90 | 565 | } |
91 | 421 | return 1; |
92 | 532 | } |
93 | | |
94 | | static int |
95 | | future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename) |
96 | 8.29k | { |
97 | 8.29k | if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) { |
98 | 172 | return 1; |
99 | 172 | } |
100 | | |
101 | 8.12k | Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body); |
102 | 8.12k | if (n == 0) { |
103 | 1.42k | return 1; |
104 | 1.42k | } |
105 | | |
106 | 6.70k | Py_ssize_t i = 0; |
107 | 6.70k | if (_PyAST_GetDocString(mod->v.Module.body) != NULL) { |
108 | 435 | i++; |
109 | 435 | } |
110 | | |
111 | 7.12k | for (; i < n; i++) { |
112 | 6.80k | stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); |
113 | | |
114 | | /* The only things that can precede a future statement |
115 | | * are another future statement and a doc string. |
116 | | */ |
117 | | |
118 | 6.80k | if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) { |
119 | 742 | identifier modname = s->v.ImportFrom.module; |
120 | 742 | if (modname && |
121 | 742 | _PyUnicode_EqualToASCIIString(modname, "__future__")) { |
122 | 532 | if (!future_check_features(ff, s, filename)) { |
123 | 111 | return 0; |
124 | 111 | } |
125 | 421 | ff->ff_location = SRC_LOCATION_FROM_AST(s); |
126 | 421 | } |
127 | 210 | else { |
128 | 210 | return 1; |
129 | 210 | } |
130 | 742 | } |
131 | 6.06k | else { |
132 | 6.06k | return 1; |
133 | 6.06k | } |
134 | 6.80k | } |
135 | 321 | return 1; |
136 | 6.70k | } |
137 | | |
138 | | |
139 | | int |
140 | | _PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff) |
141 | 8.29k | { |
142 | 8.29k | ff->ff_features = 0; |
143 | 8.29k | ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1}; |
144 | | |
145 | 8.29k | if (!future_parse(ff, mod, filename)) { |
146 | 111 | return 0; |
147 | 111 | } |
148 | 8.18k | return 1; |
149 | 8.29k | } |