Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 39e2f3f

Browse files
committed
Presumed correct compiler pass for future statements
XXX still need to integrate into symtable API compile.h: Remove ff_n_simple_stmt; obsolete. Add ff_found_docstring used internally to skip one and only one string at the beginning of a module. compile.c: Add check for from __future__ imports to far into the file. In symtable_global() check for -1 returned from symtable_lookup(), which signifies name not defined. Add missing DECERF in symtable_add_def. Free c->c_future. future.c: Add special handling for multiple statements joined on a single line using one or more semicolons; this form can include an illegal future statement that would otherwise be hard to detect. Add support for detecting and skipping doc strings.
1 parent 8e43cd7 commit 39e2f3f

3 files changed

Lines changed: 129 additions & 30 deletions

File tree

Include/compile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ DL_IMPORT(int) PyCode_Addr2Line(PyCodeObject *, int);
5151
/* Future feature support */
5252

5353
typedef struct {
54+
int ff_found_docstring;
5455
int ff_last_lineno;
55-
int ff_n_simple_stmt;
5656
int ff_nested_scopes;
5757
} PyFutureFeatures;
5858

Python/compile.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ int Py_OptimizeFlag = 0;
6464
#define LOCAL_GLOBAL \
6565
"name '%.400s' is a function paramter and declared global"
6666

67+
#define LATE_FUTURE \
68+
"from __future__ imports must occur at the beginning of the file"
69+
6770
#define MANGLE_LEN 256
6871

6972
#define OFF(x) offsetof(PyCodeObject, x)
@@ -605,6 +608,8 @@ com_free(struct compiling *c)
605608
Py_XDECREF(c->c_freevars);
606609
Py_XDECREF(c->c_cellvars);
607610
Py_XDECREF(c->c_lnotab);
611+
if (c->c_future)
612+
PyMem_Free((void *)c->c_future);
608613
}
609614

