mirror of https://github.com/python/cpython
PEP 308 implementation, including minor refdocs and some testcases. It
breaks the parser module, because it adds the if/else construct as well as two new grammar rules for backward compatibility. If no one else fixes parsermodule, I guess I'll go ahead and fix it later this week. The TeX code was checked with texcheck.py, but not rendered. There is actually a slight incompatibility: >>> (x for x in lambda:0) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: iteration over non-sequence changes into >>> (x for x in lambda: 0) File "<stdin>", line 1 (x for x in lambda: 0) ^ SyntaxError: invalid syntax Since there's no way the former version can be useful, it's probably a bugfix ;)
This commit is contained in:
parent
d3a5f53a27
commit
dca3b9c797
|
@ -155,8 +155,7 @@ square brackets:
|
|||
|
||||
\begin{productionlist}
|
||||
\production{test}
|
||||
{\token{and_test} ( "or" \token{and_test} )*
|
||||
| \token{lambda_form}}
|
||||
{\token{or_test} | \token{lambda_form}}
|
||||
\production{testlist}
|
||||
{\token{test} ( "," \token{test} )* [ "," ]}
|
||||
\production{list_display}
|
||||
|
@ -1017,7 +1016,8 @@ Boolean operations have the lowest priority of all Python operations:
|
|||
|
||||
\begin{productionlist}
|
||||
\production{expression}
|
||||
{\token{or_test} | \token{lambda_form}}
|
||||
{\token{or_test} [\token{if} \token{or_test} \token{else}
|
||||
\token{test}] | \token{lambda_form}}
|
||||
\production{or_test}
|
||||
{\token{and_test} | \token{or_test} "or" \token{and_test}}
|
||||
\production{and_test}
|
||||
|
@ -1036,6 +1036,11 @@ The operator \keyword{not} yields \code{True} if its argument is false,
|
|||
\code{False} otherwise.
|
||||
\opindex{not}
|
||||
|
||||
The expression \code{\var{x} if \var{C} else \var{y}} first evaluates
|
||||
\var{C} (\emph{not} \var{x}); if \var{C} is true, \var{x} is evaluated and
|
||||
its value is returned; otherwise, \var{y} is evaluated and its value is
|
||||
returned.
|
||||
|
||||
The expression \code{\var{x} and \var{y}} first evaluates \var{x}; if
|
||||
\var{x} is false, its value is returned; otherwise, \var{y} is
|
||||
evaluated and the resulting value is returned.
|
||||
|
|
|
@ -83,7 +83,17 @@ try_stmt: ('try' ':' suite
|
|||
except_clause: 'except' [test [',' test]]
|
||||
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
|
||||
|
||||
test: and_test ('or' and_test)* | lambdef
|
||||
# Backward compatibility cruft to support:
|
||||
# [ x for x in lambda: True, lambda: False if x() ]
|
||||
# even while also allowing:
|
||||
# lambda x: 5 if x else 2
|
||||
# (But not a mix of the two)
|
||||
testlist_safe: old_test [(',' old_test)+ [',']]
|
||||
old_test: or_test | old_lambdef
|
||||
old_lambdef: 'lambda' [varargslist] ':' old_test
|
||||
|
||||
test: or_test ['if' or_test 'else' test] | lambdef
|
||||
or_test: and_test ('or' and_test)*
|
||||
and_test: not_test ('and' not_test)*
|
||||
not_test: 'not' not_test | comparison
|
||||
comparison: expr (comp_op expr)*
|
||||
|
@ -110,7 +120,6 @@ subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
|
|||
sliceop: ':' [test]
|
||||
exprlist: expr (',' expr)* [',']
|
||||
testlist: test (',' test)* [',']
|
||||
testlist_safe: test [(',' test)+ [',']]
|
||||
dictmaker: test ':' test (',' test ':' test)* [',']
|
||||
|
||||
classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
|
||||
|
@ -123,7 +132,7 @@ list_for: 'for' exprlist 'in' testlist_safe [list_iter]
|
|||
list_if: 'if' test [list_iter]
|
||||
|
||||
gen_iter: gen_for | gen_if
|
||||
gen_for: 'for' exprlist 'in' test [gen_iter]
|
||||
gen_for: 'for' exprlist 'in' or_test [gen_iter]
|
||||
gen_if: 'if' test [gen_iter]
|
||||
|
||||
testlist1: test (',' test)*
|
||||
|
|
|
@ -175,10 +175,10 @@ struct _stmt {
|
|||
|
||||
struct _expr {
|
||||
enum { BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
|
||||
Dict_kind=5, ListComp_kind=6, GeneratorExp_kind=7, Yield_kind=8,
|
||||
Compare_kind=9, Call_kind=10, Repr_kind=11, Num_kind=12,
|
||||
Str_kind=13, Attribute_kind=14, Subscript_kind=15, Name_kind=16,
|
||||
List_kind=17, Tuple_kind=18 } kind;
|
||||
IfExp_kind=5, Dict_kind=6, ListComp_kind=7, GeneratorExp_kind=8,
|
||||
Yield_kind=9, Compare_kind=10, Call_kind=11, Repr_kind=12,
|
||||
Num_kind=13, Str_kind=14, Attribute_kind=15, Subscript_kind=16,
|
||||
Name_kind=17, List_kind=18, Tuple_kind=19 } kind;
|
||||
union {
|
||||
struct {
|
||||
boolop_ty op;
|
||||
|
@ -201,6 +201,12 @@ struct _expr {
|
|||
expr_ty body;
|
||||
} Lambda;
|
||||
|
||||
struct {
|
||||
expr_ty test;
|
||||
expr_ty body;
|
||||
expr_ty orelse;
|
||||
} IfExp;
|
||||
|
||||
struct {
|
||||
asdl_seq *keys;
|
||||
asdl_seq *values;
|
||||
|
@ -371,6 +377,8 @@ expr_ty BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, PyArena
|
|||
*arena);
|
||||
expr_ty UnaryOp(unaryop_ty op, expr_ty operand, int lineno, PyArena *arena);
|
||||
expr_ty Lambda(arguments_ty args, expr_ty body, int lineno, PyArena *arena);
|
||||
expr_ty IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena
|
||||
*arena);
|
||||
expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena);
|
||||
expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, PyArena
|
||||
*arena);
|
||||
|
|
|
@ -40,40 +40,43 @@
|
|||
#define try_stmt 295
|
||||
#define except_clause 296
|
||||
#define suite 297
|
||||
#define test 298
|
||||
#define and_test 299
|
||||
#define not_test 300
|
||||
#define comparison 301
|
||||
#define comp_op 302
|
||||
#define expr 303
|
||||
#define xor_expr 304
|
||||
#define and_expr 305
|
||||
#define shift_expr 306
|
||||
#define arith_expr 307
|
||||
#define term 308
|
||||
#define factor 309
|
||||
#define power 310
|
||||
#define atom 311
|
||||
#define listmaker 312
|
||||
#define testlist_gexp 313
|
||||
#define lambdef 314
|
||||
#define trailer 315
|
||||
#define subscriptlist 316
|
||||
#define subscript 317
|
||||
#define sliceop 318
|
||||
#define exprlist 319
|
||||
#define testlist 320
|
||||
#define testlist_safe 321
|
||||
#define dictmaker 322
|
||||
#define classdef 323
|
||||
#define arglist 324
|
||||
#define argument 325
|
||||
#define list_iter 326
|
||||
#define list_for 327
|
||||
#define list_if 328
|
||||
#define gen_iter 329
|
||||
#define gen_for 330
|
||||
#define gen_if 331
|
||||
#define testlist1 332
|
||||
#define encoding_decl 333
|
||||
#define yield_expr 334
|
||||
#define testlist_safe 298
|
||||
#define old_test 299
|
||||
#define old_lambdef 300
|
||||
#define test 301
|
||||
#define or_test 302
|
||||
#define and_test 303
|
||||
#define not_test 304
|
||||
#define comparison 305
|
||||
#define comp_op 306
|
||||
#define expr 307
|
||||
#define xor_expr 308
|
||||
#define and_expr 309
|
||||
#define shift_expr 310
|
||||
#define arith_expr 311
|
||||
#define term 312
|
||||
#define factor 313
|
||||
#define power 314
|
||||
#define atom 315
|
||||
#define listmaker 316
|
||||
#define testlist_gexp 317
|
||||
#define lambdef 318
|
||||
#define trailer 319
|
||||
#define subscriptlist 320
|
||||
#define subscript 321
|
||||
#define sliceop 322
|
||||
#define exprlist 323
|
||||
#define testlist 324
|
||||
#define dictmaker 325
|
||||
#define classdef 326
|
||||
#define arglist 327
|
||||
#define argument 328
|
||||
#define list_iter 329
|
||||
#define list_for 330
|
||||
#define list_if 331
|
||||
#define gen_iter 332
|
||||
#define gen_for 333
|
||||
#define gen_if 334
|
||||
#define testlist1 335
|
||||
#define encoding_decl 336
|
||||
#define yield_expr 337
|
||||
|
|
|
@ -798,3 +798,28 @@ verify(len(list(g)) == 10)
|
|||
x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x))
|
||||
x = 5; t = True;
|
||||
verify([(i,j) for i in range(10) for j in range(5)] == list(g))
|
||||
|
||||
# Test ifelse expressions in various cases
|
||||
def _checkeval(msg, ret):
|
||||
"helper to check that evaluation of expressions is done correctly"
|
||||
print x
|
||||
return ret
|
||||
|
||||
verify([ x() for x in lambda: True, lambda: False if x() ] == [True])
|
||||
verify([ x() for x in (lambda: True, lambda: False) if x() ] == [True])
|
||||
verify([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ] == [True])
|
||||
verify((5 if 1 else _checkeval("check 1", 0)) == 5)
|
||||
verify((_checkeval("check 2", 0) if 0 else 5) == 5)
|
||||
verify((5 and 6 if 0 else 1) == 1)
|
||||
verify(((5 and 6) if 0 else 1) == 1)
|
||||
verify((5 and (6 if 1 else 1)) == 6)
|
||||
verify((0 or _checkeval("check 3", 2) if 0 else 3) == 3)
|
||||
verify((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)) == 1)
|
||||
verify((0 or 5 if 1 else _checkeval("check 6", 3)) == 5)
|
||||
verify((not 5 if 1 else 1) == False)
|
||||
verify((not 5 if 0 else 1) == 1)
|
||||
verify((6 + 1 if 1 else 2) == 7)
|
||||
verify((6 - 1 if 1 else 2) == 5)
|
||||
verify((6 * 2 if 1 else 4) == 12)
|
||||
verify((6 / 2 if 1 else 3) == 3)
|
||||
verify((6 < 4 if 0 else 2) == 2)
|
||||
|
|
|
@ -52,6 +52,7 @@ module Python
|
|||
| BinOp(expr left, operator op, expr right)
|
||||
| UnaryOp(unaryop op, expr operand)
|
||||
| Lambda(arguments args, expr body)
|
||||
| IfExp(expr test, expr body, expr orelse)
|
||||
| Dict(expr* keys, expr* values)
|
||||
| ListComp(expr elt, comprehension* generators)
|
||||
| GeneratorExp(expr elt, comprehension* generators)
|
||||
|
|
|
@ -151,6 +151,12 @@ char *Lambda_fields[]={
|
|||
"args",
|
||||
"body",
|
||||
};
|
||||
PyTypeObject *IfExp_type;
|
||||
char *IfExp_fields[]={
|
||||
"test",
|
||||
"body",
|
||||
"orelse",
|
||||
};
|
||||
PyTypeObject *Dict_type;
|
||||
char *Dict_fields[]={
|
||||
"keys",
|
||||
|
@ -431,6 +437,7 @@ static int init_types(void)
|
|||
BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3);
|
||||
UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2);
|
||||
Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2);
|
||||
IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3);
|
||||
Dict_type = make_type("Dict", expr_type, Dict_fields, 2);
|
||||
ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2);
|
||||
GeneratorExp_type = make_type("GeneratorExp", expr_type,
|
||||
|
@ -1137,6 +1144,38 @@ Lambda(arguments_ty args, expr_ty body, int lineno, PyArena *arena)
|
|||
return p;
|
||||
}
|
||||
|
||||
expr_ty
|
||||
IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena *arena)
|
||||
{
|
||||
expr_ty p;
|
||||
if (!test) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field test is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
if (!body) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field body is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
if (!orelse) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field orelse is required for IfExp");
|
||||
return NULL;
|
||||
}
|
||||
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
|
||||
if (!p) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
p->kind = IfExp_kind;
|
||||
p->v.IfExp.test = test;
|
||||
p->v.IfExp.body = body;
|
||||
p->v.IfExp.orelse = orelse;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
expr_ty
|
||||
Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena)
|
||||
{
|
||||
|
@ -2077,6 +2116,25 @@ ast2obj_expr(void* _o)
|
|||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case IfExp_kind:
|
||||
result = PyType_GenericNew(IfExp_type, NULL, NULL);
|
||||
if (!result) goto failed;
|
||||
value = ast2obj_expr(o->v.IfExp.test);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttrString(result, "test", value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_expr(o->v.IfExp.body);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttrString(result, "body", value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
value = ast2obj_expr(o->v.IfExp.orelse);
|
||||
if (!value) goto failed;
|
||||
if (PyObject_SetAttrString(result, "orelse", value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case Dict_kind:
|
||||
result = PyType_GenericNew(Dict_type, NULL, NULL);
|
||||
if (!result) goto failed;
|
||||
|
|
40
Python/ast.c
40
Python/ast.c
|
@ -847,6 +847,25 @@ ast_for_lambdef(struct compiling *c, const node *n)
|
|||
return Lambda(args, expression, LINENO(n), c->c_arena);
|
||||
}
|
||||
|
||||
static expr_ty
|
||||
ast_for_ifexpr(struct compiling *c, const node *n)
|
||||
{
|
||||
/* test: or_test 'if' or_test 'else' test */
|
||||
expr_ty expression, body, orelse;
|
||||
|
||||
assert(NCH(n) >= 3);
|
||||
body = ast_for_expr(c, CHILD(n, 0));
|
||||
if (!body)
|
||||
return NULL;
|
||||
expression = ast_for_expr(c, CHILD(n, 2));
|
||||
if (!expression)
|
||||
return NULL;
|
||||
orelse = ast_for_expr(c, CHILD(n, 4));
|
||||
if (!orelse)
|
||||
return NULL;
|
||||
return IfExp(expression, body, orelse, LINENO(n), c->c_arena);
|
||||
}
|
||||
|
||||
/* Count the number of 'for' loop in a list comprehension.
|
||||
|
||||
Helper for ast_for_listcomp().
|
||||
|
@ -1456,7 +1475,8 @@ static expr_ty
|
|||
ast_for_expr(struct compiling *c, const node *n)
|
||||
{
|
||||
/* handle the full range of simple expressions
|
||||
test: and_test ('or' and_test)* | lambdef
|
||||
test: or_test ['if' or_test 'else' test] | lambdef
|
||||
or_test: and_test ('or' and_test)*
|
||||
and_test: not_test ('and' not_test)*
|
||||
not_test: 'not' not_test | comparison
|
||||
comparison: expr (comp_op expr)*
|
||||
|
@ -1468,6 +1488,15 @@ ast_for_expr(struct compiling *c, const node *n)
|
|||
term: factor (('*'|'/'|'%'|'//') factor)*
|
||||
factor: ('+'|'-'|'~') factor | power
|
||||
power: atom trailer* ('**' factor)*
|
||||
|
||||
As well as modified versions that exist for backward compatibility,
|
||||
to explicitly allow:
|
||||
[ x for x in lambda: 0, lambda: 1 ]
|
||||
(which would be ambiguous without these extra rules)
|
||||
|
||||
old_test: or_test | old_lambdef
|
||||
old_lambdef: 'lambda' [vararglist] ':' old_test
|
||||
|
||||
*/
|
||||
|
||||
asdl_seq *seq;
|
||||
|
@ -1476,9 +1505,14 @@ ast_for_expr(struct compiling *c, const node *n)
|
|||
loop:
|
||||
switch (TYPE(n)) {
|
||||
case test:
|
||||
if (TYPE(CHILD(n, 0)) == lambdef)
|
||||
case old_test:
|
||||
if (TYPE(CHILD(n, 0)) == lambdef ||
|
||||
TYPE(CHILD(n, 0)) == old_lambdef)
|
||||
return ast_for_lambdef(c, CHILD(n, 0));
|
||||
/* Fall through to and_test */
|
||||
else if (NCH(n) > 1)
|
||||
return ast_for_ifexpr(c, n);
|
||||
/* Fallthrough */
|
||||
case or_test:
|
||||
case and_test:
|
||||
if (NCH(n) == 1) {
|
||||
n = CHILD(n, 0);
|
||||
|
|
|
@ -2009,6 +2009,30 @@ compiler_class(struct compiler *c, stmt_ty s)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_ifexp(struct compiler *c, expr_ty e)
|
||||
{
|
||||
basicblock *end, *next;
|
||||
|
||||
assert(e->kind == IfExp_kind);
|
||||
end = compiler_new_block(c);
|
||||
if (end == NULL)
|
||||
return 0;
|
||||
next = compiler_new_block(c);
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
VISIT(c, expr, e->v.IfExp.test);
|
||||
ADDOP_JREL(c, JUMP_IF_FALSE, next);
|
||||
ADDOP(c, POP_TOP);
|
||||
VISIT(c, expr, e->v.IfExp.body);
|
||||
ADDOP_JREL(c, JUMP_FORWARD, end);
|
||||
compiler_use_next_block(c, next);
|
||||
ADDOP(c, POP_TOP);
|
||||
VISIT(c, expr, e->v.IfExp.orelse);
|
||||
compiler_use_next_block(c, end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_lambda(struct compiler *c, expr_ty e)
|
||||
{
|
||||
|
@ -3290,6 +3314,8 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
|
|||
break;
|
||||
case Lambda_kind:
|
||||
return compiler_lambda(c, e);
|
||||
case IfExp_kind:
|
||||
return compiler_ifexp(c, e);
|
||||
case Dict_kind:
|
||||
/* XXX get rid of arg? */
|
||||
ADDOP_I(c, BUILD_MAP, 0);
|
||||
|
|
1246
Python/graminit.c
1246
Python/graminit.c
File diff suppressed because it is too large
Load Diff
|
@ -1084,6 +1084,11 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
|||
return 0;
|
||||
break;
|
||||
}
|
||||
case IfExp_kind:
|
||||
VISIT(st, expr, e->v.IfExp.test);
|
||||
VISIT(st, expr, e->v.IfExp.body);
|
||||
VISIT(st, expr, e->v.IfExp.orelse);
|
||||
break;
|
||||
case Dict_kind:
|
||||
VISIT_SEQ(st, expr, e->v.Dict.keys);
|
||||
VISIT_SEQ(st, expr, e->v.Dict.values);
|
||||
|
|
Loading…
Reference in New Issue