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 8 9
#include "symtable.h"

#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
10 11
#define ERR_LATE_FUTURE \
"from __future__ imports must occur at the beginning of the file"
12 13

static int
14
future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
15
{
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
    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);
        const char *feature = _PyUnicode_AsString(name->name);
        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;
43 44
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
            ff->ff_features |= CO_FUTURE_GENERATOR_STOP;
45 46 47
        } else if (strcmp(feature, "braces") == 0) {
            PyErr_SetString(PyExc_SyntaxError,
                            "not a chance");
48
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
49 50 51 52
            return 0;
        } else {
            PyErr_Format(PyExc_SyntaxError,
                         UNDEFINED_FUTURE_FEATURE, feature);
53
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
54 55 56 57
            return 0;
        }
    }
    return 1;
58 59
}

60
static int
61
future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
62
{
63
    int i, done = 0, prev_line = 0;
Benjamin Peterson's avatar
Benjamin Peterson committed
64
    stmt_ty first;
65 66 67 68

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

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

72 73 74 75 76 77 78 79
    /* 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.
    */

80
    i = 0;
Benjamin Peterson's avatar
Benjamin Peterson committed
81
    first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
82 83
    if (first->kind == Expr_kind && first->v.Expr.value->kind == Str_kind)
        i++;
84

85 86

    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 102
            if (modname &&
                !PyUnicode_CompareWithASCIIString(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;
}