From 7690151c7e95f38b91a9c572ce29b4d8a4ca671d Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Tue, 28 Mar 2000 23:49:17 +0000 Subject: slightly modified version of Greg Ewing's extended call syntax patch 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 | 4 +- Include/opcode.h | 7 ++ Lib/dis.py | 12 ++- Misc/ACKS | 1 + Python/ceval.c | 279 +++++++++++++++++++++++++++++++----------------------- Python/compile.c | 25 ++++- Python/graminit.c | 61 ++++++++---- 7 files changed, 241 insertions(+), 148 deletions(-) diff --git a/Grammar/Grammar b/Grammar/Grammar index dabf88e..57a39de 100644 --- a/Grammar/Grammar +++ b/Grammar/Grammar @@ -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 diff --git a/Include/opcode.h b/Include/opcode.h index 8b6890f..0e15497 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -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}; diff --git a/Lib/dis.py b/Lib/dis.py index 4c67642..899393d 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -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(): diff --git a/Misc/ACKS b/Misc/ACKS index 3fe3a90..82bd3e5 100644 --- 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 diff --git a/Python/ceval.c b/Python/ceval.c index 46a60f1..7a97771 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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 diff --git a/Python/compile.c b/Python/compile.c index 72848fa..1eed7c0 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -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); } } diff --git a/Python/graminit.c b/Python/graminit.c index ba9359e..35d8de4 100644 --- a/Python/graminit.c +++ b/Python/graminit.c @@ -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"}, }; -- cgit v0.12