Skip to content

Commit 7690151

Browse files
committed
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
1 parent 93a7c0f commit 7690151

7 files changed

Lines changed: 241 additions & 148 deletions

File tree

Grammar/Grammar

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ eval_input: testlist NEWLINE* ENDMARKER
2323

2424
funcdef: 'def' NAME parameters ':' suite
2525
parameters: '(' [varargslist] ')'
26-
varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] | ('**'|'*' '*') NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
26+
varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
2727
fpdef: NAME | '(' fplist ')'
2828
fplist: fpdef (',' fpdef)* [',']
2929

@@ -86,5 +86,5 @@ dictmaker: test ':' test (',' test ':' test)* [',']
8686

8787
classdef: 'class' NAME ['(' testlist ')'] ':' suite
8888

89-
arglist: argument (',' argument)* [',']
89+
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
9090
argument: [test '='] test # Really [keyword '='] test

Include/opcode.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,17 @@ PERFORMANCE OF THIS SOFTWARE.
138138
for new opcodes. */
139139

140140
#define RAISE_VARARGS 130 /* Number of raise arguments (1, 2 or 3) */
141+
/* CALL_FUNCTION_XXX opcodes defined below depend on this definition */
141142
#define CALL_FUNCTION 131 /* #args + (#kwargs<<8) */
142143
#define MAKE_FUNCTION 132 /* #defaults */
143144
#define BUILD_SLICE 133 /* Number of items */
144145

146+
/* The next 3 opcodes must be contiguous and satisfy
147+
(CALL_FUNCTION_STAR - CALL_FUNCTION) & 3 == 1 */
148+
#define CALL_FUNCTION_VAR 140 /* #args + (#kwargs<<8) */
149+
#define CALL_FUNCTION_KW 141 /* #args + (#kwargs<<8) */
150+
#define CALL_FUNCTION_VAR_KW 142 /* #args + (#kwargs<<8) */
151+
145152
/* Comparison operator codes (argument to COMPARE_OP) */
146153
enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD};
147154

Lib/dis.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,14 @@ def jabs_op(name, op):
247247
def_op('SET_LINENO', 127) # Current line number
248248
SET_LINENO = 127
249249

250-
def_op('RAISE_VARARGS', 130)
251-
def_op('CALL_FUNCTION', 131)
252-
def_op('MAKE_FUNCTION', 132)
253-
def_op('BUILD_SLICE', 133)
250+
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
251+
def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
252+
def_op('MAKE_FUNCTION', 132) # Number of args with default values
253+
def_op('BUILD_SLICE', 133) # Number of items
254+
255+
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
256+
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
257+
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
254258

255259

256260
def _test():

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Stefan Esser
8787
Carey Evans
8888
Tim Everett
8989
Paul Everitt
90+
Greg Ewing
9091
Mark Favas
9192
Niels Ferguson
9293
Sebastian Fernandez

Python/ceval.c

