mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 11:55:39 +00:00
pyges: Sync codegen with upstream
This commit is contained in:
parent
20db3b7e78
commit
90f23b9a47
12 changed files with 1835 additions and 1217 deletions
|
@ -8,6 +8,7 @@ __all__ = [
|
|||
'docextract',
|
||||
'docgen',
|
||||
'h2def',
|
||||
'defsgen'
|
||||
'mergedefs',
|
||||
'mkskel',
|
||||
'override',
|
||||
|
|
|
@ -3,6 +3,18 @@ import string
|
|||
import keyword
|
||||
import struct
|
||||
|
||||
py_ssize_t_clean = False
|
||||
|
||||
class ArgTypeError(Exception):
|
||||
pass
|
||||
|
||||
class ArgTypeNotFoundError(ArgTypeError):
|
||||
pass
|
||||
|
||||
class ArgTypeConfigurationError(ArgTypeError):
|
||||
pass
|
||||
|
||||
|
||||
class VarList:
|
||||
"""Nicely format a C variable list"""
|
||||
def __init__(self):
|
||||
|
@ -64,17 +76,17 @@ class WrapperInfo:
|
|||
self.kwlist.append('"%s"' % kw)
|
||||
|
||||
class ArgType:
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
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):
|
||||
|
@ -82,8 +94,8 @@ class NoneArg(ArgType):
|
|||
' return Py_None;')
|
||||
|
||||
class StringArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
if pdflt:
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt != None:
|
||||
if pdflt != 'NULL': pdflt = '"' + pdflt + '"'
|
||||
info.varlist.add('char', '*' + pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -113,12 +125,15 @@ class StringArg(ArgType):
|
|||
|
||||
class UCharArg(ArgType):
|
||||
# allows strings with embedded NULLs.
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"')
|
||||
else:
|
||||
info.varlist.add('guchar', '*' + pname)
|
||||
info.varlist.add('int', pname + '_len')
|
||||
if py_ssize_t_clean:
|
||||
info.varlist.add('Py_ssize_t', pname + '_len')
|
||||
else:
|
||||
info.varlist.add('int', pname + '_len')
|
||||
info.arglist.append(pname)
|
||||
if pnull:
|
||||
info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'],
|
||||
|
@ -128,7 +143,7 @@ class UCharArg(ArgType):
|
|||
[pname])
|
||||
|
||||
class CharArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('char', pname + " = '" + pdflt + "'")
|
||||
else:
|
||||
|
@ -147,7 +162,7 @@ class GUniCharArg(ArgType):
|
|||
'#endif\n'
|
||||
' py_ret = (Py_UNICODE)ret;\n'
|
||||
' return PyUnicode_FromUnicode(&py_ret, 1);\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
|
||||
else:
|
||||
|
@ -161,7 +176,7 @@ class GUniCharArg(ArgType):
|
|||
|
||||
|
||||
class IntArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('int', pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -191,7 +206,7 @@ class UIntArg(ArgType):
|
|||
' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
|
||||
' if (PyErr_Occurred())\n'
|
||||
' return NULL;\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if not pdflt:
|
||||
pdflt = '0';
|
||||
|
||||
|
@ -211,7 +226,7 @@ class SizeArg(ArgType):
|
|||
else:
|
||||
llp64 = False
|
||||
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add(ptype, pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -235,7 +250,7 @@ class SSizeArg(ArgType):
|
|||
else:
|
||||
llp64 = False
|
||||
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add(ptype, pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -253,7 +268,7 @@ class SSizeArg(ArgType):
|
|||
info.codeafter.append(' return PyLong_FromLong(ret);\n')
|
||||
|
||||
class LongArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add(ptype, pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -270,7 +285,7 @@ class BoolArg(IntArg):
|
|||
info.codeafter.append(' return PyBool_FromLong(ret);\n')
|
||||
|
||||
class TimeTArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('time_t', pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -282,7 +297,7 @@ class TimeTArg(ArgType):
|
|||
info.codeafter.append(' return PyInt_FromLong(ret);')
|
||||
|
||||
class ULongArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('unsigned long', pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -294,8 +309,8 @@ class ULongArg(ArgType):
|
|||
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
|
||||
|
||||
class UInt32Arg(ULongArg):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
ULongArg.write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info)
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
ULongArg.write_param(self, ptype, pname, pdflt, pnull, info)
|
||||
## if sizeof(unsigned long) > sizeof(unsigned int), we need to
|
||||
## check the value is within guint32 range
|
||||
if struct.calcsize('L') > struct.calcsize('I'):
|
||||
|
@ -308,7 +323,7 @@ class UInt32Arg(ULongArg):
|
|||
' }\n') % vars())
|
||||
|
||||
class Int64Arg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('gint64', pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -320,20 +335,26 @@ class Int64Arg(ArgType):
|
|||
info.codeafter.append(' return PyLong_FromLongLong(ret);')
|
||||
|
||||
class UInt64Arg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
dflt = ' if (py_%(name)s)\n' \
|
||||
' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
|
||||
before = ' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('guint64', pname + ' = ' + pdflt)
|
||||
info.codebefore.append(self.dflt % {'name':pname})
|
||||
else:
|
||||
info.varlist.add('guint64', pname)
|
||||
info.codebefore.append(self.before % {'name':pname})
|
||||
info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
|
||||
info.arglist.append(pname)
|
||||
info.add_parselist('K', ['&' + pname], [pname])
|
||||
info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname])
|
||||
def write_return(self, ptype, ownsreturn, info):
|
||||
info.varlist.add('guint64', 'ret')
|
||||
info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);')
|
||||
|
||||
|
||||
class DoubleArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('double', pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -361,7 +382,7 @@ class FileArg(ArgType):
|
|||
' }\n')
|
||||
dflt = (' if (py_%(name)s)\n'
|
||||
' %(name)s = PyFile_AsFile(py_%(name)s);\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
if pdflt:
|
||||
info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
|
||||
|
@ -391,12 +412,12 @@ class FileArg(ArgType):
|
|||
' return Py_None;')
|
||||
|
||||
class EnumArg(ArgType):
|
||||
enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n'
|
||||
enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
|
||||
' return NULL;\n')
|
||||
def __init__(self, enumname, typecode):
|
||||
self.enumname = enumname
|
||||
self.typecode = typecode
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add(self.enumname, pname + ' = ' + pdflt)
|
||||
else:
|
||||
|
@ -411,12 +432,12 @@ class EnumArg(ArgType):
|
|||
info.codeafter.append(' return pyg_enum_from_gtype(%s, ret);' % self.typecode)
|
||||
|
||||
class FlagsArg(ArgType):
|
||||
flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n'
|
||||
flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
|
||||
' return NULL;\n')
|
||||
def __init__(self, flagname, typecode):
|
||||
self.flagname = flagname
|
||||
self.typecode = typecode
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add(self.flagname, pname + ' = ' + pdflt)
|
||||
default = "py_%s && " % (pname,)
|
||||
|
@ -456,7 +477,7 @@ class ObjectArg(ArgType):
|
|||
self.objname = objname
|
||||
self.cast = string.replace(typecode, '_TYPE_', '_', 1)
|
||||
self.parent = parent
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
if pdflt:
|
||||
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
|
||||
|
@ -506,99 +527,14 @@ class ObjectArg(ArgType):
|
|||
info.varlist.add(typename, '*ret')
|
||||
if ownsreturn:
|
||||
info.varlist.add('PyObject', '*py_ret')
|
||||
# < GLib 2.8: using our custom _new and _unref functions
|
||||
# makes sure we update the proper GstObject refcount
|
||||
info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
|
||||
' if (ret != NULL)\n'
|
||||
' g_object_unref((GObject *)ret);\n'
|
||||
' g_object_unref(ret);\n'
|
||||
' return py_ret;')
|
||||
else:
|
||||
info.codeafter.append(' /* pygobject_new handles NULL checking */\n' +
|
||||
' return pygobject_new((GObject *)ret);')
|
||||
|
||||
class MiniObjectArg(ArgType):
|
||||
# should change these checks to more typesafe versions that check
|
||||
# a little further down in the class heirachy.
|
||||
nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n'
|
||||
' %(name)s = NULL;\n'
|
||||
' else if (py_%(name)s) && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n'
|
||||
' %(name)s = %(cast)s(py_%(name)s->obj);\n'
|
||||
' else if (py_%(name)s) {\n'
|
||||
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
|
||||
' return NULL;\n'
|
||||
' }\n')
|
||||
null = (' if (py_%(name)s && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n'
|
||||
' %(name)s = %(cast)s(py_%(name)s->obj);\n'
|
||||
' else if ((PyObject *)py_%(name)s != Py_None) {\n'
|
||||
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
|
||||
' return NULL;\n'
|
||||
' }\n')
|
||||
dflt = ' if (py_%(name)s)\n' \
|
||||
' %(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.parent = parent
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
if pnull:
|
||||
if pdflt:
|
||||
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
|
||||
info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL')
|
||||
info.codebefore.append(self.nulldflt % {'name':pname,
|
||||
'cast':self.cast,
|
||||
'type':self.objname})
|
||||
else:
|
||||
info.varlist.add(self.objname, '*' + pname + ' = NULL')
|
||||
info.varlist.add('PyGstMiniObject', '*py_' + pname)
|
||||
info.codebefore.append(self.null % {'name':pname,
|
||||
'cast':self.cast,
|
||||
'type':self.objname})
|
||||
if ptype.endswith('*'):
|
||||
typename = ptype[:-1]
|
||||
try:
|
||||
const, typename = typename.split('const-')
|
||||
except ValueError:
|
||||
const = ''
|
||||
if typename != ptype:
|
||||
info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
|
||||
else:
|
||||
info.arglist.append(pname)
|
||||
|
||||
info.add_parselist('O', ['&py_' + pname], [pname])
|
||||
else:
|
||||
if pdflt:
|
||||
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
|
||||
info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL')
|
||||
info.codebefore.append(self.dflt % {'name':pname,
|
||||
'cast':self.cast})
|
||||
info.arglist.append(pname)
|
||||
info.add_parselist('O', ['&Py%s_Type' % self.objname,
|
||||
'&py_' + pname], [pname])
|
||||
else:
|
||||
info.varlist.add('PyGstMiniObject', '*' + pname)
|
||||
info.arglist.append('%s(%s->obj)' % (self.cast, pname))
|
||||
info.add_parselist('O!', ['&Py%s_Type' % self.objname,
|
||||
'&' + pname], [pname])
|
||||
if keeprefcount:
|
||||
info.codebefore.append(' gst_mini_object_ref(GST_MINI_OBJECT(%s->obj));\n' % pname)
|
||||
def write_return(self, ptype, ownsreturn, info):
|
||||
if ptype.endswith('*'):
|
||||
typename = ptype[:-1]
|
||||
try:
|
||||
const, typename = typename.split('const-')
|
||||
except ValueError:
|
||||
const = ''
|
||||
info.varlist.add(typename, '*ret')
|
||||
if ownsreturn:
|
||||
info.varlist.add('PyObject', '*py_ret')
|
||||
info.codeafter.append(' py_ret = pygstminiobject_new((GstMiniObject *)ret);\n'
|
||||
' if (ret != NULL)\n'
|
||||
' gst_mini_object_unref((GstMiniObject *)ret);\n'
|
||||
' return py_ret;')
|
||||
else:
|
||||
info.codeafter.append(' /* pygobject_new handles NULL checking */\n' +
|
||||
' return pygstminiobject_new((GstMiniObject *)ret);')
|
||||
|
||||
class BoxedArg(ArgType):
|
||||
# haven't done support for default args. Is it needed?
|
||||
check = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
|
||||
|
@ -616,7 +552,7 @@ class BoxedArg(ArgType):
|
|||
def __init__(self, ptype, typecode):
|
||||
self.typename = ptype
|
||||
self.typecode = typecode
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
info.varlist.add(self.typename, '*' + pname + ' = NULL')
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
|
||||
|
@ -643,8 +579,12 @@ class BoxedArg(ArgType):
|
|||
' return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);'
|
||||
def write_return(self, ptype, ownsreturn, info):
|
||||
if ptype[-1] == '*':
|
||||
info.varlist.add(self.typename, '*ret')
|
||||
decl_type = self.typename
|
||||
ret = 'ret'
|
||||
if ptype[:6] == 'const-':
|
||||
decl_type = 'const ' + self.typename
|
||||
ret = '(%s*) ret' % (self.typename,)
|
||||
info.varlist.add(decl_type, '*ret')
|
||||
else:
|
||||
info.varlist.add(self.typename, 'ret')
|
||||
ret = '&ret'
|
||||
|
@ -667,7 +607,7 @@ class CustomBoxedArg(ArgType):
|
|||
self.getter = getter
|
||||
self.checker = 'Py' + ptype + '_Check'
|
||||
self.new = new
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
info.varlist.add(ptype[:-1], '*' + pname + ' = NULL')
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
|
||||
|
@ -705,7 +645,7 @@ class PointerArg(ArgType):
|
|||
def __init__(self, ptype, typecode):
|
||||
self.typename = ptype
|
||||
self.typecode = typecode
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
info.varlist.add(self.typename, '*' + pname + ' = NULL')
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
|
||||
|
@ -739,7 +679,7 @@ class AtomArg(IntArg):
|
|||
atom = (' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n'
|
||||
' if (PyErr_Occurred())\n'
|
||||
' return NULL;\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pdflt:
|
||||
info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
|
||||
|
@ -762,7 +702,7 @@ class AtomArg(IntArg):
|
|||
class GTypeArg(ArgType):
|
||||
gtype = (' if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n'
|
||||
' return NULL;\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
info.varlist.add('GType', pname)
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
|
||||
info.codebefore.append(self.gtype % {'name': pname})
|
||||
|
@ -776,7 +716,7 @@ class GTypeArg(ArgType):
|
|||
class GErrorArg(ArgType):
|
||||
handleerror = (' if (pyg_error_check(&%(name)s))\n'
|
||||
' return NULL;\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
info.varlist.add('GError', '*' + pname + ' = NULL')
|
||||
info.arglist.append('&' + pname)
|
||||
info.codeafter.append(self.handleerror % { 'name': pname })
|
||||
|
@ -799,7 +739,7 @@ class GtkTreePathArg(ArgType):
|
|||
' gtk_tree_path_free(%(name)s);\n')
|
||||
def __init__(self):
|
||||
pass
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
info.varlist.add('GtkTreePath', '*' + pname + ' = NULL')
|
||||
info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
|
||||
|
@ -840,7 +780,7 @@ class GdkRectanglePtrArg(ArgType):
|
|||
' %(name)s = &%(name)s_rect;\n'
|
||||
' else\n'
|
||||
' return NULL;\n')
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
if pnull:
|
||||
info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }')
|
||||
info.varlist.add('GdkRectangle', '*' + pname)
|
||||
|
@ -861,7 +801,7 @@ class GdkRectangleArg(ArgType):
|
|||
info.codeafter.append(' return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);')
|
||||
|
||||
class PyObjectArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
info.varlist.add('PyObject', '*' + pname)
|
||||
info.add_parselist('O', ['&' + pname], [pname])
|
||||
info.arglist.append(pname)
|
||||
|
@ -878,13 +818,29 @@ class PyObjectArg(ArgType):
|
|||
' Py_INCREF(ret);\n'
|
||||
' return ret;')
|
||||
|
||||
class CairoArg(ArgType):
|
||||
def write_param(self, ptype, pname, pdflt, pnull, info):
|
||||
info.varlist.add('PycairoContext', '*' + pname)
|
||||
info.add_parselist('O!', ['&PycairoContext_Type', '&' + pname], [pname])
|
||||
info.arglist.append('%s->ctx' % pname)
|
||||
def write_return(self, ptype, ownsreturn, info):
|
||||
info.varlist.add("cairo_t", "*ret")
|
||||
if ownsreturn:
|
||||
info.codeafter.append(' return PycairoContext_FromContext(ret, NULL, NULL);')
|
||||
else:
|
||||
info.codeafter.append(' cairo_reference(ret);\n'
|
||||
' return PycairoContext_FromContext(ret, NULL, NULL);')
|
||||
|
||||
|
||||
class ArgMatcher:
|
||||
def __init__(self):
|
||||
self.argtypes = {}
|
||||
self.reverse_argtypes = {}
|
||||
self.reverse_rettypes = {}
|
||||
|
||||
def register(self, ptype, handler):
|
||||
def register(self, ptype, handler, overwrite=False):
|
||||
if not overwrite and ptype in self.argtypes:
|
||||
return
|
||||
self.argtypes[ptype] = handler
|
||||
def register_reverse(self, ptype, handler):
|
||||
self.reverse_argtypes[ptype] = handler
|
||||
|
@ -893,12 +849,14 @@ class ArgMatcher:
|
|||
|
||||
def register_enum(self, ptype, typecode):
|
||||
if typecode is None:
|
||||
typecode = "G_TYPE_NONE"
|
||||
self.register(ptype, EnumArg(ptype, typecode))
|
||||
self.register(ptype, IntArg())
|
||||
else:
|
||||
self.register(ptype, EnumArg(ptype, typecode))
|
||||
def register_flag(self, ptype, typecode):
|
||||
if typecode is None:
|
||||
typecode = "G_TYPE_NONE"
|
||||
self.register(ptype, FlagsArg(ptype, typecode))
|
||||
self.register(ptype, IntArg())
|
||||
else:
|
||||
self.register(ptype, FlagsArg(ptype, typecode))
|
||||
def register_object(self, ptype, parent, typecode):
|
||||
oa = ObjectArg(ptype, parent, typecode)
|
||||
self.register(ptype, oa) # in case I forget the * in the .defs
|
||||
|
@ -908,10 +866,6 @@ class ArgMatcher:
|
|||
# hack to handle GdkBitmap synonym.
|
||||
self.register('GdkBitmap', oa)
|
||||
self.register('GdkBitmap*', oa)
|
||||
def register_miniobject(self, ptype, parent, typecode):
|
||||
oa = MiniObjectArg(ptype, parent, typecode)
|
||||
self.register(ptype, oa) # in case I forget the * in the .defs
|
||||
self.register(ptype+'*', oa)
|
||||
def register_boxed(self, ptype, typecode):
|
||||
if self.argtypes.has_key(ptype): return
|
||||
arg = BoxedArg(ptype, typecode)
|
||||
|
@ -934,7 +888,7 @@ class ArgMatcher:
|
|||
except KeyError:
|
||||
if ptype[:8] == 'GdkEvent' and ptype[-1] == '*':
|
||||
return self.argtypes['GdkEvent*']
|
||||
raise
|
||||
raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
|
||||
def _get_reverse_common(self, ptype, registry):
|
||||
props = dict(c_type=ptype)
|
||||
try:
|
||||
|
@ -946,7 +900,7 @@ class ArgMatcher:
|
|||
if ptype.startswith('GdkEvent') and ptype.endswith('*'):
|
||||
handler = self.argtypes['GdkEvent*']
|
||||
else:
|
||||
raise
|
||||
raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
|
||||
if isinstance(handler, ObjectArg):
|
||||
return registry['GObject*'], props
|
||||
elif isinstance(handler, EnumArg):
|
||||
|
@ -962,11 +916,20 @@ class ArgMatcher:
|
|||
props['typename'] = handler.typename
|
||||
return registry['GBoxed'], props
|
||||
else:
|
||||
raise
|
||||
raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
|
||||
|
||||
def get_reverse(self, ptype):
|
||||
return self._get_reverse_common(ptype, self.reverse_argtypes)
|
||||
|
||||
def get_reverse_ret(self, ptype):
|
||||
return self._get_reverse_common(ptype, self.reverse_rettypes)
|
||||
ret, props = self._get_reverse_common(ptype, self.reverse_rettypes)
|
||||
if hasattr(ptype, 'optional') and ptype.optional:
|
||||
if ret.supports_optional:
|
||||
props['optional'] = True
|
||||
else:
|
||||
raise ArgTypeNotFoundError("Unsupported 'optional' for %s"
|
||||
% (ptype,))
|
||||
return ret, props
|
||||
|
||||
def object_is_a(self, otype, parent):
|
||||
if otype == None: return 0
|
||||
|
@ -993,6 +956,7 @@ matcher.register('static_string', arg)
|
|||
arg = UCharArg()
|
||||
matcher.register('unsigned-char*', arg)
|
||||
matcher.register('const-guchar*', arg)
|
||||
matcher.register('const-guint8*', arg)
|
||||
matcher.register('guchar*', arg)
|
||||
|
||||
arg = CharArg()
|
||||
|
@ -1017,6 +981,7 @@ matcher.register('guint16', arg)
|
|||
matcher.register('gint16', arg)
|
||||
matcher.register('gint32', arg)
|
||||
matcher.register('GTime', arg)
|
||||
matcher.register('GSeekType', arg) # Hack, but we have no python wrapper
|
||||
|
||||
arg = LongArg()
|
||||
matcher.register('long', arg)
|
||||
|
@ -1039,6 +1004,7 @@ matcher.register('gulong', arg)
|
|||
arg = Int64Arg()
|
||||
matcher.register('gint64', arg)
|
||||
matcher.register('long-long', arg)
|
||||
matcher.register('goffset', arg)
|
||||
|
||||
arg = UInt64Arg()
|
||||
matcher.register('guint64', arg)
|
||||
|
@ -1070,6 +1036,8 @@ matcher.register('PyObject*', PyObjectArg())
|
|||
matcher.register('GdkNativeWindow', ULongArg())
|
||||
|
||||
matcher.register_object('GObject', None, 'G_TYPE_OBJECT')
|
||||
matcher.register_miniobject('GstMiniObject', None, 'GST_TYPE_MINI_OBJECT')
|
||||
|
||||
del arg
|
||||
|
||||
matcher.register('cairo_t*', CairoArg())
|
||||
matcher.register_boxed("GClosure", "G_TYPE_CLOSURE")
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
from __future__ import generators
|
||||
import sys, os
|
||||
|
||||
|
|
824
bindings/python/codegen/codegen.py
Normal file → Executable file
824
bindings/python/codegen/codegen.py
Normal file → Executable file
File diff suppressed because it is too large
Load diff
|
@ -14,14 +14,13 @@ def make_docstring(lines):
|
|||
|
||||
# New Parameter class, wich emulates a tuple for compatibility reasons
|
||||
class Parameter(object):
|
||||
def __init__(self, ptype, pname, pdflt, pnull, pdir=None, keeprefcount = False):
|
||||
def __init__(self, ptype, pname, pdflt, pnull, pdir=None):
|
||||
self.ptype = ptype
|
||||
self.pname = pname
|
||||
self.pdflt = pdflt
|
||||
self.pnull = pnull
|
||||
self.pdir = pdir
|
||||
self.keeprefcount = keeprefcount
|
||||
|
||||
self.pdir = pdir
|
||||
|
||||
def __len__(self): return 4
|
||||
def __getitem__(self, i):
|
||||
return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
|
||||
|
@ -32,6 +31,17 @@ class Parameter(object):
|
|||
if old.pnull is not None:
|
||||
self.pnull = old.pnull
|
||||
|
||||
# We currently subclass 'str' to make impact on the rest of codegen as
|
||||
# little as possible. Later we can subclass 'object' instead, but
|
||||
# then we must find and adapt all places which expect return types to
|
||||
# be strings.
|
||||
class ReturnType(str):
|
||||
def __new__(cls, *args, **kwds):
|
||||
return str.__new__(cls, *args[:1])
|
||||
def __init__(self, type_name, optional=False):
|
||||
str.__init__(self)
|
||||
self.optional = optional
|
||||
|
||||
# Parameter for property based constructors
|
||||
class Property(object):
|
||||
def __init__(self, pname, optional, argname):
|
||||
|
@ -39,6 +49,10 @@ class Property(object):
|
|||
self.optional = optional
|
||||
self.argname = argname
|
||||
|
||||
def __len__(self): return 4
|
||||
def __getitem__(self, i):
|
||||
return ('', self.pname, self.optional, self.argname)[i]
|
||||
|
||||
def merge(self, old):
|
||||
if old.optional is not None:
|
||||
self.optional = old.optional
|
||||
|
@ -46,18 +60,26 @@ class Property(object):
|
|||
self.argname = old.argname
|
||||
|
||||
|
||||
class Definition:
|
||||
class Definition(object):
|
||||
docstring = "NULL"
|
||||
|
||||
def py_name(self):
|
||||
return '%s.%s' % (self.module, self.name)
|
||||
|
||||
py_name = property(py_name)
|
||||
|
||||
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"
|
||||
|
@ -119,58 +141,7 @@ class ObjectDef(Definition):
|
|||
for (ftype, fname) in self.fields:
|
||||
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||
fp.write(' )\n')
|
||||
fp.write(')\n\n')
|
||||
|
||||
class MiniObjectDef(Definition):
|
||||
def __init__(self, name, *args):
|
||||
self.name = name
|
||||
self.module = None
|
||||
self.parent = None
|
||||
self.c_name = None
|
||||
self.typecode = None
|
||||
self.fields = []
|
||||
self.implements = []
|
||||
for arg in args:
|
||||
if type(arg) != type(()) or len(arg) < 2:
|
||||
continue
|
||||
if arg[0] == 'in-module':
|
||||
self.module = arg[1]
|
||||
elif arg[0] == 'parent':
|
||||
self.parent = arg[1]
|
||||
elif arg[0] == 'c-name':
|
||||
self.c_name = arg[1]
|
||||
elif arg[0] == 'gtype-id':
|
||||
self.typecode = arg[1]
|
||||
elif arg[0] == 'fields':
|
||||
for parg in arg[1:]:
|
||||
self.fields.append((parg[0], parg[1]))
|
||||
elif arg[0] == 'implements':
|
||||
self.implements.append(arg[1])
|
||||
def merge(self, old):
|
||||
# currently the .h parser doesn't try to work out what fields of
|
||||
# an object structure should be public, so we just copy the list
|
||||
# from the old version ...
|
||||
self.fields = old.fields
|
||||
self.implements = old.implements
|
||||
def write_defs(self, fp=sys.stdout):
|
||||
fp.write('(define-object ' + self.name + '\n')
|
||||
if self.module:
|
||||
fp.write(' (in-module "' + self.module + '")\n')
|
||||
if self.parent != (None, None):
|
||||
fp.write(' (parent "' + self.parent + '")\n')
|
||||
for interface in self.implements:
|
||||
fp.write(' (implements "' + interface + '")\n')
|
||||
if self.c_name:
|
||||
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||
if self.typecode:
|
||||
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||
if self.fields:
|
||||
fp.write(' (fields\n')
|
||||
for (ftype, fname) in self.fields:
|
||||
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||
fp.write(' )\n')
|
||||
fp.write(')\n\n')
|
||||
|
||||
fp.write(')\n\n')
|
||||
|
||||
class InterfaceDef(Definition):
|
||||
def __init__(self, name, *args):
|
||||
|
@ -349,7 +320,12 @@ class MethodDefBase(Definition):
|
|||
elif arg[0] == 'gtype-id':
|
||||
self.typecode = arg[1]
|
||||
elif arg[0] == 'return-type':
|
||||
self.ret = arg[1]
|
||||
type_name = arg[1]
|
||||
optional = False
|
||||
for prop in arg[2:]:
|
||||
if prop[0] == 'optional':
|
||||
optional = True
|
||||
self.ret = ReturnType(type_name, optional)
|
||||
elif arg[0] == 'caller-owns-return':
|
||||
self.caller_owns_return = arg[1] in ('t', '#t')
|
||||
elif arg[0] == 'unblock-threads':
|
||||
|
@ -360,8 +336,7 @@ class MethodDefBase(Definition):
|
|||
pname = parg[1]
|
||||
pdflt = None
|
||||
pnull = 0
|
||||
pdir = None
|
||||
keeprefcount = False
|
||||
pdir = None
|
||||
for farg in parg[2:]:
|
||||
assert isinstance(farg, tuple)
|
||||
if farg[0] == 'default':
|
||||
|
@ -370,10 +345,7 @@ class MethodDefBase(Definition):
|
|||
pnull = 1
|
||||
elif farg[0] == 'direction':
|
||||
pdir = farg[1]
|
||||
elif farg[0] == 'keep-refcount':
|
||||
keeprefcount = True
|
||||
self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir,
|
||||
keeprefcount=keeprefcount))
|
||||
self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir))
|
||||
elif arg[0] == 'varargs':
|
||||
self.varargs = arg[1] in ('t', '#t')
|
||||
elif arg[0] == 'deprecated':
|
||||
|
@ -435,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')
|
||||
|
@ -483,17 +455,13 @@ class FunctionDef(Definition):
|
|||
pname = parg[1]
|
||||
pdflt = None
|
||||
pnull = 0
|
||||
keeprefcount = False
|
||||
for farg in parg[2:]:
|
||||
if farg[0] == 'default':
|
||||
pdflt = farg[1]
|
||||
elif farg[0] == 'null-ok':
|
||||
pnull = 1
|
||||
elif farg[0] == 'keep-refcount':
|
||||
keeprefcount = True
|
||||
self.params.append(Parameter(ptype, pname, pdflt, pnull,
|
||||
keeprefcount = keeprefcount))
|
||||
elif arg[0] == 'properties':
|
||||
self.params.append(Parameter(ptype, pname, pdflt, pnull))
|
||||
elif arg[0] == 'properties':
|
||||
if self.is_constructor_of is None:
|
||||
print >> sys.stderr, "Warning: (properties ...) "\
|
||||
"is only valid for constructors"
|
||||
|
@ -523,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']
|
||||
|
||||
|
@ -545,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:
|
||||
|
|
|
@ -2,26 +2,40 @@
|
|||
import os, sys
|
||||
import scmexpr
|
||||
from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
|
||||
InterfaceDef, MethodDef, ObjectDef, MiniObjectDef, PointerDef, \
|
||||
VirtualDef
|
||||
InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef
|
||||
|
||||
include_path = ['.']
|
||||
|
||||
class IncludeParser(scmexpr.Parser):
|
||||
"""A simple parser that follows include statements automatically"""
|
||||
def include(self, filename):
|
||||
if not os.path.isabs(filename):
|
||||
filename = os.path.join(os.path.dirname(self.filename), filename)
|
||||
|
||||
# set self.filename to the include name, to handle recursive includes
|
||||
oldfile = self.filename
|
||||
self.filename = filename
|
||||
self.startParsing()
|
||||
self.filename = oldfile
|
||||
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.miniobjects = []
|
||||
IncludeParser.__init__(self, arg)
|
||||
self.objects = []
|
||||
self.interfaces = []
|
||||
self.enums = [] # enums and flags
|
||||
self.boxes = [] # boxed types
|
||||
|
@ -33,13 +47,8 @@ class DefsParser(IncludeParser):
|
|||
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
|
||||
# TODO: define_mini_object
|
||||
def define_miniobject(self, *args):
|
||||
odef = apply(MiniObjectDef, args)
|
||||
self.miniobjects.append(odef)
|
||||
odef = apply(ObjectDef, args)
|
||||
self.objects.append(odef)
|
||||
self.c_name[odef.c_name] = odef
|
||||
def define_interface(self, *args):
|
||||
idef = apply(InterfaceDef, args)
|
||||
|
@ -89,10 +98,7 @@ class DefsParser(IncludeParser):
|
|||
f.write_defs()
|
||||
|
||||
def write_defs(self, fp=sys.stdout):
|
||||
for obj in self.objects:
|
||||
obj.write_defs(fp)
|
||||
# TODO: Add miniobject
|
||||
for obj in self.miniobjects:
|
||||
for obj in self.objects:
|
||||
obj.write_defs(fp)
|
||||
for enum in self.enums:
|
||||
enum.write_defs(fp)
|
||||
|
@ -108,7 +114,7 @@ class DefsParser(IncludeParser):
|
|||
if obj.c_name == c_name:
|
||||
return obj
|
||||
else:
|
||||
raise ValueError, 'object not found'
|
||||
raise ValueError('object %r not found' % c_name)
|
||||
|
||||
def find_constructor(self, obj, overrides):
|
||||
for func in self.functions:
|
||||
|
@ -135,7 +141,11 @@ class DefsParser(IncludeParser):
|
|||
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:
|
||||
|
|
|
@ -4,124 +4,399 @@ sources, so I can use them for other purposes.'''
|
|||
|
||||
import sys, os, string, re
|
||||
|
||||
# Used to tell if the "Since: ..." portion of the gtkdoc function description
|
||||
# should be omitted. This is useful for some C++ modules such as gstreamermm
|
||||
# that wrap C API which is still unstable and including this information would
|
||||
# not be useful.
|
||||
# This variable is modified from docextract_to_xml based on the --no-since
|
||||
# option being specified.
|
||||
no_since = False
|
||||
|
||||
__all__ = ['extract']
|
||||
|
||||
class FunctionDoc:
|
||||
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 = ''
|
||||
self.ret = ('', []) # (return, annotations)
|
||||
def set_name(self, name):
|
||||
self.name = name
|
||||
def add_param(self, name, description):
|
||||
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))
|
||||
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] = (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] = (name, self.params[i][1] + extra,
|
||||
self.params[i][2])
|
||||
return
|
||||
# fall through to adding extra parameter ...
|
||||
self.add_param(name, extra)
|
||||
def append_description(self, 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 append_return(self, extra):
|
||||
self.ret = self.ret + 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])
|
||||
|
||||
def get_param_description(self, name):
|
||||
for param, description in self.params:
|
||||
if param == name:
|
||||
return description
|
||||
else:
|
||||
return ''
|
||||
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*')
|
||||
|
||||
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?)$')
|
||||
# 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()
|
||||
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
|
||||
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
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
# inside a comment block, and not the end of the block ...
|
||||
line = comment_line_lead.sub('', line)
|
||||
# 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'
|
||||
|
||||
if not cur_doc.name:
|
||||
match = funcname_pat.match(line)
|
||||
# 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:
|
||||
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
|
||||
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:
|
||||
cur_doc.add_param(param, desc)
|
||||
else:
|
||||
# must be continuation
|
||||
try:
|
||||
if param == 'returns':
|
||||
cur_doc.append_return(line)
|
||||
# For all others ('Since:' and 'Deprecated:') just append
|
||||
# the line to the description for now.
|
||||
# But if --no-since is specified, don't append it.
|
||||
if no_since and pattern == since_pattern:
|
||||
pass
|
||||
else:
|
||||
cur_doc.append_to_last_param(line)
|
||||
except:
|
||||
sys.stderr.write('something weird while reading param\n')
|
||||
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
|
||||
|
@ -129,6 +404,7 @@ def parse_dir(dir, doc_dict):
|
|||
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):
|
||||
|
@ -137,13 +413,13 @@ def extract(dirs, doc_dict=None):
|
|||
parse_dir(dir, doc_dict)
|
||||
return doc_dict
|
||||
|
||||
tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
|
||||
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_pat.match(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)
|
||||
|
@ -152,7 +428,7 @@ def parse_tmpl(fp, doc_dict):
|
|||
if sect_type == 'FUNCTION':
|
||||
cur_doc = doc_dict.get(sect_name)
|
||||
if not cur_doc:
|
||||
cur_doc = FunctionDoc()
|
||||
cur_doc = GtkDoc()
|
||||
cur_doc.set_name(sect_name)
|
||||
doc_dict[sect_name] = cur_doc
|
||||
elif line == '<!-- # Unused Parameters # -->\n':
|
||||
|
@ -160,15 +436,15 @@ def parse_tmpl(fp, doc_dict):
|
|||
elif cur_doc:
|
||||
if line[:10] == '@Returns: ':
|
||||
if string.strip(line[10:]):
|
||||
cur_doc.append_return(line[10:])
|
||||
cur_doc.append_to_return(line[10:])
|
||||
elif line[0] == '@':
|
||||
pos = string.find(line, ':')
|
||||
if pos >= 0:
|
||||
cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
|
||||
else:
|
||||
cur_doc.append_description(line)
|
||||
cur_doc.append_to_description(line)
|
||||
else:
|
||||
cur_doc.append_description(line)
|
||||
cur_doc.append_to_description(line)
|
||||
|
||||
line = fp.readline()
|
||||
|
||||
|
|
874
bindings/python/codegen/docgen.py
Normal file → Executable file
874
bindings/python/codegen/docgen.py
Normal file → Executable file
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,69 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||
# Search through a header file looking for function prototypes.
|
||||
# For each prototype, generate a scheme style definition.
|
||||
# GPL'ed
|
||||
# Toby D. Reeves <toby@max.rl.plh.af.mil>
|
||||
#
|
||||
# Modified by James Henstridge <james@daa.com.au> to output stuff in
|
||||
# Havoc's new defs format. Info on this format can be seen at:
|
||||
# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
|
||||
# http://mail.gnome.org/archives/gtk-devel-list/2000-January/msg00070.html
|
||||
# Updated to be PEP-8 compatible and refactored to use OOP
|
||||
#
|
||||
# Scan the given public .h files of a GTK module (or module using
|
||||
# GTK object conventions) and generates a set of scheme defs.
|
||||
#
|
||||
# h2def searches through a header file looking for function prototypes and
|
||||
# generates a scheme style defenition for each prototype.
|
||||
# Basically the operation of h2def is:
|
||||
#
|
||||
# - read each .h file into a buffer which is scrubbed of extraneous data
|
||||
# - find all object defenitions:
|
||||
# - find all structures that may represent a GtkObject
|
||||
# - find all structures that might represent a class
|
||||
# - find all structures that may represent a GtkObject subclass
|
||||
# - find all structures that might represent a class/Iface inherited from
|
||||
# GTypeInterface
|
||||
# - find all enum defenitions
|
||||
# - write out the defs
|
||||
#
|
||||
# The command line options are:
|
||||
#
|
||||
# -s --separate Create separate files for objects and function/method defs
|
||||
# using the given name as the base name (optional). If this
|
||||
# is not specified the combined object and function defs
|
||||
# will be output to sys.stdout.
|
||||
# -f --defsfilter Extract defs from the given file to filter the output defs
|
||||
# that is don't output defs that are defined in the
|
||||
# defsfile. More than one deffile may be specified.
|
||||
# -m --modulename The prefix to be stripped from the front of function names
|
||||
# for the given module
|
||||
# -n --namespace The module or namespace name to be used, for example
|
||||
# WebKit where h2def is unable to detect the module name
|
||||
# automatically. it also sets the gtype-id prefix.
|
||||
# --onlyenums Only produce defs for enums and flags
|
||||
# --onlyobjdefs Only produce defs for objects
|
||||
# -v Verbose output
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# python h2def.py /usr/local/include/pango-1.0/pango/*.h >/tmp/pango.defs
|
||||
#
|
||||
# - Outputs all defs for the pango module.
|
||||
#
|
||||
# python h2def.py -m gdk -s /tmp/gdk-2.10 \
|
||||
# -f /usr/tmp/pygtk/gtk/gdk-base.defs \
|
||||
# /usr/local/include/gtk-2.0/gdk/*.h \
|
||||
# /usr/local/include/gtk-2.0/gdk-pixbuf/*.h
|
||||
#
|
||||
# - Outputs the gdk module defs that are not contained in the defs file
|
||||
# /usr/tmp/pygtk/gtk/gdk-base.defs. Two output files are created:
|
||||
# /tmp/gdk-2.10-types.defs and /tmp/gdk-2.10.defs.
|
||||
#
|
||||
# python h2def.py -n WebKit /usr/incude/webkit-1.0/webkit/*.h \
|
||||
# >/tmp/webkit.defs
|
||||
#
|
||||
# - Outputs all the defs for webkit module, setting the module name to WebKit
|
||||
# and the gtype-id prefix to WEBKIT_ which can't be detected automatically.
|
||||
#
|
||||
|
||||
import getopt
|
||||
import os
|
||||
|
@ -33,16 +88,16 @@ def to_upper_str(name):
|
|||
name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
|
||||
return string.upper(name)
|
||||
|
||||
def typecode(typename):
|
||||
def typecode(typename, namespace=None):
|
||||
"""create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
|
||||
typename2 = to_upper_str(typename)
|
||||
typename2 = string.replace(typename2, '_', "", 1)
|
||||
typename2 = typename2[:3] + '_TYPE' + typename2[3:]
|
||||
return typename2
|
||||
if namespace:
|
||||
return string.replace(string.upper(namespace) + "_" + to_upper_str(typename[len(namespace):]), '_', '_TYPE_', 1)
|
||||
|
||||
return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
|
||||
|
||||
|
||||
# ------------------ Find object definitions -----------------
|
||||
|
||||
# Strips the comments from buffer
|
||||
def strip_comments(buf):
|
||||
parts = []
|
||||
lastpos = 0
|
||||
|
@ -60,6 +115,12 @@ def strip_comments(buf):
|
|||
break
|
||||
return string.join(parts, '')
|
||||
|
||||
# Strips the dll API from buffer, for example WEBKIT_API
|
||||
def strip_dll_api(buf):
|
||||
pat = re.compile("[A-Z]*_API ")
|
||||
buf = pat.sub("", buf)
|
||||
return buf
|
||||
|
||||
obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
|
||||
|
||||
split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
|
||||
|
@ -72,10 +133,13 @@ def find_obj_defs(buf, objdefs=[]):
|
|||
# filter out comments from buffer.
|
||||
buf = strip_comments(buf)
|
||||
|
||||
# filter out dll api
|
||||
buf = strip_dll_api(buf)
|
||||
|
||||
maybeobjdefs = [] # contains all possible objects from file
|
||||
|
||||
# first find all structures that look like they may represent a GtkObject
|
||||
pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" +
|
||||
pat = re.compile("struct\s+_(" + obj_name_pat + ")\s*{\s*" +
|
||||
"(" + obj_name_pat + ")\s+", re.MULTILINE)
|
||||
pos = 0
|
||||
while pos < len(buf):
|
||||
|
@ -92,11 +156,11 @@ def find_obj_defs(buf, objdefs=[]):
|
|||
while pos < len(buf):
|
||||
m = pat.search(buf, pos)
|
||||
if not m: break
|
||||
maybeobjdefs.append((m.group(2), m.group(2)))
|
||||
maybeobjdefs.append((m.group(2), m.group(1)))
|
||||
pos = m.end()
|
||||
|
||||
# now find all structures that look like they might represent a class:
|
||||
pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
|
||||
pat = re.compile("struct\s+_(" + obj_name_pat + ")Class\s*{\s*" +
|
||||
"(" + obj_name_pat + ")Class\s+", re.MULTILINE)
|
||||
pos = 0
|
||||
while pos < len(buf):
|
||||
|
@ -125,7 +189,7 @@ def find_obj_defs(buf, objdefs=[]):
|
|||
|
||||
# now find all structures that look like they might represent
|
||||
# a class inherited from GTypeInterface:
|
||||
pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
|
||||
pat = re.compile("struct\s+_(" + obj_name_pat + ")Class\s*{\s*" +
|
||||
"GTypeInterface\s+", re.MULTILINE)
|
||||
pos = 0
|
||||
while pos < len(buf):
|
||||
|
@ -141,7 +205,7 @@ def find_obj_defs(buf, objdefs=[]):
|
|||
|
||||
# now find all structures that look like they might represent
|
||||
# an Iface inherited from GTypeInterface:
|
||||
pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" +
|
||||
pat = re.compile("struct\s+_(" + obj_name_pat + ")Iface\s*{\s*" +
|
||||
"GTypeInterface\s+", re.MULTILINE)
|
||||
pos = 0
|
||||
while pos < len(buf):
|
||||
|
@ -177,6 +241,13 @@ def find_enum_defs(buf, enums=[]):
|
|||
# bulk comments
|
||||
buf = strip_comments(buf)
|
||||
|
||||
# strip dll api macros
|
||||
buf = strip_dll_api(buf)
|
||||
|
||||
# strip # directives
|
||||
pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
|
||||
buf = pat.sub('', buf)
|
||||
|
||||
buf = re.sub('\n', ' ', buf)
|
||||
|
||||
enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
|
||||
|
@ -209,6 +280,9 @@ def clean_func(buf):
|
|||
# bulk comments
|
||||
buf = strip_comments(buf)
|
||||
|
||||
# dll api
|
||||
buf = strip_dll_api(buf)
|
||||
|
||||
# compact continued lines
|
||||
pat = re.compile(r"""\\\n""", re.MULTILINE)
|
||||
buf = pat.sub('', buf)
|
||||
|
@ -247,9 +321,14 @@ def clean_func(buf):
|
|||
buf = pat.sub(r'[] \1', buf)
|
||||
|
||||
# make return types that are const work.
|
||||
buf = re.sub(r'\s*\*\s*G_CONST_RETURN\s*\*\s*', '** ', buf)
|
||||
buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
|
||||
buf = string.replace(buf, 'const ', 'const-')
|
||||
|
||||
#strip GSEAL macros from the middle of function declarations:
|
||||
pat = re.compile(r"""GSEAL""", re.VERBOSE)
|
||||
buf = pat.sub('', buf)
|
||||
|
||||
return buf
|
||||
|
||||
proto_pat=re.compile(r"""
|
||||
|
@ -266,13 +345,14 @@ pointer_pat = re.compile('.*\*$')
|
|||
func_new_pat = re.compile('(\w+)_new$')
|
||||
|
||||
class DefsWriter:
|
||||
def __init__(self, fp=None, prefix=None, verbose=False,
|
||||
def __init__(self, fp=None, prefix=None, ns=None, verbose=False,
|
||||
defsfilter=None):
|
||||
if not fp:
|
||||
fp = sys.stdout
|
||||
|
||||
self.fp = fp
|
||||
self.prefix = prefix
|
||||
self.namespace = ns
|
||||
self.verbose = verbose
|
||||
|
||||
self._enums = {}
|
||||
|
@ -284,9 +364,9 @@ class DefsWriter:
|
|||
for func in filter.functions + filter.methods.values():
|
||||
self._functions[func.c_name] = func
|
||||
for obj in filter.objects + filter.boxes + filter.interfaces:
|
||||
self._objects[obj.c_name] = func
|
||||
self._objects[obj.c_name] = obj
|
||||
for obj in filter.enums:
|
||||
self._enums[obj.c_name] = func
|
||||
self._enums[obj.c_name] = obj
|
||||
|
||||
def write_def(self, deffile):
|
||||
buf = open(deffile).read()
|
||||
|
@ -309,10 +389,14 @@ class DefsWriter:
|
|||
continue
|
||||
name = cname
|
||||
module = None
|
||||
m = split_prefix_pat.match(cname)
|
||||
if m:
|
||||
module = m.group(1)
|
||||
name = m.group(2)
|
||||
if self.namespace:
|
||||
module = self.namespace
|
||||
name = cname[len(self.namespace):]
|
||||
else:
|
||||
m = split_prefix_pat.match(cname)
|
||||
if m:
|
||||
module = m.group(1)
|
||||
name = m.group(2)
|
||||
if isflags:
|
||||
fp.write('(define-flags ' + name + '\n')
|
||||
else:
|
||||
|
@ -320,12 +404,13 @@ class DefsWriter:
|
|||
if module:
|
||||
fp.write(' (in-module "' + module + '")\n')
|
||||
fp.write(' (c-name "' + cname + '")\n')
|
||||
fp.write(' (gtype-id "' + typecode(cname) + '")\n')
|
||||
fp.write(' (gtype-id "' + typecode(cname, self.namespace) + '")\n')
|
||||
prefix = entries[0]
|
||||
for ent in entries:
|
||||
# shorten prefix til we get a match ...
|
||||
# and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
|
||||
while ent[:len(prefix)] != prefix or len(prefix) >= len(ent):
|
||||
while ((len(prefix) and prefix[-1] != '_') or ent[:len(prefix)] != prefix
|
||||
or len(prefix) >= len(ent)):
|
||||
prefix = prefix[:-1]
|
||||
prefix_len = len(prefix)
|
||||
fp.write(' (values\n')
|
||||
|
@ -347,19 +432,23 @@ class DefsWriter:
|
|||
if filter:
|
||||
if klass in filter:
|
||||
continue
|
||||
m = split_prefix_pat.match(klass)
|
||||
cmodule = None
|
||||
cname = klass
|
||||
if m:
|
||||
cmodule = m.group(1)
|
||||
cname = m.group(2)
|
||||
if self.namespace:
|
||||
cname = klass[len(self.namespace):]
|
||||
cmodule = self.namespace
|
||||
else:
|
||||
m = split_prefix_pat.match(klass)
|
||||
cname = klass
|
||||
cmodule = None
|
||||
if m:
|
||||
cmodule = m.group(1)
|
||||
cname = m.group(2)
|
||||
fp.write('(define-object ' + cname + '\n')
|
||||
if cmodule:
|
||||
fp.write(' (in-module "' + cmodule + '")\n')
|
||||
if parent:
|
||||
fp.write(' (parent "' + parent + '")\n')
|
||||
fp.write(' (c-name "' + klass + '")\n')
|
||||
fp.write(' (gtype-id "' + typecode(klass) + '")\n')
|
||||
fp.write(' (gtype-id "' + typecode(klass, self.namespace) + '")\n')
|
||||
# should do something about accessible fields
|
||||
fp.write(')\n\n')
|
||||
|
||||
|
@ -475,11 +564,12 @@ def main(args):
|
|||
onlyobjdefs = False
|
||||
separate = False
|
||||
modulename = None
|
||||
namespace = None
|
||||
defsfilter = None
|
||||
opts, args = getopt.getopt(args[1:], 'vs:m:f:',
|
||||
opts, args = getopt.getopt(args[1:], 'vs:m:n:f:',
|
||||
['onlyenums', 'onlyobjdefs',
|
||||
'modulename=', 'separate=',
|
||||
'defsfilter='])
|
||||
'modulename=', 'namespace=',
|
||||
'separate=', 'defsfilter='])
|
||||
for o, v in opts:
|
||||
if o == '-v':
|
||||
verbose = True
|
||||
|
@ -491,6 +581,8 @@ def main(args):
|
|||
separate = v
|
||||
if o in ('-m', '--modulename'):
|
||||
modulename = v
|
||||
if o in ('-n', '--namespace'):
|
||||
namespace = v
|
||||
if o in ('-f', '--defsfilter'):
|
||||
defsfilter = v
|
||||
|
||||
|
@ -511,8 +603,8 @@ def main(args):
|
|||
methods = file(separate + '.defs', 'w')
|
||||
types = file(separate + '-types.defs', 'w')
|
||||
|
||||
dw = DefsWriter(methods, prefix=modulename, verbose=verbose,
|
||||
defsfilter=defsfilter)
|
||||
dw = DefsWriter(methods, prefix=modulename, ns=namespace,
|
||||
verbose=verbose, defsfilter=defsfilter)
|
||||
dw.write_obj_defs(objdefs, types)
|
||||
dw.write_enum_defs(enums, types)
|
||||
print "Wrote %s-types.defs" % separate
|
||||
|
@ -521,8 +613,8 @@ def main(args):
|
|||
dw.write_def(filename)
|
||||
print "Wrote %s.defs" % separate
|
||||
else:
|
||||
dw = DefsWriter(prefix=modulename, verbose=verbose,
|
||||
defsfilter=defsfilter)
|
||||
dw = DefsWriter(prefix=modulename, ns=namespace,
|
||||
verbose=verbose, defsfilter=defsfilter)
|
||||
|
||||
if onlyenums:
|
||||
dw.write_enum_defs(enums)
|
||||
|
|
|
@ -19,10 +19,13 @@ def class2cname(klass, method):
|
|||
c_name += c
|
||||
return c_name[1:] + '_' + method
|
||||
|
||||
import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)')
|
||||
# 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, path=[]):
|
||||
def __init__(self, filename=None):
|
||||
self.modulename = None
|
||||
self.ignores = {}
|
||||
self.glob_ignores = []
|
||||
|
@ -43,27 +46,16 @@ class Overrides:
|
|||
self.imports = []
|
||||
self.defines = {}
|
||||
self.functions = {}
|
||||
self.newstyle_constructors = {}
|
||||
self.path = [os.path.abspath(x) for x in path]
|
||||
if filename:
|
||||
self.newstyle_constructors = {}
|
||||
self.dynamicnamespace = False
|
||||
if filename:
|
||||
self.handle_file(filename)
|
||||
|
||||
def handle_file(self, filename):
|
||||
oldpath = os.getcwd()
|
||||
|
||||
fp = None
|
||||
for path in self.path:
|
||||
os.chdir(oldpath)
|
||||
os.chdir(path)
|
||||
try:
|
||||
fp = open(filename, 'r')
|
||||
break
|
||||
except:
|
||||
os.chdir(oldpath)
|
||||
if not fp:
|
||||
raise Exception, "Couldn't find file %s" % filename
|
||||
|
||||
dirname = path
|
||||
fp = open(filename, 'r')
|
||||
dirname = os.path.dirname(os.path.abspath(filename))
|
||||
|
||||
if dirname != oldpath:
|
||||
os.chdir(dirname)
|
||||
|
@ -177,7 +169,8 @@ class Overrides:
|
|||
for line in string.split(buffer, '\n'):
|
||||
match = import_pat.match(line)
|
||||
if match:
|
||||
self.imports.append(match.groups())
|
||||
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]"
|
||||
|
@ -210,6 +203,10 @@ class Overrides:
|
|||
"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):
|
||||
|
|
|
@ -88,10 +88,12 @@ class ReverseWrapper(object):
|
|||
self.declarations = MemoryCodeSink()
|
||||
self.post_return_code = MemoryCodeSink()
|
||||
self.body = MemoryCodeSink()
|
||||
self.check_exception_code = MemoryCodeSink()
|
||||
self.cleanup_actions = []
|
||||
self.pyargv_items = []
|
||||
self.pyargv_optional_items = []
|
||||
self.pyret_parse_items = [] # list of (format_spec, parameter)
|
||||
self.code_sinks_stack = [self.body]
|
||||
|
||||
def set_call_target(self, called_pyobj, method_name=None):
|
||||
assert called_pyobj is not None
|
||||
|
@ -122,6 +124,14 @@ class ReverseWrapper(object):
|
|||
else:
|
||||
self.pyret_parse_items.append((format_specifier, parameter))
|
||||
|
||||
|
||||
def push_code_sink(self, code_sink):
|
||||
self.code_sinks_stack.insert(0, code_sink)
|
||||
|
||||
def pop_code_sink(self):
|
||||
return self.code_sinks_stack.pop(0)
|
||||
|
||||
|
||||
def write_code(self, code,
|
||||
cleanup=None,
|
||||
failure_expression=None,
|
||||
|
@ -152,7 +162,7 @@ class ReverseWrapper(object):
|
|||
parses the python method return value.
|
||||
'''
|
||||
if code_sink is None:
|
||||
code_sink = self.body
|
||||
code_sink = self.code_sinks_stack[0]
|
||||
if code is not None:
|
||||
code_sink.writeln(code)
|
||||
if failure_expression is not None:
|
||||
|
@ -170,7 +180,13 @@ class ReverseWrapper(object):
|
|||
code_sink.writeln(failure_cleanup)
|
||||
for cleanup_action in self.cleanup_actions:
|
||||
code_sink.writeln(cleanup_action)
|
||||
self.return_type.write_error_return()
|
||||
|
||||
self.push_code_sink(code_sink)
|
||||
try:
|
||||
self.return_type.write_error_return()
|
||||
finally:
|
||||
self.pop_code_sink()
|
||||
|
||||
code_sink.unindent()
|
||||
code_sink.writeln("}")
|
||||
if cleanup is not None:
|
||||
|
@ -265,8 +281,10 @@ class ReverseWrapper(object):
|
|||
if self.method_name is None:
|
||||
self.write_code("py_retval = PyObject_Call(%s, %s);"
|
||||
% (self.called_pyobj, py_args),
|
||||
cleanup="Py_DECREF(py_retval);",
|
||||
failure_expression="!py_retval")
|
||||
cleanup="Py_XDECREF(py_retval);")
|
||||
self.check_exception_code.flush_to(self.body)
|
||||
self.write_code(None, failure_expression="!py_retval")
|
||||
|
||||
else:
|
||||
self.add_declaration("PyObject *py_method;")
|
||||
self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
|
||||
|
@ -275,8 +293,9 @@ class ReverseWrapper(object):
|
|||
failure_expression="!py_method")
|
||||
self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
|
||||
% (py_args,),
|
||||
cleanup="Py_DECREF(py_retval);",
|
||||
failure_expression="!py_retval")
|
||||
cleanup="Py_XDECREF(py_retval);")
|
||||
self.check_exception_code.flush_to(self.body)
|
||||
self.write_code(None, failure_expression="!py_retval")
|
||||
|
||||
## -- Handle the return value --
|
||||
|
||||
|
@ -291,16 +310,25 @@ class ReverseWrapper(object):
|
|||
|
||||
sink.indent()
|
||||
|
||||
if len(self.pyret_parse_items) == 1:
|
||||
## if retval is one item only, pack it in a tuple so we
|
||||
## can use PyArg_ParseTuple as usual..
|
||||
self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
|
||||
if len(self.pyret_parse_items) > 0:
|
||||
## Parse return values using PyArg_ParseTuple
|
||||
self.write_code(code=None, failure_expression=(
|
||||
'!PyArg_ParseTuple(py_retval, "%s", %s)' % (
|
||||
"".join([format for format, param in self.pyret_parse_items]),
|
||||
", ".join([param for format, param in self.pyret_parse_items]))))
|
||||
if self.pyret_parse_items == [("", "")]:
|
||||
## special case when there are no return parameters
|
||||
self.write_code(
|
||||
code=None,
|
||||
failure_expression='py_retval != Py_None',
|
||||
failure_exception=('PyErr_SetString(PyExc_TypeError, '
|
||||
'"virtual method should return None");'))
|
||||
else:
|
||||
if len(self.pyret_parse_items) == 1:
|
||||
## if retval is one item only, pack it in a tuple so we
|
||||
## can use PyArg_ParseTuple as usual..
|
||||
self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
|
||||
if len(self.pyret_parse_items) > 0:
|
||||
## Parse return values using PyArg_ParseTuple
|
||||
params = ["py_retval",
|
||||
'"%s"' % "".join([format for format, param in self.pyret_parse_items])]
|
||||
params.extend([param for format, param in self.pyret_parse_items if param])
|
||||
self.write_code(code=None, failure_expression=(
|
||||
'!PyArg_ParseTuple(%s)' % (', '.join(params),)))
|
||||
|
||||
if DEBUG_MODE:
|
||||
self.declarations.writeln("/* end declarations */")
|
||||
|
@ -331,6 +359,8 @@ class TypeHandler(object):
|
|||
|
||||
class ReturnType(TypeHandler):
|
||||
|
||||
supports_optional = False
|
||||
|
||||
def get_c_type(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -378,10 +408,22 @@ class StringParam(Parameter):
|
|||
% (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:
|
||||
elif self.props.get('nullok', False):
|
||||
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||
self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
|
||||
(self.name, self.name)),
|
||||
self.wrapper.write_code(code=("if (%s)\n"
|
||||
" py_%s = PyString_FromString(%s);\n"
|
||||
"else {\n"
|
||||
" Py_INCREF(Py_None);\n"
|
||||
" py_%s = Py_None;\n"
|
||||
"}\n"
|
||||
% (self.name, self.name, self.name, self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||
else:
|
||||
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||
self.wrapper.write_code(code=("if (%s)\n"
|
||||
" py_%s = PyString_FromString(%s);\n" %
|
||||
(self.name, self.name, self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||
failure_expression=("!py_%s" % self.name))
|
||||
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||
|
@ -394,10 +436,12 @@ del ctype
|
|||
class StringReturn(ReturnType):
|
||||
|
||||
def get_c_type(self):
|
||||
return "char *"
|
||||
return self.props.get('c_type', 'char *').replace('const-', 'const ')
|
||||
#return "char *"
|
||||
|
||||
def write_decl(self):
|
||||
self.wrapper.add_declaration("char *retval;")
|
||||
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||
#self.wrapper.add_declaration("char *retval;")
|
||||
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return NULL;")
|
||||
|
@ -406,7 +450,7 @@ class StringReturn(ReturnType):
|
|||
self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
|
||||
self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
|
||||
|
||||
for ctype in ('char*', 'gchar*'):
|
||||
for ctype in ('char*', 'gchar*', 'const-gchar*'):
|
||||
argtypes.matcher.register_reverse_ret(ctype, StringReturn)
|
||||
del ctype
|
||||
|
||||
|
@ -423,10 +467,7 @@ class VoidReturn(ReturnType):
|
|||
self.wrapper.write_code("return;")
|
||||
|
||||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression="py_retval != Py_None",
|
||||
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
|
||||
self.wrapper.add_pyret_parse_item("", "", prepend=True)
|
||||
|
||||
argtypes.matcher.register_reverse_ret('void', VoidReturn)
|
||||
argtypes.matcher.register_reverse_ret('none', VoidReturn)
|
||||
|
@ -452,23 +493,39 @@ argtypes.matcher.register_reverse('GObject*', GObjectParam)
|
|||
|
||||
class GObjectReturn(ReturnType):
|
||||
|
||||
supports_optional = True
|
||||
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type', 'GObject *')
|
||||
|
||||
def write_decl(self):
|
||||
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||
if not self.props.get('optional'):
|
||||
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||
else:
|
||||
self.wrapper.add_declaration("%s retval = NULL;" % self.get_c_type())
|
||||
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return NULL;")
|
||||
|
||||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
|
||||
failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
|
||||
self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
|
||||
% self.get_c_type())
|
||||
self.wrapper.write_code("g_object_ref((GObject *) retval);")
|
||||
if not self.props.get('optional'):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
|
||||
failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
|
||||
self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
|
||||
% self.get_c_type())
|
||||
self.wrapper.write_code("g_object_ref((GObject *) retval);")
|
||||
else:
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression="py_retval != Py_None && !PyObject_TypeCheck(py_retval, &PyGObject_Type)",
|
||||
failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be None or a GObject");')
|
||||
self.wrapper.write_code("if (py_retval != Py_None) {\n"
|
||||
" retval = (%s) pygobject_get(py_retval);\n"
|
||||
" g_object_ref((GObject *) retval);\n"
|
||||
"}\n"
|
||||
% self.get_c_type())
|
||||
|
||||
argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
|
||||
|
||||
|
@ -506,9 +563,12 @@ del argtype
|
|||
class IntPtrParam(Parameter):
|
||||
def __init__(self, wrapper, name, **props):
|
||||
if "direction" not in props:
|
||||
raise ValueError("cannot use int* parameter without direction")
|
||||
raise argtypes.ArgTypeConfigurationError(
|
||||
"cannot use int* parameter without direction")
|
||||
if props["direction"] not in ("out", "inout"):
|
||||
raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],))
|
||||
raise argtypes.ArgTypeConfigurationError(
|
||||
"cannot use int* parameter with direction '%s'"
|
||||
% (props["direction"],))
|
||||
Parameter.__init__(self, wrapper, name, **props)
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type', 'int*')
|
||||
|
@ -529,8 +589,9 @@ class GEnumReturn(IntReturn):
|
|||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
|
||||
self.props['typecode']))
|
||||
failure_expression=(
|
||||
"pyg_enum_get_value(%s, py_retval, (gint *)&retval)"
|
||||
% (self.props['typecode'],)))
|
||||
|
||||
argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
|
||||
|
||||
|
@ -538,9 +599,9 @@ class GEnumParam(IntParam):
|
|||
def convert_c2py(self):
|
||||
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||
self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
|
||||
(self.name, self.props['typecode'], self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||
failure_expression=("!py_%s" % self.name))
|
||||
(self.name, self.props['typecode'], self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||
failure_expression=("!py_%s" % self.name))
|
||||
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||
|
||||
argtypes.matcher.register_reverse("GEnum", GEnumParam)
|
||||
|
@ -549,16 +610,18 @@ class GFlagsReturn(IntReturn):
|
|||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
|
||||
self.props['typecode']))
|
||||
failure_expression=(
|
||||
"pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
|
||||
self.props['typecode']))
|
||||
|
||||
argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
|
||||
|
||||
class GFlagsParam(IntParam):
|
||||
def convert_c2py(self):
|
||||
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||
self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
|
||||
(self.name, self.props['typecode'], self.name)),
|
||||
self.wrapper.write_code(code=(
|
||||
"py_%s = pyg_flags_from_gtype(%s, %s);" %
|
||||
(self.name, self.props['typecode'], self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||
failure_expression=("!py_%s" % self.name))
|
||||
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||
|
@ -569,8 +632,9 @@ argtypes.matcher.register_reverse("GFlags", GFlagsParam)
|
|||
class GtkTreePathParam(IntParam):
|
||||
def convert_c2py(self):
|
||||
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||
self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
|
||||
(self.name, self.name)),
|
||||
self.wrapper.write_code(code=(
|
||||
"py_%s = pygtk_tree_path_to_pyobject(%s);" %
|
||||
(self.name, self.name)),
|
||||
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||
failure_expression=("!py_%s" % self.name))
|
||||
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||
|
@ -578,6 +642,23 @@ class GtkTreePathParam(IntParam):
|
|||
argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
|
||||
|
||||
|
||||
class GtkTreePathReturn(ReturnType):
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type', 'GtkTreePath *')
|
||||
def write_decl(self):
|
||||
self.wrapper.add_declaration("GtkTreePath * retval;")
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return NULL;")
|
||||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
"retval = pygtk_tree_path_from_pyobject(py_retval);\n",
|
||||
failure_expression=('!retval'),
|
||||
failure_exception=(
|
||||
'PyErr_SetString(PyExc_TypeError, "retval should be a GtkTreePath");'))
|
||||
|
||||
argtypes.matcher.register_reverse_ret("GtkTreePath*", GtkTreePathReturn)
|
||||
|
||||
|
||||
class BooleanReturn(ReturnType):
|
||||
def get_c_type(self):
|
||||
return "gboolean"
|
||||
|
@ -588,8 +669,9 @@ class BooleanReturn(ReturnType):
|
|||
self.wrapper.write_code("return FALSE;")
|
||||
def write_conversion(self):
|
||||
self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
|
||||
self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
|
||||
code_sink=self.wrapper.post_return_code)
|
||||
self.wrapper.write_code(
|
||||
"retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
|
||||
code_sink=self.wrapper.post_return_code)
|
||||
argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
|
||||
|
||||
class BooleanParam(Parameter):
|
||||
|
@ -617,9 +699,12 @@ class DoubleParam(Parameter):
|
|||
class DoublePtrParam(Parameter):
|
||||
def __init__(self, wrapper, name, **props):
|
||||
if "direction" not in props:
|
||||
raise ValueError("cannot use double* parameter without direction")
|
||||
raise argtypes.ArgTypeConfigurationError(
|
||||
"cannot use double* parameter without direction")
|
||||
if props["direction"] not in ("out", ): # inout not yet implemented
|
||||
raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],))
|
||||
raise argtypes.ArgTypeConfigurationError(
|
||||
"cannot use double* parameter with direction '%s'"
|
||||
% (props["direction"],))
|
||||
Parameter.__init__(self, wrapper, name, **props)
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type', 'double*')
|
||||
|
@ -637,11 +722,7 @@ class DoubleReturn(ReturnType):
|
|||
def write_error_return(self):
|
||||
self.wrapper.write_code("return -G_MAXFLOAT;")
|
||||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
code=None,
|
||||
failure_expression="!PyFloat_AsDouble(py_retval)",
|
||||
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
|
||||
self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
|
||||
self.wrapper.add_pyret_parse_item("d", "&retval", prepend=True)
|
||||
|
||||
for argtype in ('float', 'double', 'gfloat', 'gdouble'):
|
||||
argtypes.matcher.register_reverse(argtype, DoubleParam)
|
||||
|
@ -670,6 +751,7 @@ class GBoxedParam(Parameter):
|
|||
|
||||
argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
|
||||
|
||||
|
||||
class GBoxedReturn(ReturnType):
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type')
|
||||
|
@ -678,17 +760,64 @@ class GBoxedReturn(ReturnType):
|
|||
def write_error_return(self):
|
||||
self.wrapper.write_code("return retval;")
|
||||
def write_conversion(self):
|
||||
self.wrapper.write_code(
|
||||
self.wrapper.write_code(code = None,
|
||||
failure_expression=("!pyg_boxed_check(py_retval, %s)" %
|
||||
(self.props['typecode'],)),
|
||||
failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
|
||||
% (self.props['typename'],)))
|
||||
failure_exception=(
|
||||
'PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
|
||||
% (self.props['typename'],)))
|
||||
self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
|
||||
self.props['typename'])
|
||||
|
||||
argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
|
||||
|
||||
|
||||
class GdkRegionPtrReturn(GBoxedReturn):
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return gdk_region_new();")
|
||||
def write_conversion(self):
|
||||
self.props['typecode'] = 'PYGDK_TYPE_REGION'
|
||||
self.props['typename'] = 'GdkRegion'
|
||||
super(GdkRegionPtrReturn, self).write_conversion()
|
||||
|
||||
argtypes.matcher.register_reverse_ret("GdkRegion*", GdkRegionPtrReturn)
|
||||
|
||||
|
||||
class PangoFontDescriptionReturn(GBoxedReturn):
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return pango_font_description_new();")
|
||||
def write_conversion(self):
|
||||
self.props['typecode'] = 'PANGO_TYPE_FONT_DESCRIPTION'
|
||||
self.props['typename'] = 'PangoFontDescription'
|
||||
super(PangoFontDescriptionReturn, self).write_conversion()
|
||||
|
||||
argtypes.matcher.register_reverse_ret("PangoFontDescription*",
|
||||
PangoFontDescriptionReturn)
|
||||
|
||||
|
||||
class PangoFontMetricsReturn(GBoxedReturn):
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return pango_font_metrics_new();")
|
||||
def write_conversion(self):
|
||||
self.props['typecode'] = 'PANGO_TYPE_FONT_METRICS'
|
||||
self.props['typename'] = 'PangoFontMetrics'
|
||||
super(PangoFontMetricsReturn, self).write_conversion()
|
||||
|
||||
argtypes.matcher.register_reverse_ret("PangoFontMetrics*",
|
||||
PangoFontMetricsReturn)
|
||||
|
||||
|
||||
class PangoLanguageReturn(GBoxedReturn):
|
||||
def write_error_return(self):
|
||||
self.wrapper.write_code("return pango_language_from_string(\"\");")
|
||||
def write_conversion(self):
|
||||
self.props['typecode'] = 'PANGO_TYPE_LANGUAGE'
|
||||
self.props['typename'] = 'PangoLanguage'
|
||||
super(PangoLanguageReturn, self).write_conversion()
|
||||
|
||||
argtypes.matcher.register_reverse_ret("PangoLanguage*", PangoLanguageReturn)
|
||||
|
||||
|
||||
class GdkRectanglePtrParam(Parameter):
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type').replace('const-', 'const ')
|
||||
|
@ -704,6 +833,17 @@ argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
|
|||
argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
|
||||
|
||||
|
||||
class GErrorParam(Parameter):
|
||||
def get_c_type(self):
|
||||
return self.props.get('c_type').replace('**', ' **')
|
||||
def convert_c2py(self):
|
||||
self.wrapper.write_code(code=None,
|
||||
failure_expression=("pyg_gerror_exception_check(%s)" % self.name),
|
||||
code_sink=self.wrapper.check_exception_code)
|
||||
|
||||
argtypes.matcher.register_reverse('GError**', GErrorParam)
|
||||
|
||||
|
||||
class PyGObjectMethodParam(Parameter):
|
||||
def __init__(self, wrapper, name, method_name, **props):
|
||||
Parameter.__init__(self, wrapper, name, **props)
|
||||
|
@ -720,6 +860,7 @@ class PyGObjectMethodParam(Parameter):
|
|||
failure_expression=("!py_%s" % self.name))
|
||||
self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
|
||||
|
||||
|
||||
class CallbackInUserDataParam(Parameter):
|
||||
def __init__(self, wrapper, name, free_it, **props):
|
||||
Parameter.__init__(self, wrapper, name, **props)
|
||||
|
|
1
bindings/python/codegen/scmexpr.py
Normal file → Executable file
1
bindings/python/codegen/scmexpr.py
Normal file → Executable file
|
@ -3,7 +3,6 @@
|
|||
from __future__ import generators
|
||||
|
||||
import string
|
||||
import types
|
||||
from cStringIO import StringIO
|
||||
|
||||
class error(Exception):
|
||||
|
|
Loading…
Reference in a new issue