Commit 34aa7ba1 authored by Thomas Wouters's avatar Thomas Wouters

from __future__ import with_statement addon for 'with', mostly written by

Neal.
parent edc8f136
...@@ -46,6 +46,12 @@ typedef struct { ...@@ -46,6 +46,12 @@ typedef struct {
#endif #endif
#define CO_FUTURE_DIVISION 0x2000 #define CO_FUTURE_DIVISION 0x2000
#define CO_FUTURE_ABSIMPORT 0x4000 /* absolute import by default */ #define CO_FUTURE_ABSIMPORT 0x4000 /* absolute import by default */
#define CO_FUTURE_WITH_STATEMENT 0x8000
/* This should be defined if a future statement modifies the syntax.
For example, when a keyword is added.
*/
#define PY_PARSER_REQUIRES_FUTURE_KEYWORD
#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */ #define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
......
...@@ -23,6 +23,7 @@ typedef struct { ...@@ -23,6 +23,7 @@ typedef struct {
#define FUTURE_GENERATORS "generators" #define FUTURE_GENERATORS "generators"
#define FUTURE_DIVISION "division" #define FUTURE_DIVISION "division"
#define FUTURE_ABSIMPORT "absolute_import" #define FUTURE_ABSIMPORT "absolute_import"
#define FUTURE_WITH_STATEMENT "with_statement"
struct _mod; /* Declare the existence of this type */ struct _mod; /* Declare the existence of this type */
PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *, PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
......
...@@ -39,8 +39,8 @@ PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); ...@@ -39,8 +39,8 @@ PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *);
#define PYTHON_API_VERSION 1012 #define PYTHON_API_VERSION 1013
#define PYTHON_API_STRING "1012" #define PYTHON_API_STRING "1013"
/* The API version is maintained (independently from the Python version) /* The API version is maintained (independently from the Python version)
so we can detect mismatches between the interpreter and dynamically so we can detect mismatches between the interpreter and dynamically
loaded modules. These are diagnosed by an error message but loaded modules. These are diagnosed by an error message but
...@@ -54,6 +54,8 @@ PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char ...@@ -54,6 +54,8 @@ PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char
Please add a line or two to the top of this log for each API Please add a line or two to the top of this log for each API
version change: version change:
22-Feb-2006 GvR 1013 PEP 353 - long indices for sequence lengths
19-Aug-2002 GvR 1012 Changes to string object struct for 19-Aug-2002 GvR 1012 Changes to string object struct for
interning changes, saving 3 bytes. interning changes, saving 3 bytes.
......
...@@ -23,6 +23,8 @@ typedef struct { ...@@ -23,6 +23,8 @@ typedef struct {
#define PyPARSE_DONT_IMPLY_DEDENT 0x0002 #define PyPARSE_DONT_IMPLY_DEDENT 0x0002
#define PyPARSE_WITH_IS_KEYWORD 0x0003
PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int,
perrdetail *); perrdetail *);
PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int,
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
extern "C" { extern "C" {
#endif #endif
#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT) #define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT | \
CO_FUTURE_WITH_STATEMENT)
#define PyCF_MASK_OBSOLETE (CO_NESTED) #define PyCF_MASK_OBSOLETE (CO_NESTED)
#define PyCF_SOURCE_IS_UTF8 0x0100 #define PyCF_SOURCE_IS_UTF8 0x0100
#define PyCF_DONT_IMPLY_DEDENT 0x0200 #define PyCF_DONT_IMPLY_DEDENT 0x0200
......
...@@ -52,6 +52,7 @@ all_feature_names = [ ...@@ -52,6 +52,7 @@ all_feature_names = [
"generators", "generators",
"division", "division",
"absolute_import", "absolute_import",
"with_statement",
] ]
__all__ = ["all_feature_names"] + all_feature_names __all__ = ["all_feature_names"] + all_feature_names
...@@ -64,6 +65,7 @@ CO_NESTED = 0x0010 # nested_scopes ...@@ -64,6 +65,7 @@ CO_NESTED = 0x0010 # nested_scopes
CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000) CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000)
CO_FUTURE_DIVISION = 0x2000 # division CO_FUTURE_DIVISION = 0x2000 # division
CO_FUTURE_ABSIMPORT = 0x4000 # absolute_import CO_FUTURE_ABSIMPORT = 0x4000 # absolute_import
CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement added in 2.5
class _Feature: class _Feature:
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag): def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
...@@ -108,3 +110,7 @@ division = _Feature((2, 2, 0, "alpha", 2), ...@@ -108,3 +110,7 @@ division = _Feature((2, 2, 0, "alpha", 2),
absolute_import = _Feature((2, 5, 0, "alpha", 1), absolute_import = _Feature((2, 5, 0, "alpha", 1),
(2, 7, 0, "alpha", 0), (2, 7, 0, "alpha", 0),
CO_FUTURE_ABSIMPORT) CO_FUTURE_ABSIMPORT)
with_statement = _Feature((2, 5, 0, "alpha", 2),
(2, 6, 0, "alpha", 0),
CO_FUTURE_WITH_STATEMENT)
...@@ -15,7 +15,8 @@ def is_future(stmt): ...@@ -15,7 +15,8 @@ def is_future(stmt):
class FutureParser: class FutureParser:
features = ("nested_scopes", "generators", "division") features = ("nested_scopes", "generators", "division",
"absolute_import", "with_statement")
def __init__(self): def __init__(self):
self.found = {} # set self.found = {} # set
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
"""Unit tests for the with statement specified in PEP 343.""" """Unit tests for the with statement specified in PEP 343."""
from __future__ import with_statement
__author__ = "Mike Bland" __author__ = "Mike Bland"
__email__ = "mbland at acm dot org" __email__ = "mbland at acm dot org"
......
...@@ -32,7 +32,8 @@ Core and builtins ...@@ -32,7 +32,8 @@ Core and builtins
- dict.__getitem__ now looks for a __missing__ hook before raising - dict.__getitem__ now looks for a __missing__ hook before raising
KeyError. KeyError.
- PEP 343: with statement implemented. - PEP 343: with statement implemented. Needs 'from __future__ import
with_statement'. Use of 'with' as a variable will generate a warning.
- Fix the encodings package codec search function to only search - Fix the encodings package codec search function to only search
inside its own package. Fixes problem reported in patch #1433198. inside its own package. Fixes problem reported in patch #1433198.
......
...@@ -79,8 +79,8 @@ PyParser_New(grammar *g, int start) ...@@ -79,8 +79,8 @@ PyParser_New(grammar *g, int start)
if (ps == NULL) if (ps == NULL)
return NULL; return NULL;
ps->p_grammar = g; ps->p_grammar = g;
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
ps->p_generators = 0; ps->p_flags = 0;
#endif #endif
ps->p_tree = PyNode_New(start); ps->p_tree = PyNode_New(start);
if (ps->p_tree == NULL) { if (ps->p_tree == NULL) {
...@@ -147,10 +147,10 @@ classify(parser_state *ps, int type, char *str) ...@@ -147,10 +147,10 @@ classify(parser_state *ps, int type, char *str)
if (l->lb_type == NAME && l->lb_str != NULL && if (l->lb_type == NAME && l->lb_str != NULL &&
l->lb_str[0] == s[0] && l->lb_str[0] == s[0] &&
strcmp(l->lb_str, s) == 0) { strcmp(l->lb_str, s) == 0) {
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
if (!ps->p_generators && if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT) &&
s[0] == 'y' && s[0] == 'w' &&
strcmp(s, "yield") == 0) strcmp(s, "with") == 0)
break; /* not a keyword */ break; /* not a keyword */
#endif #endif
D(printf("It's a keyword\n")); D(printf("It's a keyword\n"));
...@@ -174,7 +174,7 @@ classify(parser_state *ps, int type, char *str) ...@@ -174,7 +174,7 @@ classify(parser_state *ps, int type, char *str)
return -1; return -1;
} }
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
static void static void
future_hack(parser_state *ps) future_hack(parser_state *ps)
{ {
...@@ -182,16 +182,27 @@ future_hack(parser_state *ps) ...@@ -182,16 +182,27 @@ future_hack(parser_state *ps)
node *ch; node *ch;
int i; int i;
if (strcmp(STR(CHILD(n, 0)), "from") != 0) /* from __future__ import ..., must have at least 4 children */
n = CHILD(n, 0);
if (NCH(n) < 4)
return;
ch = CHILD(n, 0);
if (STR(ch) == NULL || strcmp(STR(ch), "from") != 0)
return; return;
ch = CHILD(n, 1); ch = CHILD(n, 1);
if (strcmp(STR(CHILD(ch, 0)), "__future__") != 0) if (NCH(ch) == 1 && STR(CHILD(ch, 0)) &&
strcmp(STR(CHILD(ch, 0)), "__future__") != 0)
return; return;
for (i = 3; i < NCH(n); i += 2) { for (i = 3; i < NCH(n); i += 2) {
/* XXX: assume we don't have parentheses in import:
from __future__ import (x, y, z)
*/
ch = CHILD(n, i); ch = CHILD(n, i);
if (NCH(ch) == 1)
ch = CHILD(ch, 0);
if (NCH(ch) >= 1 && TYPE(CHILD(ch, 0)) == NAME && if (NCH(ch) >= 1 && TYPE(CHILD(ch, 0)) == NAME &&
strcmp(STR(CHILD(ch, 0)), "generators") == 0) { strcmp(STR(CHILD(ch, 0)), "with_statement") == 0) {
ps->p_generators = 1; ps->p_flags |= CO_FUTURE_WITH_STATEMENT;
break; break;
} }
} }
...@@ -255,7 +266,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str, ...@@ -255,7 +266,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
"Direct pop.\n", "Direct pop.\n",
d->d_name, d->d_name,
ps->p_stack.s_top->s_state)); ps->p_stack.s_top->s_state));
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
if (d->d_name[0] == 'i' && if (d->d_name[0] == 'i' &&
strcmp(d->d_name, strcmp(d->d_name,
"import_stmt") == 0) "import_stmt") == 0)
...@@ -273,7 +284,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str, ...@@ -273,7 +284,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
} }
if (s->s_accept) { if (s->s_accept) {
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
if (d->d_name[0] == 'i' && if (d->d_name[0] == 'i' &&
strcmp(d->d_name, "import_stmt") == 0) strcmp(d->d_name, "import_stmt") == 0)
future_hack(ps); future_hack(ps);
......
...@@ -25,8 +25,8 @@ typedef struct { ...@@ -25,8 +25,8 @@ typedef struct {
stack p_stack; /* Stack of parser states */ stack p_stack; /* Stack of parser states */
grammar *p_grammar; /* Grammar to use */ grammar *p_grammar; /* Grammar to use */
node *p_tree; /* Top of parse tree */ node *p_tree; /* Top of parse tree */
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
int p_generators; /* 1 if yield is a keyword */ unsigned long p_flags; /* see co_flags in Include/code.h */
#endif #endif
} parser_state; } parser_state;
......
...@@ -92,10 +92,19 @@ PyParser_ParseFileFlags(FILE *fp, const char *filename, grammar *g, int start, ...@@ -92,10 +92,19 @@ PyParser_ParseFileFlags(FILE *fp, const char *filename, grammar *g, int start,
/* Parse input coming from the given tokenizer structure. /* Parse input coming from the given tokenizer structure.
Return error code. */ Return error code. */
#if 0 /* future keyword */ static char with_msg[] =
static char yield_msg[] = "%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n";
"%s:%d: Warning: 'yield' will become a reserved keyword in the future\n";
#endif static char as_msg[] =
"%s:%d: Warning: 'as' will become a reserved keyword in Python 2.6\n";
static void
warn(const char *msg, const char *filename, int lineno)
{
if (filename == NULL)
filename = "<string>";
PySys_WriteStderr(msg, filename, lineno);
}
static node * static node *
parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
...@@ -103,7 +112,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -103,7 +112,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
{ {
parser_state *ps; parser_state *ps;
node *n; node *n;
int started = 0; int started = 0, handling_import = 0, handling_with = 0;
if ((ps = PyParser_New(g, start)) == NULL) { if ((ps = PyParser_New(g, start)) == NULL) {
fprintf(stderr, "no mem for new parser\n"); fprintf(stderr, "no mem for new parser\n");
...@@ -111,9 +120,9 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -111,9 +120,9 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
PyTokenizer_Free(tok); PyTokenizer_Free(tok);
return NULL; return NULL;
} }
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
if (flags & PyPARSE_YIELD_IS_KEYWORD) if (flags & PyPARSE_WITH_IS_KEYWORD)
ps->p_generators = 1; ps->p_flags |= CO_FUTURE_WITH_STATEMENT;
#endif #endif
for (;;) { for (;;) {
...@@ -129,6 +138,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -129,6 +138,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
} }
if (type == ENDMARKER && started) { if (type == ENDMARKER && started) {
type = NEWLINE; /* Add an extra newline */ type = NEWLINE; /* Add an extra newline */
handling_with = handling_import = 0;
started = 0; started = 0;
/* Add the right number of dedent tokens, /* Add the right number of dedent tokens,
except if a certain flag is given -- except if a certain flag is given --
...@@ -153,14 +163,27 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -153,14 +163,27 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
strncpy(str, a, len); strncpy(str, a, len);
str[len] = '\0'; str[len] = '\0';
#if 0 /* future keyword */ #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
/* Warn about yield as NAME */ /* This is only necessary to support the "as" warning, but
if (type == NAME && !ps->p_generators && we don't want to warn about "as" in import statements. */
len == 5 && str[0] == 'y' && strcmp(str, "yield") == 0) if (type == NAME &&
PySys_WriteStderr(yield_msg, len == 6 && str[0] == 'i' && strcmp(str, "import") == 0)
err_ret->filename==NULL ? handling_import = 1;
"<string>" : err_ret->filename,
tok->lineno); /* Warn about with as NAME */
if (type == NAME &&
!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) {
if (len == 4 && str[0] == 'w' && strcmp(str, "with") == 0)
warn(with_msg, err_ret->filename, tok->lineno);
else if (!(handling_import || handling_with) &&
len == 2 &&
str[0] == 'a' && strcmp(str, "as") == 0)
warn(as_msg, err_ret->filename, tok->lineno);
}
else if (type == NAME &&
(ps->p_flags & CO_FUTURE_WITH_STATEMENT) &&
len == 4 && str[0] == 'w' && strcmp(str, "with") == 0)
handling_with = 1;
#endif #endif
if ((err_ret->error = if ((err_ret->error =
......
...@@ -371,7 +371,7 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int ...@@ -371,7 +371,7 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int
} }
PyTuple_SET_ITEM(fnames, i, field); PyTuple_SET_ITEM(fnames, i, field);
} }
result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}",
type, base, "_fields", fnames, "__module__", "_ast"); type, base, "_fields", fnames, "__module__", "_ast");
Py_DECREF(fnames); Py_DECREF(fnames);
return (PyTypeObject*)result; return (PyTypeObject*)result;
...@@ -2956,7 +2956,7 @@ init_ast(void) ...@@ -2956,7 +2956,7 @@ init_ast(void)
if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return; if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;
if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0) if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
return; return;
if (PyModule_AddStringConstant(m, "__version__", "42635") < 0) if (PyModule_AddStringConstant(m, "__version__", "42649") < 0)
return; return;
if(PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return; if(PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
if(PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) if(PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
......
...@@ -4286,6 +4286,8 @@ compute_code_flags(struct compiler *c) ...@@ -4286,6 +4286,8 @@ compute_code_flags(struct compiler *c)
flags |= CO_GENERATOR; flags |= CO_GENERATOR;
if (c->c_flags->cf_flags & CO_FUTURE_DIVISION) if (c->c_flags->cf_flags & CO_FUTURE_DIVISION)
flags |= CO_FUTURE_DIVISION; flags |= CO_FUTURE_DIVISION;
if (c->c_flags->cf_flags & CO_FUTURE_WITH_STATEMENT)
flags |= CO_FUTURE_WITH_STATEMENT;
n = PyDict_Size(c->u->u_freevars); n = PyDict_Size(c->u->u_freevars);
if (n < 0) if (n < 0)
return -1; return -1;
......
...@@ -31,6 +31,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) ...@@ -31,6 +31,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
ff->ff_features |= CO_FUTURE_DIVISION; ff->ff_features |= CO_FUTURE_DIVISION;
} else if (strcmp(feature, FUTURE_ABSIMPORT) == 0) { } else if (strcmp(feature, FUTURE_ABSIMPORT) == 0) {
ff->ff_features |= CO_FUTURE_ABSIMPORT; ff->ff_features |= CO_FUTURE_ABSIMPORT;
} else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
ff->ff_features |= CO_FUTURE_WITH_STATEMENT;
} else if (strcmp(feature, "braces") == 0) { } else if (strcmp(feature, "braces") == 0) {
PyErr_SetString(PyExc_SyntaxError, PyErr_SetString(PyExc_SyntaxError,
"not a chance"); "not a chance");
......
...@@ -690,8 +690,10 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag ...@@ -690,8 +690,10 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag
/* compute parser flags based on compiler flags */ /* compute parser flags based on compiler flags */
#define PARSER_FLAGS(flags) \ #define PARSER_FLAGS(flags) \
(((flags) && (flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \ ((flags) ? ((((flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
PyPARSE_DONT_IMPLY_DEDENT : 0) PyPARSE_DONT_IMPLY_DEDENT : 0) \
| ((flags)->cf_flags & CO_FUTURE_WITH_STATEMENT ? \
PyPARSE_WITH_IS_KEYWORD : 0)) : 0)
int int
PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment