=== modified file 'Grammar/Grammar' --- Grammar/Grammar 2007-08-31 00:04:24 +0000 +++ Grammar/Grammar 2008-04-05 23:03:15 +0000 @@ -113,8 +113,12 @@ classdef: 'class' NAME ['(' [arglist] ')'] ':' suite -arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) -argument: test [comp_for] | test '=' test # Really [keyword '='] test +arglist: argument (',' argument)* [','] +# "test '=' test" is really "keyword '=' test", but we have no such token. +# These need to be in a single rule to avoid grammar that is ambiguous +# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, +# we explicitly match '*' here, too, to give it proper precedence. +argument: ( test [comp_for] | '*' test | test '=' test | '**' test ) comp_iter: comp_for | comp_if comp_for: 'for' exprlist 'in' or_test [comp_iter] === modified file 'Include/Python-ast.h' --- Include/Python-ast.h 2008-03-31 05:14:30 +0000 +++ Include/Python-ast.h 2008-04-05 23:09:08 +0000 @@ -83,8 +83,6 @@ identifier name; asdl_seq *bases; asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; asdl_seq *body; asdl_seq *decorator_list; } ClassDef; @@ -262,8 +260,6 @@ expr_ty func; asdl_seq *args; asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; } Call; struct { @@ -396,11 +392,10 @@ stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq * decorator_list, expr_ty returns, int lineno, int col_offset, PyArena *arena); -#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) +#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, - expr_ty starargs, expr_ty kwargs, asdl_seq * body, - asdl_seq * decorator_list, int lineno, int col_offset, - PyArena *arena); + asdl_seq * body, asdl_seq * decorator_list, int lineno, + int col_offset, PyArena *arena); #define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); #define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3) @@ -493,10 +488,9 @@ #define Compare(a0, a1, a2, a3, a4, a5) _Py_Compare(a0, a1, a2, a3, a4, a5) expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, int lineno, int col_offset, PyArena *arena); -#define Call(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Call(a0, a1, a2, a3, a4, a5, a6, a7) -expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty - starargs, expr_ty kwargs, int lineno, int col_offset, PyArena - *arena); +#define Call(a0, a1, a2, a3, a4, a5) _Py_Call(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, int + lineno, int col_offset, PyArena *arena); #define Num(a0, a1, a2, a3) _Py_Num(a0, a1, a2, a3) expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena); #define Str(a0, a1, a2, a3) _Py_Str(a0, a1, a2, a3) === modified file 'Include/opcode.h' --- Include/opcode.h 2007-12-19 02:07:34 +0000 +++ Include/opcode.h 2008-04-05 23:10:10 +0000 @@ -95,14 +95,15 @@ #define COMPARE_OP 107 /* Comparison operator */ #define IMPORT_NAME 108 /* Index in name list */ #define IMPORT_FROM 109 /* Index in name list */ - #define JUMP_FORWARD 110 /* Number of bytes to skip */ #define JUMP_IF_FALSE 111 /* "" */ #define JUMP_IF_TRUE 112 /* "" */ #define JUMP_ABSOLUTE 113 /* Target byte offset from beginning of code */ - +#define BUILD_LIST_UNPACK 114 /* number of iterables to unpack */ +#define BUILD_MAP_UNPACK 115 /* "" */ #define LOAD_GLOBAL 116 /* Index in name list */ - +#define BUILD_TUPLE_UNPACK 117 /* number of iterables to unpack */ +#define BUILD_SET_UNPACK 118 /* "" */ #define CONTINUE_LOOP 119 /* Start of loop (absolute) */ #define SETUP_LOOP 120 /* Target address (relative) */ #define SETUP_EXCEPT 121 /* "" */ === added file 'Lib/lib2to3/fixes/fix_stararg_params.py' --- Lib/lib2to3/fixes/fix_stararg_params.py 1970-01-01 00:00:00 +0000 +++ Lib/lib2to3/fixes/fix_stararg_params.py 2008-04-05 23:03:16 +0000 @@ -0,0 +1,34 @@ +"""Fixer for functioncalls with starargs. + +func(a, kw=b, *args) -> func(a, *args, kw=b) + +""" + +from .. import pytree +from . import basefix +from .util import Comma + +class FixStarargParams(basefix.BaseFix): + # The grammar allows trailing commas in arglists, but only if + # there is no *arg or **kwargs. Capturing the comma in stararg + # is for convenience: we don't have to mess in starkwds to see + # where the commas should go. + PATTERN = """ + arglist< + pos=any* + kwds=(argument + """ + def transform(self, node, results): + pos = [ n.clone() for n in results['pos'] ] + kwds = [ n.clone() for n in results['kwds'] ] + stararg = [ n.clone() for n in results['stararg'] ] + starkwds = [ n.clone() for n in results.get('starkwds', ()) ] + c = Comma() + if kwds[-1] == c and stararg[-1] != c: + stararg.append(kwds.pop()) + new = pytree.Node(self.syms.arglist, pos + stararg + kwds + starkwds) + new.set_prefix(node.get_prefix()) + return new === modified file 'Lib/logging/__init__.py' --- Lib/logging/__init__.py 2008-02-17 13:31:39 +0000 +++ Lib/logging/__init__.py 2008-04-05 23:03:16 +0000 @@ -1039,7 +1039,7 @@ """ Convenience method for logging an ERROR with exception information. """ - self.error(msg, exc_info=1, *args) + self.error(msg, *args, exc_info=1) def critical(self, msg, *args, **kwargs): """ @@ -1405,7 +1405,7 @@ Log a message with severity 'ERROR' on the root logger, with exception information. """ - error(msg, exc_info=1, *args) + error(msg, *args, exc_info=1) def warning(msg, *args, **kwargs): """ === modified file 'Lib/opcode.py' --- Lib/opcode.py 2008-03-18 20:13:50 +0000 +++ Lib/opcode.py 2008-04-05 23:10:48 +0000 @@ -135,9 +135,11 @@ jrel_op('JUMP_IF_FALSE', 111) # "" jrel_op('JUMP_IF_TRUE', 112) # "" jabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code - +def_op('BUILD_LIST_UNPACK', 114) +def_op('BUILD_MAP_UNPACK', 115) name_op('LOAD_GLOBAL', 116) # Index in name list - +def_op('BUILD_TUPLE_UNPACK', 117) +def_op('BUILD_SET_UNPACK', 118) jabs_op('CONTINUE_LOOP', 119) # Target address jrel_op('SETUP_LOOP', 120) # Distance to target address jrel_op('SETUP_EXCEPT', 121) # "" === modified file 'Lib/pickle.py' --- Lib/pickle.py 2008-03-17 22:56:06 +0000 +++ Lib/pickle.py 2008-04-05 23:03:15 +0000 @@ -332,7 +332,7 @@ "two to five elements" % reduce) # Save the reduce() output and finally memoize the object - self.save_reduce(obj=obj, *rv) + self.save_reduce(*rv,obj=obj) def persistent_id(self, obj): # This exists so a subclass can override it === modified file 'Lib/test/test_ast.py' --- Lib/test/test_ast.py 2008-03-31 05:29:39 +0000 +++ Lib/test/test_ast.py 2008-04-05 23:03:16 +0000 @@ -91,7 +91,7 @@ # Compare "1 < 2 < 3", # Call - "f(1,2,c=3,*d,**e)", + "f(1,2,*d,c=3,**e)", # Num "10", # Str @@ -195,7 +195,7 @@ #### EVERYTHING BELOW IS GENERATED ##### exec_results = [ ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Pass', (1, 9))], [], None)]), -('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]), +('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]), ('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]), ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]), @@ -203,7 +203,7 @@ ('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Pass', (1, 11))], [])]), ('Module', [('While', (1, 0), ('Name', (1, 6), 'v', ('Load',)), [('Pass', (1, 8))], [])]), ('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]), -('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), +('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], []), None)]), ('Module', [('TryExcept', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [])]), ('Module', [('TryFinally', (1, 0), [('Pass', (2, 2))], [('Pass', (4, 2))])]), ('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]), @@ -227,7 +227,7 @@ ('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])), -('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), +('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2), ('Starred', (1, 7), ('Name', (1, 7), 'd', ('Load',)), ('Load',))], [('keyword', 'c', ('Num', (1, 11), 3)), ('keyword', None, ('Name', (1, 15), 'e', ('Load',)))])), ('Expression', ('Num', (1, 0), 10)), ('Expression', ('Str', (1, 0), 'string')), ('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), @@ -235,6 +235,6 @@ ('Expression', ('Name', (1, 0), 'v', ('Load',))), ('Expression', ('List', (1, 0), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('Tuple', (1, 0), [('Num', (1, 0), 1), ('Num', (1, 2), 2), ('Num', (1, 4), 3)], ('Load',))), -('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), +('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [])), ] main() === modified file 'Lib/test/test_extcall.py' --- Lib/test/test_extcall.py 2008-03-19 21:50:51 +0000 +++ Lib/test/test_extcall.py 2008-04-05 23:03:16 +0000 @@ -33,24 +33,36 @@ (1, 2, 3, 4, 5) {} >>> f(1, 2, 3, *[4, 5]) (1, 2, 3, 4, 5) {} + >>> f(*[1, 2, 3], 4, 5) + (1, 2, 3, 4, 5) {} >>> f(1, 2, 3, *UserList([4, 5])) (1, 2, 3, 4, 5) {} + >>> f(1, 2, 3, *[4, 5], *[6, 7]) + (1, 2, 3, 4, 5, 6, 7) {} + >>> f(1, *[2, 3], 4, *[5, 6], 7) + (1, 2, 3, 4, 5, 6, 7) {} + >>> f(*UserList([1, 2]), *UserList([3, 4]), 5, *UserList([6, 7])) + (1, 2, 3, 4, 5, 6, 7) {} Here we add keyword arguments >>> f(1, 2, 3, **{'a':4, 'b':5}) (1, 2, 3) {'a': 4, 'b': 5} + >>> f(1, 2, **{'a': -1, 'b': 5}, **{'a': 4, 'c': 6}) + (1, 2) {'a': 4, 'b': 5, 'c': 6} >>> f(1, 2, 3, *[4, 5], **{'a':6, 'b':7}) (1, 2, 3, 4, 5) {'a': 6, 'b': 7} - >>> f(1, 2, 3, x=4, y=5, *(6, 7), **{'a':8, 'b': 9}) - (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5} + >>> f(1, 2, 3, *[4, 5], **{'c': 8}, **{'a':6, 'b':7}) + (1, 2, 3, 4, 5) {'a': 6, 'b': 7, 'c': 8} + >>> f(1, 2, 3, *(4, 5), x=6, y=7, **{'a':8, 'b': 9}) + (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7} >>> f(1, 2, 3, **UserDict(a=4, b=5)) (1, 2, 3) {'a': 4, 'b': 5} >>> f(1, 2, 3, *(4, 5), **UserDict(a=6, b=7)) (1, 2, 3, 4, 5) {'a': 6, 'b': 7} - >>> f(1, 2, 3, x=4, y=5, *(6, 7), **UserDict(a=8, b=9)) - (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5} + >>> f(1, 2, 3, *(4, 5), x=6, y=7, **UserDict(a=8, b=9)) + (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7} Examples with invalid arguments (TypeErrors). We're also testing the function names in the exception messages. === modified file 'Lib/test/test_keywordonlyarg.py' --- Lib/test/test_keywordonlyarg.py 2007-12-09 21:49:48 +0000 +++ Lib/test/test_keywordonlyarg.py 2008-04-05 23:03:16 +0000 @@ -75,7 +75,7 @@ def testSyntaxErrorForFunctionCall(self): self.assertRaisesSyntaxError("f(p, k=1, p2)") - self.assertRaisesSyntaxError("f(p, *(1,2), k1=100)") + self.assertRaisesSyntaxError("f(p, k1=100, *(1,2)") def testRaiseErrorFuncallWithUnexpectedKeywordArgument(self): self.assertRaises(TypeError, keywordonly_sum, ()) === modified file 'Lib/test/test_metaclass.py' --- Lib/test/test_metaclass.py 2007-08-02 16:48:17 +0000 +++ Lib/test/test_metaclass.py 2008-04-05 23:03:16 +0000 @@ -112,7 +112,7 @@ True >>> class B: pass >>> kwds = {'other': 'haha'} - >>> class C(B, metaclass=M, *bases, **kwds): pass + >>> class C(B, *bases, metaclass=M, **kwds): pass ... Prepare called: ('C', (, )) {'other': 'haha'} New called: {'other': 'haha'} === modified file 'Lib/test/test_print.py' --- Lib/test/test_print.py 2008-03-21 01:11:52 +0000 +++ Lib/test/test_print.py 2008-04-05 23:03:16 +0000 @@ -27,19 +27,19 @@ (False, False, False): lambda args, sep, end, file: print(*args), (False, False, True): - lambda args, sep, end, file: print(file=file, *args), + lambda args, sep, end, file: print(*args, file=file), (False, True, False): - lambda args, sep, end, file: print(end=end, *args), + lambda args, sep, end, file: print(*args, end=end), (False, True, True): - lambda args, sep, end, file: print(end=end, file=file, *args), + lambda args, sep, end, file: print(*args, end=end, file=file), (True, False, False): - lambda args, sep, end, file: print(sep=sep, *args), + lambda args, sep, end, file: print(*args, sep=sep), (True, False, True): - lambda args, sep, end, file: print(sep=sep, file=file, *args), + lambda args, sep, end, file: print(*args, sep=sep, file=file), (True, True, False): - lambda args, sep, end, file: print(sep=sep, end=end, *args), + lambda args, sep, end, file: print(*args, sep=sep, end=end), (True, True, True): - lambda args, sep, end, file: print(sep=sep, end=end, file=file, *args), + lambda args, sep, end, file: print(*args, sep=sep, end=end, file=file), } # Class used to test __str__ and print === modified file 'Lib/test/test_unpack_ex.py' --- Lib/test/test_unpack_ex.py 2008-03-14 17:16:59 +0000 +++ Lib/test/test_unpack_ex.py 2008-04-05 23:45:06 +0000 @@ -59,7 +59,7 @@ 1 [2] 3 4 [5, 6] 7 -Unpack in list +Unpack into list assignment >>> [a, *b, c] = range(5) >>> a == 0 and b == [1, 2, 3] and c == 4 @@ -71,6 +71,58 @@ >>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4 True +Unpacking inside a list literal + >>> l = [3, 4] + >>> [1, 2, *l, 5, *reversed(l), 2, 1] + [1, 2, 3, 4, 5, 4, 3, 2, 1] + +Or a tuple literal + >>> l = [3, 4] + >>> 1, 2, *l, 5, *reversed(l), 2, 1 + (1, 2, 3, 4, 5, 4, 3, 2, 1) + >>> (1, 2, *l, 5, *reversed(l), 2, 1) + (1, 2, 3, 4, 5, 4, 3, 2, 1) + +Or a set literal + >>> l = [3, 4] + >>> s = {1, 2, *l, 5, *reversed(l), 2, 1} + >>> sorted(s) + [1, 2, 3, 4, 5] + +Stars on both sides of an assignment + >>> a, b, *c = range(5) + >>> a, b, c + (0, 1, [2, 3, 4]) + >>> *a, b, c = a, b, *c + >>> a, b, c + ([0, 1, 2], 3, 4) + +Unpacking an iterator multiple times: + >>> it = (item for item in range(2)) + >>> a, b, c = *it, 2, *it, *it + >>> a, b, c + (0, 1, 2) + +Stars inside a list- or gencomp, unpacking arbitrary iterables: + >>> l = [[1], (2, 3), {4}, {5: None}, (i for i in (6, 7)), "89"] + >>> [ *item for item in l ] + [1, 2, 3, 4, 5, 6, 7, '8', '9'] + + >>> l = [[1], (2, 3), {4}, {5: None}, (i for i in (6, 7)), "89"] + >>> g = (*item for item in l) + >>> list(g) + [1, 2, 3, 4, 5, 6, 7, '8', '9'] + +Unpacking an iterator in a generator: + >>> def yield_nested(it): + ... for item in it: + ... yield *item + ... + >>> l = [[1], (2, 3), {4}, {5: None}, (i for i in (6, 7)), "89"] + >>> g = yield_nested(l) + >>> list(g) + [1, 2, 3, 4, 5, 6, 7, '8', '9'] + Now for some failures Unpacking non-sequence @@ -131,17 +183,32 @@ >>> *a # doctest:+ELLIPSIS Traceback (most recent call last): ... - SyntaxError: can use starred expression only as assignment target + SyntaxError: can't use starred expression here >>> *1 # doctest:+ELLIPSIS Traceback (most recent call last): ... - SyntaxError: can use starred expression only as assignment target + SyntaxError: can't use starred expression here >>> x = *a # doctest:+ELLIPSIS Traceback (most recent call last): ... - SyntaxError: can use starred expression only as assignment target + SyntaxError: can't use starred expression here + + >>> { x: *y for x, y in zip(range(5), range(5)) } # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> { *x: y for x, y in zip(range(5), range(5)) } # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here + + >>> { *x: *y for x, y in zip(range(5), range(5)) } # doctest:+ELLIPSIS + Traceback (most recent call last): + ... + SyntaxError: can't use starred expression here Some size constraints (all fail.) === modified file 'Modules/parsermodule.c' --- Modules/parsermodule.c 2008-01-03 23:01:04 +0000 +++ Modules/parsermodule.c 2008-04-05 23:03:17 +0000 @@ -2447,7 +2447,11 @@ /* arglist: * - * (argument ',')* (argument [','] | '*' test [',' '**' test] | '**' test) + * argument (',' argument)* [','] + * + * argument: + * + * test [comp_for] | '*' test | test '=' test | '**' test */ static int validate_arglist(node *tree) @@ -2483,9 +2487,6 @@ } ok = 1; if (nch-i > 0) { - /* - * argument | '*' test [',' '**' test] | '**' test - */ int sym = TYPE(CHILD(tree, i)); if (sym == argument) { @@ -2496,29 +2497,6 @@ ok = 0; } } - else if (sym == STAR) { - ok = validate_star(CHILD(tree, i)); - if (ok && (nch-i == 2)) - ok = validate_test(CHILD(tree, i+1)); - else if (ok && (nch-i == 5)) - ok = (validate_test(CHILD(tree, i+1)) - && validate_comma(CHILD(tree, i+2)) - && validate_doublestar(CHILD(tree, i+3)) - && validate_test(CHILD(tree, i+4))); - else { - err_string("illegal use of '*' in arglist"); - ok = 0; - } - } - else if (sym == DOUBLESTAR) { - if (nch-i == 2) - ok = (validate_doublestar(CHILD(tree, i)) - && validate_test(CHILD(tree, i+1))); - else { - err_string("illegal use of '**' in arglist"); - ok = 0; - } - } else { err_string("illegal arglist specification"); ok = 0; @@ -2538,15 +2516,19 @@ { int nch = NCH(tree); int res = (validate_ntype(tree, argument) - && ((nch == 1) || (nch == 2) || (nch == 3)) - && validate_test(CHILD(tree, 0))); - - if (res && (nch == 2)) - res = validate_comp_for(CHILD(tree, 1)); - else if (res && (nch == 3)) - res = (validate_equal(CHILD(tree, 1)) - && validate_test(CHILD(tree, 2))); - + && ((nch == 1) || (nch == 2) || (nch == 3))); + + if (res && (TYPE(CHILD(tree, 0)) == STAR || + TYPE(CHILD(tree, 0)) == DOUBLESTAR)) + res = validate_test(CHILD(tree, 1)); + else if (res) { + res = validate_test(CHILD(tree, 0)); + if (res && (nch == 2)) + res = validate_comp_for(CHILD(tree, 1)); + else if (res && (nch == 3)) + res = (validate_equal(CHILD(tree, 1)) + && validate_test(CHILD(tree, 2))); + } return (res); } === modified file 'Parser/Python.asdl' --- Parser/Python.asdl 2008-03-31 05:14:30 +0000 +++ Parser/Python.asdl 2008-04-05 23:03:18 +0000 @@ -14,8 +14,6 @@ | ClassDef(identifier name, expr* bases, keyword* keywords, - expr? starargs, - expr? kwargs, stmt* body, expr *decorator_list) | Return(expr? value) @@ -64,8 +62,7 @@ -- need sequences for compare to distinguish between -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop* ops, expr* comparators) - | Call(expr func, expr* args, keyword* keywords, - expr? starargs, expr? kwargs) + | Call(expr func, expr* args, keyword* keywords) | Num(object n) -- a number as a PyObject. | Str(string s) -- need to specify raw, unicode, etc? | Bytes(string s) @@ -110,8 +107,8 @@ expr* kw_defaults) arg = (identifier arg, expr? annotation) - -- keyword arguments supplied to call - keyword = (identifier arg, expr value) + -- keyword arguments supplied to call (NULL identifier for **kwargs) + keyword = (identifier? arg, expr value) -- import name with optional 'as' alias. alias = (identifier name, identifier? asname) === modified file 'Python/Python-ast.c' --- Python/Python-ast.c 2008-03-31 05:29:39 +0000 +++ Python/Python-ast.c 2008-04-05 23:03:18 +0000 @@ -2,7 +2,7 @@ /* - __version__ 62078. + __version__ . This module must be committed separately after each AST grammar change; The __version__ number is set to the revision number of the commit @@ -50,8 +50,6 @@ "name", "bases", "keywords", - "starargs", - "kwargs", "body", "decorator_list", }; @@ -223,8 +221,6 @@ "func", "args", "keywords", - "starargs", - "kwargs", }; static PyTypeObject *Num_type; static char *Num_fields[]={ @@ -645,7 +641,7 @@ FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields, 5); if (!FunctionDef_type) return 0; - ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 7); + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 5); if (!ClassDef_type) return 0; Return_type = make_type("Return", stmt_type, Return_fields, 1); if (!Return_type) return 0; @@ -719,7 +715,7 @@ if (!Yield_type) return 0; Compare_type = make_type("Compare", expr_type, Compare_fields, 3); if (!Compare_type) return 0; - Call_type = make_type("Call", expr_type, Call_fields, 5); + Call_type = make_type("Call", expr_type, Call_fields, 3); if (!Call_type) return 0; Num_type = make_type("Num", expr_type, Num_fields, 1); if (!Num_type) return 0; @@ -1026,9 +1022,9 @@ } stmt_ty -ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, expr_ty - starargs, expr_ty kwargs, asdl_seq * body, asdl_seq * decorator_list, - int lineno, int col_offset, PyArena *arena) +ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, asdl_seq * + body, asdl_seq * decorator_list, int lineno, int col_offset, PyArena + *arena) { stmt_ty p; if (!name) { @@ -1043,8 +1039,6 @@ p->v.ClassDef.name = name; p->v.ClassDef.bases = bases; p->v.ClassDef.keywords = keywords; - p->v.ClassDef.starargs = starargs; - p->v.ClassDef.kwargs = kwargs; p->v.ClassDef.body = body; p->v.ClassDef.decorator_list = decorator_list; p->lineno = lineno; @@ -1711,8 +1705,8 @@ } expr_ty -Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs, - expr_ty kwargs, int lineno, int col_offset, PyArena *arena) +Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, int lineno, int + col_offset, PyArena *arena) { expr_ty p; if (!func) { @@ -1727,8 +1721,6 @@ p->v.Call.func = func; p->v.Call.args = args; p->v.Call.keywords = keywords; - p->v.Call.starargs = starargs; - p->v.Call.kwargs = kwargs; p->lineno = lineno; p->col_offset = col_offset; return p; @@ -2086,11 +2078,6 @@ keyword(identifier arg, expr_ty value, PyArena *arena) { keyword_ty p; - if (!arg) { - PyErr_SetString(PyExc_ValueError, - "field arg is required for keyword"); - return NULL; - } if (!value) { PyErr_SetString(PyExc_ValueError, "field value is required for keyword"); @@ -2237,16 +2224,6 @@ if (PyObject_SetAttrString(result, "keywords", value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.starargs); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "starargs", value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.kwargs); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "kwargs", value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttrString(result, "body", value) == -1) @@ -2771,16 +2748,6 @@ if (PyObject_SetAttrString(result, "keywords", value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_expr(o->v.Call.starargs); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "starargs", value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.kwargs); - if (!value) goto failed; - if (PyObject_SetAttrString(result, "kwargs", value) == -1) - goto failed; - Py_DECREF(value); break; case Num_kind: result = PyType_GenericNew(Num_type, NULL, NULL); @@ -3628,8 +3595,6 @@ identifier name; asdl_seq* bases; asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; asdl_seq* body; asdl_seq* decorator_list; @@ -3695,28 +3660,6 @@ PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); return 1; } - if (PyObject_HasAttrString(obj, "starargs")) { - int res; - tmp = PyObject_GetAttrString(obj, "starargs"); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (PyObject_HasAttrString(obj, "kwargs")) { - int res; - tmp = PyObject_GetAttrString(obj, "kwargs"); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } if (PyObject_HasAttrString(obj, "body")) { int res; Py_ssize_t len; @@ -3767,8 +3710,8 @@ PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); return 1; } - *out = ClassDef(name, bases, keywords, starargs, kwargs, body, - decorator_list, lineno, col_offset, arena); + *out = ClassDef(name, bases, keywords, body, decorator_list, + lineno, col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -5214,8 +5157,6 @@ expr_ty func; asdl_seq* args; asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; if (PyObject_HasAttrString(obj, "func")) { int res; @@ -5279,30 +5220,7 @@ PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); return 1; } - if (PyObject_HasAttrString(obj, "starargs")) { - int res; - tmp = PyObject_GetAttrString(obj, "starargs"); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - starargs = NULL; - } - if (PyObject_HasAttrString(obj, "kwargs")) { - int res; - tmp = PyObject_GetAttrString(obj, "kwargs"); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_XDECREF(tmp); - tmp = NULL; - } else { - kwargs = NULL; - } - *out = Call(func, args, keywords, starargs, kwargs, lineno, - col_offset, arena); + *out = Call(func, args, keywords, lineno, col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -6324,8 +6242,7 @@ Py_XDECREF(tmp); tmp = NULL; } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); - return 1; + arg = NULL; } if (PyObject_HasAttrString(obj, "value")) { int res; @@ -6395,7 +6312,7 @@ if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return; if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0) return; - if (PyModule_AddStringConstant(m, "__version__", "62078") < 0) + if (PyModule_AddStringConstant(m, "__version__", "") < 0) return; if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return; if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) === modified file 'Python/ast.c' --- Python/ast.c 2008-03-31 05:14:30 +0000 +++ Python/ast.c 2008-04-05 23:03:18 +0000 @@ -925,7 +925,7 @@ name_expr = NULL; } else if (NCH(n) == 5) { /* Call with no arguments */ - d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), + d = Call(name_expr, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); if (!d) return NULL; @@ -1569,7 +1569,7 @@ REQ(n, trailer); if (TYPE(CHILD(n, 0)) == LPAR) { if (NCH(n) == 2) - return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), + return Call(left_expr, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); else return ast_for_call(c, CHILD(n, 1), left_expr); @@ -1902,7 +1902,6 @@ int i, nargs, nkeywords, ngens; asdl_seq *args; asdl_seq *keywords; - expr_ty vararg = NULL, kwarg = NULL; REQ(n, arglist); @@ -1916,6 +1915,8 @@ nargs++; else if (TYPE(CHILD(ch, 1)) == comp_for) ngens++; + else if (TYPE(CHILD(ch, 0)) == STAR) + nargs++; else nkeywords++; } @@ -1960,6 +1961,31 @@ return NULL; asdl_seq_SET(args, nargs++, e); } + else if (TYPE(CHILD(ch, 0)) == STAR) { + node *chch = CHILD(ch, 1); + expr_ty starred; + if (nkeywords) { + ast_error(chch, "non-keyword arg after keyword arg"); + return NULL; + } + e = ast_for_expr(c, chch); + if (!e) + return NULL; + starred = Starred(e, Load, LINENO(chch), chch->n_col_offset, + c->c_arena); + if (!starred) + return NULL; + asdl_seq_SET(args, nargs++, starred); + } + else if (TYPE(CHILD(ch, 0)) == DOUBLESTAR) { + keyword_ty kw; + i++; + e = ast_for_expr(c, CHILD(ch, 1)); + if (!e) + return NULL; + kw = keyword(NULL, e, c->c_arena); + asdl_seq_SET(keywords, nkeywords++, kw); + } else { keyword_ty kw; identifier key; @@ -1992,21 +2018,10 @@ asdl_seq_SET(keywords, nkeywords++, kw); } } - else if (TYPE(ch) == STAR) { - vararg = ast_for_expr(c, CHILD(n, i+1)); - if (!vararg) - return NULL; - i++; - } - else if (TYPE(ch) == DOUBLESTAR) { - kwarg = ast_for_expr(c, CHILD(n, i+1)); - if (!kwarg) - return NULL; - i++; - } } - return Call(func, args, keywords, vararg, kwarg, func->lineno, func->col_offset, c->c_arena); + return Call(func, args, keywords, func->lineno, + func->col_offset, c->c_arena); } static expr_ty @@ -2955,7 +2970,7 @@ s = ast_for_suite(c, CHILD(n, 3)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } @@ -2963,7 +2978,7 @@ s = ast_for_suite(c, CHILD(n,5)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } @@ -2978,8 +2993,7 @@ return NULL; return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), - call->v.Call.args, call->v.Call.keywords, - call->v.Call.starargs, call->v.Call.kwargs, s, + call->v.Call.args, call->v.Call.keywords, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } === modified file 'Python/ceval.c' --- Python/ceval.c 2008-03-16 00:07:10 +0000 +++ Python/ceval.c 2008-04-05 23:22:54 +0000 @@ -1769,6 +1769,38 @@ } break; + case BUILD_LIST_UNPACK: + case BUILD_TUPLE_UNPACK: + x = PyList_New(0); + if (x != NULL) { + int i; + for ( i = oparg; i > 0; i--) { + w = stack_pointer[-i]; + v = _PyList_Extend((PyListObject *)x, + w); + if (!v) { + Py_DECREF(x); + x = NULL; + break; + } + Py_DECREF(v); + } + if (x == NULL) + break; + STACKADJ(-oparg); + if (opcode == BUILD_TUPLE_UNPACK) { + v = PyObject_CallFunctionObjArgs( + (PyObject *)&PyTuple_Type, + x, NULL); + Py_DECREF(x); + if (v) + PUSH(v); + x = v; + } else + PUSH(x); + } + break; + case BUILD_SET: x = PySet_New(NULL); if (x != NULL) { @@ -1787,12 +1819,50 @@ } break; + case BUILD_SET_UNPACK: + x = PySet_New(NULL); + if (x != NULL) { + int i; + for ( i = oparg; i > 0; i--) { + w = stack_pointer[-i]; + if (_PySet_Update(x, w) < 0) { + Py_DECREF(x); + x = NULL; + break; + } + } + if (x == NULL) + break; + STACKADJ(-oparg); + PUSH(x); + } + break; + case BUILD_MAP: x = _PyDict_NewPresized((Py_ssize_t)oparg); PUSH(x); if (x != NULL) continue; break; + case BUILD_MAP_UNPACK: + x = PyDict_New(); + if (x != NULL) { + int i; + for ( i = oparg; i > 0; i--) { + w = stack_pointer[-i]; + if (PyDict_Update(x, w) < 0) { + Py_DECREF(x); + x = NULL; + break; + } + } + if (x == NULL) + break; + STACKADJ(-oparg+1); + SET_TOP(x); + } + break; + case STORE_MAP: w = TOP(); /* key */ u = SECOND(); /* value */ @@ -3690,6 +3760,11 @@ kwdict = d; } } + if (nk > 0) { + kwdict = update_keyword_args(kwdict, nk, pp_stack, func); + if (kwdict == NULL) + goto ext_call_fail; + } if (flags & CALL_FLAG_VAR) { stararg = EXT_POP(*pp_stack); if (!PyTuple_Check(stararg)) { @@ -3711,11 +3786,6 @@ } nstar = PyTuple_GET_SIZE(stararg); } - if (nk > 0) { - kwdict = update_keyword_args(kwdict, nk, pp_stack, func); - if (kwdict == NULL) - goto ext_call_fail; - } callargs = update_star_args(na, nstar, stararg, pp_stack); if (callargs == NULL) goto ext_call_fail; === modified file 'Python/compile.c' --- Python/compile.c 2008-04-01 08:08:09 +0000 +++ Python/compile.c 2008-04-05 23:44:25 +0000 @@ -183,9 +183,7 @@ static int compiler_with(struct compiler *, stmt_ty); static int compiler_call_helper(struct compiler *c, int n, asdl_seq *args, - asdl_seq *keywords, - expr_ty starargs, - expr_ty kwargs); + asdl_seq *keywords); static PyCodeObject *assemble(struct compiler *, int addNone); static PyObject *__doc__; @@ -791,6 +789,10 @@ case BUILD_TUPLE: case BUILD_LIST: case BUILD_SET: + case BUILD_LIST_UNPACK: + case BUILD_TUPLE_UNPACK: + case BUILD_SET_UNPACK: + case BUILD_MAP_UNPACK: return 1-oparg; case BUILD_MAP: return 1; @@ -1529,8 +1531,8 @@ it has a single argument (__locals__) where the dict (or MutableSequence) representing the locals is passed is the class name - is the positional arguments and *varargs argument - is the keyword arguments and **kwds argument + is the positional arguments and *varargs arguments + is the keyword arguments and **kwds arguments This borrows from compiler_call. */ @@ -1620,9 +1622,7 @@ /* 5. generate the rest of the code for the call */ if (!compiler_call_helper(c, 2, s->v.ClassDef.bases, - s->v.ClassDef.keywords, - s->v.ClassDef.starargs, - s->v.ClassDef.kwargs)) + s->v.ClassDef.keywords)) return 0; /* 6. apply decorators */ @@ -2623,11 +2623,45 @@ } static int +starunpack_helper(struct compiler *c, asdl_seq *elts, int single_op, + int inner_op, int outer_op) +{ + int n = asdl_seq_LEN(elts); + int i, nsubitems = 0, nseen = 0; + for (i = 0; i < n; i++) { + expr_ty elt = asdl_seq_GET(elts, i); + if (elt->kind == Starred_kind) { + if (nseen) { + ADDOP_I(c, inner_op, nseen); + nseen = 0; + nsubitems++; + } + VISIT(c, expr, elt->v.Starred.value); + nsubitems++; + } + else { + VISIT(c, expr, elt); + nseen++; + } + } + if (nsubitems) { + if (nseen) { + ADDOP_I(c, inner_op, nseen); + nsubitems++; + } + ADDOP_I(c, outer_op, nsubitems); + } + else + ADDOP_I(c, single_op, nseen); + return 1; +} + +static int compiler_list(struct compiler *c, expr_ty e) { - int n = asdl_seq_LEN(e->v.List.elts); if (e->v.List.ctx == Store) { int i, seen_star = 0; + int n = asdl_seq_LEN(e->v.List.elts); for (i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(e->v.List.elts, i); if (elt->kind == Starred_kind && !seen_star) { @@ -2648,19 +2682,20 @@ ADDOP_I(c, UNPACK_SEQUENCE, n); } } - VISIT_SEQ(c, expr, e->v.List.elts); - if (e->v.List.ctx == Load) { - ADDOP_I(c, BUILD_LIST, n); - } + if (e->v.List.ctx == Load) + return starunpack_helper(c, e->v.List.elts, BUILD_LIST, + BUILD_TUPLE, BUILD_LIST_UNPACK); + else + VISIT_SEQ(c, expr, e->v.List.elts); return 1; } static int compiler_tuple(struct compiler *c, expr_ty e) { - int n = asdl_seq_LEN(e->v.Tuple.elts); if (e->v.Tuple.ctx == Store) { int i, seen_star = 0; + int n = asdl_seq_LEN(e->v.Tuple.elts); for (i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(e->v.Tuple.elts, i); if (elt->kind == Starred_kind && !seen_star) { @@ -2681,14 +2716,22 @@ ADDOP_I(c, UNPACK_SEQUENCE, n); } } - VISIT_SEQ(c, expr, e->v.Tuple.elts); - if (e->v.Tuple.ctx == Load) { - ADDOP_I(c, BUILD_TUPLE, n); - } + if (e->v.Tuple.ctx == Load) + return starunpack_helper(c, e->v.Tuple.elts, BUILD_TUPLE, + BUILD_TUPLE, BUILD_TUPLE_UNPACK); + else + VISIT_SEQ(c, expr, e->v.Tuple.elts); return 1; } static int +compiler_set(struct compiler *c, expr_ty e) +{ + return starunpack_helper(c, e->v.Set.elts, BUILD_SET, + BUILD_SET, BUILD_SET_UNPACK); +} + +static int compiler_compare(struct compiler *c, expr_ty e) { int i, n; @@ -2740,36 +2783,155 @@ VISIT(c, expr, e->v.Call.func); return compiler_call_helper(c, 0, e->v.Call.args, - e->v.Call.keywords, - e->v.Call.starargs, - e->v.Call.kwargs); + e->v.Call.keywords); } /* shared code between compiler_call and compiler_class */ + +/* The call syntax (also used for class definition) allows for + an arbitrary number of *args mixed in with positional arguments, and an + arbitrary number of **kwargs mixed in with keyword arguments. Contrary to + Python 2.x, in 3.0 we do not allow *args after keyword arguments. + + The opcodes we need to emit still require a particular stack layout: + - zero or more positional arguments. + - zero or one *args sequence (for the VAR and VAR_KW opcodes.) + - zero or more keyword arguments. + - zero or one **kwargs mapping (for the _KW opcodes.) + The number of positional and keyword arguments is encoded in the opcode + argument. + + In order to support mixing star-args in positional arguments, we first + push any leading positional arguments on the stack. If a star-arg + follows, we push that on the stack, too. If then more positional + arguments or star-args follow, we build a single list of everything + including the first star-arg (but not the positional arguments) using + BUILD_LIST_UNPACK (packing any separate positional arguments into a tuple + first.) No matter how many star-args and positional arguments are mixed, + we end up with the stack in the proper shape (zero or more positional + arguments followed by zero or one star-arg), with the expressions + properly evaluated left-to-right and with a fast path for the common case + (just positional arguments, or at most one star-arg at the end.) + + We then do pretty much the same thing with keyword arguments and + starstar-kwargs, but by building a dict out of any keyword arguments + after the first grouping, and unpacking those and all starstar-kwargs + into a single dict with BUILD_MAP_UNPACK. +*/ + static int compiler_call_helper(struct compiler *c, - int n, /* Args already pushed */ + int n, /* Positional args already pushed */ asdl_seq *args, - asdl_seq *keywords, - expr_ty starargs, - expr_ty kwargs) + asdl_seq *keywords) { int code = 0; - - n += asdl_seq_LEN(args); - VISIT_SEQ(c, expr, args); - if (keywords) { - VISIT_SEQ(c, keyword, keywords); - n |= asdl_seq_LEN(keywords) << 8; - } - if (starargs) { - VISIT(c, expr, starargs); - code |= 1; - } - if (kwargs) { - VISIT(c, expr, kwargs); - code |= 2; - } + int nelts; + int i, nsubitems, nseen, nkw = 0; + + nsubitems = 0; + nseen = 0; + nelts = asdl_seq_LEN(args); + for (i = 0; i < nelts; i++) { + expr_ty elt = asdl_seq_GET(args, i); + if (elt->kind == Starred_kind) { + /* A star-arg. If this isn't the first, + and we've seen normal positional arguments + since, pack the positional arguments into a + tuple. */ + if (nseen) { + ADDOP_I(c, BUILD_TUPLE, nseen); + nseen = 0; + nsubitems++; + } + VISIT(c, expr, elt->v.Starred.value); + nsubitems++; + } + else if (nsubitems) { + /* We've seen star-args already, so we + count towards items-to-pack-into-tuple. */ + VISIT(c, expr, elt); + nseen++; + } + else { + /* positional argument before any star-arg + hanky-panky, we just leave it on the stack. */ + VISIT(c, expr, elt); + n++; + } + } + if (nseen) { + /* Pack up any trailing positional arguments */ + ADDOP_I(c, BUILD_TUPLE, nseen); + nsubitems++; + } + if (nsubitems > 1) { + /* If we ended up with more than one stararg, we need + to concatenate them into a single sequence. */ + ADDOP_I(c, BUILD_LIST_UNPACK, nsubitems); + code |= 1; + } + else if (nsubitems) { + code |= 1; + } + /* Same dance again for keyword arguments */ + nseen = 0; + nsubitems = 0; + nelts = asdl_seq_LEN(keywords); + for (i = 0; i < nelts; i++) { + keyword_ty kw = asdl_seq_GET(keywords, i); + if (kw->arg == NULL) { + /* A starstar-kwarg. Because we need to use + BUILD_MAP and STORE_SUBSCR to store + keyword arguments as we visit them, + we just need to flag that subsequent + keyword arguments should be stored in a new + dict, and count the previous dict. */ + if (nseen) { + nseen = 0; + nsubitems++; + } + VISIT(c, expr, kw->value); + nsubitems++; + } + else if (nsubitems) { + /* This code would be a lot simpler if we had + a BUILD_MAP opcode that acted like BUILD_LIST */ + if (!nseen) + ADDOP(c, BUILD_MAP); + /* Odd dance because of STORE_SUBSCR's odd-ish + stack order: , + and it eats the dict. In normal dict building, + the value is evaluated before the key, but + for keyword arguments this doesn't matter, + since the keyword is always a constant. */ + ADDOP(c, DUP_TOP); + VISIT(c, expr, kw->value); + ADDOP(c, ROT_TWO); + ADDOP_O(c, LOAD_CONST, kw->arg, consts); + ADDOP(c, STORE_SUBSCR); + } + else { + VISIT(c, keyword, kw) + nkw++; + } + } + if (nseen) { + /* Count the last built map */ + nsubitems++; + } + if (nsubitems > 1) { + /* Pack it all up */ + ADDOP_I(c, BUILD_MAP_UNPACK, nsubitems); + code |= 2; + } + else if (nsubitems) { + code |= 2; + } + assert(n < 1<<8); + assert(nkw < 1<<24); + n |= nkw << 8; + switch (code) { case 0: ADDOP_I(c, CALL_FUNCTION, n); @@ -2813,8 +2975,9 @@ comprehension_ty gen; basicblock *start, *anchor, *skip, *if_cleanup; - int i, n; - + basicblock *innerstart, *inneranchor; + int i, n, is_star = 0; + start = compiler_new_block(c); skip = compiler_new_block(c); if_cleanup = compiler_new_block(c); @@ -2857,25 +3020,44 @@ elt, val, type)) return 0; + if (elt->kind == Starred_kind && + type != COMP_DICTCOMP) { + elt = elt->v.Starred.value; + is_star = 1; + innerstart = compiler_new_block(c); + inneranchor = compiler_new_block(c); + if (innerstart == NULL || inneranchor == NULL) + return 0; + } + /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { + /* Dictcomps can't be using unpacking-*, and need + elements visited in a different order. */ + if (type != COMP_DICTCOMP) + VISIT(c, expr, elt); + if (is_star) { + ADDOP(c, GET_ITER); + compiler_use_next_block(c, innerstart); + ADDOP_JREL(c, FOR_ITER, inneranchor); + NEXT_BLOCK(c); + } /* comprehension specific code */ switch (type) { case COMP_GENEXP: - VISIT(c, expr, elt); ADDOP(c, YIELD_VALUE); ADDOP(c, POP_TOP); break; case COMP_LISTCOMP: if (!compiler_nameop(c, tmpname, Load)) return 0; - VISIT(c, expr, elt); + ADDOP(c, ROT_TWO); ADDOP(c, LIST_APPEND); break; case COMP_SETCOMP: if (!compiler_nameop(c, tmpname, Load)) return 0; - VISIT(c, expr, elt); + ADDOP(c, ROT_TWO); ADDOP(c, SET_ADD); break; case COMP_DICTCOMP: @@ -2892,7 +3074,10 @@ default: return 0; } - + if (is_star) { + ADDOP_JABS(c, JUMP_ABSOLUTE, innerstart); + compiler_use_next_block(c, inneranchor); + } compiler_use_next_block(c, skip); } for (i = 0; i < n; i++) { @@ -3042,6 +3227,47 @@ static int +compiler_yield(struct compiler *c, expr_ty e) +{ + int is_star = 0; + expr_ty elt = e->v.Yield.value; + + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'yield' outside function"); + if (elt && elt->kind == Starred_kind) { + is_star = 1; + elt = elt->v.Starred.value; + } + if (elt) { + VISIT(c, expr, elt); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + if (is_star) { + basicblock *start, *anchor; + + start = compiler_new_block(c); + anchor = compiler_new_block(c); + if (start == NULL || anchor == NULL) + return 0; + ADDOP(c, GET_ITER); + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, anchor); + NEXT_BLOCK(c); + ADDOP(c, YIELD_VALUE); + ADDOP(c, POP_TOP); + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, anchor); + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + else + ADDOP(c, YIELD_VALUE); + return 1; +} + + +static int compiler_visit_keyword(struct compiler *c, keyword_ty k) { ADDOP_O(c, LOAD_CONST, k->arg, consts); @@ -3246,10 +3472,7 @@ } break; case Set_kind: - n = asdl_seq_LEN(e->v.Set.elts); - VISIT_SEQ(c, expr, e->v.Set.elts); - ADDOP_I(c, BUILD_SET, n); - break; + return compiler_set(c, e); case GeneratorExp_kind: return compiler_genexp(c, e); case ListComp_kind: @@ -3259,16 +3482,7 @@ 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"); - if (e->v.Yield.value) { - VISIT(c, expr, e->v.Yield.value); - } - else { - ADDOP_O(c, LOAD_CONST, Py_None, consts); - } - ADDOP(c, YIELD_VALUE); - break; + return compiler_yield(c, e); case Compare_kind: return compiler_compare(c, e); case Call_kind: @@ -3349,7 +3563,7 @@ "starred assignment target must be in a list or tuple"); default: return compiler_error(c, - "can use starred expression only as assignment target"); + "can't use starred expression here"); } break; case Name_kind: === modified file 'Python/graminit.c' --- Python/graminit.c 2007-08-31 00:04:24 +0000 +++ Python/graminit.c 2008-04-05 23:10:28 +0000 @@ -1568,63 +1568,40 @@ {1, arcs_72_6}, {1, arcs_72_7}, }; -static arc arcs_73_0[3] = { +static arc arcs_73_0[1] = { {161, 1}, - {31, 2}, - {32, 3}, }; static arc arcs_73_1[2] = { - {30, 4}, + {30, 2}, {0, 1}, }; -static arc arcs_73_2[1] = { - {24, 5}, -}; -static arc arcs_73_3[1] = { - {24, 6}, -}; -static arc arcs_73_4[4] = { +static arc arcs_73_2[2] = { {161, 1}, - {31, 2}, - {32, 3}, - {0, 4}, -}; -static arc arcs_73_5[2] = { - {30, 7}, - {0, 5}, -}; -static arc arcs_73_6[1] = { - {0, 6}, -}; -static arc arcs_73_7[1] = { - {32, 3}, -}; -static state states_73[8] = { - {3, arcs_73_0}, + {0, 2}, +}; +static state states_73[3] = { + {1, arcs_73_0}, {2, arcs_73_1}, - {1, arcs_73_2}, - {1, arcs_73_3}, - {4, arcs_73_4}, - {2, arcs_73_5}, - {1, arcs_73_6}, - {1, arcs_73_7}, + {2, arcs_73_2}, }; -static arc arcs_74_0[1] = { +static arc arcs_74_0[3] = { {24, 1}, + {31, 2}, + {32, 2}, }; static arc arcs_74_1[3] = { - {156, 2}, - {29, 3}, + {156, 3}, + {29, 2}, {0, 1}, }; static arc arcs_74_2[1] = { - {0, 2}, + {24, 3}, }; static arc arcs_74_3[1] = { - {24, 2}, + {0, 3}, }; static state states_74[4] = { - {1, arcs_74_0}, + {3, arcs_74_0}, {3, arcs_74_1}, {1, arcs_74_2}, {1, arcs_74_3}, @@ -1869,10 +1846,10 @@ "\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"}, - {329, "arglist", 0, 8, states_73, + {329, "arglist", 0, 3, states_73, "\000\040\040\200\001\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"}, {330, "argument", 0, 4, states_74, - "\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\001\000\000\000\000\040\000\000\000\040\004\000\200\041\224\017\000"}, {331, "comp_iter", 0, 2, states_75, "\000\000\000\000\000\000\000\000\000\000\000\104\000\000\000\000\000\000\000\000\000"}, {332, "comp_for", 0, 6, states_76, === modified file 'Python/symtable.c' --- Python/symtable.c 2008-03-31 05:14:30 +0000 +++ Python/symtable.c 2008-04-05 23:03:18 +0000 @@ -1035,10 +1035,6 @@ return 0; VISIT_SEQ(st, expr, s->v.ClassDef.bases); VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); - if (s->v.ClassDef.starargs) - VISIT(st, expr, s->v.ClassDef.starargs); - if (s->v.ClassDef.kwargs) - VISIT(st, expr, s->v.ClassDef.kwargs); if (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, @@ -1292,10 +1288,6 @@ VISIT(st, expr, e->v.Call.func); VISIT_SEQ(st, expr, e->v.Call.args); VISIT_SEQ(st, keyword, e->v.Call.keywords); - if (e->v.Call.starargs) - VISIT(st, expr, e->v.Call.starargs); - if (e->v.Call.kwargs) - VISIT(st, expr, e->v.Call.kwargs); break; case Num_kind: case Str_kind: