Merged revisions 56154-56264 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/p3yk

................
  r56155 | neal.norwitz | 2007-07-03 08:59:08 +0300 (Tue, 03 Jul 2007) | 1 line

  Get this test working after converting map to return an iterator
................
  r56202 | neal.norwitz | 2007-07-09 04:30:09 +0300 (Mon, 09 Jul 2007) | 37 lines

  Merged revisions 56124-56201 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r56129 | georg.brandl | 2007-06-30 04:01:01 -0700 (Sat, 30 Jun 2007) | 2 lines

    Document smtp.SMTPAuthenticationError.
  ........
    r56137 | georg.brandl | 2007-07-01 01:11:35 -0700 (Sun, 01 Jul 2007) | 2 lines

    Fix a few webbrowser.py problems.
  ........
    r56143 | georg.brandl | 2007-07-02 04:54:28 -0700 (Mon, 02 Jul 2007) | 2 lines

    Remove duplicate sentence from alarm() doc.
  ........
    r56170 | mark.hammond | 2007-07-03 19:03:10 -0700 (Tue, 03 Jul 2007) | 3 lines

    copy built files to the PCBuild directory, where tools like
    distutils or external build processes can find them.
  ........
    r56176 | kurt.kaiser | 2007-07-05 15:03:39 -0700 (Thu, 05 Jul 2007) | 10 lines

    Many calls to tk.call involve an arglist containing a single tuple.
    Calls using METH_OLDARGS unpack this tuple; calls using METH_VARARG
    don't.  Tcl's concatenation of args was affected; IDLE doesn't start.

    Modify Tkapp_Call() to unpack single tuple arglists.

    Bug 1733943
    Ref http://mail.python.org/pipermail/python-checkins/2007-May/060454.html
  ........
    r56177 | neal.norwitz | 2007-07-05 21:13:39 -0700 (Thu, 05 Jul 2007) | 1 line

    Fix typo in comment
  ........
................
  r56251 | neal.norwitz | 2007-07-11 10:01:01 +0300 (Wed, 11 Jul 2007) | 1 line

  Get working with map returning an iterator (had to fix whitespace too)
................
  r56255 | thomas.wouters | 2007-07-11 13:41:37 +0300 (Wed, 11 Jul 2007) | 6 lines


  Clean up merge glitch or copy-paste error (the entire module was duplicated,
  except the first half even had some more copy-paste errors, referring to
  listcomps and genexps instead of setcomps)
................
  r56256 | thomas.wouters | 2007-07-11 15:16:01 +0300 (Wed, 11 Jul 2007) | 14 lines


  Dict comprehensions. Still needs doc changes (like many python-3000 features
  ;-). It generates bytecode similar to:

  x = {}
  for k, v in (generator here):
    x[k] = v

  except there is no tuple-packing and -unpacking involved. Trivial
  measurement suggests it's significantly faster than dict(generator here) (in
  the order of 2 to 3 times as fast) but I have not done extensive
  measurements.
................
  r56263 | guido.van.rossum | 2007-07-11 15:36:26 +0300 (Wed, 11 Jul 2007) | 3 lines

  Patch 1724999 by Ali Gholami Rudi -- avoid complaints about dict size
  change during iter in destroy call.
................
This commit is contained in:
Guido van Rossum 2007-07-11 13:09:30 +00:00
parent c6a55ee2a5
commit 992d4a3e6e
18 changed files with 280 additions and 384 deletions

View file

@ -101,8 +101,7 @@ The \module{signal} module defines the following functions:
be scheduled at any time). The returned value is then the number of be scheduled at any time). The returned value is then the number of
seconds before any previously set alarm was to have been delivered. seconds before any previously set alarm was to have been delivered.
If \var{time} is zero, no alarm is scheduled, and any scheduled If \var{time} is zero, no alarm is scheduled, and any scheduled
alarm is canceled. The return value is the number of seconds alarm is canceled. If the return value
remaining before a previously scheduled alarm. If the return value
is zero, no alarm is currently scheduled. (See the \UNIX{} man page is zero, no alarm is currently scheduled. (See the \UNIX{} man page
\manpage{alarm}{2}.) \manpage{alarm}{2}.)
Availability: \UNIX. Availability: \UNIX.

View file

