diff options
author | Lysandros Nikolaou <lisandrosnik@gmail.com> | 2025-04-30 11:46:41 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-30 11:46:41 +0200 |
commit | 60202609a2c2d0971aadfa4729ba30b50e89c6ea (patch) | |
tree | d821f3f8f277de56e5d8da457d492f1288cb2bb9 /Objects/interpolationobject.c | |
parent | 5ea9010e8910cb97555c3aef4ed95cca93a74aab (diff) | |
download | cpython-60202609a2c2d0971aadfa4729ba30b50e89c6ea.tar.gz cpython-60202609a2c2d0971aadfa4729ba30b50e89c6ea.zip |
gh-132661: Implement PEP 750 (#132662)
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Wingy <git@wingysam.xyz>
Co-authored-by: Koudai Aono <koxudaxi@gmail.com>
Co-authored-by: Dave Peck <davepeck@gmail.com>
Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
Co-authored-by: Paul Everitt <pauleveritt@me.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
Diffstat (limited to 'Objects/interpolationobject.c')
-rw-r--r-- | Objects/interpolationobject.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/Objects/interpolationobject.c b/Objects/interpolationobject.c new file mode 100644 index 00000000000..aaea3b8c067 --- /dev/null +++ b/Objects/interpolationobject.c @@ -0,0 +1,229 @@ +/* t-string Interpolation object implementation */ + +#include "Python.h" +#include "pycore_initconfig.h" // _PyStatus_OK +#include "pycore_interpolation.h" +#include "pycore_typeobject.h" // _PyType_GetDict + +static int +_conversion_converter(PyObject *arg, PyObject **conversion) +{ + if (arg == Py_None) { + return 1; + } + + if (!PyUnicode_Check(arg)) { + PyErr_Format(PyExc_TypeError, + "Interpolation() argument 'conversion' must be str, not %T", + arg); + return 0; + } + + Py_ssize_t len; + const char *conv_str = PyUnicode_AsUTF8AndSize(arg, &len); + if (len != 1 || !(conv_str[0] == 'a' || conv_str[0] == 'r' || conv_str[0] == 's')) { + PyErr_SetString(PyExc_ValueError, + "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'"); + return 0; + } + + *conversion = arg; + return 1; +} + +#include "clinic/interpolationobject.c.h" + +/*[clinic input] +class Interpolation "interpolationobject *" "&_PyInterpolation_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=161c64a16f9c4544]*/ + +typedef struct { + PyObject_HEAD + PyObject *value; + PyObject *expression; + PyObject *conversion; + PyObject *format_spec; +} interpolationobject; + +#define interpolationobject_CAST(op) \ + (assert(_PyInterpolation_CheckExact(op)), _Py_CAST(interpolationobject*, (op))) + +/*[clinic input] +@classmethod +Interpolation.__new__ as interpolation_new + + value: object + expression: object(subclass_of='&PyUnicode_Type') + conversion: object(converter='_conversion_converter') = None + format_spec: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = "" +[clinic start generated code]*/ + +static PyObject * +interpolation_new_impl(PyTypeObject *type, PyObject *value, + PyObject *expression, PyObject *conversion, + PyObject *format_spec) +/*[clinic end generated code: output=6488e288765bc1a9 input=d91711024068528c]*/ +{ + interpolationobject *self = PyObject_GC_New(interpolationobject, type); + if (!self) { + return NULL; + } + + self->value = Py_NewRef(value); + self->expression = Py_NewRef(expression); + self->conversion = Py_NewRef(conversion); + self->format_spec = Py_NewRef(format_spec); + PyObject_GC_Track(self); + return (PyObject *) self; +} + +static void +interpolation_dealloc(PyObject *op) +{ + PyObject_GC_UnTrack(op); + Py_TYPE(op)->tp_clear(op); + Py_TYPE(op)->tp_free(op); +} + +static int +interpolation_clear(PyObject *op) +{ + interpolationobject *self = interpolationobject_CAST(op); + Py_CLEAR(self->value); + Py_CLEAR(self->expression); + Py_CLEAR(self->conversion); + Py_CLEAR(self->format_spec); + return 0; +} + +static int +interpolation_traverse(PyObject *op, visitproc visit, void *arg) +{ + interpolationobject *self = interpolationobject_CAST(op); + Py_VISIT(self->value); + Py_VISIT(self->expression); + Py_VISIT(self->conversion); + Py_VISIT(self->format_spec); + return 0; +} + +static PyObject * +interpolation_repr(PyObject *op) +{ + interpolationobject *self = interpolationobject_CAST(op); + return PyUnicode_FromFormat("%s(%R, %R, %R, %R)", + _PyType_Name(Py_TYPE(self)), self->value, self->expression, + self->conversion, self->format_spec); +} + +static PyMemberDef interpolation_members[] = { + {"value", Py_T_OBJECT_EX, offsetof(interpolationobject, value), Py_READONLY, "Value"}, + {"expression", Py_T_OBJECT_EX, offsetof(interpolationobject, expression), Py_READONLY, "Expression"}, + {"conversion", Py_T_OBJECT_EX, offsetof(interpolationobject, conversion), Py_READONLY, "Conversion"}, + {"format_spec", Py_T_OBJECT_EX, offsetof(interpolationobject, format_spec), Py_READONLY, "Format specifier"}, + {NULL} +}; + +static PyObject* +interpolation_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) +{ + interpolationobject *self = interpolationobject_CAST(op); + return Py_BuildValue("(O(OOOO))", (PyObject *)Py_TYPE(op), + self->value, self->expression, + self->conversion, self->format_spec); +} + +static PyMethodDef interpolation_methods[] = { + {"__reduce__", interpolation_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + {NULL, NULL}, +}; + +PyTypeObject _PyInterpolation_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "string.templatelib.Interpolation", + .tp_doc = PyDoc_STR("Interpolation object"), + .tp_basicsize = sizeof(interpolationobject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_new = interpolation_new, + .tp_alloc = PyType_GenericAlloc, + .tp_dealloc = interpolation_dealloc, + .tp_clear = interpolation_clear, + .tp_free = PyObject_GC_Del, + .tp_repr = interpolation_repr, + .tp_members = interpolation_members, + .tp_methods = interpolation_methods, + .tp_traverse = interpolation_traverse, +}; + +PyStatus +_PyInterpolation_InitTypes(PyInterpreterState *interp) +{ + PyObject *tuple = Py_BuildValue("(ssss)", "value", "expression", "conversion", "format_spec"); + if (!tuple) { + goto error; + } + + PyObject *dict = _PyType_GetDict(&_PyInterpolation_Type); + if (!dict) { + Py_DECREF(tuple); + goto error; + } + + int status = PyDict_SetItemString(dict, "__match_args__", tuple); + Py_DECREF(tuple); + if (status < 0) { + goto error; + } + return _PyStatus_OK(); + +error: + return _PyStatus_ERR("Can't initialize interpolation types"); +} + +PyObject * +_PyInterpolation_Build(PyObject *value, PyObject *str, int conversion, PyObject *format_spec) +{ + interpolationobject *interpolation = PyObject_GC_New(interpolationobject, &_PyInterpolation_Type); + if (!interpolation) { + return NULL; + } + + interpolation->value = Py_NewRef(value); + interpolation->expression = Py_NewRef(str); + interpolation->format_spec = Py_NewRef(format_spec); + interpolation->conversion = NULL; + + if (conversion == 0) { + interpolation->conversion = Py_None; + } + else { + switch (conversion) { + case FVC_ASCII: + interpolation->conversion = _Py_LATIN1_CHR('a'); + break; + case FVC_REPR: + interpolation->conversion = _Py_LATIN1_CHR('r'); + break; + case FVC_STR: + interpolation->conversion = _Py_LATIN1_CHR('s'); + break; + default: + PyErr_SetString(PyExc_SystemError, + "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'"); + Py_DECREF(interpolation); + return NULL; + } + } + + PyObject_GC_Track(interpolation); + return (PyObject *) interpolation; +} + +PyObject * +_PyInterpolation_GetValueRef(PyObject *interpolation) +{ + return Py_NewRef(interpolationobject_CAST(interpolation)->value); +} |