From f656e50642a6e0101436e3700e38ac2bccabe05c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 8 Aug 2026 10:55:08 +0300 Subject: [PATCH] gh-155373: Inline the parsing code of optional groups in Argument Clinic Instead of one PyArg_ParseTuple() call per number of arguments, generate the inlined code of the converters, as for all other parsing methods. Every argument is parsed once. Such functions now use the fastcall convention, except for constructors and other functions which need a tuple. --- Lib/test/clinic.test.c | 136 +- ...-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst | 6 + Modules/_cursesmodule.c | 3 +- Modules/clinic/_cursesmodule.c.h | 1268 +++++++++-------- Modules/clinic/_ssl.c.h | 42 +- Modules/clinic/_testclinic.c.h | 194 +-- Modules/clinic/gcmodule.c.h | 47 +- Modules/clinic/syslogmodule.c.h | 42 +- Tools/clinic/libclinic/clanguage.py | 173 +-- Tools/clinic/libclinic/function.py | 19 + Tools/clinic/libclinic/parse_args.py | 400 +++++- 11 files changed, 1299 insertions(+), 1031 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 3dca8b8d1ed9b9..f8b0a643c20a41 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -5741,21 +5741,15 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("Test", kwargs)) { goto exit; } - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:__init__", &a)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:__init__", &a, &b)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "Test.__init__ requires 1 to 2 arguments"); - goto exit; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "Test.__init__ requires 1 to 2 arguments"); + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + if (nargs >= 2) { + b = PyTuple_GET_ITEM(args, 1); + group_right_1 = 1; } return_value = Test___init___impl((TestObj *)self, a, group_right_1, b); @@ -5766,7 +5760,7 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) static int Test___init___impl(TestObj *self, PyObject *a, int group_right_1, PyObject *b) -/*[clinic end generated code: output=2bbb8ea60e8f57a6 input=10f5d0f1e8e466ef]*/ +/*[clinic end generated code: output=72fdd2de63c05b9e input=10f5d0f1e8e466ef]*/ /*[clinic input] @@ -5783,30 +5777,25 @@ PyDoc_STRVAR(only_optional_group__doc__, "The only parameter is in an optional group."); #define ONLY_OPTIONAL_GROUP_METHODDEF \ - {"only_optional_group", (PyCFunction)only_optional_group, METH_VARARGS, only_optional_group__doc__}, + {"only_optional_group", _PyCFunction_CAST(only_optional_group), METH_FASTCALL, only_optional_group__doc__}, static PyObject * only_optional_group_impl(PyObject *module, int group_right_1, PyObject *a); static PyObject * -only_optional_group(PyObject *module, PyObject *args) +only_optional_group(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *a = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "O:only_optional_group", &a)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "only_optional_group requires 0 to 1 arguments"); - goto exit; + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "only_optional_group requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + a = args[0]; + group_right_1 = 1; } return_value = only_optional_group_impl(module, group_right_1, a); @@ -5816,7 +5805,7 @@ only_optional_group(PyObject *module, PyObject *args) static PyObject * only_optional_group_impl(PyObject *module, int group_right_1, PyObject *a) -/*[clinic end generated code: output=e7546b9441793d7d input=426c64055af7bcab]*/ +/*[clinic end generated code: output=4c7959fcc06bd216 input=426c64055af7bcab]*/ /*[clinic input] @@ -5835,14 +5824,14 @@ PyDoc_STRVAR(group_and_optional_parameter__doc__, "The optional parameter can be omitted with or without the group."); #define GROUP_AND_OPTIONAL_PARAMETER_METHODDEF \ - {"group_and_optional_parameter", (PyCFunction)group_and_optional_parameter, METH_VARARGS, group_and_optional_parameter__doc__}, + {"group_and_optional_parameter", _PyCFunction_CAST(group_and_optional_parameter), METH_FASTCALL, group_and_optional_parameter__doc__}, static PyObject * group_and_optional_parameter_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c); static PyObject * -group_and_optional_parameter(PyObject *module, PyObject *args) +group_and_optional_parameter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -5850,24 +5839,22 @@ group_and_optional_parameter(PyObject *module, PyObject *args) PyObject *b = NULL; PyObject *c = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O:group_and_optional_parameter", &c)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "OO|O:group_and_optional_parameter", &a, &b, &c)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_optional_parameter requires 0 to 3 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "group_and_optional_parameter requires 0 to 3 arguments"); + goto exit; } + if (nargs >= 2) { + a = args[0]; + b = args[1]; + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + c = args[offset]; +skip_optional: return_value = group_and_optional_parameter_impl(module, group_left_1, a, b, c); exit: @@ -5877,7 +5864,7 @@ group_and_optional_parameter(PyObject *module, PyObject *args) static PyObject * group_and_optional_parameter_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=3faea69eafd5bbbe input=7f0fbb6124f5a972]*/ +/*[clinic end generated code: output=651f2361ffc5e256 input=7f0fbb6124f5a972]*/ /*[clinic input] @@ -5899,7 +5886,7 @@ PyDoc_STRVAR(two_groups_on_the_same_level__doc__, "Groups on the same level are independent of each other."); #define TWO_GROUPS_ON_THE_SAME_LEVEL_METHODDEF \ - {"two_groups_on_the_same_level", (PyCFunction)two_groups_on_the_same_level, METH_VARARGS, two_groups_on_the_same_level__doc__}, + {"two_groups_on_the_same_level", _PyCFunction_CAST(two_groups_on_the_same_level), METH_FASTCALL, two_groups_on_the_same_level__doc__}, static PyObject * two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, @@ -5907,7 +5894,7 @@ two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, PyObject *c, PyObject *d); static PyObject * -two_groups_on_the_same_level(PyObject *module, PyObject *args) +two_groups_on_the_same_level(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -5917,35 +5904,20 @@ two_groups_on_the_same_level(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_the_same_level", &d)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_the_same_level", &c, &d)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_the_same_level", &a, &b, &d)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_the_same_level", &a, &b, &c, &d)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_the_same_level requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_the_same_level requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + c = args[nargs - 2]; + group_left_2 = 1; } + d = args[nargs - 1]; return_value = two_groups_on_the_same_level_impl(module, group_left_1, a, b, group_left_2, c, d); exit: @@ -5956,7 +5928,7 @@ static PyObject * two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, int group_left_2, PyObject *c, PyObject *d) -/*[clinic end generated code: output=508a61ee582da21e input=1b45d9b675b32d1a]*/ +/*[clinic end generated code: output=737c3f543296e916 input=1b45d9b675b32d1a]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst new file mode 100644 index 00000000000000..ed02c8b9fbf401 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst @@ -0,0 +1,6 @@ +Argument Clinic now generates the inlined code of the converters for functions +with optional groups, instead of a ``PyArg_ParseTuple()`` call for every number +of arguments. +Every argument is now parsed once, most such functions now use the fastcall +convention, and the errors for a wrong type of an argument are the same as in +other functions. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 07e924b0fc564b..03690c7cfb2d3d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -5117,7 +5117,8 @@ static PyMethodDef PyCursesWindow_methods[] = { {"standout", PyCursesWindow_wstandout, METH_NOARGS, "standout($self, /)\n--\n\n" "Turn on the A_STANDOUT attribute."}, - {"subpad", _curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + {"subpad", _PyCFunction_CAST(_curses_window_subwin), METH_FASTCALL, + _curses_window_subwin__doc__}, _CURSES_WINDOW_SUBWIN_METHODDEF {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS, "syncdown($self, /)\n--\n\n" diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index b4cb294e3bb61a..30d19b985b7fa7 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_long.h" // _PyLong_UnsignedInt_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(complexchar_new__doc__, @@ -207,7 +208,7 @@ PyDoc_STRVAR(_curses_window_addch__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDCH_METHODDEF \ - {"addch", (PyCFunction)_curses_window_addch, METH_VARARGS, _curses_window_addch__doc__}, + {"addch", _PyCFunction_CAST(_curses_window_addch), METH_FASTCALL, _curses_window_addch__doc__}, static PyObject * _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, @@ -215,7 +216,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_addch(PyObject *self, PyObject *args) +_curses_window_addch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -225,34 +226,29 @@ _curses_window_addch(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:addch", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:addch", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:addch", &y, &x, &ch)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:addch", &y, &x, &ch, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); @@ -279,7 +275,7 @@ PyDoc_STRVAR(_curses_window_addstr__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDSTR_METHODDEF \ - {"addstr", (PyCFunction)_curses_window_addstr, METH_VARARGS, _curses_window_addstr__doc__}, + {"addstr", _PyCFunction_CAST(_curses_window_addstr), METH_FASTCALL, _curses_window_addstr__doc__}, static PyObject * _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -287,7 +283,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_addstr(PyObject *self, PyObject *args) +_curses_window_addstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -297,34 +293,29 @@ _curses_window_addstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:addstr", &str)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:addstr", &str, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:addstr", &y, &x, &str)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:addstr", &y, &x, &str, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); @@ -353,7 +344,7 @@ PyDoc_STRVAR(_curses_window_addnstr__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDNSTR_METHODDEF \ - {"addnstr", (PyCFunction)_curses_window_addnstr, METH_VARARGS, _curses_window_addnstr__doc__}, + {"addnstr", _PyCFunction_CAST(_curses_window_addnstr), METH_FASTCALL, _curses_window_addnstr__doc__}, static PyObject * _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -361,7 +352,7 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_addnstr(PyObject *self, PyObject *args) +_curses_window_addnstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -372,34 +363,33 @@ _curses_window_addnstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:addnstr", &str, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:addnstr", &str, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:addnstr", &y, &x, &str, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:addnstr", &y, &x, &str, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); @@ -417,35 +407,30 @@ PyDoc_STRVAR(_curses_window_bkgd__doc__, " Background attributes."); #define _CURSES_WINDOW_BKGD_METHODDEF \ - {"bkgd", (PyCFunction)_curses_window_bkgd, METH_VARARGS, _curses_window_bkgd__doc__}, + {"bkgd", _PyCFunction_CAST(_curses_window_bkgd), METH_FASTCALL, _curses_window_bkgd__doc__}, static PyObject * _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_bkgd(PyObject *self, PyObject *args) +_curses_window_bkgd(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:bkgd", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:bkgd", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.bkgd requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.bkgd requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -720,35 +705,30 @@ PyDoc_STRVAR(_curses_window_bkgdset__doc__, " Background attributes."); #define _CURSES_WINDOW_BKGDSET_METHODDEF \ - {"bkgdset", (PyCFunction)_curses_window_bkgdset, METH_VARARGS, _curses_window_bkgdset__doc__}, + {"bkgdset", _PyCFunction_CAST(_curses_window_bkgdset), METH_FASTCALL, _curses_window_bkgdset__doc__}, static PyObject * _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_bkgdset(PyObject *self, PyObject *args) +_curses_window_bkgdset(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:bkgdset", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:bkgdset", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.bkgdset requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.bkgdset requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -865,33 +845,33 @@ PyDoc_STRVAR(_curses_window_box__doc__, "function."); #define _CURSES_WINDOW_BOX_METHODDEF \ - {"box", (PyCFunction)_curses_window_box, METH_VARARGS, _curses_window_box__doc__}, + {"box", _PyCFunction_CAST(_curses_window_box), METH_FASTCALL, _curses_window_box__doc__}, static PyObject * _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, PyObject *verch, PyObject *horch); static PyObject * -_curses_window_box(PyObject *self, PyObject *args) +_curses_window_box(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *verch = _PyLong_GetZero(); PyObject *horch = _PyLong_GetZero(); - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "OO:box", &verch, &horch)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.box requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + verch = args[0]; + horch = args[1]; + group_right_1 = 1; + } return_value = _curses_window_box_impl((PyCursesWindowObject *)self, group_right_1, verch, horch); exit: @@ -921,14 +901,14 @@ PyDoc_STRVAR(_curses_window_chgat__doc__, "contents will be redisplayed by the next window refresh."); #define _CURSES_WINDOW_CHGAT_METHODDEF \ - {"chgat", (PyCFunction)_curses_window_chgat, METH_VARARGS, _curses_window_chgat__doc__}, + {"chgat", _PyCFunction_CAST(_curses_window_chgat), METH_FASTCALL, _curses_window_chgat__doc__}, static PyObject * _curses_window_chgat_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, int group_left_2, int n, attr_t attr); static PyObject * -_curses_window_chgat(PyObject *self, PyObject *args) +_curses_window_chgat(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -938,34 +918,30 @@ _curses_window_chgat(PyObject *self, PyObject *args) int n = -1; attr_t attr; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O&:chgat", attr_converter, &attr)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "iO&:chgat", &n, attr_converter, &attr)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO&:chgat", &y, &x, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiiO&:chgat", &y, &x, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.chgat requires 1 to 4 arguments"); + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.chgat requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + n = PyLong_AsInt(args[nargs - 2]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_2 = 1; + } + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; } return_value = _curses_window_chgat_impl((PyCursesWindowObject *)self, group_left_1, y, x, group_left_2, n, attr); @@ -988,33 +964,39 @@ PyDoc_STRVAR(_curses_window_delch__doc__, "position left."); #define _CURSES_WINDOW_DELCH_METHODDEF \ - {"delch", (PyCFunction)_curses_window_delch, METH_VARARGS, _curses_window_delch__doc__}, + {"delch", _PyCFunction_CAST(_curses_window_delch), METH_FASTCALL, _curses_window_delch__doc__}, static PyObject * _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_delch(PyObject *self, PyObject *args) +_curses_window_delch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:delch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.delch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_delch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1039,14 +1021,14 @@ PyDoc_STRVAR(_curses_window_derwin__doc__, "relative to the entire screen."); #define _CURSES_WINDOW_DERWIN_METHODDEF \ - {"derwin", (PyCFunction)_curses_window_derwin, METH_VARARGS, _curses_window_derwin__doc__}, + {"derwin", _PyCFunction_CAST(_curses_window_derwin), METH_FASTCALL, _curses_window_derwin__doc__}, static PyObject * _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x); static PyObject * -_curses_window_derwin(PyObject *self, PyObject *args) +_curses_window_derwin(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1055,22 +1037,33 @@ _curses_window_derwin(PyObject *self, PyObject *args) int begin_y; int begin_x; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:derwin", &begin_y, &begin_x)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:derwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_left_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.derwin requires 2 to 4 arguments"); goto exit; } + if (nargs >= 4) { + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + begin_y = PyLong_AsInt(args[nargs - 2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[nargs - 1]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } return_value = _curses_window_derwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); exit: @@ -1109,35 +1102,30 @@ PyDoc_STRVAR(_curses_window_echochar__doc__, " Attributes for the character."); #define _CURSES_WINDOW_ECHOCHAR_METHODDEF \ - {"echochar", (PyCFunction)_curses_window_echochar, METH_VARARGS, _curses_window_echochar__doc__}, + {"echochar", _PyCFunction_CAST(_curses_window_echochar), METH_FASTCALL, _curses_window_echochar__doc__}, static PyObject * _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_echochar(PyObject *self, PyObject *args) +_curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:echochar", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:echochar", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.echochar requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.echochar requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -1278,33 +1266,39 @@ PyDoc_STRVAR(_curses_window_in_wch__doc__, "attributes and color pair."); #define _CURSES_WINDOW_IN_WCH_METHODDEF \ - {"in_wch", (PyCFunction)_curses_window_in_wch, METH_VARARGS, _curses_window_in_wch__doc__}, + {"in_wch", _PyCFunction_CAST(_curses_window_in_wch), METH_FASTCALL, _curses_window_in_wch__doc__}, static PyObject * _curses_window_in_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_in_wch(PyObject *self, PyObject *args) +_curses_window_in_wch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:in_wch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.in_wch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_in_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1344,33 +1338,39 @@ PyDoc_STRVAR(_curses_window_getch__doc__, "waits until a key is pressed."); #define _CURSES_WINDOW_GETCH_METHODDEF \ - {"getch", (PyCFunction)_curses_window_getch, METH_VARARGS, _curses_window_getch__doc__}, + {"getch", _PyCFunction_CAST(_curses_window_getch), METH_FASTCALL, _curses_window_getch__doc__}, static PyObject * _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_getch(PyObject *self, PyObject *args) +_curses_window_getch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:getch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.getch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1392,33 +1392,39 @@ PyDoc_STRVAR(_curses_window_getkey__doc__, "if there is no input."); #define _CURSES_WINDOW_GETKEY_METHODDEF \ - {"getkey", (PyCFunction)_curses_window_getkey, METH_VARARGS, _curses_window_getkey__doc__}, + {"getkey", _PyCFunction_CAST(_curses_window_getkey), METH_FASTCALL, _curses_window_getkey__doc__}, static PyObject * _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_getkey(PyObject *self, PyObject *args) +_curses_window_getkey(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:getkey", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.getkey requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_getkey_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1438,33 +1444,39 @@ PyDoc_STRVAR(_curses_window_get_wch__doc__, "keypad keys, and other special keys."); #define _CURSES_WINDOW_GET_WCH_METHODDEF \ - {"get_wch", (PyCFunction)_curses_window_get_wch, METH_VARARGS, _curses_window_get_wch__doc__}, + {"get_wch", _PyCFunction_CAST(_curses_window_get_wch), METH_FASTCALL, _curses_window_get_wch__doc__}, static PyObject * _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_get_wch(PyObject *self, PyObject *args) +_curses_window_get_wch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:get_wch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.get_wch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_get_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1483,14 +1495,14 @@ PyDoc_STRVAR(_curses_window_getstr__doc__, " Maximal number of characters."); #define _CURSES_WINDOW_GETSTR_METHODDEF \ - {"getstr", (PyCFunction)_curses_window_getstr, METH_VARARGS, _curses_window_getstr__doc__}, + {"getstr", _PyCFunction_CAST(_curses_window_getstr), METH_FASTCALL, _curses_window_getstr__doc__}, static PyObject * _curses_window_getstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_getstr(PyObject *self, PyObject *args) +_curses_window_getstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1498,24 +1510,30 @@ _curses_window_getstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:getstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:getstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.getstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.getstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; } +skip_optional: return_value = _curses_window_getstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1538,7 +1556,7 @@ PyDoc_STRVAR(_curses_window_hline__doc__, " Attributes for the characters."); #define _CURSES_WINDOW_HLINE_METHODDEF \ - {"hline", (PyCFunction)_curses_window_hline, METH_VARARGS, _curses_window_hline__doc__}, + {"hline", _PyCFunction_CAST(_curses_window_hline), METH_FASTCALL, _curses_window_hline__doc__}, static PyObject * _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, @@ -1546,7 +1564,7 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_hline(PyObject *self, PyObject *args) +_curses_window_hline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1557,34 +1575,33 @@ _curses_window_hline(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:hline", &ch, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:hline", &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:hline", &y, &x, &ch, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:hline", &y, &x, &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_hline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); @@ -1609,7 +1626,7 @@ PyDoc_STRVAR(_curses_window_insch__doc__, "right, with the rightmost characters on the line being lost."); #define _CURSES_WINDOW_INSCH_METHODDEF \ - {"insch", (PyCFunction)_curses_window_insch, METH_VARARGS, _curses_window_insch__doc__}, + {"insch", _PyCFunction_CAST(_curses_window_insch), METH_FASTCALL, _curses_window_insch__doc__}, static PyObject * _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, @@ -1617,7 +1634,7 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_insch(PyObject *self, PyObject *args) +_curses_window_insch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1627,34 +1644,29 @@ _curses_window_insch(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:insch", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:insch", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:insch", &y, &x, &ch)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:insch", &y, &x, &ch, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); @@ -1675,33 +1687,39 @@ PyDoc_STRVAR(_curses_window_inch__doc__, "attributes."); #define _CURSES_WINDOW_INCH_METHODDEF \ - {"inch", (PyCFunction)_curses_window_inch, METH_VARARGS, _curses_window_inch__doc__}, + {"inch", _PyCFunction_CAST(_curses_window_inch), METH_FASTCALL, _curses_window_inch__doc__}, static PyObject * _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_inch(PyObject *self, PyObject *args) +_curses_window_inch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:inch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.inch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1727,14 +1745,14 @@ PyDoc_STRVAR(_curses_window_instr__doc__, "the trailing NUL)."); #define _CURSES_WINDOW_INSTR_METHODDEF \ - {"instr", (PyCFunction)_curses_window_instr, METH_VARARGS, _curses_window_instr__doc__}, + {"instr", _PyCFunction_CAST(_curses_window_instr), METH_FASTCALL, _curses_window_instr__doc__}, static PyObject * _curses_window_instr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_instr(PyObject *self, PyObject *args) +_curses_window_instr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1742,24 +1760,30 @@ _curses_window_instr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:instr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:instr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.instr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.instr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_instr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1780,39 +1804,45 @@ PyDoc_STRVAR(_curses_window_get_wstr__doc__, "This is the wide-character variant of getstr(); it returns a str."); #define _CURSES_WINDOW_GET_WSTR_METHODDEF \ - {"get_wstr", (PyCFunction)_curses_window_get_wstr, METH_VARARGS, _curses_window_get_wstr__doc__}, + {"get_wstr", _PyCFunction_CAST(_curses_window_get_wstr), METH_FASTCALL, _curses_window_get_wstr__doc__}, static PyObject * _curses_window_get_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_get_wstr(PyObject *self, PyObject *args) +_curses_window_get_wstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; int y = 0; - int x = 0; - unsigned int n = 2047; - - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:get_wstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:get_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.get_wstr requires 0 to 3 arguments"); + int x = 0; + unsigned int n = 2047; + + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.get_wstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_get_wstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1833,14 +1863,14 @@ PyDoc_STRVAR(_curses_window_in_wstr__doc__, "This is the wide-character variant of instr(); it returns a str."); #define _CURSES_WINDOW_IN_WSTR_METHODDEF \ - {"in_wstr", (PyCFunction)_curses_window_in_wstr, METH_VARARGS, _curses_window_in_wstr__doc__}, + {"in_wstr", _PyCFunction_CAST(_curses_window_in_wstr), METH_FASTCALL, _curses_window_in_wstr__doc__}, static PyObject * _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_in_wstr(PyObject *self, PyObject *args) +_curses_window_in_wstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1848,24 +1878,30 @@ _curses_window_in_wstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.in_wstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.in_wstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; } +skip_optional: return_value = _curses_window_in_wstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1888,14 +1924,14 @@ PyDoc_STRVAR(_curses_window_in_wchstr__doc__, "complexstr."); #define _CURSES_WINDOW_IN_WCHSTR_METHODDEF \ - {"in_wchstr", (PyCFunction)_curses_window_in_wchstr, METH_VARARGS, _curses_window_in_wchstr__doc__}, + {"in_wchstr", _PyCFunction_CAST(_curses_window_in_wchstr), METH_FASTCALL, _curses_window_in_wchstr__doc__}, static PyObject * _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_in_wchstr(PyObject *self, PyObject *args) +_curses_window_in_wchstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1903,24 +1939,30 @@ _curses_window_in_wchstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wchstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wchstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.in_wchstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.in_wchstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_in_wchstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1947,7 +1989,7 @@ PyDoc_STRVAR(_curses_window_insstr__doc__, "moving to y, x, if specified)."); #define _CURSES_WINDOW_INSSTR_METHODDEF \ - {"insstr", (PyCFunction)_curses_window_insstr, METH_VARARGS, _curses_window_insstr__doc__}, + {"insstr", _PyCFunction_CAST(_curses_window_insstr), METH_FASTCALL, _curses_window_insstr__doc__}, static PyObject * _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -1955,7 +1997,7 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_insstr(PyObject *self, PyObject *args) +_curses_window_insstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1965,34 +2007,29 @@ _curses_window_insstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:insstr", &str)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:insstr", &str, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:insstr", &y, &x, &str)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:insstr", &y, &x, &str, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); @@ -2023,7 +2060,7 @@ PyDoc_STRVAR(_curses_window_insnstr__doc__, "does not change (after moving to y, x, if specified)."); #define _CURSES_WINDOW_INSNSTR_METHODDEF \ - {"insnstr", (PyCFunction)_curses_window_insnstr, METH_VARARGS, _curses_window_insnstr__doc__}, + {"insnstr", _PyCFunction_CAST(_curses_window_insnstr), METH_FASTCALL, _curses_window_insnstr__doc__}, static PyObject * _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -2031,7 +2068,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_insnstr(PyObject *self, PyObject *args) +_curses_window_insnstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2042,34 +2079,33 @@ _curses_window_insnstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:insnstr", &str, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:insnstr", &str, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:insnstr", &y, &x, &str, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:insnstr", &y, &x, &str, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); @@ -2122,7 +2158,7 @@ PyDoc_STRVAR(_curses_window_noutrefresh__doc__, "screen. To accomplish that, call doupdate()."); #define _CURSES_WINDOW_NOUTREFRESH_METHODDEF \ - {"noutrefresh", (PyCFunction)_curses_window_noutrefresh, METH_VARARGS, _curses_window_noutrefresh__doc__}, + {"noutrefresh", _PyCFunction_CAST(_curses_window_noutrefresh), METH_FASTCALL, _curses_window_noutrefresh__doc__}, static PyObject * _curses_window_noutrefresh_impl(PyCursesWindowObject *self, @@ -2131,7 +2167,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self, int smaxcol); static PyObject * -_curses_window_noutrefresh(PyObject *self, PyObject *args) +_curses_window_noutrefresh(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; @@ -2142,19 +2178,41 @@ _curses_window_noutrefresh(PyObject *self, PyObject *args) int smaxrow = 0; int smaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 6: - if (!PyArg_ParseTuple(args, "iiiiii:noutrefresh", &pminrow, &pmincol, &sminrow, &smincol, &smaxrow, &smaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.noutrefresh requires 0 to 6 arguments"); goto exit; } + if (nargs >= 6) { + pminrow = PyLong_AsInt(args[0]); + if (pminrow == -1 && PyErr_Occurred()) { + goto exit; + } + pmincol = PyLong_AsInt(args[1]); + if (pmincol == -1 && PyErr_Occurred()) { + goto exit; + } + sminrow = PyLong_AsInt(args[2]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[3]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + smaxrow = PyLong_AsInt(args[4]); + if (smaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + smaxcol = PyLong_AsInt(args[5]); + if (smaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_noutrefresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); exit: @@ -2204,7 +2262,7 @@ PyDoc_STRVAR(_curses_window_overlay__doc__, "a rectangle in the destination window."); #define _CURSES_WINDOW_OVERLAY_METHODDEF \ - {"overlay", (PyCFunction)_curses_window_overlay, METH_VARARGS, _curses_window_overlay__doc__}, + {"overlay", _PyCFunction_CAST(_curses_window_overlay), METH_FASTCALL, _curses_window_overlay__doc__}, static PyObject * _curses_window_overlay_impl(PyCursesWindowObject *self, @@ -2213,7 +2271,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, int dmincol, int dmaxrow, int dmaxcol); static PyObject * -_curses_window_overlay(PyObject *self, PyObject *args) +_curses_window_overlay(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyCursesWindowObject *destwin; @@ -2225,22 +2283,46 @@ _curses_window_overlay(PyObject *self, PyObject *args) int dmaxrow = 0; int dmaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 1: - if (!PyArg_ParseTuple(args, "O!:overlay", clinic_state()->window_type, &destwin)) { - goto exit; - } - break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.overlay requires 1 to 7 arguments"); goto exit; } + if (!PyObject_TypeCheck(args[0], clinic_state()->window_type)) { + _PyArg_BadArgument("overlay", "argument 1", (clinic_state()->window_type)->tp_name, args[0]); + goto exit; + } + destwin = (PyCursesWindowObject *)args[0]; + if (nargs >= 7) { + sminrow = PyLong_AsInt(args[1]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[2]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + dminrow = PyLong_AsInt(args[3]); + if (dminrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmincol = PyLong_AsInt(args[4]); + if (dmincol == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxrow = PyLong_AsInt(args[5]); + if (dmaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxcol = PyLong_AsInt(args[6]); + if (dmaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_overlay_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); exit: @@ -2263,7 +2345,7 @@ PyDoc_STRVAR(_curses_window_overwrite__doc__, "a rectangle in the destination window."); #define _CURSES_WINDOW_OVERWRITE_METHODDEF \ - {"overwrite", (PyCFunction)_curses_window_overwrite, METH_VARARGS, _curses_window_overwrite__doc__}, + {"overwrite", _PyCFunction_CAST(_curses_window_overwrite), METH_FASTCALL, _curses_window_overwrite__doc__}, static PyObject * _curses_window_overwrite_impl(PyCursesWindowObject *self, @@ -2273,7 +2355,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, int dmaxcol); static PyObject * -_curses_window_overwrite(PyObject *self, PyObject *args) +_curses_window_overwrite(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyCursesWindowObject *destwin; @@ -2285,22 +2367,46 @@ _curses_window_overwrite(PyObject *self, PyObject *args) int dmaxrow = 0; int dmaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 1: - if (!PyArg_ParseTuple(args, "O!:overwrite", clinic_state()->window_type, &destwin)) { - goto exit; - } - break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.overwrite requires 1 to 7 arguments"); goto exit; } + if (!PyObject_TypeCheck(args[0], clinic_state()->window_type)) { + _PyArg_BadArgument("overwrite", "argument 1", (clinic_state()->window_type)->tp_name, args[0]); + goto exit; + } + destwin = (PyCursesWindowObject *)args[0]; + if (nargs >= 7) { + sminrow = PyLong_AsInt(args[1]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[2]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + dminrow = PyLong_AsInt(args[3]); + if (dminrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmincol = PyLong_AsInt(args[4]); + if (dmincol == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxrow = PyLong_AsInt(args[5]); + if (dmaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxcol = PyLong_AsInt(args[6]); + if (dmaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_overwrite_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); exit: @@ -2392,7 +2498,7 @@ PyDoc_STRVAR(_curses_window_refresh__doc__, "pmincol, sminrow, or smincol are treated as if they were zero."); #define _CURSES_WINDOW_REFRESH_METHODDEF \ - {"refresh", (PyCFunction)_curses_window_refresh, METH_VARARGS, _curses_window_refresh__doc__}, + {"refresh", _PyCFunction_CAST(_curses_window_refresh), METH_FASTCALL, _curses_window_refresh__doc__}, static PyObject * _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, @@ -2400,7 +2506,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, int smincol, int smaxrow, int smaxcol); static PyObject * -_curses_window_refresh(PyObject *self, PyObject *args) +_curses_window_refresh(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; @@ -2411,19 +2517,41 @@ _curses_window_refresh(PyObject *self, PyObject *args) int smaxrow = 0; int smaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 6: - if (!PyArg_ParseTuple(args, "iiiiii:refresh", &pminrow, &pmincol, &sminrow, &smincol, &smaxrow, &smaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.refresh requires 0 to 6 arguments"); goto exit; } + if (nargs >= 6) { + pminrow = PyLong_AsInt(args[0]); + if (pminrow == -1 && PyErr_Occurred()) { + goto exit; + } + pmincol = PyLong_AsInt(args[1]); + if (pmincol == -1 && PyErr_Occurred()) { + goto exit; + } + sminrow = PyLong_AsInt(args[2]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[3]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + smaxrow = PyLong_AsInt(args[4]); + if (smaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + smaxcol = PyLong_AsInt(args[5]); + if (smaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_refresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); exit: @@ -2491,14 +2619,14 @@ PyDoc_STRVAR(_curses_window_subwin__doc__, "to the lower right corner of the window."); #define _CURSES_WINDOW_SUBWIN_METHODDEF \ - {"subwin", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + {"subwin", _PyCFunction_CAST(_curses_window_subwin), METH_FASTCALL, _curses_window_subwin__doc__}, static PyObject * _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x); static PyObject * -_curses_window_subwin(PyObject *self, PyObject *args) +_curses_window_subwin(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2507,22 +2635,33 @@ _curses_window_subwin(PyObject *self, PyObject *args) int begin_y; int begin_x; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:subwin", &begin_y, &begin_x)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:subwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_left_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.subwin requires 2 to 4 arguments"); goto exit; } + if (nargs >= 4) { + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + begin_y = PyLong_AsInt(args[nargs - 2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[nargs - 1]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } return_value = _curses_window_subwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); exit: @@ -2540,31 +2679,29 @@ PyDoc_STRVAR(_curses_window_scroll__doc__, "negative."); #define _CURSES_WINDOW_SCROLL_METHODDEF \ - {"scroll", (PyCFunction)_curses_window_scroll, METH_VARARGS, _curses_window_scroll__doc__}, + {"scroll", _PyCFunction_CAST(_curses_window_scroll), METH_FASTCALL, _curses_window_scroll__doc__}, static PyObject * _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, int lines); static PyObject * -_curses_window_scroll(PyObject *self, PyObject *args) +_curses_window_scroll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int lines = 1; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "i:scroll", &lines)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + lines = PyLong_AsInt(args[0]); + if (lines == -1 && PyErr_Occurred()) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_scroll_impl((PyCursesWindowObject *)self, group_right_1, lines); @@ -2581,14 +2718,14 @@ PyDoc_STRVAR(_curses_window_touchline__doc__, "(changed=False)."); #define _CURSES_WINDOW_TOUCHLINE_METHODDEF \ - {"touchline", (PyCFunction)_curses_window_touchline, METH_VARARGS, _curses_window_touchline__doc__}, + {"touchline", _PyCFunction_CAST(_curses_window_touchline), METH_FASTCALL, _curses_window_touchline__doc__}, static PyObject * _curses_window_touchline_impl(PyCursesWindowObject *self, int start, int count, int group_right_1, int changed); static PyObject * -_curses_window_touchline(PyObject *self, PyObject *args) +_curses_window_touchline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int start; @@ -2596,21 +2733,24 @@ _curses_window_touchline(PyObject *self, PyObject *args) int group_right_1 = 0; int changed = 1; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "ii:touchline", &start, &count)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "iip:touchline", &start, &count, &changed)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); + if (nargs < 2 || nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); + goto exit; + } + start = PyLong_AsInt(args[0]); + if (start == -1 && PyErr_Occurred()) { + goto exit; + } + count = PyLong_AsInt(args[1]); + if (count == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 3) { + changed = PyObject_IsTrue(args[2]); + if (changed < 0) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_touchline_impl((PyCursesWindowObject *)self, start, count, group_right_1, changed); @@ -2634,7 +2774,7 @@ PyDoc_STRVAR(_curses_window_vline__doc__, " Attributes for the character."); #define _CURSES_WINDOW_VLINE_METHODDEF \ - {"vline", (PyCFunction)_curses_window_vline, METH_VARARGS, _curses_window_vline__doc__}, + {"vline", _PyCFunction_CAST(_curses_window_vline), METH_FASTCALL, _curses_window_vline__doc__}, static PyObject * _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, @@ -2642,7 +2782,7 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_vline(PyObject *self, PyObject *args) +_curses_window_vline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2653,34 +2793,33 @@ _curses_window_vline(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:vline", &ch, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:vline", &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:vline", &y, &x, &ch, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:vline", &y, &x, &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_vline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); @@ -4807,14 +4946,14 @@ PyDoc_STRVAR(_curses_newwin__doc__, "lower right corner of the screen."); #define _CURSES_NEWWIN_METHODDEF \ - {"newwin", (PyCFunction)_curses_newwin, METH_VARARGS, _curses_newwin__doc__}, + {"newwin", _PyCFunction_CAST(_curses_newwin), METH_FASTCALL, _curses_newwin__doc__}, static PyObject * _curses_newwin_impl(PyObject *module, int nlines, int ncols, int group_right_1, int begin_y, int begin_x); static PyObject * -_curses_newwin(PyObject *module, PyObject *args) +_curses_newwin(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int nlines; @@ -4823,22 +4962,33 @@ _curses_newwin(PyObject *module, PyObject *args) int begin_y = 0; int begin_x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:newwin", &nlines, &ncols)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:newwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.newwin requires 2 to 4 arguments"); goto exit; } + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 4) { + begin_y = PyLong_AsInt(args[2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[3]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_newwin_impl(module, nlines, ncols, group_right_1, begin_y, begin_x); exit: @@ -6585,4 +6735,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=680f621e7c1f101b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e23b642a86fd7f59 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index e337ed2390a1fc..0ba747e4fe489e 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_long.h" // _PyLong_Size_t_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() @@ -690,35 +691,42 @@ PyDoc_STRVAR(_ssl__SSLSocket_read__doc__, "Read up to size bytes from the SSL socket."); #define _SSL__SSLSOCKET_READ_METHODDEF \ - {"read", (PyCFunction)_ssl__SSLSocket_read, METH_VARARGS, _ssl__SSLSocket_read__doc__}, + {"read", _PyCFunction_CAST(_ssl__SSLSocket_read), METH_FASTCALL, _ssl__SSLSocket_read__doc__}, static PyObject * _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, int group_right_1, Py_buffer *buffer); static PyObject * -_ssl__SSLSocket_read(PyObject *self, PyObject *args) +_ssl__SSLSocket_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; Py_ssize_t len; int group_right_1 = 0; Py_buffer buffer = {NULL, NULL}; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "n:read", &len)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "nw*:read", &len, &buffer)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_ssl._SSLSocket.read requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_ssl._SSLSocket.read requires 1 to 2 arguments"); + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { goto exit; + } + len = ival; + } + if (nargs >= 2) { + if (PyObject_GetBuffer(args[1], &buffer, PyBUF_WRITABLE) < 0) { + _PyArg_BadArgument("read", "argument 2", "read-write bytes-like object", args[1]); + goto exit; + } + group_right_1 = 1; } Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_read_impl((PySSLSocket *)self, len, group_right_1, &buffer); @@ -3326,4 +3334,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=aef2e74b706c6106 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6643d091f34595ae input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 12bf0639b66427..088e7d103504ea 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -3481,30 +3481,25 @@ PyDoc_STRVAR(only_group__doc__, "only_group([a])"); #define ONLY_GROUP_METHODDEF \ - {"only_group", (PyCFunction)only_group, METH_VARARGS, only_group__doc__}, + {"only_group", _PyCFunction_CAST(only_group), METH_FASTCALL, only_group__doc__}, static PyObject * only_group_impl(PyObject *module, int group_right_1, PyObject *a); static PyObject * -only_group(PyObject *module, PyObject *args) +only_group(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *a = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "O:only_group", &a)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "only_group requires 0 to 1 arguments"); - goto exit; + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "only_group requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + a = args[0]; + group_right_1 = 1; } return_value = only_group_impl(module, group_right_1, a); @@ -3516,14 +3511,14 @@ PyDoc_STRVAR(group_and_opt__doc__, "group_and_opt([a, b,] c=None)"); #define GROUP_AND_OPT_METHODDEF \ - {"group_and_opt", (PyCFunction)group_and_opt, METH_VARARGS, group_and_opt__doc__}, + {"group_and_opt", _PyCFunction_CAST(group_and_opt), METH_FASTCALL, group_and_opt__doc__}, static PyObject * group_and_opt_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c); static PyObject * -group_and_opt(PyObject *module, PyObject *args) +group_and_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3531,24 +3526,22 @@ group_and_opt(PyObject *module, PyObject *args) PyObject *b = NULL; PyObject *c = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O:group_and_opt", &c)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "OO|O:group_and_opt", &a, &b, &c)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_opt requires 0 to 3 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "group_and_opt requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + a = args[0]; + b = args[1]; + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; } + c = args[offset]; +skip_optional: return_value = group_and_opt_impl(module, group_left_1, a, b, c); exit: @@ -3559,7 +3552,7 @@ PyDoc_STRVAR(two_groups_on_left__doc__, "two_groups_on_left([a, b,] [c,] d)"); #define TWO_GROUPS_ON_LEFT_METHODDEF \ - {"two_groups_on_left", (PyCFunction)two_groups_on_left, METH_VARARGS, two_groups_on_left__doc__}, + {"two_groups_on_left", _PyCFunction_CAST(two_groups_on_left), METH_FASTCALL, two_groups_on_left__doc__}, static PyObject * two_groups_on_left_impl(PyObject *module, int group_left_1, PyObject *a, @@ -3567,7 +3560,7 @@ two_groups_on_left_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *d); static PyObject * -two_groups_on_left(PyObject *module, PyObject *args) +two_groups_on_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3577,35 +3570,20 @@ two_groups_on_left(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_left", &d)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_left", &c, &d)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_left", &a, &b, &d)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_left", &a, &b, &c, &d)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_left requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_left requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + c = args[nargs - 2]; + group_left_2 = 1; } + d = args[nargs - 1]; return_value = two_groups_on_left_impl(module, group_left_1, a, b, group_left_2, c, d); exit: @@ -3616,7 +3594,7 @@ PyDoc_STRVAR(two_groups_on_right__doc__, "two_groups_on_right(a, [b,] [c, d])"); #define TWO_GROUPS_ON_RIGHT_METHODDEF \ - {"two_groups_on_right", (PyCFunction)two_groups_on_right, METH_VARARGS, two_groups_on_right__doc__}, + {"two_groups_on_right", _PyCFunction_CAST(two_groups_on_right), METH_FASTCALL, two_groups_on_right__doc__}, static PyObject * two_groups_on_right_impl(PyObject *module, PyObject *a, int group_right_1, @@ -3624,7 +3602,7 @@ two_groups_on_right_impl(PyObject *module, PyObject *a, int group_right_1, PyObject *d); static PyObject * -two_groups_on_right(PyObject *module, PyObject *args) +two_groups_on_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *a; @@ -3634,34 +3612,19 @@ two_groups_on_right(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_right", &a)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_right", &a, &b)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_right", &a, &c, &d)) { - goto exit; - } - group_right_2 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_right", &a, &b, &c, &d)) { - goto exit; - } - group_right_1 = 1; - group_right_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_right requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_right requires 1 to 4 arguments"); + goto exit; + } + a = args[0]; + if (nargs == 2 || nargs == 4) { + b = args[1]; + group_right_1 = 1; + } + if (nargs >= 3) { + c = args[nargs - 2]; + d = args[nargs - 1]; + group_right_2 = 1; } return_value = two_groups_on_right_impl(module, a, group_right_1, b, group_right_2, c, d); @@ -3673,14 +3636,14 @@ PyDoc_STRVAR(group_and_two_opt__doc__, "group_and_two_opt([a, b, c,] d=None, e=None)"); #define GROUP_AND_TWO_OPT_METHODDEF \ - {"group_and_two_opt", (PyCFunction)group_and_two_opt, METH_VARARGS, group_and_two_opt__doc__}, + {"group_and_two_opt", _PyCFunction_CAST(group_and_two_opt), METH_FASTCALL, group_and_two_opt__doc__}, static PyObject * group_and_two_opt_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e); static PyObject * -group_and_two_opt(PyObject *module, PyObject *args) +group_and_two_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3690,26 +3653,27 @@ group_and_two_opt(PyObject *module, PyObject *args) PyObject *d = Py_None; PyObject *e = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - case 2: - if (!PyArg_ParseTuple(args, "|OO:group_and_two_opt", &d, &e)) { - goto exit; - } - break; - case 3: - case 4: - case 5: - if (!PyArg_ParseTuple(args, "OOO|OO:group_and_two_opt", &a, &b, &c, &d, &e)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_two_opt requires 0 to 5 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 5) { + PyErr_SetString(PyExc_TypeError, "group_and_two_opt requires 0 to 5 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + c = args[2]; + offset += 3; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; } + d = args[offset]; + if (nargs <= offset + 1) { + goto skip_optional; + } + e = args[offset + 1]; +skip_optional: return_value = group_and_two_opt_impl(module, group_left_1, a, b, c, d, e); exit: @@ -4839,4 +4803,4 @@ _testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall(PyObject *type, PyO exit: return return_value; } -/*[clinic end generated code: output=15e6c430697bd384 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=10c3b999199d7bbb input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index aa743c8f40a565..0ec615c61cbb2f 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -224,14 +224,14 @@ PyDoc_STRVAR(gc_set_threshold__doc__, "Setting \'threshold0\' to zero disables collection."); #define GC_SET_THRESHOLD_METHODDEF \ - {"set_threshold", (PyCFunction)gc_set_threshold, METH_VARARGS, gc_set_threshold__doc__}, + {"set_threshold", _PyCFunction_CAST(gc_set_threshold), METH_FASTCALL, gc_set_threshold__doc__}, static PyObject * gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1, int threshold1, int group_right_2, int threshold2); static PyObject * -gc_set_threshold(PyObject *module, PyObject *args) +gc_set_threshold(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int threshold0; @@ -240,28 +240,27 @@ gc_set_threshold(PyObject *module, PyObject *args) int group_right_2 = 0; int threshold2 = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "i:set_threshold", &threshold0)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "ii:set_threshold", &threshold0, &threshold1)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iii:set_threshold", &threshold0, &threshold1, &threshold2)) { - goto exit; - } - group_right_1 = 1; - group_right_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "gc.set_threshold requires 1 to 3 arguments"); + if (nargs < 1 || nargs > 3) { + PyErr_SetString(PyExc_TypeError, "gc.set_threshold requires 1 to 3 arguments"); + goto exit; + } + threshold0 = PyLong_AsInt(args[0]); + if (threshold0 == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 2) { + threshold1 = PyLong_AsInt(args[1]); + if (threshold1 == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } + if (nargs >= 3) { + threshold2 = PyLong_AsInt(args[2]); + if (threshold2 == -1 && PyErr_Occurred()) { goto exit; + } + group_right_2 = 1; } return_value = gc_set_threshold_impl(module, threshold0, group_right_1, threshold1, group_right_2, threshold2); @@ -584,4 +583,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=756c0e7719b76971 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d0cb000f41ffe433 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/syslogmodule.c.h b/Modules/clinic/syslogmodule.c.h index f9034982f3b2c7..1603d8ba9ff1c2 100644 --- a/Modules/clinic/syslogmodule.c.h +++ b/Modules/clinic/syslogmodule.c.h @@ -105,35 +105,43 @@ PyDoc_STRVAR(syslog_syslog__doc__, "Send the string message to the system logger."); #define SYSLOG_SYSLOG_METHODDEF \ - {"syslog", (PyCFunction)syslog_syslog, METH_VARARGS, syslog_syslog__doc__}, + {"syslog", _PyCFunction_CAST(syslog_syslog), METH_FASTCALL, syslog_syslog__doc__}, static PyObject * syslog_syslog_impl(PyObject *module, int group_left_1, int priority, const char *message); static PyObject * -syslog_syslog(PyObject *module, PyObject *args) +syslog_syslog(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; int priority = LOG_INFO; const char *message; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "s:syslog", &message)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "is:syslog", &priority, &message)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "syslog.syslog requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "syslog.syslog requires 1 to 2 arguments"); + goto exit; + } + if (nargs >= 2) { + priority = PyLong_AsInt(args[0]); + if (priority == -1 && PyErr_Occurred()) { goto exit; + } + group_left_1 = 1; + } + if (!PyUnicode_Check(args[nargs - 1])) { + _PyArg_BadArgument("syslog", "argument", "str", args[nargs - 1]); + goto exit; + } + Py_ssize_t message_length; + message = PyUnicode_AsUTF8AndSize(args[nargs - 1], &message_length); + if (message == NULL) { + goto exit; + } + if (strlen(message) != (size_t)message_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; } Py_BEGIN_CRITICAL_SECTION(module); return_value = syslog_syslog_impl(module, group_left_1, priority, message); @@ -265,4 +273,4 @@ syslog_LOG_UPTO(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=f92ac9948fa6131e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ab818466dcdbbe59 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/clanguage.py b/Tools/clinic/libclinic/clanguage.py index 1581a19a4fd78a..0f21df9da837a2 100644 --- a/Tools/clinic/libclinic/clanguage.py +++ b/Tools/clinic/libclinic/clanguage.py @@ -1,18 +1,17 @@ from __future__ import annotations import itertools import textwrap -from typing import TYPE_CHECKING, Literal, Final +from typing import TYPE_CHECKING, Final from operator import attrgetter from collections.abc import Iterable import libclinic.cpp -from libclinic import ( - unspecified, fail, Sentinels, VersionTuple) -from libclinic.codegen import CRenderData, TemplateDict, CodeGen +from libclinic import unspecified, fail, VersionTuple +from libclinic.codegen import CRenderData, CodeGen from libclinic.language import Language from libclinic.function import ( - Module, Class, Function, Parameter, ParamTuple, - permute_optional_groups, + Module, Class, Function, Parameter, + group_to_variable_name, GETTER, SETTER, METHOD_INIT) from libclinic.converters import self_converter from libclinic.parse_args import ParseArgsCodeGen @@ -20,20 +19,6 @@ from libclinic.app import Clinic -def count_required(subset: ParamTuple) -> int: - """Return the number of arguments which cannot be omitted. - - A parameter in an optional group is passed together with its group, - so only trailing parameters with a default value can be omitted. - """ - count = len(subset) - for p in reversed(subset): - if p.group or not p.is_optional(): - break - count -= 1 - return count - - def c_id(name: str) -> str: if len(name) == 1 and ord(name) < 256: if name.isalnum(): @@ -260,145 +245,6 @@ def output_templates( args = ParseArgsCodeGen(f, codegen) return args.parse_args(self) - @staticmethod - def group_to_variable_name(group: int) -> str: - adjective = "left_" if group < 0 else "right_" - return "group_" + adjective + str(abs(group)) - - def render_option_group_parsing( - self, - f: Function, - template_dict: TemplateDict, - limited_capi: bool, - ) -> None: - # positional only, grouped, optional arguments! - # can be optional on the left or right. - # here's an example: - # - # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] - # - # Here group D are required, and all other groups are optional. - # (Group D's "group" is actually None.) - # We can figure out which sets of arguments we have based on - # how many arguments are in the tuple. - # - # Note that you need to count up on both sides. For example, - # you could have groups C+D, or C+D+E, or C+D+E+F. - # - # What if the number of arguments leads us to an ambiguous result? - # Clinic prefers groups on the left. So in the above example, - # five arguments would map to B+C, not C+D. - # - # A nested group can only be omitted together with the group - # containing it, but groups on the same level, like G and H in - # - # [ G1 G2 ] [ H1 ] I1 I2 - # - # can be omitted independently of each other. - - out = [] - parameters = list(f.parameters.values()) - if isinstance(parameters[0].converter, self_converter): - del parameters[0] - - # Groups are collected into chains of nested groups. A group which - # is not nested in the preceding one starts a new chain. - group: list[Parameter] | None = None - left: list[list[list[Parameter]]] = [] - right: list[list[list[Parameter]]] = [] - required: list[Parameter] = [] - last: int | Literal[Sentinels.unspecified] = unspecified - last_depth = 0 - - for p in parameters: - group_id = p.group - if group_id != last: - last = group_id - group = [] - if group_id == 0: - group = required - else: - chains = left if group_id < 0 else right - nested = ((p.group_depth < last_depth) if group_id < 0 - else (p.group_depth > last_depth)) - if chains and nested: - chains[-1].append(group) - else: - chains.append([group]) - last_depth = p.group_depth - assert group is not None - group.append(p) - - # Map the number of arguments to the subset which accepts it. - subsets: dict[int, ParamTuple] = {} - for subset in permute_optional_groups(left, required, right): - for count in range(count_required(subset), len(subset) + 1): - if count in subsets: - fail(f"Function {f.full_name!r} has an ambiguous group " - f"configuration: a call with {count} argument(s) " - f"can be parsed in more than one way.") - subsets[count] = subset - - if limited_capi: - nargs = 'PyTuple_Size(args)' - else: - nargs = 'PyTuple_GET_SIZE(args)' - out.append(f"switch ({nargs}) {{\n") - for count, subset in sorted(subsets.items()): - if count < len(subset): - # The omitted parameters are parsed by the following case. - out.append(f" case {count}:\n") - continue - - if count == 0: - out.append(""" case 0: - break; -""") - continue - - # A set would eliminate duplicates too, but the iteration - # order of small negative integers depends on the platform. - group_ids = dict.fromkeys(p.group for p in subset) - d: dict[str, str | int] = {} - d['count'] = count - d['name'] = f.name - format_units = [p.converter.format_unit for p in subset] - n_required = count_required(subset) - if n_required < count: - format_units.insert(n_required, '|') - d['format_units'] = "".join(format_units) - - parse_arguments: list[str] = [] - for p in subset: - p.converter.parse_argument(parse_arguments) - d['parse_arguments'] = ", ".join(parse_arguments) - - group_ids.pop(0, None) - lines = "\n".join([ - self.group_to_variable_name(g) + " = 1;" - for g in group_ids - ]) - - s = """\ - case {count}: - if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{ - goto exit; - }} - {group_booleans} - break; -""" - s = libclinic.linear_format(s, group_booleans=lines) - s = s.format_map(d) - out.append(s) - - out.append(" default:\n") - s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n' - out.append(s.format(f.full_name, min(subsets), max(subsets))) - out.append(' goto exit;\n') - out.append("}") - - template_dict['option_group_parsing'] = libclinic.format_escape("".join(out)) - def render_function( self, clinic: Clinic, @@ -451,7 +297,7 @@ def render_function( if last_group != group: last_group = group if group: - group_name = self.group_to_variable_name(group) + group_name = group_to_variable_name(group) data.impl_arguments.append(group_name) data.declarations.append("int " + group_name + " = 0;") data.impl_parameters.append("int " + group_name) @@ -534,16 +380,9 @@ def render_function( template_dict['unpack_min'] = str(unpack_min) template_dict['unpack_max'] = str(unpack_max) - if has_option_groups: - self.render_option_group_parsing(f, template_dict, - limited_capi=codegen.limited_capi) - # buffers, not destination for name, destination in clinic.destination_buffers.items(): template = templates[name] - if has_option_groups: - template = libclinic.linear_format(template, - option_group_parsing=template_dict['option_group_parsing']) template = libclinic.linear_format(template, declarations=template_dict['declarations'], return_conversion=template_dict['return_conversion'], diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index 325633eb010608..81494e7881d773 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -270,6 +270,25 @@ def render_docstring(self) -> str: ParamTuple = tuple["Parameter", ...] +def group_to_variable_name(group: int) -> str: + adjective = "left_" if group < 0 else "right_" + return "group_" + adjective + str(abs(group)) + + +def count_required(subset: ParamTuple) -> int: + """Return the number of arguments which cannot be omitted. + + A parameter in an optional group is passed together with its group, + so only trailing parameters with a default value can be omitted. + """ + count = len(subset) + for p in reversed(subset): + if p.group or not p.is_optional(): + break + count -= 1 + return count + + def permute_left_option_groups( l: Sequence[Iterable[Parameter]] ) -> Iterator[ParamTuple]: diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 2ad1e94ea2b4c7..524bbdbab5372e 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -1,10 +1,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Final +from typing import TYPE_CHECKING, Final, Literal import libclinic -from libclinic import fail, warn +from libclinic import fail, warn, unspecified, Sentinels from libclinic.function import ( - Function, Parameter, + Function, Parameter, ParamTuple, + count_required, group_to_variable_name, permute_optional_groups, GETTER, SETTER, METHOD_NEW) from libclinic.converter import CConverter from libclinic.converters import ( @@ -462,15 +463,314 @@ def parse_one_arg(self) -> None: parser_code = libclinic.normalize_snippet(parsearg, indent=4) self.parser_body(parser_code) + def option_group_subsets(self) -> dict[int, ParamTuple]: + # positional only, grouped, optional arguments! + # can be optional on the left or right. + # here's an example: + # + # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] + # + # Here group D are required, and all other groups are optional. + # (Group D's "group" is actually None.) + # We can figure out which sets of arguments we have based on + # how many arguments are in the tuple. + # + # Note that you need to count up on both sides. For example, + # you could have groups C+D, or C+D+E, or C+D+E+F. + # + # What if the number of arguments leads us to an ambiguous result? + # Clinic prefers groups on the left. So in the above example, + # five arguments would map to B+C, not C+D. + # + # A nested group can only be omitted together with the group + # containing it, but groups on the same level, like G and H in + # + # [ G1 G2 ] [ H1 ] I1 I2 + # + # can be omitted independently of each other. + + # Groups are collected into chains of nested groups. A group which + # is not nested in the preceding one starts a new chain. + group: list[Parameter] | None = None + left: list[list[list[Parameter]]] = [] + right: list[list[list[Parameter]]] = [] + required: list[Parameter] = [] + last: int | Literal[Sentinels.unspecified] = unspecified + last_depth = 0 + + for p in self.parameters: + group_id = p.group + if group_id != last: + last = group_id + group = [] + if group_id == 0: + group = required + else: + chains = left if group_id < 0 else right + nested = ((p.group_depth < last_depth) if group_id < 0 + else (p.group_depth > last_depth)) + if chains and nested: + chains[-1].append(group) + else: + chains.append([group]) + last_depth = p.group_depth + assert group is not None + group.append(p) + + # Map the number of arguments to the subset which accepts it. + subsets: dict[int, ParamTuple] = {} + for subset in permute_optional_groups(left, required, right): + for count in range(count_required(subset), len(subset) + 1): + if count in subsets: + fail(f"Function {self.func.full_name!r} has an ambiguous " + f"group configuration: a call with {count} " + f"argument(s) can be parsed in more than one way.") + subsets[count] = subset + return subsets + def parse_option_groups(self) -> None: # positional parameters with option groups - # (we have to generate lots of PyArg_ParseTuple calls - # in a big switch statement) + # (which groups are passed is determined by the number of arguments) + + nargs, argname_fmt = self.select_positional_convention() + # With the stack convention "nargs" is already a parameter. + size_expr = None if self.fastcall else nargs + + subsets = self.option_group_subsets() + parser_code = self.render_option_groups(subsets, argname_fmt, size_expr) + if parser_code is None: + # The code of some converter cannot be inlined, so the + # arguments of every combination of groups are parsed at once. + parser_code = self.render_option_groups_parse_tuple(subsets) + self.parser_body(*parser_code) - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - parser_code = ' {option_group_parsing}' - self.parser_body(parser_code) + def render_option_groups( + self, + subsets: dict[int, ParamTuple], + argname_fmt: str, + size_expr: str | None, + ) -> list[str] | None: + """Return the code which parses the arguments of all groups. + + Every parameter is parsed once, in a block guarded by the number of + arguments. Return None if the code of some converter cannot be + inlined. + """ + # Split the parameters into the groups, in the order in which + # they are passed. + groups: list[tuple[int, list[Parameter]]] = [] + for p in self.parameters: + if not groups or groups[-1][0] != p.group: + groups.append((p.group, [])) + groups[-1][1].append(p) + + indices, shifting = self.render_option_group_indices(subsets, groups) + + parser_code = [] + if size_expr is not None: + parser_code.append(libclinic.normalize_snippet( + f"Py_ssize_t nargs = {size_expr};", indent=4)) + if shifting: + parser_code.append(libclinic.normalize_snippet( + "Py_ssize_t offset = 0;", indent=4)) + parser_code.append(self.render_option_group_check(subsets)) + + has_optional = False + for group_id, params in groups: + body = [] + for p in params: + index_expr = indices[p.name] + if index_expr.isdigit(): + displayname = p.get_displayname(int(index_expr) + 1) + else: + # The position of the argument differs between the calls. + displayname = p.get_displayname(0) + parsearg = p.converter.parse_arg(argname_fmt % index_expr, + displayname, + limited_capi=self.limited_capi) + if parsearg is None: + return None + if not group_id and (has_optional or p.is_optional()): + # Such parameter is omitted on its own, and nothing + # can follow it, so the rest is simply skipped. + has_optional = True + body.append(libclinic.normalize_snippet(""" + if (nargs <= %s) {{ + goto skip_optional; + }} + """, indent=4) % index_expr) + body.append(libclinic.normalize_snippet(parsearg, indent=4)) + + if not group_id: + parser_code.extend(body) + continue + + if group_id in shifting: + # The arguments of this group shift the following ones. + body.append(libclinic.normalize_snippet( + f"offset += {len(params)};", indent=4)) + body.append(libclinic.normalize_snippet( + f"{group_to_variable_name(group_id)} = 1;", indent=4)) + condition = self.render_option_group_condition(subsets, group_id) + parser_code.append(libclinic.normalize_snippet( + f"if ({condition}) {{{{", indent=4)) + parser_code.extend(libclinic.normalize_snippet(line, indent=8) + for line in body) + parser_code.append(libclinic.normalize_snippet("}}", indent=4)) + + if has_optional: + parser_code.append("skip_optional:") + return parser_code + + @staticmethod + def render_option_group_indices( + subsets: dict[int, ParamTuple], + groups: list[tuple[int, list[Parameter]]], + ) -> tuple[dict[str, str], set[int]]: + """Return the index of the argument of every parameter, as C code, + and the groups which have to add their size to "offset". + + A group which is not passed shifts the following arguments. Their + index can still be fixed if it is counted from the end; otherwise it + is counted at run time, in "offset". + """ + forward: dict[str, set[int]] = {} + backward: dict[str, set[int]] = {} + for count, subset in subsets.items(): + for i, p in enumerate(subset[:count]): + forward.setdefault(p.name, set()).add(i) + backward.setdefault(p.name, set()).add(count - i) + # A parameter with a default value can be omitted on its own, so + # its index from the end is not fixed. + for group_id, params in groups: + if not group_id: + for p in params: + if p.is_optional(): + backward.pop(p.name) + + def counted_at_run_time(p: Parameter) -> bool: + return (len(forward[p.name]) != 1 + and len(backward.get(p.name, ())) != 1) + + # A group adds its size to "offset" if it shifts an argument + # which is counted at run time. + shifting: set[int] = set() + seen: list[int] = [] + for group_id, params in groups: + if any(counted_at_run_time(p) for p in params): + shifting.update(g for g in seen if g) + seen.append(group_id) + + indices = {} + # The number of the parameters before the current one, and how many + # of them are counted in "offset". + pos = 0 + in_offset = 0 + for group_id, params in groups: + for i, p in enumerate(params): + if not counted_at_run_time(p): + if len(forward[p.name]) == 1: + indices[p.name] = str(min(forward[p.name])) + else: + indices[p.name] = f"nargs - {min(backward[p.name])}" + else: + index = pos + i - in_offset + indices[p.name] = ("offset" if index == 0 + else f"offset + {index}") + pos += len(params) + if group_id in shifting: + in_offset += len(params) + return indices, shifting + + @staticmethod + def render_option_group_condition( + subsets: dict[int, ParamTuple], + group_id: int, + ) -> str: + """Return the condition on which the group is passed.""" + counts = sorted(count for count, subset in subsets.items() + if any(p.group == group_id for p in subset)) + if counts == list(range(counts[0], max(subsets) + 1)): + return f"nargs >= {counts[0]}" + return " || ".join(f"nargs == {count}" for count in counts) + + def render_option_group_check( + self, + subsets: dict[int, ParamTuple], + ) -> str: + """Return the code which rejects an unsupported number of arguments.""" + error = ('PyErr_SetString(PyExc_TypeError, "%s requires %d to %d ' + 'arguments");' % (self.func.full_name, min(subsets), + max(subsets))) + counts = sorted(subsets) + if counts == list(range(counts[0], counts[-1] + 1)): + tests = [f"nargs > {counts[-1]}"] + if counts[0]: + tests.insert(0, f"nargs < {counts[0]}") + lines = [ + f"if ({' || '.join(tests)}) {{{{", + f" {error}", + " goto exit;", + "}}", + ] + else: + # Some numbers of arguments in between are not supported. + lines = ["switch (nargs) {{"] + lines += [f" case {count}:" for count in counts] + lines += [ + " break;", + " default:", + f" {error}", + " goto exit;", + "}}", + ] + return libclinic.normalize_snippet("\n".join(lines), indent=4) + + def render_option_groups_parse_tuple( + self, + subsets: dict[int, ParamTuple], + ) -> list[str]: + """Return the code which parses the arguments of every group at once.""" + parse_call = self.render_parse_all_arguments() + # The convention can have changed, so ask for it again. + size_expr, _ = self.select_positional_convention() + parser_code = [libclinic.normalize_snippet(f"switch ({size_expr}) {{{{", + indent=4)] + for count, subset in sorted(subsets.items()): + parser_code.append(f" case {count}:") + if count != len(subset): + # The omitted parameters are parsed by the following case. + continue + if count: + format_units = [p.converter.format_unit for p in subset] + n_required = count_required(subset) + if n_required < count: + format_units.insert(n_required, '|') + parse_arguments: list[str] = [] + for p in subset: + p.converter.parse_argument(parse_arguments) + parser_code.append(libclinic.normalize_snippet(""" + if (!%s"%s:%s", %s)) {{ + goto exit; + }} + """, indent=12) % (parse_call, "".join(format_units), + self.func.name, + ", ".join(parse_arguments))) + # A set would eliminate duplicates too, but the iteration + # order of small negative integers depends on the platform. + group_ids = dict.fromkeys(p.group for p in subset) + group_ids.pop(0, None) + for group_id in group_ids: + parser_code.append( + f" {group_to_variable_name(group_id)} = 1;") + parser_code.append(" break;") + parser_code.append(" default:") + parser_code.append( + ' PyErr_SetString(PyExc_TypeError, "%s requires %d to %d arguments");' + % (self.func.full_name, min(subsets), max(subsets))) + parser_code.append(" goto exit;") + parser_code.append(" }}") + return parser_code def _parse_vararg(self) -> str: assert self.varpos is not None @@ -488,27 +788,45 @@ def _parse_kwarg(self) -> str: assert isinstance(c, libclinic.converters.VarKeywordCConverter) return c.parse_var_keyword() - def parse_pos_only(self) -> None: - if self.fastcall: - # positional-only, but no option groups - # we only need one call to _PyArg_ParseStack + def select_positional_convention(self) -> tuple[str, str]: + """Select the calling convention of a positional-only function. + Set the method flags and the prototype, and return the expression of + the number of arguments and the format of an argument expression. + """ + if self.fastcall: self.flags = "METH_FASTCALL" self.parser_prototype = PARSER_PROTOTYPE_FASTCALL - nargs = 'nargs' - argname_fmt = 'args[%d]' - else: - # positional-only, but no option groups - # we only need one call to PyArg_ParseTuple + return 'nargs', 'args[%s]' - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - if self.limited_capi: - nargs = 'PyTuple_Size(args)' - argname_fmt = 'PyTuple_GetItem(args, %d)' - else: - nargs = 'PyTuple_GET_SIZE(args)' - argname_fmt = 'PyTuple_GET_ITEM(args, %d)' + self.flags = "METH_VARARGS" + self.parser_prototype = PARSER_PROTOTYPE_VARARGS + if self.limited_capi: + return 'PyTuple_Size(args)', 'PyTuple_GetItem(args, %s)' + return 'PyTuple_GET_SIZE(args)', 'PyTuple_GET_ITEM(args, %s)' + + def render_parse_all_arguments(self) -> str: + """Return the beginning of the call which parses all arguments. + + Fall back to the tuple convention if the stack one cannot be used. + """ + for p in self.parameters: + p.converter.use_converter() + if self.limited_capi: + # _PyArg_ParseStack() is not part of the limited C API. + self.fastcall = False + if self.fastcall: + self.codegen.add_include('pycore_modsupport.h', + '_PyArg_ParseStack()') + return '_PyArg_ParseStack(args, nargs, ' + self.flags = "METH_VARARGS" + self.parser_prototype = PARSER_PROTOTYPE_VARARGS + return 'PyArg_ParseTuple(args, ' + + def parse_pos_only(self) -> None: + # positional-only, but no option groups: we only need one call + # to _PyArg_ParseStack or PyArg_ParseTuple + nargs, argname_fmt = self.select_positional_convention() parser_code = [] max_args = NO_VARARG if self.varpos else self.max_pos @@ -586,29 +904,13 @@ def parse_pos_only(self) -> None: elif self.var_keyword: parser_code.append(libclinic.normalize_snippet(self._parse_kwarg(), indent=4)) else: - for parameter in self.parameters: - parameter.converter.use_converter() - - if self.limited_capi: - self.fastcall = False - if self.fastcall: - self.codegen.add_include('pycore_modsupport.h', - '_PyArg_ParseStack()') - parser_code = [libclinic.normalize_snippet(""" - if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}", - {parse_arguments})) {{ - goto exit; - }} - """, indent=4)] - else: - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - parser_code = [libclinic.normalize_snippet(""" - if (!PyArg_ParseTuple(args, "{format_units}:{name}", - {parse_arguments})) {{ - goto exit; - }} - """, indent=4)] + parse_call = self.render_parse_all_arguments() + parser_code = [libclinic.normalize_snippet(""" + if (!%s"{format_units}:{name}", + {parse_arguments})) {{ + goto exit; + }} + """, indent=4) % parse_call] self.parser_body(*parser_code) def parse_var_keyword(self) -> None: