From c929df3b96c8d7e7977e581431192be21cdafd19 Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Fri, 6 Jul 2018 13:17:38 +0300 Subject: [PATCH] bpo-20180: complete AC conversion of Objects/stringlib/transmogrify.h (GH-8039) * converted bytes methods: expandtabs, ljust, rjust, center, zfill * updated char_convertor to properly set the C default value --- Objects/bytearrayobject.c | 11 +- Objects/bytes_methods.c | 30 ---- Objects/bytesobject.c | 12 +- Objects/stringlib/clinic/transmogrify.h.h | 158 ++++++++++++++++++++++ Objects/stringlib/transmogrify.h | 108 ++++++++++----- Tools/clinic/clinic.py | 24 +++- 6 files changed, 265 insertions(+), 78 deletions(-) create mode 100644 Objects/stringlib/clinic/transmogrify.h.h diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 753ee8ef3a4..9d32965ca23 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2138,7 +2138,7 @@ bytearray_methods[] = { BYTEARRAY_APPEND_METHODDEF {"capitalize", stringlib_capitalize, METH_NOARGS, _Py_capitalize__doc__}, - {"center", (PyCFunction)stringlib_center, METH_VARARGS, _Py_center__doc__}, + STRINGLIB_CENTER_METHODDEF BYTEARRAY_CLEAR_METHODDEF BYTEARRAY_COPY_METHODDEF {"count", (PyCFunction)bytearray_count, METH_VARARGS, @@ -2146,8 +2146,7 @@ bytearray_methods[] = { BYTEARRAY_DECODE_METHODDEF {"endswith", (PyCFunction)bytearray_endswith, METH_VARARGS, _Py_endswith__doc__}, - {"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS, - _Py_expandtabs__doc__}, + STRINGLIB_EXPANDTABS_METHODDEF BYTEARRAY_EXTEND_METHODDEF {"find", (PyCFunction)bytearray_find, METH_VARARGS, _Py_find__doc__}, @@ -2172,7 +2171,7 @@ bytearray_methods[] = { {"isupper", stringlib_isupper, METH_NOARGS, _Py_isupper__doc__}, BYTEARRAY_JOIN_METHODDEF - {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, _Py_ljust__doc__}, + STRINGLIB_LJUST_METHODDEF {"lower", stringlib_lower, METH_NOARGS, _Py_lower__doc__}, BYTEARRAY_LSTRIP_METHODDEF BYTEARRAY_MAKETRANS_METHODDEF @@ -2183,7 +2182,7 @@ bytearray_methods[] = { BYTEARRAY_REVERSE_METHODDEF {"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__}, {"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__}, - {"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, _Py_rjust__doc__}, + STRINGLIB_RJUST_METHODDEF BYTEARRAY_RPARTITION_METHODDEF BYTEARRAY_RSPLIT_METHODDEF BYTEARRAY_RSTRIP_METHODDEF @@ -2197,7 +2196,7 @@ bytearray_methods[] = { {"title", stringlib_title, METH_NOARGS, _Py_title__doc__}, BYTEARRAY_TRANSLATE_METHODDEF {"upper", stringlib_upper, METH_NOARGS, _Py_upper__doc__}, - {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__}, + STRINGLIB_ZFILL_METHODDEF {NULL} }; diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index 07842f74691..05679e31c9d 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -845,33 +845,3 @@ _Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args) { return _Py_bytes_tailmatch(str, len, "endswith", args, +1); } - -PyDoc_STRVAR_shared(_Py_expandtabs__doc__, -"B.expandtabs(tabsize=8) -> copy of B\n\ -\n\ -Return a copy of B where all tab characters are expanded using spaces.\n\ -If tabsize is not given, a tab size of 8 characters is assumed."); - -PyDoc_STRVAR_shared(_Py_ljust__doc__, -"B.ljust(width[, fillchar]) -> copy of B\n" -"\n" -"Return B left justified in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)."); - -PyDoc_STRVAR_shared(_Py_rjust__doc__, -"B.rjust(width[, fillchar]) -> copy of B\n" -"\n" -"Return B right justified in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)"); - -PyDoc_STRVAR_shared(_Py_center__doc__, -"B.center(width[, fillchar]) -> copy of B\n" -"\n" -"Return B centered in a string of length width. Padding is\n" -"done using the specified fill character (default is a space)."); - -PyDoc_STRVAR_shared(_Py_zfill__doc__, -"B.zfill(width) -> copy of B\n" -"\n" -"Pad a numeric string B with zeros on the left, to fill a field\n" -"of the specified width. B is never truncated."); diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index f5bd5fba719..943c329ebc2 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2441,15 +2441,13 @@ bytes_methods[] = { {"__getnewargs__", (PyCFunction)bytes_getnewargs, METH_NOARGS}, {"capitalize", stringlib_capitalize, METH_NOARGS, _Py_capitalize__doc__}, - {"center", (PyCFunction)stringlib_center, METH_VARARGS, - _Py_center__doc__}, + STRINGLIB_CENTER_METHODDEF {"count", (PyCFunction)bytes_count, METH_VARARGS, _Py_count__doc__}, BYTES_DECODE_METHODDEF {"endswith", (PyCFunction)bytes_endswith, METH_VARARGS, _Py_endswith__doc__}, - {"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS | METH_KEYWORDS, - _Py_expandtabs__doc__}, + STRINGLIB_EXPANDTABS_METHODDEF {"find", (PyCFunction)bytes_find, METH_VARARGS, _Py_find__doc__}, BYTES_FROMHEX_METHODDEF @@ -2472,7 +2470,7 @@ bytes_methods[] = { {"isupper", stringlib_isupper, METH_NOARGS, _Py_isupper__doc__}, BYTES_JOIN_METHODDEF - {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, _Py_ljust__doc__}, + STRINGLIB_LJUST_METHODDEF {"lower", stringlib_lower, METH_NOARGS, _Py_lower__doc__}, BYTES_LSTRIP_METHODDEF BYTES_MAKETRANS_METHODDEF @@ -2480,7 +2478,7 @@ bytes_methods[] = { BYTES_REPLACE_METHODDEF {"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, _Py_rfind__doc__}, {"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, _Py_rindex__doc__}, - {"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, _Py_rjust__doc__}, + STRINGLIB_RJUST_METHODDEF BYTES_RPARTITION_METHODDEF BYTES_RSPLIT_METHODDEF BYTES_RSTRIP_METHODDEF @@ -2494,7 +2492,7 @@ bytes_methods[] = { {"title", stringlib_title, METH_NOARGS, _Py_title__doc__}, BYTES_TRANSLATE_METHODDEF {"upper", stringlib_upper, METH_NOARGS, _Py_upper__doc__}, - {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, _Py_zfill__doc__}, + STRINGLIB_ZFILL_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Objects/stringlib/clinic/transmogrify.h.h b/Objects/stringlib/clinic/transmogrify.h.h new file mode 100644 index 00000000000..6d266225c02 --- /dev/null +++ b/Objects/stringlib/clinic/transmogrify.h.h @@ -0,0 +1,158 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(stringlib_expandtabs__doc__, +"expandtabs($self, /, tabsize=8)\n" +"--\n" +"\n" +"Return a copy where all tab characters are expanded using spaces.\n" +"\n" +"If tabsize is not given, a tab size of 8 characters is assumed."); + +#define STRINGLIB_EXPANDTABS_METHODDEF \ + {"expandtabs", (PyCFunction)stringlib_expandtabs, METH_FASTCALL|METH_KEYWORDS, stringlib_expandtabs__doc__}, + +static PyObject * +stringlib_expandtabs_impl(PyObject *self, int tabsize); + +static PyObject * +stringlib_expandtabs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"tabsize", NULL}; + static _PyArg_Parser _parser = {"|i:expandtabs", _keywords, 0}; + int tabsize = 8; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &tabsize)) { + goto exit; + } + return_value = stringlib_expandtabs_impl(self, tabsize); + +exit: + return return_value; +} + +PyDoc_STRVAR(stringlib_ljust__doc__, +"ljust($self, width, fillchar=b\' \', /)\n" +"--\n" +"\n" +"Return a left-justified string of length width.\n" +"\n" +"Padding is done using the specified fill character."); + +#define STRINGLIB_LJUST_METHODDEF \ + {"ljust", (PyCFunction)stringlib_ljust, METH_FASTCALL, stringlib_ljust__doc__}, + +static PyObject * +stringlib_ljust_impl(PyObject *self, Py_ssize_t width, char fillchar); + +static PyObject * +stringlib_ljust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + char fillchar = ' '; + + if (!_PyArg_ParseStack(args, nargs, "n|c:ljust", + &width, &fillchar)) { + goto exit; + } + return_value = stringlib_ljust_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(stringlib_rjust__doc__, +"rjust($self, width, fillchar=b\' \', /)\n" +"--\n" +"\n" +"Return a right-justified string of length width.\n" +"\n" +"Padding is done using the specified fill character."); + +#define STRINGLIB_RJUST_METHODDEF \ + {"rjust", (PyCFunction)stringlib_rjust, METH_FASTCALL, stringlib_rjust__doc__}, + +static PyObject * +stringlib_rjust_impl(PyObject *self, Py_ssize_t width, char fillchar); + +static PyObject * +stringlib_rjust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + char fillchar = ' '; + + if (!_PyArg_ParseStack(args, nargs, "n|c:rjust", + &width, &fillchar)) { + goto exit; + } + return_value = stringlib_rjust_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(stringlib_center__doc__, +"center($self, width, fillchar=b\' \', /)\n" +"--\n" +"\n" +"Return a centered string of length width.\n" +"\n" +"Padding is done using the specified fill character."); + +#define STRINGLIB_CENTER_METHODDEF \ + {"center", (PyCFunction)stringlib_center, METH_FASTCALL, stringlib_center__doc__}, + +static PyObject * +stringlib_center_impl(PyObject *self, Py_ssize_t width, char fillchar); + +static PyObject * +stringlib_center(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + char fillchar = ' '; + + if (!_PyArg_ParseStack(args, nargs, "n|c:center", + &width, &fillchar)) { + goto exit; + } + return_value = stringlib_center_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(stringlib_zfill__doc__, +"zfill($self, width, /)\n" +"--\n" +"\n" +"Pad a numeric string with zeros on the left, to fill a field of the given width.\n" +"\n" +"The original string is never truncated."); + +#define STRINGLIB_ZFILL_METHODDEF \ + {"zfill", (PyCFunction)stringlib_zfill, METH_O, stringlib_zfill__doc__}, + +static PyObject * +stringlib_zfill_impl(PyObject *self, Py_ssize_t width); + +static PyObject * +stringlib_zfill(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + + if (!PyArg_Parse(arg, "n:zfill", &width)) { + goto exit; + } + return_value = stringlib_zfill_impl(self, width); + +exit: + return return_value; +} +/*[clinic end generated code: output=336620159a1fc70d input=a9049054013a1b77]*/ diff --git a/Objects/stringlib/transmogrify.h b/Objects/stringlib/transmogrify.h index 326ce14849c..9506019d5af 100644 --- a/Objects/stringlib/transmogrify.h +++ b/Objects/stringlib/transmogrify.h @@ -5,6 +5,13 @@ /* the more complicated methods. parts of these should be pulled out into the shared code in bytes_methods.c to cut down on duplicate code bloat. */ +/*[clinic input] +class B "PyObject *" "&PyType_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2935558188d97c76]*/ + +#include "clinic/transmogrify.h.h" + static inline PyObject * return_self(PyObject *self) { @@ -17,19 +24,24 @@ return_self(PyObject *self) return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self)); } -static PyObject* -stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds) +/*[clinic input] +B.expandtabs as stringlib_expandtabs + + tabsize: int = 8 + +Return a copy where all tab characters are expanded using spaces. + +If tabsize is not given, a tab size of 8 characters is assumed. +[clinic start generated code]*/ + +static PyObject * +stringlib_expandtabs_impl(PyObject *self, int tabsize) +/*[clinic end generated code: output=069cb7fae72e4c2b input=3c6d3b12aa3ccbea]*/ { const char *e, *p; char *q; Py_ssize_t i, j; PyObject *u; - static char *kwlist[] = {"tabsize", 0}; - int tabsize = 8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:expandtabs", - kwlist, &tabsize)) - return NULL; /* First pass: determine size of output string */ i = j = 0; @@ -119,15 +131,22 @@ pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill) return u; } +/*[clinic input] +B.ljust as stringlib_ljust + + width: Py_ssize_t + fillchar: char = b' ' + / + +Return a left-justified string of length width. + +Padding is done using the specified fill character. +[clinic start generated code]*/ + static PyObject * -stringlib_ljust(PyObject *self, PyObject *args) +stringlib_ljust_impl(PyObject *self, Py_ssize_t width, char fillchar) +/*[clinic end generated code: output=c79ca173c5ff8337 input=eff2d014bc7d80df]*/ { - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar)) - return NULL; - if (STRINGLIB_LEN(self) >= width) { return return_self(self); } @@ -136,15 +155,22 @@ stringlib_ljust(PyObject *self, PyObject *args) } +/*[clinic input] +B.rjust as stringlib_rjust + + width: Py_ssize_t + fillchar: char = b' ' + / + +Return a right-justified string of length width. + +Padding is done using the specified fill character. +[clinic start generated code]*/ + static PyObject * -stringlib_rjust(PyObject *self, PyObject *args) +stringlib_rjust_impl(PyObject *self, Py_ssize_t width, char fillchar) +/*[clinic end generated code: output=7df5d728a5439570 input=218b0bd31308955d]*/ { - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar)) - return NULL; - if (STRINGLIB_LEN(self) >= width) { return return_self(self); } @@ -153,15 +179,23 @@ stringlib_rjust(PyObject *self, PyObject *args) } +/*[clinic input] +B.center as stringlib_center + + width: Py_ssize_t + fillchar: char = b' ' + / + +Return a centered string of length width. + +Padding is done using the specified fill character. +[clinic start generated code]*/ + static PyObject * -stringlib_center(PyObject *self, PyObject *args) +stringlib_center_impl(PyObject *self, Py_ssize_t width, char fillchar) +/*[clinic end generated code: output=d8da2e055288b4c2 input=3776fd278765d89b]*/ { Py_ssize_t marg, left; - Py_ssize_t width; - char fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar)) - return NULL; if (STRINGLIB_LEN(self) >= width) { return return_self(self); @@ -173,16 +207,24 @@ stringlib_center(PyObject *self, PyObject *args) return pad(self, left, marg - left, fillchar); } +/*[clinic input] +B.zfill as stringlib_zfill + + width: Py_ssize_t + / + +Pad a numeric string with zeros on the left, to fill a field of the given width. + +The original string is never truncated. +[clinic start generated code]*/ + static PyObject * -stringlib_zfill(PyObject *self, PyObject *args) +stringlib_zfill_impl(PyObject *self, Py_ssize_t width) +/*[clinic end generated code: output=0b3c684a7f1b2319 input=2da6d7b8e9bcb19a]*/ { Py_ssize_t fill; PyObject *s; char *p; - Py_ssize_t width; - - if (!PyArg_ParseTuple(args, "n:zfill", &width)) - return NULL; if (STRINGLIB_LEN(self) >= width) { return return_self(self); diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index b704b5a669f..e7c7eb47e81 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2556,9 +2556,29 @@ class char_converter(CConverter): format_unit = 'c' c_ignored_default = "'\0'" + # characters which need to be escaped in C code + _escapes = {x: r'\%d' % x for x in range(7)} + _escapes.update({ + 0x07: r'\a', + 0x08: r'\b', + 0x09: r'\t', + 0x0A: r'\n', + 0x0B: r'\v', + 0x0C: r'\f', + 0x0D: r'\r', + 0x22: r'\"', + 0x27: r'\'', + 0x3F: r'\?', + 0x5C: r'\\', + }) + def converter_init(self): - if isinstance(self.default, self.default_type) and (len(self.default) != 1): - fail("char_converter: illegal default value " + repr(self.default)) + if isinstance(self.default, self.default_type): + if len(self.default) != 1: + fail("char_converter: illegal default value " + repr(self.default)) + + c_ord = self.default[0] + self.c_default = "'%s'" % self._escapes.get(c_ord, chr(c_ord)) @add_legacy_c_converter('B', bitwise=True)