Better example and comments.
[rox-lib.git] / python / rox / Pyrex / Compiler / TypeSlots.py
blob69a3ebc4a5053bcd3891bfb78ce4d306e39928cc
2 # Pyrex - Tables describing slots in the type object
3 # and associated know-how.
6 import Naming
7 import PyrexTypes
9 class Signature:
10 # Method slot signature descriptor.
12 # has_dummy_arg boolean
13 # has_generic_args boolean
14 # fixed_arg_format string
15 # ret_format string
16 # error_value string
18 # The formats are strings made up of the following
19 # characters:
21 # 'O' Python object
22 # 'T' Python object of the type of 'self'
23 # 'v' void
24 # 'p' void *
25 # 'P' void **
26 # 'i' int
27 # 'I' int *
28 # 'l' long
29 # 's' char *
30 # 'S' char **
31 # '-' dummy 'self' argument (not used)
32 # '*' rest of args passed as generic Python
33 # arg tuple and kw dict (must be last
34 # char in format string)
36 format_map = {
37 'O': PyrexTypes.py_object_type,
38 'v': PyrexTypes.c_void_type,
39 'p': PyrexTypes.c_void_ptr_type,
40 'P': PyrexTypes.c_void_ptr_ptr_type,
41 'i': PyrexTypes.c_int_type,
42 'I': PyrexTypes.c_int_ptr_type,
43 'l': PyrexTypes.c_long_type,
44 's': PyrexTypes.c_char_ptr_type,
45 'S': PyrexTypes.c_char_ptr_ptr_type,
46 # 'T', '-' and '*' are handled otherwise
47 # and are not looked up in here
50 error_value_map = {
51 'O': "0",
52 'i': "-1",
55 def __init__(self, arg_format, ret_format):
56 self.has_dummy_arg = 0
57 self.has_generic_args = 0
58 if arg_format[:1] == '-':
59 self.has_dummy_arg = 1
60 arg_format = arg_format[1:]
61 if arg_format[-1:] == '*':
62 self.has_generic_args = 1
63 arg_format = arg_format[:-1]
64 self.fixed_arg_format = arg_format
65 self.ret_format = ret_format
66 self.error_value = self.error_value_map.get(ret_format, None)
68 def num_fixed_args(self):
69 return len(self.fixed_arg_format)
71 def is_self_arg(self, i):
72 return self.fixed_arg_format[i] == 'T'
74 def fixed_arg_type(self, i):
75 return self.format_map[self.fixed_arg_format[i]]
77 def return_type(self):
78 return self.format_map[self.ret_format]
81 class SlotDescriptor:
82 # Abstract base class for type slot descriptors.
84 # slot_name string Member name of the slot in the type object
86 is_initialised_from_extern = 0
88 def __init__(self, slot_name):
89 self.slot_name = slot_name
90 if slot_name in slots_initialised_from_extern:
91 self.is_initialised_from_extern = 1
93 def generate(self, scope, code):
94 #code.putln("%s, /*%s*/" % (self.slot_code(scope), self.slot_name))
95 if self.is_initialised_from_extern:
96 value = 0
97 else:
98 value = self.slot_code(scope)
99 code.putln("%s, /*%s*/" % (value, self.slot_name))
101 def generate_extern_init_code(self, scope, code):
102 # Some braindead compilers have trouble statically
103 # initialising a global with a pointer to an extern
104 # function, so we initialise some of the type slots
105 # in the module init function instead.
106 if self.is_initialised_from_extern:
107 code.putln("%s.%s = %s;" % (
108 scope.parent_type.typeobj_cname,
109 self.slot_name,
110 self.slot_code(scope)
115 class FixedSlot(SlotDescriptor):
116 # Descriptor for a type slot with a fixed value.
118 # value string
120 def __init__(self, slot_name, value):
121 SlotDescriptor.__init__(self, slot_name)
122 self.value = value
124 def slot_code(self, scope):
125 return self.value
128 class EmptySlot(FixedSlot):
129 # Descriptor for a type slot whose value is always 0.
131 def __init__(self, slot_name):
132 FixedSlot.__init__(self, slot_name, "0")
135 class GCDependentSlot(SlotDescriptor):
136 # Descriptor for a slot whose value depends on whether
137 # the type participates in GC.
139 def __init__(self, slot_name, no_gc_value, gc_value):
140 SlotDescriptor.__init__(self, slot_name)
141 self.no_gc_value = no_gc_value
142 self.gc_value = gc_value
144 def slot_code(self, scope):
145 if scope.has_pyobject_attrs:
146 return self.gc_value
147 else:
148 return self.no_gc_value
151 class MethodSlot(SlotDescriptor):
152 # Type slot descriptor for a user-definable method.
154 # signature Signature
155 # method_name string The __xxx__ name of the method
156 # default string or None Default value of the slot
158 def __init__(self, signature, slot_name, method_name, default = None):
159 SlotDescriptor.__init__(self, slot_name)
160 self.signature = signature
161 self.slot_name = slot_name
162 self.method_name = method_name
163 self.default = default
164 method_name_to_slot[method_name] = self
166 def slot_code(self, scope):
167 entry = scope.lookup_here(self.method_name)
168 if entry:
169 return entry.func_cname
170 else:
171 return "0"
174 class InternalMethodSlot(SlotDescriptor):
175 # Type slot descriptor for a method which is always
176 # synthesized by Pyrex.
178 # slot_name string Member name of the slot in the type object
180 def __init__(self, slot_name):
181 SlotDescriptor.__init__(self, slot_name)
183 def slot_code(self, scope):
184 return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
187 class SyntheticSlot(InternalMethodSlot):
188 # Type slot descriptor for a synthesized method which
189 # dispatches to one or more user-defined methods depending
190 # on its arguments. If none of the relevant methods are
191 # defined, the method will not be synthesized and an
192 # alternative default value will be placed in the type
193 # slot.
195 def __init__(self, slot_name, user_methods, default_value):
196 InternalMethodSlot.__init__(self, slot_name)
197 self.user_methods = user_methods
198 self.default_value = default_value
200 def slot_code(self, scope):
201 if scope.defines_any(self.user_methods):
202 return InternalMethodSlot.slot_code(self, scope)
203 else:
204 return self.default_value
207 class TypeFlagsSlot(SlotDescriptor):
208 # Descriptor for the type flags slot.
210 def slot_code(self, scope):
211 value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE"
212 if scope.has_pyobject_attrs:
213 value += "|Py_TPFLAGS_HAVE_GC"
214 return value
217 class DocStringSlot(SlotDescriptor):
218 # Descriptor for the docstring slot.
220 def slot_code(self, scope):
221 if scope.doc is not None:
222 return '"%s"' % scope.doc
223 else:
224 return "0"
227 class SuiteSlot(SlotDescriptor):
228 # Descriptor for a substructure of the type object.
230 # sub_slots [SlotDescriptor]
232 def __init__(self, sub_slots, slot_type, slot_name):
233 SlotDescriptor.__init__(self, slot_name)
234 self.sub_slots = sub_slots
235 self.slot_type = slot_type
236 substructures.append(self)
238 def substructure_cname(self, scope):
239 return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
241 def slot_code(self, scope):
242 return "&%s" % self.substructure_cname(scope)
244 def generate_substructure(self, scope, code):
245 code.putln("")
246 code.putln(
247 "static %s %s = {" % (
248 self.slot_type,
249 self.substructure_cname(scope)))
250 for slot in self.sub_slots:
251 slot.generate(scope, code)
252 code.putln("};")
254 substructures = [] # List of all SuiteSlot instances
256 class MethodTableSlot(SlotDescriptor):
257 # Slot descriptor for the method table.
259 def slot_code(self, scope):
260 return scope.method_table_cname
263 class MemberTableSlot(SlotDescriptor):
264 # Slot descriptor for the table of Python-accessible attributes.
266 def slot_code(self, scope):
267 if scope.public_attr_entries:
268 return scope.member_table_cname
269 else:
270 return "0"
273 class GetSetSlot(SlotDescriptor):
274 # Slot descriptor for the table of attribute get & set methods.
276 def slot_code(self, scope):
277 #return scope.getset_table_cname # Later
278 return "0"
281 # The following dictionary maps __xxx__ method names to slot descriptors.
283 method_name_to_slot = {}
285 # The following slots are (or could be) initialised with an
286 # extern function pointer.
288 slots_initialised_from_extern = (
289 "tp_free",
292 #------------------------------------------------------------------------------------------
294 # Utility functions for accessing slot table data structures
296 #------------------------------------------------------------------------------------------
298 def get_special_method_signature(name):
299 # Given a method name, if it is a special method,
300 # return its signature, else return None.
301 slot = method_name_to_slot.get(name, None)
302 if slot:
303 return slot.signature
304 else:
305 return None
307 #------------------------------------------------------------------------------------------
309 # Signatures for generic Python functions and methods.
311 #------------------------------------------------------------------------------------------
313 pyfunction_signature = Signature("-*", "O")
314 pymethod_signature = Signature("T*", "O")
316 #------------------------------------------------------------------------------------------
318 # Signatures for the various kinds of function that
319 # can appear in the type object and its substructures.
321 #------------------------------------------------------------------------------------------
323 unaryfunc = Signature("T", "O") # typedef PyObject * (*unaryfunc)(PyObject *);
324 binaryfunc = Signature("OO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
325 ibinaryfunc = Signature("TO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
326 ternaryfunc = Signature("OOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
327 iternaryfunc = Signature("TOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
328 callfunc = Signature("T*", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
329 inquiry = Signature("T", "i") # typedef int (*inquiry)(PyObject *);
330 # typedef int (*coercion)(PyObject **, PyObject **);
331 intargfunc = Signature("Ti", "O") # typedef PyObject *(*intargfunc)(PyObject *, int);
332 intintargfunc = Signature("Tii", "O") # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
333 intobjargproc = Signature("TiO", "i") # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
334 intintobjargproc = Signature("TiiO", "i") # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
335 intintargproc = Signature("Tii", "i")
336 objargfunc = Signature("TO", "O")
337 objobjargproc = Signature("TOO", "i") # typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
338 getreadbufferproc = Signature("TiP", "i") # typedef int (*getreadbufferproc)(PyObject *, int, void **);
339 getwritebufferproc = Signature("TiP", "i") # typedef int (*getwritebufferproc)(PyObject *, int, void **);
340 getsegcountproc = Signature("TI", "i") # typedef int (*getsegcountproc)(PyObject *, int *);
341 getcharbufferproc = Signature("TiS", "i") # typedef int (*getcharbufferproc)(PyObject *, int, const char **);
342 objargproc = Signature("TO", "i") # typedef int (*objobjproc)(PyObject *, PyObject *);
343 # typedef int (*visitproc)(PyObject *, void *);
344 # typedef int (*traverseproc)(PyObject *, visitproc, void *);
346 destructor = Signature("T", "v") # typedef void (*destructor)(PyObject *);
347 # printfunc = Signature("TFi", "i") # typedef int (*printfunc)(PyObject *, FILE *, int);
348 # typedef PyObject *(*getattrfunc)(PyObject *, char *);
349 getattrofunc = Signature("TO", "O") # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
350 # typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
351 setattrofunc = Signature("TOO", "i") # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
352 delattrofunc = Signature("TO", "i")
353 cmpfunc = Signature("TO", "i") # typedef int (*cmpfunc)(PyObject *, PyObject *);
354 reprfunc = Signature("T", "O") # typedef PyObject *(*reprfunc)(PyObject *);
355 hashfunc = Signature("T", "l") # typedef long (*hashfunc)(PyObject *);
356 # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
357 richcmpfunc = Signature("OOi", "O") # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
358 getiterfunc = Signature("T", "O") # typedef PyObject *(*getiterfunc) (PyObject *);
359 iternextfunc = Signature("T", "O") # typedef PyObject *(*iternextfunc) (PyObject *);
360 descrgetfunc = Signature("TOO", "O") # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
361 descrsetfunc = Signature("TOO", "i") # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
362 descrdelfunc = Signature("TO", "i")
363 initproc = Signature("T*", "i") # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
364 # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
365 # typedef PyObject *(*allocfunc)(struct _typeobject *, int);
367 #------------------------------------------------------------------------------------------
369 # Descriptor tables for the slots of the various type object
370 # substructures, in the order they appear in the structure.
372 #------------------------------------------------------------------------------------------
374 PyNumberMethods = (
375 MethodSlot(binaryfunc, "nb_add", "__add__"),
376 MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
377 MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
378 MethodSlot(binaryfunc, "nb_divide", "__div__"),
379 MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
380 MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
381 MethodSlot(ternaryfunc, "nb_power", "__pow__"),
382 MethodSlot(unaryfunc, "nb_negative", "__neg__"),
383 MethodSlot(unaryfunc, "nb_positive", "__pos__"),
384 MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
385 MethodSlot(inquiry, "nb_nonzero", "__nonzero__"),
386 MethodSlot(unaryfunc, "nb_invert", "__invert__"),
387 MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
388 MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
389 MethodSlot(binaryfunc, "nb_and", "__and__"),
390 MethodSlot(binaryfunc, "nb_xor", "__xor__"),
391 MethodSlot(binaryfunc, "nb_or", "__or__"),
392 EmptySlot("nb_coerce"),
393 MethodSlot(unaryfunc, "nb_int", "__int__"),
394 MethodSlot(unaryfunc, "nb_long", "__long__"),
395 MethodSlot(unaryfunc, "nb_float", "__float__"),
396 MethodSlot(unaryfunc, "nb_oct", "__oct__"),
397 MethodSlot(unaryfunc, "nb_hex", "__hex__"),
399 # Added in release 2.0
400 MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"),
401 MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"),
402 MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"),
403 MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__"),
404 MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
405 MethodSlot(ternaryfunc, "nb_inplace_power", "__ipow__"), # NOT iternaryfunc!!!
406 MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
407 MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"),
408 MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"),
409 MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"),
410 MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"),
412 # Added in release 2.2
413 # The following require the Py_TPFLAGS_HAVE_CLASS flag
414 MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"),
415 MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
416 MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
417 MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
420 PySequenceMethods = (
421 MethodSlot(inquiry, "sq_length", "__len__"), # EmptySlot("sq_length"), # mp_length used instead
422 EmptySlot("sq_concat"), # nb_add used instead
423 EmptySlot("sq_repeat"), # nb_multiply used instead
424 SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead
425 MethodSlot(intintargfunc, "sq_slice", "__getslice__"),
426 EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
427 SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
428 MethodSlot(objargproc, "sq_contains", "__contains__"),
429 EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead
430 EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead
433 PyMappingMethods = (
434 MethodSlot(inquiry, "mp_length", "__len__"),
435 MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
436 SyntheticSlot("mp_ass_subscript", ["__setitem__"], "0"),
439 PyBufferProcs = (
440 MethodSlot(getreadbufferproc, "bf_getreadbuffer", "__getreadbuffer__"),
441 MethodSlot(getwritebufferproc, "bf_getwritebuffer", "__getwritebuffer__"),
442 MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__"),
443 MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__"),
446 #------------------------------------------------------------------------------------------
448 # The main slot table. This table contains descriptors for all the
449 # top-level type slots, beginning with tp_dealloc, in the order they
450 # appear in the type object.
452 #------------------------------------------------------------------------------------------
454 slot_table = (
455 InternalMethodSlot("tp_dealloc"),
456 EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
457 EmptySlot("tp_getattr"),
458 EmptySlot("tp_setattr"),
459 MethodSlot(cmpfunc, "tp_compare", "__cmp__"),
460 MethodSlot(reprfunc, "tp_repr", "__repr__"),
462 SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
463 SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"),
464 SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"),
466 MethodSlot(hashfunc, "tp_hash", "__hash__"),
467 MethodSlot(callfunc, "tp_call", "__call__"),
468 MethodSlot(reprfunc, "tp_str", "__str__"),
470 SyntheticSlot("tp_getattro", ["__getattr__"], "0"), #"PyObject_GenericGetAttr"),
471 SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
473 SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
475 TypeFlagsSlot("tp_flags"),
476 DocStringSlot("tp_doc"),
478 InternalMethodSlot("tp_traverse"),
479 InternalMethodSlot("tp_clear"),
481 # Later -- synthesize a method to split into separate ops?
482 MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__"), # InternalMethodSlot("tp_richcompare"),
484 EmptySlot("tp_weaklistoffset"),
486 MethodSlot(getiterfunc, "tp_iter", "__iter__"),
487 MethodSlot(iternextfunc, "tp_iternext", "__next__"),
489 MethodTableSlot("tp_methods"),
490 MemberTableSlot("tp_members"),
491 GetSetSlot("tp_getset"),
493 EmptySlot("tp_base"),
494 EmptySlot("tp_dict"),
496 SyntheticSlot("tp_descr_get", ["__get__"], "0"), #MethodSlot(descrgetfunc, "tp_descr_get", "__get__"),
497 SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"), #MethodSlot(descrsetfunc, "tp_descr_set", "__set__"),
499 EmptySlot("tp_dictoffset"),
501 MethodSlot(initproc, "tp_init", "__init__"),
502 EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
503 InternalMethodSlot("tp_new"),
504 GCDependentSlot("tp_free", "_PyObject_Del", "_PyObject_GC_Del"),
506 EmptySlot("tp_is_gc"),
507 EmptySlot("tp_bases"),
508 EmptySlot("tp_mro"),
509 EmptySlot("tp_cache"),
510 EmptySlot("tp_subclasses"),
511 EmptySlot("tp_weaklist"),
514 #------------------------------------------------------------------------------------------
516 # Descriptors for special methods which don't appear directly
517 # in the type object or its substructures. These methods are
518 # called from slot functions synthesized by Pyrex.
520 #------------------------------------------------------------------------------------------
522 MethodSlot(initproc, "", "__new__")
523 MethodSlot(destructor, "", "__dealloc__")
524 MethodSlot(objobjargproc, "", "__setitem__")
525 MethodSlot(objargproc, "", "__delitem__")
526 MethodSlot(intintobjargproc, "", "__setslice__")
527 MethodSlot(intintargproc, "", "__delslice__")
528 MethodSlot(getattrofunc, "", "__getattr__")
529 MethodSlot(setattrofunc, "", "__setattr__")
530 MethodSlot(delattrofunc, "", "__delattr__")
531 MethodSlot(descrgetfunc, "", "__get__")
532 MethodSlot(descrsetfunc, "", "__set__")
533 MethodSlot(descrdelfunc, "", "__delete__")