diff -r ac0d6c09457e Grammar/Grammar --- a/Grammar/Grammar Sun Jan 18 21:25:15 2015 -0800 +++ b/Grammar/Grammar Tue Jan 20 18:37:59 2015 -0500 @@ -116,12 +116,16 @@ classdef: 'class' NAME ['(' [arglist] ')'] ':' suite -arglist: (argument ',')* (argument [','] - |'*' test (',' argument)* [',' '**' test] - |'**' test) +arglist: argument (',' argument)* [','] + # The reason that keywords are test nodes instead of NAME is that using NAME # results in an ambiguity. ast.c makes sure it's a NAME. -argument: test [comp_for] | test '=' test # Really [keyword '='] test +# "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] comp_if: 'if' test_nocond [comp_iter] diff -r ac0d6c09457e Include/Python-ast.h --- a/Include/Python-ast.h Sun Jan 18 21:25:15 2015 -0800 +++ b/Include/Python-ast.h Tue Jan 20 18:37:59 2015 -0500 @@ -84,8 +84,6 @@ identifier name; asdl_seq *bases; asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; asdl_seq *body; asdl_seq *decorator_list; } ClassDef; @@ -263,8 +261,6 @@ expr_ty func; asdl_seq *args; asdl_seq *keywords; - expr_ty starargs; - expr_ty kwargs; } Call; struct { @@ -406,11 +402,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) @@ -504,10 +499,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) diff -r ac0d6c09457e Include/opcode.h --- a/Include/opcode.h Sun Jan 18 21:25:15 2015 -0800 +++ b/Include/opcode.h Tue Jan 20 18:37:59 2015 -0500 @@ -111,6 +111,10 @@ #define SET_ADD 146 #define MAP_ADD 147 #define LOAD_CLASSDEREF 148 +#define BUILD_LIST_UNPACK 149 +#define BUILD_MAP_UNPACK 150 +#define BUILD_TUPLE_UNPACK 151 +#define BUILD_SET_UNPACK 152 /* EXCEPT_HANDLER is a special, implicit block type which is created when entering an except handler. It is not an opcode but we define it here diff -r ac0d6c09457e Lib/opcode.py --- a/Lib/opcode.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/opcode.py Tue Jan 20 18:37:59 2015 -0500 @@ -200,4 +200,9 @@ def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 +def_op('BUILD_LIST_UNPACK', 149) +def_op('BUILD_MAP_UNPACK', 150) +def_op('BUILD_TUPLE_UNPACK', 151) +def_op('BUILD_SET_UNPACK', 152) + del def_op, name_op, jrel_op, jabs_op diff -r ac0d6c09457e Lib/test/test_ast.py --- a/Lib/test/test_ast.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/test/test_ast.py Tue Jan 20 18:37:59 2015 -0500 @@ -237,10 +237,10 @@ self.assertIsNone(ref()) def test_snippets(self): - for input, output, kind in ((exec_tests, exec_results, "exec"), - (single_tests, single_results, "single"), - (eval_tests, eval_results, "eval")): - for i, o in zip(input, output): + for input_, output, kind in ((exec_tests, exec_results, "exec"), + (single_tests, single_results, "single"), + (eval_tests, eval_results, "eval")): + for i, o in zip(input_, output): ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST) self.assertEqual(to_tuple(ast_tree), o) self._assertTrueorder(ast_tree, (0, 0)) @@ -444,17 +444,17 @@ self.assertEqual(ast.dump(node), "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), " "args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], " - "keywords=[], starargs=None, kwargs=None))])" + "keywords=[]))])" ) self.assertEqual(ast.dump(node, annotate_fields=False), "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), " - "Str('and cheese')], [], None, None))])" + "Str('and cheese')], []))])" ) self.assertEqual(ast.dump(node, include_attributes=True), "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), " "lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), " "lineno=1, col_offset=5), Str(s='and cheese', lineno=1, " - "col_offset=11)], keywords=[], starargs=None, kwargs=None, " + "col_offset=11)], keywords=[], " "lineno=1, col_offset=4), lineno=1, col_offset=0)])" ) @@ -470,16 +470,16 @@ def test_fix_missing_locations(self): src = ast.parse('write("spam")') src.body.append(ast.Expr(ast.Call(ast.Name('spam', ast.Load()), - [ast.Str('eggs')], [], None, None))) + [ast.Str('eggs')], []))) self.assertEqual(src, ast.fix_missing_locations(src)) self.assertEqual(ast.dump(src, include_attributes=True), "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " "lineno=1, col_offset=0), args=[Str(s='spam', lineno=1, " - "col_offset=6)], keywords=[], starargs=None, kwargs=None, " + "col_offset=6)], keywords=[], " "lineno=1, col_offset=5), lineno=1, col_offset=0), " "Expr(value=Call(func=Name(id='spam', ctx=Load(), lineno=1, " "col_offset=0), args=[Str(s='eggs', lineno=1, col_offset=0)], " - "keywords=[], starargs=None, kwargs=None, lineno=1, " + "keywords=[], lineno=1, " "col_offset=0), lineno=1, col_offset=0)])" ) @@ -504,8 +504,7 @@ node = ast.parse('foo()', mode='eval') d = dict(ast.iter_fields(node.body)) self.assertEqual(d.pop('func').id, 'foo') - self.assertEqual(d, {'keywords': [], 'kwargs': None, - 'args': [], 'starargs': None}) + self.assertEqual(d, {'keywords': [], 'args': []}) def test_iter_child_nodes(self): node = ast.parse("spam(23, 42, eggs='leek')", mode='eval') @@ -621,8 +620,7 @@ self._check_arguments(fac, self.stmt) def test_classdef(self): - def cls(bases=None, keywords=None, starargs=None, kwargs=None, - body=None, decorator_list=None): + def cls(bases=None, keywords=None, body=None, decorator_list=None): if bases is None: bases = [] if keywords is None: @@ -631,16 +629,12 @@ body = [ast.Pass()] if decorator_list is None: decorator_list = [] - return ast.ClassDef("myclass", bases, keywords, starargs, - kwargs, body, decorator_list) + return ast.ClassDef("myclass", bases, keywords, + body, decorator_list) self.stmt(cls(bases=[ast.Name("x", ast.Store())]), "must have Load context") self.stmt(cls(keywords=[ast.keyword("x", ast.Name("x", ast.Store()))]), "must have Load context") - self.stmt(cls(starargs=ast.Name("x", ast.Store())), - "must have Load context") - self.stmt(cls(kwargs=ast.Name("x", ast.Store())), - "must have Load context") self.stmt(cls(body=[]), "empty body on ClassDef") self.stmt(cls(body=[None]), "None disallowed") self.stmt(cls(decorator_list=[ast.Name("x", ast.Store())]), @@ -871,20 +865,12 @@ func = ast.Name("x", ast.Load()) args = [ast.Name("y", ast.Load())] keywords = [ast.keyword("w", ast.Name("z", ast.Load()))] - stararg = ast.Name("p", ast.Load()) - kwarg = ast.Name("q", ast.Load()) - call = ast.Call(ast.Name("x", ast.Store()), args, keywords, stararg, - kwarg) + call = ast.Call(ast.Name("x", ast.Store()), args, keywords) self.expr(call, "must have Load context") - call = ast.Call(func, [None], keywords, stararg, kwarg) + call = ast.Call(func, [None], keywords) self.expr(call, "None disallowed") bad_keywords = [ast.keyword("w", ast.Name("z", ast.Store()))] - call = ast.Call(func, args, bad_keywords, stararg, kwarg) - self.expr(call, "must have Load context") - call = ast.Call(func, args, keywords, ast.Name("z", ast.Store()), kwarg) - self.expr(call, "must have Load context") - call = ast.Call(func, args, keywords, stararg, - ast.Name("w", ast.Store())) + call = ast.Call(func, args, bad_keywords) self.expr(call, "must have Load context") def test_num(self): @@ -965,6 +951,8 @@ raise SystemExit unittest.main() +main() + #### EVERYTHING BELOW IS GENERATED ##### exec_results = [ ('Module', [('Expr', (1, 0), ('NameConstant', (1, 0), None))]), @@ -973,9 +961,9 @@ ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None)], None, [], [], None, [('Num', (1, 8), 0)]), [('Pass', (1, 12))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], ('arg', (1, 7), 'args', None), [], [], None, []), [('Pass', (1, 14))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], ('arg', (1, 8), 'kwargs', None), []), [('Pass', (1, 17))], [], None)]), - ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), -('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]), -('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], None, None, [('Pass', (1, 17))], [])]), +('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), +('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])]), +('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], 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))]), @@ -985,7 +973,7 @@ ('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',)))], [('Pass', (1, 13))])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',))), ('withitem', ('Name', (1, 13), 'z', ('Load',)), ('Name', (1, 18), 'q', ('Store',)))], [('Pass', (1, 21))])]), -('Module', [('Raise', (1, 0), ('Call', (1, 15), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), +('Module', [('Raise', (1, 0), ('Call', (1, 15), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], []), None)]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [], [])]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [], [], [('Pass', (4, 2))])]), ('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]), @@ -1022,7 +1010,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, 1), ('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, 1), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2), ('Starred', (1, 11), ('Name', (1, 11), 'd', ('Load',)), ('Load',))], [('keyword', 'c', ('Num', (1, 8), 3)), ('keyword', None, ('Name', (1, 15), 'e', ('Load',)))])), ('Expression', ('Num', (1, 0), 10)), ('Expression', ('Str', (1, 0), 'string')), ('Expression', ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), @@ -1033,6 +1021,5 @@ ('Expression', ('Tuple', (1, 0), [('Num', (1, 0), 1), ('Num', (1, 2), 2), ('Num', (1, 4), 3)], ('Load',))), ('Expression', ('Tuple', (1, 1), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('Tuple', (1, 0), [], ('Load',))), -('Expression', ('Call', (1, 7), ('Attribute', (1, 6), ('Attribute', (1, 4), ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 12), ('Attribute', (1, 10), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), +('Expression', ('Call', (1, 7), ('Attribute', (1, 6), ('Attribute', (1, 4), ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 12), ('Attribute', (1, 10), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [])), ] -main() diff -r ac0d6c09457e Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/test/test_extcall.py Tue Jan 20 18:37:59 2015 -0500 @@ -34,17 +34,31 @@ (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} @@ -52,6 +66,8 @@ (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. diff -r ac0d6c09457e Lib/test/test_grammar.py --- a/Lib/test/test_grammar.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/test/test_grammar.py Tue Jan 20 18:37:59 2015 -0500 @@ -296,7 +296,7 @@ return args, kwargs self.assertEqual(f(1, x=2, *[3, 4], y=5), ((1, 3, 4), {'x':2, 'y':5})) - self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)") + self.assertEqual(f(1, *(2,3), 4), ((1, 2, 3, 4), {})) self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)") # argument annotation tests diff -r ac0d6c09457e Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/test/test_syntax.py Tue Jan 20 18:37:59 2015 -0500 @@ -582,7 +582,17 @@ subclass=IndentationError) def test_kwargs_last(self): - self._check_error("int(base=10, '2')", "non-keyword arg") + self._check_error("int(base=10, '2')", + "positional argument follows keyword argument"); + + def test_kwargs_last2(self): + self._check_error("int(**{base: 10}, '2')", + "positional argument follows " + "keyword argument unpacking"); + + def test_kwargs_last3(self): + self._check_error("int(**{base: 10}, *['2'])", + "iterable argument unpacking follows ") def test_main(): support.run_unittest(SyntaxTestCase) diff -r ac0d6c09457e Lib/test/test_unpack_ex.py --- a/Lib/test/test_unpack_ex.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Lib/test/test_unpack_ex.py Tue Jan 20 18:37:59 2015 -0500 @@ -71,6 +71,24 @@ >>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4 True +Keyword argument unpacking + +Make sure that they don't corrupt the passed-in dicts. + + >>> def f(x, y): + ... print(x, y) + ... + >>> original_dict = {'x': 'bad x'} + >>> override_dict = {'y': 'good y'} + >>> f(**original_dict, x='good', y='bad', **override_dict) + good good y + >>> (original_dict, override_dict) + ({'x': 'bad x'}, {'y': 'good y'}) + +Make sure that the initial keyword arguments are overrideable. + + >>> f(x=5, **{'x': 1}, **{'x': 3}, y=2) + Now for some failures Unpacking non-sequence @@ -131,17 +149,17 @@ >>> *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 Some size constraints (all fail.) diff -r ac0d6c09457e Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Modules/_ctypes/_ctypes.c Tue Jan 20 18:37:59 2015 -0500 @@ -3655,7 +3655,7 @@ /* We have counted the arguments we have consumed in 'inargs_index'. This must be the same as len(inargs) + len(kwds), otherwise we have - either too much or not enough arguments. */ + the wrong number of arguments. */ actual_args = PyTuple_GET_SIZE(inargs) + (kwds ? PyDict_Size(kwds) : 0); if (actual_args != inargs_index) { diff -r ac0d6c09457e Modules/parsermodule.c --- a/Modules/parsermodule.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Modules/parsermodule.c Tue Jan 20 18:37:59 2015 -0500 @@ -2732,9 +2732,6 @@ } ok = 1; if (nch-i > 0) { - /* - * argument | '*' test [',' '**' test] | '**' test - */ int sym = TYPE(CHILD(tree, i)); if (sym == argument) { @@ -2745,30 +2742,7 @@ 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 { + else { err_string("illegal arglist specification"); ok = 0; } @@ -2788,14 +2762,18 @@ int nch = NCH(tree); int res = (validate_ntype(tree, argument) && ((nch == 1) || (nch == 2) || (nch == 3))); - if (res) + + 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))); - + 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); } diff -r ac0d6c09457e Parser/Python.asdl --- a/Parser/Python.asdl Sun Jan 18 21:25:15 2015 -0800 +++ b/Parser/Python.asdl Tue Jan 20 18:37:59 2015 -0500 @@ -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(bytes s) @@ -109,8 +106,8 @@ arg = (identifier arg, expr? annotation) attributes (int lineno, int col_offset) - -- 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) diff -r ac0d6c09457e Python/Python-ast.c --- a/Python/Python-ast.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/Python-ast.c Tue Jan 20 18:37:59 2015 -0500 @@ -48,14 +48,10 @@ static PyTypeObject *ClassDef_type; _Py_IDENTIFIER(bases); _Py_IDENTIFIER(keywords); -_Py_IDENTIFIER(starargs); -_Py_IDENTIFIER(kwargs); static char *ClassDef_fields[]={ "name", "bases", "keywords", - "starargs", - "kwargs", "body", "decorator_list", }; @@ -254,8 +250,6 @@ "func", "args", "keywords", - "starargs", - "kwargs", }; static PyTypeObject *Num_type; _Py_IDENTIFIER(n); @@ -812,7 +806,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; @@ -884,7 +878,7 @@ if (!YieldFrom_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; @@ -1207,9 +1201,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) { @@ -1224,8 +1218,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; @@ -1885,8 +1877,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) { @@ -1901,8 +1893,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; @@ -2276,11 +2266,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"); @@ -2442,16 +2427,6 @@ if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.ClassDef.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); if (!value) goto failed; if (_PyObject_SetAttrId(result, &PyId_body, value) == -1) @@ -2964,16 +2939,6 @@ if (_PyObject_SetAttrId(result, &PyId_keywords, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_expr(o->v.Call.starargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_starargs, value) == -1) - goto failed; - Py_DECREF(value); - value = ast2obj_expr(o->v.Call.kwargs); - if (!value) goto failed; - if (_PyObject_SetAttrId(result, &PyId_kwargs, value) == -1) - goto failed; - Py_DECREF(value); break; case Num_kind: result = PyType_GenericNew(Num_type, NULL, NULL); @@ -3875,8 +3840,6 @@ identifier name; asdl_seq* bases; asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; asdl_seq* body; asdl_seq* decorator_list; @@ -3939,26 +3902,6 @@ PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); return 1; } - if (exists_not_none(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } else { - starargs = NULL; - } - if (exists_not_none(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } else { - kwargs = NULL; - } if (_PyObject_HasAttrId(obj, &PyId_body)) { int res; Py_ssize_t len; @@ -4007,8 +3950,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; } @@ -5506,8 +5449,6 @@ expr_ty func; asdl_seq* args; asdl_seq* keywords; - expr_ty starargs; - expr_ty kwargs; if (_PyObject_HasAttrId(obj, &PyId_func)) { int res; @@ -5568,28 +5509,7 @@ PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); return 1; } - if (exists_not_none(obj, &PyId_starargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_starargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &starargs, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } else { - starargs = NULL; - } - if (exists_not_none(obj, &PyId_kwargs)) { - int res; - tmp = _PyObject_GetAttrId(obj, &PyId_kwargs); - if (tmp == NULL) goto failed; - res = obj2ast_expr(tmp, &kwargs, arena); - if (res != 0) goto failed; - Py_CLEAR(tmp); - } 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; } @@ -6737,7 +6657,7 @@ identifier arg; expr_ty value; - if (_PyObject_HasAttrId(obj, &PyId_arg)) { + if (exists_not_none(obj, &PyId_arg)) { int res; tmp = _PyObject_GetAttrId(obj, &PyId_arg); if (tmp == NULL) goto failed; @@ -6745,8 +6665,7 @@ if (res != 0) goto failed; Py_CLEAR(tmp); } else { - PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from keyword"); - return 1; + arg = NULL; } if (_PyObject_HasAttrId(obj, &PyId_value)) { int res; @@ -7074,5 +6993,3 @@ return -1; return PyObject_IsInstance(obj, (PyObject*)&AST_type); } - - diff -r ac0d6c09457e Python/ast.c --- a/Python/ast.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/ast.c Tue Jan 20 18:37:59 2015 -0500 @@ -115,7 +115,7 @@ } if (!validate_args(args->kwonlyargs)) return 0; - if (args->kwarg && args->kwarg->annotation + if (args->kwarg && args->kwarg->annotation && !validate_expr(args->kwarg->annotation, Load)) { return 0; } @@ -233,9 +233,7 @@ case Call_kind: return validate_expr(exp->v.Call.func, Load) && validate_exprs(exp->v.Call.args, Load, 0) && - validate_keywords(exp->v.Call.keywords) && - (!exp->v.Call.starargs || validate_expr(exp->v.Call.starargs, Load)) && - (!exp->v.Call.kwargs || validate_expr(exp->v.Call.kwargs, Load)); + validate_keywords(exp->v.Call.keywords); case Num_kind: { PyObject *n = exp->v.Num.n; if (!PyLong_CheckExact(n) && !PyFloat_CheckExact(n) && @@ -320,9 +318,7 @@ return validate_body(stmt->v.ClassDef.body, "ClassDef") && validate_exprs(stmt->v.ClassDef.bases, Load, 0) && validate_keywords(stmt->v.ClassDef.keywords) && - validate_exprs(stmt->v.ClassDef.decorator_list, Load, 0) && - (!stmt->v.ClassDef.starargs || validate_expr(stmt->v.ClassDef.starargs, Load)) && - (!stmt->v.ClassDef.kwargs || validate_expr(stmt->v.ClassDef.kwargs, Load)); + validate_exprs(stmt->v.ClassDef.decorator_list, Load, 0); case Return_kind: return !stmt->v.Return.value || validate_expr(stmt->v.Return.value, Load); case Delete_kind: @@ -451,7 +447,6 @@ "None disallowed in expression list"); return 0; } - } return 1; } @@ -1444,7 +1439,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; @@ -2105,7 +2100,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 { expr_ty tmp = ast_for_call(c, CHILD(n, 1), left_expr); @@ -2422,15 +2417,14 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) { /* - arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] - | '**' test) - argument: [test '='] (test) [comp_for] # Really [keyword '='] test + arglist: argument (',' argument)* [','] + argument: ( test [comp_for] | '*' test | test '=' test | '**' test ) */ int i, nargs, nkeywords, ngens; + int ndoublestars; asdl_seq *args; asdl_seq *keywords; - expr_ty vararg = NULL, kwarg = NULL; REQ(n, arglist); @@ -2444,7 +2438,10 @@ nargs++; else if (TYPE(CHILD(ch, 1)) == comp_for) ngens++; + else if (TYPE(CHILD(ch, 0)) == STAR) + nargs++; else + /* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */ nkeywords++; } } @@ -2465,21 +2462,26 @@ keywords = _Py_asdl_seq_new(nkeywords, c->c_arena); if (!keywords) return NULL; - nargs = 0; - nkeywords = 0; + + nargs = 0; /* positional arguments + iterable argument unpackings */ + nkeywords = 0; /* keyword arguments + keyword argument unpackings */ + ndoublestars = 0; /* just keyword argument unpackings */ for (i = 0; i < NCH(n); i++) { node *ch = CHILD(n, i); if (TYPE(ch) == argument) { expr_ty e; if (NCH(ch) == 1) { + /* a positional argument */ if (nkeywords) { - ast_error(c, CHILD(ch, 0), - "non-keyword arg after keyword arg"); - return NULL; - } - if (vararg) { - ast_error(c, CHILD(ch, 0), - "only named arguments may follow *expression"); + if (ndoublestars) { + ast_error(c, CHILD(ch, 0), + "positional argument follows " + "keyword argument unpacking"); + } else { + ast_error(c, CHILD(ch, 0), + "positional argument follows " + "keyword argument"); + } return NULL; } e = ast_for_expr(c, CHILD(ch, 0)); @@ -2487,13 +2489,45 @@ return NULL; asdl_seq_SET(args, nargs++, e); } + else if (TYPE(CHILD(ch, 0)) == STAR) { + /* an iterable argument unpacking */ + node *chch = CHILD(ch, 1); + expr_ty starred; + if (ndoublestars) { + ast_error(c, chch, + "iterable argument unpacking follows " + "keyword argument unpacking"); + 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) { + /* a keyword argument unpacking */ + 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); + ndoublestars++; + } else if (TYPE(CHILD(ch, 1)) == comp_for) { + /* the lone generator expression */ e = ast_for_genexp(c, ch); if (!e) return NULL; asdl_seq_SET(args, nargs++, e); } else { + /* a keyword argument */ keyword_ty kw; identifier key, tmp; int k; @@ -2508,10 +2542,12 @@ * then is very confusing. */ if (e->kind == Lambda_kind) { - ast_error(c, CHILD(ch, 0), "lambda cannot contain assignment"); + ast_error(c, CHILD(ch, 0), + "lambda cannot contain assignment"); return NULL; } else if (e->kind != Name_kind) { - ast_error(c, CHILD(ch, 0), "keyword can't be an expression"); + ast_error(c, CHILD(ch, 0), + "keyword can't be an expression"); return NULL; } else if (forbidden_name(c, e->v.Name.id, ch, 1)) { return NULL; @@ -2519,8 +2555,9 @@ key = e->v.Name.id; for (k = 0; k < nkeywords; k++) { tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg; - if (!PyUnicode_Compare(tmp, key)) { - ast_error(c, CHILD(ch, 0), "keyword argument repeated"); + if (tmp && !PyUnicode_Compare(tmp, key)) { + ast_error(c, CHILD(ch, 0), + "keyword argument repeated"); return NULL; } } @@ -2533,21 +2570,9 @@ 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 @@ -3527,8 +3552,8 @@ return NULL; if (forbidden_name(c, classname, CHILD(n, 3), 0)) return NULL; - return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq, - LINENO(n), n->n_col_offset, c->c_arena); + return ClassDef(classname, NULL, NULL, s, decorator_seq, LINENO(n), + n->n_col_offset, c->c_arena); } if (TYPE(CHILD(n, 3)) == RPAR) { /* class NAME '(' ')' ':' suite */ @@ -3540,8 +3565,8 @@ return NULL; if (forbidden_name(c, classname, CHILD(n, 3), 0)) return NULL; - return ClassDef(classname, NULL, NULL, NULL, NULL, s, decorator_seq, - LINENO(n), n->n_col_offset, c->c_arena); + return ClassDef(classname, NULL, NULL, s, decorator_seq, LINENO(n), + n->n_col_offset, c->c_arena); } /* class NAME '(' arglist ')' ':' suite */ @@ -3566,8 +3591,7 @@ if (forbidden_name(c, classname, CHILD(n, 1), 0)) return NULL; - return ClassDef(classname, call->v.Call.args, call->v.Call.keywords, - call->v.Call.starargs, call->v.Call.kwargs, s, + return ClassDef(classname, call->v.Call.args, call->v.Call.keywords, s, decorator_seq, LINENO(n), n->n_col_offset, c->c_arena); } diff -r ac0d6c09457e Python/ceval.c --- a/Python/ceval.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/ceval.c Tue Jan 20 18:37:59 2015 -0500 @@ -2379,6 +2379,72 @@ DISPATCH(); } + TARGET(BUILD_TUPLE_UNPACK) { + PyObject *x = PyList_New(0); + PyObject *w, *v; + 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); + } + DISPATCH(); + } + + TARGET(BUILD_LIST_UNPACK) { + PyObject *x = PyList_New(0); + PyObject *w, *v; + 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); + } + DISPATCH(); + } + TARGET(BUILD_SET) { PyObject *set = PySet_New(NULL); int err = 0; @@ -2398,6 +2464,27 @@ DISPATCH(); } + TARGET(BUILD_SET_UNPACK) { + PyObject *w; + PyObject *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); + } + DISPATCH(); + } + TARGET(BUILD_MAP) { PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) @@ -2406,6 +2493,27 @@ DISPATCH(); } + TARGET(BUILD_MAP_UNPACK) { + PyObject *w; + PyObject *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); + } + DISPATCH(); + } + TARGET(STORE_MAP) { PyObject *key = TOP(); PyObject *value = SECOND(); @@ -3050,6 +3158,7 @@ goto dispatch_opcode; } + #if USE_COMPUTED_GOTOS _unknown_opcode: #endif @@ -4402,6 +4511,7 @@ PyObject *value = EXT_POP(*pp_stack); PyObject *key = EXT_POP(*pp_stack); if (PyDict_GetItem(kwdict, key) != NULL) { + /* TODO: remove this */ PyErr_Format(PyExc_TypeError, "%.200s%s got multiple values " "for keyword argument '%U'", @@ -4545,6 +4655,12 @@ 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)) { @@ -4566,11 +4682,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; diff -r ac0d6c09457e Python/compile.c --- a/Python/compile.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/compile.c Tue Jan 20 18:37:59 2015 -0500 @@ -195,9 +195,7 @@ static int compiler_with(struct compiler *, stmt_ty, int); static int compiler_call_helper(struct compiler *c, Py_ssize_t n, asdl_seq *args, - asdl_seq *keywords, - expr_ty starargs, - expr_ty kwargs); + asdl_seq *keywords); static int compiler_try_except(struct compiler *, stmt_ty); static int compiler_set_qualname(struct compiler *); @@ -973,6 +971,11 @@ case BUILD_LIST: case BUILD_SET: return 1-oparg; + case BUILD_LIST_UNPACK: + case BUILD_TUPLE_UNPACK: + case BUILD_SET_UNPACK: + case BUILD_MAP_UNPACK: + return 1-oparg; case BUILD_MAP: return 1; case LOAD_ATTR: @@ -1821,9 +1824,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 */ @@ -2871,6 +2872,40 @@ return 1; } + 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) { @@ -2897,10 +2932,11 @@ 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; } @@ -2930,14 +2966,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) { Py_ssize_t i, n; @@ -2988,9 +3032,7 @@ 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 */ @@ -2998,26 +3040,111 @@ compiler_call_helper(struct compiler *c, Py_ssize_t n, /* 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; + int top_dict_is_local; + + int nelts; + int i, nsubitems, nseen, nkw = 0; + nsubitems = 0; /* the number of tuples on the stack */ + nseen = 0; /* the number of positional arguments on the stack */ + 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 we've seen positional arguments, + 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 arguments before star-arguments + are left on the stack. */ + VISIT(c, expr, elt); + n++; + } } - if (starargs) { - VISIT(c, expr, starargs); + 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; } - if (kwargs) { - VISIT(c, expr, kwargs); + else if (nsubitems) { + code |= 1; + } + /* Same dance again for keyword arguments */ + top_dict_is_local = 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 keyword argument unpacking. */ + top_dict_is_local = 0; + VISIT(c, expr, kw->value); + nsubitems++; + } + else if (nsubitems) { + /* A keyword argument and we already have a dict. + * Create a dict if the top dict was passed in and we can't + * modify it. */ + if (!top_dict_is_local) { + ADDOP_I(c, BUILD_MAP, 1); + nsubitems++; + top_dict_is_local = 1; + } + /* roll these into the top dictionary */ + /* This code would be a lot simpler if we had + a BUILD_MAP opcode that acted like BUILD_LIST */ + /* 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 { + /* keyword argument */ + VISIT(c, keyword, kw) + nkw++; + } + } + 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); @@ -3061,7 +3188,9 @@ comprehension_ty gen; basicblock *start, *anchor, *skip, *if_cleanup; + basicblock *innerstart, *inneranchor; Py_ssize_t i, n; + int is_star = 0; start = compiler_new_block(c); skip = compiler_new_block(c); @@ -3104,21 +3233,42 @@ 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); + gen_index++; + } + /* comprehension specific code */ switch (type) { case COMP_GENEXP: - VISIT(c, expr, elt); ADDOP(c, YIELD_VALUE); ADDOP(c, POP_TOP); break; case COMP_LISTCOMP: - VISIT(c, expr, elt); + //ADDOP(c, ROT_TWO); ADDOP_I(c, LIST_APPEND, gen_index + 1); break; case COMP_SETCOMP: - VISIT(c, expr, elt); + //ADDOP(c, ROT_TWO); ADDOP_I(c, SET_ADD, gen_index + 1); break; case COMP_DICTCOMP: @@ -3131,6 +3281,11 @@ default: return 0; } + if (is_star) { + gen_index--; + ADDOP_JABS(c, JUMP_ABSOLUTE, innerstart); + compiler_use_next_block(c, inneranchor); + } compiler_use_next_block(c, skip); } @@ -3441,10 +3596,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: @@ -3555,7 +3707,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: diff -r ac0d6c09457e Python/graminit.c --- a/Python/graminit.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/graminit.c Tue Jan 20 18:37:59 2015 -0500 @@ -1660,64 +1660,40 @@ {1, arcs_73_6}, {1, arcs_73_7}, }; -static arc arcs_74_0[3] = { +static arc arcs_74_0[1] = { {164, 1}, - {31, 2}, - {32, 3}, }; static arc arcs_74_1[2] = { - {30, 4}, + {30, 2}, {0, 1}, }; -static arc arcs_74_2[1] = { - {24, 5}, +static arc arcs_74_2[2] = { + {164, 1}, + {0, 2}, }; -static arc arcs_74_3[1] = { - {24, 6}, +static state states_74[3] = { + {1, arcs_74_0}, + {2, arcs_74_1}, + {2, arcs_74_2}, }; -static arc arcs_74_4[4] = { - {164, 1}, +static arc arcs_75_0[3] = { + {24, 1}, {31, 2}, - {32, 3}, - {0, 4}, -}; -static arc arcs_74_5[2] = { - {30, 7}, - {0, 5}, -}; -static arc arcs_74_6[1] = { - {0, 6}, -}; -static arc arcs_74_7[2] = { - {164, 5}, - {32, 3}, -}; -static state states_74[8] = { - {3, arcs_74_0}, - {2, arcs_74_1}, - {1, arcs_74_2}, - {1, arcs_74_3}, - {4, arcs_74_4}, - {2, arcs_74_5}, - {1, arcs_74_6}, - {2, arcs_74_7}, -}; -static arc arcs_75_0[1] = { - {24, 1}, + {32, 2}, }; static arc arcs_75_1[3] = { - {159, 2}, - {29, 3}, + {159, 3}, + {29, 2}, {0, 1}, }; static arc arcs_75_2[1] = { - {0, 2}, + {24, 3}, }; static arc arcs_75_3[1] = { - {24, 2}, + {0, 3}, }; static state states_75[4] = { - {1, arcs_75_0}, + {3, arcs_75_0}, {3, arcs_75_1}, {1, arcs_75_2}, {1, arcs_75_3}, @@ -1968,10 +1944,10 @@ "\000\040\040\000\000\000\000\000\000\000\001\000\000\000\041\000\000\014\241\174\000\000"}, {329, "classdef", 0, 8, states_73, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000"}, - {330, "arglist", 0, 8, states_74, + {330, "arglist", 0, 3, states_74, "\000\040\040\200\001\000\000\000\000\000\001\000\000\000\041\000\000\014\241\174\000\000"}, {331, "argument", 0, 4, states_75, - "\000\040\040\000\000\000\000\000\000\000\001\000\000\000\041\000\000\014\241\174\000\000"}, + "\000\040\040\200\001\000\000\000\000\000\001\000\000\000\041\000\000\014\241\174\000\000"}, {332, "comp_iter", 0, 2, states_76, "\000\000\000\000\000\000\000\000\000\000\000\040\002\000\000\000\000\000\000\000\000\000"}, {333, "comp_for", 0, 6, states_77, diff -r ac0d6c09457e Python/opcode_targets.h --- a/Python/opcode_targets.h Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/opcode_targets.h Tue Jan 20 18:37:59 2015 -0500 @@ -148,10 +148,10 @@ &&TARGET_SET_ADD, &&TARGET_MAP_ADD, &&TARGET_LOAD_CLASSDEREF, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_BUILD_LIST_UNPACK, + &&TARGET_BUILD_MAP_UNPACK, + &&TARGET_BUILD_TUPLE_UNPACK, + &&TARGET_BUILD_SET_UNPACK, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff -r ac0d6c09457e Python/symtable.c --- a/Python/symtable.c Sun Jan 18 21:25:15 2015 -0800 +++ b/Python/symtable.c Tue Jan 20 18:37:59 2015 -0500 @@ -1201,10 +1201,6 @@ VISIT_QUIT(st, 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, @@ -1452,10 +1448,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: diff -r ac0d6c09457e Tools/parser/unparse.py --- a/Tools/parser/unparse.py Sun Jan 18 21:25:15 2015 -0800 +++ b/Tools/parser/unparse.py Tue Jan 20 18:37:59 2015 -0500 @@ -211,16 +211,6 @@ if comma: self.write(", ") else: comma = True self.dispatch(e) - if t.starargs: - if comma: self.write(", ") - else: comma = True - self.write("*") - self.dispatch(t.starargs) - if t.kwargs: - if comma: self.write(", ") - else: comma = True - self.write("**") - self.dispatch(t.kwargs) self.write(")") self.enter() @@ -450,16 +440,6 @@ if comma: self.write(", ") else: comma = True self.dispatch(e) - if t.starargs: - if comma: self.write(", ") - else: comma = True - self.write("*") - self.dispatch(t.starargs) - if t.kwargs: - if comma: self.write(", ") - else: comma = True - self.write("**") - self.dispatch(t.kwargs) self.write(")") def _Subscript(self, t): @@ -543,8 +523,11 @@ self.dispatch(t.kwarg.annotation) def _keyword(self, t): - self.write(t.arg) - self.write("=") + if t.arg is None: + self.write("**") + else: + self.write(t.arg) + self.write("=") self.dispatch(t.value) def _Lambda(self, t):