Skip to content

Commit 65391c3

Browse files
committed
Hide list comp variables and support set comprehensions
1 parent 7b1dd1e commit 65391c3

29 files changed

Lines changed: 1944 additions & 1261 deletions

Doc/lib/libdis.tex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ \subsection{Python Byte Code Instructions}
363363
instruction).
364364
\end{opcodedesc}
365365

366+
\begin{opcodedesc}{SET_ADD}{}
367+
Calls \code{set.add(TOS1, TOS)}. Used to implement set comprehensions.
368+
\end{opcodedesc}
369+
366370
\begin{opcodedesc}{LIST_APPEND}{}
367371
Calls \code{list.append(TOS1, TOS)}. Used to implement list comprehensions.
368372
\end{opcodedesc}

Grammar/Grammar

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,10 @@ with_var: 'as' expr
8282
except_clause: 'except' [test ['as' NAME]]
8383
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
8484

85-
# Backward compatibility cruft to support:
86-
# [ x for x in lambda: True, lambda: False if x() ]
87-
# even while also allowing:
88-
# lambda x: 5 if x else 2
89-
# (But not a mix of the two)
90-
testlist_safe: old_test [(',' old_test)+ [',']]
91-
old_test: or_test | old_lambdef
92-
old_lambdef: 'lambda' [varargslist] ':' old_test
93-
9485
test: or_test ['if' or_test 'else' test] | lambdef
86+
test_nocond: or_test | lambdef_nocond
87+
lambdef: 'lambda' [varargslist] ':' test
88+
lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
9589
or_test: and_test ('or' and_test)*
9690
and_test: not_test ('and' not_test)*
9791
not_test: 'not' not_test | comparison
@@ -105,33 +99,28 @@ arith_expr: term (('+'|'-') term)*
10599
term: factor (('*'|'/'|'%'|'//') factor)*
106100
factor: ('+'|'-'|'~') factor | power
107101
power: atom trailer* ['**' factor]
108-
atom: ('(' [yield_expr|testlist_gexp] ')' |
109-
'[' [listmaker] ']' |
110-
'{' [dictsetmaker] '}' |
102+
atom: ('(' [yield_expr|testlist_comp] ')' |
103+
'[' [testlist_comp] ']' |
104+
'{' [dictorsetmaker] '}' |
111105
NAME | NUMBER | STRING+ | '...')
112-
listmaker: test ( list_for | (',' test)* [','] )
113-
testlist_gexp: test ( gen_for | (',' test)* [','] )
114-
lambdef: 'lambda' [varargslist] ':' test
106+
testlist_comp: test ( comp_for | (',' test)* [','] )
115107
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
116108
subscriptlist: subscript (',' subscript)* [',']
117109
subscript: test | [test] ':' [test] [sliceop]
118110
sliceop: ':' [test]
119111
exprlist: expr (',' expr)* [',']
120112
testlist: test (',' test)* [',']
121-
dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [','])
113+
dictorsetmaker: ( (test ':' test (',' test ':' test)* [',']) |
114+
(test (comp_for | (',' test)* [','])) )
122115

123116
classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
124117

125118
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
126-
argument: test [gen_for] | test '=' test # Really [keyword '='] test
127-
128-
list_iter: list_for | list_if
129-
list_for: 'for' exprlist 'in' testlist_safe [list_iter]
130-
list_if: 'if' old_test [list_iter]
119+
argument: test [comp_for] | test '=' test # Really [keyword '='] test
131120

132-
gen_iter: gen_for | gen_if
133-
gen_for: 'for' exprlist 'in' or_test [gen_iter]
134-
gen_if: 'if' old_test [gen_iter]
121+
comp_iter: comp_for | comp_if
122+
comp_for: 'for' exprlist 'in' or_test [comp_iter]
123+
comp_if: 'if' test_nocond [comp_iter]
135124

136125
testlist1: test (',' test)*
137126

