Coverage Report

Created: 2025-07-11 06:59

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