| from bgenOutput import * |
| from bgenGeneratorGroup import GeneratorGroup |
| |
| class ObjectDefinition(GeneratorGroup): |
| "Spit out code that together defines a new Python object type" |
| basechain = "NULL" |
| tp_flags = "Py_TPFLAGS_DEFAULT" |
| basetype = None |
| |
| def __init__(self, name, prefix, itselftype): |
| """ObjectDefinition constructor. May be extended, but do not override. |
| |
| - name: the object's official name, e.g. 'SndChannel'. |
| - prefix: the prefix used for the object's functions and data, e.g. 'SndCh'. |
| - itselftype: the C type actually contained in the object, e.g. 'SndChannelPtr'. |
| |
| XXX For official Python data types, rules for the 'Py' prefix are a problem. |
| """ |
| |
| GeneratorGroup.__init__(self, prefix or name) |
| self.name = name |
| self.itselftype = itselftype |
| self.objecttype = name + 'Object' |
| self.typename = name + '_Type' |
| self.argref = "" # set to "*" if arg to <type>_New should be pointer |
| self.static = "static " # set to "" to make <type>_New and <type>_Convert public |
| self.modulename = None |
| if hasattr(self, "assertions"): |
| self.assertions() |
| |
| def add(self, g, dupcheck=0): |
| g.setselftype(self.objecttype, self.itselftype) |
| GeneratorGroup.add(self, g, dupcheck) |
| |
| def reference(self): |
| # In case we are referenced from a module |
| pass |
| |
| def setmodulename(self, name): |
| self.modulename = name |
| |
| def generate(self): |
| # XXX This should use long strings and %(varname)s substitution! |
| |
| OutHeader2("Object type " + self.name) |
| |
| sf = self.static and "static " |
| Output("%sPyTypeObject %s;", sf, self.typename) |
| Output() |
| Output("#define %s_Check(x) ((x)->ob_type == &%s || PyObject_TypeCheck((x), &%s))", |
| self.prefix, self.typename, self.typename) |
| Output() |
| Output("typedef struct %s {", self.objecttype) |
| IndentLevel() |
| Output("PyObject_HEAD") |
| self.outputStructMembers() |
| DedentLevel() |
| Output("} %s;", self.objecttype) |
| |
| self.outputNew() |
| |
| self.outputConvert() |
| |
| self.outputDealloc() |
| |
| GeneratorGroup.generate(self) |
| |
| Output() |
| self.outputMethodChain() |
| |
| self.outputGetattr() |
| |
| self.outputSetattr() |
| |
| self.outputCompare() |
| |
| self.outputRepr() |
| |
| self.outputHash() |
| |
| self.outputPEP253Hooks() |
| |
| self.outputTypeObject() |
| |
| OutHeader2("End object type " + self.name) |
| |
| def outputMethodChain(self): |
| Output("%sPyMethodChain %s_chain = { %s_methods, %s };", |
| self.static, self.prefix, self.prefix, self.basechain) |
| |
| def outputStructMembers(self): |
| Output("%s ob_itself;", self.itselftype) |
| |
| def outputNew(self): |
| Output() |
| Output("%sPyObject *%s_New(%s %sitself)", self.static, self.prefix, |
| self.itselftype, self.argref) |
| OutLbrace() |
| Output("%s *it;", self.objecttype) |
| self.outputCheckNewArg() |
| Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename) |
| Output("if (it == NULL) return NULL;") |
| if self.basetype: |
| Output("/* XXXX Should we tp_init or tp_new our basetype? */") |
| self.outputInitStructMembers() |
| Output("return (PyObject *)it;") |
| OutRbrace() |
| |
| def outputInitStructMembers(self): |
| Output("it->ob_itself = %sitself;", self.argref) |
| |
| def outputCheckNewArg(self): |
| "Override this method to apply additional checks/conversions" |
| |
| def outputConvert(self): |
| Output("%sint %s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, |
| self.itselftype) |
| OutLbrace() |
| self.outputCheckConvertArg() |
| Output("if (!%s_Check(v))", self.prefix) |
| OutLbrace() |
| Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name) |
| Output("return 0;") |
| OutRbrace() |
| Output("*p_itself = ((%s *)v)->ob_itself;", self.objecttype) |
| Output("return 1;") |
| OutRbrace() |
| |
| def outputCheckConvertArg(self): |
| "Override this method to apply additional conversions" |
| |
| def outputDealloc(self): |
| Output() |
| Output("static void %s_dealloc(%s *self)", self.prefix, self.objecttype) |
| OutLbrace() |
| self.outputCleanupStructMembers() |
| if self.basetype: |
| Output("%s.tp_dealloc(self)", self.basetype) |
| elif hasattr(self, 'output_tp_free'): |
| # This is a new-style object with tp_free slot |
| Output("self->ob_type->tp_free((PyObject *)self);") |
| else: |
| Output("PyObject_Free((PyObject *)self);") |
| OutRbrace() |
| |
| def outputCleanupStructMembers(self): |
| self.outputFreeIt("self->ob_itself") |
| |
| def outputFreeIt(self, name): |
| Output("/* Cleanup of %s goes here */", name) |
| |
| def outputGetattr(self): |
| Output() |
| Output("static PyObject *%s_getattr(%s *self, char *name)", self.prefix, self.objecttype) |
| OutLbrace() |
| self.outputGetattrBody() |
| OutRbrace() |
| |
| def outputGetattrBody(self): |
| self.outputGetattrHook() |
| Output("return Py_FindMethodInChain(&%s_chain, (PyObject *)self, name);", |
| self.prefix) |
| |
| def outputGetattrHook(self): |
| pass |
| |
| def outputSetattr(self): |
| Output() |
| Output("#define %s_setattr NULL", self.prefix) |
| |
| def outputCompare(self): |
| Output() |
| Output("#define %s_compare NULL", self.prefix) |
| |
| def outputRepr(self): |
| Output() |
| Output("#define %s_repr NULL", self.prefix) |
| |
| def outputHash(self): |
| Output() |
| Output("#define %s_hash NULL", self.prefix) |
| |
| def outputTypeObject(self): |
| sf = self.static and "static " |
| Output() |
| Output("%sPyTypeObject %s = {", sf, self.typename) |
| IndentLevel() |
| Output("PyObject_HEAD_INIT(NULL)") |
| Output("0, /*ob_size*/") |
| if self.modulename: |
| Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) |
| else: |
| Output("\"%s\", /*tp_name*/", self.name) |
| Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) |
| Output("0, /*tp_itemsize*/") |
| Output("/* methods */") |
| Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) |
| Output("0, /*tp_print*/") |
| Output("(getattrfunc) %s_getattr, /*tp_getattr*/", self.prefix) |
| Output("(setattrfunc) %s_setattr, /*tp_setattr*/", self.prefix) |
| Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) |
| Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) |
| Output("(PyNumberMethods *)0, /* tp_as_number */") |
| Output("(PySequenceMethods *)0, /* tp_as_sequence */") |
| Output("(PyMappingMethods *)0, /* tp_as_mapping */") |
| Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) |
| DedentLevel() |
| Output("};") |
| |
| def outputTypeObjectInitializer(self): |
| Output("""%s.ob_type = &PyType_Type;""", self.typename) |
| if self.basetype: |
| Output("%s.tp_base = %s;", self.typename, self.basetype) |
| Output("if (PyType_Ready(&%s) < 0) return;", self.typename) |
| Output("""Py_INCREF(&%s);""", self.typename) |
| Output("PyModule_AddObject(m, \"%s\", (PyObject *)&%s);", self.name, self.typename); |
| Output("/* Backward-compatible name */") |
| Output("""Py_INCREF(&%s);""", self.typename); |
| Output("PyModule_AddObject(m, \"%sType\", (PyObject *)&%s);", self.name, self.typename); |
| |
| def outputPEP253Hooks(self): |
| pass |
| |
| class PEP252Mixin: |
| getsetlist = [] |
| |
| def assertions(self): |
| # Check that various things aren't overridden. If they are it could |
| # signify a bgen-client that has been partially converted to PEP252. |
| assert self.outputGetattr.im_func == PEP252Mixin.outputGetattr.im_func |
| assert self.outputSetattr.im_func == PEP252Mixin.outputSetattr.im_func |
| assert self.outputGetattrBody == None |
| assert self.outputGetattrHook == None |
| assert self.basechain == "NULL" |
| |
| def outputGetattr(self): |
| pass |
| |
| outputGetattrBody = None |
| |
| outputGetattrHook = None |
| |
| def outputSetattr(self): |
| pass |
| |
| def outputMethodChain(self): |
| # This is a good place to output the getters and setters |
| self.outputGetSetList() |
| |
| def outputHook(self, name): |
| methodname = "outputHook_" + name |
| if hasattr(self, methodname): |
| func = getattr(self, methodname) |
| func() |
| else: |
| Output("0, /*%s*/", name) |
| |
| def outputTypeObject(self): |
| sf = self.static and "static " |
| Output() |
| Output("%sPyTypeObject %s = {", sf, self.typename) |
| IndentLevel() |
| Output("PyObject_HEAD_INIT(NULL)") |
| Output("0, /*ob_size*/") |
| if self.modulename: |
| Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) |
| else: |
| Output("\"%s\", /*tp_name*/", self.name) |
| Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) |
| Output("0, /*tp_itemsize*/") |
| |
| Output("/* methods */") |
| Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) |
| Output("0, /*tp_print*/") |
| Output("(getattrfunc)0, /*tp_getattr*/") |
| Output("(setattrfunc)0, /*tp_setattr*/") |
| Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) |
| Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) |
| |
| Output("(PyNumberMethods *)0, /* tp_as_number */") |
| Output("(PySequenceMethods *)0, /* tp_as_sequence */") |
| Output("(PyMappingMethods *)0, /* tp_as_mapping */") |
| |
| Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) |
| self.outputHook("tp_call") |
| Output("0, /*tp_str*/") |
| Output("PyObject_GenericGetAttr, /*tp_getattro*/") |
| Output("PyObject_GenericSetAttr, /*tp_setattro */") |
| |
| self.outputHook("tp_as_buffer") |
| Output("%s, /* tp_flags */", self.tp_flags) |
| self.outputHook("tp_doc") |
| self.outputHook("tp_traverse") |
| self.outputHook("tp_clear") |
| self.outputHook("tp_richcompare") |
| self.outputHook("tp_weaklistoffset") |
| self.outputHook("tp_iter") |
| self.outputHook("tp_iternext") |
| Output("%s_methods, /* tp_methods */", self.prefix) |
| self.outputHook("tp_members") |
| Output("%s_getsetlist, /*tp_getset*/", self.prefix) |
| self.outputHook("tp_base") |
| self.outputHook("tp_dict") |
| self.outputHook("tp_descr_get") |
| self.outputHook("tp_descr_set") |
| self.outputHook("tp_dictoffset") |
| self.outputHook("tp_init") |
| self.outputHook("tp_alloc") |
| self.outputHook("tp_new") |
| self.outputHook("tp_free") |
| DedentLevel() |
| Output("};") |
| |
| def outputGetSetList(self): |
| if self.getsetlist: |
| for name, get, set, doc in self.getsetlist: |
| if get: |
| self.outputGetter(name, get) |
| else: |
| Output("#define %s_get_%s NULL", self.prefix, name) |
| Output() |
| if set: |
| self.outputSetter(name, set) |
| else: |
| Output("#define %s_set_%s NULL", self.prefix, name) |
| Output() |
| |
| Output("static PyGetSetDef %s_getsetlist[] = {", self.prefix) |
| IndentLevel() |
| for name, get, set, doc in self.getsetlist: |
| if doc: |
| doc = '"' + doc + '"' |
| else: |
| doc = "NULL" |
| Output("{\"%s\", (getter)%s_get_%s, (setter)%s_set_%s, %s},", |
| name, self.prefix, name, self.prefix, name, doc) |
| Output("{NULL, NULL, NULL, NULL},") |
| DedentLevel() |
| Output("};") |
| else: |
| Output("#define %s_getsetlist NULL", self.prefix) |
| Output() |
| |
| def outputGetter(self, name, code): |
| Output("static PyObject *%s_get_%s(%s *self, void *closure)", |
| self.prefix, name, self.objecttype) |
| OutLbrace() |
| Output(code) |
| OutRbrace() |
| Output() |
| |
| def outputSetter(self, name, code): |
| Output("static int %s_set_%s(%s *self, PyObject *v, void *closure)", |
| self.prefix, name, self.objecttype) |
| OutLbrace() |
| Output(code) |
| Output("return 0;") |
| OutRbrace() |
| Output() |
| |
| class PEP253Mixin(PEP252Mixin): |
| tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE" |
| |
| def outputHook_tp_init(self): |
| Output("%s_tp_init, /* tp_init */", self.prefix) |
| |
| def outputHook_tp_alloc(self): |
| Output("%s_tp_alloc, /* tp_alloc */", self.prefix) |
| |
| def outputHook_tp_new(self): |
| Output("%s_tp_new, /* tp_new */", self.prefix) |
| |
| def outputHook_tp_free(self): |
| Output("%s_tp_free, /* tp_free */", self.prefix) |
| |
| output_tp_initBody = None |
| |
| def output_tp_init(self): |
| if self.output_tp_initBody: |
| Output("static int %s_tp_init(PyObject *self, PyObject *args, PyObject *kwds)", self.prefix) |
| OutLbrace() |
| self.output_tp_initBody() |
| OutRbrace() |
| else: |
| Output("#define %s_tp_init 0", self.prefix) |
| Output() |
| |
| output_tp_allocBody = None |
| |
| def output_tp_alloc(self): |
| if self.output_tp_allocBody: |
| Output("static PyObject *%s_tp_alloc(PyTypeObject *type, int nitems)", |
| self.prefix) |
| OutLbrace() |
| self.output_tp_allocBody() |
| OutRbrace() |
| else: |
| Output("#define %s_tp_alloc PyType_GenericAlloc", self.prefix) |
| Output() |
| |
| def output_tp_newBody(self): |
| Output("PyObject *self;"); |
| Output("%s itself;", self.itselftype); |
| Output("char *kw[] = {\"itself\", 0};") |
| Output() |
| Output("if (!PyArg_ParseTupleAndKeywords(args, kwds, \"O&\", kw, %s_Convert, &itself)) return NULL;", |
| self.prefix); |
| Output("if ((self = type->tp_alloc(type, 0)) == NULL) return NULL;") |
| Output("((%s *)self)->ob_itself = itself;", self.objecttype) |
| Output("return self;") |
| |
| def output_tp_new(self): |
| if self.output_tp_newBody: |
| Output("static PyObject *%s_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)", self.prefix) |
| OutLbrace() |
| self.output_tp_newBody() |
| OutRbrace() |
| else: |
| Output("#define %s_tp_new PyType_GenericNew", self.prefix) |
| Output() |
| |
| output_tp_freeBody = None |
| |
| def output_tp_free(self): |
| if self.output_tp_freeBody: |
| Output("static void %s_tp_free(PyObject *self)", self.prefix) |
| OutLbrace() |
| self.output_tp_freeBody() |
| OutRbrace() |
| else: |
| Output("#define %s_tp_free PyObject_Del", self.prefix) |
| Output() |
| |
| def outputPEP253Hooks(self): |
| self.output_tp_init() |
| self.output_tp_alloc() |
| self.output_tp_new() |
| self.output_tp_free() |
| |
| class GlobalObjectDefinition(ObjectDefinition): |
| """Like ObjectDefinition but exports some parts. |
| |
| XXX Should also somehow generate a .h file for them. |
| """ |
| |
| def __init__(self, name, prefix = None, itselftype = None): |
| ObjectDefinition.__init__(self, name, prefix or name, itselftype or name) |
| self.static = "" |
| |
| class ObjectIdentityMixin: |
| """A mixin class for objects that makes the identity of ob_itself |
| govern comparisons and dictionary lookups. Useful if the C object can |
| be returned by library calls and it is difficult (or impossible) to find |
| the corresponding Python objects. With this you can create Python object |
| wrappers on the fly""" |
| |
| def outputCompare(self): |
| Output() |
| Output("static int %s_compare(%s *self, %s *other)", self.prefix, self.objecttype, |
| self.objecttype) |
| OutLbrace() |
| Output("unsigned long v, w;") |
| Output() |
| Output("if (!%s_Check((PyObject *)other))", self.prefix) |
| OutLbrace() |
| Output("v=(unsigned long)self;") |
| Output("w=(unsigned long)other;") |
| OutRbrace() |
| Output("else") |
| OutLbrace() |
| Output("v=(unsigned long)self->ob_itself;") |
| Output("w=(unsigned long)other->ob_itself;") |
| OutRbrace() |
| Output("if( v < w ) return -1;") |
| Output("if( v > w ) return 1;") |
| Output("return 0;") |
| OutRbrace() |
| |
| def outputHash(self): |
| Output() |
| Output("static long %s_hash(%s *self)", self.prefix, self.objecttype) |
| OutLbrace() |
| Output("return (long)self->ob_itself;") |
| OutRbrace() |
| |
| |