]> granicus.if.org Git - python/commitdiff
slightly modified version of Greg Ewing's extended call syntax patch
authorJeremy Hylton <jeremy@alum.mit.edu>
Tue, 28 Mar 2000 23:49:17 +0000 (23:49 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Tue, 28 Mar 2000 23:49:17 +0000 (23:49 +0000)
executive summary:
Instead of typing 'apply(f, args, kwargs)' you can type 'f(*arg, **kwargs)'.
Some file-by-file details follow.

Grammar/Grammar:
    simplify varargslist, replacing '*' '*' with '**'
    add * & ** options to arglist

Include/opcode.h & Lib/dis.py:
    define three new opcodes
        CALL_FUNCTION_VAR
        CALL_FUNCTION_KW
        CALL_FUNCTION_VAR_KW

Python/ceval.c:
    extend TypeError "keyword parameter redefined" message to include
        the name of the offending keyword
    reindent CALL_FUNCTION using four spaces
    add handling of sequences and dictionaries using extend calls
    fix function import_from to use PyErr_Format

Grammar/Grammar
Include/opcode.h
Lib/dis.py
Misc/ACKS
Python/ceval.c
Python/compile.c
Python/graminit.c

index dabf88e5aaa52af3f717df3f96bed3d706640f8f..57a39de2f0011235225b60f301734f0284a8731e 100644 (file)
@@ -23,7 +23,7 @@ eval_input: testlist NEWLINE* ENDMARKER
 
 funcdef: 'def' NAME parameters ':' suite
 parameters: '(' [varargslist] ')'
-varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] | ('**'|'*' '*') NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
 fpdef: NAME | '(' fplist ')'
 fplist: fpdef (',' fpdef)* [',']
 
@@ -86,5 +86,5 @@ dictmaker: test ':' test (',' test ':' test)* [',']
 
 classdef: 'class' NAME ['(' testlist ')'] ':' suite
 
-arglist:  argument (',' argument)* [',']
+arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
 argument: [test '='] test      # Really [keyword '='] test
index 8b6890fe27932431933cd42a77308376206949c3..0e15497e088c5c3e1e270d6d2551e40b0847ef2a 100644 (file)
@@ -138,10 +138,17 @@ PERFORMANCE OF THIS SOFTWARE.
    for new opcodes. */
 
 #define RAISE_VARARGS  130     /* Number of raise arguments (1, 2 or 3) */
+/* CALL_FUNCTION_XXX opcodes defined below depend on this definition */
 #define CALL_FUNCTION  131     /* #args + (#kwargs<<8) */
 #define MAKE_FUNCTION  132     /* #defaults */
 #define BUILD_SLICE    133     /* Number of items */
 
+/* The next 3 opcodes must be contiguous and satisfy
+   (CALL_FUNCTION_STAR - CALL_FUNCTION) & 3 == 1  */
+#define CALL_FUNCTION_VAR          140 /* #args + (#kwargs<<8) */
+#define CALL_FUNCTION_KW           141 /* #args + (#kwargs<<8) */
+#define CALL_FUNCTION_VAR_KW       142 /* #args + (#kwargs<<8) */
+
 /* Comparison operator codes (argument to COMPARE_OP) */
 enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD};
 
index 4c6764209cbd78c85be29af110e6fdf99edc2203..899393d3acdbc893387ff2f584f478a86e128ea5 100644 (file)
@@ -247,10 +247,14 @@ haslocal.append(126)
 def_op('SET_LINENO', 127)      # Current line number
 SET_LINENO = 127
 
-def_op('RAISE_VARARGS', 130)
-def_op('CALL_FUNCTION', 131)
-def_op('MAKE_FUNCTION', 132)
-def_op('BUILD_SLICE', 133)
+def_op('RAISE_VARARGS', 130)    # Number of raise arguments (1, 2, or 3)
+def_op('CALL_FUNCTION', 131)    # #args + (#kwargs << 8)
+def_op('MAKE_FUNCTION', 132)    # Number of args with default values
+def_op('BUILD_SLICE', 133)      # Number of items
+
+def_op('CALL_FUNCTION_VAR', 140)     # #args + (#kwargs << 8)
+def_op('CALL_FUNCTION_KW', 141)      # #args + (#kwargs << 8)
+def_op('CALL_FUNCTION_VAR_KW', 142)  # #args + (#kwargs << 8)
 
 
 def _test():
