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
This commit is contained in:
parent
93a7c0fe6b
commit
7690151c7e
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
12
Lib/dis.py
12
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():
|
||||
|
|
|
@ -87,6 +87,7 @@ Stefan Esser
|
|||
Carey Evans
|
||||
Tim Everett
|
||||
Paul Everitt
|
||||
Greg Ewing
|
||||
Mark Favas
|
||||
Niels Ferguson
|
||||
Sebastian Fernandez
|
||||
|
|
277
Python/ceval.c
277
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
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 {
|
||||
PyObject *args = PyTuple_New(na);
|
||||
PyObject *kwdict = NULL;
|
||||
if (args == NULL) {
|
||||
x = NULL;
|
||||
break;
|
||||
/* 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 {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
while (--na >= 0) {
|
||||
w = POP();
|
||||
PyTuple_SET_ITEM(args, na, w);
|
||||
}
|
||||
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(kwdict);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Py_DECREF(func);
|
||||
while (stack_pointer > pfunc) {
|
||||
w = POP();
|
||||
Py_DECREF(w);
|
||||
args = PyTuple_New(na + nstar);
|
||||
if (args == NULL) {
|
||||
x = NULL;
|
||||
break;
|
||||
}
|
||||
PUSH(x);
|
||||
if (x != NULL) continue;
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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] = {
|
||||
{123, 1},
|
||||
{0, 2},
|
||||
static arc arcs_55_2[1] = {
|
||||
{21, 5},
|
||||
};
|
||||
static state states_55[3] = {
|
||||
{1, arcs_55_0},
|
||||
static arc arcs_55_3[1] = {
|
||||
{21, 6},
|
||||
};
|
||||
static arc arcs_55_4[4] = {
|
||||
{123, 1},
|
||||
{23, 2},
|
||||
{24, 3},
|
||||
{0, 4},
|
||||
};
|
||||
static arc arcs_55_5[2] = {
|
||||
{22, 7},
|
||||
{0, 5},
|
||||
};
|
||||
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"},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue