medit/api/mpi/docbookwriter.py

503 lines
18 KiB
Python

import StringIO
from mpi.util import *
from mpi.module import *
lua_constants = {
'NULL': '<constant>nil</constant>',
'TRUE': '<constant>true</constant>',
'FALSE': '<constant>false</constant>',
'INDEXBASE': '<constant>1</constant>',
}
python_constants = {
'NULL': '<constant>None</constant>',
'TRUE': '<constant>True</constant>',
'FALSE': '<constant>False</constant>',
'GTK_RESPONSE_OK': '<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/' +
'gtk-constants.html#gtk-response-type-constants">gtk.RESPONSE_OK</ulink></constant>',
'INDEXBASE': '<constant>0</constant>',
}
common_types = {
'gboolean': '<constant>bool</constant>',
'strv': 'list of strings',
}
lua_types = dict(common_types)
lua_types.update({
'index': '<constant>integer index (1-based)</constant>',
'value': '<constant>value</constant>',
'gunichar': '<constant>string</constant>',
'double': '<constant>number</constant>',
'int': '<constant>integer</constant>',
'gint': '<constant>integer</constant>',
'guint': '<constant>integer</constant>',
'gulong': '<constant>integer</constant>',
'const-utf8': '<constant>string</constant>',
'utf8': '<constant>string</constant>',
'const-filename': '<constant>string</constant>',
'filename': '<constant>string</constant>',
'const-cstring': '<constant>string</constant>',
'cstring': '<constant>string</constant>',
})
python_types = dict(common_types)
python_types.update({
'index': '<constant>integer index (0-based)</constant>',
'gunichar': '<constant>str</constant>',
'double': '<constant>float</constant>',
'int': '<constant>int</constant>',
'gint': '<constant>int</constant>',
'guint': '<constant>int</constant>',
'gulong': '<constant>int</constant>',
'const-utf8': '<constant>str</constant>',
'utf8': '<constant>str</constant>',
'const-filename': '<constant>str</constant>',
'filename': '<constant>str</constant>',
'const-cstring': '<constant>str</constant>',
'cstring': '<constant>str</constant>',
})
def format_python_symbol_ref(symbol):
constants = {
}
classes = {
'GFile': '<ulink url="http://library.gnome.org/devel/pygobject/stable/class-giofile.html">gio.File</ulink>',
'GObject': '<ulink url="http://library.gnome.org/devel/pygobject/stable/class-gobject.html">gobject.Object</ulink>',
'GType': 'type',
}
if symbol in constants:
return '<constant>%s</constant>' % constants[symbol]
if symbol in classes:
return '<constant>%s</constant>' % classes[symbol]
if symbol.startswith('Gtk'):
return ('<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/class-' + \
'gtk%s.html">gtk.%s</ulink></constant>') % (symbol[3:].lower(), symbol[3:])
if symbol.startswith('Gdk'):
return '<constant><ulink url="http://library.gnome.org/devel/pygtk/stable/class-' + \
'gdk%s.html">gtk.gdk.%s</ulink></constant>' % (symbol[3:].lower(), symbol[3:])
raise NotImplementedError(symbol)
def split_camel_case_name(name):
comps = []
cur = ''
for c in name:
if c.islower() or not cur:
cur += c
else:
comps.append(cur)
cur = c
if cur:
comps.append(cur)
return comps
def name_all_caps(cls):
return '_'.join([s.upper() for s in split_camel_case_name(cls.name)])
class Writer(object):
def __init__(self, mode, template, out):
super(Writer, self).__init__()
self.file = out
self.out = StringIO.StringIO()
self.mode = mode
self.template = template
if mode == 'python':
self.constants = python_constants
self.builtin_types = python_types
elif mode == 'lua':
self.constants = lua_constants
self.builtin_types = lua_types
else:
oops('unknown mode %s' % mode)
self.section_suffix = ' (%s)' % self.mode.capitalize()
def __format_symbol_ref(self, name):
sym = self.symbols.get(name)
if sym:
if isinstance(sym, EnumValue):
return '<constant><link linkend="%(mode)s.%(parent)s" endterm="%(mode)s.%(symbol)s.title"></link></constant>' % \
dict(symbol=name, mode=self.mode, parent=sym.enum.symbol_id())
elif isinstance(sym, Type):
return '<constant><link linkend="%(mode)s.%(symbol)s">%(name)s</link></constant>' % \
dict(symbol=name, mode=self.mode, name=self.__make_class_name(sym))
elif isinstance(sym, Method):
return '<constant><link linkend="%(mode)s.%(symbol)s">%(Class)s.%(method)s()</link></constant>' % \
dict(symbol=name, mode=self.mode, Class=self.__make_class_name(sym.cls), method=sym.name)
else:
oops(name)
if self.mode == 'python':
return format_python_symbol_ref(name)
else:
raise NotImplementedError(name)
def __string_to_bool(self, s):
if s == '0':
return False
elif s == '1':
return True
else:
oops()
def __check_bind_ann(self, obj):
bind = self.__string_to_bool(obj.annotations.get('moo.' + self.mode, '1'))
if bind:
bind = not self.__string_to_bool(obj.annotations.get('moo.private', '0'))
return bind
def __format_constant(self, value):
if value in self.constants:
return self.constants[value]
try:
i = int(value)
return value
except ValueError:
pass
formatted = self.__format_symbol_ref(value)
if formatted:
return formatted
error("unknown constant '%s'" % value)
return value
def __format_default_value(self, p):
if p.type.name == 'index' and self.mode == 'lua':
return str(int(p.default_value) + 1)
else:
return self.__format_constant(p.default_value)
def __format_doc(self, doc):
text = doc.text
text = re.sub(r'@([\w\d_]+)(?!\{)', r'<parameter>\1</parameter>', text)
text = re.sub(r'%NULL\b', '<constant>%s</constant>' % self.constants['NULL'], text)
text = re.sub(r'%TRUE\b', '<constant>%s</constant>' % self.constants['TRUE'], text)
text = re.sub(r'%FALSE\b', '<constant>%s</constant>' % self.constants['FALSE'], text)
text = re.sub(r'%INDEXBASE\b', '<constant>%s</constant>' % self.constants['INDEXBASE'], text)
text = text.replace(r'<n/>', '')
text = text.replace(r'<nl/>', '\n')
def repl_func(m):
func_id = m.group(1)
symbol = self.symbols.get(func_id)
if not isinstance(symbol, MethodBase) or symbol.cls == self.current_class:
return '<function><link linkend="%(mode)s.%(func_id)s" endterm="%(mode)s.%(func_id)s.title"/></function>' % \
dict(func_id=func_id, mode=self.mode)
else:
return '<function><link linkend="%(mode)s.%(func_id)s">%(Class)s.%(method)s()</link></function>' % \
dict(func_id=func_id, mode=self.mode, Class=self.__make_class_name(symbol.cls), method=symbol.name)
text = re.sub(r'([\w\d_.]+)\(\)', repl_func, text)
def repl_signal(m):
cls = m.group(1)
signal = m.group(2).replace('_', '-')
symbol = 'signal:%s:%s' % (cls, signal)
if self.symbols[cls] != self.current_class:
return '<function><link linkend="%(mode)s.%(symbol)s">%(Class)s.%(signal)s</link></function>' % \
dict(Class=cls, symbol=symbol, mode=self.mode, signal=signal)
else:
return '<function><link linkend="%(mode)s.%(symbol)s">%(signal)s</link></function>' % \
dict(symbol=symbol, mode=self.mode, signal=signal)
text = re.sub(r'([\w\d_-]+)::([\w\d_-]+)', repl_signal, text)
def repl_symbol(m):
symbol = m.group(1)
formatted = self.__format_symbol_ref(symbol)
if not formatted:
raise RuntimeError('unknown symbol %s' % symbol)
return formatted
text = re.sub(r'#([\w\d_]+)', repl_symbol, text)
assert not re.search(r'NULL|TRUE|FALSE', text)
return text
def __make_class_name(self, cls):
return '%s.%s' % (cls.module.name.lower(), cls.short_name)
def __get_obj_name(self, cls):
name = cls.annotations.get('moo.doc-object-name')
if not name:
name = '_'.join([c.lower() for c in split_camel_case_name(cls.name)[1:]])
return name
def __write_function(self, func, cls):
if not self.__check_bind_ann(func):
return
func_params = list(func.params)
if func.has_gerror_return:
func_params = func_params[:-1]
params = []
for p in func_params:
if not self.__check_bind_ann(p.type):
return
if p.default_value is not None:
params.append('%s=%s' % (p.name, self.__format_default_value(p)))
else:
params.append(p.name)
if isinstance(func, Constructor):
if self.mode == 'python':
func_title = cls.short_name + '()'
func_name = cls.short_name
elif self.mode == 'lua':
func_title = 'new' + '()'
func_name = '%s.new' % cls.short_name
else:
oops()
elif isinstance(func, Signal):
if self.mode == 'python':
func_title = 'signal ' + func.name
func_name = func.name
elif self.mode == 'lua':
func_title = 'signal ' + func.name
func_name = func.name
else:
oops()
elif cls is not None:
if self.mode in ('python', 'lua'):
func_title = func.name + '()'
func_name = '%s.%s' % (self.__get_obj_name(cls), func.name) \
if not isinstance(func, StaticMethod) \
else '%s.%s' % (cls.short_name, func.name)
else:
oops()
else:
func_title = func.name + '()'
func_name = '%s.%s' % (self.module.name.lower(), func.name)
params_string = ', '.join(params)
if func.summary:
oops(func_id)
func_id = func.symbol_id()
mode = self.mode
if mode == 'lua' and func.kwargs:
left_paren, right_paren = '{}'
else:
left_paren, right_paren = '()'
self.out.write("""\
<!-- %(func_id)s -->
<sect2 id="%(mode)s.%(func_id)s">
<title id="%(mode)s.%(func_id)s.title">%(func_title)s</title>
<programlisting>%(func_name)s%(left_paren)s%(params_string)s%(right_paren)s</programlisting>
""" % locals())
if func.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(func.doc))
if func_params:
self.out.write("""\
<variablelist>
<?dbhtml list-presentation="table"?>
<?dbhtml term-separator=" : "?>
""")
for p in func_params:
if p.doc:
docs = doc=self.__format_doc(p.doc)
else:
ptype = p.type.symbol_id()
if ptype.endswith('*'):
ptype = ptype[:-1]
if ptype.startswith('const-'):
ptype = ptype[len('const-'):]
if ptype in self.builtin_types:
docs = self.builtin_types[ptype]
if p.allow_none:
docs = docs + ' or ' + self.__format_constant('NULL')
elif ptype.endswith('Array'):
elmtype = ptype[:-len('Array')]
if elmtype in self.symbols and isinstance(self.symbols[elmtype], InstanceType):
docs = 'list of %s objects' % self.__format_symbol_ref(self.symbols[elmtype].symbol_id())
else:
docs = self.__format_symbol_ref(ptype)
else:
docs = self.__format_symbol_ref(ptype)
if p.allow_none:
docs = docs + ' or ' + self.__format_constant('NULL')
param_dic = dict(param=p.name, doc=docs)
self.out.write("""\
<varlistentry>
<term><parameter>%(param)s</parameter></term>
<listitem><para>%(doc)s</para></listitem>
</varlistentry>
""" % param_dic)
self.out.write('</variablelist>\n')
if func.retval:
retdoc = None
if func.retval.doc:
retdoc = self.__format_doc(func.retval.doc)
else:
rettype = func.retval.type.symbol_id()
if rettype.endswith('*'):
rettype = rettype[:-1]
if rettype in self.builtin_types:
retdoc = self.builtin_types[rettype]
elif rettype.endswith('Array'):
elmtype = rettype[:-len('Array')]
if elmtype in self.symbols and isinstance(self.symbols[elmtype], InstanceType):
retdoc = 'list of %s objects' % self.__format_symbol_ref(self.symbols[elmtype].symbol_id())
else:
retdoc = self.__format_symbol_ref(rettype)
else:
retdoc = self.__format_symbol_ref(rettype)
if retdoc:
self.out.write('<para><parameter>Returns:</parameter> %s</para>\n' % retdoc)
self.out.write('</sect2>\n')
def __write_gobject_constructor(self, cls):
func = Constructor()
self.__write_function(func, cls)
def __write_class(self, cls):
if not self.__check_bind_ann(cls):
return
self.current_class = cls
title = self.__make_class_name(cls)
if cls.summary:
title += ' - ' + cls.summary.text
dic = dict(class_id=cls.symbol_id(), title=title, mode=self.mode)
self.out.write("""\
<!-- %(class_id)s -->
<sect1 id="%(mode)s.%(class_id)s">
<title id="%(mode)s.%(class_id)s.title">%(title)s</title>
""" % dic)
if cls.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(cls.doc))
if getattr(cls, 'parent', 'none') != 'none':
self.out.write("""\
<programlisting>
%(ParentClass)s
|
+-- %(Class)s
</programlisting>
""" % dict(ParentClass=self.__format_symbol_ref(cls.parent), Class=self.__make_class_name(cls)))
if hasattr(cls, 'signals') and cls.signals:
for signal in cls.signals:
self.__write_function(signal, cls)
if cls.constructor is not None:
self.__write_function(cls.constructor, cls)
if hasattr(cls, 'constructable') and cls.constructable:
self.__write_gobject_constructor(cls)
for meth in cls.static_methods:
self.__write_function(meth, cls)
if isinstance(cls, Class):
if cls.vmethods:
implement_me('virtual methods of %s' % cls.name)
for meth in cls.methods:
self.__write_function(meth, cls)
self.out.write("""\
</sect1>
""" % dic)
self.current_class = None
def __write_enum(self, enum):
if not self.__check_bind_ann(enum):
return
do_write = False
for v in enum.values:
if self.__check_bind_ann(v):
do_write = True
break
if not do_write:
return
title = self.__make_class_name(enum)
if enum.summary:
title += ' - ' + enum.summary.text
dic = dict(title=title,
mode=self.mode,
enum_id=enum.symbol_id())
self.out.write("""\
<!-- %(enum_id)s -->
<sect2 id="%(mode)s.%(enum_id)s">
<title id="%(mode)s.%(enum_id)s.title">%(title)s</title>
""" % dic)
if enum.doc:
self.out.write('<para>%s</para>\n' % self.__format_doc(enum.doc))
self.out.write("""\
<variablelist>
<?dbhtml list-presentation="table"?>
""")
for v in enum.values:
if not self.__check_bind_ann(v):
continue
value_dic = dict(mode=self.mode, enum_id=v.name, value=v.short_name,
doc=self.__format_doc(v.doc) if v.doc else '')
self.out.write("""\
<varlistentry>
<term><constant id="%(mode)s.%(enum_id)s.title">%(value)s</constant></term>
<listitem><para>%(doc)s</para></listitem>
</varlistentry>
""" % value_dic)
self.out.write('</variablelist>\n')
self.out.write('</sect2>\n')
def write(self, module):
self.module = module
self.symbols = module.get_symbols()
self.current_class = None
classes = module.get_classes() + module.get_boxed() + module.get_pointers()
for cls in sorted(classes, lambda cls1, cls2: cmp(cls1.short_name, cls2.short_name)):
self.__write_class(cls)
funcs = []
for f in module.get_functions():
if self.__check_bind_ann(f):
funcs.append(f)
dic = dict(mode=self.mode)
if funcs:
self.out.write("""\
<!-- functions -->
<sect1 id="%(mode)s.functions">
<title>Functions</title>
""" % dic)
for func in funcs:
self.__write_function(func, None)
self.out.write('</sect1>\n')
self.out.write("""\
<!-- enums -->
<sect1 id="%(mode)s.enums">
<title>Enumerations</title>
""" % dic)
for func in module.get_enums():
self.__write_enum(func)
self.out.write('</sect1>\n')
content = self.out.getvalue()
template = open(self.template).read()
self.file.write(template.replace('###GENERATED###', content))
del self.out
del self.module