@ -113,6 +113,10 @@ A nice selection of exceptions is defined as well:
The server refused our \samp{HELO} message. The server refused our \samp{HELO} message.
\end{excdesc} \end{excdesc}
\begin{excdesc}{SMTPAuthenticationError}
SMTP authentication went wrong. Most probably the server didn't accept
the username/password combination provided.
\end{excdesc}
\begin{seealso} \begin{seealso}
\seerfc{821}{Simple Mail Transfer Protocol}{Protocol definition for \seerfc{821}{Simple Mail Transfer Protocol}{Protocol definition for

View file

@ -36,7 +36,7 @@ class Node:
str = pattern.sub(replacement, str) str = pattern.sub(replacement, str)
# build up the text # build up the text
self.text = split_entry_text(str) self.text = split_entry_text(str)
self.key = split_entry_key(str) self.key = list(split_entry_key(str))
def __eq__(self, other): def __eq__(self, other):
return cmp(self, other) == 0 return cmp(self, other) == 0

View file

@ -108,7 +108,7 @@ subscript: test | [test] ':' [test] [sliceop]
sliceop: ':' [test] sliceop: ':' [test]
exprlist: star_expr (',' star_expr)* [','] exprlist: star_expr (',' star_expr)* [',']
testlist: test (',' test)* [','] testlist: test (',' test)* [',']
dictorsetmaker: ( (test ':' test (',' test ':' test)* [',']) | dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
(test (comp_for | (',' test)* [','])) ) (test (comp_for | (',' test)* [','])) )
classdef: 'class' NAME ['(' [arglist] ')'] ':' suite classdef: 'class' NAME ['(' [arglist] ')'] ':' suite

View file

@ -184,11 +184,11 @@ struct _stmt {
enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8,
SetComp_kind=9, GeneratorExp_kind=10, Yield_kind=11, SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11,
Compare_kind=12, Call_kind=13, Num_kind=14, Str_kind=15, Yield_kind=12, Compare_kind=13, Call_kind=14, Num_kind=15,
Bytes_kind=16, Ellipsis_kind=17, Attribute_kind=18, Str_kind=16, Bytes_kind=17, Ellipsis_kind=18,
Subscript_kind=19, Starred_kind=20, Name_kind=21, Attribute_kind=19, Subscript_kind=20, Starred_kind=21,
List_kind=22, Tuple_kind=23}; Name_kind=22, List_kind=23, Tuple_kind=24};
struct _expr { struct _expr {
enum _expr_kind kind; enum _expr_kind kind;
union { union {
@ -238,6 +238,12 @@ struct _expr {
asdl_seq *generators; asdl_seq *generators;
} SetComp; } SetComp;
struct {
expr_ty key;
expr_ty value;
asdl_seq *generators;
} DictComp;
struct { struct {
expr_ty elt; expr_ty elt;
asdl_seq *generators; asdl_seq *generators;
@ -470,6 +476,9 @@ expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int
#define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4) #define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4)
expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int
col_offset, PyArena *arena); col_offset, PyArena *arena);
#define DictComp(a0, a1, a2, a3, a4, a5) _Py_DictComp(a0, a1, a2, a3, a4, a5)
expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int
lineno, int col_offset, PyArena *arena);
#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4) #define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4)
expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int
col_offset, PyArena *arena); col_offset, PyArena *arena);

View file

@ -72,13 +72,13 @@ class JoinTestCase(unittest.TestCase):
# create and populate primary index # create and populate primary index
priDB = db.DB(self.env) priDB = db.DB(self.env)
priDB.open(self.filename, "primary", db.DB_BTREE, db.DB_CREATE) priDB.open(self.filename, "primary", db.DB_BTREE, db.DB_CREATE)
map(lambda t, priDB=priDB: priDB.put(*t), ProductIndex) [priDB.put(*t) for t in ProductIndex]
# create and populate secondary index # create and populate secondary index
secDB = db.DB(self.env) secDB = db.DB(self.env)
secDB.set_flags(db.DB_DUP | db.DB_DUPSORT) secDB.set_flags(db.DB_DUP | db.DB_DUPSORT)
secDB.open(self.filename, "secondary", db.DB_BTREE, db.DB_CREATE) secDB.open(self.filename, "secondary", db.DB_BTREE, db.DB_CREATE)
map(lambda t, secDB=secDB: secDB.put(*t), ColorIndex) [secDB.put(*t) for t in ColorIndex]
sCursor = None sCursor = None
jCursor = None jCursor = None

View file

@ -1931,7 +1931,7 @@ class BaseWidget(Misc):
k.configure(self, v) k.configure(self, v)
def destroy(self): def destroy(self):
"""Destroy this and all descendants widgets.""" """Destroy this and all descendants widgets."""
for c in self.children.values(): c.destroy() for c in list(self.children.values()): c.destroy()
self.tk.call('destroy', self._w) self.tk.call('destroy', self._w)
if self._name in self.master.children: if self._name in self.master.children:
del self.master.children[self._name] del self.master.children[self._name]

View file

@ -280,7 +280,7 @@ def _mk_bitmap(bits):
# To represent a big charset, first a bitmap of all characters in the # To represent a big charset, first a bitmap of all characters in the
# set is constructed. Then, this bitmap is sliced into chunks of 256 # set is constructed. Then, this bitmap is sliced into chunks of 256
# characters, duplicate chunks are eliminitated, and each chunk is # characters, duplicate chunks are eliminated, and each chunk is
# given a number. In the compiled expression, the charset is # given a number. In the compiled expression, the charset is
# represented by a 16-bit word sequence, consisting of one word for # represented by a 16-bit word sequence, consisting of one word for
# the number of different chunks, a sequence of 256 bytes (128 words) # the number of different chunks, a sequence of 256 bytes (128 words)

View file

