Commit e3944a5e authored by Brett Cannon's avatar Brett Cannon

The BDFL has retired! Long live the FLUFL (Friendly Language Uncle For Life)!

parent 4ed72acd
...@@ -87,7 +87,7 @@ or_test: and_test ('or' and_test)* ...@@ -87,7 +87,7 @@ or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)* and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison not_test: 'not' not_test | comparison
comparison: star_expr (comp_op star_expr)* comparison: star_expr (comp_op star_expr)*
comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not' comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
star_expr: ['*'] expr star_expr: ['*'] expr
expr: xor_expr ('|' xor_expr)* expr: xor_expr ('|' xor_expr)*
xor_expr: and_expr ('^' and_expr)* xor_expr: and_expr ('^' and_expr)*
......
...@@ -52,10 +52,12 @@ typedef struct { ...@@ -52,10 +52,12 @@ typedef struct {
#define CO_FUTURE_UNICODE_LITERALS 0x20000 #define CO_FUTURE_UNICODE_LITERALS 0x20000
#endif #endif
#define CO_FUTURE_BARRY_AS_BDFL 0x40000
/* This should be defined if a future statement modifies the syntax. /* This should be defined if a future statement modifies the syntax.
For example, when a keyword is added. For example, when a keyword is added.
*/ */
/* #define PY_PARSER_REQUIRES_FUTURE_KEYWORD */ #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 */
......
...@@ -26,6 +26,7 @@ typedef struct { ...@@ -26,6 +26,7 @@ typedef struct {
#define FUTURE_WITH_STATEMENT "with_statement" #define FUTURE_WITH_STATEMENT "with_statement"
#define FUTURE_PRINT_FUNCTION "print_function" #define FUTURE_PRINT_FUNCTION "print_function"
#define FUTURE_UNICODE_LITERALS "unicode_literals" #define FUTURE_UNICODE_LITERALS "unicode_literals"
#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
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 *,
......
...@@ -30,6 +30,7 @@ typedef struct { ...@@ -30,6 +30,7 @@ typedef struct {
#endif #endif
#define PyPARSE_IGNORE_COOKIE 0x0010 #define PyPARSE_IGNORE_COOKIE 0x0010
#define PyPARSE_BARRY_AS_BDFL 0x0020
PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int,
perrdetail *); perrdetail *);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
extern "C" { extern "C" {
#endif #endif
#define PyCF_MASK 0 #define PyCF_MASK CO_FUTURE_BARRY_AS_BDFL
#define PyCF_MASK_OBSOLETE 0 #define PyCF_MASK_OBSOLETE 0
#define PyCF_SOURCE_IS_UTF8 0x0100 #define PyCF_SOURCE_IS_UTF8 0x0100
#define PyCF_DONT_IMPLY_DEDENT 0x0200 #define PyCF_DONT_IMPLY_DEDENT 0x0200
......
...@@ -70,6 +70,7 @@ CO_FUTURE_ABSOLUTE_IMPORT = 0x4000 # perform absolute imports by default ...@@ -70,6 +70,7 @@ CO_FUTURE_ABSOLUTE_IMPORT = 0x4000 # perform absolute imports by default
CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement CO_FUTURE_WITH_STATEMENT = 0x8000 # with statement
CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function CO_FUTURE_PRINT_FUNCTION = 0x10000 # print function
CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals CO_FUTURE_UNICODE_LITERALS = 0x20000 # unicode string literals
CO_FUTURE_BARRY_AS_BDFL = 0x40000
class _Feature: class _Feature:
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag): def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
...@@ -126,3 +127,7 @@ print_function = _Feature((2, 6, 0, "alpha", 2), ...@@ -126,3 +127,7 @@ print_function = _Feature((2, 6, 0, "alpha", 2),
unicode_literals = _Feature((2, 6, 0, "alpha", 2), unicode_literals = _Feature((2, 6, 0, "alpha", 2),
(3, 0, 0, "alpha", 0), (3, 0, 0, "alpha", 0),
CO_FUTURE_UNICODE_LITERALS) CO_FUTURE_UNICODE_LITERALS)
barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2),
(3, 9, 0, "alpha", 0),
CO_FUTURE_BARRY_AS_BDFL)
import __future__
import unittest
class FLUFLTests(unittest.TestCase):
def test_barry_as_bdfl(self):
code = "from __future__ import barry_as_FLUFL; 2 {0} 3"
compile(code.format('<>'), '<BDFL test>', 'exec',
__future__.CO_FUTURE_BARRY_AS_BDFL)
self.assertRaises(SyntaxError, compile, code.format('!='),
'<FLUFL test>', 'exec',
__future__.CO_FUTURE_BARRY_AS_BDFL)
def test_guido_as_bdfl(self):
code = '2 {0} 3'
compile(code.format('!='), '<BDFL test>', 'exec')
self.assertRaises(SyntaxError, compile, code.format('<>'),
'<FLUFL test>', 'exec')
def test_main():
from test.support import run_unittest
run_unittest(FLUFLTests)
if __name__ == '__main__':
test_main()
...@@ -149,6 +149,7 @@ classify(parser_state *ps, int type, char *str) ...@@ -149,6 +149,7 @@ classify(parser_state *ps, int type, char *str)
strcmp(l->lb_str, s) != 0) strcmp(l->lb_str, s) != 0)
continue; continue;
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
#if 0
/* Leaving this in as an example */ /* Leaving this in as an example */
if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) {
if (s[0] == 'w' && strcmp(s, "with") == 0) if (s[0] == 'w' && strcmp(s, "with") == 0)
...@@ -156,6 +157,7 @@ classify(parser_state *ps, int type, char *str) ...@@ -156,6 +157,7 @@ classify(parser_state *ps, int type, char *str)
else if (s[0] == 'a' && strcmp(s, "as") == 0) else if (s[0] == 'a' && strcmp(s, "as") == 0)
break; /* not a keyword yet */ break; /* not a keyword yet */
} }
#endif
#endif #endif
D(printf("It's a keyword\n")); D(printf("It's a keyword\n"));
return n - i; return n - i;
...@@ -178,6 +180,7 @@ classify(parser_state *ps, int type, char *str) ...@@ -178,6 +180,7 @@ classify(parser_state *ps, int type, char *str)
} }
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
#if 0
/* Leaving this in as an example */ /* Leaving this in as an example */
static void static void
future_hack(parser_state *ps) future_hack(parser_state *ps)
...@@ -218,6 +221,7 @@ future_hack(parser_state *ps) ...@@ -218,6 +221,7 @@ future_hack(parser_state *ps)
} }
} }
} }
#endif
#endif /* future keyword */ #endif /* future keyword */
int int
...@@ -278,10 +282,12 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str, ...@@ -278,10 +282,12 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
d->d_name, d->d_name,
ps->p_stack.s_top->s_state)); ps->p_stack.s_top->s_state));
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
#if 0
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)
future_hack(ps); future_hack(ps);
#endif
#endif #endif
s_pop(&ps->p_stack); s_pop(&ps->p_stack);
if (s_empty(&ps->p_stack)) { if (s_empty(&ps->p_stack)) {
...@@ -296,9 +302,11 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str, ...@@ -296,9 +302,11 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
if (s->s_accept) { if (s->s_accept) {
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
#if 0
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);
#endif
#endif #endif
/* Pop this dfa and try again */ /* Pop this dfa and try again */
s_pop(&ps->p_stack); s_pop(&ps->p_stack);
......
...@@ -100,6 +100,7 @@ PyParser_ParseFileFlagsEx(FILE *fp, const char *filename, ...@@ -100,6 +100,7 @@ PyParser_ParseFileFlagsEx(FILE *fp, const char *filename,
} }
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
#if 0
static char with_msg[] = static char with_msg[] =
"%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n"; "%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n";
...@@ -114,6 +115,7 @@ warn(const char *msg, const char *filename, int lineno) ...@@ -114,6 +115,7 @@ warn(const char *msg, const char *filename, int lineno)
PySys_WriteStderr(msg, filename, lineno); PySys_WriteStderr(msg, filename, lineno);
} }
#endif #endif
#endif
/* Parse input coming from the given tokenizer structure. /* Parse input coming from the given tokenizer structure.
Return error code. */ Return error code. */
...@@ -133,8 +135,8 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -133,8 +135,8 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
return NULL; return NULL;
} }
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
if (*flags & PyPARSE_WITH_IS_KEYWORD) if (*flags & PyPARSE_BARRY_AS_BDFL)
ps->p_flags |= CO_FUTURE_WITH_STATEMENT; ps->p_flags |= CO_FUTURE_BARRY_AS_BDFL;
#endif #endif
for (;;) { for (;;) {
...@@ -177,26 +179,20 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, ...@@ -177,26 +179,20 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
str[len] = '\0'; str[len] = '\0';
#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
/* This is only necessary to support the "as" warning, but if (type == NOTEQUAL) {
we don't want to warn about "as" in import statements. */ if (!(ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
if (type == NAME && strcmp(str, "!=")) {
len == 6 && str[0] == 'i' && strcmp(str, "import") == 0) err_ret->error = E_SYNTAX;
handling_import = 1; break;
}
/* Warn about with as NAME */ else if ((ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
if (type == NAME && strcmp(str, "<>")) {
!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { err_ret->text = "with Barry as BDFL, use '<>' "
if (len == 4 && str[0] == 'w' && strcmp(str, "with") == 0) "instead of '!='";
warn(with_msg, err_ret->filename, tok->lineno); err_ret->error = E_SYNTAX;
else if (!(handling_import || handling_with) && break;
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 (a >= tok->line_start) if (a >= tok->line_start)
col_offset = a - tok->line_start; col_offset = a - tok->line_start;
......
...@@ -1040,6 +1040,7 @@ PyToken_TwoChars(int c1, int c2) ...@@ -1040,6 +1040,7 @@ PyToken_TwoChars(int c1, int c2)
break; break;
case '<': case '<':
switch (c2) { switch (c2) {
case '>': return NOTEQUAL;
case '=': return LESSEQUAL; case '=': return LESSEQUAL;
case '<': return LEFTSHIFT; case '<': return LEFTSHIFT;
} }
......
...@@ -39,6 +39,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) ...@@ -39,6 +39,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
continue; continue;
} else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
continue; continue;
} else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
} 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");
......
This diff is collapsed.
...@@ -1011,6 +1011,8 @@ static int PARSER_FLAGS(PyCompilerFlags *flags) ...@@ -1011,6 +1011,8 @@ static int PARSER_FLAGS(PyCompilerFlags *flags)
parser_flags |= PyPARSE_DONT_IMPLY_DEDENT; parser_flags |= PyPARSE_DONT_IMPLY_DEDENT;
if (flags->cf_flags & PyCF_IGNORE_COOKIE) if (flags->cf_flags & PyCF_IGNORE_COOKIE)
parser_flags |= PyPARSE_IGNORE_COOKIE; parser_flags |= PyPARSE_IGNORE_COOKIE;
if (flags->cf_flags & CO_FUTURE_BARRY_AS_BDFL)
parser_flags |= PyPARSE_BARRY_AS_BDFL;
return parser_flags; return parser_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