Line | Count | Source (jump to first uncovered line) |
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 | |
8 | static int |
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++216 ) { Branch (16:17): [True: 224, False: 211]
|
17 | alias_ty name = (alias_ty)asdl_seq_GET(names, i); |
18 | const char *feature = PyUnicode_AsUTF8(name->name); |
19 | if (!feature) Branch (19:13): [True: 0, False: 224]
|
20 | return 0; |
21 | if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { Branch (21:13): [True: 11, False: 213]
|
22 | continue; |
23 | } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { Branch (23:20): [True: 3, False: 210]
|
24 | continue; |
25 | } else if (strcmp(feature, FUTURE_DIVISION) == 0) { Branch (25:20): [True: 1, False: 209]
|
26 | continue; |
27 | } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { Branch (27:20): [True: 12, False: 197]
|
28 | continue; |
29 | } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { Branch (29:20): [True: 0, False: 197]
|
30 | continue; |
31 | } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { Branch (31:20): [True: 0, False: 197]
|
32 | continue; |
33 | } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { Branch (33:20): [True: 1, False: 196]
|
34 | continue; |
35 | } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) { Branch (35:20): [True: 1, False: 195]
|
36 | ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL; |
37 | } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) { Branch (37:20): [True: 1, False: 194]
|
38 | continue; |
39 | } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) { Branch (39:20): [True: 186, False: 8]
|
40 | ff->ff_features |= CO_FUTURE_ANNOTATIONS; |
41 | } else if (8 strcmp(feature, "braces") == 08 ) { Branch (41:20): [True: 3, False: 5]
|
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 | |
56 | static int |
57 | future_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_kind40.0k )) Branch (61:11): [True: 8.78k, False: 40.0k]
Branch (61:39): [True: 4.10k, False: 35.9k]
|
62 | return 1; |
63 | |
64 | if (asdl_seq_LEN(mod->v.Module.body) == 0) Branch (64:9): [True: 299, False: 12.5k]
|
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) Branch (76:9): [True: 317, False: 12.2k]
|
77 | i++; |
78 | |
79 | for (; i < asdl_seq_LEN(mod->v.Module.body); i++13.0k ) { Branch (79:12): [True: 14.6k, False: 11.0k]
|
80 | stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); |
81 | |
82 | if (done && s->lineno > prev_line1.87k ) Branch (82:13): [True: 1.87k, False: 12.7k]
Branch (82:21): [True: 1.57k, False: 303]
|
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) { Branch (92:13): [True: 693, False: 12.3k]
|
93 | identifier modname = s->v.ImportFrom.module; |
94 | if (modname && Branch (94:17): [True: 676, False: 17]
|
95 | _PyUnicode_EqualToASCIIString(modname, "__future__")676 ) { Branch (95:17): [True: 221, False: 455]
|
96 | if (done) { Branch (96:21): [True: 2, False: 219]
|
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)) Branch (102:21): [True: 8, False: 211]
|
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 | |
118 | PyFutureFeatures * |
119 | _PyFuture_FromAST(mod_ty mod, PyObject *filename) |
120 | { |
121 | PyFutureFeatures *ff; |
122 | |
123 | ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures)); |
124 | if (ff == NULL) { Branch (124:9): [True: 0, False: 48.8k]
|
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)) { Branch (131:9): [True: 10, False: 48.7k]
|
132 | PyObject_Free(ff); |
133 | return NULL; |
134 | } |
135 | return ff; |
136 | } |