610615
static void
@@ -1544,9 +1549,12 @@ com_argument(struct compiling *c, node *n, PyObject **pkeywords)
15441549
PyObject *v = PyString_InternFromString(STR(m));
15451550
if (v != NULL && *pkeywords == NULL)
15461551
*pkeywords = PyDict_New();
1547-
if (v == NULL || *pkeywords == NULL)
1552+
if (v == NULL)
15481553
c->c_errors++;
1549-
else {
1554+
else if (*pkeywords == NULL) {
1555+
c->c_errors++;
1556+
Py_DECREF(v);
1557+
} else {
15501558
if (PyDict_GetItem(*pkeywords, v) != NULL)
15511559
com_error(c, PyExc_SyntaxError,
15521560
"duplicate keyword argument");
@@ -3995,6 +4003,7 @@ symtable_build(struct compiling *c, node *n)
39954003
{
39964004
if ((c->c_symtable = symtable_init()) == NULL)
39974005
return -1;
4006+
c->c_symtable->st_future = c->c_future;
39984007
if (c->c_future->ff_nested_scopes)
39994008
c->c_symtable->st_nested_scopes = 1;
40004009
c->c_symtable->st_filename = c->c_filename;
@@ -4482,12 +4491,15 @@ symtable_add_def(struct symtable *st, char *name, int flag)
44824491
{
44834492
PyObject *s;
44844493
char buffer[MANGLE_LEN];
4494+
int ret;
44854495

44864496
if (mangle(st->st_private, name, buffer, sizeof(buffer)))
44874497
name = buffer;
44884498
if ((s = PyString_InternFromString(name)) == NULL)
44894499
return -1;
4490-
return symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag);
4500+
ret = symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag);
4501+
Py_DECREF(s);
4502+
return ret;
44914503
}
44924504

44934505
/* Must only be called with mangled names */
@@ -4819,12 +4831,14 @@ symtable_global(struct symtable *st, node *n)
48194831
int flags;
48204832

48214833
flags = symtable_lookup(st, name);
4834+
if (flags < 0)
4835+
continue;
48224836
if (flags && flags != DEF_GLOBAL) {
48234837
char buf[500];
48244838
if (flags & DEF_PARAM) {
48254839
PyErr_Format(PyExc_SyntaxError,
48264840
"name '%.400s' is local and global",
4827-
PyString_AS_STRING(name));
4841+
name);
48284842
set_error_location(st->st_filename,
48294843
st->st_cur->ste_lineno);
48304844
st->st_errors++;
@@ -4873,6 +4887,18 @@ symtable_import(struct symtable *st, node *n)
48734887
import_as_name: NAME [NAME NAME]
48744888
*/
48754889
if (STR(CHILD(n, 0))[0] == 'f') { /* from */
4890+
node *dotname = CHILD(n, 1);
4891+
if (strcmp(STR(CHILD(dotname, 0)), "__future__") == 0) {
4892+
/* check for bogus imports */
4893+
if (n->n_lineno >= st->st_future->ff_last_lineno) {
4894+
PyErr_SetString(PyExc_SyntaxError,
4895+
LATE_FUTURE);
4896+
set_error_location(st->st_filename,
4897+
n->n_lineno);
4898+
st->st_errors++;
4899+
return;
4900+
}
4901+
}
48764902
if (TYPE(CHILD(n, 3)) == STAR) {
48774903
st->st_cur->ste_optimized |= OPT_IMPORT_STAR;
48784904
} else {

Python/future.c

Lines changed: 98 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
99

10+
#define FUTURE_POSSIBLE(FF) ((FF)->ff_last_lineno == -1)
11+
1012
static int
1113
future_check_features(PyFutureFeatures *ff, node *n)
1214
{
@@ -28,6 +30,15 @@ future_check_features(PyFutureFeatures *ff, node *n)
2830
return 0;
2931
}
3032

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+
3142
/* Relevant portions of the grammar:
3243
3344
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
@@ -48,52 +59,82 @@ dotted_name: NAME ('.' NAME)*
4859
*/
4960

5061
static int
51-
future_parse(PyFutureFeatures *ff, node *n)
62+
future_parse(PyFutureFeatures *ff, node *n, char *filename)
5263
{
53-
int i, r, found;
64+
int i, r;
5465
loop:
5566

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);
5870
*/
71+
5972
switch (TYPE(n)) {
6073

6174
case file_input:
6275
for (i = 0; i < NCH(n); i++) {
6376
node *ch = CHILD(n, i);
6477
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;
6781
}
6882
}
6983
return 0;
7084

7185
case simple_stmt:
72-
if (NCH(n) == 1) {
86+
if (NCH(n) == 2) {
7387
REQ(CHILD(n, 0), small_stmt);
7488
n = CHILD(n, 0);
7589
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+
}
87115
}
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+
}
92130

93131
case stmt:
94132
if (TYPE(CHILD(n, 0)) == simple_stmt) {
95133
n = CHILD(n, 0);
96134
goto loop;
135+
} else if (TYPE(CHILD(n, 0)) == expr_stmt) {
136+
n = CHILD(n, 0);
137+
goto loop;
97138
} else {
98139
REQ(CHILD(n, 0), compound_stmt);
99140
ff->ff_last_lineno = n->n_lineno;
@@ -119,10 +160,42 @@ future_parse(PyFutureFeatures *ff, node *n)
119160
return 1;
120161
}
121162

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+
122194
default:
123195
ff->ff_last_lineno = n->n_lineno;
124196
return 0;
125197
}
198+
return 0;
126199
}
127200

128201
PyFutureFeatures *
@@ -133,11 +206,11 @@ PyNode_Future(node *n, char *filename)
133206
ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
134207
if (ff == NULL)
135208
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;
138211
ff->ff_nested_scopes = 0;
139212

140-
if (future_parse(ff, n) < 0) {
213+
if (future_parse(ff, n, filename) < 0) {
141214
PyMem_Free((void *)ff);
142215
return NULL;
143216
}

0 commit comments

Comments
 (0)