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

Skip to content

Commit 5ba5866

Browse files
committed
Part way to allowing "from __future__ import generators" to communicate
that info to code dynamically compiled *by* code compiled with generators enabled. Doesn't yet work because there's still no way to tell the parser that "yield" is OK (unlike nested_scopes, the parser has its fingers in this too). Replaced PyEval_GetNestedScopes by a more-general PyEval_MergeCompilerFlags. Perhaps I should not have? I doubted it was *intended* to be part of the public API, so just did.
1 parent 4dbf871 commit 5ba5866

11 files changed

Lines changed: 77 additions & 33 deletions

File tree

Include/Python.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@
9696
#include "pystate.h"
9797

9898
#include "modsupport.h"
99-
#include "ceval.h"
10099
#include "pythonrun.h"
100+
#include "ceval.h"
101101
#include "sysmodule.h"
102102
#include "intrcheck.h"
103103
#include "import.h"

Include/ceval.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ DL_IMPORT(PyObject *) PyEval_GetLocals(void);
3131
DL_IMPORT(PyObject *) PyEval_GetOwner(void);
3232
DL_IMPORT(PyObject *) PyEval_GetFrame(void);
3333
DL_IMPORT(int) PyEval_GetRestricted(void);
34-
DL_IMPORT(int) PyEval_GetNestedScopes(void);
34+
35+
/* Look at the current frame's (if any) code's co_flags, and turn on
36+
the corresponding compiler flags in cf->cf_flags. Return 1 if any
37+
flag was set, else return 0. */
38+
DL_IMPORT(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
3539

3640
DL_IMPORT(int) Py_FlushLine(void);
3741

Include/compile.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ typedef struct {
3434
#define CO_VARKEYWORDS 0x0008
3535
#define CO_NESTED 0x0010
3636
#define CO_GENERATOR 0x0020
37+
/* XXX Temporary hack. Until generators are a permanent part of the
38+
language, we need a way for a code object to record that generators
39+
were *possible* when it was compiled. This is so code dynamically
40+
compiled *by* a code object knows whether to allow yield stmts. In
41+
effect, this passes on the "from __future__ import generators" state
42+
in effect when the code block was compiled. */
43+
#define CO_GENERATOR_ALLOWED 0x1000
3744

3845
extern DL_IMPORT(PyTypeObject) PyCode_Type;
3946

@@ -56,6 +63,7 @@ typedef struct {
5663
int ff_found_docstring;
5764
int ff_last_lineno;
5865
int ff_nested_scopes;
66+
int ff_generators;
5967
} PyFutureFeatures;
6068

6169
DL_IMPORT(PyFutureFeatures *) PyNode_Future(struct _node *, char *);

Include/pythonrun.h

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

10+
/* These flags are named after the __future__ statements that introduced
11+
them. May not remain true for later additions, so fiddle this comment
12+
accordingly then. */
13+
#define PyCF_NESTED_SCOPES (0x00000001UL)
14+
#define PyCF_GENERATORS (0x00000002UL)
1015
typedef struct {
11-
int cf_nested_scopes;
16+
unsigned long cf_flags; /* bitmask of PyCF_xxx flags */
1217
} PyCompilerFlags;
1318

1419
DL_IMPORT(void) Py_SetProgramName(char *);

Lib/test/test_generators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import generators
2+
13
tutorial_tests = """
24
Let's try a simple generator:
35

Modules/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ Py_Main(int argc, char **argv)
298298
Py_DECREF(v);
299299
}
300300

301-
cf.cf_nested_scopes = 0;
301+
cf.cf_flags = 0;
302302

303303
if (command) {
304304
sts = PyRun_SimpleString(command) != 0;

Python/bltinmodule.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ builtin_compile(PyObject *self, PyObject *args)
393393
char *filename;
394394
char *startstr;
395395
int start;
396+
PyCompilerFlags cf;
396397

397398
if (!PyArg_ParseTuple(args, "sss:compile", &str, &filename, &startstr))
398399
return NULL;
@@ -407,11 +408,10 @@ builtin_compile(PyObject *self, PyObject *args)
407408
"compile() arg 3 must be 'exec' or 'eval' or 'single'");
408409
return NULL;
409410
}
410-
if (PyEval_GetNestedScopes()) {
411-
PyCompilerFlags cf;
412-
cf.cf_nested_scopes = 1;
411+
cf.cf_flags = 0;
412+
if (PyEval_MergeCompilerFlags(&cf))
413413
return Py_CompileStringFlags(str, filename, start, &cf);
414-
} else
414+
else
415415
return Py_CompileString(str, filename, start);
416416
}
417417

@@ -822,6 +822,7 @@ builtin_execfile(PyObject *self, PyObject *args)
822822
PyObject *globals = Py_None, *locals = Py_None;
823823
PyObject *res;
824824
FILE* fp;
825+
PyCompilerFlags cf;
825826

826827
if (!PyArg_ParseTuple(args, "s|O!O!:execfile",
827828
&filename,
@@ -847,12 +848,11 @@ builtin_execfile(PyObject *self, PyObject *args)
847848
PyErr_SetFromErrno(PyExc_IOError);
848849
return NULL;
849850
}
850-
if (PyEval_GetNestedScopes()) {
851-
PyCompilerFlags cf;
852-
cf.cf_nested_scopes = 1;
851+
cf.cf_flags = 0;
852+
if (PyEval_MergeCompilerFlags(&cf))
853853
res = PyRun_FileExFlags(fp, filename, Py_file_input, globals,
854854
locals, 1, &cf);
855-
} else
855+
else
856856
res = PyRun_FileEx(fp, filename, Py_file_input, globals,
857857
locals, 1);
858858
return res;

Python/ceval.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,7 +2524,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
25242524
if (co->co_flags & CO_GENERATOR) {
25252525
/* Don't need to keep the reference to f_back, it will be set
25262526
* when the generator is resumed. */
2527-
Py_DECREF(f->f_back);
2527+
Py_XDECREF(f->f_back);
25282528
f->f_back = NULL;
25292529

25302530
/* Create a new generator that owns the ready to run frame
@@ -2906,11 +2906,23 @@ PyEval_GetRestricted(void)
29062906
}
29072907

29082908
int
2909-
PyEval_GetNestedScopes(void)
2909+
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
29102910
{
29112911
PyFrameObject *current_frame = PyThreadState_Get()->frame;
2912-
return current_frame == NULL ? 0 :
2913-
current_frame->f_code->co_flags & CO_NESTED;
2912+
int result = 0;
2913+
2914+
if (current_frame != NULL) {
2915+
const int codeflags = current_frame->f_code->co_flags;
2916+
if (codeflags & CO_NESTED) {
2917+
result = 1;
2918+
cf->cf_flags |= PyCF_NESTED_SCOPES;
2919+
}
2920+
if (codeflags & CO_GENERATOR_ALLOWED) {
2921+
result = 1;
2922+
cf->cf_flags |= PyCF_GENERATORS;
2923+
}
2924+
}
2925+
return result;
29142926
}
29152927

29162928
int
@@ -3730,26 +3742,25 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
37303742
else if (PyFile_Check(prog)) {
37313743
FILE *fp = PyFile_AsFile(prog);
37323744
char *name = PyString_AsString(PyFile_Name(prog));
3733-
if (PyEval_GetNestedScopes()) {
3734-
PyCompilerFlags cf;
3735-
cf.cf_nested_scopes = 1;
3745+
PyCompilerFlags cf;
3746+
cf.cf_flags = 0;
3747+
if (PyEval_MergeCompilerFlags(&cf))
37363748
v = PyRun_FileFlags(fp, name, Py_file_input, globals,
37373749
locals, &cf);
3738-
} else {
3750+
else
37393751
v = PyRun_File(fp, name, Py_file_input, globals,
37403752
locals);
3741-
}
37423753
}
37433754
else {
37443755
char *str;
3756+
PyCompilerFlags cf;
37453757
if (PyString_AsStringAndSize(prog, &str, NULL))
37463758
return -1;
3747-
if (PyEval_GetNestedScopes()) {
3748-
PyCompilerFlags cf;
3749-
cf.cf_nested_scopes = 1;
3759+
cf.cf_flags = 0;
3760+
if (PyEval_MergeCompilerFlags(&cf))
37503761
v = PyRun_StringFlags(str, Py_file_input, globals,
37513762
locals, &cf);
3752-
} else
3763+
else
37533764
v = PyRun_String(str, Py_file_input, globals, locals);
37543765
}
37553766
if (plain)

Python/compile.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3953,10 +3953,15 @@ jcompile(node *n, char *filename, struct compiling *base,
39533953
return NULL;
39543954
}
39553955
if (flags) {
3956-
if (flags->cf_nested_scopes)
3956+
if (flags->cf_flags & PyCF_NESTED_SCOPES)
39573957
sc.c_future->ff_nested_scopes = 1;
39583958
else if (sc.c_future->ff_nested_scopes)
3959-
flags->cf_nested_scopes = 1;
3959+
flags->cf_flags |= PyCF_NESTED_SCOPES;
3960+
3961+
if (flags->cf_flags & PyCF_GENERATORS)
3962+
sc.c_future->ff_generators = 1;
3963+
else if (sc.c_future->ff_generators)
3964+
flags->cf_flags |= PyCF_GENERATORS;
39603965
}
39613966
if (symtable_build(&sc, n) < 0) {
39623967
com_free(&sc);
@@ -4426,8 +4431,12 @@ static int
44264431
symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
44274432
struct symbol_info *si)
44284433
{
4429-
if (c->c_future && c->c_future->ff_nested_scopes)
4430-
c->c_flags |= CO_NESTED;
4434+
if (c->c_future) {
4435+
if (c->c_future->ff_nested_scopes)
4436+
c->c_flags |= CO_NESTED;
4437+
if (c->c_future->ff_generators)
4438+
c->c_flags |= CO_GENERATOR_ALLOWED;
4439+
}
44314440
if (ste->ste_generator)
44324441
c->c_flags |= CO_GENERATOR;
44334442
if (ste->ste_type != TYPE_MODULE)

Python/future.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ future_check_features(PyFutureFeatures *ff, node *n, char *filename)
3232
if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
3333
ff->ff_nested_scopes = 1;
3434
} else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
35-
/* OK; this is processed by the parser */
35+
ff->ff_generators= 1;
3636
} else if (strcmp(feature, "braces") == 0) {
3737
PyErr_SetString(PyExc_SyntaxError,
3838
"not a chance");
@@ -233,6 +233,7 @@ PyNode_Future(node *n, char *filename)
233233
ff->ff_found_docstring = 0;
234234
ff->ff_last_lineno = -1;
235235
ff->ff_nested_scopes = 0;
236+
ff->ff_generators = 0;
236237

237238
if (future_parse(ff, n, filename) < 0) {
238239
PyMem_Free((void *)ff);

0 commit comments

Comments
 (0)