Include/Python-ast.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,10 @@ struct _stmt {
183183

184184
enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
185185
IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8,
186-
GeneratorExp_kind=9, Yield_kind=10, Compare_kind=11,
187-
Call_kind=12, Num_kind=13, Str_kind=14, Bytes_kind=15,
188-
Ellipsis_kind=16, Attribute_kind=17, Subscript_kind=18,
189-
Name_kind=19, List_kind=20, Tuple_kind=21};
186+
SetComp_kind=9, GeneratorExp_kind=10, Yield_kind=11,
187+
Compare_kind=12, Call_kind=13, Num_kind=14, Str_kind=15,
188+
Bytes_kind=16, Ellipsis_kind=17, Attribute_kind=18,
189+
Subscript_kind=19, Name_kind=20, List_kind=21, Tuple_kind=22};
190190
struct _expr {
191191
enum _expr_kind kind;
192192
union {
@@ -231,6 +231,11 @@ struct _expr {
231231
asdl_seq *generators;
232232
} ListComp;
233233

234+
struct {
235+
expr_ty elt;
236+
asdl_seq *generators;
237+
} SetComp;
238+
234239
struct {
235240
expr_ty elt;
236241
asdl_seq *generators;
@@ -465,6 +470,9 @@ expr_ty _Py_Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena);
465470
#define ListComp(a0, a1, a2, a3, a4) _Py_ListComp(a0, a1, a2, a3, a4)
466471
expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int
467472
col_offset, PyArena *arena);
473+
#define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4)
474+
expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int
475+
col_offset, PyArena *arena);
468476
#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4)
469477
expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int
470478
col_offset, PyArena *arena);

