Home | History | Annotate | Download | only in bgen
      1 from bgenOutput import *
      2 from bgenGeneratorGroup import GeneratorGroup
      3 
      4 class 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 
    233 class 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 
    370 class 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 
    468 class 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 
    478 class 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