1from bgenOutput import * 2from bgenGeneratorGroup import GeneratorGroup 3 4class ObjectDefinition(GeneratorGroup): 5 "Spit out code that together defines a new Python object type" 6 basechain = "NULL" 7 tp_flags = "Py_TPFLAGS_DEFAULT" 8 basetype = None 9 argref = "" # set to "*" if arg to <type>_New should be pointer 10 argconst = "" # set to "const " if arg to <type>_New should be const 11 12 def __init__(self, name, prefix, itselftype): 13 """ObjectDefinition constructor. May be extended, but do not override. 14 15 - name: the object's official name, e.g. 'SndChannel'. 16 - prefix: the prefix used for the object's functions and data, e.g. 'SndCh'. 17 - itselftype: the C type actually contained in the object, e.g. 'SndChannelPtr'. 18 19 XXX For official Python data types, rules for the 'Py' prefix are a problem. 20 """ 21 22 GeneratorGroup.__init__(self, prefix or name) 23 self.name = name 24 self.itselftype = itselftype 25 self.objecttype = name + 'Object' 26 self.typename = name + '_Type' 27 self.static = "static " # set to "" to make <type>_New and <type>_Convert public 28 self.modulename = None 29 if hasattr(self, "assertions"): 30 self.assertions() 31 32 def add(self, g, dupcheck=0): 33 g.setselftype(self.objecttype, self.itselftype) 34 GeneratorGroup.add(self, g, dupcheck) 35 36 def reference(self): 37 # In case we are referenced from a module 38 pass 39 40 def setmodulename(self, name): 41 self.modulename = name 42 43 def generate(self): 44 # XXX This should use long strings and %(varname)s substitution! 45 46 OutHeader2("Object type " + self.name) 47 48 self.outputCheck() 49 50 Output("typedef struct %s {", self.objecttype) 51 IndentLevel() 52 Output("PyObject_HEAD") 53 self.outputStructMembers() 54 DedentLevel() 55 Output("} %s;", self.objecttype) 56 57 self.outputNew() 58 59 self.outputConvert() 60 61 self.outputDealloc() 62 63 GeneratorGroup.generate(self) 64 65 Output() 66 self.outputMethodChain() 67 68 self.outputGetattr() 69 70 self.outputSetattr() 71 72 self.outputCompare() 73 74 self.outputRepr() 75 76 self.outputHash() 77 78 self.outputPEP253Hooks() 79 80 self.outputTypeObject() 81 82 OutHeader2("End object type " + self.name) 83 84 def outputCheck(self): 85 sf = self.static and "static " 86 Output("%sPyTypeObject %s;", sf, self.typename) 87 Output() 88 Output("#define %s_Check(x) ((x)->ob_type == &%s || PyObject_TypeCheck((x), &%s))", 89 self.prefix, self.typename, self.typename) 90 Output() 91 92 def outputMethodChain(self): 93 Output("%sPyMethodChain %s_chain = { %s_methods, %s };", 94 self.static, self.prefix, self.prefix, self.basechain) 95 96 def outputStructMembers(self): 97 Output("%s ob_itself;", self.itselftype) 98 99 def outputNew(self): 100 Output() 101 Output("%sPyObject *%s_New(%s%s %sitself)", self.static, self.prefix, 102 self.argconst, self.itselftype, self.argref) 103 OutLbrace() 104 Output("%s *it;", self.objecttype) 105 self.outputCheckNewArg() 106 Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename) 107 Output("if (it == NULL) return NULL;") 108 if self.basetype: 109 Output("/* XXXX Should we tp_init or tp_new our basetype? */") 110 self.outputInitStructMembers() 111 Output("return (PyObject *)it;") 112 OutRbrace() 113 114 def outputInitStructMembers(self): 115 Output("it->ob_itself = %sitself;", self.argref) 116 117 def outputCheckNewArg(self): 118 "Override this method to apply additional checks/conversions" 119 120 def outputConvert(self): 121 Output() 122 Output("%sint %s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, 123 self.itselftype) 124 OutLbrace() 125 self.outputCheckConvertArg() 126 Output("if (!%s_Check(v))", self.prefix) 127 OutLbrace() 128 Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name) 129 Output("return 0;") 130 OutRbrace() 131 Output("*p_itself = ((%s *)v)->ob_itself;", self.objecttype) 132 Output("return 1;") 133 OutRbrace() 134 135 def outputCheckConvertArg(self): 136 "Override this method to apply additional conversions" 137 138 def outputDealloc(self): 139 Output() 140 Output("static void %s_dealloc(%s *self)", self.prefix, self.objecttype) 141 OutLbrace() 142 self.outputCleanupStructMembers() 143 if self.basetype: 144 Output("%s.tp_dealloc((PyObject *)self);", self.basetype) 145 elif hasattr(self, 'output_tp_free'): 146 # This is a new-style object with tp_free slot 147 Output("self->ob_type->tp_free((PyObject *)self);") 148 else: 149 Output("PyObject_Free((PyObject *)self);") 150 OutRbrace() 151 152 def outputCleanupStructMembers(self): 153 self.outputFreeIt("self->ob_itself") 154 155 def outputFreeIt(self, name): 156 Output("/* Cleanup of %s goes here */", name) 157 158 def outputGetattr(self): 159 Output() 160 Output("static PyObject *%s_getattr(%s *self, char *name)", self.prefix, self.objecttype) 161 OutLbrace() 162 self.outputGetattrBody() 163 OutRbrace() 164 165 def outputGetattrBody(self): 166 self.outputGetattrHook() 167 Output("return Py_FindMethodInChain(&%s_chain, (PyObject *)self, name);", 168 self.prefix) 169 170 def outputGetattrHook(self): 171 pass 172 173 def outputSetattr(self): 174 Output() 175 Output("#define %s_setattr NULL", self.prefix) 176 177 def outputCompare(self): 178 Output() 179 Output("#define %s_compare NULL", self.prefix) 180 181 def outputRepr(self): 182 Output() 183 Output("#define %s_repr NULL", self.prefix) 184 185 def outputHash(self): 186 Output() 187 Output("#define %s_hash NULL", self.prefix) 188 189 def outputTypeObject(self): 190 sf = self.static and "static " 191 Output() 192 Output("%sPyTypeObject %s = {", sf, self.typename) 193 IndentLevel() 194 Output("PyObject_HEAD_INIT(NULL)") 195 Output("0, /*ob_size*/") 196 if self.modulename: 197 Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) 198 else: 199 Output("\"%s\", /*tp_name*/", self.name) 200 Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) 201 Output("0, /*tp_itemsize*/") 202 Output("/* methods */") 203 Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) 204 Output("0, /*tp_print*/") 205 Output("(getattrfunc) %s_getattr, /*tp_getattr*/", self.prefix) 206 Output("(setattrfunc) %s_setattr, /*tp_setattr*/", self.prefix) 207 Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) 208 Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) 209 Output("(PyNumberMethods *)0, /* tp_as_number */") 210 Output("(PySequenceMethods *)0, /* tp_as_sequence */") 211 Output("(PyMappingMethods *)0, /* tp_as_mapping */") 212 Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) 213 DedentLevel() 214 Output("};") 215 216 def outputTypeObjectInitializer(self): 217 Output("""%s.ob_type = &PyType_Type;""", self.typename) 218 if self.basetype: 219 Output("%s.tp_base = &%s;", self.typename, self.basetype) 220 Output("if (PyType_Ready(&%s) < 0) return;", self.typename) 221 Output("""Py_INCREF(&%s);""", self.typename) 222 Output("PyModule_AddObject(m, \"%s\", (PyObject *)&%s);", self.name, self.typename); 223 self.outputTypeObjectInitializerCompat() 224 225 def outputTypeObjectInitializerCompat(self): 226 Output("/* Backward-compatible name */") 227 Output("""Py_INCREF(&%s);""", self.typename); 228 Output("PyModule_AddObject(m, \"%sType\", (PyObject *)&%s);", self.name, self.typename); 229 230 def outputPEP253Hooks(self): 231 pass 232 233class PEP252Mixin: 234 getsetlist = [] 235 236 def assertions(self): 237 # Check that various things aren't overridden. If they are it could 238 # signify a bgen-client that has been partially converted to PEP252. 239 assert self.outputGetattr.im_func == PEP252Mixin.outputGetattr.im_func 240 assert self.outputSetattr.im_func == PEP252Mixin.outputSetattr.im_func 241 assert self.outputGetattrBody == None 242 assert self.outputGetattrHook == None 243 assert self.basechain == "NULL" 244 245 def outputGetattr(self): 246 pass 247 248 outputGetattrBody = None 249 250 outputGetattrHook = None 251 252 def outputSetattr(self): 253 pass 254 255 def outputMethodChain(self): 256 # This is a good place to output the getters and setters 257 self.outputGetSetList() 258 259 def outputHook(self, name): 260 methodname = "outputHook_" + name 261 if hasattr(self, methodname): 262 func = getattr(self, methodname) 263 func() 264 else: 265 Output("0, /*%s*/", name) 266 267 def outputTypeObject(self): 268 sf = self.static and "static " 269 Output() 270 Output("%sPyTypeObject %s = {", sf, self.typename) 271 IndentLevel() 272 Output("PyObject_HEAD_INIT(NULL)") 273 Output("0, /*ob_size*/") 274 if self.modulename: 275 Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) 276 else: 277 Output("\"%s\", /*tp_name*/", self.name) 278 Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) 279 Output("0, /*tp_itemsize*/") 280 281 Output("/* methods */") 282 Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) 283 Output("0, /*tp_print*/") 284 Output("(getattrfunc)0, /*tp_getattr*/") 285 Output("(setattrfunc)0, /*tp_setattr*/") 286 Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) 287 Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) 288 289 Output("(PyNumberMethods *)0, /* tp_as_number */") 290 Output("(PySequenceMethods *)0, /* tp_as_sequence */") 291 Output("(PyMappingMethods *)0, /* tp_as_mapping */") 292 293 Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) 294 self.outputHook("tp_call") 295 Output("0, /*tp_str*/") 296 Output("PyObject_GenericGetAttr, /*tp_getattro*/") 297 Output("PyObject_GenericSetAttr, /*tp_setattro */") 298 299 self.outputHook("tp_as_buffer") 300 Output("%s, /* tp_flags */", self.tp_flags) 301 self.outputHook("tp_doc") 302 self.outputHook("tp_traverse") 303 self.outputHook("tp_clear") 304 self.outputHook("tp_richcompare") 305 self.outputHook("tp_weaklistoffset") 306 self.outputHook("tp_iter") 307 self.outputHook("tp_iternext") 308 Output("%s_methods, /* tp_methods */", self.prefix) 309 self.outputHook("tp_members") 310 Output("%s_getsetlist, /*tp_getset*/", self.prefix) 311 self.outputHook("tp_base") 312 self.outputHook("tp_dict") 313 self.outputHook("tp_descr_get") 314 self.outputHook("tp_descr_set") 315 self.outputHook("tp_dictoffset") 316 self.outputHook("tp_init") 317 self.outputHook("tp_alloc") 318 self.outputHook("tp_new") 319 self.outputHook("tp_free") 320 DedentLevel() 321 Output("};") 322 323 def outputGetSetList(self): 324 if self.getsetlist: 325 for name, get, set, doc in self.getsetlist: 326 if get: 327 self.outputGetter(name, get) 328 else: 329 Output("#define %s_get_%s NULL", self.prefix, name) 330 Output() 331 if set: 332 self.outputSetter(name, set) 333 else: 334 Output("#define %s_set_%s NULL", self.prefix, name) 335 Output() 336 337 Output("static PyGetSetDef %s_getsetlist[] = {", self.prefix) 338 IndentLevel() 339 for name, get, set, doc in self.getsetlist: 340 if doc: 341 doc = '"' + doc + '"' 342 else: 343 doc = "NULL" 344 Output("{\"%s\", (getter)%s_get_%s, (setter)%s_set_%s, %s},", 345 name, self.prefix, name, self.prefix, name, doc) 346 Output("{NULL, NULL, NULL, NULL},") 347 DedentLevel() 348 Output("};") 349 else: 350 Output("#define %s_getsetlist NULL", self.prefix) 351 Output() 352 353 def outputGetter(self, name, code): 354 Output("static PyObject *%s_get_%s(%s *self, void *closure)", 355 self.prefix, name, self.objecttype) 356 OutLbrace() 357 Output(code) 358 OutRbrace() 359 Output() 360 361 def outputSetter(self, name, code): 362 Output("static int %s_set_%s(%s *self, PyObject *v, void *closure)", 363 self.prefix, name, self.objecttype) 364 OutLbrace() 365 Output(code) 366 Output("return 0;") 367 OutRbrace() 368 Output() 369 370class PEP253Mixin(PEP252Mixin): 371 tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE" 372 373 def outputHook_tp_init(self): 374 Output("%s_tp_init, /* tp_init */", self.prefix) 375 376 def outputHook_tp_alloc(self): 377 Output("%s_tp_alloc, /* tp_alloc */", self.prefix) 378 379 def outputHook_tp_new(self): 380 Output("%s_tp_new, /* tp_new */", self.prefix) 381 382 def outputHook_tp_free(self): 383 Output("%s_tp_free, /* tp_free */", self.prefix) 384 385 def output_tp_initBody_basecall(self): 386 """If a type shares its init call with its base type set output_tp_initBody 387 to output_tp_initBody_basecall""" 388 if self.basetype: 389 Output("if (%s.tp_init)", self.basetype) 390 OutLbrace() 391 Output("if ( (*%s.tp_init)(_self, _args, _kwds) < 0) return -1;", self.basetype) 392 OutRbrace() 393 394 output_tp_initBody = None 395 396 def output_tp_init(self): 397 if self.output_tp_initBody: 398 Output("static int %s_tp_init(PyObject *_self, PyObject *_args, PyObject *_kwds)", self.prefix) 399 OutLbrace() 400 self.output_tp_initBody() 401 OutRbrace() 402 else: 403 Output("#define %s_tp_init 0", self.prefix) 404 Output() 405 406 output_tp_allocBody = None 407 408 def output_tp_alloc(self): 409 if self.output_tp_allocBody: 410 Output("static PyObject *%s_tp_alloc(PyTypeObject *type, int nitems)", 411 self.prefix) 412 OutLbrace() 413 self.output_tp_allocBody() 414 OutRbrace() 415 else: 416 Output("#define %s_tp_alloc PyType_GenericAlloc", self.prefix) 417 Output() 418 419 def output_tp_newBody(self): 420 Output("PyObject *_self;"); 421 Output("%s itself;", self.itselftype); 422 Output("char *kw[] = {\"itself\", 0};") 423 Output() 424 Output("if (!PyArg_ParseTupleAndKeywords(_args, _kwds, \"O&\", kw, %s_Convert, &itself)) return NULL;", 425 self.prefix); 426 if self.basetype: 427 Output("if (%s.tp_new)", self.basetype) 428 OutLbrace() 429 Output("if ( (*%s.tp_new)(type, _args, _kwds) == NULL) return NULL;", self.basetype) 430 Dedent() 431 Output("} else {") 432 Indent() 433 Output("if ((_self = type->tp_alloc(type, 0)) == NULL) return NULL;") 434 OutRbrace() 435 else: 436 Output("if ((_self = type->tp_alloc(type, 0)) == NULL) return NULL;") 437 Output("((%s *)_self)->ob_itself = itself;", self.objecttype) 438 Output("return _self;") 439 440 def output_tp_new(self): 441 if self.output_tp_newBody: 442 Output("static PyObject *%s_tp_new(PyTypeObject *type, PyObject *_args, PyObject *_kwds)", self.prefix) 443 OutLbrace() 444 self.output_tp_newBody() 445 OutRbrace() 446 else: 447 Output("#define %s_tp_new PyType_GenericNew", self.prefix) 448 Output() 449 450 output_tp_freeBody = None 451 452 def output_tp_free(self): 453 if self.output_tp_freeBody: 454 Output("static void %s_tp_free(PyObject *self)", self.prefix) 455 OutLbrace() 456 self.output_tp_freeBody() 457 OutRbrace() 458 else: 459 Output("#define %s_tp_free PyObject_Del", self.prefix) 460 Output() 461 462 def outputPEP253Hooks(self): 463 self.output_tp_init() 464 self.output_tp_alloc() 465 self.output_tp_new() 466 self.output_tp_free() 467 468class GlobalObjectDefinition(ObjectDefinition): 469 """Like ObjectDefinition but exports some parts. 470 471 XXX Should also somehow generate a .h file for them. 472 """ 473 474 def __init__(self, name, prefix = None, itselftype = None): 475 ObjectDefinition.__init__(self, name, prefix or name, itselftype or name) 476 self.static = "" 477 478class ObjectIdentityMixin: 479 """A mixin class for objects that makes the identity of ob_itself 480 govern comparisons and dictionary lookups. Useful if the C object can 481 be returned by library calls and it is difficult (or impossible) to find 482 the corresponding Python objects. With this you can create Python object 483 wrappers on the fly""" 484 485 def outputCompare(self): 486 Output() 487 Output("static int %s_compare(%s *self, %s *other)", self.prefix, self.objecttype, 488 self.objecttype) 489 OutLbrace() 490 Output("unsigned long v, w;") 491 Output() 492 Output("if (!%s_Check((PyObject *)other))", self.prefix) 493 OutLbrace() 494 Output("v=(unsigned long)self;") 495 Output("w=(unsigned long)other;") 496 OutRbrace() 497 Output("else") 498 OutLbrace() 499 Output("v=(unsigned long)self->ob_itself;") 500 Output("w=(unsigned long)other->ob_itself;") 501 OutRbrace() 502 Output("if( v < w ) return -1;") 503 Output("if( v > w ) return 1;") 504 Output("return 0;") 505 OutRbrace() 506 507 def outputHash(self): 508 Output() 509 Output("static long %s_hash(%s *self)", self.prefix, self.objecttype) 510 OutLbrace() 511 Output("return (long)self->ob_itself;") 512 OutRbrace() 513