2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
21 from __future__ import with_statement
24 from ctypes.util import find_library
26 from .ast import (Alias, Array, Bitfield, Callback, Class, Constant, Enum,
27 Function, Interface, List, Map, Member, Struct, Union,
29 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
30 GLibFlags, GLibObject, GLibInterface)
31 from .xmlwriter import XMLWriter
34 class GIRWriter(XMLWriter):
36 def __init__(self, namespace, shlibs, includes, pkgs):
37 super(GIRWriter, self).__init__()
39 '''This file was automatically generated from C sources - DO NOT EDIT!
40 To affect the contents of this file, edit the original C definitions,
41 and/or use gtk-doc annotations. ''')
42 self._write_repository(namespace, shlibs, includes, pkgs)
44 def _write_repository(self, namespace, shlibs, includes=None,
47 includes = frozenset()
49 packages = frozenset()
52 ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
53 ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
54 ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0'),
56 with self.tagcontext('repository', attrs):
57 for include in sorted(includes):
58 self._write_include(include)
59 for pkg in sorted(set(packages)):
60 self._write_pkgconfig_pkg(pkg)
61 self._write_namespace(namespace, shlibs)
63 def _write_include(self, include):
64 attrs = [('name', include.name), ('version', include.version)]
65 self.write_tag('include', attrs)
67 def _write_pkgconfig_pkg(self, package):
68 attrs = [('name', package)]
69 self.write_tag('package', attrs)
71 def _write_namespace(self, namespace, shlibs):
74 found_libname = find_library(l)
77 libraries.append(os.path.basename(found_libname))
79 attrs = [('name', namespace.name),
80 ('version', namespace.version),
81 ('shared-library', ','.join(libraries))]
82 with self.tagcontext('namespace', attrs):
83 for node in namespace.nodes:
84 self._write_node(node)
86 def _write_node(self, node):
87 if isinstance(node, Function):
88 self._write_function(node)
89 elif isinstance(node, Enum):
90 self._write_enum(node)
91 elif isinstance(node, Bitfield):
92 self._write_bitfield(node)
93 elif isinstance(node, (Class, Interface)):
94 self._write_class(node)
95 elif isinstance(node, Callback):
96 self._write_callback(node)
97 elif isinstance(node, Struct):
98 self._write_record(node)
99 elif isinstance(node, Union):
100 self._write_union(node)
101 elif isinstance(node, GLibBoxed):
102 self._write_boxed(node)
103 elif isinstance(node, Member):
104 # FIXME: atk_misc_instance singleton
106 elif isinstance(node, Alias):
107 self._write_alias(node)
108 elif isinstance(node, Constant):
109 self._write_constant(node)
111 print 'WRITER: Unhandled node', node
113 def _append_version(self, node, attrs):
115 attrs.append(('version', node.version))
117 def _append_deprecated(self, node, attrs):
119 attrs.append(('deprecated', node.deprecated))
120 if node.deprecated_version:
121 attrs.append(('deprecated-version',
122 node.deprecated_version))
124 def _append_throws(self, func, attrs):
126 attrs.append(('throws', '1'))
128 def _write_alias(self, alias):
129 attrs = [('name', alias.name), ('target', alias.target)]
130 if alias.ctype is not None:
131 attrs.append(('c:type', alias.ctype))
132 self.write_tag('alias', attrs)
134 def _write_function(self, func, tag_name='function'):
135 attrs = [('name', func.name),
136 ('c:identifier', func.symbol)]
138 attrs.append(('doc', func.doc))
139 self._append_version(func, attrs)
140 self._append_deprecated(func, attrs)
141 self._append_throws(func, attrs)
142 with self.tagcontext(tag_name, attrs):
143 self._write_return_type(func.retval)
144 self._write_parameters(func.parameters)
146 def _write_method(self, method):
147 self._write_function(method, tag_name='method')
149 def _write_static_method(self, method):
150 self._write_function(method, tag_name='function')
152 def _write_constructor(self, method):
153 self._write_function(method, tag_name='constructor')
155 def _write_return_type(self, return_):
159 assert return_.transfer is not None, return_
162 attrs.append(('transfer-ownership', return_.transfer))
164 attrs.append(('doc', return_.doc))
165 with self.tagcontext('return-value', attrs):
166 self._write_type(return_.type)
168 def _write_parameters(self, parameters):
171 with self.tagcontext('parameters'):
172 for parameter in parameters:
173 self._write_parameter(parameter)
175 def _write_parameter(self, parameter):
176 assert parameter.transfer is not None, parameter
179 if parameter.name is not None:
180 attrs.append(('name', parameter.name))
181 if parameter.direction != 'in':
182 attrs.append(('direction', parameter.direction))
183 attrs.append(('transfer-ownership',
185 if parameter.allow_none:
186 attrs.append(('allow-none', '1'))
188 attrs.append(('scope', parameter.scope))
189 if parameter.closure_index >= 0:
190 attrs.append(('closure', '%d' % parameter.closure_index))
191 if parameter.destroy_index >= 0:
192 attrs.append(('destroy', '%d' % parameter.destroy_index))
194 attrs.append(('doc', parameter.doc))
195 with self.tagcontext('parameter', attrs):
196 self._write_type(parameter.type)
198 def _type_to_string(self, ntype):
199 if isinstance(ntype, basestring):
203 def _write_type(self, ntype, relation=None):
204 if isinstance(ntype, basestring):
208 typename = ntype.name
209 type_cname = ntype.ctype
210 if isinstance(ntype, Varargs):
211 with self.tagcontext('varargs', []):
214 if isinstance(ntype, Array):
216 if not ntype.zeroterminated:
217 attrs.append(('zero-terminated', '0'))
218 if ntype.length_param_index >= 0:
219 attrs.append(('length', '%d' % (ntype.length_param_index, )))
220 attrs.append(('c:type', ntype.ctype))
221 if ntype.size is not None:
222 attrs.append(('fixed-size', ntype.size))
223 with self.tagcontext('array', attrs):
224 self._write_type(ntype.element_type)
226 attrs = [('name', self._type_to_string(ntype))]
227 # FIXME: figure out if type references a basic type
228 # or a boxed/class/interface etc. and skip
229 # writing the ctype if the latter.
230 if type_cname is not None:
231 attrs.append(('c:type', type_cname))
232 if isinstance(ntype, List) and ntype.element_type:
233 with self.tagcontext('type', attrs):
234 self._write_type(ntype.element_type)
236 if isinstance(ntype, Map) and ntype.key_type:
237 with self.tagcontext('type', attrs):
238 self._write_type(ntype.key_type)
239 self._write_type(ntype.value_type)
241 # Not a special type, just write it out
242 self.write_tag('type', attrs)
244 def _write_enum(self, enum):
245 attrs = [('name', enum.name)]
247 attrs.append(('doc', enum.doc))
248 self._append_version(enum, attrs)
249 self._append_deprecated(enum, attrs)
250 if isinstance(enum, GLibEnum):
251 attrs.extend([('glib:type-name', enum.type_name),
252 ('glib:get-type', enum.get_type),
253 ('c:type', enum.ctype)])
255 attrs.append(('glib:error-quark', enum.error_quark))
257 attrs.append(('c:type', enum.symbol))
259 with self.tagcontext('enumeration', attrs):
260 for member in enum.members:
261 self._write_member(member)
263 def _write_bitfield(self, bitfield):
264 attrs = [('name', bitfield.name)]
266 attrs.append(('doc', bitfield.doc))
267 self._append_version(bitfield, attrs)
268 self._append_deprecated(bitfield, attrs)
269 if isinstance(bitfield, GLibFlags):
270 attrs.extend([('glib:type-name', bitfield.type_name),
271 ('glib:get-type', bitfield.get_type),
272 ('c:type', bitfield.ctype)])
274 attrs.append(('c:type', bitfield.symbol))
275 with self.tagcontext('bitfield', attrs):
276 for member in bitfield.members:
277 self._write_member(member)
279 def _write_member(self, member):
280 attrs = [('name', member.name),
281 ('value', str(member.value)),
282 ('c:identifier', member.symbol)]
283 if isinstance(member, GLibEnumMember):
284 attrs.append(('glib:nick', member.nick))
285 self.write_tag('member', attrs)
287 def _write_constant(self, constant):
288 attrs = [('name', constant.name),
289 ('value', str(constant.value))]
290 with self.tagcontext('constant', attrs):
291 self._write_type(constant.type)
293 def _write_class(self, node):
294 attrs = [('name', node.name),
295 ('c:type', node.ctype)]
297 attrs.append(('doc', node.doc))
298 self._append_version(node, attrs)
299 self._append_deprecated(node, attrs)
300 if isinstance(node, Class):
302 if node.parent is not None:
303 attrs.append(('parent', node.parent))
305 attrs.append(('abstract', '1'))
307 tag_name = 'interface'
308 if isinstance(node, (GLibObject, GLibInterface)):
309 attrs.append(('glib:type-name', node.type_name))
311 attrs.append(('glib:get-type', node.get_type))
312 if isinstance(node, GLibObject):
313 if node.class_struct:
314 attrs.append(('glib:class-struct', node.class_struct.name))
315 with self.tagcontext(tag_name, attrs):
316 if isinstance(node, GLibObject):
317 for iface in node.interfaces:
318 self.write_tag('implements', [('name', iface)])
319 if isinstance(node, Interface):
320 for iface in node.prerequisites:
321 self.write_tag('prerequisite', [('name', iface)])
322 if isinstance(node, Class):
323 for method in node.constructors:
324 self._write_constructor(method)
325 for method in node.static_methods:
326 self._write_static_method(method)
327 for method in node.methods:
328 self._write_method(method)
329 for prop in node.properties:
330 self._write_property(prop)
331 for field in node.fields:
332 self._write_field(field)
333 for signal in node.signals:
334 self._write_signal(signal)
336 def _write_boxed(self, boxed):
337 attrs = [('c:type', boxed.ctype),
338 ('glib:name', boxed.name)]
340 attrs.append(('doc', boxed.doc))
341 attrs.extend(self._boxed_attrs(boxed))
342 with self.tagcontext('glib:boxed', attrs):
343 for method in boxed.constructors:
344 self._write_constructor(method)
345 for method in boxed.methods:
346 self._write_method(method)
348 def _write_property(self, prop):
349 attrs = [('name', prop.name)]
350 self._append_version(prop, attrs)
351 self._append_deprecated(prop, attrs)
352 # Properties are assumed to be readable (see also generate.c)
353 if not prop.readable:
354 attrs.append(('readable', '0'))
356 attrs.append(('writable', '1'))
358 attrs.append(('construct', '1'))
359 if prop.construct_only:
360 attrs.append(('construct-only', '1'))
362 attrs.append(('doc', prop.doc))
363 with self.tagcontext('property', attrs):
364 self._write_type(prop.type)
366 def _write_callback(self, callback):
367 # FIXME: reuse _write_function
368 attrs = [('name', callback.name), ('c:type', callback.ctype)]
370 attrs.append(('doc', callback.doc))
371 self._append_version(callback, attrs)
372 self._append_deprecated(callback, attrs)
373 self._append_throws(callback, attrs)
374 with self.tagcontext('callback', attrs):
375 self._write_return_type(callback.retval)
376 self._write_parameters(callback.parameters)
378 def _boxed_attrs(self, boxed):
379 return [('glib:type-name', boxed.type_name),
380 ('glib:get-type', boxed.get_type)]
382 def _write_record(self, record, extra_attrs=[]):
383 attrs = list(extra_attrs)
384 if record.name is not None:
385 attrs.append(('name', record.name))
386 if record.symbol is not None: # the record might be anonymous
387 attrs.append(('c:type', record.symbol))
389 attrs.append(('disguised', '1'))
390 if record.is_gobject_struct_for:
391 attrs.append(('glib:is-class-struct-for',
392 record.is_gobject_struct_for))
394 attrs.append(('doc', record.doc))
395 self._append_version(record, attrs)
396 self._append_deprecated(record, attrs)
397 if isinstance(record, GLibBoxed):
398 attrs.extend(self._boxed_attrs(record))
399 with self.tagcontext('record', attrs):
401 for field in record.fields:
402 self._write_field(field)
403 for method in record.constructors:
404 self._write_constructor(method)
405 for method in record.methods:
406 self._write_method(method)
408 def _write_union(self, union):
410 if union.name is not None:
411 attrs.append(('name', union.name))
412 if union.symbol is not None: # the union might be anonymous
413 attrs.append(('c:type', union.symbol))
415 attrs.append(('doc', union.doc))
416 self._append_version(union, attrs)
417 self._append_deprecated(union, attrs)
418 if isinstance(union, GLibBoxed):
419 attrs.extend(self._boxed_attrs(union))
420 with self.tagcontext('union', attrs):
422 for field in union.fields:
423 self._write_field(field)
424 for method in union.constructors:
425 self._write_constructor(method)
426 for method in union.methods:
427 self._write_method(method)
429 def _write_field(self, field):
430 if isinstance(field, Function):
431 self._write_method(field)
434 if isinstance(field, Callback):
435 self._write_callback(field)
436 elif isinstance(field, Struct):
437 self._write_record(field)
438 elif isinstance(field, Union):
439 self._write_union(field)
441 attrs = [('name', field.name)]
442 # Fields are assumed to be read-only
443 # (see also girparser.c and generate.c)
444 if not field.readable:
445 attrs.append(('readable', '0'))
447 attrs.append(('writable', '1'))
449 attrs.append(('bits', str(field.bits)))
450 with self.tagcontext('field', attrs):
451 self._write_type(field.type)
453 def _write_signal(self, signal):
454 attrs = [('name', signal.name)]
456 attrs.append(('doc', signal.doc))
457 self._append_version(signal, attrs)
458 self._append_deprecated(signal, attrs)
459 with self.tagcontext('glib:signal', attrs):
460 self._write_return_type(signal.retval)
461 self._write_parameters(signal.parameters)