r1205@localhost: muntyan | 2005-12-01 09:02:56 -0600

Added codegen
master
Yevgen Muntyan 2005-12-01 22:05:16 +00:00
parent ccee0ebdca
commit c5980502e2
12 changed files with 4756 additions and 4 deletions

View File

@ -10,6 +10,19 @@ moopython_plugins = \
$(moopython)/plugins/pyconsole.py \
$(moopython)/plugins/pystuff.py
moopython_codegen = \
$(moopython)/codegen/__init__.py \
$(moopython)/codegen/argtypes.py \
$(moopython)/codegen/codegen.py \
$(moopython)/codegen/definitions.py \
$(moopython)/codegen/defsparser.py \
$(moopython)/codegen/docgen.py \
$(moopython)/codegen/mergedefs.py \
$(moopython)/codegen/mkskel.py \
$(moopython)/codegen/override.py \
$(moopython)/codegen/reversewrapper.py \
$(moopython)/codegen/scmexpr.py
moopython_sources = \
$(moopython)/moo-pygtk.c \
$(moopython)/moo-pygtk.h \
@ -38,6 +51,7 @@ mooedit_defs_files = \
moopython_extra_dist = \
$(moopython_plugins) \
$(moopython_codegen) \
$(moopython)/moo-mod.py \
$(moopython)/moo-pygtk.c \
$(moopython)/mooapp-mod.py \
@ -91,7 +105,8 @@ endif MOO_BUILD_APP
$(moopython)/mooutils-pygtk.c: $(moopython)/mooutils-pygtk.defs $(moopython)/mooutils-pygtk.override $(mooutils_override_files)
mkdir -p $(moopython)
pygtk-codegen-2.0 --prefix _moo_utils \
$(PYTHON) $(moopython_srcdir)/codegen/codegen.py \
--prefix _moo_utils \
--register $(PYGTK_DEFS_DIR)/gtk-types.defs \
--register $(PYGTK_DEFS_DIR)/gdk-types.defs \
--override $(moopython_srcdir)/mooutils-pygtk.override \
@ -100,7 +115,8 @@ $(moopython)/mooutils-pygtk.c: $(moopython)/mooutils-pygtk.defs $(moopython)/moo
$(moopython)/mooterm-pygtk.c: $(moopython)/mooterm-pygtk.defs $(moopython)/mooterm-pygtk.override
mkdir -p $(moopython)
pygtk-codegen-2.0 --prefix _moo_term \
$(PYTHON) $(moopython_srcdir)/codegen/codegen.py \
--prefix _moo_term \
--register $(PYGTK_DEFS_DIR)/gtk-types.defs \
--register $(PYGTK_DEFS_DIR)/gdk-types.defs \
--register $(moopython_srcdir)/mooutils-pygtk.defs \
@ -110,7 +126,8 @@ $(moopython)/mooterm-pygtk.c: $(moopython)/mooterm-pygtk.defs $(moopython)/moote
$(moopython)/mooedit-pygtk.c: $(moopython)/mooedit-pygtk.defs $(moopython)/mooedit-pygtk.override $(mooedit_defs_files)
mkdir -p $(moopython)
pygtk-codegen-2.0 --prefix _moo_edit \
$(PYTHON) $(moopython_srcdir)/codegen/codegen.py \
--prefix _moo_edit \
--register $(PYGTK_DEFS_DIR)/gtk-types.defs \
--register $(PYGTK_DEFS_DIR)/gdk-types.defs \
--register $(moopython_srcdir)/mooutils-pygtk.defs \
@ -120,7 +137,8 @@ $(moopython)/mooedit-pygtk.c: $(moopython)/mooedit-pygtk.defs $(moopython)/mooed
$(moopython)/mooapp-pygtk.c: $(moopython)/mooapp-pygtk.defs $(moopython)/mooapp-pygtk.override
mkdir -p $(moopython)
pygtk-codegen-2.0 --prefix _moo_app \
$(PYTHON) $(moopython_srcdir)/codegen/codegen.py \
--prefix _moo_app \
--register $(PYGTK_DEFS_DIR)/gtk-types.defs \
--register $(PYGTK_DEFS_DIR)/gdk-types.defs \
--register $(moopython_srcdir)/mooedit-pygtk.defs \

View File

@ -0,0 +1,15 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
__all__ = [
'argtypes',
'codegen',
'definitions',
'defsparser',
'docextract',
'docgen',
'h2def',
'mergedefs',
'mkskel',
'override',
'scmexpr'
]

View File