Include/graminit.h

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@
4646
#define with_var 301
4747
#define except_clause 302
4848
#define suite 303
49-
#define testlist_safe 304
50-
#define old_test 305
51-
#define old_lambdef 306
52-
#define test 307
49+
#define test 304
50+
#define test_nocond 305
51+
#define lambdef 306
52+
#define lambdef_nocond 307
5353
#define or_test 308
5454
#define and_test 309
5555
#define not_test 310
@@ -64,25 +64,20 @@
6464
#define factor 319
6565
#define power 320
6666
#define atom 321
67-
#define listmaker 322
68-
#define testlist_gexp 323
69-
#define lambdef 324
70-
#define trailer 325
71-
#define subscriptlist 326
72-
#define subscript 327
73-
#define sliceop 328
74-
#define exprlist 329
75-
#define testlist 330
76-
#define dictsetmaker 331
77-
#define classdef 332
78-
#define arglist 333
79-
#define argument 334
80-
#define list_iter 335
81-
#define list_for 336
82-
#define list_if 337
83-
#define gen_iter 338
84-
#define gen_for 339
85-
#define gen_if 340
86-
#define testlist1 341
87-
#define encoding_decl 342
88-
#define yield_expr 343
67+
#define testlist_comp 322
68+
#define trailer 323
69+
#define subscriptlist 324
70+
#define subscript 325
71+
#define sliceop 326
72+
#define exprlist 327
73+
#define testlist 328
74+
#define dictorsetmaker 329
75+
#define classdef 330
76+
#define arglist 331
77+
#define argument 332
78+
#define comp_iter 333
79+
#define comp_for 334
80+
#define comp_if 335
81+
#define testlist1 336
82+
#define encoding_decl 337
83+
#define yield_expr 338

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern "C" {
2121

2222
#define UNARY_INVERT 15
2323

24+
#define SET_ADD 17
2425
#define LIST_APPEND 18
2526
#define BINARY_POWER 19
2627

Include/symtable.h

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,35 @@
55
extern "C" {
66
#endif
77

8+
/* XXX(ncoghlan): This is a weird mix of public names and interpreter internal
9+
* names.
10+
*/
11+
812
typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock }
913
_Py_block_ty;
1014

1115
struct _symtable_entry;
1216

1317
struct symtable {
14-
const char *st_filename; /* name of file being compiled */
18+
const char *st_filename; /* name of file being compiled */
1519
struct _symtable_entry *st_cur; /* current symbol table entry */
16-
struct _symtable_entry *st_top; /* module entry */
17-
PyObject *st_symbols; /* dictionary of symbol table entries */
18-
PyObject *st_stack; /* stack of namespace info */
19-
PyObject *st_global; /* borrowed ref to MODULE in st_symbols */
20-
int st_nblocks; /* number of blocks */
21-
PyObject *st_private; /* name of current class or NULL */
22-
int st_tmpname; /* temporary name counter */
23-
PyFutureFeatures *st_future; /* module's future features */
20+
struct _symtable_entry *st_top; /* symbol table entry for module */
21+
PyObject *st_blocks; /* dict: map AST node addresses
22+
* to symbol table entries */
23+
PyObject *st_stack; /* list: stack of namespace info */
24+
PyObject *st_global; /* borrowed ref to st_top->st_symbols */
25+
int st_nblocks; /* number of blocks used */
26+
PyObject *st_private; /* name of current class or NULL */
27+
PyFutureFeatures *st_future; /* module's future features */
2428
};
2529

2630
typedef struct _symtable_entry {
2731
PyObject_HEAD
28-
PyObject *ste_id; /* int: key in st_symbols */
29-
PyObject *ste_symbols; /* dict: name to flags */
30-
PyObject *ste_name; /* string: name of block */
32+
PyObject *ste_id; /* int: key in ste_table->st_blocks */
33+
PyObject *ste_symbols; /* dict: variable names to flags */
34+
PyObject *ste_name; /* string: name of current block */
3135
PyObject *ste_varnames; /* list of variable names */
32-
PyObject *ste_children; /* list of child ids */
36+
PyObject *ste_children; /* list of child blocks */
3337
_Py_block_ty ste_type; /* module, class, or function */
3438
int ste_unoptimized; /* false if namespace is optimized */
3539
unsigned ste_nested : 1; /* true if block is nested */
@@ -80,7 +84,7 @@ PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
8084
table. GLOBAL is returned from PyST_GetScope() for either of them.
8185
It is stored in ste_symbols at bits 12-15.
8286
*/
83-
#define SCOPE_OFF 11
87+
#define SCOPE_OFFSET 11
8488
#define SCOPE_MASK (DEF_GLOBAL | DEF_LOCAL | DEF_PARAM | DEF_NONLOCAL)
8589

8690
#define LOCAL 1

Lib/compiler/transformer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ def testlist(self, nodelist):
559559
testlist1 = testlist
560560
exprlist = testlist
561561

562-
def testlist_gexp(self, nodelist):
562+
def testlist_comp(self, nodelist):
563563
if len(nodelist) == 2 and nodelist[1][0] == symbol.gen_for:
564564
test = self.com_node(nodelist[0])
565565
return self.com_generator_expression(test, nodelist[1])
@@ -1027,7 +1027,7 @@ def com_assign(self, node, assigning):
10271027
# loop to avoid trivial recursion
10281028
while 1:
10291029
t = node[0]
1030-
if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_gexp):
1030+
if t in (symbol.exprlist, symbol.testlist, symbol.testlist_comp):
10311031
if len(node) > 2:
10321032
return self.com_assign_tuple(node, assigning)
10331033
node = node[1]

Lib/decimal.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,10 +2282,8 @@ def __init__(self, prec=None, rounding=None,
22822282
_ignored_flags = []
22832283
if not isinstance(flags, dict):
22842284
flags = dict([(s,s in flags) for s in _signals])
2285-
del s
22862285
if traps is not None and not isinstance(traps, dict):
22872286
traps = dict([(s,s in traps) for s in _signals])
2288-
del s
22892287
for name, val in locals().items():
22902288
if val is None:
22912289
setattr(self, name, _copy.copy(getattr(DefaultContext, name)))

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def jabs_op(name, op):
5757

5858
def_op('UNARY_INVERT', 15)
5959

60+
def_op('SET_ADD', 17)
6061
def_op('LIST_APPEND', 18)
6162
def_op('BINARY_POWER', 19)
6263
def_op('BINARY_MULTIPLY', 20)

Lib/pickle.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ def __init__(self, value):
163163

164164

165165
__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$",x)])
166-
del x
167166

168167

169168
# Pickling machinery

0 commit comments

Comments
 (0)