index 3fe3a908c819e2cea4b48e835480ceb62fd7183a..82bd3e5ef723cdf03fec1d60dd1cc90785f5765b 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -87,6 +87,7 @@ Stefan Esser
 Carey Evans
 Tim Everett
 Paul Everitt
+Greg Ewing
 Mark Favas
 Niels Ferguson
 Sebastian Fernandez
index 46a60f1173c9961447a92a9d152fe497016131e4..7a97771327b5bed6f3f896ee5ab2d8f18ed1cc86 100644 (file)
@@ -499,15 +499,16 @@ eval_code2(co, globals, locals,
                                if (kwdict == NULL) {
                                        PyErr_Format(PyExc_TypeError,
                                         "unexpected keyword argument: %.400s",
-                                        PyString_AsString(keyword));
+                                           PyString_AsString(keyword));
                                        goto fail;
                                }
                                PyDict_SetItem(kwdict, keyword, value);
                        }
                        else {
                                if (GETLOCAL(j) != NULL) {
-                                       PyErr_SetString(PyExc_TypeError,
-                                               "keyword parameter redefined");
+                                       PyErr_Format(PyExc_TypeError, 
+                                    "keyword parameter redefined: %.400s",
+                                            PyString_AsString(keyword));
                                        goto fail;
                                }
                                Py_INCREF(value);
@@ -1548,125 +1549,166 @@ eval_code2(co, globals, locals,
                        break;
 
                case CALL_FUNCTION:
+               case CALL_FUNCTION_VAR:
+               case CALL_FUNCTION_KW:
+               case CALL_FUNCTION_VAR_KW:
                {
-                       int na = oparg & 0xff;
-                       int nk = (oparg>>8) & 0xff;
-                       int n = na + 2*nk;
-                       PyObject **pfunc = stack_pointer - n - 1;
-                       PyObject *func = *pfunc;
-                       PyObject *self = NULL;
-                       PyObject *class = NULL;
-                       f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
-                       if (PyMethod_Check(func)) {
-                               self = PyMethod_Self(func);
-                               class = PyMethod_Class(func);
-                               func = PyMethod_Function(func);
-                               Py_INCREF(func);
-                               if (self != NULL) {
-                                       Py_INCREF(self);
-                                       Py_DECREF(*pfunc);
-                                       *pfunc = self;
-                                       na++;
-                                       n++;
-                               }
-                               else {
-                                       /* Unbound methods must be
-                                          called with an instance of
-                                          the class (or a derived
-                                          class) as first argument */
-                                       if (na > 0 &&
-                                           (self = stack_pointer[-n])
-                                               != NULL &&
-                                           PyInstance_Check(self) &&
-                                           PyClass_IsSubclass(
-                                                   (PyObject *)
-                                                   (((PyInstanceObject *)self)
-                                                    ->in_class),
-                                                   class))
-                                               /* Handy-dandy */ ;
-                                       else {
-                                               PyErr_SetString(
-                                                       PyExc_TypeError,
-          "unbound method must be called with class instance 1st argument");
-                                               x = NULL;
-                                               break;
-                                       }
-                               }
+                   int na = oparg & 0xff;
+                   int nk = (oparg>>8) & 0xff;
+                   int flags = (opcode - CALL_FUNCTION) & 3;
+                   int n = na + 2*nk + (flags & 1) + ((flags >> 1) & 1);
+                   PyObject **pfunc = stack_pointer - n - 1;
+                   PyObject *func = *pfunc;
+                   PyObject *self = NULL;
+                   PyObject *class = NULL;
+                   f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
+                   if (PyMethod_Check(func)) {
+                       self = PyMethod_Self(func);
+                       class = PyMethod_Class(func);
+                       func = PyMethod_Function(func);
+                       Py_INCREF(func);
+                       if (self != NULL) {
+                           Py_INCREF(self);
+                           Py_DECREF(*pfunc);
+                           *pfunc = self;
+                           na++;
+                           n++;
                        }
-                       else
-                               Py_INCREF(func);
-                       if (PyFunction_Check(func)) {
-                               PyObject *co = PyFunction_GetCode(func);
-                               PyObject *globals =
-                                       PyFunction_GetGlobals(func);
-                               PyObject *argdefs =
-                                       PyFunction_GetDefaults(func);
-                               PyObject **d;
-                               int nd;
-                               if (argdefs != NULL) {
-                                       d = &PyTuple_GET_ITEM(argdefs, 0);
-                                       nd = ((PyTupleObject *)argdefs) ->
-                                               ob_size;
-                               }
-                               else {
-                                       d = NULL;
-                                       nd = 0;
-                               }
-                               x = eval_code2(
-                                       (PyCodeObject *)co,
-                                       globals, (PyObject *)NULL,
-                                       stack_pointer-n, na,
-                                       stack_pointer-2*nk, nk,
-                                       d, nd,
-                                       class);
+                       else {
+                           /* Unbound methods must be called with an
+                              instance of the class (or a derived
+                              class) as first argument */ 
+                           if (na > 0 && (self = stack_pointer[-n]) != NULL 
+                               && PyInstance_Check(self) 
+                               && PyClass_IsSubclass((PyObject *)
+                                   (((PyInstanceObject *)self)->in_class),
+                                                     class))
+                                  /* Handy-dandy */ ;
+                           else {
+                               PyErr_SetString(PyExc_TypeError,
+           "unbound method must be called with class instance 1st argument");
+                               x = NULL;
+                               break;
+                           }
+                       }
+                   }
+                   else
+                       Py_INCREF(func);
+                   if (PyFunction_Check(func) && flags == 0) {
+                       PyObject *co = PyFunction_GetCode(func);
+                       PyObject *globals = PyFunction_GetGlobals(func);
+                       PyObject *argdefs = PyFunction_GetDefaults(func);
+                       PyObject **d;
+                       int nd;
+                       if (argdefs != NULL) {
+                           d = &PyTuple_GET_ITEM(argdefs, 0);
+                           nd = ((PyTupleObject *)argdefs)->ob_size;
                        }
                        else {
-                               PyObject *args = PyTuple_New(na);
-                               PyObject *kwdict = NULL;
-                               if (args == NULL) {
-                                       x = NULL;
-                                       break;
-                               }
-                               if (nk > 0) {
-                                       kwdict = PyDict_New();
-                                       if (kwdict == NULL) {
-                                               x = NULL;
-                                               break;
-                                       }
-                                       err = 0;
-                                       while (--nk >= 0) {
-                                               PyObject *value = POP();
-                                               PyObject *key = POP();
-                                               err = PyDict_SetItem(
-                                                       kwdict, key, value);
-                                               Py_DECREF(key);
-                                               Py_DECREF(value);
-                                               if (err)
-                                                       break;
-                                       }
-                                       if (err) {
-                                               Py_DECREF(args);
-                                               Py_DECREF(kwdict);
-                                               break;
-                                       }
+                           d = NULL;
+                           nd = 0;
+                       }
+                       x = eval_code2((PyCodeObject *)co, globals, 
+                                      (PyObject *)NULL, stack_pointer-n, na,
+                                      stack_pointer-2*nk, nk, d, nd,
+                                      class);
+                   }
+                   else {
+                       int nstar = 0;
+                       PyObject *args;
+                       PyObject *stararg = 0;
+                       PyObject *kwdict = NULL;
+                       if (flags & 2) {
+                           kwdict = POP();
+                           if (!PyDict_Check(kwdict)) {
+                               PyErr_SetString(PyExc_TypeError,
+                                       "** argument must be a dictionary");
+                               x = NULL;
+                               break;
+                           }
+                       }
+                       if (flags & 1) {
+                           stararg = POP();
+                           if (!PySequence_Check(stararg)) {
+                               PyErr_SetString(PyExc_TypeError,
+                                       "* argument must be a sequence");
+                               x = NULL;
+                               break;
+                           }
+                           nstar = PySequence_Length(stararg);
+                       }
+                       if (nk > 0) {
+                           if (kwdict == NULL) {
+                               kwdict = PyDict_New();
+                               if (kwdict == NULL) {
+                                   x = NULL;
+                                   break;
                                }
-                               while (--na >= 0) {
-                                       w = POP();
-                                       PyTuple_SET_ITEM(args, na, w);
+                           }
+                           err = 0;
+                           while (--nk >= 0) {
+                               PyObject *value = POP();
+                               PyObject *key = POP();
+                               if (PyDict_GetItem(kwdict, key) != NULL) {
+                                   err = 1;
+                                   PyErr_Format(PyExc_TypeError,
+                                       "keyword parameter redefined: %.400s",
+                                                PyString_AsString(key));
+                                   break;
                                }
-                               x = PyEval_CallObjectWithKeywords(
-                                       func, args, kwdict);
+                               err = PyDict_SetItem(kwdict, key, value);
+                               Py_DECREF(key);
+                               Py_DECREF(value);
+                               if (err)
+                                   break;
+                           }
+                           if (err) {
                                Py_DECREF(args);
-                               Py_XDECREF(kwdict);
-                       }
-                       Py_DECREF(func);
-                       while (stack_pointer > pfunc) {
-                               w = POP();
-                               Py_DECREF(w);
-                       }
-                       PUSH(x);
-                       if (x != NULL) continue;
-                       break;
+                               Py_DECREF(kwdict);
+                               break;
+                           }
+                       }
+                       args = PyTuple_New(na + nstar);
+                       if (args == NULL) {
+                           x = NULL;
+                           break;
+                       }
+                       if (stararg) {
+                           PyObject *t = NULL;
+                           int i;
+                           if (!PyTuple_Check(stararg)) {
+                               /* must be sequence to pass earlier test */
+                               t = PySequence_Tuple(stararg);
+                               if (t == NULL) {
+                                   x = NULL;
+                                   break;
+                               }
+                               Py_DECREF(stararg);
+                               stararg = t;
+                           }
+                           for (i = 0; i < nstar; i++) {
+                               PyObject *a = PyTuple_GET_ITEM(stararg, i);
+                               Py_INCREF(a);
+                               PyTuple_SET_ITEM(args, na + i, a);
+                           }
+                           Py_DECREF(stararg);
+                       }
+                       while (--na >= 0) {
+                           w = POP();
+                           PyTuple_SET_ITEM(args, na, w);
+                       }
+                       x = PyEval_CallObjectWithKeywords(func, args, kwdict);
+                       Py_DECREF(args);
+                       Py_XDECREF(kwdict);
+                   }
+                   Py_DECREF(func);
+                   while (stack_pointer > pfunc) {
+                       w = POP();
+                       Py_DECREF(w);
+                   }
+                   PUSH(x);
+                   if (x != NULL) continue;
+                   break;
                }
                
                case MAKE_FUNCTION:
@@ -2687,10 +2729,9 @@ import_from(locals, v, name)
        else {
                x = PyDict_GetItem(w, name);
                if (x == NULL) {
-                       char buf[250];
-                       sprintf(buf, "cannot import name %.230s",
-                               PyString_AsString(name));
-                       PyErr_SetString(PyExc_ImportError, buf);
+                       PyErr_Format(PyExc_ImportError, 
+                                    "cannot import name %.230s",
+                                    PyString_AsString(name));
                        return -1;
                }
                else
index 72848fae363935e4fe3a53521cc674f37cd34181..1eed7c06b2a5c6bc88c7b3b83692bdb99ea5f893 100644 (file)
@@ -1185,11 +1185,17 @@ com_call_function(c, n)
                PyObject *keywords = NULL;
                int i, na, nk;
                int lineno = n->n_lineno;
+               int star_flag = 0;
+               int starstar_flag = 0;
+               int opcode;
                REQ(n, arglist);
                na = 0;
                nk = 0;
                for (i = 0; i < NCH(n); i += 2) {
                        node *ch = CHILD(n, i);
+                       if (TYPE(ch) == STAR ||
+                           TYPE(ch) == DOUBLESTAR)
+                         break;
                        if (ch->n_lineno != lineno) {
                                lineno = ch->n_lineno;
                                com_addoparg(c, SET_LINENO, lineno);
@@ -1201,12 +1207,27 @@ com_call_function(c, n)
                                nk++;
                }
                Py_XDECREF(keywords);
+               while (i < NCH(n)) {
+                   node *tok = CHILD(n, i);
+                   node *ch = CHILD(n, i+1);
+                   i += 3;
+                   switch (TYPE(tok)) {
+                   case STAR:       star_flag = 1;     break;
+                   case DOUBLESTAR: starstar_flag = 1; break;
+                   }
+                   com_node(c, ch);
+               }
                if (na > 255 || nk > 255) {
                        com_error(c, PyExc_SyntaxError,
                                  "more than 255 arguments");
                }
-               com_addoparg(c, CALL_FUNCTION, na | (nk << 8));
-               com_pop(c, na + 2*nk);
+               if (star_flag || starstar_flag)
+                   opcode = CALL_FUNCTION_STAR - 1 + 
+                       star_flag + (starstar_flag << 1);
+               else
+                   opcode = CALL_FUNCTION;
+               com_addoparg(c, opcode, na | (nk << 8));
+               com_pop(c, na + 2*nk + star_flag + starstar_flag);
        }
 }
 
index ba9359e839224d9a7e4924691e44ff31a16ca3d1..35d8de4ee134c56beca3bcf46819dcd3c640344e 100644 (file)
@@ -98,9 +98,8 @@ static arc arcs_5_1[3] = {
        {22, 5},
        {0, 1},
 };
-static arc arcs_5_2[2] = {
+static arc arcs_5_2[1] = {
        {12, 6},
-       {23, 3},
 };
 static arc arcs_5_3[1] = {
        {12, 7},
@@ -125,25 +124,20 @@ static arc arcs_5_8[2] = {
        {22, 5},
        {0, 8},
 };
-static arc arcs_5_9[2] = {
+static arc arcs_5_9[1] = {
        {24, 3},
-       {23, 10},
 };
-static arc arcs_5_10[1] = {
-       {23, 3},
-};
-static state states_5[11] = {
+static state states_5[10] = {
        {3, arcs_5_0},
        {3, arcs_5_1},
-       {2, arcs_5_2},
+       {1, arcs_5_2},
        {1, arcs_5_3},
        {1, arcs_5_4},
        {4, arcs_5_5},
        {2, arcs_5_6},
        {1, arcs_5_7},
        {2, arcs_5_8},
-       {2, arcs_5_9},
-       {1, arcs_5_10},
+       {1, arcs_5_9},
 };
 static arc arcs_6_0[2] = {
        {12, 1},
@@ -1169,21 +1163,46 @@ static state states_54[8] = {
        {1, arcs_54_6},
        {1, arcs_54_7},
 };
-static arc arcs_55_0[1] = {
+static arc arcs_55_0[3] = {
        {123, 1},
+       {23, 2},
+       {24, 3},
 };
 static arc arcs_55_1[2] = {
-       {22, 2},
+       {22, 4},
        {0, 1},
 };
-static arc arcs_55_2[2] = {
+static arc arcs_55_2[1] = {
+       {21, 5},
+};
+static arc arcs_55_3[1] = {
+       {21, 6},
+};
+static arc arcs_55_4[4] = {
        {123, 1},
-       {0, 2},
+       {23, 2},
+       {24, 3},
+       {0, 4},
+};
+static arc arcs_55_5[2] = {
+       {22, 7},
+       {0, 5},
 };
-static state states_55[3] = {
-       {1, arcs_55_0},
+static arc arcs_55_6[1] = {
+       {0, 6},
+};
+static arc arcs_55_7[1] = {
+       {24, 3},
+};
+static state states_55[8] = {
+       {3, arcs_55_0},
        {2, arcs_55_1},
-       {2, arcs_55_2},
+       {1, arcs_55_2},
+       {1, arcs_55_3},
+       {4, arcs_55_4},
+       {2, arcs_55_5},
+       {1, arcs_55_6},
+       {1, arcs_55_7},
 };
 static arc arcs_56_0[1] = {
        {21, 1},
@@ -1215,7 +1234,7 @@ static dfa dfas[57] = {
         "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {260, "parameters", 0, 4, states_4,
         "\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000"},
-       {261, "varargslist", 0, 11, states_5,
+       {261, "varargslist", 0, 10, states_5,
         "\000\020\201\001\000\000\000\000\000\000\000\000\000\000\000\000"},
        {262, "fpdef", 0, 4, states_6,
         "\000\020\001\000\000\000\000\000\000\000\000\000\000\000\000\000"},
@@ -1315,8 +1334,8 @@ static dfa dfas[57] = {
         "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"},
        {310, "classdef", 0, 8, states_54,
         "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004"},
-       {311, "arglist", 0, 3, states_55,
-        "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"},
+       {311, "arglist", 0, 8, states_55,
+        "\000\020\201\001\000\000\000\000\000\200\000\000\060\242\074\000"},
        {312, "argument", 0, 4, states_56,
         "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"},
 };