@ -129,308 +129,6 @@ We also repeat each of the above scoping tests inside a function
""" """
__test__ = {'doctests' : doctests}
def test_main(verbose=None):
import sys
from test import test_support
from test import test_listcomps
test_support.run_doctest(test_listcomps, verbose)
# verify reference counting
if verbose and hasattr(sys, "gettotalrefcount"):
import gc
counts = [None] * 5
for i in range(len(counts)):
test_support.run_doctest(test_genexps, verbose)
gc.collect()
counts[i] = sys.gettotalrefcount()
print(counts)
if __name__ == "__main__":
test_main(verbose=True)
doctests = """
########### Tests mostly copied from test_listcomps.py ############
Test simple loop with conditional
>>> sum({i*i for i in range(100) if i&1 == 1})
166650
Test simple case
>>> {2*y + x + 1 for x in (0,) for y in (1,)}
{3}
Test simple nesting
>>> list(sorted({(i,j) for i in range(3) for j in range(4)}))
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
Test nesting with the inner expression dependent on the outer
>>> list(sorted({(i,j) for i in range(4) for j in range(i)}))
[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
Make sure the induction variable is not exposed
>>> i = 20
>>> sum({i*i for i in range(100)})
328350
>>> i
20
Verify that syntax error's are raised for setcomps used as lvalues
>>> {y for y in (1,2)} = 10 # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SyntaxError: ...
>>> {y for y in (1,2)} += 10 # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SyntaxError: ...
Make a nested set comprehension that acts like set(range())
>>> def srange(n):
... return {i for i in range(n)}
>>> list(sorted(srange(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Same again, only as a lambda expression instead of a function definition
>>> lrange = lambda n: {i for i in range(n)}
>>> list(sorted(lrange(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Generators can call other generators:
>>> def grange(n):
... for x in {i for i in range(n)}:
... yield x
>>> list(sorted(grange(5)))
[0, 1, 2, 3, 4]
Make sure that None is a valid return value
>>> {None for i in range(10)}
{None}
########### Tests for various scoping corner cases ############
Return lambdas that use the iteration variable as a default argument
>>> items = {(lambda i=i: i) for i in range(5)}
>>> {x() for x in items} == set(range(5))
True
Same again, only this time as a closure variable
>>> items = {(lambda: i) for i in range(5)}
>>> {x() for x in items}
{4}
Another way to test that the iteration variable is local to the list comp
>>> items = {(lambda: i) for i in range(5)}
>>> i = 20
>>> {x() for x in items}
{4}
And confirm that a closure can jump over the list comp scope
>>> items = {(lambda: y) for i in range(5)}
>>> y = 2
>>> {x() for x in items}
{2}
We also repeat each of the above scoping tests inside a function
>>> def test_func():
... items = {(lambda i=i: i) for i in range(5)}
... return {x() for x in items}
>>> test_func() == set(range(5))
True
>>> def test_func():
... items = {(lambda: i) for i in range(5)}
... return {x() for x in items}
>>> test_func()
{4}
>>> def test_func():
... items = {(lambda: i) for i in range(5)}
... i = 20
... return {x() for x in items}
>>> test_func()
{4}
>>> def test_func():
... items = {(lambda: y) for i in range(5)}
... y = 2
... return {x() for x in items}
>>> test_func()
{2}
"""
__test__ = {'doctests' : doctests}
def test_main(verbose=None):
import sys
from test import test_support
from test import test_listcomps
test_support.run_doctest(test_listcomps, verbose)
# verify reference counting
if verbose and hasattr(sys, "gettotalrefcount"):
import gc
counts = [None] * 5
for i in range(len(counts)):
test_support.run_doctest(test_genexps, verbose)
gc.collect()
counts[i] = sys.gettotalrefcount()
print(counts)
if __name__ == "__main__":
test_main(verbose=True)
doctests = """
########### Tests mostly copied from test_listcomps.py ############
Test simple loop with conditional
>>> sum({i*i for i in range(100) if i&1 == 1})
166650
Test simple case
>>> {2*y + x + 1 for x in (0,) for y in (1,)}
{3}
Test simple nesting
>>> list(sorted({(i,j) for i in range(3) for j in range(4)}))
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
Test nesting with the inner expression dependent on the outer
>>> list(sorted({(i,j) for i in range(4) for j in range(i)}))
[(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
Make sure the induction variable is not exposed
>>> i = 20
>>> sum({i*i for i in range(100)})
328350
>>> i
20
Verify that syntax error's are raised for setcomps used as lvalues
>>> {y for y in (1,2)} = 10 # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SyntaxError: ...
>>> {y for y in (1,2)} += 10 # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SyntaxError: ...
Make a nested set comprehension that acts like set(range())
>>> def srange(n):
... return {i for i in range(n)}
>>> list(sorted(srange(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Same again, only as a lambda expression instead of a function definition
>>> lrange = lambda n: {i for i in range(n)}
>>> list(sorted(lrange(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Generators can call other generators:
>>> def grange(n):
... for x in {i for i in range(n)}:
... yield x
>>> list(sorted(grange(5)))
[0, 1, 2, 3, 4]
Make sure that None is a valid return value
>>> {None for i in range(10)}
{None}
########### Tests for various scoping corner cases ############
Return lambdas that use the iteration variable as a default argument
>>> items = {(lambda i=i: i) for i in range(5)}
>>> {x() for x in items} == set(range(5))
True
Same again, only this time as a closure variable
>>> items = {(lambda: i) for i in range(5)}
>>> {x() for x in items}
{4}
Another way to test that the iteration variable is local to the list comp
>>> items = {(lambda: i) for i in range(5)}
>>> i = 20
>>> {x() for x in items}
{4}
And confirm that a closure can jump over the list comp scope
>>> items = {(lambda: y) for i in range(5)}
>>> y = 2
>>> {x() for x in items}
{2}
We also repeat each of the above scoping tests inside a function
>>> def test_func():
... items = {(lambda i=i: i) for i in range(5)}
... return {x() for x in items}
>>> test_func() == set(range(5))
True
>>> def test_func():
... items = {(lambda: i) for i in range(5)}
... return {x() for x in items}
>>> test_func()
{4}
>>> def test_func():
... items = {(lambda: i) for i in range(5)}
... i = 20
... return {x() for x in items}
>>> test_func()
{4}
>>> def test_func():
... items = {(lambda: y) for i in range(5)}
... y = 2
... return {x() for x in items}
>>> test_func()
{2}
"""
__test__ = {'doctests' : doctests} __test__ = {'doctests' : doctests}
def test_main(verbose=None): def test_main(verbose=None):

