| /* 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', c_default='&_Py_STR(empty)') = "" | |
| 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=fc5c285c1dd23d36]*/ | |
| { | |
| 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)")}, | |
| {"__class_getitem__", Py_GenericAlias, | |
| METH_O|METH_CLASS, PyDoc_STR("Interpolations are generic over the types of their values")}, | |
| {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); | |
| } |