Skip to content

Commit 4db62b1

Browse files
committed
Improved __future__ parser; still more to do
Makefile.pre.in: add target future.o Include/compile.h: define PyFutureFeaters and PyNode_Future() add c_future slot to struct compiling Include/symtable.h: add st_future slot to struct symtable Python/future.c: implementation of PyNode_Future() Python/compile.c: use PyNode_Future() for nested_scopes support Python/symtable.c: include compile.h to pick up PyFutureFeatures decl
1 parent ed5e823 commit 4db62b1

File tree

6 files changed

+167
-46
lines changed

6 files changed

+167
-46
lines changed

Include/compile.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
extern "C" {
88
#endif
99

10-
#define NESTED_SCOPES_DEFAULT 0
11-
#define FUTURE_NESTED_SCOPES "nested_scopes"
12-
1310
/* Bytecode object */
1411
typedef struct {
1512
PyObject_HEAD
@@ -51,6 +48,19 @@ DL_IMPORT(PyCodeObject *) PyCode_New(
5148
/* same as struct above */
5249
DL_IMPORT(int) PyCode_Addr2Line(PyCodeObject *, int);
5350

51+
/* Future feature support */
52+
53+
typedef struct {
54+
int ff_last_lineno;
55+
int ff_n_simple_stmt;
56+
int ff_nested_scopes;
57+
} PyFutureFeatures;
58+
59+
DL_IMPORT(PyFutureFeatures *) PyNode_Future(struct _node *, char *);
60+
61+
#define NESTED_SCOPES_DEFAULT 0
62+
#define FUTURE_NESTED_SCOPES "nested_scopes"
63+
5464
/* for internal use only */
5565
#define _PyCode_GETCODEPTR(co, pp) \
5666
((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \

Include/symtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct symtable {
3030
int st_errors; /* number of errors */
3131
char *st_private; /* name of current class or NULL */
3232
int st_tmpname; /* temporary name counter */
33+
PyFutureFeatures *st_future; /* module's future features */
3334
};
3435

3536
typedef struct _symtable_entry {

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ PYTHON_OBJS= \
200200
Python/errors.o \
201201
Python/frozen.o \
202202
Python/frozenmain.o \
203+
Python/future.o \
203204
Python/getargs.o \
204205
Python/getcompiler.o \
205206
Python/getcopyright.o \

Python/compile.c

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ int Py_OptimizeFlag = 0;
5555
#define ILLEGAL_DYNAMIC_SCOPE \
5656
"%.100s: exec or 'import *' makes names ambiguous in nested scope"
5757

58-
#define UNDEFINED_FUTURE_FEATURE \
59-
"future feature %.100s is not defined"
60-
6158
#define GLOBAL_AFTER_ASSIGN \
6259
"name '%.400s' is assigned to before global declaration"
6360

@@ -368,6 +365,7 @@ struct compiling {
368365
int c_nested; /* Is block nested funcdef or lamdef? */
369366
int c_closure; /* Is nested w/freevars? */
370367
struct symtable *c_symtable; /* pointer to module symbol table */
368+
PyFutureFeatures *c_future; /* pointer to module's __future__ */
371369
};
372370

373371
int is_free(int v)
@@ -3864,7 +3862,8 @@ jcompile(node *n, char *filename, struct compiling *base)
38643862
sc.c_nested = 1;
38653863
} else {
38663864
sc.c_private = NULL;
3867-
if (symtable_build(&sc, n) < 0) {
3865+
sc.c_future = PyNode_Future(n, filename);
3866+
if (sc.c_future == NULL || symtable_build(&sc, n) < 0) {
38683867
com_free(&sc);
38693868
return NULL;
38703869
}
@@ -3996,6 +3995,8 @@ symtable_build(struct compiling *c, node *n)
39963995
{
39973996
if ((c->c_symtable = symtable_init()) == NULL)
39983997
return -1;
3998+
if (c->c_future->ff_nested_scopes)
3999+
c->c_symtable->st_nested_scopes = 1;
39994000
c->c_symtable->st_filename = c->c_filename;
40004001
symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
40014002
if (c->c_symtable->st_errors > 0)
@@ -4280,44 +4281,6 @@ PySymtable_Free(struct symtable *st)
42804281
PyMem_Free((void *)st);
42814282
}
42824283

4283-
/* XXX this code is a placeholder for correct code.
4284-
from __future__ import name set language options */
4285-
4286-
static int
4287-
symtable_check_future(struct symtable *st, node *n)
4288-
{
4289-
int i;
4290-
node *name = CHILD(n, 1);
4291-
4292-
if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
4293-
return 0;
4294-
/* It is only legal to define __future__ features at the top
4295-
of a module. If the current scope is not the module level
4296-
or if there are any symbols defined, it is too late. */
4297-
if (st->st_cur->ste_symbols != st->st_global
4298-
|| PyDict_Size(st->st_cur->ste_symbols) != 0) {
4299-
PyErr_SetString(PyExc_SyntaxError,
4300-
"imports from __future__ are only legal at the beginning of a module");
4301-
return -1;
4302-
}
4303-
for (i = 3; i < NCH(n); ++i) {
4304-
char *feature = STR(CHILD(CHILD(n, i), 0));
4305-
/* Do a linear search through the defined features,
4306-
assuming there aren't very many of them. */
4307-
if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
4308-
st->st_nested_scopes = 1;
4309-
} else {
4310-
PyErr_Format(PyExc_SyntaxError,
4311-
UNDEFINED_FUTURE_FEATURE, feature);
4312-
set_error_location(st->st_filename,
4313-
st->st_cur->ste_lineno);
4314-
st->st_errors++;
4315-
return -1;
4316-
}
4317-
}
4318-
return 1;
4319-
}
4320-
43214284
/* When the compiler exits a scope, it must should update the scope's
43224285
free variable information with the list of free variables in its
43234286
children.
@@ -4910,7 +4873,6 @@ symtable_import(struct symtable *st, node *n)
49104873
import_as_name: NAME [NAME NAME]
49114874
*/
49124875
if (STR(CHILD(n, 0))[0] == 'f') { /* from */
4913-
symtable_check_future(st, n);
49144876
if (TYPE(CHILD(n, 3)) == STAR) {
49154877
st->st_cur->ste_optimized |= OPT_IMPORT_STAR;
49164878
} else {

Python/future.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#include "Python.h"
2+
#include "node.h"
3+
#include "token.h"
4+
#include "graminit.h"
5+
#include "compile.h"
6+
#include "symtable.h"
7+
8+
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
9+
10+
static int
11+
future_check_features(PyFutureFeatures *ff, node *n)
12+
{
13+
int i;
14+
char *feature;
15+
16+
REQ(n, import_stmt); /* must by from __future__ import ... */
17+
18+
for (i = 3; i < NCH(n); ++i) {
19+
feature = STR(CHILD(CHILD(n, i), 0));
20+
if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
21+
ff->ff_nested_scopes = 1;
22+
} else {
23+
PyErr_Format(PyExc_SyntaxError,
24+
UNDEFINED_FUTURE_FEATURE, feature);
25+
return -1;
26+
}
27+
}
28+
return 0;
29+
}
30+
31+
/* Relevant portions of the grammar:
32+
33+
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
34+
file_input: (NEWLINE | stmt)* ENDMARKER
35+
stmt: simple_stmt | compound_stmt
36+
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
37+
small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
38+
import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
39+
import_as_name: NAME [NAME NAME]
40+
dotted_as_name: dotted_name [NAME NAME]
41+
dotted_name: NAME ('.' NAME)*
42+
*/
43+
44+
/* future_parse() return values:
45+
-1 indicates an error occurred, e.g. unknown feature name
46+
0 indicates no feature was found
47+
1 indicates a feature was found
48+
*/
49+
50+
static int
51+
future_parse(PyFutureFeatures *ff, node *n)
52+
{
53+
int i, r, found;
54+
loop:
55+
56+
/* fprintf(stderr, "future_parse(%d, %d, %s)\n",
57+
TYPE(n), NCH(n), (n == NULL) ? "NULL" : STR(n));
58+
*/
59+
switch (TYPE(n)) {
60+
61+
case file_input:
62+
for (i = 0; i < NCH(n); i++) {
63+
node *ch = CHILD(n, i);
64+
if (TYPE(ch) == stmt) {
65+
n = ch;
66+
goto loop;
67+
}
68+
}
69+
return 0;
70+
71+
case simple_stmt:
72+
if (NCH(n) == 1) {
73+
REQ(CHILD(n, 0), small_stmt);
74+
n = CHILD(n, 0);
75+
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++;
87+
}
88+
if (found)
89+
return 1;
90+
else
91+
return 0;
92+
93+
case stmt:
94+
if (TYPE(CHILD(n, 0)) == simple_stmt) {
95+
n = CHILD(n, 0);
96+
goto loop;
97+
} else {
98+
REQ(CHILD(n, 0), compound_stmt);
99+
ff->ff_last_lineno = n->n_lineno;
100+
return 0;
101+
}
102+
103+
case small_stmt:
104+
n = CHILD(n, 0);
105+
goto loop;
106+
107+
case import_stmt: {
108+
node *name;
109+
110+
if (STR(CHILD(n, 0))[0] != 'f') { /* from */
111+
ff->ff_last_lineno = n->n_lineno;
112+
return 0;
113+
}
114+
name = CHILD(n, 1);
115+
if (strcmp(STR(CHILD(name, 0)), "__future__") != 0)
116+
return 0;
117+
if (future_check_features(ff, n) < 0)
118+
return -1;
119+
return 1;
120+
}
121+
122+
default:
123+
ff->ff_last_lineno = n->n_lineno;
124+
return 0;
125+
}
126+
}
127+
128+
PyFutureFeatures *
129+
PyNode_Future(node *n, char *filename)
130+
{
131+
PyFutureFeatures *ff;
132+
133+
ff = (PyFutureFeatures *)PyMem_Malloc(sizeof(PyFutureFeatures));
134+
if (ff == NULL)
135+
return NULL;
136+
ff->ff_last_lineno = 0;
137+
ff->ff_n_simple_stmt = -1;
138+
ff->ff_nested_scopes = 0;
139+
140+
if (future_parse(ff, n) < 0) {
141+
PyMem_Free((void *)ff);
142+
return NULL;
143+
}
144+
return ff;
145+
}
146+

Python/symtable.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "Python.h"
2+
#include "compile.h"
23
#include "symtable.h"
34
#include "graminit.h"
45
#include "structmember.h"

0 commit comments

Comments
 (0)