future.c 4.75 KB
Newer Older
1
#include "Python.h"
Jeremy Hylton's avatar
Jeremy Hylton committed
2
#include "Python-ast.h"
3 4 5
#include "node.h"
#include "token.h"
#include "graminit.h"
Jeremy Hylton's avatar
Jeremy Hylton committed
6
#include "code.h"
7
#include "symtable.h"
8
#include "ast.h"
9 10

#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
11 12
#define ERR_LATE_FUTURE \
"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
{
17 18 19 20 21 22 23 24
    int i;
    asdl_seq *names;

    assert(s->kind == ImportFrom_kind);

    names = s->v.ImportFrom.names;
    for (i = 0; i < asdl_seq_LEN(names); i++) {
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
25
        const char *feature = PyUnicode_AsUTF8(name->name);
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
        if (!feature)
            return 0;
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
44
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
45
            continue;
46 47
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
48 49 50
        } else if (strcmp(feature, "braces") == 0) {
            PyErr_SetString(PyExc_SyntaxError,
                            "not a chance");
51
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
52 53 54 55
            return 0;
        } else {
            PyErr_Format(PyExc_SyntaxError,
                         UNDEFINED_FUTURE_FEATURE, feature);
56
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
57 58 59 60
            return 0;
        }
    }
    return 1;
61 62
}

63
static int
64
future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
65
{
66
    int i, done = 0, prev_line = 0;
67 68 69 70

    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
        return 1;

71 72 73
    if (asdl_seq_LEN(mod->v.Module.body) == 0)
        return 1;

74 75 76 77 78 79 80 81
    /* A subsequent pass will detect future imports that don't
       appear at the beginning of the file.  There's one case,
       however, that is easier to handle here: A series of imports
       joined by semi-colons, where the first import is a future
       statement but some subsequent import has the future form
       but is preceded by a regular import.
    */

82
    i = 0;
83
    if (_PyAST_GetDocString(mod->v.Module.body) != NULL)
84 85 86
        i++;

    for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
87 88 89 90 91 92 93 94 95 96 97 98 99
        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);

        if (done && s->lineno > prev_line)
            return 1;
        prev_line = s->lineno;

        /* The tests below will return from this function unless it is
           still possible to find a future statement.  The only things
           that can precede a future statement are another future
           statement and a doc string.
        */

        if (s->kind == ImportFrom_kind) {
100
            identifier modname = s->v.ImportFrom.module;
Benjamin Peterson's avatar
Benjamin Peterson committed
101
            if (modname &&
102
                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
103 104 105
                if (done) {
                    PyErr_SetString(PyExc_SyntaxError,
                                    ERR_LATE_FUTURE);
106
                    PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
107 108 109 110 111 112
                    return 0;
                }
                if (!future_check_features(ff, s, filename))
                    return 0;
                ff->ff_lineno = s->lineno;
            }
113
            else {
114
                done = 1;
115
            }
116
        }
117
        else {
118
            done = 1;
119
        }
120 121
    }
    return 1;
122 123
}

Jeremy Hylton's avatar
Jeremy Hylton committed
124

125
PyFutureFeatures *
126
PyFuture_FromASTObject(mod_ty mod, PyObject *filename)
127
{
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    PyFutureFeatures *ff;

    ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
    if (ff == NULL) {
        PyErr_NoMemory();
        return NULL;
    }
    ff->ff_features = 0;
    ff->ff_lineno = -1;

    if (!future_parse(ff, mod, filename)) {
        PyObject_Free(ff);
        return NULL;
    }
    return ff;
143
}
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158


PyFutureFeatures *
PyFuture_FromAST(mod_ty mod, const char *filename_str)
{
    PyFutureFeatures *ff;
    PyObject *filename;

    filename = PyUnicode_DecodeFSDefault(filename_str);
    if (filename == NULL)
        return NULL;
    ff = PyFuture_FromASTObject(mod, filename);
    Py_DECREF(filename);
    return ff;
}