@ -0,0 +1,950 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
import string
import traceback
import keyword
import struct
class VarList:
"""Nicely format a C variable list"""
def __init__(self):
self.vars = {}
def add(self, ctype, name):
if self.vars.has_key(ctype):
self.vars[ctype] = self.vars[ctype] + (name,)
else:
self.vars[ctype] = (name,)
def __str__(self):
ret = []
for type in self.vars.keys():
ret.append(' ')
ret.append(type)
ret.append(' ')
ret.append(string.join(self.vars[type], ', '))
ret.append(';\n')
if ret:
ret.append('\n')
return string.join(ret, '')
return ''
class WrapperInfo:
"""A class that holds information about variable defs, code
snippets, etcd for use in writing out the function/method
wrapper."""
def __init__(self):
self.varlist = VarList()
self.parsestr = ''
self.parselist = ['', 'kwlist']
self.codebefore = []
self.codeafter = []
self.arglist = []
self.kwlist = []
def get_parselist(self):
return string.join(self.parselist, ', ')
def get_codebefore(self):
return string.join(self.codebefore, '')
def get_codeafter(self):
return string.join(self.codeafter, '')
def get_arglist(self):
return string.join(self.arglist, ', ')
def get_varlist(self):
return str(self.varlist)
def get_kwlist(self):
ret = ' static char *kwlist[] = { %s };\n' % \
string.join(self.kwlist + [ 'NULL' ], ', ')
if not self.get_varlist():
ret = ret + '\n'
return ret
def add_parselist(self, codes, parseargs, keywords):
self.parsestr = self.parsestr + codes
for arg in parseargs:
self.parselist.append(arg)
for kw in keywords:
if keyword.iskeyword(kw):
kw = kw + '_'
self.kwlist.append('(char*)"%s"' % kw)
class ArgType:
def write_param(self, ptype, pname, pdflt, pnull, info):
"""Add code to the WrapperInfo instance to handle
parameter."""
raise RuntimeError, "write_param not implemented for %s" % \
self.__class__.__name__
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__
class NoneArg(ArgType):
def write_return(self, ptype, ownsreturn, info):
info.codeafter.append(' Py_INCREF(Py_None);\n' +
' return Py_None;')
class StringArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
if pdflt != 'NULL': pdflt = '"' + pdflt + '"'
info.varlist.add('char', '*' + pname + ' = ' + pdflt)
else:
info.varlist.add('char', '*' + pname)
info.arglist.append(pname)
if pnull:
info.add_parselist('z', ['&' + pname], [pname])
else:
info.add_parselist('s', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
if ownsreturn:
# have to free result ...
info.varlist.add('gchar', '*ret')
info.codeafter.append(' if (ret) {\n' +
' PyObject *py_ret = PyString_FromString(ret);\n' +
' g_free(ret);\n' +
' return py_ret;\n' +
' }\n' +
' Py_INCREF(Py_None);\n' +
' return Py_None;')
else:
info.varlist.add('const gchar', '*ret')
info.codeafter.append(' if (ret)\n' +
' return PyString_FromString(ret);\n'+
' Py_INCREF(Py_None);\n' +
' return Py_None;')
class UCharArg(ArgType):
# allows strings with embedded NULLs.
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')
info.arglist.append(pname)
if pnull:
info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'],
[pname])
else:
info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'],
[pname])
class CharArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('char', pname + " = '" + pdflt + "'")
else:
info.varlist.add('char', pname)
info.arglist.append(pname)
info.add_parselist('c', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gchar', 'ret')
info.codeafter.append(' return PyString_FromStringAndSize(&ret, 1);')
class GUniCharArg(ArgType):
ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n'
' if (ret > 0xffff) {\n'
' PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n'
' return NULL;\n'
' }\n'
'#endif\n'
' py_ret = (Py_UNICODE)ret;\n'
' return PyUnicode_FromUnicode(&py_ret, 1);\n')
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
else:
info.varlist.add('gunichar', pname)
info.arglist.append(pname)
info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gunichar', 'ret')
info.varlist.add('Py_UNICODE', 'py_ret')
info.codeafter.append(self.ret_tmpl)
class IntArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('int', pname + ' = ' + pdflt)
else:
info.varlist.add('int', pname)
info.arglist.append(pname)
info.add_parselist('i', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('int', 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);')
class UIntArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
info.add_parselist('I', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
class SizeArg(ArgType):
if struct.calcsize('P') <= struct.calcsize('l'):
llp64 = True
else:
llp64 = False
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
if self.llp64:
info.add_parselist('k', ['&' + pname], [pname])
else:
info.add_parselist('K', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
if self.llp64:
info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);\n')
else:
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
class SSizeArg(ArgType):
if struct.calcsize('P') <= struct.calcsize('l'):
llp64 = True
else:
llp64 = False
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
if self.llp64:
info.add_parselist('l', ['&' + pname], [pname])
else:
info.add_parselist('L', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
if self.llp64:
info.codeafter.append(' return PyLong_FromLongLong(ret);\n')
else:
info.codeafter.append(' return PyLong_FromLong(ret);\n')
class LongArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
info.add_parselist('l', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);\n')
class BoolArg(IntArg):
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('int', 'ret')
info.codeafter.append(' return PyBool_FromLong(ret);\n')
class TimeTArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('time_t', pname + ' = ' + pdflt)
else:
info.varlist.add('time_t', pname)
info.arglist.append(pname)
info.add_parselist('i', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('time_t', 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);')
class ULongArg(ArgType):
dflt = ' if (py_%(name)s)\n' \
' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
before = ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('gulong', pname + ' = ' + pdflt)
info.codebefore.append(self.dflt % {'name':pname})
else:
info.varlist.add('gulong', pname)
info.codebefore.append(self.before % {'name':pname})
info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
info.arglist.append(pname)
info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gulong', 'ret')
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);')
class Int64Arg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('gint64', pname + ' = ' + pdflt)
else:
info.varlist.add('gint64', pname)
info.arglist.append(pname)
info.add_parselist('L', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gint64', 'ret')
info.codeafter.append(' return PyLong_FromLongLong(ret);')
class UInt64Arg(ArgType):
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('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, info):
if pdflt:
info.varlist.add('double', pname + ' = ' + pdflt)
else:
info.varlist.add('double', pname)
info.arglist.append(pname)
info.add_parselist('d', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('double', 'ret')
info.codeafter.append(' return PyFloat_FromDouble(ret);')
class FileArg(ArgType):
nulldflt = (' if (py_%(name)s == Py_None)\n'
' %(name)s = NULL;\n'
' else if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
' %s = PyFile_AsFile(py_%(name)s);\n'
' else if (py_%(name)s) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
' return NULL;\n'
' }')
null = (' if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
' %(name)s = PyFile_AsFile(py_%(name)s);\n'
' else if (py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
' return NULL;\n'
' }\n')
dflt = (' if (py_%(name)s)\n'
' %(name)s = PyFile_AsFile(py_%(name)s);\n')
def write_param(self, ptype, pname, pdflt, pnull, info):
if pnull:
if pdflt:
info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.nulldflt % {'name':pname})
else:
info.varlist.add('FILE', '*' + pname + ' = NULL')
info.varlist.add('PyObject', '*py_' + pname)
info.codebefore.append(self.null & {'name':pname})
info.arglist.appned(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
else:
if pdflt:
info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.dflt % {'name':pname})
info.arglist.append(pname)
else:
info.varlist.add('PyObject', '*' + pname)
info.arglist.append('PyFile_AsFile(' + pname + ')')
info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('FILE', '*ret')
info.codeafter.append(' if (ret)\n' +
' return PyFile_FromFile(ret, "", "", fclose);\n' +
' Py_INCREF(Py_None);\n' +
' return Py_None;')
class EnumArg(ArgType):
enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gint *)&%(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, info):
if pdflt:
info.varlist.add(self.enumname, pname + ' = ' + pdflt)
else:
info.varlist.add(self.enumname, pname)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.enum % { 'typecode': self.typecode,
'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname]);
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gint', 'ret')
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'
' return NULL;\n')
def __init__(self, flagname, typecode):
self.flagname = flagname
self.typecode = typecode
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(self.flagname, pname + ' = ' + pdflt)
default = "py_%s && " % (pname,)
else:
info.varlist.add(self.flagname, pname)
default = ""
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.flag % {'default':default,
'typecode':self.typecode,
'name':pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('guint', 'ret')
info.codeafter.append(' return pyg_flags_from_gtype(%s, ret);' % self.typecode)
class ObjectArg(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 && pygobject_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 && pygobject_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, info):
if pnull:
if pdflt:
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
info.varlist.add('PyGObject', '*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('PyGObject', '*py_' + pname)
info.codebefore.append(self.null % {'name':pname,
'cast':self.cast,
'type':self.objname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
else:
if pdflt:
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
info.varlist.add('PyGObject', '*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('PyGObject', '*' + pname)
info.arglist.append('%s(%s->obj)' % (self.cast, pname))
info.add_parselist('O!', ['&Py%s_Type' % self.objname,
'&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
if ptype[-1] == '*': ptype = ptype[:-1]
info.varlist.add(ptype, '*ret')
if ownsreturn:
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
' if (ret != NULL)\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 BoxedArg(ArgType):
# haven't done support for default args. Is it needed?
check = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
' else {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
' return NULL;\n'
' }\n')
null = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
' else if (py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
' return NULL;\n'
' }\n')
def __init__(self, ptype, typecode):
self.typename = ptype
self.typecode = typecode
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')
info.codebefore.append(self.null % {'name': pname,
'typename': self.typename,
'typecode': self.typecode})
else:
info.varlist.add(self.typename, '*' + pname + ' = NULL')
info.varlist.add('PyObject', '*py_' + pname)
info.codebefore.append(self.check % {'name': pname,
'typename': self.typename,
'typecode': self.typecode})
if ptype[-1] == '*':
typename = ptype[:-1]
if typename[:6] == 'const-': typename = typename[6:]
if typename != self.typename:
info.arglist.append('(%s *)%s' % (ptype[:-1], pname))
else:
info.arglist.append(pname)
else:
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
ret_tmpl = ' /* pyg_boxed_new handles NULL checking */\n' \
' 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')
ret = 'ret'
else:
info.varlist.add(self.typename, 'ret')
ret = '&ret'
ownsreturn = 0 # of course it can't own a ref to a local var ...
info.codeafter.append(self.ret_tmpl %
{ 'typecode': self.typecode,
'ret': ret,
'copy': ownsreturn and 'FALSE' or 'TRUE'})
class CustomBoxedArg(ArgType):
# haven't done support for default args. Is it needed?
null = (' if (%(check)s(py_%(name)s))\n'
' %(name)s = %(get)s(py_%(name)s);\n'
' else if (py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
' return NULL;\n'
' }\n')
def __init__(self, ptype, pytype, getter, new):
self.pytype = pytype
self.getter = getter
self.checker = 'Py' + ptype + '_Check'
self.new = new
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')
info.codebefore.append(self.null % {'name': pname,
'get': self.getter,
'check': self.checker,
'type': ptype[:-1]})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
else:
info.varlist.add('PyObject', '*' + pname)
info.arglist.append(self.getter + '(' + pname + ')')
info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype[:-1], '*ret')
info.codeafter.append(' if (ret)\n' +
' return ' + self.new + '(ret);\n' +
' Py_INCREF(Py_None);\n' +
' return Py_None;')
class PointerArg(ArgType):
# haven't done support for default args. Is it needed?
check = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
' else {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
' return NULL;\n'
' }\n')
null = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
' else if (py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
' return NULL;\n'
' }\n')
def __init__(self, ptype, typecode):
self.typename = ptype
self.typecode = typecode
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')
info.codebefore.append(self.null % {'name': pname,
'typename': self.typename,
'typecode': self.typecode})
else:
info.varlist.add(self.typename, '*' + pname + ' = NULL')
info.varlist.add('PyObject', '*py_' + pname)
info.codebefore.append(self.check % {'name': pname,
'typename': self.typename,
'typecode': self.typecode})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
if ptype[-1] == '*':
info.varlist.add(self.typename, '*ret')
info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' +
' return pyg_pointer_new(' + self.typecode + ', ret);')
else:
info.varlist.add(self.typename, 'ret')
info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' +
' return pyg_pointer_new(' + self.typecode + ', &ret);')
class AtomArg(IntArg):
dflt = ' if (py_%(name)s) {\n' \
' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \
' if (PyErr_Occurred())\n' \
' return NULL;\n' \
' }\n'
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, info):
if pdflt:
info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.dflt % {'name': pname})
else:
info.varlist.add('GdkAtom', pname)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.atom % {'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('GdkAtom', 'ret')
info.codeafter.append(' return PyString_FromString(gdk_atom_name(ret));')
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, info):
info.varlist.add('GType', pname)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.gtype % {'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('GType', 'ret')
info.codeafter.append(' return pyg_type_wrapper_new(ret);')
# simple GError handler.
class GErrorArg(ArgType):
handleerror = (' if (pyg_error_check(&%(name)s))\n'
' return NULL;\n')
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 })
class GtkTreePathArg(ArgType):
# haven't done support for default args. Is it needed?
normal = (' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
' if (!%(name)s) {\n'
' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
' return NULL;\n'
' }\n')
null = (' if (py_%(name)s != Py_None) {\n'
' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
' if (!%(name)s) {\n'
' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
' return NULL;\n'
' }\n'
' }\n')
freepath = (' if (%(name)s)\n'
' gtk_tree_path_free(%(name)s);\n')
def __init__(self):
pass
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')
info.codebefore.append(self.null % {'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
else:
info.varlist.add('GtkTreePath', '*' + pname)
info.varlist.add('PyObject', '*py_' + pname)
info.codebefore.append(self.normal % {'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
info.codeafter.append(self.freepath % {'name': pname})
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('GtkTreePath', '*ret')
if ownsreturn:
info.codeafter.append(' if (ret) {\n'
' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
' gtk_tree_path_free(ret);\n'
' return py_ret;\n'
' }\n'
' Py_INCREF(Py_None);\n'
' return Py_None;')
else:
info.codeafter.append(' if (ret) {\n'
' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
' return py_ret;\n'
' }\n'
' Py_INCREF(Py_None);\n'
' return Py_None;')
class GdkRectanglePtrArg(ArgType):
normal = (' if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n'
' return NULL;\n')
null = (' if (py_%(name)s == Py_None)\n'
' %(name)s = NULL;\n'
' else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n'
' %(name)s = &%(name)s_rect;\n'
' else\n'
' return NULL;\n')
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)
info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
info.add_parselist('O', ['&py_' + pname], [pname])
info.arglist.append(pname)
info.codebefore.append(self.null % {'name': pname})
else:
info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }')
info.varlist.add('PyObject', '*py_' + pname)
info.add_parselist('O', ['&py_' + pname], [pname])
info.arglist.append('&' + pname)
info.codebefore.append(self.normal % {'name': pname})
class GdkRectangleArg(ArgType):
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('GdkRectangle', 'ret')
info.codeafter.append(' return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);')
class PyObjectArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
info.varlist.add('PyObject', '*' + pname)
info.add_parselist('O', ['&' + pname], [pname])
info.arglist.append(pname)
def write_return(self, ptype, ownsreturn, info):
info.varlist.add("PyObject", "*ret")
if ownsreturn:
info.codeafter.append(' if (ret) {\n'
' return ret;\n'
' }\n'
' Py_INCREF(Py_None);\n'
' return Py_None;')
else:
info.codeafter.append(' if (!ret) ret = Py_None;\n'
' Py_INCREF(ret);\n'
' return ret;')
class ArgMatcher:
def __init__(self):
self.argtypes = {}
self.reverse_argtypes = {}
self.reverse_rettypes = {}
def register(self, ptype, handler):
self.argtypes[ptype] = handler
def register_reverse(self, ptype, handler):
self.reverse_argtypes[ptype] = handler
def register_reverse_ret(self, ptype, handler):
self.reverse_rettypes[ptype] = handler
def register_enum(self, ptype, typecode):
if typecode is None:
typecode = "G_TYPE_NONE"
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))
def register_object(self, ptype, parent, typecode):
oa = ObjectArg(ptype, parent, typecode)
self.register(ptype, oa) # in case I forget the * in the .defs
self.register(ptype+'*', oa)
if ptype == 'GdkPixmap':
# hack to handle GdkBitmap synonym.
self.register('GdkBitmap', oa)
self.register('GdkBitmap*', oa)
def register_boxed(self, ptype, typecode):
if self.argtypes.has_key(ptype): return
arg = BoxedArg(ptype, typecode)
self.register(ptype, arg)
self.register(ptype+'*', arg)
self.register('const-'+ptype+'*', arg)
def register_custom_boxed(self, ptype, pytype, getter, new):
arg = CustomBoxedArg(ptype, pytype, getter, new)
self.register(ptype+'*', arg)
self.register('const-'+ptype+'*', arg)
def register_pointer(self, ptype, typecode):
arg = PointerArg(ptype, typecode)
self.register(ptype, arg)
self.register(ptype+'*', arg)
self.register('const-'+ptype+'*', arg)
def get(self, ptype):
try:
return self.argtypes[ptype]
except KeyError:
if ptype[:8] == 'GdkEvent' and ptype[-1] == '*':
return self.argtypes['GdkEvent*']
raise
def _get_reverse_common(self, ptype, registry):
props = dict(c_type=ptype)
try:
return registry[ptype], props
except KeyError:
try:
handler = self.argtypes[ptype]
except KeyError:
if ptype.startswith('GdkEvent') and ptype.endswith('*'):
handler = self.argtypes['GdkEvent*']
else:
raise
if isinstance(handler, ObjectArg):
return registry['GObject*'], props
elif isinstance(handler, EnumArg):
props['typecode'] = handler.typecode
props['enumname'] = handler.enumname
return registry['GEnum'], props
elif isinstance(handler, FlagsArg):
props['typecode'] = handler.typecode
props['flagname'] = handler.flagname
return registry['GFlags'], props
elif isinstance(handler, BoxedArg):
props['typecode'] = handler.typecode
props['typename'] = handler.typename
return registry['GBoxed'], props
else:
raise
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)
def object_is_a(self, otype, parent):
if otype == None: return 0
if otype == parent: return 1
if not self.argtypes.has_key(otype): return 0
return self.object_is_a(self.get(otype).parent, parent)
matcher = ArgMatcher()
arg = NoneArg()
matcher.register(None, arg)
matcher.register('none', arg)
arg = StringArg()
matcher.register('char*', arg)
matcher.register('gchar*', arg)
matcher.register('const-char*', arg)
matcher.register('char-const*', arg)
matcher.register('const-gchar*', arg)
matcher.register('gchar-const*', arg)
matcher.register('string', arg)
matcher.register('static_string', arg)
arg = UCharArg()
matcher.register('unsigned-char*', arg)
matcher.register('const-guchar*', arg)
matcher.register('guchar*', arg)
arg = CharArg()
matcher.register('char', arg)
matcher.register('gchar', arg)
matcher.register('guchar', arg)
arg = GUniCharArg()
matcher.register('gunichar', arg)
arg = IntArg()
matcher.register('int', arg)
matcher.register('gint', arg)
matcher.register('short', arg)
matcher.register('gshort', arg)
matcher.register('gushort', arg)
matcher.register('gsize', SizeArg())
matcher.register('gssize', SSizeArg())
matcher.register('guint8', arg)
matcher.register('gint8', arg)
matcher.register('guint16', arg)
matcher.register('gint16', arg)
matcher.register('gint32', arg)
matcher.register('GTime', arg)
arg = LongArg()
matcher.register('long', arg)
matcher.register('glong', arg)
arg = UIntArg()
matcher.register('guint', arg)
arg = BoolArg()
matcher.register('gboolean', arg)
arg = TimeTArg()
matcher.register('time_t', arg)
# If the system maxint is smaller than unsigned int, we need to use
# Long objects with PyLong_AsUnsignedLong
if sys.maxint >= (1L << 32):
matcher.register('guint32', arg)
else:
arg = ULongArg()
matcher.register('guint32', arg)
arg = ULongArg()
matcher.register('gulong', arg)
arg = Int64Arg()
matcher.register('gint64', arg)
matcher.register('long-long', arg)
arg = UInt64Arg()
matcher.register('guint64', arg)
matcher.register('unsigned-long-long', arg)
arg = DoubleArg()
matcher.register('double', arg)
matcher.register('gdouble', arg)
matcher.register('float', arg)
matcher.register('gfloat', arg)
arg = FileArg()
matcher.register('FILE*', arg)
# enums, flags, objects
matcher.register('GdkAtom', AtomArg())
matcher.register('GType', GTypeArg())
matcher.register('GtkType', GTypeArg())
matcher.register('GError**', GErrorArg())
matcher.register('GtkTreePath*', GtkTreePathArg())
matcher.register('GdkRectangle*', GdkRectanglePtrArg())
matcher.register('GtkAllocation*', GdkRectanglePtrArg())
matcher.register('GdkRectangle', GdkRectangleArg())
matcher.register('PyObject*', PyObjectArg())
matcher.register('GdkNativeWindow', ULongArg())
matcher.register_object('GObject', None, 'G_TYPE_OBJECT')
del arg

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,532 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
from copy import *
def get_valid_scheme_definitions(defs):
return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]
def unescape(s):
s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t')
return s.replace('\r', '\\r').replace('\n', '\\n')
def make_docstring(lines):
return "(char*)" + '\n'.join(['"%s"' % unescape(s) for s in lines])
# New Parameter class, wich emulates a tuple for compatibility reasons
class Parameter(object):
def __init__(self, ptype, pname, pdflt, pnull, prop=None):
self.ptype = ptype
self.pname = pname
self.pdflt = pdflt
self.pnull = pnull
def __len__(self): return 4
def __getitem__(self, i):
return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
def merge(self, old):
if old.pdflt is not None:
self.pdflt = old.pdflt
if old.pnull is not None:
self.pnull = old.pnull
# Parameter for property based constructors
class Property(object):
def __init__(self, pname, optional, argname):
self.pname = pname
self.optional = optional
self.argname = argname
def merge(self, old):
if old.optional is not None:
self.optional = old.optional
if old.argname is not None:
self.argname = old.argname
class Definition:
docstring = "NULL"
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"
def merge(self, old):
"""Merge in customisations from older version of definition"""
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"
def guess_return_value_ownership(self):
"return 1 if caller owns return value"
if getattr(self, 'is_constructor_of', False):
self.caller_owns_return = True
elif self.ret in ('char*', 'gchar*', 'string'):
self.caller_owns_return = True
else:
self.caller_owns_return = False
class ObjectDef(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 = []
self.class_init_func = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(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')
class InterfaceDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.vtable = None
self.fields = []
self.interface_info = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'vtable':
self.vtable = arg[1]
if self.vtable is None:
self.vtable = self.c_name + "Iface"
def write_defs(self, fp=sys.stdout):
fp.write('(define-interface ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\n')
if self.c_name:
fp.write(' (c-name "' + self.c_name + '")\n')
if self.typecode:
fp.write(' (gtype-id "' + self.typecode + '")\n')
fp.write(')\n\n')
class EnumDef(Definition):
def __init__(self, name, *args):
self.deftype = 'enum'
self.name = name
self.in_module = None
self.c_name = None
self.typecode = None
self.values = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.in_module = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'values':
for varg in arg[1:]:
self.values.append((varg[0], varg[1]))
def merge(self, old):
pass
def write_defs(self, fp=sys.stdout):
fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
if self.in_module:
fp.write(' (in-module "' + self.in_module + '")\n')
fp.write(' (c-name "' + self.c_name + '")\n')
fp.write(' (gtype-id "' + self.typecode + '")\n')
if self.values:
fp.write(' (values\n')
for name, val in self.values:
fp.write(' \'("' + name + '" "' + val + '")\n')
fp.write(' )\n')
fp.write(')\n\n')
class FlagsDef(EnumDef):
def __init__(self, *args):
apply(EnumDef.__init__, (self,) + args)
self.deftype = 'flags'
class BoxedDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.copy = None
self.release = None
self.fields = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'copy-func':
self.copy = arg[1]
elif arg[0] == 'release-func':
self.release = arg[1]
elif arg[0] == 'fields':
for parg in arg[1:]:
self.fields.append((parg[0], parg[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
def write_defs(self, fp=sys.stdout):
fp.write('(define-boxed ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\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.copy:
fp.write(' (copy-func "' + self.copy + '")\n')
if self.release:
fp.write(' (release-func "' + self.release + '")\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')
class PointerDef(Definition):
def __init__(self, name, *args):
self.name = name
self.module = None
self.c_name = None
self.typecode = None
self.fields = []
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.module = 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]))
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
def write_defs(self, fp=sys.stdout):
fp.write('(define-pointer ' + self.name + '\n')
if self.module:
fp.write(' (in-module "' + self.module + '")\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')
class MethodDefBase(Definition):
def __init__(self, name, *args):
dump = 0
self.name = name
self.ret = None
self.caller_owns_return = None
self.c_name = None
self.typecode = None
self.of_object = None
self.params = [] # of form (type, name, default, nullok)
self.varargs = 0
self.deprecated = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'of-object':
self.of_object = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'return-type':
self.ret = arg[1]
elif arg[0] == 'caller-owns-return':
self.caller_owns_return = arg[1] in ('t', '#t')
elif arg[0] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
for farg in parg[2:]:
assert isinstance(farg, tuple)
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
self.params.append(Parameter(ptype, pname, pdflt, pnull))
elif arg[0] == 'varargs':
self.varargs = arg[1] in ('t', '#t')
elif arg[0] == 'deprecated':
self.deprecated = arg[1]
else:
sys.stderr.write("Warning: %s argument unsupported.\n"
% (arg[0]))
dump = 1
if dump:
self.write_defs(sys.stderr)
if self.caller_owns_return is None and self.ret is not None:
self.guess_return_value_ownership()
def merge(self, old, parmerge):
self.caller_owns_return = old.caller_owns_return
self.varargs = old.varargs
# here we merge extra parameter flags accross to the new object.
if not parmerge:
self.params = deepcopy(old.params)
return
for i in range(len(self.params)):
ptype, pname, pdflt, pnull = self.params[i]
for p2 in old.params:
if p2[1] == pname:
self.params[i] = (ptype, pname, p2[2], p2[3])
break
def _write_defs(self, fp=sys.stdout):
if self.of_object != (None, None):
fp.write(' (of-object "' + self.of_object + '")\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.caller_owns_return:
fp.write(' (caller-owns-return #t)\n')
if self.ret:
fp.write(' (return-type "' + self.ret + '")\n')
if self.deprecated:
fp.write(' (deprecated "' + self.deprecated + '")\n')
if self.params:
fp.write(' (parameters\n')
for ptype, pname, pdflt, pnull in self.params:
fp.write(' \'("' + ptype + '" "' + pname +'"')
if pdflt: fp.write(' (default "' + pdflt + '")')
if pnull: fp.write(' (null-ok)')
fp.write(')\n')
fp.write(' )\n')
if self.varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')
class MethodDef(MethodDefBase):
def __init__(self, name, *args):
MethodDefBase.__init__(self, name, *args)
for item in ('c_name', 'of_object'):
if self.__dict__[item] == None:
self.write_defs(sys.stderr)
raise RuntimeError, "definition missing required %s" % (item,)
def write_defs(self, fp=sys.stdout):
fp.write('(define-method ' + self.name + '\n')
self._write_defs(fp)
class VirtualDef(MethodDefBase):
def write_defs(self, fp=sys.stdout):
fp.write('(define-virtual ' + self.name + '\n')
self._write_defs(fp)
class FunctionDef(Definition):
def __init__(self, name, *args):
dump = 0
self.name = name
self.in_module = None
self.is_constructor_of = None
self.ret = None
self.caller_owns_return = None
self.c_name = None
self.typecode = None
self.params = [] # of form (type, name, default, nullok)
self.varargs = 0
self.deprecated = None
for arg in get_valid_scheme_definitions(args):
if arg[0] == 'in-module':
self.in_module = arg[1]
elif arg[0] == 'docstring':
self.docstring = make_docstring(arg[1:])
elif arg[0] == 'is-constructor-of':
self.is_constructor_of = arg[1]
elif arg[0] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
elif arg[0] == 'return-type':
self.ret = arg[1]
elif arg[0] == 'caller-owns-return':
self.caller_owns_return = arg[1] in ('t', '#t')
elif arg[0] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
for farg in parg[2:]:
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
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"
for prop in arg[1:]:
pname = prop[0]
optional = False
argname = pname
for farg in prop[1:]:
if farg[0] == 'optional':
optional = True
elif farg[0] == 'argname':
argname = farg[1]
self.params.append(Property(pname, optional, argname))
elif arg[0] == 'varargs':
self.varargs = arg[1] in ('t', '#t')
elif arg[0] == 'deprecated':
self.deprecated = arg[1]
else:
sys.stderr.write("Warning: %s argument unsupported\n"
% (arg[0],))
dump = 1
if dump:
self.write_defs(sys.stderr)
if self.caller_owns_return is None and self.ret is not None:
self.guess_return_value_ownership()
for item in ('c_name',):
if self.__dict__[item] == None:
self.write_defs(sys.stderr)
raise RuntimeError, "definition missing required %s" % (item,)
_method_write_defs = MethodDef.__dict__['write_defs']
def merge(self, old, parmerge):
self.caller_owns_return = old.caller_owns_return
self.varargs = old.varargs
if not parmerge:
self.params = deepcopy(old.params)
return
# here we merge extra parameter flags accross to the new object.
def merge_param(param):
for old_param in old.params:
if old_param.pname == param.pname:
if isinstance(old_param, Property):
# h2def never scans Property's, therefore if
# we have one it was manually written, so we
# keep it.
return deepcopy(old_param)
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])
try:
self.params = map(merge_param, self.params)
except RuntimeError:
# parameter names changed and we can't find a match; it's
# safer to keep the old parameter list untouched.
self.params = deepcopy(old.params)
if not self.is_constructor_of:
try:
self.is_constructor_of = old.is_constructor_of
except AttributeError:
pass
if isinstance(old, MethodDef):
self.name = old.name
# transmogrify from function into method ...
self.write_defs = self._method_write_defs
self.of_object = old.of_object
del self.params[0]
def write_defs(self, fp=sys.stdout):
fp.write('(define-function ' + self.name + '\n')
if self.in_module:
fp.write(' (in-module "' + self.in_module + '")\n')
if self.is_constructor_of:
fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\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.caller_owns_return:
fp.write(' (caller-owns-return #t)\n')
if self.ret:
fp.write(' (return-type "' + self.ret + '")\n')
if self.deprecated:
fp.write(' (deprecated "' + self.deprecated + '")\n')
if self.params:
if isinstance(self.params[0], Parameter):
fp.write(' (parameters\n')
for ptype, pname, pdflt, pnull in self.params:
fp.write(' \'("' + ptype + '" "' + pname +'"')
if pdflt: fp.write(' (default "' + pdflt + '")')
if pnull: fp.write(' (null-ok)')
fp.write(')\n')
fp.write(' )\n')
elif isinstance(self.params[0], Property):
fp.write(' (properties\n')
for prop in self.params:
fp.write(' \'("' + prop.pname +'"')
if prop.optional: fp.write(' (optional)')
fp.write(')\n')
fp.write(' )\n')
else:
assert False, "strange parameter list %r" % self.params[0]
if self.varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')

View File

@ -0,0 +1,133 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import os, sys
import scmexpr
from definitions import *
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
class DefsParser(IncludeParser):
def __init__(self, arg, defines={}):
IncludeParser.__init__(self, arg)
self.objects = []
self.interfaces = []
self.enums = [] # enums and flags
self.boxes = [] # boxed types
self.pointers = [] # pointer types
self.functions = [] # functions and methods
self.virtuals = [] # virtual methods
self.c_name = {} # hash of c names of functions
self.methods = {} # hash of methods of particular objects
self.defines = defines # -Dfoo=bar options, as dictionary
def define_object(self, *args):
odef = apply(ObjectDef, args)
self.objects.append(odef)
self.c_name[odef.c_name] = odef
def define_interface(self, *args):
idef = apply(InterfaceDef, args)
self.interfaces.append(idef)
self.c_name[idef.c_name] = idef
def define_enum(self, *args):
edef = apply(EnumDef, args)
self.enums.append(edef)
self.c_name[edef.c_name] = edef
def define_flags(self, *args):
fdef = apply(FlagsDef, args)
self.enums.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_boxed(self, *args):
bdef = apply(BoxedDef, args)
self.boxes.append(bdef)
self.c_name[bdef.c_name] = bdef
def define_pointer(self, *args):
pdef = apply(PointerDef, args)
self.pointers.append(pdef)
self.c_name[pdef.c_name] = pdef
def define_function(self, *args):
fdef = apply(FunctionDef, args)
self.functions.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_method(self, *args):
mdef = apply(MethodDef, args)
self.functions.append(mdef)
self.c_name[mdef.c_name] = mdef
def define_virtual(self, *args):
vdef = apply(VirtualDef, args)
self.virtuals.append(vdef)
def merge(self, old, parmerge):
for obj in self.objects:
if old.c_name.has_key(obj.c_name):
obj.merge(old.c_name[obj.c_name])
for f in self.functions:
if old.c_name.has_key(f.c_name):
f.merge(old.c_name[f.c_name], parmerge)
def printMissing(self, old):
for obj in self.objects:
if not old.c_name.has_key(obj.c_name):
obj.write_defs()
for f in self.functions:
if not old.c_name.has_key(f.c_name):
f.write_defs()
def write_defs(self, fp=sys.stdout):
for obj in self.objects:
obj.write_defs(fp)
for enum in self.enums:
enum.write_defs(fp)
for boxed in self.boxes:
boxed.write_defs(fp)
for pointer in self.pointers:
pointer.write_defs(fp)
for func in self.functions:
func.write_defs(fp)
def find_object(self, c_name):
for obj in self.objects:
if obj.c_name == c_name:
return obj
else:
raise ValueError, 'object not found'
def find_constructor(self, obj, overrides):
for func in self.functions:
if isinstance(func, FunctionDef) and \
func.is_constructor_of == obj.c_name and \
not overrides.is_ignored(func.c_name):
return func
def find_methods(self, obj):
objname = obj.c_name
return filter(lambda func, on=objname: isinstance(func, MethodDef) and
func.of_object == on, self.functions)
def find_virtuals(self, obj):
objname = obj.c_name
retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and
func.of_object == on, self.virtuals)
return retval
def find_functions(self):
return filter(lambda func: isinstance(func, FunctionDef) and
not func.is_constructor_of, self.functions)
def ifdef(self, *args):
if args[0] in self.defines:
for arg in args[1:]:
self.handle(arg)
def ifndef(self, *args):
if args[0] not in self.defines:
for arg in args[1:]:
self.handle(arg)

View File

@ -0,0 +1,751 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys, os, string, re, getopt
import defsparser
import definitions
import override
import docextract
class Node:
def __init__(self, name, interfaces=[]):
self.name = name
self.interfaces = interfaces
self.subclasses = []
def add_child(self, node):
self.subclasses.append(node)
def build_object_tree(parser):
# reorder objects so that parent classes come first ...
objects = parser.objects[:]
pos = 0
while pos < len(objects):
parent = objects[pos].parent
for i in range(pos+1, len(objects)):
if objects[i].c_name == parent:
objects.insert(i+1, objects[pos])
del objects[pos]
break
else:
pos = pos + 1
root = Node(None)
nodes = { None: root }
for obj_def in objects:
parent_node = nodes[obj_def.parent]
node = Node(obj_def.c_name, obj_def.implements)
parent_node.add_child(node)
nodes[node.name] = node
if parser.interfaces:
interfaces = Node('gobject.GInterface')
root.add_child(interfaces)
nodes[interfaces.name] = interfaces
for obj_def in parser.interfaces:
node = Node(obj_def.c_name)
interfaces.add_child(node)
nodes[node.name] = node
if parser.boxes:
boxed = Node('gobject.GBoxed')
root.add_child(boxed)
nodes[boxed.name] = boxed
for obj_def in parser.boxes:
node = Node(obj_def.c_name)
boxed.add_child(node)
nodes[node.name] = node
if parser.pointers:
pointers = Node('gobject.GPointer')
root.add_child(pointers)
nodes[pointers.name] = pointers
for obj_def in parser.pointers:
node = Node(obj_def.c_name)
pointers.add_child(node)
nodes[node.name] = node
return root
class DocWriter:
def __init__(self):
# parse the defs file
self.parser = defsparser.DefsParser(())
self.overrides = override.Overrides()
self.classmap = {}
self.docs = {}
def add_sourcedirs(self, source_dirs):
self.docs = docextract.extract(source_dirs, self.docs)
def add_tmpldirs(self, tmpl_dirs):
self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs)
def add_docs(self, defs_file, overrides_file, module_name):
'''parse information about a given defs file'''
self.parser.filename = defs_file
self.parser.startParsing(defs_file)
if overrides_file:
self.overrides.handle_file(overrides_file)
for obj in self.parser.objects:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.interfaces:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.boxes:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
for obj in self.parser.pointers:
if not self.classmap.has_key(obj.c_name):
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
def pyname(self, name):
return self.classmap.get(name, name)
def __compare(self, obja, objb):
return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name))
def output_docs(self, output_prefix):
files = []
# class hierarchy
hierarchy = build_object_tree(self.parser)
filename = self.create_filename('hierarchy', output_prefix)
fp = open(filename, 'w')
self.write_full_hierarchy(hierarchy, fp)
fp.close()
obj_defs = self.parser.objects + self.parser.interfaces + \
self.parser.boxes + self.parser.pointers
obj_defs.sort(self.__compare)
for obj_def in obj_defs:
filename = self.create_filename(obj_def.c_name, output_prefix)
fp = open(filename, 'w')
if isinstance(obj_def, definitions.ObjectDef):
self.output_object_docs(obj_def, fp)
elif isinstance(obj_def, definitions.InterfaceDef):
self.output_interface_docs(obj_def, fp)
elif isinstance(obj_def, definitions.BoxedDef):
self.output_boxed_docs(obj_def, fp)
elif isinstance(obj_def, definitions.PointerDef):
self.output_boxed_docs(obj_def, fp)
fp.close()
files.append((os.path.basename(filename), obj_def))
if files:
filename = self.create_toc_filename(output_prefix)
fp = open(filename, 'w')
self.output_toc(files, fp)
fp.close()
def output_object_docs(self, obj_def, fp=sys.stdout):
self.write_class_header(obj_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(obj_def, fp)
self.close_section(fp)
# construct the inheritence hierarchy ...
ancestry = [ (obj_def.c_name, obj_def.implements) ]
try:
parent = obj_def.parent
while parent != None:
if parent == 'GObject':
ancestry.append(('GObject', []))
parent = None
else:
parent_def = self.parser.find_object(parent)
ancestry.append((parent_def.c_name, parent_def.implements))
parent = parent_def.parent
except ValueError:
pass
ancestry.reverse()
self.write_heading('Ancestry', fp)
self.write_hierarchy(obj_def.c_name, ancestry, fp)
self.close_section(fp)
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
self.write_heading('Constructor', fp)
self.write_constructor(constructor,
self.docs.get(constructor.c_name, None),
fp)
self.close_section(fp)
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(obj_def.c_name, fp)
def output_interface_docs(self, int_def, fp=sys.stdout):
self.write_class_header(int_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(int_def, fp)
self.close_section(fp)
methods = self.parser.find_methods(int_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(int_def.c_name, fp)
def output_boxed_docs(self, box_def, fp=sys.stdout):
self.write_class_header(box_def.c_name, fp)
self.write_heading('Synopsis', fp)
self.write_synopsis(box_def, fp)
self.close_section(fp)
constructor = self.parser.find_constructor(box_def, self.overrides)
if constructor:
self.write_heading('Constructor', fp)
self.write_constructor(constructor,
self.docs.get(constructor.c_name, None),
fp)
self.close_section(fp)
methods = self.parser.find_methods(box_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
if methods:
self.write_heading('Methods', fp)
for method in methods:
self.write_method(method, self.docs.get(method.c_name, None), fp)
self.close_section(fp)
self.write_class_footer(box_def.c_name, fp)
def output_toc(self, files, fp=sys.stdout):
fp.write('TOC\n\n')
for filename, obj_def in files:
fp.write(obj_def.c_name + ' - ' + filename + '\n')
# override the following to create a more complex output format
def create_filename(self, obj_name, output_prefix):
'''Create output filename for this particular object'''
return output_prefix + '-' + string.lower(obj_name) + '.txt'
def create_toc_filename(self, output_prefix):
return self.create_filename(self, 'docs', output_prefix)
def write_full_hierarchy(self, hierarchy, fp):
def handle_node(node, fp, indent=''):
for child in node.subclasses:
fp.write(indent + node.name)
if node.interfaces:
fp.write(' (implements ')
fp.write(string.join(node.interfaces, ', '))
fp.write(')\n')
else:
fp.write('\n')
handle_node(child, fp, indent + ' ')
handle_node(hierarchy, fp)
# these need to handle default args ...
def create_constructor_prototype(self, func_def):
return func_def.is_constructor_of + '(' + \
string.join(map(lambda x: x[1], func_def.params), ', ') + \
')'
def create_function_prototype(self, func_def):
return func_def.name + '(' + \
string.join(map(lambda x: x[1], func_def.params), ', ') + \
')'
def create_method_prototype(self, meth_def):
return meth_def.of_object + '.' + \
meth_def.name + '(' + \
string.join(map(lambda x: x[1], meth_def.params), ', ') + \
')'
def write_class_header(self, obj_name, fp):
fp.write('Class %s\n' % obj_name)
fp.write('======%s\n\n' % ('=' * len(obj_name)))
def write_class_footer(self, obj_name, fp):
pass
def write_heading(self, text, fp):
fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
def close_section(self, fp):
pass
def write_synopsis(self, obj_def, fp):
fp.write('class %s' % obj_def.c_name)
if isinstance(obj_def, definitions.ObjectDef):
bases = []
if obj_def.parent: bases.append(obj_def.parent)
bases = bases = obj_def.implements
if bases:
fp.write('(%s)' % string.join(bases, ', '))
fp.write(':\n')
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
prototype = self.create_constructor_prototype(constructor)
fp.write(' def %s\n' % prototype)
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
for meth in methods:
prototype = self.create_method_prototype(meth)
fp.write(' def %s\n' % prototype)
def write_hierarchy(self, obj_name, ancestry, fp):
indent = ''
for name, interfaces in ancestry:
fp.write(indent + '+-- ' + name)
if interfaces:
fp.write(' (implements ')
fp.write(string.join(interfaces, ', '))
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
fp.write('\n')
def write_constructor(self, func_def, func_doc, fp):
prototype = self.create_constructor_prototype(func_def)
fp.write(prototype + '\n\n')
for type, name, dflt, null in func_def.params:
if func_doc:
descr = func_doc.get_param_description(name)
else:
descr = 'a ' + type
fp.write(' ' + name + ': ' + descr + '\n')
if func_def.ret and func_def.ret != 'none':
if func_doc and func_doc.ret:
descr = func_doc.ret
else:
descr = 'a ' + func_def.ret
fp.write(' Returns: ' + descr + '\n')
if func_doc and func_doc.description:
fp.write(func_doc.description)
fp.write('\n\n\n')
def write_method(self, meth_def, func_doc, fp):
prototype = self.create_method_prototype(meth_def)
fp.write(prototype + '\n\n')
for type, name, dflt, null in meth_def.params:
if func_doc:
descr = func_doc.get_param_description(name)
else:
descr = 'a ' + type
fp.write(' ' + name + ': ' + descr + '\n')
if meth_def.ret and meth_def.ret != 'none':
if func_doc and func_doc.ret:
descr = func_doc.ret
else:
descr = 'a ' + meth_def.ret
fp.write(' Returns: ' + descr + '\n')
if func_doc and func_doc.description:
fp.write('\n')
fp.write(func_doc.description)
fp.write('\n\n')
class DocbookDocWriter(DocWriter):
def __init__(self, use_xml=0):
DocWriter.__init__(self)
self.use_xml = use_xml
def create_filename(self, obj_name, output_prefix):
'''Create output filename for this particular object'''
stem = output_prefix + '-' + string.lower(obj_name)
if self.use_xml:
return stem + '.xml'
else:
return stem + '.sgml'
def create_toc_filename(self, output_prefix):
if self.use_xml:
return self.create_filename('classes', output_prefix)
else:
return self.create_filename('docs', output_prefix)
# make string -> reference translation func
__transtable = [ '-' ] * 256
for digit in '0123456789':
__transtable[ord(digit)] = digit
for letter in 'abcdefghijklmnopqrstuvwxyz':
__transtable[ord(letter)] = letter
__transtable[ord(string.upper(letter))] = letter
__transtable = string.join(__transtable, '')
def make_class_ref(self, obj_name):
return 'class-' + string.translate(obj_name, self.__transtable)
def make_method_ref(self, meth_def):
return 'method-' + string.translate(meth_def.of_object,
self.__transtable) + \
'--' + string.translate(meth_def.name, self.__transtable)
__function_pat = re.compile(r'(\w+)\s*\(\)')
def __format_function(self, match):
info = self.parser.c_name.get(match.group(1), None)
if info:
if isinstance(info, defsparser.FunctionDef):
if info.is_constructor_of is not None:
# should have a link here
return '<function>%s()</function>' % \
self.pyname(info.is_constructor_of)
else:
return '<function>' + info.name + '()</function>'
if isinstance(info, defsparser.MethodDef):
return '<link linkend="' + self.make_method_ref(info) + \
'"><function>' + self.pyname(info.of_object) + '.' + \
info.name + '()</function></link>'
# fall through through
return '<function>' + match.group(1) + '()</function>'
__parameter_pat = re.compile(r'\@(\w+)')
def __format_param(self, match):
return '<parameter>' + match.group(1) + '</parameter>'
__constant_pat = re.compile(r'\%(-?\w+)')
def __format_const(self, match):
return '<literal>' + match.group(1) + '</literal>'
__symbol_pat = re.compile(r'#([\w-]+)')
def __format_symbol(self, match):
info = self.parser.c_name.get(match.group(1), None)
if info:
if isinstance(info, defsparser.FunctionDef):
if info.is_constructor_of is not None:
# should have a link here
return '<methodname>' + self.pyname(info.is_constructor_of) + \
'</methodname>'
else:
return '<function>' + info.name + '</function>'
if isinstance(info, defsparser.MethodDef):
return '<link linkend="' + self.make_method_ref(info) + \
'"><methodname>' + self.pyname(info.of_object) + '.' + \
info.name + '</methodname></link>'
if isinstance(info, defsparser.ObjectDef) or \
isinstance(info, defsparser.InterfaceDef) or \
isinstance(info, defsparser.BoxedDef) or \
isinstance(info, defsparser.PointerDef):
return '<link linkend="' + self.make_class_ref(info.c_name) + \
'"><classname>' + self.pyname(info.c_name) + \
'</classname></link>'
# fall through through
return '<literal>' + match.group(1) + '</literal>'
def reformat_text(self, text, singleline=0):
# replace special strings ...
text = self.__function_pat.sub(self.__format_function, text)
text = self.__parameter_pat.sub(self.__format_param, text)
text = self.__constant_pat.sub(self.__format_const, text)
text = self.__symbol_pat.sub(self.__format_symbol, text)
# don't bother with <para> expansion for single line text.
if singleline: return text
lines = string.split(string.strip(text), '\n')
for index in range(len(lines)):
if string.strip(lines[index]) == '':
lines[index] = '</para>\n<para>'
continue
lines.insert(0, '<para>')
lines.append('</para>')
return string.join(lines, '\n')
# write out hierarchy
def write_full_hierarchy(self, hierarchy, fp):
def handle_node(node, fp, indent=''):
if node.name:
fp.write('%s<link linkend="%s">%s</link>' %
(indent, self.make_class_ref(node.name),
self.pyname(node.name)))
if node.interfaces:
fp.write(' (implements ')
for i in range(len(node.interfaces)):
fp.write('<link linkend="%s">%s</link>' %
(self.make_class_ref(node.interfaces[i]),
self.pyname(node.interfaces[i])))
if i != len(node.interfaces) - 1:
fp.write(', ')
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
node.subclasses.sort(lambda a,b:
cmp(self.pyname(a.name), self.pyname(b.name)))
for child in node.subclasses:
handle_node(child, fp, indent)
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
fp.write('<synopsis>')
handle_node(hierarchy, fp)
fp.write('</synopsis>\n')
# these need to handle default args ...
def create_constructor_prototype(self, func_def):
sgml = [ '<constructorsynopsis language="python">\n']
sgml.append(' <methodname>__init__</methodname>\n')
for type, name, dflt, null in func_def.params:
sgml.append(' <methodparam><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</methodparam>\n')
if not func_def.params:
sgml.append(' <methodparam></methodparam>')
sgml.append(' </constructorsynopsis>')
return string.join(sgml, '')
def create_function_prototype(self, func_def):
sgml = [ '<funcsynopsis language="python">\n <funcprototype>\n']
sgml.append(' <funcdef><function>')
sgml.append(func_def.name)
sgml.append('</function></funcdef>\n')
for type, name, dflt, null in func_def.params:
sgml.append(' <paramdef><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</paramdef>\n')
if not func_def.params:
sgml.append(' <paramdef></paramdef')
sgml.append(' </funcprototype>\n </funcsynopsis>')
return string.join(sgml, '')
def create_method_prototype(self, meth_def, addlink=0):
sgml = [ '<methodsynopsis language="python">\n']
sgml.append(' <methodname>')
if addlink:
sgml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
sgml.append(self.pyname(meth_def.name))
if addlink:
sgml.append('</link>')
sgml.append('</methodname>\n')
for type, name, dflt, null in meth_def.params:
sgml.append(' <methodparam><parameter>')
sgml.append(name)
sgml.append('</parameter>')
if dflt:
sgml.append('<initializer>')
sgml.append(dflt)
sgml.append('</initializer>')
sgml.append('</methodparam>\n')
if not meth_def.params:
sgml.append(' <methodparam></methodparam>')
sgml.append(' </methodsynopsis>')
return string.join(sgml, '')
def write_class_header(self, obj_name, fp):
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
fp.write('<refentry id="' + self.make_class_ref(obj_name) + '">\n')
fp.write(' <refmeta>\n')
fp.write(' <refentrytitle>%s</refentrytitle>\n'
% self.pyname(obj_name))
fp.write(' <manvolnum>3</manvolnum>\n')
fp.write(' <refmiscinfo>PyGTK Docs</refmiscinfo>\n')
fp.write(' </refmeta>\n\n')
fp.write(' <refnamediv>\n')
fp.write(' <refname>%s</refname><refpurpose></refpurpose>\n'
% self.pyname(obj_name))
fp.write(' </refnamediv>\n\n')
def write_class_footer(self, obj_name, fp):
fp.write('</refentry>\n')
def write_heading(self, text, fp):
fp.write(' <refsect1>\n')
fp.write(' <title>' + text + '</title>\n\n')
def close_section(self, fp):
fp.write(' </refsect1>\n')
def write_synopsis(self, obj_def, fp):
fp.write('<classsynopsis language="python">\n')
fp.write(' <ooclass><classname>%s</classname></ooclass>\n'
% self.pyname(obj_def.c_name))
if isinstance(obj_def, definitions.ObjectDef):
if obj_def.parent:
fp.write(' <ooclass><classname><link linkend="%s">%s'
'</link></classname></ooclass>\n'
% (self.make_class_ref(obj_def.parent),
self.pyname(obj_def.parent)))
for base in obj_def.implements:
fp.write(' <ooclass><classname><link linkend="%s">%s'
'</link></classname></ooclass>\n'
% (self.make_class_ref(base), self.pyname(base)))
elif isinstance(obj_def, definitions.InterfaceDef):
fp.write(' <ooclass><classname>gobject.GInterface'
'</classname></ooclass>\n')
elif isinstance(obj_def, definitions.BoxedDef):
fp.write(' <ooclass><classname>gobject.GBoxed'
'</classname></ooclass>\n')
elif isinstance(obj_def, definitions.PointerDef):
fp.write(' <ooclass><classname>gobject.GPointer'
'</classname></ooclass>\n')
constructor = self.parser.find_constructor(obj_def, self.overrides)
if constructor:
fp.write('%s\n' % self.create_constructor_prototype(constructor))
methods = self.parser.find_methods(obj_def)
methods = filter(lambda meth, self=self:
not self.overrides.is_ignored(meth.c_name), methods)
for meth in methods:
fp.write('%s\n' % self.create_method_prototype(meth, addlink=1))
fp.write('</classsynopsis>\n\n')
def write_hierarchy(self, obj_name, ancestry, fp):
fp.write('<synopsis>')
indent = ''
for name, interfaces in ancestry:
fp.write(indent + '+-- <link linkend="' +
self.make_class_ref(name) + '">'+ self.pyname(name) + '</link>')
if interfaces:
fp.write(' (implements ')
for i in range(len(interfaces)):
fp.write('<link linkend="%s">%s</link>' %
(self.make_class_ref(interfaces[i]),
self.pyname(interfaces[i])))
if i != len(interfaces) - 1:
fp.write(', ')
fp.write(')\n')
else:
fp.write('\n')
indent = indent + ' '
fp.write('</synopsis>\n\n')
def write_params(self, params, ret, func_doc, fp):
if not params and (not ret or ret == 'none'):
return
fp.write(' <variablelist>\n')
for type, name, dflt, null in params:
if func_doc:
descr = string.strip(func_doc.get_param_description(name))
else:
descr = 'a ' + type
fp.write(' <varlistentry>\n')
fp.write(' <term><parameter>%s</parameter>&nbsp;:</term>\n' % name)
fp.write(' <listitem><simpara>%s</simpara></listitem>\n' %
self.reformat_text(descr, singleline=1))
fp.write(' </varlistentry>\n')
if ret and ret != 'none':
if func_doc and func_doc.ret:
descr = string.strip(func_doc.ret)
else:
descr = 'a ' + ret
fp.write(' <varlistentry>\n')
fp.write(' <term><emphasis>Returns</emphasis>&nbsp;:</term>\n')
fp.write(' <listitem><simpara>%s</simpara></listitem>\n' %
self.reformat_text(descr, singleline=1))
fp.write(' </varlistentry>\n')
fp.write(' </variablelist>\n')
def write_constructor(self, func_def, func_doc, fp):
prototype = self.create_constructor_prototype(func_def)
fp.write('<programlisting>%s</programlisting>\n' % prototype)
self.write_params(func_def.params, func_def.ret, func_doc, fp)
if func_doc and func_doc.description:
fp.write(self.reformat_text(func_doc.description))
fp.write('\n\n\n')
def write_method(self, meth_def, func_doc, fp):
fp.write(' <refsect2 id="' + self.make_method_ref(meth_def) + '">\n')
fp.write(' <title>' + self.pyname(meth_def.of_object) + '.' +
meth_def.name + '</title>\n\n')
prototype = self.create_method_prototype(meth_def)
fp.write('<programlisting>%s</programlisting>\n' % prototype)
self.write_params(meth_def.params, meth_def.ret, func_doc, fp)
if func_doc and func_doc.description:
fp.write(self.reformat_text(func_doc.description))
fp.write(' </refsect2>\n\n\n')
def output_toc(self, files, fp=sys.stdout):
if self.use_xml:
fp.write('<?xml version="1.0" standalone="no"?>\n')
fp.write('<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
#for filename, obj_def in files:
# fp.write(' <!ENTITY ' + string.translate(obj_def.c_name,
# self.__transtable) +
# ' SYSTEM "' + filename + '" >\n')
#fp.write(']>\n\n')
#fp.write('<reference id="class-reference">\n')
#fp.write(' <title>Class Documentation</title>\n')
#for filename, obj_def in files:
# fp.write('&' + string.translate(obj_def.c_name,
# self.__transtable) + ';\n')
#fp.write('</reference>\n')
fp.write('<reference id="class-reference" xmlns:xi="http://www.w3.org/2001/XInclude">\n')
fp.write(' <title>Class Reference</title>\n')
for filename, obj_def in files:
fp.write(' <xi:include href="%s"/>\n' % filename)
fp.write('</reference>\n')
else:
fp.write('<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1.2//EN" [\n')
for filename, obj_def in files:
fp.write(' <!ENTITY ' + string.translate(obj_def.c_name,
self.__transtable) +
' SYSTEM "' + filename + '" >\n')
fp.write(']>\n\n')
fp.write('<book id="index">\n\n')
fp.write(' <bookinfo>\n')
fp.write(' <title>PyGTK Docs</title>\n')
fp.write(' <authorgroup>\n')
fp.write(' <author>\n')
fp.write(' <firstname>James</firstname>\n')
fp.write(' <surname>Henstridge</surname>\n')
fp.write(' </author>\n')
fp.write(' </authorgroup>\n')
fp.write(' </bookinfo>\n\n')
fp.write(' <chapter id="class-hierarchy">\n')
fp.write(' <title>Class Hierarchy</title>\n')
fp.write(' <para>Not done yet</para>\n')
fp.write(' </chapter>\n\n')
fp.write(' <reference id="class-reference">\n')
fp.write(' <title>Class Documentation</title>\n')
for filename, obj_def in files:
fp.write('&' + string.translate(obj_def.c_name,
self.__transtable) + ';\n')
fp.write(' </reference>\n')
fp.write('</book>\n')
if __name__ == '__main__':
try:
opts, args = getopt.getopt(sys.argv[1:], "d:s:o:",
["defs-file=", "override=", "source-dir=",
"output-prefix="])
except getopt.error, e:
sys.stderr.write('docgen.py: %s\n' % e)
sys.stderr.write(
'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
sys.exit(1)
defs_file = None
overrides_file = None
source_dirs = []
output_prefix = 'docs'
for opt, arg in opts:
if opt in ('-d', '--defs-file'):
defs_file = arg
if opt in ('--override',):
overrides_file = arg
elif opt in ('-s', '--source-dir'):
source_dirs.append(arg)
elif opt in ('-o', '--output-prefix'):
output_prefix = arg
if len(args) != 0 or not defs_file:
sys.stderr.write(
'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
sys.exit(1)
d = DocbookDocWriter()
d.add_sourcedirs(source_dirs)
d.add_docs(defs_file, overrides_file, 'gtk')
d.output_docs(output_prefix)

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
import defsparser
from optparse import OptionParser
parser = OptionParser(usage="usage: %prog [options] generated-defs old-defs")
parser.add_option("-p", "--merge-parameters",
help="Merge changes in function/methods parameter lists",
action="store_true", dest="parmerge", default=False)
(options, args) = parser.parse_args()
if len(args) != 2:
parser.error("wrong number of arguments")
newp = defsparser.DefsParser(args[0])
oldp = defsparser.DefsParser(args[1])
newp.startParsing()
oldp.startParsing()
newp.merge(oldp, options.parmerge)
newp.write_defs()

89
moo/moopython/codegen/mkskel.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys, os, getopt
module_init_template = \
'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
'#ifdef HAVE_CONFIG_H\n' + \
'# include "config.h"\n' + \
'#endif\n' + \
'#include <Python.h>\n' + \
'#include <pygtk.h>\n' + \
'\n' + \
'/* include any extra headers needed here */\n' + \
'\n' + \
'void %(prefix)s_register_classes(PyObject *d);\n' + \
'extern PyMethodDef %(prefix)s_functions[];\n' + \
'\n' + \
'DL_EXPORT(void)\n' + \
'init%(module)s(void)\n' + \
'{\n' + \
' PyObject *m, *d;\n' + \
'\n' + \
' /* perform any initialisation required by the library here */\n' + \
'\n' + \
' m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \
' d = PyModule_GetDict(m);\n' + \
'\n' + \
' init_pygtk();\n' + \
'\n' + \
' %(prefix)s_register_classes(d);\n' + \
'\n' + \
' /* add anything else to the module dictionary (such as constants) */\n' +\
'\n' + \
' if (PyErr_Occurred())\n' + \
' Py_FatalError("could not initialise module %(module)s");\n' + \
'}\n'
override_template = \
'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
'%%%%\n' + \
'headers\n' + \
'/* include any required headers here */\n' + \
'%%%%\n' + \
'init\n' + \
' /* include any code here that needs to be executed before the\n' + \
' * extension classes get initialised */\n' + \
'%%%%\n' + \
'\n' + \
'/* you should add appropriate ignore, ignore-glob and\n' + \
' * override sections here */\n'
def open_with_backup(file):
if os.path.exists(file):
try:
os.rename(file, file+'~')
except OSError:
# fail silently if we can't make a backup
pass
return open(file, 'w')
def write_skels(fileprefix, prefix, module):
fp = open_with_backup(fileprefix+'module.c')
fp.write(module_init_template % { 'prefix': prefix, 'module': module })
fp.close()
fp = open_with_backup(fileprefix+'.override')
fp.write(override_template % { 'prefix': prefix, 'module': module })
fp.close()
if __name__ == '__main__':
opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h',
['file-prefix=', 'prefix=', 'module=', 'help'])
fileprefix = None
prefix = None
module = None
for opt, arg in opts:
if opt in ('-f', '--file-prefix'):
fileprefix = arg
elif opt in ('-p', '--prefix'):
prefix = arg
elif opt in ('-m', '--module'):
module = arg
elif opt in ('-h', '--help'):
print 'usage: mkskel.py -f fileprefix -p prefix -m module'
sys.exit(0)
if not fileprefix or not prefix or not module:
print 'usage: mkskel.py -f fileprefix -p prefix -m module'
sys.exit(1)
write_skels(fileprefix, prefix, module)

View File

@ -0,0 +1,223 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# this file contains code for loading up an override file. The override file
# provides implementations of functions where the code generator could not
# do its job correctly.
import fnmatch
import os
import re
import string
import sys
def class2cname(klass, method):
c_name = ''
for c in klass:
if c.isupper():
c_name += '_' + c.lower()
else:
c_name += c
return c_name[1:] + '_' + method
import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)')
class Overrides:
def __init__(self, filename=None):
self.modulename = None
self.ignores = {}
self.glob_ignores = []
self.overrides = {}
self.overridden = {}
self.kwargs = {}
self.noargs = {}
self.startlines = {}
self.override_attrs = {}
self.override_slots = {}
self.headers = ''
self.init = ''
self.imports = []
self.defines = {}
self.functions = {}
if filename:
self.handle_file(filename)
def handle_file(self, filename):
oldpath = os.getcwd()
fp = open(filename, 'r')
dirname = os.path.dirname(os.path.abspath(filename))
if dirname != oldpath:
os.chdir(dirname)
# read all the components of the file ...
bufs = []
startline = 1
lines = []
line = fp.readline()
linenum = 1
while line:
if line == '%%\n' or line == '%%':
if lines:
bufs.append((string.join(lines, ''), startline))
startline = linenum + 1
lines = []
else:
lines.append(line)
line = fp.readline()
linenum = linenum + 1
if lines:
bufs.append((string.join(lines, ''), startline))
if not bufs: return
for buf, startline in bufs:
self.__parse_override(buf, startline, filename)
os.chdir(oldpath)
def __parse_override(self, buffer, startline, filename):
pos = string.find(buffer, '\n')
if pos >= 0:
line = buffer[:pos]
rest = buffer[pos+1:]
else:
line = buffer ; rest = ''
words = string.split(line)
command = words[0]
if (command == 'ignore' or
command == 'ignore-' + sys.platform):
"ignore/ignore-platform [functions..]"
for func in words[1:]:
self.ignores[func] = 1
for func in string.split(rest):
self.ignores[func] = 1
elif (command == 'ignore-glob' or
command == 'ignore-glob-' + sys.platform):
"ignore-glob/ignore-glob-platform [globs..]"
for func in words[1:]:
self.glob_ignores.append(func)
for func in string.split(rest):
self.glob_ignores.append(func)
elif command == 'override':
"override function/method [kwargs,noargs]"
func = words[1]
if 'kwargs' in words[1:]:
self.kwargs[func] = 1
elif 'noargs' in words[1:]:
self.noargs[func] = 1
self.overrides[func] = rest
self.startlines[func] = (startline + 1, filename)
elif command == 'override-attr':
"override-slot Class.attr"
attr = words[1]
self.override_attrs[attr] = rest
self.startlines[attr] = (startline + 1, filename)
elif command == 'override-slot':
"override-slot Class.slot"
slot = words[1]
self.override_slots[slot] = rest
self.startlines[slot] = (startline + 1, filename)
elif command == 'headers':
"headers"
self.headers = '%s\n#line %d "%s"\n%s' % \
(self.headers, startline + 1, filename, rest)
elif command == 'init':
"init"
self.init = '%s\n#line %d "%s"\n%s' % \
(self.init, startline + 1, filename, rest)
elif command == 'modulename':
"modulename name"
self.modulename = words[1]
elif command == 'include':
"include filename"
for filename in words[1:]:
self.handle_file(filename)
for filename in string.split(rest):
self.handle_file(filename)
elif command == 'import':
"import module1 [\n module2, \n module3 ...]"
for line in string.split(buffer, '\n'):
match = import_pat.match(line)
if match:
self.imports.append(match.groups())
elif command == 'define':
"define funcname [kwargs,noargs]"
"define Class.method [kwargs,noargs]"
func = words[1]
klass = None
if func.find('.') != -1:
klass, func = func.split('.', 1)
if not self.defines.has_key(klass):
self.defines[klass] = {}
self.defines[klass][func] = rest
else:
self.functions[func] = rest
if 'kwargs' in words[1:]:
self.kwargs[func] = 1
elif 'noargs' in words[1:]:
self.noargs[func] = 1
self.startlines[func] = (startline + 1, filename)
def is_ignored(self, name):
if self.ignores.has_key(name):
return 1
for glob in self.glob_ignores:
if fnmatch.fnmatchcase(name, glob):
return 1
return 0
def is_overriden(self, name):
return self.overrides.has_key(name)
def is_already_included(self, name):
return self.overridden.has_key(name)
def override(self, name):
self.overridden[name] = 1
return self.overrides[name]
def define(self, klass, name):
self.overridden[class2cname(klass, name)] = 1
return self.defines[klass][name]
def function(self, name):
return self.functions[name]
def getstartline(self, name):
return self.startlines[name]
def wants_kwargs(self, name):
return self.kwargs.has_key(name)
def wants_noargs(self, name):
return self.noargs.has_key(name)
def attr_is_overriden(self, attr):
return self.override_attrs.has_key(attr)
def attr_override(self, attr):
return self.override_attrs[attr]
def slot_is_overriden(self, slot):
return self.override_slots.has_key(slot)
def slot_override(self, slot):
return self.override_slots[slot]
def get_headers(self):
return self.headers
def get_init(self):
return self.init
def get_imports(self):
return self.imports
def get_defines_for(self, klass):
return self.defines.get(klass, {})
def get_functions(self):
return self.functions

View File

@ -0,0 +1,667 @@
### -*- python -*-
### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
import argtypes
def join_ctype_name(ctype, name):
'''Joins a C type and a variable name into a single string'''
if ctype[-1] != '*':
return " ".join((ctype, name))
else:
return "".join((ctype, name))
class CodeSink(object):
def __init__(self):
self.indent_level = 0 # current indent level
self.indent_stack = [] # previous indent levels
def _format_code(self, code):
assert isinstance(code, str)
l = []
for line in code.split('\n'):
l.append(' '*self.indent_level + line)
if l[-1]:
l.append('')
return '\n'.join(l)
def writeln(self, line=''):
raise NotImplementedError
def indent(self, level=4):
'''Add a certain ammount of indentation to all lines written
from now on and until unindent() is called'''
self.indent_stack.append(self.indent_level)
self.indent_level += level
def unindent(self):
'''Revert indentation level to the value before last indent() call'''
self.indent_level = self.indent_stack.pop()
class FileCodeSink(CodeSink):
def __init__(self, fp):
CodeSink.__init__(self)
assert isinstance(fp, file)
self.fp = fp
def writeln(self, line=''):
self.fp.write(self._format_code(line))
class MemoryCodeSink(CodeSink):
def __init__(self):
CodeSink.__init__(self)
self.lines = []
def writeln(self, line=''):
self.lines.append(self._format_code(line))
def flush_to(self, sink):
assert isinstance(sink, CodeSink)
for line in self.lines:
sink.writeln(line.rstrip())
self.lines = []
def flush(self):
l = []
for line in self.lines:
l.append(self._format_code(line))
self.lines = []
return "".join(l)
class ReverseWrapper(object):
'''Object that generates a C->Python wrapper'''
def __init__(self, cname, is_static=True):
assert isinstance(cname, str)
self.cname = cname
## function object we will call, or object whose method we will call
self.called_pyobj = None
## name of method of self.called_pyobj we will call
self.method_name = None
self.is_static = is_static
self.parameters = []
self.declarations = MemoryCodeSink()
self.body = MemoryCodeSink()
self.cleanup_actions = []
self.pyargv_items = []
self.pyargv_optional_items = []
def set_call_target(self, called_pyobj, method_name=None):
assert called_pyobj is not None
assert self.called_pyobj is None
self.called_pyobj = called_pyobj
self.method_name = method_name
def set_return_type(self, return_type):
assert isinstance(return_type, ReturnType)
self.return_type = return_type
def add_parameter(self, param):
assert isinstance(param, Parameter)
self.parameters.append(param)
def add_declaration(self, decl_code):
self.declarations.writeln(decl_code)
def add_pyargv_item(self, variable, optional=False):
if optional:
self.pyargv_optional_items.append(variable)
else:
self.pyargv_items.append(variable)
def write_code(self, code,
cleanup=None,
failure_expression=None,
failure_cleanup=None):
'''Add a chunk of code with cleanup and error handling
This method is to be used by TypeHandlers when generating code
Keywork arguments:
code -- code to add
cleanup -- code to cleanup any dynamic resources created by @code
(except in case of failure) (default None)
failure_expression -- C boolean expression to indicate
if anything failed (default None)
failure_cleanup -- code to cleanup any dynamic resources
created by @code in case of failure (default None)
'''
if code is not None:
self.body.writeln(code)
if failure_expression is not None:
self.body.writeln("if (%s) {" % failure_expression)
self.body.indent()
self.body.writeln("if (PyErr_Occurred())")
self.body.indent()
self.body.writeln("PyErr_Print();")
self.body.unindent()
if failure_cleanup is not None:
self.body.writeln(failure_cleanup)
for cleanup_action in self.cleanup_actions:
self.body.writeln(cleanup_action)
self.return_type.write_error_return()
self.body.unindent()
self.body.writeln("}")
if cleanup is not None:
self.cleanup_actions.insert(0, cleanup)
def generate(self, sink):
'''Generate the code into a CodeSink object'''
assert isinstance(sink, CodeSink)
self.add_declaration("PyGILState_STATE __py_state;")
self.write_code(code="__py_state = pyg_gil_state_ensure();",
cleanup="pyg_gil_state_release(__py_state);")
for param in self.parameters:
param.convert_c2py()
assert self.called_pyobj is not None,\
"Parameters failed to provide a target function or method."
if self.is_static:
sink.writeln('static %s' % self.return_type.get_c_type())
else:
sink.writeln(self.return_type.get_c_type())
c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
self.return_type.write_decl()
self.add_declaration("PyObject *py_retval;")
## Handle number of arguments
if self.pyargv_items:
self.add_declaration("PyObject *py_args;")
py_args = "py_args"
if self.pyargv_optional_items:
self.add_declaration("int argc = %i;" % len(self.pyargv_items))
argc = "argc"
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s)" % arg)
self.body.indent()
self.body.writeln("++argc;")
self.body.unindent()
else:
argc = str(len(self.pyargv_items))
else:
if self.pyargv_optional_items:
self.add_declaration("PyObject *py_args;")
py_args = "py_args"
self.add_declaration("int argc = 0;")
argc = "argc"
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s)" % arg)
self.body.indent()
self.body.writeln("++argc;")
self.body.unindent()
else:
py_args = "NULL"
argc = None
self.body.writeln()
if py_args != "NULL":
self.write_code("py_args = PyTuple_New(%s);" % argc,
cleanup="Py_DECREF(py_args);")
pos = 0
for arg in self.pyargv_items:
try: # try to remove the Py_DECREF cleanup action, if we can
self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
except ValueError: # otherwise we have to Py_INCREF..
self.body.writeln("Py_INCREF(%s);" % arg)
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
pos += 1
for arg in self.pyargv_optional_items:
self.body.writeln("if (%s) {" % arg)
self.body.indent()
try: # try to remove the Py_DECREF cleanup action, if we can
self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
except ValueError: # otherwise we have to Py_INCREF..
self.body.writeln("Py_INCREF(%s);" % arg)
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
self.body.unindent()
self.body.writeln("}")
pos += 1
self.body.writeln()
# call it
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")
else:
self.add_declaration("PyObject *py_method;")
self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
% (self.called_pyobj, self.method_name),
cleanup="Py_DECREF(py_method);",
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")
self.return_type.write_conversion()
sink.indent()
self.declarations.flush_to(sink)
sink.writeln()
self.body.flush_to(sink)
sink.writeln()
for cleanup_action in self.cleanup_actions:
sink.writeln(cleanup_action)
if self.return_type.get_c_type() != 'void':
sink.writeln()
sink.writeln("return retval;")
sink.unindent()
sink.writeln("}")
class TypeHandler(object):
def __init__(self, wrapper, **props):
assert isinstance(wrapper, ReverseWrapper)
self.wrapper = wrapper
self.props = props
class ReturnType(TypeHandler):
def get_c_type(self):
raise NotImplementedError
def write_decl(self):
raise NotImplementedError
def write_error_return(self):
'''Write "return <value>" code in case of error'''
raise NotImplementedError
def write_conversion(self):
'''Writes code to convert Python return value in 'py_retval'
into C 'retval'. Returns a string with C boolean expression
that determines if anything went wrong. '''
raise NotImplementedError
class Parameter(TypeHandler):
def __init__(self, wrapper, name, **props):
TypeHandler.__init__(self, wrapper, **props)
self.name = name
def get_c_type(self):
raise NotImplementedError
def convert_c2py(self):
'''Write some code before calling the Python method.'''
pass
def format_for_c_proto(self):
return join_ctype_name(self.get_c_type(), self.name)
###---
class StringParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'char *').replace('const-', 'const ')
def convert_c2py(self):
if self.props.get('optional', False):
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
self.wrapper.write_code(code=("if (%s)\n"
" py_%s = PyString_FromString(%s);\n"
% (self.name, self.name, self.name)),
cleanup=("Py_XDECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
else:
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
(self.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)
for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
'gchar-const*', 'string', 'static_string'):
argtypes.matcher.register_reverse(ctype, StringParam)
class StringReturn(ReturnType):
def get_c_type(self):
return "char *"
def write_decl(self):
self.wrapper.add_declaration("char *retval;")
def write_error_return(self):
self.wrapper.write_code("return NULL;")
def write_conversion(self):
self.wrapper.write_code(
code=None,
failure_expression="!PyString_Check(py_retval)",
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");')
self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));")
for ctype in ('char*', 'gchar*'):
argtypes.matcher.register_reverse(ctype, StringReturn)
class VoidReturn(ReturnType):
def get_c_type(self):
return "void"
def write_decl(self):
pass
def write_error_return(self):
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");')
argtypes.matcher.register_reverse_ret('void', VoidReturn)
argtypes.matcher.register_reverse_ret('none', VoidReturn)
class GObjectParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'GObject *')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
self.wrapper.write_code(code=("if (%s)\n"
" py_%s = pygobject_new((GObject *) %s);\n"
"else {\n"
" Py_INCREF(Py_None);\n"
" py_%s = Py_None;\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)
argtypes.matcher.register_reverse('GObject*', GObjectParam)
class GObjectReturn(ReturnType):
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())
def write_error_return(self):
self.wrapper.write_code("return NULL;")
def write_conversion(self):
self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
% self.get_c_type())
self.wrapper.write_code("g_object_ref((GObject *) retval);")
argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
class IntParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'int')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
class IntReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'int')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return -G_MAXINT;")
def write_conversion(self):
self.wrapper.write_code(
code=None,
failure_expression="!PyInt_Check(py_retval)",
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an int");')
self.wrapper.write_code("retval = PyInt_AsLong(py_retval);")
for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
'gint16', 'gint32', 'GTime'):
argtypes.matcher.register_reverse(argtype, IntParam)
argtypes.matcher.register_reverse_ret(argtype, IntReturn)
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']))
argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
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.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GEnum", GEnumParam)
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']))
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)),
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("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)),
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("GtkTreePath*", GtkTreePathParam)
class BooleanReturn(ReturnType):
def get_c_type(self):
return "gboolean"
def write_decl(self):
self.wrapper.add_declaration("gboolean retval;")
def write_error_return(self):
self.wrapper.write_code("return FALSE;")
def write_conversion(self):
self.wrapper.write_code("retval = PyObject_IsTrue(py_retval)? TRUE : FALSE;")
argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
class BooleanParam(Parameter):
def get_c_type(self):
return "gboolean"
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
% (self.name, self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("gboolean", BooleanParam)
class DoubleParam(Parameter):
def get_c_type(self):
return self.props.get('c_type', 'gdouble')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
class DoubleReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type', 'gdouble')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
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);")
for argtype in ('float', 'double', 'gfloat', 'gdouble'):
argtypes.matcher.register_reverse(argtype, DoubleParam)
argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
class GBoxedParam(Parameter):
def get_c_type(self):
return self.props.get('c_type').replace('const-', 'const ')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
ctype = self.get_c_type()
if ctype.startswith('const '):
ctype_no_const = ctype[len('const '):]
self.wrapper.write_code(
code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
(self.name, self.props['typecode'],
ctype_no_const, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
else:
self.wrapper.write_code(
code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
(self.name, self.props['typecode'], self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
class GBoxedReturn(ReturnType):
def get_c_type(self):
return self.props.get('c_type')
def write_decl(self):
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
def write_error_return(self):
self.wrapper.write_code("return retval;")
def write_conversion(self):
self.wrapper.write_code(
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'],)))
self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
self.props['typename'])
argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
class GdkRectanglePtrParam(Parameter):
def get_c_type(self):
return self.props.get('c_type').replace('const-', 'const ')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(
code=('py_%(name)s = Py_BuildValue("(ffff)", %(name)s->x, %(name)s->y,\n'
' %(name)s->width, %(name)s->height);'
% dict(name=self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
class PyGObjectMethodParam(Parameter):
def __init__(self, wrapper, name, method_name, **props):
Parameter.__init__(self, wrapper, name, **props)
self.method_name = method_name
def get_c_type(self):
return self.props.get('c_type', 'GObject *')
def convert_c2py(self):
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
(self.name, self.name)),
cleanup=("Py_DECREF(py_%s);" % self.name),
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)
self.free_it = free_it
def get_c_type(self):
return "gpointer"
def convert_c2py(self):
self.wrapper.add_declaration("PyObject **_user_data;")
cleanup = self.free_it and ("g_free(%s);" % self.name) or None
self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
% self.name),
cleanup=cleanup)
self.wrapper.add_declaration("PyObject *py_func;")
cleanup = self.free_it and "Py_DECREF(py_func);" or None
self.wrapper.write_code(code="py_func = _user_data[0];",
cleanup=cleanup)
self.wrapper.set_call_target("py_func")
self.wrapper.add_declaration("PyObject *py_user_data;")
cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
self.wrapper.write_code(code="py_user_data = _user_data[1];",
cleanup=cleanup)
self.wrapper.add_pyargv_item("py_user_data", optional=True)
def _test():
import sys
wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
wrapper.set_return_type(StringReturn(wrapper))
wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
wrapper.add_parameter(GObjectParam(wrapper, "param3"))
wrapper.generate(FileCodeSink(sys.stderr))
wrapper = ReverseWrapper("this_a_callback_wrapper")
wrapper.set_return_type(VoidReturn(wrapper))
wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
wrapper.add_parameter(GObjectParam(wrapper, "param2"))
wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
wrapper.generate(FileCodeSink(sys.stderr))
if __name__ == '__main__':
_test()

View File

@ -0,0 +1,144 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
from __future__ import generators
import string
import types
from cStringIO import StringIO
class error(Exception):
def __init__(self, filename, lineno, msg):
Exception.__init__(self, msg)
self.filename = filename
self.lineno = lineno
self.msg = msg
def __str__(self):
return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg)
trans = [' '] * 256
for i in range(256):
if chr(i) in string.letters + string.digits + '_':
trans[i] = chr(i)
else:
trans[i] = '_'
trans = string.join(trans, '')
def parse(filename):
if isinstance(filename, str):
fp = open(filename, 'r')
else: # if not string, assume it is some kind of iterator
fp = filename
filename = getattr(fp, 'name', '<unknown>')
whitespace = ' \t\n\r\x0b\x0c'
nonsymbol = whitespace + '();\'"'
stack = []
openlines = []
lineno = 0
for line in fp:
pos = 0
lineno += 1
while pos < len(line):
if line[pos] in whitespace: # ignore whitespace
pass
elif line[pos] == ';': # comment
break
elif line[pos:pos+2] == "'(":
pass # the open parenthesis will be handled next iteration
elif line[pos] == '(':
stack.append(())
openlines.append(lineno)
elif line[pos] == ')':
if len(stack) == 0:
raise error(filename, lineno, 'close parenthesis found when none open')
closed = stack[-1]
del stack[-1]
del openlines[-1]
if stack:
stack[-1] += (closed,)
else:
yield closed
elif line[pos] == '"': # quoted string
if not stack:
raise error(filename, lineno,
'string found outside of s-expression')
endpos = pos + 1
chars = []
while endpos < len(line):
if endpos+1 < len(line) and line[endpos] == '\\':
endpos += 1
if line[endpos] == 'n':
chars.append('\n')
elif line[endpos] == 'r':
chars.append('\r')
elif line[endpos] == 't':
chars.append('\t')
else:
chars.append('\\')
chars.append(line[endpos])
elif line[endpos] == '"':
break
else:
chars.append(line[endpos])
endpos += 1
if endpos >= len(line):
raise error(filename, lineno, "unclosed quoted string")
pos = endpos
stack[-1] += (''.join(chars),)
else: # symbol/number
if not stack:
raise error(filename, lineno,
'identifier found outside of s-expression')
endpos = pos
while endpos < len(line) and line[endpos] not in nonsymbol:
endpos += 1
symbol = line[pos:endpos]
pos = max(pos, endpos-1)
try: symbol = int(symbol)
except ValueError:
try: symbol = float(symbol)
except ValueError: pass
stack[-1] += (symbol,)
pos += 1
if len(stack) != 0:
msg = '%d unclosed parentheses found at end of ' \
'file (opened on line(s) %s)' % (len(stack),
', '.join(map(str, openlines)))
raise error(filename, lineno, msg)
class Parser:
def __init__(self, filename):
"""Argument is either a string, a parse tree, or file object"""
self.filename = filename
def startParsing(self, filename=None):
statements = parse(filename or self.filename)
for statement in statements:
self.handle(statement)
def handle(self, tup):
cmd = string.translate(tup[0], trans)
if hasattr(self, cmd):
getattr(self, cmd)(*tup[1:])
else:
self.unknown(tup)
def unknown(self, tup):
pass
_testString = """; a scheme file
(define-func gdk_font_load ; a comment at end of line
GdkFont
((string name)))
(define-boxed GdkEvent
gdk_event_copy
gdk_event_free
"sizeof(GdkEvent)")
"""
if __name__ == '__main__':
import sys
if sys.argv[1:]:
fp = open(sys.argv[1])
else:
fp = StringIO(_testString)
statements = parse(fp)
for s in statements:
print `s`