7
7
8
8
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
9
9
10
+ #define FUTURE_POSSIBLE (FF ) ((FF)->ff_last_lineno == -1)
11
+
10
12
static int
11
13
future_check_features (PyFutureFeatures * ff , node * n )
12
14
{
@@ -28,6 +30,15 @@ future_check_features(PyFutureFeatures *ff, node *n)
28
30
return 0 ;
29
31
}
30
32
33
+ static void
34
+ future_error (node * n , char * filename )
35
+ {
36
+ PyErr_SetString (PyExc_SyntaxError ,
37
+ "from __future__ imports must occur at the "
38
+ "beginning of the file" );
39
+ /* XXX set filename and lineno */
40
+ }
41
+
31
42
/* Relevant portions of the grammar:
32
43
33
44
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
@@ -48,52 +59,82 @@ dotted_name: NAME ('.' NAME)*
48
59
*/
49
60
50
61
static int
51
- future_parse (PyFutureFeatures * ff , node * n )
62
+ future_parse (PyFutureFeatures * ff , node * n , char * filename )
52
63
{
53
- int i , r , found ;
64
+ int i , r ;
54
65
loop :
55
66
56
- /* fprintf(stderr, "future_parse(%d, %d, %s)\n",
57
- TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n));
67
+ /* fprintf(stderr, "future_parse(%d, %d, %s, %d)\n",
68
+ TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n),
69
+ n->n_lineno);
58
70
*/
71
+
59
72
switch (TYPE (n )) {
60
73
61
74
case file_input :
62
75
for (i = 0 ; i < NCH (n ); i ++ ) {
63
76
node * ch = CHILD (n , i );
64
77
if (TYPE (ch ) == stmt ) {
65
- n = ch ;
66
- goto loop ;
78
+ r = future_parse (ff , ch , filename );
79
+ if (!FUTURE_POSSIBLE (ff ))
80
+ return r ;
67
81
}
68
82
}
69
83
return 0 ;
70
84
71
85
case simple_stmt :
72
- if (NCH (n ) == 1 ) {
86
+ if (NCH (n ) == 2 ) {
73
87
REQ (CHILD (n , 0 ), small_stmt );
74
88
n = CHILD (n , 0 );
75
89
goto loop ;
76
- }
77
- found = 0 ;
78
- for (i = 0 ; i < NCH (n ); ++ i )
79
- if (TYPE (CHILD (n , i )) == small_stmt ) {
80
- r = future_parse (ff , CHILD (n , i ));
81
- if (r < 1 ) {
82
- ff -> ff_last_lineno = n -> n_lineno ;
83
- ff -> ff_n_simple_stmt = i ;
84
- return r ;
85
- } else
86
- found ++ ;
90
+ } else {
91
+ /* Deal with the special case of a series of
92
+ small statements on a single line. If a
93
+ future statement follows some other
94
+ statement, the SyntaxError is raised here.
95
+ In all other cases, the symtable pass
96
+ raises the exception.
97
+ */
98
+ int found = 0 , end_of_future = 0 ;
99
+
100
+ for (i = 0 ; i < NCH (n ); i += 2 ) {
101
+ if (TYPE (CHILD (n , i )) == small_stmt ) {
102
+ r = future_parse (ff , CHILD (n , i ),
103
+ filename );
104
+ if (r < 1 )
105
+ end_of_future = 1 ;
106
+ else {
107
+ found = 1 ;
108
+ if (end_of_future ) {
109
+ future_error (n ,
110
+ filename );
111
+ return -1 ;
112
+ }
113
+ }
114
+ }
87
115
}
88
- if (found )
89
- return 1 ;
90
- else
91
- return 0 ;
116
+
117
+ /* If we found one and only one, then the
118
+ current lineno is legal.
119
+ */
120
+ if (found )
121
+ ff -> ff_last_lineno = n -> n_lineno + 1 ;
122
+ else
123
+ ff -> ff_last_lineno = n -> n_lineno ;
124
+
125
+ if (end_of_future && found )
126
+ return 1 ;
127
+ else
128
+ return 0 ;
129
+ }
92
130
93
131
case stmt :
94
132
if (TYPE (CHILD (n , 0 )) == simple_stmt ) {
95
133
n = CHILD (n , 0 );
96
134
goto loop ;
135
+ } else if (TYPE (CHILD (n , 0 )) == expr_stmt ) {
136
+ n = CHILD (n , 0 );
137
+ goto loop ;
97
138
} else {
98
139
REQ (CHILD (n , 0 ), compound_stmt );
99
140
ff -> ff_last_lineno = n -> n_lineno ;
@@ -119,10 +160,42 @@ future_parse(PyFutureFeatures *ff, node *n)
119
160
return 1 ;
120
161
}
121
162
163
+ /* The cases below -- all of them! -- are necessary to find
164
+ and skip doc strings. */
165
+ case expr_stmt :
166
+ case testlist :
167
+ case test :
168
+ case and_test :
169
+ case not_test :
170
+ case comparison :
171
+ case expr :
172
+ case xor_expr :
173
+ case and_expr :
174
+ case shift_expr :
175
+ case arith_expr :
176
+ case term :
177
+ case factor :
178
+ case power :
179
+ if (NCH (n ) == 1 ) {
180
+ n = CHILD (n , 0 );
181
+ goto loop ;
182
+ }
183
+ break ;
184
+
185
+ case atom :
186
+ if (TYPE (CHILD (n , 0 )) == STRING
187
+ && ff -> ff_found_docstring == 0 ) {
188
+ ff -> ff_found_docstring = 1 ;
189
+ return 0 ;
190
+ }
191
+ ff -> ff_last_lineno = n -> n_lineno ;
192
+ return 0 ;
193
+
122
194
default :
123
195
ff -> ff_last_lineno = n -> n_lineno ;
124
196
return 0 ;
125
197
}
198
+ return 0 ;
126
199
}
127
200
128
201
PyFutureFeatures *
@@ -133,11 +206,11 @@ PyNode_Future(node *n, char *filename)
133
206
ff = (PyFutureFeatures * )PyMem_Malloc (sizeof (PyFutureFeatures ));
134
207
if (ff == NULL )
135
208
return NULL ;
136
- ff -> ff_last_lineno = 0 ;
137
- ff -> ff_n_simple_stmt = -1 ;
209
+ ff -> ff_found_docstring = 0 ;
210
+ ff -> ff_last_lineno = -1 ;
138
211
ff -> ff_nested_scopes = 0 ;
139
212
140
- if (future_parse (ff , n ) < 0 ) {
213
+ if (future_parse (ff , n , filename ) < 0 ) {
141
214
PyMem_Free ((void * )ff );
142
215
return NULL ;
143
216
}
0 commit comments