This commit was manufactured by cvs2svn to create tag 'r241c1'.
[python/dscho.git] / Python / future.c
blob20d8dd290924ee7e8aba5ce79ef6e80294d72444
1 #include "Python.h"
2 #include "node.h"
3 #include "token.h"
4 #include "graminit.h"
5 #include "compile.h"
6 #include "symtable.h"
8 #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
9 #define FUTURE_IMPORT_STAR "future statement does not support import *"
11 /* FUTURE_POSSIBLE() is provided to accomodate doc strings, which is
12 the only statement that can occur before a future statement.
14 #define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
16 static int
17 future_check_features(PyFutureFeatures *ff, node *n, const char *filename)
19 int i;
20 char *feature;
21 node *ch, *nn;
23 REQ(n, import_from);
24 nn = CHILD(n, 3 + (TYPE(CHILD(n, 3)) == LPAR));
25 if (TYPE(nn) == STAR) {
26 PyErr_SetString(PyExc_SyntaxError, FUTURE_IMPORT_STAR);
27 PyErr_SyntaxLocation(filename, nn->n_lineno);
28 return -1;
30 REQ(nn, import_as_names);
31 for (i = 0; i < NCH(nn); i += 2) {
32 ch = CHILD(nn, i);
33 REQ(ch, import_as_name);
34 feature = STR(CHILD(ch, 0));
35 if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
36 continue;
37 } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
38 continue;
39 } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
40 ff->ff_features |= CO_FUTURE_DIVISION;
41 } else if (strcmp(feature, "braces") == 0) {
42 PyErr_SetString(PyExc_SyntaxError,
43 "not a chance");
44 PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
45 return -1;
46 } else {
47 PyErr_Format(PyExc_SyntaxError,
48 UNDEFINED_FUTURE_FEATURE, feature);
49 PyErr_SyntaxLocation(filename, CHILD(ch, 0)->n_lineno);
50 return -1;
53 return 0;
56 static void
57 future_error(node *n, const char *filename)
59 PyErr_SetString(PyExc_SyntaxError,
60 "from __future__ imports must occur at the "
61 "beginning of the file");
62 PyErr_SyntaxLocation(filename, n->n_lineno);
65 /* Relevant portions of the grammar:
67 single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
68 file_input: (NEWLINE | stmt)* ENDMARKER
69 stmt: simple_stmt | compound_stmt
70 simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
71 small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt
72 | import_stmt | global_stmt | exec_stmt | assert_stmt
73 import_stmt: 'import' dotted_as_name (',' dotted_as_name)*
74 | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
75 import_as_name: NAME [NAME NAME]
76 dotted_as_name: dotted_name [NAME NAME]
77 dotted_name: NAME ('.' NAME)*
80 /* future_parse() finds future statements at the beginnning of a
81 module. The function calls itself recursively, rather than
82 factoring out logic for different kinds of statements into
83 different routines.
85 Return values:
86 -1 indicates an error occurred, e.g. unknown feature name
87 0 indicates no feature was found
88 1 indicates a feature was found
91 static int
92 future_parse(PyFutureFeatures *ff, node *n, const char *filename)
94 int i, r;
95 loop:
97 switch (TYPE(n)) {
99 case single_input:
100 if (TYPE(CHILD(n, 0)) == simple_stmt) {
101 n = CHILD(n, 0);
102 goto loop;
104 return 0;
106 case file_input:
107 /* Check each statement in the file, starting with the
108 first, and continuing until the first statement
109 that isn't a future statement.
111 for (i = 0; i < NCH(n); i++) {
112 node *ch = CHILD(n, i);
113 if (TYPE(ch) == stmt) {
114 r = future_parse(ff, ch, filename);
115 /* Need to check both conditions below
116 to accomodate doc strings, which
117 causes r < 0.
119 if (r < 1 && !FUTURE_POSSIBLE(ff))
120 return r;
123 return 0;
125 case simple_stmt:
126 if (NCH(n) == 2) {
127 REQ(CHILD(n, 0), small_stmt);
128 n = CHILD(n, 0);
129 goto loop;
130 } else {
131 /* Deal with the special case of a series of
132 small statements on a single line. If a
133 future statement follows some other
134 statement, the SyntaxError is raised here.
135 In all other cases, the symtable pass
136 raises the exception.
138 int found = 0, end_of_future = 0;
140 for (i = 0; i < NCH(n); i += 2) {
141 if (TYPE(CHILD(n, i)) == small_stmt) {
142 r = future_parse(ff, CHILD(n, i),
143 filename);
144 if (r < 1)
145 end_of_future = 1;
146 else {
147 found = 1;
148 if (end_of_future) {
149 future_error(n,
150 filename);
151 return -1;
157 /* If we found one and only one, then the
158 current lineno is legal.
160 if (found)
161 ff->ff_last_lineno = n->n_lineno + 1;
162 else
163 ff->ff_last_lineno = n->n_lineno;
165 if (end_of_future && found)
166 return 1;
167 else
168 return 0;
171 case stmt:
172 if (TYPE(CHILD(n, 0)) == simple_stmt) {
173 n = CHILD(n, 0);
174 goto loop;
175 } else if (TYPE(CHILD(n, 0)) == expr_stmt) {
176 n = CHILD(n, 0);
177 goto loop;
178 } else {
179 REQ(CHILD(n, 0), compound_stmt);
180 ff->ff_last_lineno = n->n_lineno;
181 return 0;
184 case small_stmt:
185 n = CHILD(n, 0);
186 goto loop;
188 case import_stmt: {
189 node *name;
191 n = CHILD(n, 0);
192 if (TYPE(n) != import_from) {
193 ff->ff_last_lineno = n->n_lineno;
194 return 0;
196 name = CHILD(n, 1);
197 if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
198 return 0;
199 if (future_check_features(ff, n, filename) < 0)
200 return -1;
201 ff->ff_last_lineno = n->n_lineno + 1;
202 return 1;
205 /* The cases below -- all of them! -- are necessary to find
206 and skip doc strings. */
207 case expr_stmt:
208 case testlist:
209 case test:
210 case and_test:
211 case not_test:
212 case comparison:
213 case expr:
214 case xor_expr:
215 case and_expr:
216 case shift_expr:
217 case arith_expr:
218 case term:
219 case factor:
220 case power:
221 if (NCH(n) == 1) {
222 n = CHILD(n, 0);
223 goto loop;
225 break;
227 case atom:
228 if (TYPE(CHILD(n, 0)) == STRING
229 && ff->ff_found_docstring == 0) {
230 ff->ff_found_docstring = 1;
231 return 0;
233 ff->ff_last_lineno = n->n_lineno;
234 return 0;
236 default:
237 ff->ff_last_lineno = n->n_lineno;
238 return 0;
240 return 0;
243 PyFutureFeatures *
244 PyNode_Future(node *n, const char *filename)
246 PyFutureFeatures *ff;
248 ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
249 if (ff == NULL)
250 return NULL;
251 ff->ff_found_docstring = 0;
252 ff->ff_last_lineno = -1;
253 ff->ff_features = 0;
255 if (future_parse(ff, n, filename) < 0) {
256 PyMem_Free((void *)ff);
257 return NULL;
259 return ff;