PEP 448: additional unpacking generalizations (closes #2292)

Patch by Neil Girdhar.
This commit is contained in:
Benjamin Peterson 2015-05-05 20:16:41 -04:00
parent 4ccc1514d0
commit 025e9ebd0a
26 changed files with 2664 additions and 2118 deletions

View file

@ -12,8 +12,10 @@
#include "Python.h"
#include "code.h"
#include "dictobject.h"
#include "frameobject.h"
#include "opcode.h"
#include "setobject.h"
#include "structmember.h"
#include <ctype.h>
@ -2379,6 +2381,43 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET_WITH_IMPL(BUILD_TUPLE_UNPACK, _build_list_unpack)
TARGET(BUILD_LIST_UNPACK)
_build_list_unpack: {
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
int i;
PyObject *sum = PyList_New(0);
PyObject *return_value;
if (sum == NULL)
goto error;
for (i = oparg; i > 0; i--) {
PyObject *none_val;
none_val = _PyList_Extend((PyListObject *)sum, PEEK(i));
if (none_val == NULL) {
Py_DECREF(sum);
goto error;
}
Py_DECREF(none_val);
}
if (convert_to_tuple) {
return_value = PyList_AsTuple(sum);
Py_DECREF(sum);
if (return_value == NULL)
goto error;
}
else {
return_value = sum;
}
while (oparg--)
Py_DECREF(POP());
PUSH(return_value);
DISPATCH();
}
TARGET(BUILD_SET) {
PyObject *set = PySet_New(NULL);
int err = 0;
@ -2398,14 +2437,127 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET(BUILD_SET_UNPACK) {
int i;
PyObject *sum = PySet_New(NULL);
if (sum == NULL)
goto error;
for (i = oparg; i > 0; i--) {
if (_PySet_Update(sum, PEEK(i)) < 0) {
Py_DECREF(sum);
goto error;
}
}
while (oparg--)
Py_DECREF(POP());
PUSH(sum);
DISPATCH();
}
TARGET(BUILD_MAP) {
PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
if (map == NULL)
goto error;
while (--oparg >= 0) {
int err;
PyObject *key = TOP();
PyObject *value = SECOND();
STACKADJ(-2);
err = PyDict_SetItem(map, key, value);
Py_DECREF(value);
Py_DECREF(key);
if (err != 0) {
Py_DECREF(map);
goto error;
}
}
PUSH(map);
DISPATCH();
}
TARGET_WITH_IMPL(BUILD_MAP_UNPACK_WITH_CALL, _build_map_unpack)
TARGET(BUILD_MAP_UNPACK)
_build_map_unpack: {
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
int num_maps;
int function_location;
int i;
PyObject *sum = PyDict_New();
if (sum == NULL)
goto error;
if (with_call) {
num_maps = oparg & 0xff;
function_location = (oparg>>8) & 0xff;
}
else {
num_maps = oparg;
}
for (i = num_maps; i > 0; i--) {
PyObject *arg = PEEK(i);
if (with_call) {
PyObject *intersection = _PyDictView_Intersect(sum, arg);
if (intersection == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyObject *func = (
PEEK(function_location + num_maps));
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after ** "
"must be a mapping, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
arg->ob_type->tp_name);
}
Py_DECREF(sum);
goto error;
}
if (PySet_GET_SIZE(intersection)) {
Py_ssize_t idx = 0;
PyObject *key;
PyObject *func = PEEK(function_location + num_maps);
Py_hash_t hash;
_PySet_NextEntry(intersection, &idx, &key, &hash);
if (!PyUnicode_Check(key)) {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s keywords must be strings",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func));
} else {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s got multiple "
"values for keyword argument '%U'",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
key);
}
Py_DECREF(intersection);
Py_DECREF(sum);
goto error;
}
Py_DECREF(intersection);
}
if (PyDict_Update(sum, arg) < 0) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_TypeError,
"'%.200s' object is not a mapping",
arg->ob_type->tp_name);
}
Py_DECREF(sum);
goto error;
}
}
while (num_maps--)
Py_DECREF(POP());
PUSH(sum);
DISPATCH();
}
TARGET(STORE_MAP) {
PyObject *key = TOP();
PyObject *value = SECOND();
@ -3050,6 +3202,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto dispatch_opcode;
}
#if USE_COMPUTED_GOTOS
_unknown_opcode:
#endif
@ -4557,6 +4710,12 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
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)) {
@ -4578,11 +4737,6 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
}
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;