1"""
2The class PyTypeObject generates a PyTypeObject structure contents.
3"""
4
5class PyTypeObject(object):
6    TEMPLATE = (
7        'PyTypeObject %(typestruct)s = {\n'
8        '    PyObject_HEAD_INIT(NULL)\n'
9        '    0,                                 /* ob_size */\n'
10        '    (char *) "%(tp_name)s",            /* tp_name */\n'
11        '    %(tp_basicsize)s,                  /* tp_basicsize */\n'
12        '    0,                                 /* tp_itemsize */\n'
13        '    /* methods */\n'
14        '    (destructor)%(tp_dealloc)s,        /* tp_dealloc */\n'
15        '    (printfunc)0,                      /* tp_print */\n'
16        '    (getattrfunc)%(tp_getattr)s,       /* tp_getattr */\n'
17        '    (setattrfunc)%(tp_setattr)s,       /* tp_setattr */\n'
18        '    (cmpfunc)%(tp_compare)s,           /* tp_compare */\n'
19        '    (reprfunc)%(tp_repr)s,             /* tp_repr */\n'
20        '    (PyNumberMethods*)%(tp_as_number)s,     /* tp_as_number */\n'
21        '    (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
22        '    (PyMappingMethods*)%(tp_as_mapping)s,   /* tp_as_mapping */\n'
23        '    (hashfunc)%(tp_hash)s,             /* tp_hash */\n'
24        '    (ternaryfunc)%(tp_call)s,          /* tp_call */\n'
25        '    (reprfunc)%(tp_str)s,              /* tp_str */\n'
26        '    (getattrofunc)%(tp_getattro)s,     /* tp_getattro */\n'
27        '    (setattrofunc)%(tp_setattro)s,     /* tp_setattro */\n'
28        '    (PyBufferProcs*)%(tp_as_buffer)s,  /* tp_as_buffer */\n'
29        '    %(tp_flags)s,                      /* tp_flags */\n'
30        '    %(tp_doc)s,                        /* Documentation string */\n'
31        '    (traverseproc)%(tp_traverse)s,     /* tp_traverse */\n'
32        '    (inquiry)%(tp_clear)s,             /* tp_clear */\n'
33        '    (richcmpfunc)%(tp_richcompare)s,   /* tp_richcompare */\n'
34        '    %(tp_weaklistoffset)s,             /* tp_weaklistoffset */\n'
35        '    (getiterfunc)%(tp_iter)s,          /* tp_iter */\n'
36        '    (iternextfunc)%(tp_iternext)s,     /* tp_iternext */\n'
37        '    (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
38        '    (struct PyMemberDef*)0,              /* tp_members */\n'
39        '    %(tp_getset)s,                     /* tp_getset */\n'
40        '    NULL,                              /* tp_base */\n'
41        '    NULL,                              /* tp_dict */\n'
42        '    (descrgetfunc)%(tp_descr_get)s,    /* tp_descr_get */\n'
43        '    (descrsetfunc)%(tp_descr_set)s,    /* tp_descr_set */\n'
44        '    %(tp_dictoffset)s,                 /* tp_dictoffset */\n'
45        '    (initproc)%(tp_init)s,             /* tp_init */\n'
46        '    (allocfunc)%(tp_alloc)s,           /* tp_alloc */\n'
47        '    (newfunc)%(tp_new)s,               /* tp_new */\n'
48        '    (freefunc)%(tp_free)s,             /* tp_free */\n'
49        '    (inquiry)%(tp_is_gc)s,             /* tp_is_gc */\n'
50        '    NULL,                              /* tp_bases */\n'
51        '    NULL,                              /* tp_mro */\n'
52        '    NULL,                              /* tp_cache */\n'
53        '    NULL,                              /* tp_subclasses */\n'
54        '    NULL,                              /* tp_weaklist */\n'
55        '    (destructor) NULL                  /* tp_del */\n'
56        '};\n'
57        )
58
59    def __init__(self):
60        self.slots = {}
61
62    def generate(self, code_sink):
63        """
64        Generates the type structure.  All slots are optional except
65        'tp_name', 'tp_basicsize', and the pseudo-slot 'typestruct'.
66        """
67
68        slots = dict(self.slots)
69
70        slots.setdefault('tp_dealloc', 'NULL')
71        slots.setdefault('tp_getattr', 'NULL')
72        slots.setdefault('tp_setattr', 'NULL')
73        slots.setdefault('tp_compare', 'NULL')
74        slots.setdefault('tp_repr', 'NULL')
75        slots.setdefault('tp_as_number', 'NULL')
76        slots.setdefault('tp_as_sequence', 'NULL')
77        slots.setdefault('tp_as_mapping', 'NULL')
78        slots.setdefault('tp_hash', 'NULL')
79        slots.setdefault('tp_call', 'NULL')
80        slots.setdefault('tp_str', 'NULL')
81        slots.setdefault('tp_getattro', 'NULL')
82        slots.setdefault('tp_setattro', 'NULL')
83        slots.setdefault('tp_as_buffer', 'NULL')
84        slots.setdefault('tp_flags', 'Py_TPFLAGS_DEFAULT')
85        slots.setdefault('tp_doc', 'NULL')
86        slots.setdefault('tp_traverse', 'NULL')
87        slots.setdefault('tp_clear', 'NULL')
88        slots.setdefault('tp_richcompare', 'NULL')
89        slots.setdefault('tp_weaklistoffset', '0')
90        slots.setdefault('tp_iter', 'NULL')
91        slots.setdefault('tp_iternext', 'NULL')
92        slots.setdefault('tp_methods', 'NULL')
93        slots.setdefault('tp_getset', 'NULL')
94        slots.setdefault('tp_descr_get', 'NULL')
95        slots.setdefault('tp_descr_set', 'NULL')
96        slots.setdefault('tp_dictoffset', '0')
97        slots.setdefault('tp_init', 'NULL')
98        slots.setdefault('tp_alloc', 'PyType_GenericAlloc')
99        slots.setdefault('tp_new', 'PyType_GenericNew')
100        slots.setdefault('tp_free', '0')
101        slots.setdefault('tp_is_gc', 'NULL')
102
103        code_sink.writeln(self.TEMPLATE % slots)
104
105
106class PyNumberMethods(object):
107    TEMPLATE = (
108        'static PyNumberMethods %(variable)s = {\n'
109	'    (binaryfunc) %(nb_add)s,\n'
110	'    (binaryfunc) %(nb_subtract)s,\n'
111	'    (binaryfunc) %(nb_multiply)s,\n'
112	'    (binaryfunc) %(nb_divide)s,\n'
113	'    (binaryfunc) %(nb_remainder)s,\n'
114	'    (binaryfunc) %(nb_divmod)s,\n'
115	'    (ternaryfunc) %(nb_power)s,\n'
116	'    (unaryfunc) %(nb_negative)s,\n'
117	'    (unaryfunc) %(nb_positive)s,\n'
118	'    (unaryfunc) %(nb_absolute)s,\n'
119	'    (inquiry) %(nb_nonzero)s,\n'
120	'    (unaryfunc) %(nb_invert)s,\n'
121	'    (binaryfunc) %(nb_lshift)s,\n'
122	'    (binaryfunc) %(nb_rshift)s,\n'
123	'    (binaryfunc) %(nb_and)s,\n'
124	'    (binaryfunc) %(nb_xor)s,\n'
125	'    (binaryfunc) %(nb_or)s,\n'
126	'    (coercion) %(nb_coerce)s,\n'
127	'    (unaryfunc) %(nb_int)s,\n'
128	'    (unaryfunc) %(nb_long)s,\n'
129	'    (unaryfunc) %(nb_float)s,\n'
130	'    (unaryfunc) %(nb_oct)s,\n'
131	'    (unaryfunc) %(nb_hex)s,\n'
132	'    /* Added in release 2.0 */\n'
133	'    (binaryfunc) %(nb_inplace_add)s,\n'
134	'    (binaryfunc) %(nb_inplace_subtract)s,\n'
135	'    (binaryfunc) %(nb_inplace_multiply)s,\n'
136	'    (binaryfunc) %(nb_inplace_divide)s,\n'
137	'    (binaryfunc) %(nb_inplace_remainder)s,\n'
138	'    (ternaryfunc) %(nb_inplace_power)s,\n'
139	'    (binaryfunc) %(nb_inplace_lshift)s,\n'
140	'    (binaryfunc) %(nb_inplace_rshift)s,\n'
141	'    (binaryfunc) %(nb_inplace_and)s,\n'
142	'    (binaryfunc) %(nb_inplace_xor)s,\n'
143	'    (binaryfunc) %(nb_inplace_or)s,\n'
144        '\n'
145	'    /* Added in release 2.2 */\n'
146	'    /* The following require the Py_TPFLAGS_HAVE_CLASS flag */\n'
147	'    (binaryfunc) %(nb_floor_divide)s,\n'
148	'    (binaryfunc) %(nb_true_divide)s,\n'
149	'    (binaryfunc) %(nb_inplace_floor_divide)s,\n'
150	'    (binaryfunc) %(nb_inplace_true_divide)s,\n'
151        '\n'
152        '#if PY_VERSION_HEX >= 0x020500F0\n'
153	'    /* Added in release 2.5 */\n'
154	'    (unaryfunc) %(nb_index)s,\n'
155        '\n'
156        '#endif\n'
157        '};\n'
158        )
159
160    def __init__(self):
161        self.slots = {}
162
163    def generate(self, code_sink):
164        """
165        Generates the structure.  All slots are optional except 'variable'.
166        """
167
168        slots = dict(self.slots)
169
170	slots.setdefault('nb_add', 'NULL')
171	slots.setdefault('nb_subtract', 'NULL')
172	slots.setdefault('nb_multiply', 'NULL')
173	slots.setdefault('nb_divide', 'NULL')
174	slots.setdefault('nb_remainder', 'NULL')
175	slots.setdefault('nb_divmod', 'NULL')
176	slots.setdefault('nb_power', 'NULL')
177	slots.setdefault('nb_negative', 'NULL')
178	slots.setdefault('nb_positive', 'NULL')
179	slots.setdefault('nb_absolute', 'NULL')
180	slots.setdefault('nb_nonzero', 'NULL')
181	slots.setdefault('nb_invert', 'NULL')
182	slots.setdefault('nb_lshift', 'NULL')
183	slots.setdefault('nb_rshift', 'NULL')
184	slots.setdefault('nb_and', 'NULL')
185	slots.setdefault('nb_xor', 'NULL')
186        slots.setdefault('nb_or', 'NULL')
187	slots.setdefault('nb_coerce', 'NULL')
188	slots.setdefault('nb_int', 'NULL')
189	slots.setdefault('nb_long', 'NULL')
190	slots.setdefault('nb_float', 'NULL')
191	slots.setdefault('nb_oct', 'NULL')
192	slots.setdefault('nb_hex', 'NULL')
193	slots.setdefault('nb_inplace_add', 'NULL')
194	slots.setdefault('nb_inplace_subtract', 'NULL')
195	slots.setdefault('nb_inplace_multiply', 'NULL')
196	slots.setdefault('nb_inplace_divide', 'NULL')
197	slots.setdefault('nb_inplace_remainder', 'NULL')
198	slots.setdefault('nb_inplace_power', 'NULL')
199	slots.setdefault('nb_inplace_lshift', 'NULL')
200	slots.setdefault('nb_inplace_rshift', 'NULL')
201	slots.setdefault('nb_inplace_and', 'NULL')
202	slots.setdefault('nb_inplace_xor', 'NULL')
203	slots.setdefault('nb_inplace_or', 'NULL')
204	slots.setdefault('nb_floor_divide', 'NULL')
205	slots.setdefault('nb_true_divide', 'NULL')
206	slots.setdefault('nb_inplace_floor_divide', 'NULL')
207	slots.setdefault('nb_inplace_true_divide', 'NULL')
208	slots.setdefault('nb_index', 'NULL')
209
210        code_sink.writeln(self.TEMPLATE % slots)
211
212class PySequenceMethods(object):
213    TEMPLATE = '''
214static PySequenceMethods %(variable)s = {
215    (lenfunc) %(sq_length)s,
216    (binaryfunc) %(sq_concat)s,
217    (ssizeargfunc) %(sq_repeat)s,
218    (ssizeargfunc) %(sq_item)s,
219    (ssizessizeargfunc) %(sq_slice)s,
220    (ssizeobjargproc) %(sq_ass_item)s,
221    (ssizessizeobjargproc) %(sq_ass_slice)s,
222    (objobjproc) %(sq_contains)s,
223    /* Added in release 2.0 */
224    (binaryfunc) %(sq_inplace_concat)s,
225    (ssizeargfunc) %(sq_inplace_repeat)s,
226};
227
228'''
229
230    FUNCTION_TEMPLATES = {
231        "sq_length" : '''
232static Py_ssize_t
233%(wrapper_name)s (%(py_struct)s *py_self)
234{
235    PyObject *py_result;
236    Py_ssize_t result;
237
238    py_result = %(method_name)s(py_self);
239    if (py_result == NULL) {
240        return -1;
241    }
242    result = PyInt_AsSsize_t(py_result);
243    Py_DECREF(py_result);
244    return result;
245}
246
247''',
248
249        # This hacky version is necessary 'cause if we're calling a function rather than a method
250        # or an overloaded wrapper the args parameter gets tacked into the call sequence.
251        "sq_length_ARGS" : '''
252static Py_ssize_t
253%(wrapper_name)s (%(py_struct)s *py_self)
254{
255    PyObject *py_result;
256    PyObject *args;
257    Py_ssize_t result;
258
259    args = PyTuple_New (0);
260    py_result = %(method_name)s(py_self, args, NULL);
261    Py_DECREF(args);
262    if (py_result == NULL) {
263        return -1;
264    }
265    result = PyInt_AsSsize_t(py_result);
266    Py_DECREF(py_result);
267    return result;
268}
269
270''',
271
272        "sq_item" : '''
273static PyObject*
274%(wrapper_name)s (%(py_struct)s *py_self, Py_ssize_t py_i)
275{
276    PyObject *result;
277    PyObject *args;
278
279    args = Py_BuildValue("(i)", py_i);
280    result = %(method_name)s(py_self, args, NULL);
281    Py_DECREF(args);
282    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
283        PyErr_ExceptionMatches(PyExc_StopIteration)) {
284        Py_XDECREF(result);
285        return NULL;
286    } else {
287        return result;
288    }
289}
290
291
292''',
293
294        "sq_ass_item" : '''
295static int
296%(wrapper_name)s (%(py_struct)s *py_self, Py_ssize_t py_i, PyObject *py_val)
297{
298    PyObject *result;
299    PyObject *args;
300
301    args = Py_BuildValue("(iO)", py_i, py_val);
302    result = %(method_name)s(py_self, args, NULL);
303    Py_DECREF(args);
304    if (result == NULL) {
305        return -1;
306    } else {
307        Py_DECREF(result);
308        return 0;
309    }
310}
311
312''',
313        }
314
315    def __init__(self):
316        self.slots = {}
317
318    def generate(self, code_sink):
319        """
320        Generates the structure.  All slots are optional except 'variable'.
321        """
322
323        slots = dict(self.slots)
324
325	slots.setdefault('sq_length', 'NULL')
326	slots.setdefault('sq_concat', 'NULL')
327	slots.setdefault('sq_repeat', 'NULL')
328	slots.setdefault('sq_item', 'NULL')
329	slots.setdefault('sq_slice', 'NULL')
330	slots.setdefault('sq_ass_item', 'NULL')
331	slots.setdefault('sq_ass_slice', 'NULL')
332	slots.setdefault('sq_contains', 'NULL')
333	slots.setdefault('sq_inplace_concat', 'NULL')
334	slots.setdefault('sq_inplace_repeat', 'NULL')
335
336        code_sink.writeln(self.TEMPLATE % slots)
337
338