From e42b18f9d1fca06df34d9fcbd54a2a6045329197 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Mon, 25 Aug 1997 22:13:04 +0000 Subject: [PATCH] eval_code2(): collapsed the implementations of UNPACK_TUPLE and UNPACK_LIST byte codes and added a third code path that allows generalized sequence unpacking. Now both syntaxes: a, b, c = seq [a, b, c] = seq can be used to unpack any sequence with the exact right number of items. unpack_sequence(): out-lined implementation of generalized sequence unpacking. tuple and list unpacking are still inlined. --- Python/ceval.c | 109 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 4c7a9585b5e..e08e1c972fb 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -312,6 +312,7 @@ enum why_code { }; static enum why_code do_raise Py_PROTO((PyObject *, PyObject *, PyObject *)); +static int unpack_sequence Py_PROTO((PyObject *, int, PyObject **)); /* Backward compatible interface */ @@ -1182,45 +1183,47 @@ eval_code2(co, globals, locals, #endif case UNPACK_TUPLE: - v = POP(); - if (!PyTuple_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "unpack non-tuple"); - why = WHY_EXCEPTION; - } - else if (PyTuple_Size(v) != oparg) { - PyErr_SetString(PyExc_ValueError, - "unpack tuple of wrong size"); - why = WHY_EXCEPTION; - } - else { - for (; --oparg >= 0; ) { - w = PyTuple_GET_ITEM(v, oparg); - Py_INCREF(w); - PUSH(w); - } - } - Py_DECREF(v); - break; - case UNPACK_LIST: v = POP(); - if (!PyList_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "unpack non-list"); - why = WHY_EXCEPTION; + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyTuple_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } } - else if (PyList_Size(v) != oparg) { - PyErr_SetString(PyExc_ValueError, - "unpack list of wrong size"); - why = WHY_EXCEPTION; + else if (PyList_Check(v)) { + if (PyList_Size(v) != oparg) { + PyErr_SetString(PyExc_ValueError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = PyList_GET_ITEM(v, oparg); + Py_INCREF(w); + PUSH(w); + } + } + } + else if (PySequence_Check(v)) { + if (unpack_sequence(v, oparg, + stack_pointer + oparg)) + stack_pointer += oparg; + else + why = WHY_EXCEPTION; } else { - for (; --oparg >= 0; ) { - w = PyList_GetItem(v, oparg); - Py_INCREF(w); - PUSH(w); - } + PyErr_SetString(PyExc_TypeError, + "unpack non-sequence"); + why = WHY_EXCEPTION; } Py_DECREF(v); break; @@ -2042,6 +2045,44 @@ do_raise(type, value, tb) return WHY_EXCEPTION; } +static int +unpack_sequence(v, argcnt, sp) + PyObject *v; + int argcnt; + PyObject **sp; +{ + int i; + PyObject *w; + + for (i = 0; i < argcnt; i++) { + if (! (w = PySequence_GetItem(v, i))) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + goto finally; + } + *--sp = w; + } + /* we better get an IndexError now */ + if (PySequence_GetItem(v, i) == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; + } + /* some other exception occurred. fall through to finally */ + } + else + PyErr_SetString(PyExc_ValueError, + "unpack sequence of wrong size"); + /* fall through */ +finally: + for (; i > 0; i--) + Py_DECREF(*sp++); + + return 0; +} + + #ifdef LLTRACE static int prtrace(v, str)