View file

@ -1,5 +1,6 @@
#! /usr/bin/env python #! /usr/bin/env python
"""Interfaces for launching and remotely controlling Web browsers.""" """Interfaces for launching and remotely controlling Web browsers."""
# Maintained by Georg Brandl.
import os import os
import shlex import shlex
@ -160,6 +161,7 @@ class GenericBrowser(BaseBrowser):
def __init__(self, name): def __init__(self, name):
if isinstance(name, basestring): if isinstance(name, basestring):
self.name = name self.name = name
self.args = ["%s"]
else: else:
# name should be a list with arguments # name should be a list with arguments
self.name = name[0] self.name = name[0]

View file

@ -1255,6 +1255,12 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
/* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */ /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */
int flags = TCL_EVAL_DIRECT; int flags = TCL_EVAL_DIRECT;
/* If args is a single tuple, replace with contents of tuple */
if (1 == PyTuple_Size(args)){
PyObject* item = PyTuple_GetItem(args, 0);
if (PyTuple_Check(item))
args = item;
}
#ifdef WITH_THREAD #ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
/* We cannot call the command directly. Instead, we must /* We cannot call the command directly. Instead, we must

View file

@ -15,3 +15,14 @@ if "%1"=="-r" (set build=/rebuild) & shift & goto CheckOpts
set cmd=devenv pcbuild.sln %build% "%conf%|%platf%" set cmd=devenv pcbuild.sln %build% "%conf%|%platf%"
echo %cmd% echo %cmd%
%cmd% %cmd%
rem Copy whatever was built to the canonical 'PCBuild' directory.
rem This helps extensions which use distutils etc.
rem (Don't check if the build was successful - we expect a few failures
rem due to missing libs)
echo Copying built files to ..\PCBuild
if not exist %platf%%conf%\. (echo %platf%%conf% does not exist - nothing copied & goto xit)
if not exist ..\PCBuild\. (echo ..\PCBuild does not exist - nothing copied & goto xit)
xcopy /q/y %platf%%conf%\* ..\PCBuild\.
:xit

View file

@ -57,7 +57,8 @@ module Python version "$Revision$"
| Dict(expr* keys, expr* values) | Dict(expr* keys, expr* values)
| Set(expr* elts) | Set(expr* elts)
| ListComp(expr elt, comprehension* generators) | ListComp(expr elt, comprehension* generators)
| SetComp(expr elt, comprehension* generators) | SetComp(expr elt, comprehension* generators)
| DictComp(expr key, expr value, comprehension* generators)
| GeneratorExp(expr elt, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators)
-- the grammar constrains where yield expressions can occur -- the grammar constrains where yield expressions can occur
| Yield(expr? value) | Yield(expr? value)

View file

@ -198,6 +198,12 @@ static char *SetComp_fields[]={
"elt", "elt",
"generators", "generators",
}; };
static PyTypeObject *DictComp_type;
static char *DictComp_fields[]={
"key",
"value",
"generators",
};
static PyTypeObject *GeneratorExp_type; static PyTypeObject *GeneratorExp_type;
static char *GeneratorExp_fields[]={ static char *GeneratorExp_fields[]={
"elt", "elt",
@ -551,6 +557,8 @@ static int init_types(void)
if (!ListComp_type) return 0; if (!ListComp_type) return 0;
SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2);
if (!SetComp_type) return 0; if (!SetComp_type) return 0;
DictComp_type = make_type("DictComp", expr_type, DictComp_fields, 3);
if (!DictComp_type) return 0;
GeneratorExp_type = make_type("GeneratorExp", expr_type, GeneratorExp_type = make_type("GeneratorExp", expr_type,
GeneratorExp_fields, 2); GeneratorExp_fields, 2);
if (!GeneratorExp_type) return 0; if (!GeneratorExp_type) return 0;
@ -1444,6 +1452,33 @@ SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena
return p; return p;
} }
expr_ty
DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int lineno, int
col_offset, PyArena *arena)
{
expr_ty p;
if (!key) {
PyErr_SetString(PyExc_ValueError,
"field key is required for DictComp");
return NULL;
}
if (!value) {
PyErr_SetString(PyExc_ValueError,
"field value is required for DictComp");
return NULL;
}
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p)
return NULL;
p->kind = DictComp_kind;
p->v.DictComp.key = key;
p->v.DictComp.value = value;
p->v.DictComp.generators = generators;
p->lineno = lineno;
p->col_offset = col_offset;
return p;
}
expr_ty expr_ty
GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset,
PyArena *arena) PyArena *arena)
@ -2479,6 +2514,26 @@ ast2obj_expr(void* _o)
goto failed; goto failed;
Py_DECREF(value); Py_DECREF(value);
break; break;
case DictComp_kind:
result = PyType_GenericNew(DictComp_type, NULL, NULL);
if (!result) goto failed;
value = ast2obj_expr(o->v.DictComp.key);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "key", value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_expr(o->v.DictComp.value);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "value", value) == -1)
goto failed;
Py_DECREF(value);
value = ast2obj_list(o->v.DictComp.generators,
ast2obj_comprehension);
if (!value) goto failed;
if (PyObject_SetAttrString(result, "generators", value) == -1)
goto failed;
Py_DECREF(value);
break;
case GeneratorExp_kind: case GeneratorExp_kind:
result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); result = PyType_GenericNew(GeneratorExp_type, NULL, NULL);
if (!result) goto failed; if (!result) goto failed;
@ -3186,6 +3241,8 @@ init_ast(void)
return; return;
if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0)
return; return;
if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0)
return;
if (PyDict_SetItemString(d, "GeneratorExp", if (PyDict_SetItemString(d, "GeneratorExp",
(PyObject*)GeneratorExp_type) < 0) return; (PyObject*)GeneratorExp_type) < 0) return;
if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return; if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return;

View file

@ -426,6 +426,9 @@ set_context(expr_ty e, expr_context_ty ctx, const node *n)
case SetComp_kind: case SetComp_kind:
expr_name = "set comprehension"; expr_name = "set comprehension";
break; break;
case DictComp_kind:
expr_name = "dict comprehension";
break;
case Dict_kind: case Dict_kind:
case Set_kind: case Set_kind:
case Num_kind: case Num_kind:
@ -1047,23 +1050,22 @@ static int
count_comp_fors(const node *n) count_comp_fors(const node *n)
{ {
int n_fors = 0; int n_fors = 0;
node *ch = CHILD(n, 1);
count_comp_for: count_comp_for:
n_fors++; n_fors++;
REQ(ch, comp_for); REQ(n, comp_for);
if (NCH(ch) == 5) if (NCH(n) == 5)
ch = CHILD(ch, 4); n = CHILD(n, 4);
else else
return n_fors; return n_fors;
count_comp_iter: count_comp_iter:
REQ(ch, comp_iter); REQ(n, comp_iter);
ch = CHILD(ch, 0); n = CHILD(n, 0);
if (TYPE(ch) == comp_for) if (TYPE(n) == comp_for)
goto count_comp_for; goto count_comp_for;
else if (TYPE(ch) == comp_if) { else if (TYPE(n) == comp_if) {
if (NCH(ch) == 3) { if (NCH(n) == 3) {
ch = CHILD(ch, 2); n = CHILD(n, 2);
goto count_comp_iter; goto count_comp_iter;
} }
else else
@ -1099,21 +1101,11 @@ count_comp_ifs(const node *n)
} }
} }
static expr_ty static asdl_seq *
ast_for_comprehension(struct compiling *c, const node *n, int type) ast_for_comprehension(struct compiling *c, const node *n)
{ {
/* testlist_comp: test ( comp_for | (',' test)* [','] )
argument: [test '='] test [comp_for] # Really [keyword '='] test */
expr_ty elt;
asdl_seq *comps;
int i, n_fors; int i, n_fors;
node *ch; asdl_seq *comps;
assert(NCH(n) > 1);
elt = ast_for_expr(c, CHILD(n, 0));
if (!elt)
return NULL;
n_fors = count_comp_fors(n); n_fors = count_comp_fors(n);
if (n_fors == -1) if (n_fors == -1)
@ -1123,20 +1115,19 @@ ast_for_comprehension(struct compiling *c, const node *n, int type)
if (!comps) if (!comps)
return NULL; return NULL;
ch = CHILD(n, 1);
for (i = 0; i < n_fors; i++) { for (i = 0; i < n_fors; i++) {
comprehension_ty comp; comprehension_ty comp;
asdl_seq *t; asdl_seq *t;
expr_ty expression; expr_ty expression;
node *for_ch; node *for_ch;
REQ(ch, comp_for); REQ(n, comp_for);
for_ch = CHILD(ch, 1); for_ch = CHILD(n, 1);
t = ast_for_exprlist(c, for_ch, Store); t = ast_for_exprlist(c, for_ch, Store);
if (!t) if (!t)
return NULL; return NULL;
expression = ast_for_expr(c, CHILD(ch, 3)); expression = ast_for_expr(c, CHILD(n, 3));
if (!expression) if (!expression)
return NULL; return NULL;
@ -1146,19 +1137,19 @@ ast_for_comprehension(struct compiling *c, const node *n, int type)
comp = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, comp = comprehension((expr_ty)asdl_seq_GET(t, 0), expression,
NULL, c->c_arena); NULL, c->c_arena);
else else
comp = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, comp = comprehension(Tuple(t, Store, LINENO(n), n->n_col_offset,
c->c_arena), c->c_arena),
expression, NULL, c->c_arena); expression, NULL, c->c_arena);
if (!comp) if (!comp)
return NULL; return NULL;
if (NCH(ch) == 5) { if (NCH(n) == 5) {
int j, n_ifs; int j, n_ifs;
asdl_seq *ifs; asdl_seq *ifs;
ch = CHILD(ch, 4); n = CHILD(n, 4);
n_ifs = count_comp_ifs(ch); n_ifs = count_comp_ifs(n);
if (n_ifs == -1) if (n_ifs == -1)
return NULL; return NULL;
@ -1167,24 +1158,44 @@ ast_for_comprehension(struct compiling *c, const node *n, int type)
return NULL; return NULL;
for (j = 0; j < n_ifs; j++) { for (j = 0; j < n_ifs; j++) {
REQ(ch, comp_iter); REQ(n, comp_iter);
ch = CHILD(ch, 0); n = CHILD(n, 0);
REQ(ch, comp_if); REQ(n, comp_if);
expression = ast_for_expr(c, CHILD(ch, 1)); expression = ast_for_expr(c, CHILD(n, 1));
if (!expression) if (!expression)
return NULL; return NULL;
asdl_seq_SET(ifs, j, expression); asdl_seq_SET(ifs, j, expression);
if (NCH(ch) == 3) if (NCH(n) == 3)
ch = CHILD(ch, 2); n = CHILD(n, 2);
} }
/* on exit, must guarantee that ch is a comp_for */ /* on exit, must guarantee that n is a comp_for */
if (TYPE(ch) == comp_iter) if (TYPE(n) == comp_iter)
ch = CHILD(ch, 0); n = CHILD(n, 0);
comp->ifs = ifs; comp->ifs = ifs;
} }
asdl_seq_SET(comps, i, comp); asdl_seq_SET(comps, i, comp);
} }
return comps;
}
static expr_ty
ast_for_itercomp(struct compiling *c, const node *n, int type)
{
/* testlist_comp: test ( comp_for | (',' test)* [','] )
argument: [test '='] test [comp_for] # Really [keyword '='] test */
expr_ty elt;
asdl_seq *comps;
assert(NCH(n) > 1);
elt = ast_for_expr(c, CHILD(n, 0));
if (!elt)
return NULL;
comps = ast_for_comprehension(c, CHILD(n, 1));
if (!comps)
return NULL;
if (type == COMP_GENEXP) if (type == COMP_GENEXP)
return GeneratorExp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena); return GeneratorExp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena);
@ -1197,25 +1208,49 @@ ast_for_comprehension(struct compiling *c, const node *n, int type)
return NULL; return NULL;
} }
static expr_ty
ast_for_dictcomp(struct compiling *c, const node *n)
{
expr_ty key, value;
asdl_seq *comps;
assert(NCH(n) > 3);
REQ(CHILD(n, 1), COLON);
key = ast_for_expr(c, CHILD(n, 0));
if (!key)
return NULL;
value = ast_for_expr(c, CHILD(n, 2));
if (!value)
return NULL;
comps = ast_for_comprehension(c, CHILD(n, 3));
if (!comps)
return NULL;
return DictComp(key, value, comps, LINENO(n), n->n_col_offset, c->c_arena);
}
static expr_ty static expr_ty
ast_for_genexp(struct compiling *c, const node *n) ast_for_genexp(struct compiling *c, const node *n)
{ {
assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument)); assert(TYPE(n) == (testlist_comp) || TYPE(n) == (argument));
return ast_for_comprehension(c, n, COMP_GENEXP); return ast_for_itercomp(c, n, COMP_GENEXP);
} }
static expr_ty static expr_ty
ast_for_listcomp(struct compiling *c, const node *n) ast_for_listcomp(struct compiling *c, const node *n)
{ {
assert(TYPE(n) == (testlist_comp)); assert(TYPE(n) == (testlist_comp));
return ast_for_comprehension(c, n, COMP_LISTCOMP); return ast_for_itercomp(c, n, COMP_LISTCOMP);
} }
static expr_ty static expr_ty
ast_for_setcomp(struct compiling *c, const node *n) ast_for_setcomp(struct compiling *c, const node *n)
{ {
assert(TYPE(n) == (dictorsetmaker)); assert(TYPE(n) == (dictorsetmaker));
return ast_for_comprehension(c, n, COMP_SETCOMP); return ast_for_itercomp(c, n, COMP_SETCOMP);
} }
@ -1313,6 +1348,8 @@ ast_for_atom(struct compiling *c, const node *n)
} else if (TYPE(CHILD(ch, 1)) == comp_for) { } else if (TYPE(CHILD(ch, 1)) == comp_for) {
/* it's a set comprehension */ /* it's a set comprehension */
return ast_for_setcomp(c, ch); return ast_for_setcomp(c, ch);
} else if (NCH(ch) > 3 && TYPE(CHILD(ch, 3)) == comp_for) {
return ast_for_dictcomp(c, ch);
} else { } else {
/* it's a dict */ /* it's a dict */
size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */

View file

@ -42,6 +42,7 @@ int Py_OptimizeFlag = 0;
#define COMP_GENEXP 0 #define COMP_GENEXP 0
#define COMP_LISTCOMP 1 #define COMP_LISTCOMP 1
#define COMP_SETCOMP 2 #define COMP_SETCOMP 2
#define COMP_DICTCOMP 3
struct instr { struct instr {
unsigned i_jabs : 1; unsigned i_jabs : 1;
@ -2753,7 +2754,7 @@ compiler_call_helper(struct compiler *c,
static int static int
compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
asdl_seq *generators, int gen_index, asdl_seq *generators, int gen_index,
expr_ty elt, int type) expr_ty elt, expr_ty val, int type)
{ {
/* generate code for the iterator, then each of the ifs, /* generate code for the iterator, then each of the ifs,
and then write to the element */ and then write to the element */
@ -2801,7 +2802,7 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
if (++gen_index < asdl_seq_LEN(generators)) if (++gen_index < asdl_seq_LEN(generators))
if (!compiler_comprehension_generator(c, tmpname, if (!compiler_comprehension_generator(c, tmpname,
generators, gen_index, generators, gen_index,
elt, type)) elt, val, type))
return 0; return 0;
/* only append after the last for generator */ /* only append after the last for generator */
@ -2825,6 +2826,17 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
VISIT(c, expr, elt); VISIT(c, expr, elt);
ADDOP(c, SET_ADD); ADDOP(c, SET_ADD);
break; break;
case COMP_DICTCOMP:
if (!compiler_nameop(c, tmpname, Load))
return 0;
/* With 'd[k] = v', v is evaluated before k, so we do
the same. STORE_SUBSCR requires (item, map, key),
so we still end up ROTing once. */
VISIT(c, expr, val);
ADDOP(c, ROT_TWO);
VISIT(c, expr, elt);
ADDOP(c, STORE_SUBSCR);
break;
default: default:
return 0; return 0;
} }
@ -2846,7 +2858,7 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname,
static int static int
compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
asdl_seq *generators, expr_ty elt) asdl_seq *generators, expr_ty elt, expr_ty val)
{ {
PyCodeObject *co = NULL; PyCodeObject *co = NULL;
identifier tmp = NULL; identifier tmp = NULL;
@ -2859,18 +2871,34 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
goto error; goto error;
if (type != COMP_GENEXP) { if (type != COMP_GENEXP) {
int op;
tmp = compiler_new_tmpname(c); tmp = compiler_new_tmpname(c);
if (!tmp) if (!tmp)
goto error_in_scope; goto error_in_scope;
switch (type) {
case COMP_LISTCOMP:
op = BUILD_LIST;
break;
case COMP_SETCOMP:
op = BUILD_SET;
break;
case COMP_DICTCOMP:
op = BUILD_MAP;
break;
default:
PyErr_Format(PyExc_SystemError,
"unknown comprehension type %d", type);
goto error_in_scope;
}
ADDOP_I(c, (type == COMP_LISTCOMP ? ADDOP_I(c, op, 0);
BUILD_LIST : BUILD_SET), 0);
ADDOP(c, DUP_TOP); ADDOP(c, DUP_TOP);
if (!compiler_nameop(c, tmp, Store)) if (!compiler_nameop(c, tmp, Store))
goto error_in_scope; goto error_in_scope;
} }
if (!compiler_comprehension_generator(c, tmp, generators, 0, elt, type)) if (!compiler_comprehension_generator(c, tmp, generators, 0, elt,
val, type))
goto error_in_scope; goto error_in_scope;
if (type != COMP_GENEXP) { if (type != COMP_GENEXP) {
@ -2911,7 +2939,7 @@ compiler_genexp(struct compiler *c, expr_ty e)
assert(e->kind == GeneratorExp_kind); assert(e->kind == GeneratorExp_kind);
return compiler_comprehension(c, e, COMP_GENEXP, name, return compiler_comprehension(c, e, COMP_GENEXP, name,
e->v.GeneratorExp.generators, e->v.GeneratorExp.generators,
e->v.GeneratorExp.elt); e->v.GeneratorExp.elt, NULL);
} }
static int static int
@ -2926,7 +2954,7 @@ compiler_listcomp(struct compiler *c, expr_ty e)
assert(e->kind == ListComp_kind); assert(e->kind == ListComp_kind);
return compiler_comprehension(c, e, COMP_LISTCOMP, name, return compiler_comprehension(c, e, COMP_LISTCOMP, name,
e->v.ListComp.generators, e->v.ListComp.generators,
e->v.ListComp.elt); e->v.ListComp.elt, NULL);
} }
static int static int
@ -2941,7 +2969,23 @@ compiler_setcomp(struct compiler *c, expr_ty e)
assert(e->kind == SetComp_kind); assert(e->kind == SetComp_kind);
return compiler_comprehension(c, e, COMP_SETCOMP, name, return compiler_comprehension(c, e, COMP_SETCOMP, name,
e->v.SetComp.generators, e->v.SetComp.generators,
e->v.SetComp.elt); e->v.SetComp.elt, NULL);
}
static int
compiler_dictcomp(struct compiler *c, expr_ty e)
{
static identifier name;
if (!name) {
name = PyString_FromString("<dictcomp>");
if (!name)
return 0;
}
assert(e->kind == DictComp_kind);
return compiler_comprehension(c, e, COMP_DICTCOMP, name,
e->v.DictComp.generators,
e->v.DictComp.key, e->v.DictComp.value);
} }
@ -3173,6 +3217,8 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
return compiler_listcomp(c, e); return compiler_listcomp(c, e);
case SetComp_kind: case SetComp_kind:
return compiler_setcomp(c, e); return compiler_setcomp(c, e);
case DictComp_kind:
return compiler_dictcomp(c, e);
case Yield_kind: case Yield_kind:
if (c->u->u_ste->ste_type != FunctionBlock) if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'yield' outside function"); return compiler_error(c, "'yield' outside function");

