future.c 5.96 KB
Newer Older
1 2 3 4 5 6 7 8
#include "Python.h"
#include "node.h"
#include "token.h"
#include "graminit.h"
#include "compile.h"
#include "symtable.h"

#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
9
#define FUTURE_IMPORT_STAR "future statement does not support import *"
10

11 12 13
/* FUTURE_POSSIBLE() is provided to accomodate doc strings, which is
   the only statement that can occur before a future statement.
*/
14 15
#define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)

16
static int
17
future_check_features(PyFutureFeatures *ff, node *n, char *filename)
18 19 20
{
	int i;
	char *feature;
21
	node *ch;
22 23 24

	REQ(n, import_stmt); /* must by from __future__ import ... */

25
	for (i = 3; i < NCH(n); i += 2) {
26 27 28 29 30 31 32 33 34
		ch = CHILD(n, i);
		if (TYPE(ch) == STAR) {
			PyErr_SetString(PyExc_SyntaxError,
					FUTURE_IMPORT_STAR);
			PyErr_SyntaxLocation(filename, ch->n_lineno);
			return -1;
		}
		REQ(ch, import_as_name);
		feature = STR(CHILD(ch, 0));
35
		if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
36
			continue;
37
		} else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
38
			ff->ff_features |= CO_GENERATOR_ALLOWED;
39
		} else if (strcmp(feature, FUTURE_DIVISION) == 0) {
40
			ff->ff_features |= CO_FUTURE_DIVISION;
41 42 43 44 45
		} else if (strcmp(feature, "braces") == 0) {
			PyErr_SetString(PyExc_SyntaxError,
					"not a chance");
			PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
			return -1;
46 47 48
		} else {
			PyErr_Format(PyExc_SyntaxError,
				     UNDEFINED_FUTURE_FEATURE, feature);
49
			PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
50 51 52 53 54 55
			return -1;
		}
	}
	return 0;
}

56 57 58 59 60 61
static void
future_error(node *n, char *filename)
{
	PyErr_SetString(PyExc_SyntaxError,
			"from __future__ imports must occur at the "
			"beginning of the file");
62
	PyErr_SyntaxLocation(filename, n->n_lineno);
63 64
}

65 66 67 68 69 70
/* Relevant portions of the grammar:

single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
file_input: (NEWLINE | stmt)* ENDMARKER
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
71 72 73 74
small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt 
    | import_stmt | global_stmt | exec_stmt | assert_stmt
import_stmt: 'import' dotted_as_name (',' dotted_as_name)* 
    | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
75 76 77 78 79
import_as_name: NAME [NAME NAME]
dotted_as_name: dotted_name [NAME NAME]
dotted_name: NAME ('.' NAME)*
*/

80 81 82 83 84 85
/* future_parse() finds future statements at the beginnning of a
   module.  The function calls itself recursively, rather than
   factoring out logic for different kinds of statements into
   different routines.

   Return values:
86 87 88 89 90 91
   -1 indicates an error occurred, e.g. unknown feature name
   0 indicates no feature was found
   1 indicates a feature was found
*/

static int
92
future_parse(PyFutureFeatures *ff, node *n, char *filename)
93
{
94
	int i, r;
95 96 97 98
 loop:

	switch (TYPE(n)) {

99 100 101 102 103 104 105
	case single_input:
		if (TYPE(CHILD(n, 0)) == simple_stmt) {
			n = CHILD(n, 0);
			goto loop;
		}
		return 0;

106
	case file_input:
107 108 109 110
		/* Check each statement in the file, starting with the
		   first, and continuing until the first statement
		   that isn't a future statement.
		*/
111 112 113
		for (i = 0; i < NCH(n); i++) {
			node *ch = CHILD(n, i);
			if (TYPE(ch) == stmt) {
114
				r = future_parse(ff, ch, filename);
115 116 117 118 119
				/* Need to check both conditions below
				   to accomodate doc strings, which
				   causes r < 0.
				*/
				if (r < 1 && !FUTURE_POSSIBLE(ff))
120
					return r;
121 122 123 124 125
			}
		}
		return 0;

	case simple_stmt:
126
		if (NCH(n) == 2) {
127 128 129
			REQ(CHILD(n, 0), small_stmt);
			n = CHILD(n, 0);
			goto loop;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
		} else {
			/* Deal with the special case of a series of
			   small statements on a single line.  If a
			   future statement follows some other
			   statement, the SyntaxError is raised here.
			   In all other cases, the symtable pass
			   raises the exception.
			*/
			int found = 0, end_of_future = 0;

			for (i = 0; i < NCH(n); i += 2) {
				if (TYPE(CHILD(n, i)) == small_stmt) {
					r = future_parse(ff, CHILD(n, i), 
							 filename);
					if (r < 1)
						end_of_future = 1;
					else {
						found = 1;
						if (end_of_future) {
							future_error(n, 
								     filename);
							return -1;
						}
					}
				}
155
			}
156 157 158 159 160 161 162 163 164 165 166 167 168 169

			/* If we found one and only one, then the
			   current lineno is legal. 
			*/
			if (found)
				ff->ff_last_lineno = n->n_lineno + 1;
			else
				ff->ff_last_lineno = n->n_lineno;

			if (end_of_future && found)
				return 1;
			else 
				return 0;
		}
170 171 172 173 174
	
	case stmt:
		if (TYPE(CHILD(n, 0)) == simple_stmt) {
			n = CHILD(n, 0);
			goto loop;
175 176 177
		} else if (TYPE(CHILD(n, 0)) == expr_stmt) {
			n = CHILD(n, 0);
			goto loop;
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
		} else {
			REQ(CHILD(n, 0), compound_stmt);
			ff->ff_last_lineno = n->n_lineno;
			return 0;
		}

	case small_stmt:
		n = CHILD(n, 0);
		goto loop;

	case import_stmt: {
		node *name;

		if (STR(CHILD(n, 0))[0] != 'f') { /* from */
			ff->ff_last_lineno = n->n_lineno;
			return 0;
		}
		name = CHILD(n, 1);
		if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
			return 0;
198
		if (future_check_features(ff, n, filename) < 0)
199
			return -1;
200
		ff->ff_last_lineno = n->n_lineno + 1;
201 202 203
		return 1;
	}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	/* The cases below -- all of them! -- are necessary to find
	   and skip doc strings. */
	case expr_stmt:
	case testlist:
	case test:
	case and_test:
	case not_test:
	case comparison:
	case expr:
	case xor_expr:
	case and_expr:
	case shift_expr:
	case arith_expr:
	case term:
	case factor:
	case power:
		if (NCH(n) == 1) {
			n = CHILD(n, 0);
			goto loop;
		}
		break;

	case atom:
		if (TYPE(CHILD(n, 0)) == STRING 
		    && ff->ff_found_docstring == 0) {
			ff->ff_found_docstring = 1;
			return 0;
		}
		ff->ff_last_lineno = n->n_lineno;
		return 0;

235 236 237 238
	default:
		ff->ff_last_lineno = n->n_lineno;
		return 0;
	}
239
	return 0;
240 241 242 243 244 245 246 247 248 249
}

PyFutureFeatures *
PyNode_Future(node *n, char *filename)
{
	PyFutureFeatures *ff;

	ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
	if (ff == NULL)
		return NULL;
250 251
	ff->ff_found_docstring = 0;
	ff->ff_last_lineno = -1;
252
	ff->ff_features = 0;
253

254
	if (future_parse(ff, n, filename) < 0) {
255 256 257 258 259 260
		PyMem_Free((void *)ff);
		return NULL;
	}
	return ff;
}