Lines changed: 160 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -499,15 +499,16 @@ eval_code2(co, globals, locals,
499499
if (kwdict == NULL) {
500500
PyErr_Format(PyExc_TypeError,
501501
"unexpected keyword argument: %.400s",
502-
PyString_AsString(keyword));
502+
PyString_AsString(keyword));
503503
goto fail;
504504
}
505505
PyDict_SetItem(kwdict, keyword, value);
506506
}
507507
else {
508508
if (GETLOCAL(j) != NULL) {
509-
PyErr_SetString(PyExc_TypeError,
510-
"keyword parameter redefined");
509+
PyErr_Format(PyExc_TypeError,
510+
"keyword parameter redefined: %.400s",
511+
PyString_AsString(keyword));
511512
goto fail;
512513
}
513514
Py_INCREF(value);
@@ -1548,125 +1549,166 @@ eval_code2(co, globals, locals,
15481549
break;
15491550

15501551
case CALL_FUNCTION:
1552+
case CALL_FUNCTION_VAR:
1553+
case CALL_FUNCTION_KW:
1554+
case CALL_FUNCTION_VAR_KW:
15511555
{
1552-
int na = oparg & 0xff;
1553-
int nk = (oparg>>8) & 0xff;
1554-
int n = na + 2*nk;
1555-
PyObject **pfunc = stack_pointer - n - 1;
1556-
PyObject *func = *pfunc;
1557-
PyObject *self = NULL;
1558-
PyObject *class = NULL;
1559-
f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
1560-
if (PyMethod_Check(func)) {
1561-
self = PyMethod_Self(func);
1562-
class = PyMethod_Class(func);
1563-
func = PyMethod_Function(func);
1564-
Py_INCREF(func);
1565-
if (self != NULL) {
1566-
Py_INCREF(self);
1567-
Py_DECREF(*pfunc);
1568-
*pfunc = self;
1569-
na++;
1570-
n++;
1571-
}
1572-
else {
1573-
/* Unbound methods must be
1574-
called with an instance of
1575-
the class (or a derived
1576-
class) as first argument */
1577-
if (na > 0 &&
1578-
(self = stack_pointer[-n])
1579-
!= NULL &&
1580-
PyInstance_Check(self) &&
1581-
PyClass_IsSubclass(
1582-
(PyObject *)
1583-
(((PyInstanceObject *)self)
1584-
->in_class),
1585-
class))
1586-
/* Handy-dandy */ ;
1587-
else {
1588-
PyErr_SetString(
1589-
PyExc_TypeError,
1590-
"unbound method must be called with class instance 1st argument");
1591-
x = NULL;
1592-
break;
1593-
}
1594-
}
1556+
int na = oparg & 0xff;
1557+
int nk = (oparg>>8) & 0xff;
1558+
int flags = (opcode - CALL_FUNCTION) & 3;
1559+
int n = na + 2*nk + (flags & 1) + ((flags >> 1) & 1);
1560+
PyObject **pfunc = stack_pointer - n - 1;
1561+
PyObject *func = *pfunc;
1562+
PyObject *self = NULL;
1563+
PyObject *class = NULL;
1564+
f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
1565+
if (PyMethod_Check(func)) {
1566+
self = PyMethod_Self(func);
1567+
class = PyMethod_Class(func);
1568+
func = PyMethod_Function(func);
1569+
Py_INCREF(func);
1570+
if (self != NULL) {
1571+
Py_INCREF(self);
1572+
Py_DECREF(*pfunc);
1573+
*pfunc = self;
1574+
na++;
1575+
n++;
15951576
}
1596-
else
1597-
Py_INCREF(func);
1598-
if (PyFunction_Check(func)) {
1599-
PyObject *co = PyFunction_GetCode(func);
1600-
PyObject *globals =
1601-
PyFunction_GetGlobals(func);
1602-
PyObject *argdefs =
1603-
PyFunction_GetDefaults(func);
1604-
PyObject **d;
1605-
int nd;
1606-
if (argdefs != NULL) {
1607-
d = &PyTuple_GET_ITEM(argdefs, 0);
1608-
nd = ((PyTupleObject *)argdefs) ->
1609-
ob_size;
1610-
}
1611-
else {
1612-
d = NULL;
1613-
nd = 0;
1614-
}
1615-
x = eval_code2(
1616-
(PyCodeObject *)co,
1617-
globals, (PyObject *)NULL,
1618-
stack_pointer-n, na,
1619-
stack_pointer-2*nk, nk,
1620-
d, nd,
1621-
class);
1577+
else {
1578+
/* Unbound methods must be called with an
1579+
instance of the class (or a derived
1580+
class) as first argument */
1581+
if (na > 0 && (self = stack_pointer[-n]) != NULL
1582+
&& PyInstance_Check(self)
1583+
&& PyClass_IsSubclass((PyObject *)
1584+
(((PyInstanceObject *)self)->in_class),
1585+
class))
1586+
/* Handy-dandy */ ;
1587+
else {
1588+
PyErr_SetString(PyExc_TypeError,
1589+
"unbound method must be called with class instance 1st argument");
1590+
x = NULL;
1591+
break;
1592+
}
1593+
}
1594+
}
1595+
else
1596+
Py_INCREF(func);
1597+
if (PyFunction_Check(func) && flags == 0) {
1598+
PyObject *co = PyFunction_GetCode(func);
1599+
PyObject *globals = PyFunction_GetGlobals(func);
1600+
PyObject *argdefs = PyFunction_GetDefaults(func);
1601+
PyObject **d;
1602+
int nd;
1603+
if (argdefs != NULL) {
1604+
d = &PyTuple_GET_ITEM(argdefs, 0);
1605+
nd = ((PyTupleObject *)argdefs)->ob_size;
16221606
}
16231607
else {
1624-
PyObject *args = PyTuple_New(na);
1625-
PyObject *kwdict = NULL;
1626-
if (args == NULL) {
1627-
x = NULL;
1628-
break;
1629-
}
1630-
if (nk > 0) {
1631-
kwdict = PyDict_New();
1632-
if (kwdict == NULL) {
1633-
x = NULL;
1634-
break;
1635-
}
1636-
err = 0;
1637-
while (--nk >= 0) {
1638-
PyObject *value = POP();
1639-
PyObject *key = POP();
1640-
err = PyDict_SetItem(
1641-
kwdict, key, value);
1642-
Py_DECREF(key);
1643-
Py_DECREF(value);
1644-
if (err)
1645-
break;
1646-
}
1647-
if (err) {
1648-
Py_DECREF(args);
1649-
Py_DECREF(kwdict);
1650-
break;
1651-
}
1608+
d = NULL;
1609+
nd = 0;
1610+
}
1611+
x = eval_code2((PyCodeObject *)co, globals,
1612+
(PyObject *)NULL, stack_pointer-n, na,
1613+
stack_pointer-2*nk, nk, d, nd,
1614+
class);
1615+
}
1616+
else {
1617+
int nstar = 0;
1618+
PyObject *args;
1619+
PyObject *stararg = 0;
1620+
PyObject *kwdict = NULL;
1621+
if (flags & 2) {
1622+
kwdict = POP();
1623+
if (!PyDict_Check(kwdict)) {
1624+
PyErr_SetString(PyExc_TypeError,
1625+
"** argument must be a dictionary");
1626+
x = NULL;
1627+
break;
1628+
}
1629+
}
1630+
if (flags & 1) {
1631+
stararg = POP();
1632+
if (!PySequence_Check(stararg)) {
1633+
PyErr_SetString(PyExc_TypeError,
1634+
"* argument must be a sequence");
1635+
x = NULL;
1636+
break;
1637+
}
1638+
nstar = PySequence_Length(stararg);
1639+
}
1640+
if (nk > 0) {
1641+
if (kwdict == NULL) {
1642+
kwdict = PyDict_New();
1643+
if (kwdict == NULL) {
1644+
x = NULL;
1645+
break;
16521646
}
1653-
while (--na >= 0) {
1654-
w = POP();
1655-
PyTuple_SET_ITEM(args, na, w);
1647+
}
1648+
err = 0;
1649+
while (--nk >= 0) {
1650+
PyObject *value = POP();
1651+
PyObject *key = POP();
1652+
if (PyDict_GetItem(kwdict, key) != NULL) {
1653+
err = 1;
1654+
PyErr_Format(PyExc_TypeError,
1655+
"keyword parameter redefined: %.400s",
1656+
PyString_AsString(key));
1657+
break;
16561658
}
1657-
x = PyEval_CallObjectWithKeywords(
1658-
func, args, kwdict);
1659+
err = PyDict_SetItem(kwdict, key, value);
1660+
Py_DECREF(key);
1661+
Py_DECREF(value);
1662+
if (err)
1663+
break;
1664+
}
1665+
if (err) {
16591666
Py_DECREF(args);
1660-
Py_XDECREF(kwdict);
1661-
}
1662-
Py_DECREF(func);
1663-
while (stack_pointer > pfunc) {
1664-
w = POP();
1665-
Py_DECREF(w);
1666-
}
1667-
PUSH(x);
1668-
if (x != NULL) continue;
1669-
break;
1667+
Py_DECREF(kwdict);
1668+
break;
1669+
}
1670+
}
1671+
args = PyTuple_New(na + nstar);
1672+
if (args == NULL) {
1673+
x = NULL;
1674+
break;
1675+
}
1676+
if (stararg) {
1677+
PyObject *t = NULL;
1678+
int i;
1679+
if (!PyTuple_Check(stararg)) {
1680+
/* must be sequence to pass earlier test */
1681+
t = PySequence_Tuple(stararg);
1682+
if (t == NULL) {
1683+
x = NULL;
1684+
break;
1685+
}
1686+
Py_DECREF(stararg);
1687+
stararg = t;
1688+
}
1689+
for (i = 0; i < nstar; i++) {
1690+
PyObject *a = PyTuple_GET_ITEM(stararg, i);
1691+
Py_INCREF(a);
1692+
PyTuple_SET_ITEM(args, na + i, a);
1693+
}
1694+
Py_DECREF(stararg);
1695+
}
1696+
while (--na >= 0) {
1697+
w = POP();
1698+
PyTuple_SET_ITEM(args, na, w);
1699+
}
1700+
x = PyEval_CallObjectWithKeywords(func, args, kwdict);
1701+
Py_DECREF(args);
1702+
Py_XDECREF(kwdict);
1703+
}
1704+
Py_DECREF(func);
1705+
while (stack_pointer > pfunc) {
1706+
w = POP();
1707+
Py_DECREF(w);
1708+
}
1709+
PUSH(x);
1710+
if (x != NULL) continue;
1711+
break;
16701712
}
16711713

16721714
case MAKE_FUNCTION:
@@ -2687,10 +2729,9 @@ import_from(locals, v, name)
26872729
else {
26882730
x = PyDict_GetItem(w, name);
26892731
if (x == NULL) {
2690-
char buf[250];
2691-
sprintf(buf, "cannot import name %.230s",
2692-
PyString_AsString(name));
2693-
PyErr_SetString(PyExc_ImportError, buf);
2732+
PyErr_Format(PyExc_ImportError,
2733+
"cannot import name %.230s",
2734+
PyString_AsString(name));
26942735
return -1;
26952736
}
26962737
else

0 commit comments

Comments
 (0)