View file

@ -1505,7 +1505,8 @@ static arc arcs_71_4[2] = {
{24, 6}, {24, 6},
{0, 4}, {0, 4},
}; };
static arc arcs_71_5[2] = { static arc arcs_71_5[3] = {
{156, 3},
{30, 7}, {30, 7},
{0, 5}, {0, 5},
}; };
@ -1518,18 +1519,27 @@ static arc arcs_71_7[2] = {
{0, 7}, {0, 7},
}; };
static arc arcs_71_8[1] = { static arc arcs_71_8[1] = {
{25, 2}, {25, 9},
}; };
static state states_71[9] = { static arc arcs_71_9[1] = {
{24, 10},
};
static arc arcs_71_10[2] = {
{30, 7},
{0, 10},
};
static state states_71[11] = {
{1, arcs_71_0}, {1, arcs_71_0},
{4, arcs_71_1}, {4, arcs_71_1},
{1, arcs_71_2}, {1, arcs_71_2},
{1, arcs_71_3}, {1, arcs_71_3},
{2, arcs_71_4}, {2, arcs_71_4},
{2, arcs_71_5}, {3, arcs_71_5},
{2, arcs_71_6}, {2, arcs_71_6},
{2, arcs_71_7}, {2, arcs_71_7},
{1, arcs_71_8}, {1, arcs_71_8},
{1, arcs_71_9},
{2, arcs_71_10},
}; };
static arc arcs_72_0[1] = { static arc arcs_72_0[1] = {
{160, 1}, {160, 1},
@ -1864,7 +1874,7 @@ static dfa dfas[81] = {
"\000\040\040\200\000\000\000\000\000\040\000\000\000\000\000\000\200\041\224\017\000"}, "\000\040\040\200\000\000\000\000\000\040\000\000\000\000\000\000\200\041\224\017\000"},
{326, "testlist", 0, 3, states_70, {326, "testlist", 0, 3, states_70,
"\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"}, "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"},
{327, "dictorsetmaker", 0, 9, states_71, {327, "dictorsetmaker", 0, 11, states_71,
"\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"}, "\000\040\040\200\000\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"},
{328, "classdef", 0, 8, states_72, {328, "classdef", 0, 8, states_72,
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"}, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"},

View file

@ -170,6 +170,7 @@ static int symtable_visit_expr(struct symtable *st, expr_ty s);
static int symtable_visit_genexp(struct symtable *st, expr_ty s); static int symtable_visit_genexp(struct symtable *st, expr_ty s);
static int symtable_visit_listcomp(struct symtable *st, expr_ty s); static int symtable_visit_listcomp(struct symtable *st, expr_ty s);
static int symtable_visit_setcomp(struct symtable *st, expr_ty s); static int symtable_visit_setcomp(struct symtable *st, expr_ty s);
static int symtable_visit_dictcomp(struct symtable *st, expr_ty s);
static int symtable_visit_arguments(struct symtable *st, arguments_ty); static int symtable_visit_arguments(struct symtable *st, arguments_ty);
static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty); static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty);
static int symtable_visit_alias(struct symtable *st, alias_ty); static int symtable_visit_alias(struct symtable *st, alias_ty);
@ -183,7 +184,7 @@ static int symtable_visit_annotations(struct symtable *st, stmt_ty s);
static identifier top = NULL, lambda = NULL, genexpr = NULL, static identifier top = NULL, lambda = NULL, genexpr = NULL,
listcomp = NULL, setcomp = NULL, __class__ = NULL; listcomp = NULL, setcomp = NULL, dictcomp = NULL, __class__ = NULL;
#define GET_IDENTIFIER(VAR) \ #define GET_IDENTIFIER(VAR) \
((VAR) ? (VAR) : ((VAR) = PyUnicode_InternFromString(# VAR))) ((VAR) ? (VAR) : ((VAR) = PyUnicode_InternFromString(# VAR)))
@ -1270,6 +1271,10 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
if (!symtable_visit_setcomp(st, e)) if (!symtable_visit_setcomp(st, e))
return 0; return 0;
break; break;
case DictComp_kind:
if (!symtable_visit_dictcomp(st, e))
return 0;
break;
case Yield_kind: case Yield_kind:
if (e->v.Yield.value) if (e->v.Yield.value)
VISIT(st, expr, e->v.Yield.value); VISIT(st, expr, e->v.Yield.value);
@ -1521,8 +1526,8 @@ symtable_visit_slice(struct symtable *st, slice_ty s)
static int static int
symtable_handle_comprehension(struct symtable *st, expr_ty e, symtable_handle_comprehension(struct symtable *st, expr_ty e,
identifier scope_name, identifier scope_name, asdl_seq *generators,
asdl_seq *generators, expr_ty elt) expr_ty elt, expr_ty value)
{ {
int is_generator = (e->kind == GeneratorExp_kind); int is_generator = (e->kind == GeneratorExp_kind);
int needs_tmp = !is_generator; int needs_tmp = !is_generator;
@ -1550,6 +1555,8 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e); VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e);
VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension, VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension,
generators, 1, (void*)e); generators, 1, (void*)e);
if (value)
VISIT_IN_BLOCK(st, expr, value, (void*)e);
VISIT_IN_BLOCK(st, expr, elt, (void*)e); VISIT_IN_BLOCK(st, expr, elt, (void*)e);
return symtable_exit_block(st, (void *)e); return symtable_exit_block(st, (void *)e);
} }
@ -1559,7 +1566,7 @@ symtable_visit_genexp(struct symtable *st, expr_ty e)
{ {
return symtable_handle_comprehension(st, e, GET_IDENTIFIER(genexpr), return symtable_handle_comprehension(st, e, GET_IDENTIFIER(genexpr),
e->v.GeneratorExp.generators, e->v.GeneratorExp.generators,
e->v.GeneratorExp.elt); e->v.GeneratorExp.elt, NULL);
} }
static int static int
@ -1567,7 +1574,7 @@ symtable_visit_listcomp(struct symtable *st, expr_ty e)
{ {
return symtable_handle_comprehension(st, e, GET_IDENTIFIER(listcomp), return symtable_handle_comprehension(st, e, GET_IDENTIFIER(listcomp),
e->v.ListComp.generators, e->v.ListComp.generators,
e->v.ListComp.elt); e->v.ListComp.elt, NULL);
} }
static int static int
@ -1575,5 +1582,14 @@ symtable_visit_setcomp(struct symtable *st, expr_ty e)
{ {
return symtable_handle_comprehension(st, e, GET_IDENTIFIER(setcomp), return symtable_handle_comprehension(st, e, GET_IDENTIFIER(setcomp),
e->v.SetComp.generators, e->v.SetComp.generators,
e->v.SetComp.elt); e->v.SetComp.elt, NULL);
}
static int
symtable_visit_dictcomp(struct symtable *st, expr_ty e)
{
return symtable_handle_comprehension(st, e, GET_IDENTIFIER(dictcomp),
e->v.DictComp.generators,
e->v.DictComp.key,
e->v.DictComp.value);
} }