/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 | 108 | #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 | 524 | { |
12 | 524 | Py_ssize_t i; |
13 | | |
14 | 524 | assert(s->kind == ImportFrom_kind); |
15 | | |
16 | 524 | asdl_alias_seq *names = s->v.ImportFrom.names; |
17 | 975 | for (i = 0; i < asdl_seq_LEN(names); i++) { |
18 | 559 | alias_ty name = (alias_ty)asdl_seq_GET(names, i); |
19 | 559 | const char *feature = PyUnicode_AsUTF8(name->name); |
20 | 559 | if (!feature) |
21 | 0 | return 0; |
22 | 559 | if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { |
23 | 73 | continue; |
24 | 486 | } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { |
25 | 12 | continue; |
26 | 474 | } else if (strcmp(feature, FUTURE_DIVISION) == 0) { |
27 | 71 | continue; |
28 | 403 | } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { |
29 | 67 | continue; |
30 | 336 | } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { |
31 | 10 | continue; |
32 | 326 | } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { |
33 | 10 | continue; |
34 | 316 | } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { |
35 | 30 | continue; |
36 | 286 | } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) { |
37 | 67 | ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL; |
38 | 219 | } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) { |
39 | 18 | continue; |
40 | 201 | } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) { |
41 | 93 | ff->ff_features |= CO_FUTURE_ANNOTATIONS; |
42 | 108 | } 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 | 108 | } else { |
52 | | // Keep this list in sync with the feature checks above. |
53 | 108 | PyObject *future_features = Py_BuildValue("[ssssssssss]", |
54 | 108 | FUTURE_NESTED_SCOPES, |
55 | 108 | FUTURE_GENERATORS, |
56 | 108 | FUTURE_DIVISION, |
57 | 108 | FUTURE_ABSOLUTE_IMPORT, |
58 | 108 | FUTURE_WITH_STATEMENT, |
59 | 108 | FUTURE_PRINT_FUNCTION, |
60 | 108 | FUTURE_UNICODE_LITERALS, |
61 | 108 | FUTURE_BARRY_AS_BDFL, |
62 | 108 | FUTURE_GENERATOR_STOP, |
63 | 108 | FUTURE_ANNOTATIONS); |
64 | 108 | PyObject *suggestion = NULL; |
65 | 108 | if (future_features != NULL) { |
66 | 108 | suggestion = _Py_CalculateSuggestions(future_features, |
67 | 108 | name->name); |
68 | 108 | } |
69 | 108 | if (suggestion != NULL) { |
70 | 29 | PyErr_Format(PyExc_SyntaxError, |
71 | 29 | UNDEFINED_FUTURE_FEATURE ". Did you mean: %R?", |
72 | 29 | feature, suggestion); |
73 | 29 | Py_DECREF(suggestion); |
74 | 29 | } |
75 | 79 | else { |
76 | | // Do not fail on missing suggestion, |
77 | | // just show the default message. |
78 | 79 | PyErr_Format(PyExc_SyntaxError, |
79 | 79 | UNDEFINED_FUTURE_FEATURE, |
80 | 79 | feature); |
81 | 79 | } |
82 | 108 | Py_XDECREF(future_features); |
83 | 108 | PyErr_RangedSyntaxLocationObject(filename, |
84 | 108 | name->lineno, |
85 | 108 | name->col_offset + 1, |
86 | 108 | name->end_lineno, |
87 | 108 | name->end_col_offset + 1); |
88 | 108 | return 0; |
89 | 108 | } |
90 | 559 | } |
91 | 416 | return 1; |
92 | 524 | } |
93 | | |
94 | | static int |
95 | | future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename) |
96 | 8.23k | { |
97 | 8.23k | if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) { |
98 | 196 | return 1; |
99 | 196 | } |
100 | | |
101 | 8.03k | Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body); |
102 | 8.03k | if (n == 0) { |
103 | 1.39k | return 1; |
104 | 1.39k | } |
105 | | |
106 | 6.64k | Py_ssize_t i = 0; |
107 | 6.64k | if (_PyAST_GetDocString(mod->v.Module.body) != NULL) { |
108 | 421 | i++; |
109 | 421 | } |
110 | | |
111 | 7.05k | for (; i < n; i++) { |
112 | 6.74k | 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.74k | if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) { |
119 | 735 | identifier modname = s->v.ImportFrom.module; |
120 | 735 | if (modname && |
121 | 735 | _PyUnicode_EqualToASCIIString(modname, "__future__")) { |
122 | 524 | if (!future_check_features(ff, s, filename)) { |
123 | 108 | return 0; |
124 | 108 | } |
125 | 416 | ff->ff_location = SRC_LOCATION_FROM_AST(s); |
126 | 416 | } |
127 | 211 | else { |
128 | 211 | return 1; |
129 | 211 | } |
130 | 735 | } |
131 | 6.01k | else { |
132 | 6.01k | return 1; |
133 | 6.01k | } |
134 | 6.74k | } |
135 | 309 | return 1; |
136 | 6.64k | } |
137 | | |
138 | | |
139 | | int |
140 | | _PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff) |
141 | 8.23k | { |
142 | 8.23k | ff->ff_features = 0; |
143 | 8.23k | ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1}; |
144 | | |
145 | 8.23k | if (!future_parse(ff, mod, filename)) { |
146 | 108 | return 0; |
147 | 108 | } |
148 | 8.12k | return 1; |
149 | 8.23k | } |