| 
									
										
										
										
											2025-04-30 11:46:41 +02:00
										 |  |  | /* 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 | 
					
						
							| 
									
										
										
										
											2025-07-10 07:27:41 -07:00
										 |  |  |     expression: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = "" | 
					
						
							| 
									
										
										
										
											2025-04-30 11:46:41 +02:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2025-07-10 07:27:41 -07:00
										 |  |  | /*[clinic end generated code: output=6488e288765bc1a9 input=fc5c285c1dd23d36]*/ | 
					
						
							| 
									
										
										
										
											2025-04-30 11:46:41 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     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)")}, | 
					
						
							| 
									
										
										
										
											2025-05-15 09:11:46 +03:00
										 |  |  |     {"__class_getitem__", Py_GenericAlias, | 
					
						
							|  |  |  |         METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, | 
					
						
							| 
									
										
										
										
											2025-04-30 11:46:41 +02:00
										 |  |  |     {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); | 
					
						
							|  |  |  | } |