/src/cpython/Objects/interpolationobject.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* t-string Interpolation object implementation */ |
2 | | |
3 | | #include "Python.h" |
4 | | #include "pycore_initconfig.h" // _PyStatus_OK |
5 | | #include "pycore_interpolation.h" |
6 | | #include "pycore_typeobject.h" // _PyType_GetDict |
7 | | |
8 | | static int |
9 | | _conversion_converter(PyObject *arg, PyObject **conversion) |
10 | 0 | { |
11 | 0 | if (arg == Py_None) { |
12 | 0 | return 1; |
13 | 0 | } |
14 | | |
15 | 0 | if (!PyUnicode_Check(arg)) { |
16 | 0 | PyErr_Format(PyExc_TypeError, |
17 | 0 | "Interpolation() argument 'conversion' must be str, not %T", |
18 | 0 | arg); |
19 | 0 | return 0; |
20 | 0 | } |
21 | | |
22 | 0 | Py_ssize_t len; |
23 | 0 | const char *conv_str = PyUnicode_AsUTF8AndSize(arg, &len); |
24 | 0 | if (len != 1 || !(conv_str[0] == 'a' || conv_str[0] == 'r' || conv_str[0] == 's')) { |
25 | 0 | PyErr_SetString(PyExc_ValueError, |
26 | 0 | "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'"); |
27 | 0 | return 0; |
28 | 0 | } |
29 | | |
30 | 0 | *conversion = arg; |
31 | 0 | return 1; |
32 | 0 | } |
33 | | |
34 | | #include "clinic/interpolationobject.c.h" |
35 | | |
36 | | /*[clinic input] |
37 | | class Interpolation "interpolationobject *" "&_PyInterpolation_Type" |
38 | | [clinic start generated code]*/ |
39 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=161c64a16f9c4544]*/ |
40 | | |
41 | | typedef struct { |
42 | | PyObject_HEAD |
43 | | PyObject *value; |
44 | | PyObject *expression; |
45 | | PyObject *conversion; |
46 | | PyObject *format_spec; |
47 | | } interpolationobject; |
48 | | |
49 | | #define interpolationobject_CAST(op) \ |
50 | 0 | (assert(_PyInterpolation_CheckExact(op)), _Py_CAST(interpolationobject*, (op))) |
51 | | |
52 | | /*[clinic input] |
53 | | @classmethod |
54 | | Interpolation.__new__ as interpolation_new |
55 | | |
56 | | value: object |
57 | | expression: object(subclass_of='&PyUnicode_Type') |
58 | | conversion: object(converter='_conversion_converter') = None |
59 | | format_spec: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = "" |
60 | | [clinic start generated code]*/ |
61 | | |
62 | | static PyObject * |
63 | | interpolation_new_impl(PyTypeObject *type, PyObject *value, |
64 | | PyObject *expression, PyObject *conversion, |
65 | | PyObject *format_spec) |
66 | | /*[clinic end generated code: output=6488e288765bc1a9 input=d91711024068528c]*/ |
67 | 0 | { |
68 | 0 | interpolationobject *self = PyObject_GC_New(interpolationobject, type); |
69 | 0 | if (!self) { |
70 | 0 | return NULL; |
71 | 0 | } |
72 | | |
73 | 0 | self->value = Py_NewRef(value); |
74 | 0 | self->expression = Py_NewRef(expression); |
75 | 0 | self->conversion = Py_NewRef(conversion); |
76 | 0 | self->format_spec = Py_NewRef(format_spec); |
77 | 0 | PyObject_GC_Track(self); |
78 | 0 | return (PyObject *) self; |
79 | 0 | } |
80 | | |
81 | | static void |
82 | | interpolation_dealloc(PyObject *op) |
83 | 0 | { |
84 | 0 | PyObject_GC_UnTrack(op); |
85 | 0 | Py_TYPE(op)->tp_clear(op); |
86 | 0 | Py_TYPE(op)->tp_free(op); |
87 | 0 | } |
88 | | |
89 | | static int |
90 | | interpolation_clear(PyObject *op) |
91 | 0 | { |
92 | 0 | interpolationobject *self = interpolationobject_CAST(op); |
93 | 0 | Py_CLEAR(self->value); |
94 | 0 | Py_CLEAR(self->expression); |
95 | 0 | Py_CLEAR(self->conversion); |
96 | 0 | Py_CLEAR(self->format_spec); |
97 | 0 | return 0; |
98 | 0 | } |
99 | | |
100 | | static int |
101 | | interpolation_traverse(PyObject *op, visitproc visit, void *arg) |
102 | 0 | { |
103 | 0 | interpolationobject *self = interpolationobject_CAST(op); |
104 | 0 | Py_VISIT(self->value); |
105 | 0 | Py_VISIT(self->expression); |
106 | 0 | Py_VISIT(self->conversion); |
107 | 0 | Py_VISIT(self->format_spec); |
108 | 0 | return 0; |
109 | 0 | } |
110 | | |
111 | | static PyObject * |
112 | | interpolation_repr(PyObject *op) |
113 | 0 | { |
114 | 0 | interpolationobject *self = interpolationobject_CAST(op); |
115 | 0 | return PyUnicode_FromFormat("%s(%R, %R, %R, %R)", |
116 | 0 | _PyType_Name(Py_TYPE(self)), self->value, self->expression, |
117 | 0 | self->conversion, self->format_spec); |
118 | 0 | } |
119 | | |
120 | | static PyMemberDef interpolation_members[] = { |
121 | | {"value", Py_T_OBJECT_EX, offsetof(interpolationobject, value), Py_READONLY, "Value"}, |
122 | | {"expression", Py_T_OBJECT_EX, offsetof(interpolationobject, expression), Py_READONLY, "Expression"}, |
123 | | {"conversion", Py_T_OBJECT_EX, offsetof(interpolationobject, conversion), Py_READONLY, "Conversion"}, |
124 | | {"format_spec", Py_T_OBJECT_EX, offsetof(interpolationobject, format_spec), Py_READONLY, "Format specifier"}, |
125 | | {NULL} |
126 | | }; |
127 | | |
128 | | static PyObject* |
129 | | interpolation_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) |
130 | 0 | { |
131 | 0 | interpolationobject *self = interpolationobject_CAST(op); |
132 | 0 | return Py_BuildValue("(O(OOOO))", (PyObject *)Py_TYPE(op), |
133 | 0 | self->value, self->expression, |
134 | 0 | self->conversion, self->format_spec); |
135 | 0 | } |
136 | | |
137 | | static PyMethodDef interpolation_methods[] = { |
138 | | {"__reduce__", interpolation_reduce, METH_NOARGS, |
139 | | PyDoc_STR("__reduce__() -> (cls, state)")}, |
140 | | {"__class_getitem__", Py_GenericAlias, |
141 | | METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, |
142 | | {NULL, NULL}, |
143 | | }; |
144 | | |
145 | | PyTypeObject _PyInterpolation_Type = { |
146 | | PyVarObject_HEAD_INIT(NULL, 0) |
147 | | .tp_name = "string.templatelib.Interpolation", |
148 | | .tp_doc = PyDoc_STR("Interpolation object"), |
149 | | .tp_basicsize = sizeof(interpolationobject), |
150 | | .tp_itemsize = 0, |
151 | | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, |
152 | | .tp_new = interpolation_new, |
153 | | .tp_alloc = PyType_GenericAlloc, |
154 | | .tp_dealloc = interpolation_dealloc, |
155 | | .tp_clear = interpolation_clear, |
156 | | .tp_free = PyObject_GC_Del, |
157 | | .tp_repr = interpolation_repr, |
158 | | .tp_members = interpolation_members, |
159 | | .tp_methods = interpolation_methods, |
160 | | .tp_traverse = interpolation_traverse, |
161 | | }; |
162 | | |
163 | | PyStatus |
164 | | _PyInterpolation_InitTypes(PyInterpreterState *interp) |
165 | 16 | { |
166 | 16 | PyObject *tuple = Py_BuildValue("(ssss)", "value", "expression", "conversion", "format_spec"); |
167 | 16 | if (!tuple) { |
168 | 0 | goto error; |
169 | 0 | } |
170 | | |
171 | 16 | PyObject *dict = _PyType_GetDict(&_PyInterpolation_Type); |
172 | 16 | if (!dict) { |
173 | 0 | Py_DECREF(tuple); |
174 | 0 | goto error; |
175 | 0 | } |
176 | | |
177 | 16 | int status = PyDict_SetItemString(dict, "__match_args__", tuple); |
178 | 16 | Py_DECREF(tuple); |
179 | 16 | if (status < 0) { |
180 | 0 | goto error; |
181 | 0 | } |
182 | 16 | return _PyStatus_OK(); |
183 | | |
184 | 0 | error: |
185 | 0 | return _PyStatus_ERR("Can't initialize interpolation types"); |
186 | 16 | } |
187 | | |
188 | | PyObject * |
189 | | _PyInterpolation_Build(PyObject *value, PyObject *str, int conversion, PyObject *format_spec) |
190 | 0 | { |
191 | 0 | interpolationobject *interpolation = PyObject_GC_New(interpolationobject, &_PyInterpolation_Type); |
192 | 0 | if (!interpolation) { |
193 | 0 | return NULL; |
194 | 0 | } |
195 | | |
196 | 0 | interpolation->value = Py_NewRef(value); |
197 | 0 | interpolation->expression = Py_NewRef(str); |
198 | 0 | interpolation->format_spec = Py_NewRef(format_spec); |
199 | 0 | interpolation->conversion = NULL; |
200 | |
|
201 | 0 | if (conversion == 0) { |
202 | 0 | interpolation->conversion = Py_None; |
203 | 0 | } |
204 | 0 | else { |
205 | 0 | switch (conversion) { |
206 | 0 | case FVC_ASCII: |
207 | 0 | interpolation->conversion = _Py_LATIN1_CHR('a'); |
208 | 0 | break; |
209 | 0 | case FVC_REPR: |
210 | 0 | interpolation->conversion = _Py_LATIN1_CHR('r'); |
211 | 0 | break; |
212 | 0 | case FVC_STR: |
213 | 0 | interpolation->conversion = _Py_LATIN1_CHR('s'); |
214 | 0 | break; |
215 | 0 | default: |
216 | 0 | PyErr_SetString(PyExc_SystemError, |
217 | 0 | "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'"); |
218 | 0 | Py_DECREF(interpolation); |
219 | 0 | return NULL; |
220 | 0 | } |
221 | 0 | } |
222 | | |
223 | 0 | PyObject_GC_Track(interpolation); |
224 | 0 | return (PyObject *) interpolation; |
225 | 0 | } |
226 | | |
227 | | PyObject * |
228 | | _PyInterpolation_GetValueRef(PyObject *interpolation) |
229 | 0 | { |
230 | 0 | return Py_NewRef(interpolationobject_CAST(interpolation)->value); |
231 | 0 | } |