2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
4 # Copyright (C) 2008, 2009 Red Hat, Inc.
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the
18 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 # Boston, MA 02111-1307, USA.
22 from __future__ import with_statement
25 from ctypes.util import find_library
27 from .ast import (Alias, Array, Bitfield, Callback, Class, Constant, Enum,
28 Function, Interface, List, Map, Member, Struct, Union,
30 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
31 GLibFlags, GLibObject, GLibInterface,
33 from .xmlwriter import XMLWriter
36 class GIRWriter(XMLWriter):
38 def __init__(self, namespace, shlibs, includes, pkgs, c_includes, cprefix):
39 super(GIRWriter, self).__init__()
41 '''This file was automatically generated from C sources - DO NOT EDIT!
42 To affect the contents of this file, edit the original C definitions,
43 and/or use gtk-doc annotations. ''')
44 self._write_repository(namespace, shlibs, includes, pkgs,
47 def _write_repository(self, namespace, shlibs, includes=None,
48 packages=None, c_includes=None, cprefix=None):
50 includes = frozenset()
52 packages = frozenset()
53 if c_includes is None:
54 c_includes = frozenset()
57 ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
58 ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
59 ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0'),
61 with self.tagcontext('repository', attrs):
62 for include in sorted(includes):
63 self._write_include(include)
64 for pkg in sorted(set(packages)):
65 self._write_pkgconfig_pkg(pkg)
66 for c_include in sorted(set(c_includes)):
67 self._write_c_include(c_include)
68 self._write_namespace(namespace, shlibs, cprefix)
70 def _write_include(self, include):
71 attrs = [('name', include.name), ('version', include.version)]
72 self.write_tag('include', attrs)
74 def _write_pkgconfig_pkg(self, package):
75 attrs = [('name', package)]
76 self.write_tag('package', attrs)
78 def _write_c_include(self, c_include):
79 attrs = [('name', c_include)]
80 self.write_tag('c:include', attrs)
82 def _write_namespace(self, namespace, shlibs, cprefix):
85 found_libname = find_library(l)
88 libraries.append(os.path.basename(found_libname))
90 attrs = [('name', namespace.name),
91 ('version', namespace.version),
92 ('shared-library', ','.join(libraries)),
93 ('c:prefix', cprefix)]
94 with self.tagcontext('namespace', attrs):
95 # We define a custom sorting function here because
96 # we want aliases to be first. They're a bit
97 # special because the typelib compiler expands them.
99 if isinstance(a, Alias):
100 if isinstance(b, Alias):
101 return cmp(a.name, b.name)
104 elif isinstance(b, Alias):
108 for node in sorted(namespace.nodes, cmp=nscmp):
109 self._write_node(node)
111 def _write_node(self, node):
112 if isinstance(node, Function):
113 self._write_function(node)
114 elif isinstance(node, Enum):
115 self._write_enum(node)
116 elif isinstance(node, Bitfield):
117 self._write_bitfield(node)
118 elif isinstance(node, (Class, Interface)):
119 self._write_class(node)
120 elif isinstance(node, Callback):
121 self._write_callback(node)
122 elif isinstance(node, Struct):
123 self._write_record(node)
124 elif isinstance(node, Union):
125 self._write_union(node)
126 elif isinstance(node, GLibBoxed):
127 self._write_boxed(node)
128 elif isinstance(node, Member):
129 # FIXME: atk_misc_instance singleton
131 elif isinstance(node, Alias):
132 self._write_alias(node)
133 elif isinstance(node, Constant):
134 self._write_constant(node)
136 print 'WRITER: Unhandled node', node
138 def _append_version(self, node, attrs):
140 attrs.append(('version', node.version))
142 def _write_attributes(self, node):
143 for key, value in node.attributes:
144 self.write_tag('attribute', [('name', key), ('value', value)])
146 def _append_deprecated(self, node, attrs):
148 attrs.append(('deprecated', node.deprecated))
149 if node.deprecated_version:
150 attrs.append(('deprecated-version',
151 node.deprecated_version))
153 def _append_throws(self, func, attrs):
155 attrs.append(('throws', '1'))
157 def _write_alias(self, alias):
158 attrs = [('name', alias.name), ('target', alias.target)]
159 if alias.ctype is not None:
160 attrs.append(('c:type', alias.ctype))
161 self.write_tag('alias', attrs)
163 def _write_callable(self, callable, tag_name, extra_attrs):
164 attrs = [('name', callable.name)]
165 attrs.extend(extra_attrs)
167 attrs.append(('doc', callable.doc))
168 self._append_version(callable, attrs)
169 self._append_deprecated(callable, attrs)
170 self._append_throws(callable, attrs)
171 with self.tagcontext(tag_name, attrs):
172 self._write_attributes(callable)
173 self._write_return_type(callable.retval)
174 self._write_parameters(callable.parameters)
176 def _write_function(self, func, tag_name='function'):
177 attrs = [('c:identifier', func.symbol)]
178 self._write_callable(func, tag_name, attrs)
180 def _write_method(self, method):
181 self._write_function(method, tag_name='method')
183 def _write_static_method(self, method):
184 self._write_function(method, tag_name='function')
186 def _write_constructor(self, method):
187 self._write_function(method, tag_name='constructor')
189 def _write_return_type(self, return_):
193 assert return_.transfer is not None, return_
196 attrs.append(('transfer-ownership', return_.transfer))
198 attrs.append(('doc', return_.doc))
199 with self.tagcontext('return-value', attrs):
200 self._write_type(return_.type)
202 def _write_parameters(self, parameters):
205 with self.tagcontext('parameters'):
206 for parameter in parameters:
207 self._write_parameter(parameter)
209 def _write_parameter(self, parameter):
210 assert parameter.transfer is not None, parameter
213 if parameter.name is not None:
214 attrs.append(('name', parameter.name))
215 if parameter.direction != 'in':
216 attrs.append(('direction', parameter.direction))
217 attrs.append(('transfer-ownership',
219 if parameter.allow_none:
220 attrs.append(('allow-none', '1'))
222 attrs.append(('scope', parameter.scope))
223 if parameter.closure_index >= 0:
224 attrs.append(('closure', '%d' % parameter.closure_index))
225 if parameter.destroy_index >= 0:
226 attrs.append(('destroy', '%d' % parameter.destroy_index))
228 attrs.append(('doc', parameter.doc))
229 with self.tagcontext('parameter', attrs):
230 self._write_type(parameter.type)
232 def _type_to_string(self, ntype):
233 if isinstance(ntype, basestring):
237 def _write_type(self, ntype, relation=None):
238 if isinstance(ntype, basestring):
242 typename = ntype.name
243 type_cname = ntype.ctype
244 if isinstance(ntype, Varargs):
245 with self.tagcontext('varargs', []):
248 if isinstance(ntype, Array):
250 if not ntype.zeroterminated:
251 attrs.append(('zero-terminated', '0'))
252 if ntype.length_param_index >= 0:
253 attrs.append(('length', '%d' % (ntype.length_param_index, )))
254 attrs.append(('c:type', ntype.ctype))
255 if ntype.size is not None:
256 attrs.append(('fixed-size', ntype.size))
257 with self.tagcontext('array', attrs):
258 self._write_type(ntype.element_type)
260 attrs = [('name', self._type_to_string(ntype))]
261 # FIXME: figure out if type references a basic type
262 # or a boxed/class/interface etc. and skip
263 # writing the ctype if the latter.
264 if type_cname is not None:
265 attrs.append(('c:type', type_cname))
266 if isinstance(ntype, List) and ntype.element_type:
267 with self.tagcontext('type', attrs):
268 self._write_type(ntype.element_type)
270 if isinstance(ntype, Map) and ntype.key_type:
271 with self.tagcontext('type', attrs):
272 self._write_type(ntype.key_type)
273 self._write_type(ntype.value_type)
275 # Not a special type, just write it out
276 self.write_tag('type', attrs)
278 def _write_enum(self, enum):
279 attrs = [('name', enum.name)]
281 attrs.append(('doc', enum.doc))
282 self._append_version(enum, attrs)
283 self._append_deprecated(enum, attrs)
284 if isinstance(enum, GLibEnum):
285 attrs.extend([('glib:type-name', enum.type_name),
286 ('glib:get-type', enum.get_type),
287 ('c:type', enum.ctype)])
289 attrs.append(('glib:error-quark', enum.error_quark))
291 attrs.append(('c:type', enum.symbol))
293 with self.tagcontext('enumeration', attrs):
294 self._write_attributes(enum)
295 for member in enum.members:
296 self._write_member(member)
298 def _write_bitfield(self, bitfield):
299 attrs = [('name', bitfield.name)]
301 attrs.append(('doc', bitfield.doc))
302 self._append_version(bitfield, attrs)
303 self._append_deprecated(bitfield, attrs)
304 if isinstance(bitfield, GLibFlags):
305 attrs.extend([('glib:type-name', bitfield.type_name),
306 ('glib:get-type', bitfield.get_type),
307 ('c:type', bitfield.ctype)])
309 attrs.append(('c:type', bitfield.symbol))
310 with self.tagcontext('bitfield', attrs):
311 self._write_attributes(bitfield)
312 for member in bitfield.members:
313 self._write_member(member)
315 def _write_member(self, member):
316 attrs = [('name', member.name),
317 ('value', str(member.value)),
318 ('c:identifier', member.symbol)]
319 if isinstance(member, GLibEnumMember):
320 attrs.append(('glib:nick', member.nick))
321 self.write_tag('member', attrs)
323 def _write_constant(self, constant):
324 attrs = [('name', constant.name),
325 ('value', str(constant.value))]
326 with self.tagcontext('constant', attrs):
327 self._write_type(constant.type)
329 def _write_class(self, node):
330 attrs = [('name', node.name),
331 ('c:type', node.ctype)]
333 attrs.append(('doc', node.doc))
334 self._append_version(node, attrs)
335 self._append_deprecated(node, attrs)
336 if isinstance(node, Class):
338 if node.parent is not None:
339 attrs.append(('parent', node.parent))
341 attrs.append(('abstract', '1'))
343 tag_name = 'interface'
344 if isinstance(node, (GLibObject, GLibInterface)):
345 attrs.append(('glib:type-name', node.type_name))
347 attrs.append(('glib:get-type', node.get_type))
348 if node.glib_type_struct:
349 attrs.append(('glib:type-struct', node.glib_type_struct.name))
350 with self.tagcontext(tag_name, attrs):
351 self._write_attributes(node)
352 if isinstance(node, GLibObject):
353 for iface in node.interfaces:
354 self.write_tag('implements', [('name', iface)])
355 if isinstance(node, Interface):
356 for iface in node.prerequisites:
357 self.write_tag('prerequisite', [('name', iface)])
358 if isinstance(node, Class):
359 for method in node.constructors:
360 self._write_constructor(method)
361 for method in node.static_methods:
362 self._write_static_method(method)
363 for vfunc in node.virtual_methods:
364 self._write_vfunc(vfunc)
365 for method in node.methods:
366 self._write_method(method)
367 for prop in node.properties:
368 self._write_property(prop)
369 for field in node.fields:
370 self._write_field(field)
371 for signal in node.signals:
372 self._write_signal(signal)
374 def _write_boxed(self, boxed):
375 attrs = [('c:type', boxed.ctype),
376 ('glib:name', boxed.name)]
378 attrs.append(('doc', boxed.doc))
379 attrs.extend(self._boxed_attrs(boxed))
380 with self.tagcontext('glib:boxed', attrs):
381 self._write_attributes(boxed)
382 for method in boxed.constructors:
383 self._write_constructor(method)
384 for method in boxed.methods:
385 self._write_method(method)
387 def _write_property(self, prop):
388 attrs = [('name', prop.name)]
389 self._append_version(prop, attrs)
390 self._append_deprecated(prop, attrs)
391 # Properties are assumed to be readable (see also generate.c)
392 if not prop.readable:
393 attrs.append(('readable', '0'))
395 attrs.append(('writable', '1'))
397 attrs.append(('construct', '1'))
398 if prop.construct_only:
399 attrs.append(('construct-only', '1'))
401 attrs.append(('doc', prop.doc))
402 with self.tagcontext('property', attrs):
403 self._write_attributes(prop)
404 self._write_type(prop.type)
406 def _write_vfunc(self, vf):
409 attrs.append(('invoker', vf.invoker))
410 self._write_callable(vf, 'virtual-method', attrs)
412 def _write_callback(self, callback):
413 attrs = [('c:type', callback.ctype)]
414 self._write_callable(callback, 'callback', attrs)
416 def _boxed_attrs(self, boxed):
417 return [('glib:type-name', boxed.type_name),
418 ('glib:get-type', boxed.get_type)]
420 def _write_record(self, record, extra_attrs=[]):
421 attrs = list(extra_attrs)
422 if record.name is not None:
423 attrs.append(('name', record.name))
424 if record.symbol is not None: # the record might be anonymous
425 attrs.append(('c:type', record.symbol))
427 attrs.append(('disguised', '1'))
428 if isinstance(record, GLibRecord):
429 if record.is_gtype_struct_for:
430 attrs.append(('glib:is-gtype-struct-for',
431 record.is_gtype_struct_for))
433 attrs.append(('doc', record.doc))
434 self._append_version(record, attrs)
435 self._append_deprecated(record, attrs)
436 if isinstance(record, GLibBoxed):
437 attrs.extend(self._boxed_attrs(record))
438 with self.tagcontext('record', attrs):
439 self._write_attributes(record)
441 for field in record.fields:
442 self._write_field(field)
443 for method in record.constructors:
444 self._write_constructor(method)
445 for method in record.methods:
446 self._write_method(method)
448 def _write_union(self, union):
450 if union.name is not None:
451 attrs.append(('name', union.name))
452 if union.symbol is not None: # the union might be anonymous
453 attrs.append(('c:type', union.symbol))
455 attrs.append(('doc', union.doc))
456 self._append_version(union, attrs)
457 self._append_deprecated(union, attrs)
458 if isinstance(union, GLibBoxed):
459 attrs.extend(self._boxed_attrs(union))
460 with self.tagcontext('union', attrs):
461 self._write_attributes(union)
463 for field in union.fields:
464 self._write_field(field)
465 for method in union.constructors:
466 self._write_constructor(method)
467 for method in union.methods:
468 self._write_method(method)
470 def _write_field(self, field):
471 if isinstance(field, Function):
472 self._write_method(field)
475 if isinstance(field, Callback):
476 self._write_callback(field)
477 elif isinstance(field, Struct):
478 self._write_record(field)
479 elif isinstance(field, Union):
480 self._write_union(field)
482 attrs = [('name', field.name)]
483 # Fields are assumed to be read-only
484 # (see also girparser.c and generate.c)
485 if not field.readable:
486 attrs.append(('readable', '0'))
488 attrs.append(('writable', '1'))
490 attrs.append(('bits', str(field.bits)))
491 with self.tagcontext('field', attrs):
492 self._write_attributes(field)
493 self._write_type(field.type)
495 def _write_signal(self, signal):
496 attrs = [('name', signal.name)]
498 attrs.append(('doc', signal.doc))
499 self._append_version(signal, attrs)
500 self._append_deprecated(signal, attrs)
501 with self.tagcontext('glib:signal', attrs):
502 self._write_attributes(signal)
503 self._write_return_type(signal.retval)
504 self._write_parameters(signal.parameters)