From 992d4a3e6e67a05b85350820157028a61d1f22cf Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 11 Jul 2007 13:09:30 +0000 Subject: 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. ................ --- Doc/lib/libsignal.tex | 3 +- Doc/lib/libsmtplib.tex | 4 + Doc/tools/buildindex.py | 8 +- Grammar/Grammar | 2 +- Include/Python-ast.h | 19 ++- Lib/bsddb/test/test_join.py | 4 +- Lib/lib-tk/Tkinter.py | 2 +- Lib/sre_compile.py | 2 +- Lib/test/test_setcomps.py | 302 -------------------------------------------- Lib/webbrowser.py | 2 + Modules/_tkinter.c | 6 + PCbuild8/build.bat | 13 +- Parser/Python.asdl | 3 +- Python/Python-ast.c | 57 +++++++++ Python/ast.c | 125 +++++++++++------- Python/compile.c | 64 ++++++++-- Python/graminit.c | 20 ++- Python/symtable.c | 28 +++- 18 files changed, 280 insertions(+), 384 deletions(-) diff --git a/Doc/lib/libsignal.tex b/Doc/lib/libsignal.tex index cfdb4dd..e98aa90 100644 --- a/Doc/lib/libsignal.tex +++ b/Doc/lib/libsignal.tex @@ -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 seconds before any previously set alarm was to have been delivered. If \var{time} is zero, no alarm is scheduled, and any scheduled - alarm is canceled. The return value is the number of seconds - remaining before a previously scheduled alarm. If the return value + alarm is canceled. If the return value is zero, no alarm is currently scheduled. (See the \UNIX{} man page \manpage{alarm}{2}.) Availability: \UNIX. diff --git a/Doc/lib/libsmtplib.tex b/Doc/lib/libsmtplib.tex index 1c034e7..7786102 100644 --- a/Doc/lib/libsmtplib.tex +++ b/Doc/lib/libsmtplib.tex @@ -113,6 +113,10 @@ A nice selection of exceptions is defined as well: The server refused our \samp{HELO} message. \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} \seerfc{821}{Simple Mail Transfer Protocol}{Protocol definition for diff --git a/Doc/tools/buildindex.py b/Doc/tools/buildindex.py index 8b24cc5..0e5ba84 100755 --- a/Doc/tools/buildindex.py +++ b/Doc/tools/buildindex.py @@ -36,14 +36,14 @@ class Node: str = pattern.sub(replacement, str) # build up the text self.text = split_entry_text(str) - self.key = split_entry_key(str) - + self.key = list(split_entry_key(str)) + def __eq__(self, other): return cmp(self, other) == 0 - + def __lt__(self, other): return cmp(self, other) == -1 - + def __gt__(self, other): return cmp(self, other) == 1 diff --git a/Grammar/Grammar b/Grammar/Grammar index 5041eb1..17a0148 100644 --- a/Grammar/Grammar +++ b/Grammar/Grammar @@ -108,7 +108,7 @@ subscript: test | [test] ':' [test] [sliceop] sliceop: ':' [test] exprlist: star_expr (',' star_expr)* [','] testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (',' test ':' test)* [',']) | +dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | (test (comp_for | (',' test)* [','])) ) classdef: 'class' NAME ['(' [arglist] ')'] ':' suite diff --git a/Include/Python-ast.h b/Include/Python-ast.h index cc7619d..174a841 100644 --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -184,11 +184,11 @@ struct _stmt { 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, - SetComp_kind=9, GeneratorExp_kind=10, Yield_kind=11, - Compare_kind=12, Call_kind=13, Num_kind=14, Str_kind=15, - Bytes_kind=16, Ellipsis_kind=17, Attribute_kind=18, - Subscript_kind=19, Starred_kind=20, Name_kind=21, - List_kind=22, Tuple_kind=23}; + SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, + Yield_kind=12, Compare_kind=13, Call_kind=14, Num_kind=15, + Str_kind=16, Bytes_kind=17, Ellipsis_kind=18, + Attribute_kind=19, Subscript_kind=20, Starred_kind=21, + Name_kind=22, List_kind=23, Tuple_kind=24}; struct _expr { enum _expr_kind kind; union { @@ -239,6 +239,12 @@ struct _expr { } SetComp; struct { + expr_ty key; + expr_ty value; + asdl_seq *generators; + } DictComp; + + struct { expr_ty elt; asdl_seq *generators; } GeneratorExp; @@ -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) expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int 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) expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena); diff --git a/Lib/bsddb/test/test_join.py b/Lib/bsddb/test/test_join.py index 00e7479..46178b0 100644 --- a/Lib/bsddb/test/test_join.py +++ b/Lib/bsddb/test/test_join.py @@ -72,13 +72,13 @@ class JoinTestCase(unittest.TestCase): # create and populate primary index priDB = db.DB(self.env) 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 secDB = db.DB(self.env) secDB.set_flags(db.DB_DUP | db.DB_DUPSORT) 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 jCursor = None diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py index 1426357..1e4d771 100644 --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -1931,7 +1931,7 @@ class BaseWidget(Misc): k.configure(self, v) def destroy(self): """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) if self._name in self.master.children: del self.master.children[self._name] diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py index 5b66084..3c9035f 100644 --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -280,7 +280,7 @@ def _mk_bitmap(bits): # 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 -# 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 # represented by a 16-bit word sequence, consisting of one word for # the number of different chunks, a sequence of 256 bytes (128 words) diff --git a/Lib/test/test_setcomps.py b/Lib/test/test_setcomps.py index 7b09527..f382293 100644 --- a/Lib/test/test_setcomps.py +++ b/Lib/test/test_setcomps.py @@ -134,308 +134,6 @@ __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} - -def test_main(verbose=None): - import sys - from test import test_support from test import test_setcomps test_support.run_doctest(test_setcomps, verbose) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index dd5e019..d15f59c 100644 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -1,5 +1,6 @@ #! /usr/bin/env python """Interfaces for launching and remotely controlling Web browsers.""" +# Maintained by Georg Brandl. import os import shlex @@ -160,6 +161,7 @@ class GenericBrowser(BaseBrowser): def __init__(self, name): if isinstance(name, basestring): self.name = name + self.args = ["%s"] else: # name should be a list with arguments self.name = name[0] diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 12490b0..b7d637b 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1255,6 +1255,12 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */ 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 if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { /* We cannot call the command directly. Instead, we must diff --git a/PCbuild8/build.bat b/PCbuild8/build.bat index 8c61a70..ba21390 100644 --- a/PCbuild8/build.bat +++ b/PCbuild8/build.bat @@ -14,4 +14,15 @@ if "%1"=="-r" (set build=/rebuild) & shift & goto CheckOpts set cmd=devenv pcbuild.sln %build% "%conf%|%platf%" echo %cmd% -%cmd% \ No newline at end of file +%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 diff --git a/Parser/Python.asdl b/Parser/Python.asdl index f76f5b8..ea9f502 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -57,7 +57,8 @@ module Python version "$Revision$" | Dict(expr* keys, expr* values) | Set(expr* elts) | 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) -- the grammar constrains where yield expressions can occur | Yield(expr? value) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 18c2eb5..d5250a4 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -198,6 +198,12 @@ static char *SetComp_fields[]={ "elt", "generators", }; +static PyTypeObject *DictComp_type; +static char *DictComp_fields[]={ + "key", + "value", + "generators", +}; static PyTypeObject *GeneratorExp_type; static char *GeneratorExp_fields[]={ "elt", @@ -551,6 +557,8 @@ static int init_types(void) if (!ListComp_type) return 0; SetComp_type = make_type("SetComp", expr_type, SetComp_fields, 2); 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_fields, 2); if (!GeneratorExp_type) return 0; @@ -1445,6 +1453,33 @@ SetComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena } 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 GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { @@ -2479,6 +2514,26 @@ ast2obj_expr(void* _o) goto failed; Py_DECREF(value); 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: result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); if (!result) goto failed; @@ -3186,6 +3241,8 @@ init_ast(void) return; if (PyDict_SetItemString(d, "SetComp", (PyObject*)SetComp_type) < 0) return; + if (PyDict_SetItemString(d, "DictComp", (PyObject*)DictComp_type) < 0) + return; if (PyDict_SetItemString(d, "GeneratorExp", (PyObject*)GeneratorExp_type) < 0) return; if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return; diff --git a/Python/ast.c b/Python/ast.c index c611436..23df29f 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -426,6 +426,9 @@ set_context(expr_ty e, expr_context_ty ctx, const node *n) case SetComp_kind: expr_name = "set comprehension"; break; + case DictComp_kind: + expr_name = "dict comprehension"; + break; case Dict_kind: case Set_kind: case Num_kind: @@ -1047,23 +1050,22 @@ static int count_comp_fors(const node *n) { int n_fors = 0; - node *ch = CHILD(n, 1); count_comp_for: n_fors++; - REQ(ch, comp_for); - if (NCH(ch) == 5) - ch = CHILD(ch, 4); + REQ(n, comp_for); + if (NCH(n) == 5) + n = CHILD(n, 4); else return n_fors; count_comp_iter: - REQ(ch, comp_iter); - ch = CHILD(ch, 0); - if (TYPE(ch) == comp_for) + REQ(n, comp_iter); + n = CHILD(n, 0); + if (TYPE(n) == comp_for) goto count_comp_for; - else if (TYPE(ch) == comp_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); + else if (TYPE(n) == comp_if) { + if (NCH(n) == 3) { + n = CHILD(n, 2); goto count_comp_iter; } else @@ -1099,22 +1101,12 @@ count_comp_ifs(const node *n) } } -static expr_ty -ast_for_comprehension(struct compiling *c, const node *n, int type) +static asdl_seq * +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; - node *ch; - - assert(NCH(n) > 1); - - elt = ast_for_expr(c, CHILD(n, 0)); - if (!elt) - return NULL; - + asdl_seq *comps; + n_fors = count_comp_fors(n); if (n_fors == -1) return NULL; @@ -1123,20 +1115,19 @@ ast_for_comprehension(struct compiling *c, const node *n, int type) if (!comps) return NULL; - ch = CHILD(n, 1); for (i = 0; i < n_fors; i++) { comprehension_ty comp; asdl_seq *t; expr_ty expression; 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); if (!t) return NULL; - expression = ast_for_expr(c, CHILD(ch, 3)); + expression = ast_for_expr(c, CHILD(n, 3)); if (!expression) 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, NULL, c->c_arena); 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), expression, NULL, c->c_arena); if (!comp) return NULL; - if (NCH(ch) == 5) { + if (NCH(n) == 5) { int j, n_ifs; asdl_seq *ifs; - ch = CHILD(ch, 4); - n_ifs = count_comp_ifs(ch); + n = CHILD(n, 4); + n_ifs = count_comp_ifs(n); if (n_ifs == -1) return NULL; @@ -1167,24 +1158,44 @@ ast_for_comprehension(struct compiling *c, const node *n, int type) return NULL; for (j = 0; j < n_ifs; j++) { - REQ(ch, comp_iter); - ch = CHILD(ch, 0); - REQ(ch, comp_if); + REQ(n, comp_iter); + n = CHILD(n, 0); + REQ(n, comp_if); - expression = ast_for_expr(c, CHILD(ch, 1)); + expression = ast_for_expr(c, CHILD(n, 1)); if (!expression) return NULL; asdl_seq_SET(ifs, j, expression); - if (NCH(ch) == 3) - ch = CHILD(ch, 2); + if (NCH(n) == 3) + n = CHILD(n, 2); } - /* on exit, must guarantee that ch is a comp_for */ - if (TYPE(ch) == comp_iter) - ch = CHILD(ch, 0); + /* on exit, must guarantee that n is a comp_for */ + if (TYPE(n) == comp_iter) + n = CHILD(n, 0); comp->ifs = ifs; } 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) return GeneratorExp(elt, comps, LINENO(n), n->n_col_offset, c->c_arena); @@ -1198,24 +1209,48 @@ ast_for_comprehension(struct compiling *c, const node *n, int type) } 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 ast_for_genexp(struct compiling *c, const node *n) { 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 ast_for_listcomp(struct compiling *c, const node *n) { assert(TYPE(n) == (testlist_comp)); - return ast_for_comprehension(c, n, COMP_LISTCOMP); + return ast_for_itercomp(c, n, COMP_LISTCOMP); } static expr_ty ast_for_setcomp(struct compiling *c, const node *n) { 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) { /* it's a set comprehension */ return ast_for_setcomp(c, ch); + } else if (NCH(ch) > 3 && TYPE(CHILD(ch, 3)) == comp_for) { + return ast_for_dictcomp(c, ch); } else { /* it's a dict */ size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ diff --git a/Python/compile.c b/Python/compile.c index cbb6b4d..77c6a77 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -42,6 +42,7 @@ int Py_OptimizeFlag = 0; #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 #define COMP_SETCOMP 2 +#define COMP_DICTCOMP 3 struct instr { unsigned i_jabs : 1; @@ -2753,7 +2754,7 @@ compiler_call_helper(struct compiler *c, static int compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, 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, 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 (!compiler_comprehension_generator(c, tmpname, generators, gen_index, - elt, type)) + elt, val, type)) return 0; /* only append after the last for generator */ @@ -2825,6 +2826,17 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, VISIT(c, expr, elt); ADDOP(c, SET_ADD); 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: return 0; } @@ -2846,7 +2858,7 @@ compiler_comprehension_generator(struct compiler *c, PyObject *tmpname, static int 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; identifier tmp = NULL; @@ -2859,18 +2871,34 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, goto error; if (type != COMP_GENEXP) { + int op; tmp = compiler_new_tmpname(c); if (!tmp) 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 ? - BUILD_LIST : BUILD_SET), 0); + ADDOP_I(c, op, 0); ADDOP(c, DUP_TOP); if (!compiler_nameop(c, tmp, Store)) 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; if (type != COMP_GENEXP) { @@ -2911,7 +2939,7 @@ compiler_genexp(struct compiler *c, expr_ty e) assert(e->kind == GeneratorExp_kind); return compiler_comprehension(c, e, COMP_GENEXP, name, e->v.GeneratorExp.generators, - e->v.GeneratorExp.elt); + e->v.GeneratorExp.elt, NULL); } static int @@ -2926,7 +2954,7 @@ compiler_listcomp(struct compiler *c, expr_ty e) assert(e->kind == ListComp_kind); return compiler_comprehension(c, e, COMP_LISTCOMP, name, e->v.ListComp.generators, - e->v.ListComp.elt); + e->v.ListComp.elt, NULL); } static int @@ -2941,7 +2969,23 @@ compiler_setcomp(struct compiler *c, expr_ty e) assert(e->kind == SetComp_kind); return compiler_comprehension(c, e, COMP_SETCOMP, name, 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(""); + 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); case SetComp_kind: return compiler_setcomp(c, e); + case DictComp_kind: + return compiler_dictcomp(c, e); case Yield_kind: if (c->u->u_ste->ste_type != FunctionBlock) return compiler_error(c, "'yield' outside function"); diff --git a/Python/graminit.c b/Python/graminit.c index c1c070b..95905d7 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -1505,7 +1505,8 @@ static arc arcs_71_4[2] = { {24, 6}, {0, 4}, }; -static arc arcs_71_5[2] = { +static arc arcs_71_5[3] = { + {156, 3}, {30, 7}, {0, 5}, }; @@ -1518,18 +1519,27 @@ static arc arcs_71_7[2] = { {0, 7}, }; static arc arcs_71_8[1] = { - {25, 2}, + {25, 9}, +}; +static arc arcs_71_9[1] = { + {24, 10}, +}; +static arc arcs_71_10[2] = { + {30, 7}, + {0, 10}, }; -static state states_71[9] = { +static state states_71[11] = { {1, arcs_71_0}, {4, arcs_71_1}, {1, arcs_71_2}, {1, arcs_71_3}, {2, arcs_71_4}, - {2, arcs_71_5}, + {3, arcs_71_5}, {2, arcs_71_6}, {2, arcs_71_7}, {1, arcs_71_8}, + {1, arcs_71_9}, + {2, arcs_71_10}, }; static arc arcs_72_0[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"}, {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"}, - {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"}, {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"}, diff --git a/Python/symtable.c b/Python/symtable.c index 30e97d6..121f3ee 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -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_listcomp(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_excepthandler(struct symtable *st, excepthandler_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, - listcomp = NULL, setcomp = NULL, __class__ = NULL; + listcomp = NULL, setcomp = NULL, dictcomp = NULL, __class__ = NULL; #define GET_IDENTIFIER(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)) return 0; break; + case DictComp_kind: + if (!symtable_visit_dictcomp(st, e)) + return 0; + break; case Yield_kind: if (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 symtable_handle_comprehension(struct symtable *st, expr_ty e, - identifier scope_name, - asdl_seq *generators, expr_ty elt) + identifier scope_name, asdl_seq *generators, + expr_ty elt, expr_ty value) { int is_generator = (e->kind == GeneratorExp_kind); 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_TAIL_IN_BLOCK(st, comprehension, generators, 1, (void*)e); + if (value) + VISIT_IN_BLOCK(st, expr, value, (void*)e); VISIT_IN_BLOCK(st, expr, elt, (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), e->v.GeneratorExp.generators, - e->v.GeneratorExp.elt); + e->v.GeneratorExp.elt, NULL); } static int @@ -1567,7 +1574,7 @@ symtable_visit_listcomp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, GET_IDENTIFIER(listcomp), e->v.ListComp.generators, - e->v.ListComp.elt); + e->v.ListComp.elt, NULL); } static int @@ -1575,5 +1582,14 @@ symtable_visit_setcomp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, GET_IDENTIFIER(setcomp), 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); } -- cgit v0.12