diff options
Diffstat (limited to 'codegen')
-rw-r--r-- | codegen/__init__.py | 16 | ||||
-rwxr-xr-x | codegen/code-coverage.py | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | codegen/codegen.py | 1722 | ||||
-rwxr-xr-x | codegen/defsconvert.py | 4 | ||||
-rwxr-xr-x | codegen/defsgen.py | 4 | ||||
-rw-r--r-- | codegen/defsparser.py | 154 | ||||
-rw-r--r-- | codegen/docextract.py | 448 | ||||
-rwxr-xr-x | codegen/docextract_to_xml.py | 101 | ||||
-rw-r--r-- | codegen/libcodegen/__init__.py | 16 | ||||
-rw-r--r-- | codegen/libcodegen/argtypes.py (renamed from codegen/argtypes.py) | 53 | ||||
-rw-r--r-- | codegen/libcodegen/codegen.py | 1722 | ||||
-rw-r--r-- | codegen/libcodegen/definitions.py (renamed from codegen/definitions.py) | 16 | ||||
-rw-r--r-- | codegen/libcodegen/defsparser.py | 153 | ||||
-rw-r--r-- | codegen/libcodegen/docextract.py | 185 | ||||
-rw-r--r-- | codegen/libcodegen/override.py | 285 | ||||
-rw-r--r-- | codegen/libcodegen/reversewrapper.py (renamed from codegen/reversewrapper.py) | 10 | ||||
-rw-r--r-- | codegen/libcodegen/scmexpr.py | 147 | ||||
-rw-r--r-- | codegen/override.py | 286 | ||||
-rw-r--r--[-rwxr-xr-x] | codegen/scmexpr.py | 146 |
19 files changed, 2590 insertions, 2880 deletions
diff --git a/codegen/__init__.py b/codegen/__init__.py index 86188f9..e69de29 100644 --- a/codegen/__init__.py +++ b/codegen/__init__.py @@ -1,16 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- - -__all__ = [ - 'argtypes', - 'codegen', - 'definitions', - 'defsparser', - 'docextract', - 'docgen', - 'h2def', - 'defsgen' - 'mergedefs', - 'mkskel', - 'override', - 'scmexpr' -] diff --git a/codegen/code-coverage.py b/codegen/code-coverage.py index 1dc54c3..5d192b3 100755 --- a/codegen/code-coverage.py +++ b/codegen/code-coverage.py @@ -38,7 +38,7 @@ def main(): for symbol in read_symbols(library, type='T', dynamic=1): if symbol[0] == '_': continue if symbol not in wrapper_symbols: - print symbol + print(symbol) if __name__ == '__main__': main() diff --git a/codegen/codegen.py b/codegen/codegen.py index aef93ae..6486fb7 100755..100644 --- a/codegen/codegen.py +++ b/codegen/codegen.py @@ -1,1719 +1,11 @@ #! /usr/bin/env python -import getopt -import keyword -import os -import string -import sys - -import argtypes -import definitions -import defsparser -import override -import reversewrapper -import warnings - -class Coverage(object): - def __init__(self, name): - self.name = name - self.wrapped = 0 - self.not_wrapped = 0 - - def declare_wrapped(self): - self.wrapped += 1 - - def declare_not_wrapped(self): - self.not_wrapped += 1 - - def printstats(self): - total = self.wrapped + self.not_wrapped - fd = sys.stderr - if total: - fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" % - (self.name, - float(self.wrapped*100)/total, - self.wrapped, - total)) - else: - fd.write("***INFO*** There are no declared %s.\n" % self.name) - -functions_coverage = Coverage("global functions") -methods_coverage = Coverage("methods") -vproxies_coverage = Coverage("virtual proxies") -vaccessors_coverage = Coverage("virtual accessors") -iproxies_coverage = Coverage("interface proxies") - -def exc_info(): - warnings.warn("deprecated", DeprecationWarning, stacklevel=2) - #traceback.print_exc() - etype, value, tb = sys.exc_info() - ret = "" - try: - sval = str(value) - if etype == argtypes.ArgTypeError: - ret = "No ArgType for %s" % (sval,) - else: - ret = sval - finally: - del etype, value, tb - return ret - -def fixname(name): - if keyword.iskeyword(name): - return name + '_' - return name - -class FileOutput: - '''Simple wrapper for file object, that makes writing #line - statements easier.''' # " - def __init__(self, fp, filename=None): - self.fp = fp - self.lineno = 1 - if filename: - self.filename = filename - else: - self.filename = self.fp.name - # handle writing to the file, and keep track of the line number ... - def write(self, str): - self.fp.write(str) - self.lineno = self.lineno + str.count('\n') - def writelines(self, sequence): - for line in sequence: - self.write(line) - def close(self): - self.fp.close() - def flush(self): - self.fp.flush() - - def setline(self, linenum, filename): - '''writes out a #line statement, for use by the C - preprocessor.''' # " - self.write('#line %d "%s"\n' % (linenum, filename)) - def resetline(self): - '''resets line numbering to the original file''' - self.setline(self.lineno + 1, self.filename) - -class Wrapper: - type_tmpl = ( - 'PyTypeObject G_GNUC_INTERNAL Py%(typename)s_Type = {\n' - ' PyVarObject_HEAD_INIT(NULL, 0)\n' - ' "%(classname)s", /* tp_name */\n' - ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n' - ' 0, /* tp_itemsize */\n' - ' /* methods */\n' - ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n' - ' (printfunc)0, /* tp_print */\n' - ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n' - ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n' - ' NULL, //%(tp_compare)s, /* tp_compare */\n' - ' (reprfunc)%(tp_repr)s, /* tp_repr */\n' - ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n' - ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n' - ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n' - ' (hashfunc)%(tp_hash)s, /* tp_hash */\n' - ' (ternaryfunc)%(tp_call)s, /* tp_call */\n' - ' (reprfunc)%(tp_str)s, /* tp_str */\n' - ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n' - ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n' - ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n' - ' %(tp_flags)s, /* tp_flags */\n' - ' %(tp_doc)s, /* Documentation string */\n' - ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n' - ' (inquiry)%(tp_clear)s, /* tp_clear */\n' - ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n' - ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n' - ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n' - ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n' - ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n' - ' (struct PyMemberDef*)0, /* tp_members */\n' - ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n' - ' NULL, /* tp_base */\n' - ' NULL, /* tp_dict */\n' - ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n' - ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n' - ' %(tp_dictoffset)s, /* tp_dictoffset */\n' - ' (initproc)%(tp_init)s, /* tp_init */\n' - ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n' - ' (newfunc)%(tp_new)s, /* tp_new */\n' - ' (freefunc)%(tp_free)s, /* tp_free */\n' - ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n' - '};\n\n' - ) - - slots_list = [ - 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro', - 'tp_compare', 'tp_repr', - 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash', - 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter', - 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init', - 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc', - 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc' - ] - - getter_tmpl = ( - 'static PyObject *\n' - '%(funcname)s(PyObject *self, void *closure)\n' - '{\n' - '%(varlist)s' - ' ret = %(field)s;\n' - '%(codeafter)s\n' - '}\n\n' - ) - - parse_tmpl = ( - ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,' - '"%(typecodes)s:%(name)s"%(parselist)s))\n' - ' return %(errorreturn)s;\n' - ) - - deprecated_tmpl = ( - ' if (PyErr_Warn(PyExc_DeprecationWarning, ' - '"%(deprecationmsg)s") < 0)\n' - ' return %(errorreturn)s;\n' - ) - - methdef_tmpl = ( - ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n' - ' %(docstring)s },\n' - ) - - noconstructor = ( - 'static int\n' - 'pygobject_no_constructor(PyObject *self, PyObject *args, ' - 'PyObject *kwargs)\n' - '{\n' - ' gchar buf[512];\n' - '\n' - ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", ' - 'self->ob_type->tp_name);\n' - ' PyErr_SetString(PyExc_NotImplementedError, buf);\n' - ' return -1;\n' - '}\n\n' - ) - - function_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - - virtual_accessor_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' - '{\n' - ' gpointer klass;\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' klass = g_type_class_ref(pyg_type_from_object(cls));\n' - ' if (%(class_cast_macro)s(klass)->%(virtual)s)\n' - ' %(setreturn)s%(class_cast_macro)s(klass)->' - '%(virtual)s(%(arglist)s);\n' - ' else {\n' - ' PyErr_SetString(PyExc_NotImplementedError, ' - '"virtual method %(name)s not implemented");\n' - ' g_type_class_unref(klass);\n' - ' return NULL;\n' - ' }\n' - ' g_type_class_unref(klass);\n' - '%(codeafter)s\n' - '}\n\n' - ) - - # template for method calls - constructor_tmpl = None - method_tmpl = None - - def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): - self.parser = parser - self.objinfo = objinfo - self.overrides = overrides - self.fp = fp - - def get_lower_name(self): - return string.lower(string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1)) - - def get_field_accessor(self, fieldname): - raise NotImplementedError - - def get_initial_class_substdict(self): return {} - - def get_initial_constructor_substdict(self, constructor): - return { 'name': '%s.__init__' % self.objinfo.py_name, - 'errorreturn': '-1' } - - def get_initial_method_substdict(self, method): - substdict = { 'name': '%s.%s' % (self.objinfo.py_name, method.name) } - if method.unblock_threads: - substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' - substdict['end_allow_threads'] = 'pyg_end_allow_threads;' - else: - substdict['begin_allow_threads'] = '' - substdict['end_allow_threads'] = '' - return substdict - - def write_class(self): - if self.overrides.is_type_ignored(self.objinfo.c_name): - return - self.fp.write('\n/* ----------- %s ----------- */\n\n' % - self.objinfo.c_name) - substdict = self.get_initial_class_substdict() - if not substdict.has_key('tp_flags'): - substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE' - substdict['typename'] = self.objinfo.c_name - if self.overrides.modulename: - substdict['classname'] = '%s.%s' % (self.overrides.modulename, - self.objinfo.name) - else: - substdict['classname'] = self.objinfo.name - substdict['tp_doc'] = self.objinfo.docstring - - # Maybe this could be done in a nicer way, but I'll leave it as it is - # for now: -- Johan - if not self.overrides.slot_is_overriden('%s.tp_init' % - self.objinfo.c_name): - substdict['tp_init'] = self.write_constructor() - substdict['tp_methods'] = self.write_methods() - substdict['tp_getset'] = self.write_getsets() - - # handle slots ... - for slot in self.slots_list: - - slotname = '%s.%s' % (self.objinfo.c_name, slot) - slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot) - if slot[:6] == 'tp_as_': - slotfunc = '&' + slotfunc - if self.overrides.slot_is_overriden(slotname): - data = self.overrides.slot_override(slotname) - self.write_function(slotname, data) - substdict[slot] = slotfunc - else: - if not substdict.has_key(slot): - substdict[slot] = '0' - - self.fp.write(self.type_tmpl % substdict) - - self.write_virtuals() - - def write_function_wrapper(self, function_obj, template, - handle_return=0, is_method=0, kwargs_needed=0, - substdict=None): - '''This function is the guts of all functions that generate - wrappers for functions, methods and constructors.''' - if not substdict: substdict = {} - - info = argtypes.WrapperInfo() - - substdict.setdefault('errorreturn', 'NULL') - - # for methods, we want the leading comma - if is_method: - info.arglist.append('') - - if function_obj.varargs: - raise argtypes.ArgTypeNotFoundError("varargs functions not supported") - - for param in function_obj.params: - if param.pdflt != None and '|' not in info.parsestr: - info.add_parselist('|', [], []) - handler = argtypes.matcher.get(param.ptype) - handler.write_param(param.ptype, param.pname, param.pdflt, - param.pnull, info) - - substdict['setreturn'] = '' - if handle_return: - if function_obj.ret not in ('none', None): - substdict['setreturn'] = 'ret = ' - handler = argtypes.matcher.get(function_obj.ret) - handler.write_return(function_obj.ret, - function_obj.caller_owns_return, info) - - if function_obj.deprecated != None: - deprecated = self.deprecated_tmpl % { - 'deprecationmsg': function_obj.deprecated, - 'errorreturn': substdict['errorreturn'] } - else: - deprecated = '' - - # if name isn't set, set it to function_obj.name - substdict.setdefault('name', function_obj.name) - - if function_obj.unblock_threads: - substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' - substdict['end_allow_threads'] = 'pyg_end_allow_threads;' - else: - substdict['begin_allow_threads'] = '' - substdict['end_allow_threads'] = '' - - if self.objinfo: - substdict['typename'] = self.objinfo.c_name - substdict.setdefault('cname', function_obj.c_name) - substdict['varlist'] = info.get_varlist() - substdict['typecodes'] = info.parsestr - substdict['parselist'] = info.get_parselist() - substdict['arglist'] = info.get_arglist() - substdict['codebefore'] = deprecated + ( - string.replace(info.get_codebefore(), - 'return NULL', 'return ' + substdict['errorreturn']) - ) - substdict['codeafter'] = ( - string.replace(info.get_codeafter(), - 'return NULL', - 'return ' + substdict['errorreturn'])) - - if info.parsestr or kwargs_needed: - substdict['parseargs'] = self.parse_tmpl % substdict - substdict['extraparams'] = ', PyObject *args, PyObject *kwargs' - flags = 'METH_VARARGS|METH_KEYWORDS' - - # prepend the keyword list to the variable list - substdict['varlist'] = info.get_kwlist() + substdict['varlist'] - else: - substdict['parseargs'] = '' - substdict['extraparams'] = '' - flags = 'METH_NOARGS' - - return template % substdict, flags - - def write_constructor(self): - initfunc = '0' - constructor = self.parser.find_constructor(self.objinfo,self.overrides) - if not constructor: - return self.write_default_constructor() - - funcname = constructor.c_name - try: - if self.overrides.is_overriden(funcname): - data = self.overrides.override(funcname) - self.write_function(funcname, data) - self.objinfo.has_new_constructor_api = ( - self.objinfo.typecode in - self.overrides.newstyle_constructors) - else: - # ok, a hack to determine if we should use - # new-style constructores :P - property_based = getattr(self, - 'write_property_based_constructor', - None) - if property_based: - if (len(constructor.params) == 0 or - isinstance(constructor.params[0], - definitions.Property)): - # write_property_based_constructor is only - # implemented in GObjectWrapper - return self.write_property_based_constructor( - constructor) - else: - sys.stderr.write( - "Warning: generating old-style constructor for:" + - constructor.c_name + '\n') - - # write constructor from template ... - code = self.write_function_wrapper(constructor, - self.constructor_tmpl, - handle_return=0, is_method=0, kwargs_needed=1, - substdict=self.get_initial_constructor_substdict( - constructor))[0] - self.fp.write(code) - initfunc = '_wrap_' + funcname - except argtypes.ArgTypeError, ex: - sys.stderr.write('Could not write constructor for %s: %s\n' - % (self.objinfo.c_name, str(ex))) - - initfunc = self.write_noconstructor() - return initfunc - - def write_noconstructor(self): - # this is a hack ... - if not hasattr(self.overrides, 'no_constructor_written'): - self.fp.write(self.noconstructor) - self.overrides.no_constructor_written = 1 - initfunc = 'pygobject_no_constructor' - return initfunc - - def write_default_constructor(self): - return self.write_noconstructor() - - def get_methflags(self, funcname): - if self.overrides.wants_kwargs(funcname): - flags = 'METH_VARARGS|METH_KEYWORDS' - elif self.overrides.wants_noargs(funcname): - flags = 'METH_NOARGS' - elif self.overrides.wants_onearg(funcname): - flags = 'METH_O' - else: - flags = 'METH_VARARGS' - if self.overrides.is_staticmethod(funcname): - flags += '|METH_STATIC' - elif self.overrides.is_classmethod(funcname): - flags += '|METH_CLASS' - return flags - - def write_function(self, funcname, data): - lineno, filename = self.overrides.getstartline(funcname) - self.fp.setline(lineno, filename) - self.fp.write(data) - self.fp.resetline() - self.fp.write('\n\n') - - def _get_class_virtual_substdict(self, meth, cname, parent): - substdict = self.get_initial_method_substdict(meth) - substdict['virtual'] = meth.name - substdict['cname'] = cname - substdict['class_cast_macro'] = parent.typecode.replace( - '_TYPE_', '_', 1) + "_CLASS" - substdict['typecode'] = self.objinfo.typecode - substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1) - return substdict - - def write_methods(self): - methods = [] - klass = self.objinfo.c_name - # First, get methods from the defs files - for meth in self.parser.find_methods(self.objinfo): - method_name = meth.c_name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - - methflags = self.get_methflags(method_name) - else: - # write constructor from template ... - code, methflags = self.write_function_wrapper(meth, - self.method_tmpl, handle_return=1, is_method=1, - substdict=self.get_initial_method_substdict(meth)) - self.fp.write(code) - methods.append(self.methdef_tmpl % - { 'name': fixname(meth.name), - 'cname': '_wrap_' + method_name, - 'flags': methflags, - 'docstring': meth.docstring }) - methods_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - methods_coverage.declare_not_wrapped() - sys.stderr.write('Could not write method %s.%s: %s\n' - % (klass, meth.name, str(ex))) - - # Now try to see if there are any defined in the override - for method_name in self.overrides.get_defines_for(klass): - c_name = override.class2cname(klass, method_name) - if self.overrides.is_already_included(method_name): - continue - - try: - data = self.overrides.define(klass, method_name) - self.write_function(method_name, data) - methflags = self.get_methflags(method_name) - - methods.append(self.methdef_tmpl % - { 'name': method_name, - 'cname': '_wrap_' + c_name, - 'flags': methflags, - 'docstring': 'NULL' }) - methods_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - methods_coverage.declare_not_wrapped() - sys.stderr.write('Could not write method %s.%s: %s\n' - % (klass, method_name, str(ex))) - - # Add GObject virtual method accessors, for chaining to parent - # virtuals from subclasses - methods += self.write_virtual_accessors() - - if methods: - methoddefs = '_Py%s_methods' % self.objinfo.c_name - # write the PyMethodDef structure - methods.append(' { NULL, NULL, 0, NULL }\n') - self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs) - self.fp.write(string.join(methods, '')) - self.fp.write('};\n\n') - else: - methoddefs = 'NULL' - return methoddefs - - def write_virtual_accessors(self): - klass = self.objinfo.c_name - methods = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - methflags = self.get_methflags(method_name) - else: - # temporarily add a 'self' parameter as first argument - meth.params.insert(0, definitions.Parameter( - ptype=(self.objinfo.c_name + '*'), - pname='self', pdflt=None, pnull=None)) - try: - # write method from template ... - code, methflags = self.write_function_wrapper( - meth, self.virtual_accessor_tmpl, - handle_return=True, is_method=False, - substdict=self._get_class_virtual_substdict( - meth, method_name, self.objinfo)) - self.fp.write(code) - finally: - del meth.params[0] - methods.append(self.methdef_tmpl % - { 'name': "do_" + fixname(meth.name), - 'cname': '_wrap_' + method_name, - 'flags': methflags + '|METH_CLASS', - 'docstring': 'NULL'}) - vaccessors_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - vaccessors_coverage.declare_not_wrapped() - sys.stderr.write( - 'Could not write virtual accessor method %s.%s: %s\n' - % (klass, meth.name, str(ex))) - return methods - - def write_virtuals(self): - ''' - Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for - GObject virtuals - ''' - klass = self.objinfo.c_name - virtuals = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__proxy_do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - else: - # write virtual proxy ... - ret, props = argtypes.matcher.get_reverse_ret(meth.ret) - wrapper = reversewrapper.ReverseWrapper( - '_wrap_' + method_name, is_static=True) - wrapper.set_return_type(ret(wrapper, **props)) - wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( - wrapper, "self", method_name="do_" + meth.name, - c_type=(klass + ' *'))) - for param in meth.params: - handler, props = argtypes.matcher.get_reverse( - param.ptype) - props["direction"] = param.pdir - wrapper.add_parameter(handler(wrapper, - param.pname, **props)) - buf = reversewrapper.MemoryCodeSink() - wrapper.generate(buf) - self.fp.write(buf.flush()) - virtuals.append((fixname(meth.name), '_wrap_' + method_name)) - vproxies_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - vproxies_coverage.declare_not_wrapped() - virtuals.append((fixname(meth.name), None)) - sys.stderr.write('Could not write virtual proxy %s.%s: %s\n' - % (klass, meth.name, str(ex))) - if virtuals: - # Write a 'pygtk class init' function for this object, - # except when the object type is explicitly ignored (like - # GtkPlug and GtkSocket on win32). - if self.overrides.is_ignored(self.objinfo.typecode): - return - class_cast_macro = self.objinfo.typecode.replace( - '_TYPE_', '_', 1) + "_CLASS" - cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1) - funcname = "__%s_class_init" % klass - self.objinfo.class_init_func = funcname - have_implemented_virtuals = not not [True - for name, cname in virtuals - if cname is not None] - self.fp.write( - ('\nstatic int\n' - '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n' - '{\n') % vars()) - - if have_implemented_virtuals: - self.fp.write(' PyObject *o;\n') - self.fp.write( - ' %(klass)sClass *klass = ' - '%(class_cast_macro)s(gclass);\n' - ' PyObject *gsignals = ' - 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' - % vars()) - - for name, cname in virtuals: - do_name = 'do_' + name - if cname is None: - self.fp.write('\n /* overriding %(do_name)s ' - 'is currently not supported */\n' % vars()) - else: - self.fp.write(''' - o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s"); - if (o == NULL) - PyErr_Clear(); - else { - if (!PyObject_TypeCheck(o, &PyCFunction_Type) - && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) - klass->%(name)s = %(cname)s; - Py_DECREF(o); - } -''' % vars()) - self.fp.write(' return 0;\n}\n') - - def write_getsets(self): - lower_name = self.get_lower_name() - getsets_name = lower_name + '_getsets' - getterprefix = '_wrap_' + lower_name + '__get_' - setterprefix = '_wrap_' + lower_name + '__set_' - - # no overrides for the whole function. If no fields, - # don't write a func - if not self.objinfo.fields: - return '0' - getsets = [] - for ftype, cfname in self.objinfo.fields: - fname = cfname.replace('.', '_') - gettername = '0' - settername = '0' - attrname = self.objinfo.c_name + '.' + fname - if self.overrides.attr_is_overriden(attrname): - code = self.overrides.attr_override(attrname) - self.write_function(attrname, code) - if string.find(code, getterprefix + fname) >= 0: - gettername = getterprefix + fname - if string.find(code, setterprefix + fname) >= 0: - settername = setterprefix + fname - if gettername == '0': - try: - funcname = getterprefix + fname - info = argtypes.WrapperInfo() - handler = argtypes.matcher.get(ftype) - # for attributes, we don't own the "return value" - handler.write_return(ftype, 0, info) - self.fp.write(self.getter_tmpl % - { 'funcname': funcname, - 'varlist': info.varlist, - 'field': self.get_field_accessor(cfname), - 'codeafter': info.get_codeafter() }) - gettername = funcname - except argtypes.ArgTypeError, ex: - sys.stderr.write( - "Could not write getter for %s.%s: %s\n" - % (self.objinfo.c_name, fname, str(ex))) - if gettername != '0' or settername != '0': - getsets.append(' { "%s", (getter)%s, (setter)%s },\n' % - (fixname(fname), gettername, settername)) - - if not getsets: - return '0' - self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name) - for getset in getsets: - self.fp.write(getset) - self.fp.write(' { NULL, (getter)0, (setter)0 },\n') - self.fp.write('};\n\n') - - return getsets_name - - def _write_get_symbol_names(self, writer, functions): - self.fp.write("""static PyObject * -_wrap__get_symbol_names(PyObject *self) -{ - PyObject *pylist = PyList_New(0); - -""") - for obj, bases in writer.get_classes(): - self.fp.write(' PyList_Append(pylist, ' - 'PyString_FromString("%s"));\n' % (obj.name)) - - for name, cname, flags, docstring in functions: - self.fp.write(' PyList_Append(pylist, ' - 'PyString_FromString("%s"));\n' % (name)) - - for enum in writer.get_enums(): - self.fp.write(' PyList_Append(pylist, ' - 'PyString_FromString("%s"));\n' % (enum.name)) - for nick, value in enum.values: - name = value[len(self.overrides.modulename)+1:] - self.fp.write(' PyList_Append(pylist, ' - 'PyString_FromString("%s"));\n' % (name)) - - self.fp.write(" return pylist;\n}\n\n"); - - def _write_get_symbol(self, writer, functions): - self.fp.write("""static PyObject * -_wrap__get_symbol(PyObject *self, PyObject *args) -{ - PyObject *d; - char *name; - static PyObject *modulename = NULL; - static PyObject *module = NULL; - static char *strip_prefix = "%s"; - - if (!PyArg_ParseTuple(args, "Os", &d, &name)) - return NULL; - - if (!modulename) - modulename = PyString_FromString("%s"); - - if (!module) - module = PyDict_GetItemString(d, "__module__"); - -""" % (self.overrides.modulename.upper() + '_', - self.overrides.modulename)) - - first = True - # Classes / GObjects - for obj, bases in writer.get_classes(): - if first: - self.fp.write(' if (!strcmp(name, "%s")) {\n' % obj.name) - first = False - else: - self.fp.write(' } else if (!strcmp(name, "%s")) {\n' % obj.name) - self.fp.write( - ' return (PyObject*)pygobject_lookup_class(%s);\n' % - obj.typecode) - self.fp.write(' }\n') - - # Functions - for name, cname, flags, docstring in functions: - self.fp.write(' else if (!strcmp(name, "%s")) {\n' % name) - self.fp.write(' static PyMethodDef ml = { ' - '"%s", (PyCFunction)%s, %s, "%s"};\n' % ( - name, cname, flags, docstring)) - self.fp.write(' return PyCFunction_NewEx(&ml, NULL, modulename);\n') - self.fp.write(' }\n') - - # Enums - def write_enum(enum, returnobj=False): - if returnobj: - ret = 'return ' - else: - ret = '' - if enum.deftype == 'enum': - self.fp.write( - ' %spyg_enum_add(module, "%s", strip_prefix, %s);\n' - % (ret, enum.name, enum.typecode)) - else: - self.fp.write( - ' %spyg_flags_add(module, "%s", strip_prefix, %s);\n' - % (ret, enum.name, enum.typecode)) - - strip_len = len(self.overrides.modulename)+1 # GTK_ - for enum in writer.get_enums(): - # XXX: Implement without typecodes - self.fp.write(' else if (!strcmp(name, "%s")) {\n' % enum.name) - write_enum(enum, returnobj=True) - self.fp.write(' }\n') - - for nick, value in enum.values: - value = value[strip_len:] - self.fp.write(' else if (!strcmp(name, "%s")) {\n' % value) - write_enum(enum) - self.fp.write(' return PyObject_GetAttrString(module, "%s");\n' % - value) - self.fp.write(' }\n') - - self.fp.write(' return Py_None;\n}\n\n'); - - def _write_function_bodies(self): - functions = [] - # First, get methods from the defs files - for func in self.parser.find_functions(): - funcname = func.c_name - if self.overrides.is_ignored(funcname): - continue - try: - if self.overrides.is_overriden(funcname): - data = self.overrides.override(funcname) - self.write_function(funcname, data) - - methflags = self.get_methflags(funcname) - else: - # write constructor from template ... - code, methflags = self.write_function_wrapper(func, - self.function_tmpl, handle_return=1, is_method=0) - self.fp.write(code) - functions.append((func.name, '_wrap_' + funcname, - methflags, func.docstring)) - functions_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - functions_coverage.declare_not_wrapped() - sys.stderr.write('Could not write function %s: %s\n' - % (func.name, str(ex))) - - # Now try to see if there are any defined in the override - for funcname in self.overrides.get_functions(): - try: - data = self.overrides.function(funcname) - self.write_function(funcname, data) - methflags = self.get_methflags(funcname) - functions.append((funcname, '_wrap_' + funcname, - methflags, 'NULL')) - functions_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - functions_coverage.declare_not_wrapped() - sys.stderr.write('Could not write function %s: %s\n' - % (funcname, str(ex))) - return functions - - def write_functions(self, writer, prefix): - self.fp.write('\n/* ----------- functions ----------- */\n\n') - functions = [] - func_infos = self._write_function_bodies() - - # If we have a dynamic namespace, write symbol and attribute getter - if self.overrides.dynamicnamespace: - self._write_get_symbol_names(writer, func_infos) - self._write_get_symbol(writer, func_infos) - for obj, bases in writer.get_classes(): - self.fp.write("""static PyTypeObject * -%s_register_type(const gchar *name, PyObject *unused) -{ - PyObject *m = PyImport_ImportModule("gtk"); - PyObject *d = PyModule_GetDict(m); -""" % obj.c_name) - writer.write_class(obj, bases, indent=1) - self.fp.write( - ' return (%s)PyDict_GetItemString(d, "%s");\n' % ( - 'PyTypeObject*', obj.name)) - self.fp.write("}\n") - - functions.append(' { "_get_symbol_names", ' - '(PyCFunction)_wrap__get_symbol_names, ' - 'METH_NOARGS, NULL },\n') - functions.append(' { "_get_symbol", ' - '(PyCFunction)_wrap__get_symbol, ' - 'METH_VARARGS, NULL },\n') - else: - for name, cname, flags, docstring in func_infos: - functions.append(self.methdef_tmpl % dict(name=name, - cname=cname, - flags=flags, - docstring=docstring)) - - # write the PyMethodDef structure - functions.append(' { NULL, NULL, 0, NULL }\n') - - self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n') - self.fp.write(string.join(functions, '')) - self.fp.write('};\n\n') - -class GObjectWrapper(Wrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->obj) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - '%(aftercreate)s' - ' pygobject_register_wrapper((PyObject *)self);\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): - Wrapper.__init__(self, parser, objinfo, overrides, fp) - if self.objinfo: - self.castmacro = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGObject', - 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)', - 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' } - - def get_field_accessor(self, fieldname): - castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1) - return '%s(pygobject_get(self))->%s' % (castmacro, fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict(self, - constructor) - if not constructor.caller_owns_return: - substdict['aftercreate'] = " g_object_ref(self->obj);\n" - else: - substdict['aftercreate'] = '' - return substdict - - def get_initial_method_substdict(self, method): - substdict = Wrapper.get_initial_method_substdict(self, method) - substdict['cast'] = string.replace(self.objinfo.typecode, - '_TYPE_', '_', 1) - return substdict - - def write_default_constructor(self): - try: - parent = self.parser.find_object(self.objinfo.parent) - except ValueError: - parent = None - if parent is not None: - ## just like the constructor is inheritted, we should - # inherit the new API compatibility flag - self.objinfo.has_new_constructor_api = ( - parent.has_new_constructor_api) - elif self.objinfo.parent == 'GObject': - self.objinfo.has_new_constructor_api = True - return '0' - - def write_property_based_constructor(self, constructor): - self.objinfo.has_new_constructor_api = True - out = self.fp - print >> out, "static int" - print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \ - ' PyObject *kwargs)\n{' % constructor.c_name - if constructor.params: - s = " GType obj_type = pyg_type_from_object((PyObject *) self);" - print >> out, s - - def py_str_list_to_c(arg): - if arg: - return "{" + ", ".join( - map(lambda s: '"' + s + '"', arg)) + ", NULL }" - else: - return "{ NULL }" - - classname = '%s.%s' % (self.overrides.modulename, - self.objinfo.name) - - if constructor.params: - mandatory_arguments = [param for param in constructor.params - if not param.optional] - optional_arguments = [param for param in constructor.params - if param.optional] - arg_names = py_str_list_to_c( - [param.argname - for param in mandatory_arguments + optional_arguments]) - - prop_names = py_str_list_to_c( - [param.pname - for param in mandatory_arguments + optional_arguments]) - - print >> out, " GParameter params[%i];" % \ - len(constructor.params) - print >> out, " PyObject *parsed_args[%i] = {NULL, };" % \ - len(constructor.params) - print >> out, " char *arg_names[] = %s;" % arg_names - print >> out, " char *prop_names[] = %s;" % prop_names - print >> out, " guint nparams, i;" - print >> out - if constructor.deprecated is not None: - out.write( - ' if (PyErr_Warn(PyExc_DeprecationWarning, ' - '"%s") < 0)\n' % - constructor.deprecated) - print >> out, ' return -1;' - print >> out - out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, ") - template = '"' - if mandatory_arguments: - template += "O"*len(mandatory_arguments) - if optional_arguments: - template += "|" + "O"*len(optional_arguments) - template += ':%s.__init__"' % classname - print >> out, template, ", arg_names", - for i in range(len(constructor.params)): - print >> out, ", &parsed_args[%i]" % i, - - out.write( - "))\n" - " return -1;\n" - "\n" - " memset(params, 0, sizeof(GParameter)*%i);\n" - " if (!pyg_parse_constructor_args(obj_type, arg_names,\n" - " prop_names, params, \n" - " &nparams, parsed_args))\n" - " return -1;\n" - " pygobject_constructv(self, nparams, params);\n" - " for (i = 0; i < nparams; ++i)\n" - " g_value_unset(¶ms[i].value);\n" - % len(constructor.params)) - else: - out.write( - " static char* kwlist[] = { NULL };\n" - "\n") - - if constructor.deprecated is not None: - out.write( - ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n' - ' return -1;\n' - '\n' % constructor.deprecated) - - out.write( - ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n' - ' ":%s.__init__",\n' - ' kwlist))\n' - ' return -1;\n' - '\n' - ' pygobject_constructv(self, 0, NULL);\n' % classname) - out.write( - ' if (!self->obj) {\n' - ' PyErr_SetString(\n' - ' PyExc_RuntimeError, \n' - ' "could not create %s object");\n' - ' return -1;\n' - ' }\n' % classname) - - if not constructor.caller_owns_return: - print >> out, " g_object_ref(self->obj);\n" - - out.write( - ' return 0;\n' - '}\n\n') - - return "_wrap_%s" % constructor.c_name - - -class GInterfaceWrapper(GObjectWrapper): - virtual_accessor_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' - '{\n' - ' %(vtable)s *iface;\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' iface = g_type_interface_peek(' - 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n' - ' if (iface->%(virtual)s)\n' - ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n' - ' else {\n' - ' PyErr_SetString(PyExc_NotImplementedError, ' - '"interface method %(name)s not implemented");\n' - ' return NULL;\n' - ' }\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyObject', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0'} - - def write_constructor(self): - # interfaces have no constructors ... - return '0' - def write_getsets(self): - # interfaces have no fields ... - return '0' - - def _get_class_virtual_substdict(self, meth, cname, parent): - substdict = self.get_initial_method_substdict(meth) - substdict['virtual'] = meth.name - substdict['cname'] = cname - substdict['typecode'] = self.objinfo.typecode - substdict['vtable'] = self.objinfo.vtable - return substdict - - def write_virtuals(self): - ## Now write reverse method wrappers, which let python code - ## implement interface methods. - # First, get methods from the defs files - klass = self.objinfo.c_name - proxies = [] - for meth in self.parser.find_virtuals(self.objinfo): - method_name = self.objinfo.c_name + "__proxy_do_" + meth.name - if self.overrides.is_ignored(method_name): - continue - try: - if self.overrides.is_overriden(method_name): - if not self.overrides.is_already_included(method_name): - data = self.overrides.override(method_name) - self.write_function(method_name, data) - else: - # write proxy ... - ret, props = argtypes.matcher.get_reverse_ret(meth.ret) - wrapper = reversewrapper.ReverseWrapper( - '_wrap_' + method_name, is_static=True) - wrapper.set_return_type(ret(wrapper, **props)) - wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( - wrapper, "self", method_name="do_" + meth.name, - c_type=(klass + ' *'))) - for param in meth.params: - handler, props = argtypes.matcher.get_reverse( - param.ptype) - props["direction"] = param.pdir - wrapper.add_parameter( - handler(wrapper, param.pname, **props)) - buf = reversewrapper.MemoryCodeSink() - wrapper.generate(buf) - self.fp.write(buf.flush()) - proxies.append((fixname(meth.name), '_wrap_' + method_name)) - iproxies_coverage.declare_wrapped() - except argtypes.ArgTypeError, ex: - iproxies_coverage.declare_not_wrapped() - proxies.append((fixname(meth.name), None)) - sys.stderr.write('Could not write interface proxy %s.%s: %s\n' - % (klass, meth.name, str(ex))) - - if not proxies or not [cname for name, cname in proxies if cname]: - return - - ## Write an interface init function for this object - funcname = "__%s__interface_init" % klass - vtable = self.objinfo.vtable - self.fp.write( - '\nstatic void\n' - '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n' - '{\n' - ' %(vtable)s *parent_iface = ' - 'g_type_interface_peek_parent(iface);\n' - ' PyObject *py_method;\n' - '\n' - % vars()) - - for name, cname in proxies: - do_name = 'do_' + name - if cname is None: - continue - - self.fp.write(( - ' py_method = pytype? PyObject_GetAttrString(' - '(PyObject *) pytype, "%(do_name)s") : NULL;\n' - ' if (py_method && !PyObject_TypeCheck(py_method, ' - '&PyCFunction_Type)) {\n' - ' iface->%(name)s = %(cname)s;\n' - ' } else {\n' - ' PyErr_Clear();\n' - ' if (parent_iface) {\n' - ' iface->%(name)s = parent_iface->%(name)s;\n' - ' }\n' - ' Py_XDECREF(py_method);\n' - ' }\n' - ) % vars()) - self.fp.write('}\n\n') - interface_info = "__%s__iinfo" % klass - self.fp.write(''' -static const GInterfaceInfo %s = { - (GInterfaceInitFunc) %s, - NULL, - NULL -}; -''' % (interface_info, funcname)) - self.objinfo.interface_info = interface_info - -class GBoxedWrapper(Wrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->gtype = %(typecode)s;\n' - ' self->free_on_dealloc = FALSE;\n' - ' self->boxed = %(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->boxed) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - ' self->free_on_dealloc = TRUE;\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(begin_allow_threads)s\n' - ' %(setreturn)s%(cname)s(pyg_boxed_get(self, ' - '%(typename)s)%(arglist)s);\n' - ' %(end_allow_threads)s\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGBoxed', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0' } - - def get_field_accessor(self, fieldname): - return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict( - self, constructor) - substdict['typecode'] = self.objinfo.typecode - return substdict - -class GPointerWrapper(GBoxedWrapper): - constructor_tmpl = ( - 'static int\n' - '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' self->gtype = %(typecode)s;\n' - ' self->pointer = %(cname)s(%(arglist)s);\n' - '%(codeafter)s\n' - ' if (!self->pointer) {\n' - ' PyErr_SetString(PyExc_RuntimeError, ' - '"could not create %(typename)s object");\n' - ' return -1;\n' - ' }\n' - ' return 0;\n' - '}\n\n' - ) - - method_tmpl = ( - 'static PyObject *\n' - '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' - '{\n' - '%(varlist)s' - '%(parseargs)s' - '%(codebefore)s' - ' %(setreturn)s%(cname)s(pyg_pointer_get(self, ' - '%(typename)s)%(arglist)s);\n' - '%(codeafter)s\n' - '}\n\n' - ) - - def get_initial_class_substdict(self): - return { 'tp_basicsize' : 'PyGPointer', - 'tp_weaklistoffset' : '0', - 'tp_dictoffset' : '0' } - - def get_field_accessor(self, fieldname): - return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name, - fieldname) - - def get_initial_constructor_substdict(self, constructor): - substdict = Wrapper.get_initial_constructor_substdict( - self, constructor) - substdict['typecode'] = self.objinfo.typecode - return substdict - -class SourceWriter: - def __init__(self, parser, overrides, prefix, fp=FileOutput(sys.stdout)): - self.parser = parser - self.overrides = overrides - self.prefix = prefix - self.fp = fp - - def write(self, py_ssize_t_clean=False): - argtypes.py_ssize_t_clean = py_ssize_t_clean - - self.write_headers(py_ssize_t_clean) - self.write_imports() - self.write_type_declarations() - self.write_body() - self.write_classes() - - wrapper = Wrapper(self.parser, None, self.overrides, self.fp) - wrapper.write_functions(self, self.prefix) - - if not self.overrides.dynamicnamespace: - self.write_enums() - self.write_extension_init() - self.write_registers() - - argtypes.py_ssize_t_clean = False - - def write_headers(self, py_ssize_t_clean): - self.fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */') - self.fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n') - if py_ssize_t_clean: - self.fp.write('#define PY_SSIZE_T_CLEAN\n') - self.fp.write('#include <Python.h>\n\n\n') - if py_ssize_t_clean: - self.fp.write(''' - -#if PY_VERSION_HEX < 0x02050000 -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -typedef inquiry lenfunc; -typedef intargfunc ssizeargfunc; -typedef intobjargproc ssizeobjargproc; -#endif - -''') - self.fp.write(self.overrides.get_headers()) - self.fp.resetline() - self.fp.write('\n\n') - - def write_imports(self): - self.fp.write('/* ---------- types from other modules ---------- */\n') - for module, pyname, cname, importing_for in self.overrides.get_imports(): - if importing_for is None or is_registered_object(importing_for): - self.fp.write('static PyTypeObject *_%s;\n' % cname) - self.fp.write('#define %s (*_%s)\n' % (cname, cname)) - self.fp.write('\n\n') - - def write_type_declarations(self): - #todo use 'static' if used only in one file - self.fp.write('/* ---------- forward type declarations ---------- */\n') - for obj in self.parser.boxes: - if not self.overrides.is_type_ignored(obj.c_name): - self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') - for obj in self.parser.objects: - if not self.overrides.is_type_ignored(obj.c_name): - self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') - for interface in self.parser.interfaces: - if not self.overrides.is_type_ignored(interface.c_name): - self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + interface.c_name + '_Type;\n') - self.fp.write('\n') - - def write_body(self): - self.fp.write(self.overrides.get_body()) - self.fp.resetline() - self.fp.write('\n\n') - - def _sort_parent_children(self, objects): - objects = list(objects) - modified = True - while modified: - modified = False - parent_index = None - child_index = None - for i, obj in enumerate(objects): - if obj.parent == 'GObject': - continue - if obj.parent not in [info.c_name for info in objects[:i]]: - for j, info in enumerate(objects[i+1:]): - if info.c_name == obj.parent: - parent_index = i + 1 + j - child_index = i - break - else: - continue - break - if child_index is not None and parent_index is not None: - if child_index != parent_index: - objects.insert(child_index, objects.pop(parent_index)) - modified = True - return objects - - def write_classes(self): - ## Sort the objects, so that we generate code for the parent types - ## before their children. - objects = self._sort_parent_children(self.parser.objects) - - for klass, items in ((GBoxedWrapper, self.parser.boxes), - (GPointerWrapper, self.parser.pointers), - (GObjectWrapper, objects), - (GInterfaceWrapper, self.parser.interfaces)): - for item in items: - instance = klass(self.parser, item, self.overrides, self.fp) - instance.write_class() - self.fp.write('\n') - - def get_enums(self): - enums = [] - for enum in self.parser.enums: - if self.overrides.is_type_ignored(enum.c_name): - continue - enums.append(enum) - return enums - - def write_enums(self): - if not self.parser.enums: - return - - self.fp.write('\n/* ----------- enums and flags ----------- */\n\n') - self.fp.write( - 'void\n' + self.prefix + - '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') - - self.fp.write( - '#ifdef VERSION\n' - ' PyModule_AddStringConstant(module, "__version__", VERSION);\n' - '#endif\n') - - for enum in self.get_enums(): - if enum.typecode is None: - for nick, value in enum.values: - self.fp.write( - ' PyModule_AddIntConstant(module, ' - '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n' - % (value, value)) - else: - if enum.deftype == 'enum': - self.fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' - % (enum.name, enum.typecode)) - else: - self.fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' - % (enum.name, enum.typecode)) - - self.fp.write('\n') - self.fp.write(' if (PyErr_Occurred())\n') - self.fp.write(' PyErr_Print();\n') - self.fp.write('}\n\n') - - def write_object_imports(self, retval=''): - imports = self.overrides.get_imports()[:] - if not imports: - return - - bymod = {} - for module, pyname, cname, importing_for in imports: - if importing_for is None or is_registered_object(importing_for): - bymod.setdefault(module, []).append((pyname, cname)) - self.fp.write(' PyObject *module;\n\n') - for module in bymod: - self.fp.write( - ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n' - % module) - #self.fp.write( - # ' PyObject *moddict = PyModule_GetDict(module);\n\n') - for pyname, cname in bymod[module]: - #self.fp.write( - # ' _%s = (PyTypeObject *)PyDict_GetItemString(' - # 'moddict, "%s");\n' % (cname, pyname)) - self.fp.write( - ' _%s = (PyTypeObject *)PyObject_GetAttrString(' - 'module, "%s");\n' % (cname, pyname)) - self.fp.write(' if (_%s == NULL) {\n' % cname) - self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') - self.fp.write(' "cannot import name %s from %s");\n' - % (pyname, module)) - self.fp.write(' return %s;\n' % retval) - self.fp.write(' }\n') - self.fp.write(' } else {\n') - self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') - self.fp.write(' "could not import %s");\n' % module) - self.fp.write(' return %s;\n' % retval) - self.fp.write(' }\n') - self.fp.write('\n') - - def write_extension_init(self): - self.fp.write('/* initialise stuff extension classes */\n') - self.fp.write('void\n' + self.prefix + '_register_classes(PyObject *d)\n{\n') - self.write_object_imports() - self.fp.write(self.overrides.get_init() + '\n') - self.fp.resetline() - - def get_classes(self): - objects = self.parser.objects[:] - pos = 0 - while pos < len(objects): - parent = objects[pos].parent - for i in range(pos+1, len(objects)): - if objects[i].c_name == parent: - objects.insert(i+1, objects[pos]) - del objects[pos] - break - else: - pos = pos + 1 - - retval = [] - for obj in objects: - if self.overrides.is_type_ignored(obj.c_name): - continue - bases = [] - if obj.parent != None: - bases.append(obj.parent) - bases = bases + obj.implements - retval.append((obj, bases)) - - return retval - - def write_registers(self): - for boxed in self.parser.boxes: - if not self.overrides.is_type_ignored(boxed.c_name): - self.fp.write(' pyg_register_boxed(d, "' + boxed.name + - '", ' + boxed.typecode + - ', &Py' + boxed.c_name + - '_Type);\n') - for pointer in self.parser.pointers: - if not self.overrides.is_type_ignored(pointer.c_name): - self.fp.write(' pyg_register_pointer(d, "' + pointer.name + - '", ' + pointer.typecode + - ', &Py' + pointer.c_name + '_Type);\n') - for interface in self.parser.interfaces: - if not self.overrides.is_type_ignored(interface.c_name): - self.fp.write(' pyg_register_interface(d, "' - + interface.name + '", '+ interface.typecode - + ', &Py' + interface.c_name + '_Type);\n') - if interface.interface_info is not None: - self.fp.write(' pyg_register_interface_info(%s, &%s);\n' % - (interface.typecode, interface.interface_info)) - - if not self.overrides.dynamicnamespace: - for obj, bases in self.get_classes(): - self.write_class(obj, bases) - else: - for obj, bases in self.get_classes(): - self.fp.write( - ' pyg_type_register_custom_callback("%s", ' - '(PyGTypeRegistrationFunction)%s_register_type, d);\n' % - (obj.c_name, obj.c_name)) - - self.fp.write('}\n') - - def _can_direct_ref(self, base): - if not self.overrides.dynamicnamespace: - return True - if base == 'GObject': - return True - obj = get_object_by_name(base) - if obj.module.lower() != self.overrides.modulename: - return True - return False - - def write_class(self, obj, bases, indent=1): - indent_str = ' ' * (indent * 4) - if bases: - bases_str = 'Py_BuildValue("(%s)"' % (len(bases) * 'O') - - for base in bases: - if self._can_direct_ref(base): - bases_str += ', &Py%s_Type' % base - else: - baseobj = get_object_by_name(base) - bases_str += ', PyObject_GetAttrString(m, "%s")' % baseobj.name - bases_str += ')' - else: - bases_str = 'NULL' - - self.fp.write( - '%(indent)spygobject_register_class(d, "%(c_name)s", %(typecode)s, &Py%(c_name)s_Type, %(bases)s);\n' - % dict(indent=indent_str, c_name=obj.c_name, typecode=obj.typecode, bases=bases_str)) - - if obj.has_new_constructor_api: - self.fp.write( - indent_str + 'pyg_set_object_has_new_constructor(%s);\n' % - obj.typecode) - else: - print >> sys.stderr, ( - "Warning: Constructor for %s needs to be updated to new API\n" - " See http://live.gnome.org/PyGTK_2fWhatsNew28" - "#update-constructors") % obj.c_name - - if obj.class_init_func is not None: - self.fp.write( - indent_str + 'pyg_register_class_init(%s, %s);\n' % - (obj.typecode, obj.class_init_func)) - -_objects = {} - -def is_registered_object(c_name): - return c_name in _objects - -def get_object_by_name(c_name): - global _objects - return _objects[c_name] - -def register_types(parser): - global _objects - for boxed in parser.boxes: - argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode) - _objects[boxed.c_name] = boxed - for pointer in parser.pointers: - argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode) - for obj in parser.objects: - argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode) - _objects[obj.c_name] = obj - for iface in parser.interfaces: - argtypes.matcher.register_object(iface.c_name, None, iface.typecode) - _objects[iface.c_name] = iface - for enum in parser.enums: - if enum.deftype == 'flags': - argtypes.matcher.register_flag(enum.c_name, enum.typecode) - else: - argtypes.matcher.register_enum(enum.c_name, enum.typecode) - -usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile' -def main(argv): - o = override.Overrides() - prefix = 'pygtk' - outfilename = None - errorfilename = None - opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:I:", - ["override=", "prefix=", "register=", "outfilename=", - "load-types=", "errorfilename=", "py_ssize_t-clean"]) - defines = {} # -Dkey[=val] options - py_ssize_t_clean = False - for opt, arg in opts: - if opt in ('-o', '--override'): - o = override.Overrides(arg) - elif opt in ('-p', '--prefix'): - prefix = arg - elif opt in ('-r', '--register'): - # Warning: user has to make sure all -D options appear before -r - p = defsparser.DefsParser(arg, defines) - p.startParsing() - register_types(p) - del p - elif opt == '--outfilename': - outfilename = arg - elif opt == '--errorfilename': - errorfilename = arg - elif opt in ('-t', '--load-types'): - globals = {} - execfile(arg, globals) - elif opt == '-D': - nameval = arg.split('=') - try: - defines[nameval[0]] = nameval[1] - except IndexError: - defines[nameval[0]] = None - elif opt == '-I': - defsparser.include_path.insert(0, arg) - elif opt == '--py_ssize_t-clean': - py_ssize_t_clean = True - if len(args) < 1: - print >> sys.stderr, usage - return 1 - if errorfilename: - sys.stderr = open(errorfilename, "w") - p = defsparser.DefsParser(args[0], defines) - if not outfilename: - outfilename = os.path.splitext(args[0])[0] + '.c' - - p.startParsing() - - register_types(p) - sw = SourceWriter(p, o, prefix, FileOutput(sys.stdout, outfilename)) - sw.write(py_ssize_t_clean) +# codegen.py is runnable as a script and available as module in codegen package +if __name__ == '__main__': + from libcodegen import codegen + import sys + sys.exit(codegen.main(sys.argv)) +else: + from codegen.libcodegen.codegen import * - functions_coverage.printstats() - methods_coverage.printstats() - vproxies_coverage.printstats() - vaccessors_coverage.printstats() - iproxies_coverage.printstats() -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/codegen/defsconvert.py b/codegen/defsconvert.py index c3c2324..c58db53 100755 --- a/codegen/defsconvert.py +++ b/codegen/defsconvert.py @@ -16,11 +16,11 @@ def to_upper_str(name): name = _upperstr_pat1.sub(r'\1_\2', name) name = _upperstr_pat2.sub(r'\1_\2', name) name = _upperstr_pat3.sub(r'\1_\2', name, count=1) - return string.upper(name) + return name.upper() def typecode(typename): """create a typecode (eg. GTK_TYPE_WIDGET) from a typename""" - return string.replace(to_upper_str(typename), '_', '_TYPE_', 1) + return to_upper_str(typename).replace('_', '_TYPE_', 1) STATE_START = 0 diff --git a/codegen/defsgen.py b/codegen/defsgen.py index 6c2e63d..de7c0de 100755 --- a/codegen/defsgen.py +++ b/codegen/defsgen.py @@ -220,7 +220,7 @@ def find_defs(buf, gobj, modlib, defs): func_name = m[1] for lib in modlib: if hasattr(lib, func_name): - objtype = apply(getattr(lib, func_name)) + objtype = getattr(lib, func_name)() obj_name = gobj.g_type_name(objtype) parent = gobj.g_type_parent(objtype) parent_name = gobj.g_type_name(parent) @@ -504,7 +504,7 @@ class DefsWriter: func = m.group(1) + '_get_type' lib = [l for l in self.modlib if hasattr(l, func)] if lib: - cname = self.gobj.g_type_name(apply(getattr(lib[0], func))) + cname = self.gobj.g_type_name(getattr(lib[0], func)()) if cname and self.gobj.g_type_from_name(r.group(1)): self.fp.write(' (is-constructor-of "' + cname + '")\n') self._write_return(ret) diff --git a/codegen/defsparser.py b/codegen/defsparser.py index 37ba0a2..27b6b4d 100644 --- a/codegen/defsparser.py +++ b/codegen/defsparser.py @@ -1,153 +1 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -import os, sys -import scmexpr -from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \ - InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef - -include_path = ['.'] - -class IncludeParser(scmexpr.Parser): - """A simple parser that follows include statements automatically""" - def include(self, input_filename): - global include_path - if os.path.isabs(input_filename): - filename = input_filename - # set self.filename to the include name, to handle recursive includes - oldfile = self.filename - self.filename = filename - self.startParsing() - self.filename = oldfile - else: - inc_path = [os.path.dirname(self.filename)] + include_path - for filename in [os.path.join(path_entry, input_filename) - for path_entry in inc_path]: - if not os.path.exists(filename): - continue - # set self.filename to the include name, to handle recursive includes - oldfile = self.filename - self.filename = filename - self.startParsing() - self.filename = oldfile - break - else: - raise IOError("%s not found in include path %s" % (input_filename, inc_path)) - -class DefsParser(IncludeParser): - def __init__(self, arg, defines={}): - IncludeParser.__init__(self, arg) - self.objects = [] - self.interfaces = [] - self.enums = [] # enums and flags - self.boxes = [] # boxed types - self.pointers = [] # pointer types - self.functions = [] # functions and methods - self.virtuals = [] # virtual methods - self.c_name = {} # hash of c names of functions - self.methods = {} # hash of methods of particular objects - self.defines = defines # -Dfoo=bar options, as dictionary - - def define_object(self, *args): - odef = apply(ObjectDef, args) - self.objects.append(odef) - self.c_name[odef.c_name] = odef - def define_interface(self, *args): - idef = apply(InterfaceDef, args) - self.interfaces.append(idef) - self.c_name[idef.c_name] = idef - def define_enum(self, *args): - edef = apply(EnumDef, args) - self.enums.append(edef) - self.c_name[edef.c_name] = edef - def define_flags(self, *args): - fdef = apply(FlagsDef, args) - self.enums.append(fdef) - self.c_name[fdef.c_name] = fdef - def define_boxed(self, *args): - bdef = apply(BoxedDef, args) - self.boxes.append(bdef) - self.c_name[bdef.c_name] = bdef - def define_pointer(self, *args): - pdef = apply(PointerDef, args) - self.pointers.append(pdef) - self.c_name[pdef.c_name] = pdef - def define_function(self, *args): - fdef = apply(FunctionDef, args) - self.functions.append(fdef) - self.c_name[fdef.c_name] = fdef - def define_method(self, *args): - mdef = apply(MethodDef, args) - self.functions.append(mdef) - self.c_name[mdef.c_name] = mdef - def define_virtual(self, *args): - vdef = apply(VirtualDef, args) - self.virtuals.append(vdef) - def merge(self, old, parmerge): - for obj in self.objects: - if old.c_name.has_key(obj.c_name): - obj.merge(old.c_name[obj.c_name]) - for f in self.functions: - if old.c_name.has_key(f.c_name): - f.merge(old.c_name[f.c_name], parmerge) - - def printMissing(self, old): - for obj in self.objects: - if not old.c_name.has_key(obj.c_name): - obj.write_defs() - for f in self.functions: - if not old.c_name.has_key(f.c_name): - f.write_defs() - - def write_defs(self, fp=sys.stdout): - for obj in self.objects: - obj.write_defs(fp) - for enum in self.enums: - enum.write_defs(fp) - for boxed in self.boxes: - boxed.write_defs(fp) - for pointer in self.pointers: - pointer.write_defs(fp) - for func in self.functions: - func.write_defs(fp) - - def find_object(self, c_name): - for obj in self.objects: - if obj.c_name == c_name: - return obj - else: - raise ValueError('object %r not found' % c_name) - - def find_constructor(self, obj, overrides): - for func in self.functions: - if isinstance(func, FunctionDef) and \ - func.is_constructor_of == obj.c_name and \ - not overrides.is_ignored(func.c_name): - return func - - def find_methods(self, obj): - objname = obj.c_name - return filter(lambda func, on=objname: isinstance(func, MethodDef) and - func.of_object == on, self.functions) - - def find_virtuals(self, obj): - objname = obj.c_name - retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and - func.of_object == on, self.virtuals) - return retval - - def find_functions(self): - return filter(lambda func: isinstance(func, FunctionDef) and - not func.is_constructor_of, self.functions) - - def ifdef(self, *args): - if args[0] in self.defines: - for arg in args[1:]: - #print >> sys.stderr, "-----> Handling conditional definition (%s): %s" % (args[0], arg) - self.handle(arg) - else: - pass - #print >> sys.stderr, "-----> Conditional %s is not true" % (args[0],) - - def ifndef(self, *args): - if args[0] not in self.defines: - for arg in args[1:]: - self.handle(arg) +from .libcodegen.defsparser import * diff --git a/codegen/docextract.py b/codegen/docextract.py deleted file mode 100644 index 06a08a3..0000000 --- a/codegen/docextract.py +++ /dev/null @@ -1,448 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -'''Simple module for extracting GNOME style doc comments from C -sources, so I can use them for other purposes.''' - -import sys, os, string, re - -__all__ = ['extract'] - -class GtkDoc: - def __init__(self): - self.name = None - self.block_type = '' # The block type ('function', 'signal', 'property') - self.params = [] - self.annotations = [] - self.description = '' - self.ret = ('', []) # (return, annotations) - def set_name(self, name): - self.name = name - def set_type(self, block_type): - self.block_type = block_type - def get_type(self): - return self.block_type - def add_param(self, name, description, annotations=[]): - if name == '...': - name = 'Varargs' - self.params.append((name, description, annotations)) - def append_to_last_param(self, extra): - self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra, - self.params[-1][2]) - def append_to_named_param(self, name, extra): - for i in range(len(self.params)): - if self.params[i][0] == name: - self.params[i] = (name, self.params[i][1] + extra, - self.params[i][2]) - return - # fall through to adding extra parameter ... - self.add_param(name, extra) - def add_annotation(self, annotation): - self.annotations.append(annotation) - def get_annotations(self): - return self.annotations - def append_to_description(self, extra): - self.description = self.description + extra - def get_description(self): - return self.description - def add_return(self, first_line, annotations=[]): - self.ret = (first_line, annotations) - def append_to_return(self, extra): - self.ret = (self.ret[0] + extra, self.ret[1]) - -comment_start_pattern = re.compile(r'^\s*/\*\*\s') -comment_end_pattern = re.compile(r'^\s*\*+/') -comment_line_lead_pattern = re.compile(r'^\s*\*\s*') -comment_empty_line_pattern = re.compile(r'^\s*\**\s*$') -function_name_pattern = re.compile(r'^([a-z]\w*)\s*:?(\s*\(.*\)\s*){0,2}\s*$') -signal_name_pattern = re.compile(r'^([A-Z]\w+::[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$') -property_name_pattern = re.compile(r'^([A-Z]\w+:[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$') -return_pattern = re.compile(r'^@?(returns:|return\s+value:)(.*\n?)$', re.IGNORECASE) -deprecated_pattern = re.compile(r'^(deprecated\s*:\s*.*\n?)$', re.IGNORECASE) -rename_to_pattern = re.compile(r'^(rename\s+to)\s*:\s*(.*\n?)$', re.IGNORECASE) -param_pattern = re.compile(r'^@(\S+)\s*:(.*\n?)$') -# Used to extract the annotations in the parameter and return descriptions -# extracted using above [param|return]_pattern patterns. -annotations_pattern = re.compile(r'^(?:(\s*\(.*\)\s*)*:)') -# Used to construct the annotation lists. -annotation_lead_pattern = re.compile(r'^\s*\(\s*(.*?)\s*\)\s*') - -# These patterns determine the identifier of the current comment block. They -# are grouped in a list for easy determination of block identifiers (in -# skip_to_identifier). The function_name_pattern should be tested for last -# because it always matches signal and property identifiers. -identifier_patterns = [ signal_name_pattern, property_name_pattern, function_name_pattern ] - -# This pattern is to match return sections that forget to have a colon (':') -# after the initial 'Return' phrase. It is not included by default in the list -# of final sections below because a lot of function descriptions begin with -# 'Returns ...' and the process_description() function would stop right at that -# first line, thinking it is a return section. -no_colon_return_pattern = re.compile(r'^@?(returns|return\s+value)\s*(.*\n?)$', re.IGNORECASE) -since_pattern = re.compile(r'^(since\s*:\s*.*\n?)$', re.IGNORECASE) - -# These patterns normally will be encountered after the description. Knowing -# the order of their appearance is difficult so this list is used to test when -# one begins and the other ends when processing the rest of the sections after -# the description. -final_section_patterns = [ return_pattern, since_pattern, deprecated_pattern, rename_to_pattern ] - -def parse_file(fp, doc_dict): - line = fp.readline() - while line: - cur_doc = GtkDoc() - line = skip_to_comment_block(fp, line) - line = skip_to_identifier(fp, line, cur_doc) - # See if the identifier is found (stored in the current GtkDoc by - # skip_to_identifier). If so, continue reading the rest of the comment - # block. - if cur_doc.name: - line = process_params(fp, line, cur_doc) - line = process_description(fp, line, cur_doc) - line = process_final_sections(fp, line, cur_doc) - # Add the current doc block to the dictionary of doc blocks. - doc_dict[cur_doc.name] = cur_doc - -# Given a list of annotations as string of the form -# '(annotation1) (annotation2) ...' return a list of annotations of the form -# [ (name1, value1), (name2, value2) ... ]. Not all annotations have values so -# the values in the list of tuples could be empty (''). -def get_annotation_list(annotations): - annotation_list = [] - while annotations: - match = annotation_lead_pattern.match(annotations) - if match: - annotation_contents = match.group(1) - name, split, value = annotation_contents.strip().partition(' ') - annotation_list.append((name, value)) - # Remove first occurrence to continue processing. - annotations = annotation_lead_pattern.sub('', annotations) - else: - break - return annotation_list - -# Given a currently read line, test that line and continue reading until the -# beginning of a comment block is found or eof is reached. Return the last -# read line. -def skip_to_comment_block(fp, line): - while line: - if comment_start_pattern.match(line): - break - line = fp.readline() - return line - -# Given the current line in a comment block, continue skipping lines until a -# non-blank line in the comment block is found or until the end of the block -# (or eof) is reached. Returns the line where reading stopped. -def skip_to_nonblank(fp, line): - while line: - if not comment_empty_line_pattern.match(line): - break - line = fp.readline() - # Stop processing if eof or end of comment block is reached. - if not line or comment_end_pattern.match(line): - break - return line - -# Given the first line of a comment block (the '/**'), see if the next -# non-blank line is the identifier of the comment block. Stop processing if -# the end of the block or eof is reached. Store the identifier (if there is -# one) and its type ('function', 'signal' or 'property') in the given GtkDoc. -# Return the line where the identifier is found or the line that stops the -# processing (if eof or the end of the comment block is found first). -def skip_to_identifier(fp, line, cur_doc): - # Skip the initial comment block line ('/**') if not eof. - if line: line = fp.readline() - - # Now skip empty lines. - line = skip_to_nonblank(fp, line) - - # See if the first non-blank line is the identifier. - if line and not comment_end_pattern.match(line): - # Remove the initial ' * ' in comment block line and see if there is an - # identifier. - line = comment_line_lead_pattern.sub('', line) - for pattern in identifier_patterns: - match = pattern.match(line) - if match: - # Set the GtkDoc name. - cur_doc.set_name(match.group(1)) - # Get annotations and add them to the GtkDoc. - annotations = get_annotation_list(match.group(2)) - for annotation in annotations: - cur_doc.add_annotation(annotation) - # Set the GtkDoc type. - if pattern == signal_name_pattern: - cur_doc.set_type('signal') - elif pattern == property_name_pattern: - cur_doc.set_type('property') - elif pattern == function_name_pattern: - cur_doc.set_type('function') - return line - return line - -# Given a currently read line (presumably the identifier line), read the next -# lines, testing to see if the lines are part of parameter descriptions. If -# so, store the parameter descriptions in the given doc block. Stop on eof and -# return the last line that stops the processing. -def process_params(fp, line, cur_doc): - # Skip the identifier line if not eof. Also skip any blank lines in the - # comment block. Return if eof or the end of the comment block are - # encountered. - if line: line = fp.readline() - line = skip_to_nonblank(fp, line) - if not line or comment_end_pattern.match(line): - return line - - # Remove initial ' * ' in first non-empty comment block line. - line = comment_line_lead_pattern.sub('', line) - - # Now process possible parameters as long as no eof or the end of the - # param section is not reached (which could be triggered by anything that - # doesn't match a '@param:..." line, even the end of the comment block). - match = param_pattern.match(line) - while line and match: - description = match.group(2) - - # First extract the annotations from the description and save them. - annotations = [] - annotation_match = annotations_pattern.match(description) - if annotation_match: - annotations = get_annotation_list(annotation_match.group(1)) - # Remove the annotations from the description - description = annotations_pattern.sub('', description) - - # Default to appending lines to current parameter. - append_func = cur_doc.append_to_last_param - - # See if the return has been included as part of the parameter - # section and make sure that lines are added to the GtkDoc return if - # so. - if match.group(1).lower() == "returns": - cur_doc.add_return(description, annotations) - append_func = cur_doc.append_to_return - # If not, just add it as a regular parameter. - else: - cur_doc.add_param(match.group(1), description, annotations) - - # Now read lines and append them until next parameter, beginning of - # description (an empty line), the end of the comment block or eof. - line = fp.readline() - while line: - # Stop processing if end of comment block or a blank comment line - # is encountered. - if comment_empty_line_pattern.match(line) or \ - comment_end_pattern.match(line): - break - - # Remove initial ' * ' in comment block line. - line = comment_line_lead_pattern.sub('', line) - - # Break from current param processing if a new one is - # encountered. - if param_pattern.match(line): break; - - # Otherwise, just append the current line and get the next line. - append_func(line) - line = fp.readline() - - # Re-evaluate match for while condition - match = param_pattern.match(line) - - # End by returning the current line. - return line - -# Having processed parameters, read the following lines into the description of -# the current doc block until the end of the comment block, the end of file or -# a return section is encountered. -def process_description(fp, line, cur_doc): - # First skip empty lines returning on eof or end of comment block. - line = skip_to_nonblank(fp, line) - if not line or comment_end_pattern.match(line): - return line - - # Remove initial ' * ' in non-empty comment block line. - line = comment_line_lead_pattern.sub('', line) - - # Also remove possible 'Description:' prefix. - if line[:12] == 'Description:': line = line[12:] - - # Used to tell if the previous line was blank and a return section - # uncommonly marked with 'Returns ...' instead of 'Returns: ...' has - # started (assume it is non-empty to begin with). - prev_line = 'non-empty' - - # Now read lines until a new section (like a return or a since section) is - # encountered. - while line: - # See if the description section has ended (if the line begins with - # 'Returns ...' and the previous line was empty -- this loop replaces - # empty lines with a newline). - if no_colon_return_pattern.match(line) and prev_line == '\n': - return line - # Or if one of the patterns of the final sections match - for pattern in final_section_patterns: - if pattern.match(line): - return line - - # If not, append lines to description in the doc comment block. - cur_doc.append_to_description(line) - - prev_line = line - line = fp.readline() - - # Stop processing on eof or at the end of comment block. - if not line or comment_end_pattern.match(line): - return line - - # Remove initial ' * ' in line so that the text can be appended to the - # description of the comment block and make sure that if the line is - # empty it be interpreted as a newline. - line = comment_line_lead_pattern.sub('', line) - if not line: line = '\n' - -# Given the line that ended the description (the first line of one of the final -# sections) process the final sections ('Returns:', 'Since:', etc.) until the -# end of the comment block or eof. Return the line that ends the processing. -def process_final_sections(fp, line, cur_doc): - while line and not comment_end_pattern.match(line): - # Remove leading ' * ' from current non-empty comment line. - line = comment_line_lead_pattern.sub('', line) - # Temporarily append the no colon return pattern to the final section - # patterns now that the description has been processed. It will be - # removed after the for loop below executes so that future descriptions - # that begin with 'Returns ...' are not interpreted as a return - # section. - final_section_patterns.append(no_colon_return_pattern) - for pattern in final_section_patterns: - match = pattern.match(line) - if match: - if pattern == return_pattern or \ - pattern == no_colon_return_pattern: - # Dealing with a 'Returns:' so first extract the - # annotations from the description and save them. - description = match.group(2) - annotations = [] - annotation_match = \ - annotations_pattern.match(description) - if annotation_match: - annotations = \ - get_annotation_list(annotation_match.group(1)) - # Remove the annotations from the description - description = annotations_pattern.sub('', description) - - # Now add the return. - cur_doc.add_return(description, annotations) - # In case more lines need to be appended. - append_func = cur_doc.append_to_return - elif pattern == rename_to_pattern: - # Dealing with a 'Rename to:' section (GObjectIntrospection - # annotation) so no further lines will be appended but this - # single one (and only to the annotations). - append_func = None - cur_doc.add_annotation((match.group(1), - match.group(2))) - else: - # For all others ('Since:' and 'Deprecated:') just append - # the line to the description for now. - cur_doc.append_to_description(line) - # In case more lines need to be appended. - append_func = cur_doc.append_to_description - - # Stop final section pattern matching for loop since a match - # has already been found. - break - - # Remove the no colon return pattern (which was temporarily added in - # the just executed loop) from the list of final section patterns. - final_section_patterns.pop() - - line = fp.readline() - - # Now continue appending lines to current section until a new one is - # found or an eof or the end of the comment block is encountered. - finished = False - while not finished and line and \ - not comment_end_pattern.match(line): - # Remove leading ' * ' from line and make sure that if it is empty, - # it be interpreted as a newline. - line = comment_line_lead_pattern.sub('', line) - if not line: line = '\n' - - for pattern in final_section_patterns: - if pattern.match(line): - finished = True - break - - # Break out of loop if a new section is found (determined in above - # inner loop). - if finished: break - - # Now it's safe to append line. - if append_func: append_func(line) - - # Get the next line to continue processing. - line = fp.readline() - - return line - -def parse_dir(dir, doc_dict): - for file in os.listdir(dir): - if file in ('.', '..'): continue - path = os.path.join(dir, file) - if os.path.isdir(path): - parse_dir(path, doc_dict) - if len(file) > 2 and file[-2:] == '.c': - sys.stderr.write("Processing " + path + '\n') - parse_file(open(path, 'r'), doc_dict) - -def extract(dirs, doc_dict=None): - if not doc_dict: doc_dict = {} - for dir in dirs: - parse_dir(dir, doc_dict) - return doc_dict - -tmpl_section_pattern = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$') -def parse_tmpl(fp, doc_dict): - cur_doc = None - - line = fp.readline() - while line: - match = tmpl_section_pattern.match(line) - if match: - cur_doc = None # new input shouldn't affect the old doc dict - sect_type = match.group(1) - sect_name = match.group(2) - - if sect_type == 'FUNCTION': - cur_doc = doc_dict.get(sect_name) - if not cur_doc: - cur_doc = GtkDoc() - cur_doc.set_name(sect_name) - doc_dict[sect_name] = cur_doc - elif line == '<!-- # Unused Parameters # -->\n': - cur_doc = None # don't worry about unused params. - elif cur_doc: - if line[:10] == '@Returns: ': - if line[10:].strip(): - cur_doc.append_to_return(line[10:]) - elif line[0] == '@': - pos = line.find(':') - if pos >= 0: - cur_doc.append_to_named_param(line[1:pos], line[pos+1:]) - else: - cur_doc.append_to_description(line) - else: - cur_doc.append_to_description(line) - - line = fp.readline() - -def extract_tmpl(dirs, doc_dict=None): - if not doc_dict: doc_dict = {} - for dir in dirs: - for file in os.listdir(dir): - if file in ('.', '..'): continue - path = os.path.join(dir, file) - if os.path.isdir(path): - continue - if len(file) > 2 and file[-2:] == '.sgml': - parse_tmpl(open(path, 'r'), doc_dict) - return doc_dict diff --git a/codegen/docextract_to_xml.py b/codegen/docextract_to_xml.py index 775b57d..f8d3bae 100755 --- a/codegen/docextract_to_xml.py +++ b/codegen/docextract_to_xml.py @@ -13,18 +13,6 @@ import sys import docextract -def usage(): - sys.stderr.write('usage: docextract_to_xml.py ' + - '[-s /src/dir | --source-dir=/src/dir] ' + - '[-a | --with-annotations] [-p | --with-properties] ' + - '[-i | --with-signals ]\n') - sys.exit(1) - -# Translates special texts to &... HTML acceptable format. Also replace -# occurrences of '/*' and '*/' with '/ *' and '* /' respectively to avoid -# comment errors (note the spaces). Some function descriptions include C++ -# multi-line comments which cause errors when the description is included in a -# C++ Doxygen comment block. def escape_text(unescaped_text): # Escape every "&" not part of an entity reference escaped_text = re.sub(r'&(?![A-Za-z]+;)', '&', unescaped_text) @@ -34,51 +22,31 @@ def escape_text(unescaped_text): escaped_text = string.replace(escaped_text, '*', '*') escaped_text = string.replace(escaped_text, '%', '%') escaped_text = string.replace(escaped_text, '@', '@') - escaped_text = string.replace(escaped_text, '#', '') - escaped_text = string.replace(escaped_text, ' ', ' ') - # This represents a '/' before or after an '*' so replace with slash but - # with spaces. - escaped_text = string.replace(escaped_text, '/', ' / ') # Escape for both tag contents and attribute values escaped_text = string.replace(escaped_text, '<', '<') escaped_text = string.replace(escaped_text, '>', '>') escaped_text = string.replace(escaped_text, '"', '"') - # Replace C++ comment begin and ends to ones that don't affect Doxygen. - escaped_text = string.replace(escaped_text, '/*', '/ *') - escaped_text = string.replace(escaped_text, '*/', '* /') - return escaped_text -def print_annotations(annotations): - for annotation in annotations: - print "<annotation name=" + annotation[0] + ">" + \ - escape_text(annotation[1]) + "</annotation>" - if __name__ == '__main__': try: - opts, args = getopt.getopt(sys.argv[1:], "d:s:o:api", - ["source-dir=", "with-annotations", - "with-properties", "with-signals"]) + opts, args = getopt.getopt(sys.argv[1:], "d:s:o:", + ["source-dir="]) except getopt.error, e: - sys.stderr.write('docextract_to_xml.py: %s\n' % e) - usage() + sys.stderr.write('docgen.py: %s\n' % e) + sys.stderr.write( + 'usage: docgen.py [-s /src/dir]\n') + sys.exit(1) source_dirs = [] - with_annotations = False - with_signals = False - with_properties = False for opt, arg in opts: if opt in ('-s', '--source-dir'): source_dirs.append(arg) - if opt in ('-a', '--with-annotations'): - with_annotations = True - if opt in ('-p', '--with-properties'): - with_properties = True - if opt in ('-i', '--with-signals'): - with_signals = True if len(args) != 0: - usage() + sys.stderr.write( + 'usage: docgen.py [-s /src/dir]\n') + sys.exit(1) docs = docextract.extract(source_dirs); docextract.extract_tmpl(source_dirs, docs); #Try the tmpl sgml files too. @@ -90,50 +58,25 @@ if __name__ == '__main__': print "<root>" for name, value in docs.items(): - # Get the type of comment block ('function', 'signal' or - # 'property') (the value is a GtkDoc). - block_type = value.get_type() - - # Skip signals if the option was not specified. - if block_type == 'signal' and not with_signals: - continue - # Likewise for properties. - elif block_type == 'property' and not with_properties: - continue - - print "<" + block_type + " name=\"" + escape_text(name) + "\">" + print "<function name=\"" + escape_text(name) + "\">" print "<description>" - print escape_text(value.get_description()) + #The value is a docextract.FunctionDoc + print escape_text(value.description) print "</description>" - # Loop through the parameters if not dealing with a property: - if block_type != 'property': - print "<parameters>" - for name, description, annotations in value.params: - print "<parameter name=\"" + escape_text(name) + "\">" - print "<parameter_description>" + escape_text(description) + "</parameter_description>" - - if with_annotations: - print_annotations(annotations) - - print "</parameter>" - - print "</parameters>" + # Loop through the parameters: + print "<parameters>" + for name, description in value.params: + print "<parameter name=\"" + escape_text(name) + "\">" + print "<parameter_description>" + escape_text(description) + "</parameter_description>" + print "</parameter>" - # Show the return-type (also if not dealing with a property): - if with_annotations: - print "<return>" - print "<return_description>" + escape_text(value.ret[0]) + \ - "</return_description>" - print_annotations(value.ret[1]) - print "</return>" - else: - print "<return>" + escape_text(value.ret[0]) + "</return>" + print "</parameters>" - if with_annotations: - print_annotations(value.get_annotations()) + # Show the return-type: + print "<return>" + escape_text(value.ret) + "</return>" - print "</" + block_type + ">\n" + print "</function>\n" print "</root>" diff --git a/codegen/libcodegen/__init__.py b/codegen/libcodegen/__init__.py new file mode 100644 index 0000000..86188f9 --- /dev/null +++ b/codegen/libcodegen/__init__.py @@ -0,0 +1,16 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- + +__all__ = [ + 'argtypes', + 'codegen', + 'definitions', + 'defsparser', + 'docextract', + 'docgen', + 'h2def', + 'defsgen' + 'mergedefs', + 'mkskel', + 'override', + 'scmexpr' +] diff --git a/codegen/argtypes.py b/codegen/libcodegen/argtypes.py index b35f6ef..c8252bb 100644 --- a/codegen/argtypes.py +++ b/codegen/libcodegen/argtypes.py @@ -1,5 +1,4 @@ # -*- Mode: Python; py-indent-offset: 4 -*- -import string import keyword import struct @@ -20,7 +19,7 @@ class VarList: def __init__(self): self.vars = {} def add(self, ctype, name): - if self.vars.has_key(ctype): + if ctype in self.vars: self.vars[ctype] = self.vars[ctype] + (name,) else: self.vars[ctype] = (name,) @@ -30,11 +29,11 @@ class VarList: ret.append(' ') ret.append(type) ret.append(' ') - ret.append(string.join(self.vars[type], ', ')) + ret.append(', '.join(self.vars[type])) ret.append(';\n') if ret: ret.append('\n') - return string.join(ret, '') + return ''.join(ret) return '' class WrapperInfo: @@ -50,18 +49,18 @@ class WrapperInfo: self.arglist = [] self.kwlist = [] def get_parselist(self): - return string.join(self.parselist, ', ') + return ', '.join(self.parselist) def get_codebefore(self): - return string.join(self.codebefore, '') + return ''.join(self.codebefore) def get_codeafter(self): - return string.join(self.codeafter, '') + return ''.join(self.codeafter) def get_arglist(self): - return string.join(self.arglist, ', ') + return ', '.join(self.arglist) def get_varlist(self): return str(self.varlist) def get_kwlist(self): ret = ' static char *kwlist[] = { %s };\n' % \ - string.join(self.kwlist + [ 'NULL' ], ', ') + ', '.join(self.kwlist + [ 'NULL' ]) if not self.get_varlist(): ret = ret + '\n' return ret @@ -79,14 +78,14 @@ class ArgType: def write_param(self, ptype, pname, pdflt, pnull, info): """Add code to the WrapperInfo instance to handle parameter.""" - raise RuntimeError, "write_param not implemented for %s" % \ - self.__class__.__name__ + raise RuntimeError("write_param not implemented for %s" % \ + self.__class__.__name__) def write_return(self, ptype, ownsreturn, info): """Adds a variable named ret of the return type to info.varlist, and add any required code to info.codeafter to convert the return value to a python object.""" - raise RuntimeError, "write_return not implemented for %s" % \ - self.__class__.__name__ + raise RuntimeError("write_return not implemented for %s" % \ + self.__class__.__name__) class NoneArg(ArgType): def write_return(self, ptype, ownsreturn, info): @@ -110,7 +109,7 @@ class StringArg(ArgType): # have to free result ... info.varlist.add('gchar', '*ret') info.codeafter.append(' if (ret) {\n' + - ' PyObject *py_ret = PyString_FromString(ret);\n' + + ' PyObject *py_ret = _PyUnicode_FromString(ret);\n' + ' g_free(ret);\n' + ' return py_ret;\n' + ' }\n' + @@ -119,7 +118,7 @@ class StringArg(ArgType): else: info.varlist.add('const gchar', '*ret') info.codeafter.append(' if (ret)\n' + - ' return PyString_FromString(ret);\n'+ + ' return _PyUnicode_FromString(ret);\n'+ ' Py_INCREF(Py_None);\n' + ' return Py_None;') @@ -152,7 +151,7 @@ class CharArg(ArgType): info.add_parselist('c', ['&' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add('gchar', 'ret') - info.codeafter.append(' return PyString_FromStringAndSize(&ret, 1);') + info.codeafter.append(' return _PyUnicode_FromStringAndSize(&ret, 1);') class GUniCharArg(ArgType): ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n' ' if (ret > 0xffff) {\n' @@ -185,14 +184,14 @@ class IntArg(ArgType): info.add_parselist('i', ['&' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add('int', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') + info.codeafter.append(' return _PyLong_FromLong(ret);') class UIntArg(ArgType): dflt = (' if (py_%(name)s) {\n' ' if (PyLong_Check(py_%(name)s))\n' ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' - ' else if (PyInt_Check(py_%(name)s))\n' - ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else if (_PyLong_Check(py_%(name)s))\n' + ' %(name)s = _PyLong_AsLong(py_%(name)s);\n' ' else\n' ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' ' if (PyErr_Occurred())\n' @@ -200,8 +199,8 @@ class UIntArg(ArgType): ' }\n') before = (' if (PyLong_Check(py_%(name)s))\n' ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n' - ' else if (PyInt_Check(py_%(name)s))\n' - ' %(name)s = PyInt_AsLong(py_%(name)s);\n' + ' else if (_PyLong_Check(py_%(name)s))\n' + ' %(name)s = _PyLong_AsLong(py_%(name)s);\n' ' else\n' ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n' ' if (PyErr_Occurred())\n' @@ -277,7 +276,7 @@ class LongArg(ArgType): info.add_parselist('l', ['&' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add(ptype, 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);\n') + info.codeafter.append(' return _PyLong_FromLong(ret);\n') class BoolArg(IntArg): def write_return(self, ptype, ownsreturn, info): @@ -294,7 +293,7 @@ class TimeTArg(ArgType): info.add_parselist('i', ['&' + pname], [pname]) def write_return(self, ptype, ownsreturn, info): info.varlist.add('time_t', 'ret') - info.codeafter.append(' return PyInt_FromLong(ret);') + info.codeafter.append(' return _PyLong_FromLong(ret);') class ULongArg(ArgType): def write_param(self, ptype, pname, pdflt, pnull, info): @@ -475,7 +474,7 @@ class ObjectArg(ArgType): ' %(name)s = %(cast)s(py_%(name)s->obj);\n' def __init__(self, objname, parent, typecode): self.objname = objname - self.cast = string.replace(typecode, '_TYPE_', '_', 1) + self.cast = typecode.replace('_TYPE_', '_', 1) self.parent = parent def write_param(self, ptype, pname, pdflt, pnull, info): if pnull: @@ -695,7 +694,7 @@ class AtomArg(IntArg): info.varlist.add('PyObject *', 'py_ret') info.varlist.add('gchar *', 'name') info.codeafter.append(' name = gdk_atom_name(ret);\n' - ' py_ret = PyString_FromString(name);\n' + ' py_ret = _PyUnicode_FromString(name);\n' ' g_free(name);\n' ' return py_ret;') @@ -867,7 +866,7 @@ class ArgMatcher: self.register('GdkBitmap', oa) self.register('GdkBitmap*', oa) def register_boxed(self, ptype, typecode): - if self.argtypes.has_key(ptype): return + if ptype in self.argtypes: return arg = BoxedArg(ptype, typecode) self.register(ptype, arg) self.register(ptype+'*', arg) @@ -934,7 +933,7 @@ class ArgMatcher: def object_is_a(self, otype, parent): if otype == None: return 0 if otype == parent: return 1 - if not self.argtypes.has_key(otype): return 0 + if otype not in self.argtypes: return 0 return self.object_is_a(self.get(otype).parent, parent) matcher = ArgMatcher() diff --git a/codegen/libcodegen/codegen.py b/codegen/libcodegen/codegen.py new file mode 100644 index 0000000..538a68c --- /dev/null +++ b/codegen/libcodegen/codegen.py @@ -0,0 +1,1722 @@ + +import getopt +import keyword +import os +import string +import sys + +from . import argtypes +from . import definitions +from . import defsparser +from . import override +from . import reversewrapper +import warnings + +class Coverage(object): + def __init__(self, name): + self.name = name + self.wrapped = 0 + self.not_wrapped = 0 + + def declare_wrapped(self): + self.wrapped += 1 + + def declare_not_wrapped(self): + self.not_wrapped += 1 + + def printstats(self): + total = self.wrapped + self.not_wrapped + fd = sys.stderr + if total: + fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" % + (self.name, + float(self.wrapped*100)/total, + self.wrapped, + total)) + else: + fd.write("***INFO*** There are no declared %s.\n" % self.name) + +functions_coverage = Coverage("global functions") +methods_coverage = Coverage("methods") +vproxies_coverage = Coverage("virtual proxies") +vaccessors_coverage = Coverage("virtual accessors") +iproxies_coverage = Coverage("interface proxies") + +def exc_info(): + warnings.warn("deprecated", DeprecationWarning, stacklevel=2) + #traceback.print_exc() + etype, value, tb = sys.exc_info() + ret = "" + try: + sval = str(value) + if etype == argtypes.ArgTypeError: + ret = "No ArgType for %s" % (sval,) + else: + ret = sval + finally: + del etype, value, tb + return ret + +def fixname(name): + if keyword.iskeyword(name): + return name + '_' + return name + +class FileOutput: + '''Simple wrapper for file object, that makes writing #line + statements easier.''' # " + def __init__(self, fp, filename=None): + self.fp = fp + self.lineno = 1 + if filename: + self.filename = filename + else: + self.filename = self.fp.name + # handle writing to the file, and keep track of the line number ... + def write(self, str): + self.fp.write(str) + self.lineno = self.lineno + str.count('\n') + def writelines(self, sequence): + for line in sequence: + self.write(line) + def close(self): + self.fp.close() + def flush(self): + self.fp.flush() + + def setline(self, linenum, filename): + '''writes out a #line statement, for use by the C + preprocessor.''' # " + self.write('#line %d "%s"\n' % (linenum, filename)) + def resetline(self): + '''resets line numbering to the original file''' + self.setline(self.lineno + 1, self.filename) + +class Wrapper: + type_tmpl = ( + 'PyTypeObject G_GNUC_INTERNAL Py%(typename)s_Type = {\n' + ' PyVarObject_HEAD_INIT(NULL, 0)' + ' "%(classname)s", /* tp_name */\n' + ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n' + ' 0, /* tp_itemsize */\n' + ' /* methods */\n' + ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n' + ' (printfunc)0, /* tp_print */\n' + ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n' + ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n' + ' NULL, //%(tp_compare)s, /* tp_compare */\n' + ' (reprfunc)%(tp_repr)s, /* tp_repr */\n' + ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n' + ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n' + ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n' + ' (hashfunc)%(tp_hash)s, /* tp_hash */\n' + ' (ternaryfunc)%(tp_call)s, /* tp_call */\n' + ' (reprfunc)%(tp_str)s, /* tp_str */\n' + ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n' + ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n' + ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n' + ' %(tp_flags)s, /* tp_flags */\n' + ' %(tp_doc)s, /* Documentation string */\n' + ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n' + ' (inquiry)%(tp_clear)s, /* tp_clear */\n' + ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n' + ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n' + ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n' + ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n' + ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n' + ' (struct PyMemberDef*)0, /* tp_members */\n' + ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n' + ' NULL, /* tp_base */\n' + ' NULL, /* tp_dict */\n' + ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n' + ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n' + ' %(tp_dictoffset)s, /* tp_dictoffset */\n' + ' (initproc)%(tp_init)s, /* tp_init */\n' + ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n' + ' (newfunc)%(tp_new)s, /* tp_new */\n' + ' (freefunc)%(tp_free)s, /* tp_free */\n' + ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n' + '};\n\n' + ) + + slots_list = [ + 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro', + 'tp_compare', 'tp_repr', + 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash', + 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter', + 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init', + 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc', + 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc' + ] + + getter_tmpl = ( + 'static PyObject *\n' + '%(funcname)s(PyObject *self, void *closure)\n' + '{\n' + '%(varlist)s' + ' ret = %(field)s;\n' + '%(codeafter)s\n' + '}\n\n' + ) + + parse_tmpl = ( + ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,' + '"%(typecodes)s:%(name)s"%(parselist)s))\n' + ' return %(errorreturn)s;\n' + ) + + deprecated_tmpl = ( + ' if (PyErr_Warn(PyExc_DeprecationWarning, ' + '"%(deprecationmsg)s") < 0)\n' + ' return %(errorreturn)s;\n' + ) + + methdef_tmpl = ( + ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n' + ' %(docstring)s },\n' + ) + + noconstructor = ( + 'static int\n' + 'pygobject_no_constructor(PyObject *self, PyObject *args, ' + 'PyObject *kwargs)\n' + '{\n' + ' gchar buf[512];\n' + '\n' + ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", ' + 'Py_TYPE(self)->tp_name);\n' + ' PyErr_SetString(PyExc_NotImplementedError, buf);\n' + ' return -1;\n' + '}\n\n' + ) + + function_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + + virtual_accessor_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' + '{\n' + ' gpointer klass;\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' klass = g_type_class_ref(pyg_type_from_object(cls));\n' + ' if (%(class_cast_macro)s(klass)->%(virtual)s)\n' + ' %(setreturn)s%(class_cast_macro)s(klass)->' + '%(virtual)s(%(arglist)s);\n' + ' else {\n' + ' PyErr_SetString(PyExc_NotImplementedError, ' + '"virtual method %(name)s not implemented");\n' + ' g_type_class_unref(klass);\n' + ' return NULL;\n' + ' }\n' + ' g_type_class_unref(klass);\n' + '%(codeafter)s\n' + '}\n\n' + ) + + # template for method calls + constructor_tmpl = None + method_tmpl = None + + def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): + self.parser = parser + self.objinfo = objinfo + self.overrides = overrides + self.fp = fp + + def get_lower_name(self): + return self.objinfo.typecode.replace('_TYPE_', '_', 1).lower() + + def get_field_accessor(self, fieldname): + raise NotImplementedError + + def get_initial_class_substdict(self): return {} + + def get_initial_constructor_substdict(self, constructor): + return { 'name': '%s.__init__' % self.objinfo.py_name, + 'errorreturn': '-1' } + + def get_initial_method_substdict(self, method): + substdict = { 'name': '%s.%s' % (self.objinfo.py_name, method.name) } + if method.unblock_threads: + substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' + substdict['end_allow_threads'] = 'pyg_end_allow_threads;' + else: + substdict['begin_allow_threads'] = '' + substdict['end_allow_threads'] = '' + return substdict + + def write_class(self): + if self.overrides.is_type_ignored(self.objinfo.c_name): + return + self.fp.write('\n/* ----------- %s ----------- */\n\n' % + self.objinfo.c_name) + substdict = self.get_initial_class_substdict() + if 'tp_flags' not in substdict: + substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE' + substdict['typename'] = self.objinfo.c_name + if self.overrides.modulename: + substdict['classname'] = '%s.%s' % (self.overrides.modulename, + self.objinfo.name) + else: + substdict['classname'] = self.objinfo.name + substdict['tp_doc'] = self.objinfo.docstring + + # Maybe this could be done in a nicer way, but I'll leave it as it is + # for now: -- Johan + if not self.overrides.slot_is_overriden('%s.tp_init' % + self.objinfo.c_name): + substdict['tp_init'] = self.write_constructor() + substdict['tp_methods'] = self.write_methods() + substdict['tp_getset'] = self.write_getsets() + + # handle slots ... + for slot in self.slots_list: + + slotname = '%s.%s' % (self.objinfo.c_name, slot) + slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot) + if slot[:6] == 'tp_as_': + slotfunc = '&' + slotfunc + if self.overrides.slot_is_overriden(slotname): + data = self.overrides.slot_override(slotname) + self.write_function(slotname, data) + substdict[slot] = slotfunc + else: + if slot not in substdict: + substdict[slot] = '0' + + self.fp.write(self.type_tmpl % substdict) + + self.write_virtuals() + + def write_function_wrapper(self, function_obj, template, + handle_return=0, is_method=0, kwargs_needed=0, + substdict=None): + '''This function is the guts of all functions that generate + wrappers for functions, methods and constructors.''' + if not substdict: substdict = {} + + info = argtypes.WrapperInfo() + + substdict.setdefault('errorreturn', 'NULL') + + # for methods, we want the leading comma + if is_method: + info.arglist.append('') + + if function_obj.varargs: + raise argtypes.ArgTypeNotFoundError("varargs functions not supported") + + for param in function_obj.params: + if param.pdflt != None and '|' not in info.parsestr: + info.add_parselist('|', [], []) + handler = argtypes.matcher.get(param.ptype) + handler.write_param(param.ptype, param.pname, param.pdflt, + param.pnull, info) + + substdict['setreturn'] = '' + if handle_return: + if function_obj.ret not in ('none', None): + substdict['setreturn'] = 'ret = ' + handler = argtypes.matcher.get(function_obj.ret) + handler.write_return(function_obj.ret, + function_obj.caller_owns_return, info) + + if function_obj.deprecated != None: + deprecated = self.deprecated_tmpl % { + 'deprecationmsg': function_obj.deprecated, + 'errorreturn': substdict['errorreturn'] } + else: + deprecated = '' + + # if name isn't set, set it to function_obj.name + substdict.setdefault('name', function_obj.name) + + if function_obj.unblock_threads: + substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;' + substdict['end_allow_threads'] = 'pyg_end_allow_threads;' + else: + substdict['begin_allow_threads'] = '' + substdict['end_allow_threads'] = '' + + if self.objinfo: + substdict['typename'] = self.objinfo.c_name + substdict.setdefault('cname', function_obj.c_name) + substdict['varlist'] = info.get_varlist() + substdict['typecodes'] = info.parsestr + substdict['parselist'] = info.get_parselist() + substdict['arglist'] = info.get_arglist() + substdict['codebefore'] = deprecated + ( + info.get_codebefore().replace( + 'return NULL', 'return ' + substdict['errorreturn']) + ) + substdict['codeafter'] = ( + info.get_codeafter().replace( + 'return NULL', + 'return ' + substdict['errorreturn'])) + + if info.parsestr or kwargs_needed: + substdict['parseargs'] = self.parse_tmpl % substdict + substdict['extraparams'] = ', PyObject *args, PyObject *kwargs' + flags = 'METH_VARARGS|METH_KEYWORDS' + + # prepend the keyword list to the variable list + substdict['varlist'] = info.get_kwlist() + substdict['varlist'] + else: + substdict['parseargs'] = '' + substdict['extraparams'] = '' + flags = 'METH_NOARGS' + + return template % substdict, flags + + def write_constructor(self): + initfunc = '0' + constructor = self.parser.find_constructor(self.objinfo,self.overrides) + if not constructor: + return self.write_default_constructor() + + funcname = constructor.c_name + try: + if self.overrides.is_overriden(funcname): + data = self.overrides.override(funcname) + self.write_function(funcname, data) + self.objinfo.has_new_constructor_api = ( + self.objinfo.typecode in + self.overrides.newstyle_constructors) + else: + # ok, a hack to determine if we should use + # new-style constructores :P + property_based = getattr(self, + 'write_property_based_constructor', + None) + if property_based: + if (len(constructor.params) == 0 or + isinstance(constructor.params[0], + definitions.Property)): + # write_property_based_constructor is only + # implemented in GObjectWrapper + return self.write_property_based_constructor( + constructor) + else: + sys.stderr.write( + "Warning: generating old-style constructor for:" + + constructor.c_name + '\n') + + # write constructor from template ... + code = self.write_function_wrapper(constructor, + self.constructor_tmpl, + handle_return=0, is_method=0, kwargs_needed=1, + substdict=self.get_initial_constructor_substdict( + constructor))[0] + self.fp.write(code) + initfunc = '_wrap_' + funcname + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + sys.stderr.write('Could not write constructor for %s: %s\n' + % (self.objinfo.c_name, str(ex))) + + initfunc = self.write_noconstructor() + return initfunc + + def write_noconstructor(self): + # this is a hack ... + if not hasattr(self.overrides, 'no_constructor_written'): + self.fp.write(self.noconstructor) + self.overrides.no_constructor_written = 1 + initfunc = 'pygobject_no_constructor' + return initfunc + + def write_default_constructor(self): + return self.write_noconstructor() + + def get_methflags(self, funcname): + if self.overrides.wants_kwargs(funcname): + flags = 'METH_VARARGS|METH_KEYWORDS' + elif self.overrides.wants_noargs(funcname): + flags = 'METH_NOARGS' + elif self.overrides.wants_onearg(funcname): + flags = 'METH_O' + else: + flags = 'METH_VARARGS' + if self.overrides.is_staticmethod(funcname): + flags += '|METH_STATIC' + elif self.overrides.is_classmethod(funcname): + flags += '|METH_CLASS' + return flags + + def write_function(self, funcname, data): + lineno, filename = self.overrides.getstartline(funcname) + self.fp.setline(lineno, filename) + self.fp.write(data) + self.fp.resetline() + self.fp.write('\n\n') + + def _get_class_virtual_substdict(self, meth, cname, parent): + substdict = self.get_initial_method_substdict(meth) + substdict['virtual'] = meth.name + substdict['cname'] = cname + substdict['class_cast_macro'] = parent.typecode.replace( + '_TYPE_', '_', 1) + "_CLASS" + substdict['typecode'] = self.objinfo.typecode + substdict['cast'] = parent.typecode.replace('_TYPE_', '_', 1) + return substdict + + def write_methods(self): + methods = [] + klass = self.objinfo.c_name + # First, get methods from the defs files + for meth in self.parser.find_methods(self.objinfo): + method_name = meth.c_name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + + methflags = self.get_methflags(method_name) + else: + # write constructor from template ... + code, methflags = self.write_function_wrapper(meth, + self.method_tmpl, handle_return=1, is_method=1, + substdict=self.get_initial_method_substdict(meth)) + self.fp.write(code) + methods.append(self.methdef_tmpl % + { 'name': fixname(meth.name), + 'cname': '_wrap_' + method_name, + 'flags': methflags, + 'docstring': meth.docstring }) + methods_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + methods_coverage.declare_not_wrapped() + sys.stderr.write('Could not write method %s.%s: %s\n' + % (klass, meth.name, str(ex))) + + # Now try to see if there are any defined in the override + for method_name in self.overrides.get_defines_for(klass): + c_name = override.class2cname(klass, method_name) + if self.overrides.is_already_included(method_name): + continue + + try: + data = self.overrides.define(klass, method_name) + self.write_function(method_name, data) + methflags = self.get_methflags(method_name) + + methods.append(self.methdef_tmpl % + { 'name': method_name, + 'cname': '_wrap_' + c_name, + 'flags': methflags, + 'docstring': 'NULL' }) + methods_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + methods_coverage.declare_not_wrapped() + sys.stderr.write('Could not write method %s.%s: %s\n' + % (klass, method_name, str(ex))) + + # Add GObject virtual method accessors, for chaining to parent + # virtuals from subclasses + methods += self.write_virtual_accessors() + + if methods: + methoddefs = '_Py%s_methods' % self.objinfo.c_name + # write the PyMethodDef structure + methods.append(' { NULL, NULL, 0, NULL }\n') + self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs) + self.fp.write(''.join(methods)) + self.fp.write('};\n\n') + else: + methoddefs = 'NULL' + return methoddefs + + def write_virtual_accessors(self): + klass = self.objinfo.c_name + methods = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + methflags = self.get_methflags(method_name) + else: + # temporarily add a 'self' parameter as first argument + meth.params.insert(0, definitions.Parameter( + ptype=(self.objinfo.c_name + '*'), + pname='self', pdflt=None, pnull=None)) + try: + # write method from template ... + code, methflags = self.write_function_wrapper( + meth, self.virtual_accessor_tmpl, + handle_return=True, is_method=False, + substdict=self._get_class_virtual_substdict( + meth, method_name, self.objinfo)) + self.fp.write(code) + finally: + del meth.params[0] + methods.append(self.methdef_tmpl % + { 'name': "do_" + fixname(meth.name), + 'cname': '_wrap_' + method_name, + 'flags': methflags + '|METH_CLASS', + 'docstring': 'NULL'}) + vaccessors_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + vaccessors_coverage.declare_not_wrapped() + sys.stderr.write( + 'Could not write virtual accessor method %s.%s: %s\n' + % (klass, meth.name, str(ex))) + return methods + + def write_virtuals(self): + ''' + Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for + GObject virtuals + ''' + klass = self.objinfo.c_name + virtuals = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__proxy_do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + else: + # write virtual proxy ... + ret, props = argtypes.matcher.get_reverse_ret(meth.ret) + wrapper = reversewrapper.ReverseWrapper( + '_wrap_' + method_name, is_static=True) + wrapper.set_return_type(ret(wrapper, **props)) + wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( + wrapper, "self", method_name="do_" + meth.name, + c_type=(klass + ' *'))) + for param in meth.params: + handler, props = argtypes.matcher.get_reverse( + param.ptype) + props["direction"] = param.pdir + wrapper.add_parameter(handler(wrapper, + param.pname, **props)) + buf = reversewrapper.MemoryCodeSink() + wrapper.generate(buf) + self.fp.write(buf.flush()) + virtuals.append((fixname(meth.name), '_wrap_' + method_name)) + vproxies_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + vproxies_coverage.declare_not_wrapped() + virtuals.append((fixname(meth.name), None)) + sys.stderr.write('Could not write virtual proxy %s.%s: %s\n' + % (klass, meth.name, str(ex))) + if virtuals: + # Write a 'pygtk class init' function for this object, + # except when the object type is explicitly ignored (like + # GtkPlug and GtkSocket on win32). + if self.overrides.is_ignored(self.objinfo.typecode): + return + class_cast_macro = self.objinfo.typecode.replace( + '_TYPE_', '_', 1) + "_CLASS" + cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1) + funcname = "__%s_class_init" % klass + self.objinfo.class_init_func = funcname + have_implemented_virtuals = not not [True + for name, cname in virtuals + if cname is not None] + self.fp.write( + ('\nstatic int\n' + '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n' + '{\n') % vars()) + + if have_implemented_virtuals: + self.fp.write(' PyObject *o;\n') + self.fp.write( + ' %(klass)sClass *klass = ' + '%(class_cast_macro)s(gclass);\n' + ' PyObject *gsignals = ' + 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n' + % vars()) + + for name, cname in virtuals: + do_name = 'do_' + name + if cname is None: + self.fp.write('\n /* overriding %(do_name)s ' + 'is currently not supported */\n' % vars()) + else: + self.fp.write(''' + o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s"); + if (o == NULL) + PyErr_Clear(); + else { + if (!PyObject_TypeCheck(o, &PyCFunction_Type) + && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s"))) + klass->%(name)s = %(cname)s; + Py_DECREF(o); + } +''' % vars()) + self.fp.write(' return 0;\n}\n') + + def write_getsets(self): + lower_name = self.get_lower_name() + getsets_name = lower_name + '_getsets' + getterprefix = '_wrap_' + lower_name + '__get_' + setterprefix = '_wrap_' + lower_name + '__set_' + + # no overrides for the whole function. If no fields, + # don't write a func + if not self.objinfo.fields: + return '0' + getsets = [] + for ftype, cfname in self.objinfo.fields: + fname = cfname.replace('.', '_') + gettername = '0' + settername = '0' + attrname = self.objinfo.c_name + '.' + fname + if self.overrides.attr_is_overriden(attrname): + code = self.overrides.attr_override(attrname) + self.write_function(attrname, code) + if code.find(getterprefix + fname) >= 0: + gettername = getterprefix + fname + if code.find(setterprefix + fname) >= 0: + settername = setterprefix + fname + if gettername == '0': + try: + funcname = getterprefix + fname + info = argtypes.WrapperInfo() + handler = argtypes.matcher.get(ftype) + # for attributes, we don't own the "return value" + handler.write_return(ftype, 0, info) + self.fp.write(self.getter_tmpl % + { 'funcname': funcname, + 'varlist': info.varlist, + 'field': self.get_field_accessor(cfname), + 'codeafter': info.get_codeafter() }) + gettername = funcname + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + sys.stderr.write( + "Could not write getter for %s.%s: %s\n" + % (self.objinfo.c_name, fname, str(ex))) + if gettername != '0' or settername != '0': + getsets.append(' { "%s", (getter)%s, (setter)%s },\n' % + (fixname(fname), gettername, settername)) + + if not getsets: + return '0' + self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name) + for getset in getsets: + self.fp.write(getset) + self.fp.write(' { NULL, (getter)0, (setter)0 },\n') + self.fp.write('};\n\n') + + return getsets_name + + def _write_get_symbol_names(self, writer, functions): + self.fp.write("""static PyObject * +_wrap__get_symbol_names(PyObject *self) +{ + PyObject *pylist = PyList_New(0); + +""") + for obj, bases in writer.get_classes(): + self.fp.write(' PyList_Append(pylist, ' + '_PyUnicode_FromString("%s"));\n' % (obj.name)) + + for name, cname, flags, docstring in functions: + self.fp.write(' PyList_Append(pylist, ' + '_PyUnicode_FromString("%s"));\n' % (name)) + + for enum in writer.get_enums(): + self.fp.write(' PyList_Append(pylist, ' + '_PyUnicode_FromString("%s"));\n' % (enum.name)) + for nick, value in enum.values: + name = value[len(self.overrides.modulename)+1:] + self.fp.write(' PyList_Append(pylist, ' + '_PyUnicode_FromString("%s"));\n' % (name)) + + self.fp.write(" return pylist;\n}\n\n"); + + def _write_get_symbol(self, writer, functions): + self.fp.write("""static PyObject * +_wrap__get_symbol(PyObject *self, PyObject *args) +{ + PyObject *d; + char *name; + static PyObject *modulename = NULL; + static PyObject *module = NULL; + static char *strip_prefix = "%s"; + + if (!PyArg_ParseTuple(args, "Os", &d, &name)) + return NULL; + + if (!modulename) + modulename = _PyUnicode_FromString("%s"); + + if (!module) + module = PyDict_GetItemString(d, "__module__"); + +""" % (self.overrides.modulename.upper() + '_', + self.overrides.modulename)) + + first = True + # Classes / GObjects + for obj, bases in writer.get_classes(): + if first: + self.fp.write(' if (!strcmp(name, "%s")) {\n' % obj.name) + first = False + else: + self.fp.write(' } else if (!strcmp(name, "%s")) {\n' % obj.name) + self.fp.write( + ' return (PyObject*)pygobject_lookup_class(%s);\n' % + obj.typecode) + self.fp.write(' }\n') + + # Functions + for name, cname, flags, docstring in functions: + self.fp.write(' else if (!strcmp(name, "%s")) {\n' % name) + self.fp.write(' static PyMethodDef ml = { ' + '"%s", (PyCFunction)%s, %s, "%s"};\n' % ( + name, cname, flags, docstring)) + self.fp.write(' return PyCFunction_NewEx(&ml, NULL, modulename);\n') + self.fp.write(' }\n') + + # Enums + def write_enum(enum, returnobj=False): + if returnobj: + ret = 'return ' + else: + ret = '' + if enum.deftype == 'enum': + self.fp.write( + ' %spyg_enum_add(module, "%s", strip_prefix, %s);\n' + % (ret, enum.name, enum.typecode)) + else: + self.fp.write( + ' %spyg_flags_add(module, "%s", strip_prefix, %s);\n' + % (ret, enum.name, enum.typecode)) + + strip_len = len(self.overrides.modulename)+1 # GTK_ + for enum in writer.get_enums(): + # XXX: Implement without typecodes + self.fp.write(' else if (!strcmp(name, "%s")) {\n' % enum.name) + write_enum(enum, returnobj=True) + self.fp.write(' }\n') + + for nick, value in enum.values: + value = value[strip_len:] + self.fp.write(' else if (!strcmp(name, "%s")) {\n' % value) + write_enum(enum) + self.fp.write(' return PyObject_GetAttrString(module, "%s");\n' % + value) + self.fp.write(' }\n') + + self.fp.write(' return Py_None;\n}\n\n'); + + def _write_function_bodies(self): + functions = [] + # First, get methods from the defs files + for func in self.parser.find_functions(): + funcname = func.c_name + if self.overrides.is_ignored(funcname): + continue + try: + if self.overrides.is_overriden(funcname): + data = self.overrides.override(funcname) + self.write_function(funcname, data) + + methflags = self.get_methflags(funcname) + else: + # write constructor from template ... + code, methflags = self.write_function_wrapper(func, + self.function_tmpl, handle_return=1, is_method=0) + self.fp.write(code) + functions.append((func.name, '_wrap_' + funcname, + methflags, func.docstring)) + functions_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + functions_coverage.declare_not_wrapped() + sys.stderr.write('Could not write function %s: %s\n' + % (func.name, str(ex))) + + # Now try to see if there are any defined in the override + for funcname in self.overrides.get_functions(): + try: + data = self.overrides.function(funcname) + self.write_function(funcname, data) + methflags = self.get_methflags(funcname) + functions.append((funcname, '_wrap_' + funcname, + methflags, 'NULL')) + functions_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + functions_coverage.declare_not_wrapped() + sys.stderr.write('Could not write function %s: %s\n' + % (funcname, str(ex))) + return functions + + def write_functions(self, writer, prefix): + self.fp.write('\n/* ----------- functions ----------- */\n\n') + functions = [] + func_infos = self._write_function_bodies() + + # If we have a dynamic namespace, write symbol and attribute getter + if self.overrides.dynamicnamespace: + self._write_get_symbol_names(writer, func_infos) + self._write_get_symbol(writer, func_infos) + for obj, bases in writer.get_classes(): + self.fp.write("""static PyTypeObject * +%s_register_type(const gchar *name, PyObject *unused) +{ + PyObject *m = PyImport_ImportModule("gtk"); + PyObject *d = PyModule_GetDict(m); +""" % obj.c_name) + writer.write_class(obj, bases, indent=1) + self.fp.write( + ' return (%s)PyDict_GetItemString(d, "%s");\n' % ( + 'PyTypeObject*', obj.name)) + self.fp.write("}\n") + + functions.append(' { "_get_symbol_names", ' + '(PyCFunction)_wrap__get_symbol_names, ' + 'METH_NOARGS, NULL },\n') + functions.append(' { "_get_symbol", ' + '(PyCFunction)_wrap__get_symbol, ' + 'METH_VARARGS, NULL },\n') + else: + for name, cname, flags, docstring in func_infos: + functions.append(self.methdef_tmpl % dict(name=name, + cname=cname, + flags=flags, + docstring=docstring)) + + # write the PyMethodDef structure + functions.append(' { NULL, NULL, 0, NULL }\n') + + self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n') + self.fp.write(''.join(functions)) + self.fp.write('};\n\n') + +class GObjectWrapper(Wrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->obj) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + '%(aftercreate)s' + ' pygobject_register_wrapper((PyObject *)self);\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)): + Wrapper.__init__(self, parser, objinfo, overrides, fp) + if self.objinfo: + self.castmacro = self.objinfo.typecode.replace( + '_TYPE_', '_', 1) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGObject', + 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)', + 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' } + + def get_field_accessor(self, fieldname): + castmacro = self.objinfo.typecode.replace('_TYPE_', '_', 1) + return '%s(pygobject_get(self))->%s' % (castmacro, fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict(self, + constructor) + if not constructor.caller_owns_return: + substdict['aftercreate'] = " g_object_ref(self->obj);\n" + else: + substdict['aftercreate'] = '' + return substdict + + def get_initial_method_substdict(self, method): + substdict = Wrapper.get_initial_method_substdict(self, method) + substdict['cast'] = self.objinfo.typecode.replace( + '_TYPE_', '_', 1) + return substdict + + def write_default_constructor(self): + try: + parent = self.parser.find_object(self.objinfo.parent) + except ValueError: + parent = None + if parent is not None: + ## just like the constructor is inheritted, we should + # inherit the new API compatibility flag + self.objinfo.has_new_constructor_api = ( + parent.has_new_constructor_api) + elif self.objinfo.parent == 'GObject': + self.objinfo.has_new_constructor_api = True + return '0' + + def write_property_based_constructor(self, constructor): + self.objinfo.has_new_constructor_api = True + out = self.fp + out.write("static int\n") + out.write('_wrap_%s(PyGObject *self, PyObject *args,' \ + ' PyObject *kwargs)\n{\n\n' % constructor.c_name) + if constructor.params: + s = " GType obj_type = pyg_type_from_object((PyObject *) self);\n" + out.write(s) + + def py_str_list_to_c(arg): + if arg: + return "{" + ", ".join( + map(lambda s: '"' + s + '"', arg)) + ", NULL }" + else: + return "{ NULL }" + + classname = '%s.%s' % (self.overrides.modulename, + self.objinfo.name) + + if constructor.params: + mandatory_arguments = [param for param in constructor.params + if not param.optional] + optional_arguments = [param for param in constructor.params + if param.optional] + arg_names = py_str_list_to_c( + [param.argname + for param in mandatory_arguments + optional_arguments]) + + prop_names = py_str_list_to_c( + [param.pname + for param in mandatory_arguments + optional_arguments]) + + out.write(" GParameter params[%i];\n" % \ + len(constructor.params)) + out.write(" PyObject *parsed_args[%i] = {NULL, };\n" % \ + len(constructor.params)) + out.write(" char *arg_names[] = %s;\n" % arg_names) + out.write(" char *prop_names[] = %s;\n" % prop_names) + out.write(" guint nparams, i;\n\n") + if constructor.deprecated is not None: + out.write( + ' if (PyErr_Warn(PyExc_DeprecationWarning, ' + '"%s") < 0)\n' % + constructor.deprecated) + out.write(' return -1;\n\n') + out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, \n") + template = '"' + if mandatory_arguments: + template += "O"*len(mandatory_arguments) + if optional_arguments: + template += "|" + "O"*len(optional_arguments) + template += ':%s.__init__"' % classname + out.write(template + " , arg_names") + for i in range(len(constructor.params)): + out.write(", &parsed_args[%i]" % i) + + out.write( + "))\n" + " return -1;\n" + "\n" + " memset(params, 0, sizeof(GParameter)*%i);\n" + " if (!pyg_parse_constructor_args(obj_type, arg_names,\n" + " prop_names, params, \n" + " &nparams, parsed_args))\n" + " return -1;\n" + " pygobject_constructv(self, nparams, params);\n" + " for (i = 0; i < nparams; ++i)\n" + " g_value_unset(¶ms[i].value);\n\n" + % len(constructor.params)) + else: + out.write( + " static char* kwlist[] = { NULL };\n" + "\n") + + if constructor.deprecated is not None: + out.write( + ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n' + ' return -1;\n' + '\n' % constructor.deprecated) + + out.write( + ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n' + ' ":%s.__init__",\n' + ' kwlist))\n' + ' return -1;\n' + '\n' + ' pygobject_constructv(self, 0, NULL);\n' % classname) + out.write( + ' if (!self->obj) {\n' + ' PyErr_SetString(\n' + ' PyExc_RuntimeError, \n' + ' "could not create %s object");\n' + ' return -1;\n' + ' }\n' % classname) + + if not constructor.caller_owns_return: + out.write(" g_object_ref(self->obj);\n\n") + + out.write( + ' return 0;\n' + '}\n\n') + + return "_wrap_%s" % constructor.c_name + + +class GInterfaceWrapper(GObjectWrapper): + virtual_accessor_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n' + '{\n' + ' %(vtable)s *iface;\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' iface = g_type_interface_peek(' + 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n' + ' if (iface->%(virtual)s)\n' + ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n' + ' else {\n' + ' PyErr_SetString(PyExc_NotImplementedError, ' + '"interface method %(name)s not implemented");\n' + ' return NULL;\n' + ' }\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyObject', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0'} + + def write_constructor(self): + # interfaces have no constructors ... + return '0' + def write_getsets(self): + # interfaces have no fields ... + return '0' + + def _get_class_virtual_substdict(self, meth, cname, parent): + substdict = self.get_initial_method_substdict(meth) + substdict['virtual'] = meth.name + substdict['cname'] = cname + substdict['typecode'] = self.objinfo.typecode + substdict['vtable'] = self.objinfo.vtable + return substdict + + def write_virtuals(self): + ## Now write reverse method wrappers, which let python code + ## implement interface methods. + # First, get methods from the defs files + klass = self.objinfo.c_name + proxies = [] + for meth in self.parser.find_virtuals(self.objinfo): + method_name = self.objinfo.c_name + "__proxy_do_" + meth.name + if self.overrides.is_ignored(method_name): + continue + try: + if self.overrides.is_overriden(method_name): + if not self.overrides.is_already_included(method_name): + data = self.overrides.override(method_name) + self.write_function(method_name, data) + else: + # write proxy ... + ret, props = argtypes.matcher.get_reverse_ret(meth.ret) + wrapper = reversewrapper.ReverseWrapper( + '_wrap_' + method_name, is_static=True) + wrapper.set_return_type(ret(wrapper, **props)) + wrapper.add_parameter(reversewrapper.PyGObjectMethodParam( + wrapper, "self", method_name="do_" + meth.name, + c_type=(klass + ' *'))) + for param in meth.params: + handler, props = argtypes.matcher.get_reverse( + param.ptype) + props["direction"] = param.pdir + wrapper.add_parameter( + handler(wrapper, param.pname, **props)) + buf = reversewrapper.MemoryCodeSink() + wrapper.generate(buf) + self.fp.write(buf.flush()) + proxies.append((fixname(meth.name), '_wrap_' + method_name)) + iproxies_coverage.declare_wrapped() + except argtypes.ArgTypeError: + ex = sys.exc_info()[1] + iproxies_coverage.declare_not_wrapped() + proxies.append((fixname(meth.name), None)) + sys.stderr.write('Could not write interface proxy %s.%s: %s\n' + % (klass, meth.name, str(ex))) + + if not proxies or not [cname for name, cname in proxies if cname]: + return + + ## Write an interface init function for this object + funcname = "__%s__interface_init" % klass + vtable = self.objinfo.vtable + self.fp.write( + '\nstatic void\n' + '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n' + '{\n' + ' %(vtable)s *parent_iface = ' + 'g_type_interface_peek_parent(iface);\n' + ' PyObject *py_method;\n' + '\n' + % vars()) + + for name, cname in proxies: + do_name = 'do_' + name + if cname is None: + continue + + self.fp.write(( + ' py_method = pytype? PyObject_GetAttrString(' + '(PyObject *) pytype, "%(do_name)s") : NULL;\n' + ' if (py_method && !PyObject_TypeCheck(py_method, ' + '&PyCFunction_Type)) {\n' + ' iface->%(name)s = %(cname)s;\n' + ' } else {\n' + ' PyErr_Clear();\n' + ' if (parent_iface) {\n' + ' iface->%(name)s = parent_iface->%(name)s;\n' + ' }\n' + ' Py_XDECREF(py_method);\n' + ' }\n' + ) % vars()) + self.fp.write('}\n\n') + interface_info = "__%s__iinfo" % klass + self.fp.write(''' +static const GInterfaceInfo %s = { + (GInterfaceInitFunc) %s, + NULL, + NULL +}; +''' % (interface_info, funcname)) + self.objinfo.interface_info = interface_info + +class GBoxedWrapper(Wrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->gtype = %(typecode)s;\n' + ' self->free_on_dealloc = FALSE;\n' + ' self->boxed = %(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->boxed) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + ' self->free_on_dealloc = TRUE;\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(begin_allow_threads)s\n' + ' %(setreturn)s%(cname)s(pyg_boxed_get(self, ' + '%(typename)s)%(arglist)s);\n' + ' %(end_allow_threads)s\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGBoxed', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0' } + + def get_field_accessor(self, fieldname): + return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict( + self, constructor) + substdict['typecode'] = self.objinfo.typecode + return substdict + +class GPointerWrapper(GBoxedWrapper): + constructor_tmpl = ( + 'static int\n' + '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' self->gtype = %(typecode)s;\n' + ' self->pointer = %(cname)s(%(arglist)s);\n' + '%(codeafter)s\n' + ' if (!self->pointer) {\n' + ' PyErr_SetString(PyExc_RuntimeError, ' + '"could not create %(typename)s object");\n' + ' return -1;\n' + ' }\n' + ' return 0;\n' + '}\n\n' + ) + + method_tmpl = ( + 'static PyObject *\n' + '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n' + '{\n' + '%(varlist)s' + '%(parseargs)s' + '%(codebefore)s' + ' %(setreturn)s%(cname)s(pyg_pointer_get(self, ' + '%(typename)s)%(arglist)s);\n' + '%(codeafter)s\n' + '}\n\n' + ) + + def get_initial_class_substdict(self): + return { 'tp_basicsize' : 'PyGPointer', + 'tp_weaklistoffset' : '0', + 'tp_dictoffset' : '0' } + + def get_field_accessor(self, fieldname): + return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name, + fieldname) + + def get_initial_constructor_substdict(self, constructor): + substdict = Wrapper.get_initial_constructor_substdict( + self, constructor) + substdict['typecode'] = self.objinfo.typecode + return substdict + +class SourceWriter: + def __init__(self, parser, overrides, prefix, fp=FileOutput(sys.stdout)): + self.parser = parser + self.overrides = overrides + self.prefix = prefix + self.fp = fp + + def write(self, py_ssize_t_clean=False): + argtypes.py_ssize_t_clean = py_ssize_t_clean + + self.write_headers(py_ssize_t_clean) + self.write_imports() + self.write_type_declarations() + self.write_body() + self.write_classes() + + wrapper = Wrapper(self.parser, None, self.overrides, self.fp) + wrapper.write_functions(self, self.prefix) + + if not self.overrides.dynamicnamespace: + self.write_enums() + self.write_extension_init() + self.write_registers() + + argtypes.py_ssize_t_clean = False + + def write_headers(self, py_ssize_t_clean): + self.fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */') + self.fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n') + if py_ssize_t_clean: + self.fp.write('#define PY_SSIZE_T_CLEAN\n') + self.fp.write('#include <Python.h>\n\n\n') + if py_ssize_t_clean: + self.fp.write(''' + +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +typedef inquiry lenfunc; +typedef intargfunc ssizeargfunc; +typedef intobjargproc ssizeobjargproc; +#endif + +''') + self.fp.write(self.overrides.get_headers()) + self.fp.resetline() + self.fp.write('\n\n') + + def write_imports(self): + self.fp.write('/* ---------- types from other modules ---------- */\n') + for module, pyname, cname, importing_for in self.overrides.get_imports(): + if importing_for is None or is_registered_object(importing_for): + self.fp.write('static PyTypeObject *_%s;\n' % cname) + self.fp.write('#define %s (*_%s)\n' % (cname, cname)) + self.fp.write('\n\n') + + def write_type_declarations(self): + #todo use 'static' if used only in one file + self.fp.write('/* ---------- forward type declarations ---------- */\n') + for obj in self.parser.boxes: + if not self.overrides.is_type_ignored(obj.c_name): + self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') + for obj in self.parser.objects: + if not self.overrides.is_type_ignored(obj.c_name): + self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n') + for interface in self.parser.interfaces: + if not self.overrides.is_type_ignored(interface.c_name): + self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + interface.c_name + '_Type;\n') + self.fp.write('\n') + + def write_body(self): + self.fp.write(self.overrides.get_body()) + self.fp.resetline() + self.fp.write('\n\n') + + def _sort_parent_children(self, objects): + objects = list(objects) + modified = True + while modified: + modified = False + parent_index = None + child_index = None + for i, obj in enumerate(objects): + if obj.parent == 'GObject': + continue + if obj.parent not in [info.c_name for info in objects[:i]]: + for j, info in enumerate(objects[i+1:]): + if info.c_name == obj.parent: + parent_index = i + 1 + j + child_index = i + break + else: + continue + break + if child_index is not None and parent_index is not None: + if child_index != parent_index: + objects.insert(child_index, objects.pop(parent_index)) + modified = True + return objects + + def write_classes(self): + ## Sort the objects, so that we generate code for the parent types + ## before their children. + objects = self._sort_parent_children(self.parser.objects) + + for klass, items in ((GBoxedWrapper, self.parser.boxes), + (GPointerWrapper, self.parser.pointers), + (GObjectWrapper, objects), + (GInterfaceWrapper, self.parser.interfaces)): + for item in items: + instance = klass(self.parser, item, self.overrides, self.fp) + instance.write_class() + self.fp.write('\n') + + def get_enums(self): + enums = [] + for enum in self.parser.enums: + if self.overrides.is_type_ignored(enum.c_name): + continue + enums.append(enum) + return enums + + def write_enums(self): + if not self.parser.enums: + return + + self.fp.write('\n/* ----------- enums and flags ----------- */\n\n') + self.fp.write( + 'void\n' + self.prefix + + '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n') + + self.fp.write( + '#ifdef VERSION\n' + ' PyModule_AddStringConstant(module, "__version__", VERSION);\n' + '#endif\n') + + for enum in self.get_enums(): + if enum.typecode is None: + for nick, value in enum.values: + self.fp.write( + ' PyModule_AddIntConstant(module, ' + '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n' + % (value, value)) + else: + if enum.deftype == 'enum': + self.fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n' + % (enum.name, enum.typecode)) + else: + self.fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n' + % (enum.name, enum.typecode)) + + self.fp.write('\n') + self.fp.write(' if (PyErr_Occurred())\n') + self.fp.write(' PyErr_Print();\n') + self.fp.write('}\n\n') + + def write_object_imports(self, retval=''): + imports = self.overrides.get_imports()[:] + if not imports: + return + + bymod = {} + for module, pyname, cname, importing_for in imports: + if importing_for is None or is_registered_object(importing_for): + bymod.setdefault(module, []).append((pyname, cname)) + self.fp.write(' PyObject *module;\n\n') + for module in bymod: + self.fp.write( + ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n' + % module) + #self.fp.write( + # ' PyObject *moddict = PyModule_GetDict(module);\n\n') + for pyname, cname in bymod[module]: + #self.fp.write( + # ' _%s = (PyTypeObject *)PyDict_GetItemString(' + # 'moddict, "%s");\n' % (cname, pyname)) + self.fp.write( + ' _%s = (PyTypeObject *)PyObject_GetAttrString(' + 'module, "%s");\n' % (cname, pyname)) + self.fp.write(' if (_%s == NULL) {\n' % cname) + self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') + self.fp.write(' "cannot import name %s from %s");\n' + % (pyname, module)) + self.fp.write(' return %s;\n' % retval) + self.fp.write(' }\n') + self.fp.write(' } else {\n') + self.fp.write(' PyErr_SetString(PyExc_ImportError,\n') + self.fp.write(' "could not import %s");\n' % module) + self.fp.write(' return %s;\n' % retval) + self.fp.write(' }\n') + self.fp.write('\n') + + def write_extension_init(self): + self.fp.write('/* initialise stuff extension classes */\n') + self.fp.write('void\n' + self.prefix + '_register_classes(PyObject *d)\n{\n') + self.write_object_imports() + self.fp.write(self.overrides.get_init() + '\n') + self.fp.resetline() + + def get_classes(self): + objects = self.parser.objects[:] + pos = 0 + while pos < len(objects): + parent = objects[pos].parent + for i in range(pos+1, len(objects)): + if objects[i].c_name == parent: + objects.insert(i+1, objects[pos]) + del objects[pos] + break + else: + pos = pos + 1 + + retval = [] + for obj in objects: + if self.overrides.is_type_ignored(obj.c_name): + continue + bases = [] + if obj.parent != None: + bases.append(obj.parent) + bases = bases + obj.implements + retval.append((obj, bases)) + + return retval + + def write_registers(self): + for boxed in self.parser.boxes: + if not self.overrides.is_type_ignored(boxed.c_name): + self.fp.write(' pyg_register_boxed(d, "' + boxed.name + + '", ' + boxed.typecode + + ', &Py' + boxed.c_name + + '_Type);\n') + for pointer in self.parser.pointers: + if not self.overrides.is_type_ignored(pointer.c_name): + self.fp.write(' pyg_register_pointer(d, "' + pointer.name + + '", ' + pointer.typecode + + ', &Py' + pointer.c_name + '_Type);\n') + for interface in self.parser.interfaces: + if not self.overrides.is_type_ignored(interface.c_name): + self.fp.write(' pyg_register_interface(d, "' + + interface.name + '", '+ interface.typecode + + ', &Py' + interface.c_name + '_Type);\n') + if interface.interface_info is not None: + self.fp.write(' pyg_register_interface_info(%s, &%s);\n' % + (interface.typecode, interface.interface_info)) + + if not self.overrides.dynamicnamespace: + for obj, bases in self.get_classes(): + self.write_class(obj, bases) + else: + for obj, bases in self.get_classes(): + self.fp.write( + ' pyg_type_register_custom_callback("%s", ' + '(PyGTypeRegistrationFunction)%s_register_type, d);\n' % + (obj.c_name, obj.c_name)) + + self.fp.write('}\n') + + def _can_direct_ref(self, base): + if not self.overrides.dynamicnamespace: + return True + if base == 'GObject': + return True + obj = get_object_by_name(base) + if obj.module.lower() != self.overrides.modulename: + return True + return False + + def write_class(self, obj, bases, indent=1): + indent_str = ' ' * (indent * 4) + if bases: + bases_str = 'Py_BuildValue("(%s)"' % (len(bases) * 'O') + + for base in bases: + if self._can_direct_ref(base): + bases_str += ', &Py%s_Type' % base + else: + baseobj = get_object_by_name(base) + bases_str += ', PyObject_GetAttrString(m, "%s")' % baseobj.name + bases_str += ')' + else: + bases_str = 'NULL' + + self.fp.write( + '%(indent)spygobject_register_class(d, "%(c_name)s", %(typecode)s, &Py%(c_name)s_Type, %(bases)s);\n' + % dict(indent=indent_str, c_name=obj.c_name, typecode=obj.typecode, bases=bases_str)) + + if obj.has_new_constructor_api: + self.fp.write( + indent_str + 'pyg_set_object_has_new_constructor(%s);\n' % + obj.typecode) + else: + sys.stderr.write( + "Warning: Constructor for %s needs to be updated to new API\n" + " See http://live.gnome.org/PyGTK_2fWhatsNew28" + "#update-constructors\n" % obj.c_name) + + if obj.class_init_func is not None: + self.fp.write( + indent_str + 'pyg_register_class_init(%s, %s);\n' % + (obj.typecode, obj.class_init_func)) + +_objects = {} + +def is_registered_object(c_name): + return c_name in _objects + +def get_object_by_name(c_name): + global _objects + return _objects[c_name] + +def register_types(parser): + global _objects + for boxed in parser.boxes: + argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode) + _objects[boxed.c_name] = boxed + for pointer in parser.pointers: + argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode) + for obj in parser.objects: + argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode) + _objects[obj.c_name] = obj + for iface in parser.interfaces: + argtypes.matcher.register_object(iface.c_name, None, iface.typecode) + _objects[iface.c_name] = iface + for enum in parser.enums: + if enum.deftype == 'flags': + argtypes.matcher.register_flag(enum.c_name, enum.typecode) + else: + argtypes.matcher.register_enum(enum.c_name, enum.typecode) + +usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile' +def main(argv): + o = override.Overrides() + prefix = 'pygtk' + outfilename = None + errorfilename = None + opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:I:", + ["override=", "prefix=", "register=", "outfilename=", + "load-types=", "errorfilename=", "py_ssize_t-clean"]) + defines = {} # -Dkey[=val] options + py_ssize_t_clean = False + for opt, arg in opts: + if opt in ('-o', '--override'): + o = override.Overrides(arg) + elif opt in ('-p', '--prefix'): + prefix = arg + elif opt in ('-r', '--register'): + # Warning: user has to make sure all -D options appear before -r + p = defsparser.DefsParser(arg, defines) + p.startParsing() + register_types(p) + del p + elif opt == '--outfilename': + outfilename = arg + elif opt == '--errorfilename': + errorfilename = arg + elif opt in ('-t', '--load-types'): + globals = {} + execfile(arg, globals) + elif opt == '-D': + nameval = arg.split('=') + try: + defines[nameval[0]] = nameval[1] + except IndexError: + defines[nameval[0]] = None + elif opt == '-I': + defsparser.include_path.insert(0, arg) + elif opt == '--py_ssize_t-clean': + py_ssize_t_clean = True + if len(args) < 1: + print >> sys.stderr, usage + return 1 + if errorfilename: + sys.stderr = open(errorfilename, "w") + p = defsparser.DefsParser(args[0], defines) + if not outfilename: + outfilename = os.path.splitext(args[0])[0] + '.c' + + p.startParsing() + + register_types(p) + sw = SourceWriter(p, o, prefix, FileOutput(sys.stdout, outfilename)) + sw.write(py_ssize_t_clean) + + functions_coverage.printstats() + methods_coverage.printstats() + vproxies_coverage.printstats() + vaccessors_coverage.printstats() + iproxies_coverage.printstats() + diff --git a/codegen/definitions.py b/codegen/libcodegen/definitions.py index aca5adb..bab0ecb 100644 --- a/codegen/definitions.py +++ b/codegen/libcodegen/definitions.py @@ -71,15 +71,15 @@ class Definition(object): def __init__(self, *args): """Create a new defs object of this type. The arguments are the components of the definition""" - raise RuntimeError, "this is an abstract class" + raise RuntimeError("this is an abstract class") def merge(self, old): """Merge in customisations from older version of definition""" - raise RuntimeError, "this is an abstract class" + raise RuntimeError("this is an abstract class") def write_defs(self, fp=sys.stdout): """write out this definition in defs file format""" - raise RuntimeError, "this is an abstract class" + raise RuntimeError("this is an abstract class") def guess_return_value_ownership(self): "return 1 if caller owns return value" @@ -210,7 +210,7 @@ class EnumDef(Definition): class FlagsDef(EnumDef): def __init__(self, *args): - apply(EnumDef.__init__, (self,) + args) + EnumDef.__init__(self, *args) self.deftype = 'flags' class BoxedDef(Definition): @@ -407,7 +407,7 @@ class MethodDef(MethodDefBase): for item in ('c_name', 'of_object'): if self.__dict__[item] == None: self.write_defs(sys.stderr) - raise RuntimeError, "definition missing required %s" % (item,) + raise RuntimeError("definition missing required %s" % (item,)) def write_defs(self, fp=sys.stdout): fp.write('(define-method ' + self.name + '\n') @@ -491,7 +491,7 @@ class FunctionDef(Definition): for item in ('c_name',): if self.__dict__[item] == None: self.write_defs(sys.stderr) - raise RuntimeError, "definition missing required %s" % (item,) + raise RuntimeError("definition missing required %s" % (item,)) _method_write_defs = MethodDef.__dict__['write_defs'] @@ -513,8 +513,8 @@ class FunctionDef(Definition): else: param.merge(old_param) return param - raise RuntimeError, "could not find %s in old_parameters %r" % ( - param.pname, [p.pname for p in old.params]) + raise RuntimeError("could not find %s in old_parameters %r" % ( + param.pname, [p.pname for p in old.params])) try: self.params = map(merge_param, self.params) except RuntimeError: diff --git a/codegen/libcodegen/defsparser.py b/codegen/libcodegen/defsparser.py new file mode 100644 index 0000000..b901f31 --- /dev/null +++ b/codegen/libcodegen/defsparser.py @@ -0,0 +1,153 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +import os, sys +from . import scmexpr +from .definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \ + InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef + +include_path = ['.'] + +class IncludeParser(scmexpr.Parser): + """A simple parser that follows include statements automatically""" + def include(self, input_filename): + global include_path + if os.path.isabs(input_filename): + filename = input_filename + # set self.filename to the include name, to handle recursive includes + oldfile = self.filename + self.filename = filename + self.startParsing() + self.filename = oldfile + else: + inc_path = [os.path.dirname(self.filename)] + include_path + for filename in [os.path.join(path_entry, input_filename) + for path_entry in inc_path]: + if not os.path.exists(filename): + continue + # set self.filename to the include name, to handle recursive includes + oldfile = self.filename + self.filename = filename + self.startParsing() + self.filename = oldfile + break + else: + raise IOError("%s not found in include path %s" % (input_filename, inc_path)) + +class DefsParser(IncludeParser): + def __init__(self, arg, defines={}): + IncludeParser.__init__(self, arg) + self.objects = [] + self.interfaces = [] + self.enums = [] # enums and flags + self.boxes = [] # boxed types + self.pointers = [] # pointer types + self.functions = [] # functions and methods + self.virtuals = [] # virtual methods + self.c_name = {} # hash of c names of functions + self.methods = {} # hash of methods of particular objects + self.defines = defines # -Dfoo=bar options, as dictionary + + def define_object(self, *args): + odef = ObjectDef(*args) + self.objects.append(odef) + self.c_name[odef.c_name] = odef + def define_interface(self, *args): + idef = InterfaceDef(*args) + self.interfaces.append(idef) + self.c_name[idef.c_name] = idef + def define_enum(self, *args): + edef = EnumDef(*args) + self.enums.append(edef) + self.c_name[edef.c_name] = edef + def define_flags(self, *args): + fdef = FlagsDef(*args) + self.enums.append(fdef) + self.c_name[fdef.c_name] = fdef + def define_boxed(self, *args): + bdef = BoxedDef(*args) + self.boxes.append(bdef) + self.c_name[bdef.c_name] = bdef + def define_pointer(self, *args): + pdef = PointerDef(*args) + self.pointers.append(pdef) + self.c_name[pdef.c_name] = pdef + def define_function(self, *args): + fdef = FunctionDef(*args) + self.functions.append(fdef) + self.c_name[fdef.c_name] = fdef + def define_method(self, *args): + mdef = MethodDef(*args) + self.functions.append(mdef) + self.c_name[mdef.c_name] = mdef + def define_virtual(self, *args): + vdef = VirtualDef(*args) + self.virtuals.append(vdef) + def merge(self, old, parmerge): + for obj in self.objects: + if obj.c_name in old.c_name: + obj.merge(old.c_name[obj.c_name]) + for f in self.functions: + if f.c_name in old.c_name: + f.merge(old.c_name[f.c_name], parmerge) + + def printMissing(self, old): + for obj in self.objects: + if obj.c_name not in old.c_name: + obj.write_defs() + for f in self.functions: + if f.c_name not in old.c_name: + f.write_defs() + + def write_defs(self, fp=sys.stdout): + for obj in self.objects: + obj.write_defs(fp) + for enum in self.enums: + enum.write_defs(fp) + for boxed in self.boxes: + boxed.write_defs(fp) + for pointer in self.pointers: + pointer.write_defs(fp) + for func in self.functions: + func.write_defs(fp) + + def find_object(self, c_name): + for obj in self.objects: + if obj.c_name == c_name: + return obj + else: + raise ValueError('object %r not found' % c_name) + + def find_constructor(self, obj, overrides): + for func in self.functions: + if isinstance(func, FunctionDef) and \ + func.is_constructor_of == obj.c_name and \ + not overrides.is_ignored(func.c_name): + return func + + def find_methods(self, obj): + objname = obj.c_name + return filter(lambda func, on=objname: isinstance(func, MethodDef) and + func.of_object == on, self.functions) + + def find_virtuals(self, obj): + objname = obj.c_name + retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and + func.of_object == on, self.virtuals) + return retval + + def find_functions(self): + return filter(lambda func: isinstance(func, FunctionDef) and + not func.is_constructor_of, self.functions) + + def ifdef(self, *args): + if args[0] in self.defines: + for arg in args[1:]: + #print >> sys.stderr, "-----> Handling conditional definition (%s): %s" % (args[0], arg) + self.handle(arg) + else: + pass + #print >> sys.stderr, "-----> Conditional %s is not true" % (args[0],) + + def ifndef(self, *args): + if args[0] not in self.defines: + for arg in args[1:]: + self.handle(arg) diff --git a/codegen/libcodegen/docextract.py b/codegen/libcodegen/docextract.py new file mode 100644 index 0000000..027afbc --- /dev/null +++ b/codegen/libcodegen/docextract.py @@ -0,0 +1,185 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +'''Simple module for extracting GNOME style doc comments from C +sources, so I can use them for other purposes.''' + +import sys, os, string, re + +__all__ = ['extract'] + +class FunctionDoc: + def __init__(self): + self.name = None + self.params = [] + self.description = '' + self.ret = '' + def set_name(self, name): + self.name = name + def add_param(self, name, description): + if name == '...': + name = 'Varargs' + self.params.append((name, description)) + def append_to_last_param(self, extra): + self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra) + def append_to_named_param(self, name, extra): + for i in range(len(self.params)): + if self.params[i][0] == name: + self.params[i] = (name, self.params[i][1] + extra) + return + # fall through to adding extra parameter ... + self.add_param(name, extra) + def append_description(self, extra): + self.description = self.description + extra + def append_return(self, extra): + self.ret = self.ret + extra + + def get_param_description(self, name): + for param, description in self.params: + if param == name: + return description + else: + return '' + +comment_start_pat = re.compile(r'^\s*/\*\*\s') +comment_end_pat = re.compile(r'^\s*\*+/') +comment_line_lead = re.compile(r'^\s*\*\s*') +funcname_pat = re.compile(r'^(\w+)\s*:?') +return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$', + re.IGNORECASE) +param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$') + +def parse_file(fp, doc_dict): + line = fp.readline() + in_comment_block = 0 + while line: + if not in_comment_block: + if comment_start_pat.match(line): + in_comment_block = 1 + cur_doc = FunctionDoc() + in_description = 0 + in_return = 0 + line = fp.readline() + continue + + # we are inside a comment block ... + if comment_end_pat.match(line): + if not cur_doc.name: + sys.stderr.write("no function name found in doc comment\n") + else: + doc_dict[cur_doc.name] = cur_doc + in_comment_block = 0 + line = fp.readline() + continue + + # inside a comment block, and not the end of the block ... + line = comment_line_lead.sub('', line) + if not line: line = '\n' + + if not cur_doc.name: + match = funcname_pat.match(line) + if match: + cur_doc.set_name(match.group(1)) + elif in_return: + match = return_pat.match(line) + if match: + # assume the last return statement was really part of the + # description + return_start = match.group(1) + cur_doc.ret = match.group(2) + cur_doc.description = cur_doc.description + return_start + \ + cur_doc.ret + else: + cur_doc.append_return(line) + elif in_description: + if line[:12] == 'Description:': + line = line[12:] + match = return_pat.match(line) + if match: + in_return = 1 + return_start = match.group(1) + cur_doc.append_return(match.group(2)) + else: + cur_doc.append_description(line) + elif line == '\n': + # end of parameters + in_description = 1 + else: + match = param_pat.match(line) + if match: + param = match.group(1) + desc = match.group(2) + if param == 'returns': + cur_doc.ret = desc + else: + cur_doc.add_param(param, desc) + else: + # must be continuation + try: + if param == 'returns': + cur_doc.append_return(line) + else: + cur_doc.append_to_last_param(line) + except: + sys.stderr.write('something weird while reading param\n') + line = fp.readline() + +def parse_dir(dir, doc_dict): + for file in os.listdir(dir): + if file in ('.', '..'): continue + path = os.path.join(dir, file) + if os.path.isdir(path): + parse_dir(path, doc_dict) + if len(file) > 2 and file[-2:] == '.c': + parse_file(open(path, 'r'), doc_dict) + +def extract(dirs, doc_dict=None): + if not doc_dict: doc_dict = {} + for dir in dirs: + parse_dir(dir, doc_dict) + return doc_dict + +tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$') +def parse_tmpl(fp, doc_dict): + cur_doc = None + + line = fp.readline() + while line: + match = tmpl_section_pat.match(line) + if match: + cur_doc = None # new input shouldn't affect the old doc dict + sect_type = match.group(1) + sect_name = match.group(2) + + if sect_type == 'FUNCTION': + cur_doc = doc_dict.get(sect_name) + if not cur_doc: + cur_doc = FunctionDoc() + cur_doc.set_name(sect_name) + doc_dict[sect_name] = cur_doc + elif line == '<!-- # Unused Parameters # -->\n': + cur_doc = None # don't worry about unused params. + elif cur_doc: + if line[:10] == '@Returns: ': + if line[10:].strip(): + cur_doc.append_return(line[10:]) + elif line[0] == '@': + pos = line.find(':') + if pos >= 0: + cur_doc.append_to_named_param(line[1:pos], line[pos+1:]) + else: + cur_doc.append_description(line) + else: + cur_doc.append_description(line) + + line = fp.readline() + +def extract_tmpl(dirs, doc_dict=None): + if not doc_dict: doc_dict = {} + for dir in dirs: + for file in os.listdir(dir): + if file in ('.', '..'): continue + path = os.path.join(dir, file) + if os.path.isdir(path): + continue + if len(file) > 2 and file[-2:] == '.sgml': + parse_tmpl(open(path, 'r'), doc_dict) + return doc_dict diff --git a/codegen/libcodegen/override.py b/codegen/libcodegen/override.py new file mode 100644 index 0000000..5caa893 --- /dev/null +++ b/codegen/libcodegen/override.py @@ -0,0 +1,285 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- + +# this file contains code for loading up an override file. The override file +# provides implementations of functions where the code generator could not +# do its job correctly. + +import fnmatch +import os +import re +import string +import sys + +def class2cname(klass, method): + c_name = '' + for c in klass: + if c.isupper(): + c_name += '_' + c.lower() + else: + c_name += c + return c_name[1:] + '_' + method + +# import python_type as c_name [for arg_type] +# Last ('for') clause is optional. If present, the type will be +# imported only if given 'arg_type' is registered. +import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)(\s+for\s+(\S+))?') + +class Overrides: + def __init__(self, filename=None): + self.modulename = None + self.ignores = {} + self.glob_ignores = [] + self.type_ignores = {} + self.overrides = {} + self.overridden = {} + self.kwargs = {} + self.noargs = {} + self.onearg = {} + self.staticmethod = {} + self.classmethod = {} + self.startlines = {} + self.override_attrs = {} + self.override_slots = {} + self.headers = '' + self.body = '' + self.init = '' + self.imports = [] + self.defines = {} + self.functions = {} + self.newstyle_constructors = {} + self.dynamicnamespace = False + if filename: + self.handle_file(filename) + + def handle_file(self, filename): + oldpath = os.getcwd() + + fp = open(filename, 'r') + dirname = os.path.dirname(os.path.abspath(filename)) + + if dirname != oldpath: + os.chdir(dirname) + + # read all the components of the file ... + bufs = [] + startline = 1 + lines = [] + line = fp.readline() + linenum = 1 + while line: + if line == '%%\n' or line == '%%': + if lines: + bufs.append((''.join(lines), startline)) + startline = linenum + 1 + lines = [] + else: + lines.append(line) + line = fp.readline() + linenum = linenum + 1 + if lines: + bufs.append((''.join(lines), startline)) + if not bufs: return + + for buf, startline in bufs: + self.__parse_override(buf, startline, filename) + + os.chdir(oldpath) + + def __parse_override(self, buffer, startline, filename): + pos = buffer.find('\n') + if pos >= 0: + line = buffer[:pos] + rest = buffer[pos+1:] + else: + line = buffer ; rest = '' + words = line.split() + command = words[0] + if (command == 'ignore' or + command == 'ignore-' + sys.platform): + "ignore/ignore-platform [functions..]" + for func in words[1:]: + self.ignores[func] = 1 + for func in rest.split(): + self.ignores[func] = 1 + elif (command == 'ignore-glob' or + command == 'ignore-glob-' + sys.platform): + "ignore-glob/ignore-glob-platform [globs..]" + for func in words[1:]: + self.glob_ignores.append(func) + for func in rest.split(): + self.glob_ignores.append(func) + elif (command == 'ignore-type' or + command == 'ignore-type-' + sys.platform): + "ignore-type/ignore-type-platform [typenames..]" + for typename in words[1:]: + self.type_ignores[typename] = 1 + for typename in rest.split(): + self.type_ignores[typename] = 1 + elif command == 'override': + "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]" + func = words[1] + if 'kwargs' in words[1:]: + self.kwargs[func] = 1 + elif 'noargs' in words[1:]: + self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = True + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True + if func in self.overrides: + raise RuntimeError("Function %s is being overridden more than once" % (func,)) + self.overrides[func] = rest + self.startlines[func] = (startline + 1, filename) + elif command == 'override-attr': + "override-slot Class.attr" + attr = words[1] + self.override_attrs[attr] = rest + self.startlines[attr] = (startline + 1, filename) + elif command == 'override-slot': + "override-slot Class.slot" + slot = words[1] + self.override_slots[slot] = rest + self.startlines[slot] = (startline + 1, filename) + elif command == 'headers': + "headers" + self.headers = '%s\n#line %d "%s"\n%s' % \ + (self.headers, startline + 1, filename, rest) + elif command == 'body': + "body" + self.body = '%s\n#line %d "%s"\n%s' % \ + (self.body, startline + 1, filename, rest) + elif command == 'init': + "init" + self.init = '%s\n#line %d "%s"\n%s' % \ + (self.init, startline + 1, filename, rest) + elif command == 'modulename': + "modulename name" + self.modulename = words[1] + elif command == 'include': + "include filename" + for filename in words[1:]: + self.handle_file(filename) + for filename in rest.split(): + self.handle_file(filename) + elif command == 'import': + "import module1 [\n module2, \n module3 ...]" + for line in buffer.split('\n'): + match = import_pat.match(line) + if match: + module, pyname, cname, conditional, importing_for = match.groups() + self.imports.append((module, pyname, cname, importing_for or None)) + elif command == 'define': + "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]" + "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]" + func = words[1] + klass = None + if func.find('.') != -1: + klass, func = func.split('.', 1) + + if klass not in self.defines: + self.defines[klass] = {} + self.defines[klass][func] = rest + else: + self.functions[func] = rest + + if 'kwargs' in words[1:]: + self.kwargs[func] = 1 + elif 'noargs' in words[1:]: + self.noargs[func] = 1 + elif 'onearg' in words[1:]: + self.onearg[func] = 1 + + if 'staticmethod' in words[1:]: + self.staticmethod[func] = True + elif 'classmethod' in words[1:]: + self.classmethod[func] = True + + self.startlines[func] = (startline + 1, filename) + + elif command == 'new-constructor': + "new-constructor GType" + gtype, = words[1:] + self.newstyle_constructors[gtype] = True + elif command == 'options': + for option in words[1:]: + if option == 'dynamicnamespace': + self.dynamicnamespace = True + + def is_ignored(self, name): + if name in self.ignores: + return 1 + for glob in self.glob_ignores: + if fnmatch.fnmatchcase(name, glob): + return 1 + return 0 + + def is_type_ignored(self, name): + return name in self.type_ignores + + def is_overriden(self, name): + return name in self.overrides + + def is_already_included(self, name): + return name in self.overridden + + def override(self, name): + self.overridden[name] = 1 + return self.overrides[name] + + def define(self, klass, name): + self.overridden[class2cname(klass, name)] = 1 + return self.defines[klass][name] + + def function(self, name): + return self.functions[name] + + def getstartline(self, name): + return self.startlines[name] + + def wants_kwargs(self, name): + return name in self.kwargs + + def wants_noargs(self, name): + return name in self.noargs + + def wants_onearg(self, name): + return name in self.onearg + + def is_staticmethod(self, name): + return name in self.staticmethod + + def is_classmethod(self, name): + return name in self.classmethod + + def attr_is_overriden(self, attr): + return attr in self.override_attrs + + def attr_override(self, attr): + return self.override_attrs[attr] + + def slot_is_overriden(self, slot): + return slot in self.override_slots + + def slot_override(self, slot): + return self.override_slots[slot] + + def get_headers(self): + return self.headers + + def get_body(self): + return self.body + + def get_init(self): + return self.init + + def get_imports(self): + return self.imports + + def get_defines_for(self, klass): + return self.defines.get(klass, {}) + + def get_functions(self): + return self.functions diff --git a/codegen/reversewrapper.py b/codegen/libcodegen/reversewrapper.py index ed48629..27ebb2e 100644 --- a/codegen/reversewrapper.py +++ b/codegen/libcodegen/reversewrapper.py @@ -1,7 +1,7 @@ ### -*- python -*- ### Code to generate "Reverse Wrappers", i.e. C->Python wrappers ### (C) 2004 Gustavo Carneiro <gjc@gnome.org> -import argtypes +from . import argtypes import os DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ) @@ -404,13 +404,13 @@ class StringParam(Parameter): if self.props.get('optional', False): self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name) self.wrapper.write_code(code=("if (%s)\n" - " py_%s = PyString_FromString(%s);\n" + " py_%s = _PyUnicode_FromString(%s);\n" % (self.name, self.name, self.name)), cleanup=("Py_XDECREF(py_%s);" % self.name)) self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True) else: self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" % + self.wrapper.write_code(code=("py_%s = _PyUnicode_FromString(%s);" % (self.name, self.name)), cleanup=("Py_DECREF(py_%s);" % self.name), failure_expression=("!py_%s" % self.name)) @@ -526,7 +526,7 @@ class IntParam(Parameter): def convert_c2py(self): self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" % + self.wrapper.write_code(code=("py_%s = _PyLong_FromLong(%s);" % (self.name, self.name)), cleanup=("Py_DECREF(py_%s);" % self.name)) self.wrapper.add_pyargv_item("py_%s" % self.name) @@ -563,7 +563,7 @@ class IntPtrParam(Parameter): def convert_c2py(self): if self.props["direction"] == "inout": self.wrapper.add_declaration("PyObject *py_%s;" % self.name) - self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" % + self.wrapper.write_code(code=("py_%s = _PyLong_FromLong(*%s);" % (self.name, self.name)), cleanup=("Py_DECREF(py_%s);" % self.name)) self.wrapper.add_pyargv_item("py_%s" % self.name) diff --git a/codegen/libcodegen/scmexpr.py b/codegen/libcodegen/scmexpr.py new file mode 100644 index 0000000..0f38063 --- /dev/null +++ b/codegen/libcodegen/scmexpr.py @@ -0,0 +1,147 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +from __future__ import generators + +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + +try: + _unicode = unicode +except NameError: + _unicode = str + +class error(Exception): + def __init__(self, filename, lineno, msg): + Exception.__init__(self, msg) + self.filename = filename + self.lineno = lineno + self.msg = msg + def __str__(self): + return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg) + +trans = {} +for i in range(256): + c = chr(i) + if not c.isalnum() and c != '_': + trans[i] = _unicode('_') + +def parse(filename): + if isinstance(filename, str): + fp = open(filename, 'r') + else: # if not string, assume it is some kind of iterator + fp = filename + filename = getattr(fp, 'name', '<unknown>') + whitespace = ' \t\n\r\x0b\x0c' + nonsymbol = whitespace + '();\'"' + stack = [] + openlines = [] + lineno = 0 + for line in fp: + pos = 0 + lineno += 1 + while pos < len(line): + if line[pos] in whitespace: # ignore whitespace + pass + elif line[pos] == ';': # comment + break + elif line[pos:pos+2] == "'(": + pass # the open parenthesis will be handled next iteration + elif line[pos] == '(': + stack.append(()) + openlines.append(lineno) + elif line[pos] == ')': + if len(stack) == 0: + raise error(filename, lineno, 'close parenthesis found when none open') + closed = stack[-1] + del stack[-1] + del openlines[-1] + if stack: + stack[-1] += (closed,) + else: + yield closed + elif line[pos] == '"': # quoted string + if not stack: + raise error(filename, lineno, + 'string found outside of s-expression') + endpos = pos + 1 + chars = [] + while endpos < len(line): + if endpos+1 < len(line) and line[endpos] == '\\': + endpos += 1 + if line[endpos] == 'n': + chars.append('\n') + elif line[endpos] == 'r': + chars.append('\r') + elif line[endpos] == 't': + chars.append('\t') + else: + chars.append('\\') + chars.append(line[endpos]) + elif line[endpos] == '"': + break + else: + chars.append(line[endpos]) + endpos += 1 + if endpos >= len(line): + raise error(filename, lineno, "unclosed quoted string") + pos = endpos + stack[-1] += (''.join(chars),) + else: # symbol/number + if not stack: + raise error(filename, lineno, + 'identifier found outside of s-expression') + endpos = pos + while endpos < len(line) and line[endpos] not in nonsymbol: + endpos += 1 + symbol = line[pos:endpos] + pos = max(pos, endpos-1) + try: symbol = int(symbol) + except ValueError: + try: symbol = float(symbol) + except ValueError: pass + stack[-1] += (symbol,) + pos += 1 + if len(stack) != 0: + msg = '%d unclosed parentheses found at end of ' \ + 'file (opened on line(s) %s)' % (len(stack), + ', '.join(map(str, openlines))) + raise error(filename, lineno, msg) + +class Parser: + def __init__(self, filename): + """Argument is either a string, a parse tree, or file object""" + self.filename = filename + def startParsing(self, filename=None): + statements = parse(filename or self.filename) + for statement in statements: + self.handle(statement) + def handle(self, tup): + cmd = _unicode(tup[0]).translate(trans) + if hasattr(self, cmd): + getattr(self, cmd)(*tup[1:]) + else: + self.unknown(tup) + def unknown(self, tup): + pass + +_testString = """; a scheme file +(define-func gdk_font_load ; a comment at end of line + GdkFont + ((string name))) + +(define-boxed GdkEvent + gdk_event_copy + gdk_event_free + "sizeof(GdkEvent)") +""" + +if __name__ == '__main__': + import sys + if sys.argv[1:]: + fp = open(sys.argv[1]) + else: + fp = StringIO(_testString) + statements = parse(fp) + for s in statements: + sys.stdout.write(repr(s) + '\n') diff --git a/codegen/override.py b/codegen/override.py index bba5e42..71082ed 100644 --- a/codegen/override.py +++ b/codegen/override.py @@ -1,285 +1 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- - -# this file contains code for loading up an override file. The override file -# provides implementations of functions where the code generator could not -# do its job correctly. - -import fnmatch -import os -import re -import string -import sys - -def class2cname(klass, method): - c_name = '' - for c in klass: - if c.isupper(): - c_name += '_' + c.lower() - else: - c_name += c - return c_name[1:] + '_' + method - -# import python_type as c_name [for arg_type] -# Last ('for') clause is optional. If present, the type will be -# imported only if given 'arg_type' is registered. -import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)(\s+for\s+(\S+))?') - -class Overrides: - def __init__(self, filename=None): - self.modulename = None - self.ignores = {} - self.glob_ignores = [] - self.type_ignores = {} - self.overrides = {} - self.overridden = {} - self.kwargs = {} - self.noargs = {} - self.onearg = {} - self.staticmethod = {} - self.classmethod = {} - self.startlines = {} - self.override_attrs = {} - self.override_slots = {} - self.headers = '' - self.body = '' - self.init = '' - self.imports = [] - self.defines = {} - self.functions = {} - self.newstyle_constructors = {} - self.dynamicnamespace = False - if filename: - self.handle_file(filename) - - def handle_file(self, filename): - oldpath = os.getcwd() - - fp = open(filename, 'r') - dirname = os.path.dirname(os.path.abspath(filename)) - - if dirname != oldpath: - os.chdir(dirname) - - # read all the components of the file ... - bufs = [] - startline = 1 - lines = [] - line = fp.readline() - linenum = 1 - while line: - if line == '%%\n' or line == '%%': - if lines: - bufs.append((string.join(lines, ''), startline)) - startline = linenum + 1 - lines = [] - else: - lines.append(line) - line = fp.readline() - linenum = linenum + 1 - if lines: - bufs.append((string.join(lines, ''), startline)) - if not bufs: return - - for buf, startline in bufs: - self.__parse_override(buf, startline, filename) - - os.chdir(oldpath) - - def __parse_override(self, buffer, startline, filename): - pos = string.find(buffer, '\n') - if pos >= 0: - line = buffer[:pos] - rest = buffer[pos+1:] - else: - line = buffer ; rest = '' - words = string.split(line) - command = words[0] - if (command == 'ignore' or - command == 'ignore-' + sys.platform): - "ignore/ignore-platform [functions..]" - for func in words[1:]: - self.ignores[func] = 1 - for func in string.split(rest): - self.ignores[func] = 1 - elif (command == 'ignore-glob' or - command == 'ignore-glob-' + sys.platform): - "ignore-glob/ignore-glob-platform [globs..]" - for func in words[1:]: - self.glob_ignores.append(func) - for func in string.split(rest): - self.glob_ignores.append(func) - elif (command == 'ignore-type' or - command == 'ignore-type-' + sys.platform): - "ignore-type/ignore-type-platform [typenames..]" - for typename in words[1:]: - self.type_ignores[typename] = 1 - for typename in string.split(rest): - self.type_ignores[typename] = 1 - elif command == 'override': - "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]" - func = words[1] - if 'kwargs' in words[1:]: - self.kwargs[func] = 1 - elif 'noargs' in words[1:]: - self.noargs[func] = 1 - elif 'onearg' in words[1:]: - self.onearg[func] = True - - if 'staticmethod' in words[1:]: - self.staticmethod[func] = True - elif 'classmethod' in words[1:]: - self.classmethod[func] = True - if func in self.overrides: - raise RuntimeError("Function %s is being overridden more than once" % (func,)) - self.overrides[func] = rest - self.startlines[func] = (startline + 1, filename) - elif command == 'override-attr': - "override-slot Class.attr" - attr = words[1] - self.override_attrs[attr] = rest - self.startlines[attr] = (startline + 1, filename) - elif command == 'override-slot': - "override-slot Class.slot" - slot = words[1] - self.override_slots[slot] = rest - self.startlines[slot] = (startline + 1, filename) - elif command == 'headers': - "headers" - self.headers = '%s\n#line %d "%s"\n%s' % \ - (self.headers, startline + 1, filename, rest) - elif command == 'body': - "body" - self.body = '%s\n#line %d "%s"\n%s' % \ - (self.body, startline + 1, filename, rest) - elif command == 'init': - "init" - self.init = '%s\n#line %d "%s"\n%s' % \ - (self.init, startline + 1, filename, rest) - elif command == 'modulename': - "modulename name" - self.modulename = words[1] - elif command == 'include': - "include filename" - for filename in words[1:]: - self.handle_file(filename) - for filename in string.split(rest): - self.handle_file(filename) - elif command == 'import': - "import module1 [\n module2, \n module3 ...]" - for line in string.split(buffer, '\n'): - match = import_pat.match(line) - if match: - module, pyname, cname, conditional, importing_for = match.groups() - self.imports.append((module, pyname, cname, importing_for or None)) - elif command == 'define': - "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]" - "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]" - func = words[1] - klass = None - if func.find('.') != -1: - klass, func = func.split('.', 1) - - if not self.defines.has_key(klass): - self.defines[klass] = {} - self.defines[klass][func] = rest - else: - self.functions[func] = rest - - if 'kwargs' in words[1:]: - self.kwargs[func] = 1 - elif 'noargs' in words[1:]: - self.noargs[func] = 1 - elif 'onearg' in words[1:]: - self.onearg[func] = 1 - - if 'staticmethod' in words[1:]: - self.staticmethod[func] = True - elif 'classmethod' in words[1:]: - self.classmethod[func] = True - - self.startlines[func] = (startline + 1, filename) - - elif command == 'new-constructor': - "new-constructor GType" - gtype, = words[1:] - self.newstyle_constructors[gtype] = True - elif command == 'options': - for option in words[1:]: - if option == 'dynamicnamespace': - self.dynamicnamespace = True - - def is_ignored(self, name): - if self.ignores.has_key(name): - return 1 - for glob in self.glob_ignores: - if fnmatch.fnmatchcase(name, glob): - return 1 - return 0 - - def is_type_ignored(self, name): - return name in self.type_ignores - - def is_overriden(self, name): - return self.overrides.has_key(name) - - def is_already_included(self, name): - return self.overridden.has_key(name) - - def override(self, name): - self.overridden[name] = 1 - return self.overrides[name] - - def define(self, klass, name): - self.overridden[class2cname(klass, name)] = 1 - return self.defines[klass][name] - - def function(self, name): - return self.functions[name] - - def getstartline(self, name): - return self.startlines[name] - - def wants_kwargs(self, name): - return self.kwargs.has_key(name) - - def wants_noargs(self, name): - return self.noargs.has_key(name) - - def wants_onearg(self, name): - return self.onearg.has_key(name) - - def is_staticmethod(self, name): - return self.staticmethod.has_key(name) - - def is_classmethod(self, name): - return self.classmethod.has_key(name) - - def attr_is_overriden(self, attr): - return self.override_attrs.has_key(attr) - - def attr_override(self, attr): - return self.override_attrs[attr] - - def slot_is_overriden(self, slot): - return self.override_slots.has_key(slot) - - def slot_override(self, slot): - return self.override_slots[slot] - - def get_headers(self): - return self.headers - - def get_body(self): - return self.body - - def get_init(self): - return self.init - - def get_imports(self): - return self.imports - - def get_defines_for(self, klass): - return self.defines.get(klass, {}) - - def get_functions(self): - return self.functions +from .libcodegen.override import * diff --git a/codegen/scmexpr.py b/codegen/scmexpr.py index 02f2e4b..2ba30e1 100755..100644 --- a/codegen/scmexpr.py +++ b/codegen/scmexpr.py @@ -1,143 +1,11 @@ #!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -from __future__ import generators - -import string -from cStringIO import StringIO - -class error(Exception): - def __init__(self, filename, lineno, msg): - Exception.__init__(self, msg) - self.filename = filename - self.lineno = lineno - self.msg = msg - def __str__(self): - return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg) - -trans = [' '] * 256 -for i in range(256): - if chr(i) in string.letters + string.digits + '_': - trans[i] = chr(i) - else: - trans[i] = '_' -trans = string.join(trans, '') - -def parse(filename): - if isinstance(filename, str): - fp = open(filename, 'r') - else: # if not string, assume it is some kind of iterator - fp = filename - filename = getattr(fp, 'name', '<unknown>') - whitespace = ' \t\n\r\x0b\x0c' - nonsymbol = whitespace + '();\'"' - stack = [] - openlines = [] - lineno = 0 - for line in fp: - pos = 0 - lineno += 1 - while pos < len(line): - if line[pos] in whitespace: # ignore whitespace - pass - elif line[pos] == ';': # comment - break - elif line[pos:pos+2] == "'(": - pass # the open parenthesis will be handled next iteration - elif line[pos] == '(': - stack.append(()) - openlines.append(lineno) - elif line[pos] == ')': - if len(stack) == 0: - raise error(filename, lineno, 'close parenthesis found when none open') - closed = stack[-1] - del stack[-1] - del openlines[-1] - if stack: - stack[-1] += (closed,) - else: - yield closed - elif line[pos] == '"': # quoted string - if not stack: - raise error(filename, lineno, - 'string found outside of s-expression') - endpos = pos + 1 - chars = [] - while endpos < len(line): - if endpos+1 < len(line) and line[endpos] == '\\': - endpos += 1 - if line[endpos] == 'n': - chars.append('\n') - elif line[endpos] == 'r': - chars.append('\r') - elif line[endpos] == 't': - chars.append('\t') - else: - chars.append('\\') - chars.append(line[endpos]) - elif line[endpos] == '"': - break - else: - chars.append(line[endpos]) - endpos += 1 - if endpos >= len(line): - raise error(filename, lineno, "unclosed quoted string") - pos = endpos - stack[-1] += (''.join(chars),) - else: # symbol/number - if not stack: - raise error(filename, lineno, - 'identifier found outside of s-expression') - endpos = pos - while endpos < len(line) and line[endpos] not in nonsymbol: - endpos += 1 - symbol = line[pos:endpos] - pos = max(pos, endpos-1) - try: symbol = int(symbol) - except ValueError: - try: symbol = float(symbol) - except ValueError: pass - stack[-1] += (symbol,) - pos += 1 - if len(stack) != 0: - msg = '%d unclosed parentheses found at end of ' \ - 'file (opened on line(s) %s)' % (len(stack), - ', '.join(map(str, openlines))) - raise error(filename, lineno, msg) - -class Parser: - def __init__(self, filename): - """Argument is either a string, a parse tree, or file object""" - self.filename = filename - def startParsing(self, filename=None): - statements = parse(filename or self.filename) - for statement in statements: - self.handle(statement) - def handle(self, tup): - cmd = string.translate(tup[0], trans) - if hasattr(self, cmd): - getattr(self, cmd)(*tup[1:]) - else: - self.unknown(tup) - def unknown(self, tup): - pass - -_testString = """; a scheme file -(define-func gdk_font_load ; a comment at end of line - GdkFont - ((string name))) - -(define-boxed GdkEvent - gdk_event_copy - gdk_event_free - "sizeof(GdkEvent)") -""" +# scmexpr.py is runnable as a script and available as module in codegen package if __name__ == '__main__': + from libcodegen import scmrexpr import sys - if sys.argv[1:]: - fp = open(sys.argv[1]) - else: - fp = StringIO(_testString) - statements = parse(fp) - for s in statements: - print `s` + sys.exit(scmrexpr.main(sys.argv)) +else: + from codegen.libcodegen.scmexpr import * + + |