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 .xmlwriter import XMLWriter
27 # Bump this for *incompatible* changes to the .gir.
28 # Compatible changes we just make inline
29 COMPATIBLE_GIR_VERSION = '1.2'
31 class GIRWriter(XMLWriter):
33 def __init__(self, namespace, shlibs, includes, pkgs, c_includes):
34 super(GIRWriter, self).__init__()
36 '''This file was automatically generated from C sources - DO NOT EDIT!
37 To affect the contents of this file, edit the original C definitions,
38 and/or use gtk-doc annotations. ''')
39 self._write_repository(namespace, shlibs, includes, pkgs,
42 def _write_repository(self, namespace, shlibs, includes=None,
43 packages=None, c_includes=None):
45 includes = frozenset()
47 packages = frozenset()
48 if c_includes is None:
49 c_includes = frozenset()
51 ('version', COMPATIBLE_GIR_VERSION),
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 for c_include in sorted(set(c_includes)):
62 self._write_c_include(c_include)
63 self._namespace = namespace
64 self._write_namespace(namespace, shlibs)
65 self._namespace = None
67 def _write_include(self, include):
68 attrs = [('name', include.name), ('version', include.version)]
69 self.write_tag('include', attrs)
71 def _write_pkgconfig_pkg(self, package):
72 attrs = [('name', package)]
73 self.write_tag('package', attrs)
75 def _write_c_include(self, c_include):
76 attrs = [('name', c_include)]
77 self.write_tag('c:include', attrs)
79 def _write_namespace(self, namespace, shlibs):
80 attrs = [('name', namespace.name),
81 ('version', namespace.version),
82 ('shared-library', ','.join(shlibs)),
83 ('c:identifier-prefixes', ','.join(namespace.identifier_prefixes)),
84 ('c:symbol-prefixes', ','.join(namespace.symbol_prefixes))]
85 with self.tagcontext('namespace', attrs):
86 # We define a custom sorting function here because
87 # we want aliases to be first. They're a bit
88 # special because the typelib compiler expands them.
90 if isinstance(a, ast.Alias):
91 if isinstance(b, ast.Alias):
92 return cmp(a.name, b.name)
95 elif isinstance(b, ast.Alias):
99 for node in sorted(namespace.itervalues(), cmp=nscmp):
100 self._write_node(node)
102 def _write_node(self, node):
103 if isinstance(node, ast.Function):
104 self._write_function(node)
105 elif isinstance(node, ast.Enum):
106 self._write_enum(node)
107 elif isinstance(node, ast.Bitfield):
108 self._write_bitfield(node)
109 elif isinstance(node, (ast.Class, ast.Interface)):
110 self._write_class(node)
111 elif isinstance(node, ast.Callback):
112 self._write_callback(node)
113 elif isinstance(node, ast.Record):
114 self._write_record(node)
115 elif isinstance(node, ast.Union):
116 self._write_union(node)
117 elif isinstance(node, ast.Boxed):
118 self._write_boxed(node)
119 elif isinstance(node, ast.Member):
120 # FIXME: atk_misc_instance singleton
122 elif isinstance(node, ast.Alias):
123 self._write_alias(node)
124 elif isinstance(node, ast.Constant):
125 self._write_constant(node)
127 print 'WRITER: Unhandled node', node
129 def _append_version(self, node, attrs):
131 attrs.append(('version', node.version))
133 def _write_generic(self, node):
134 for key, value in node.attributes:
135 self.write_tag('attribute', [('name', key), ('value', value)])
136 if hasattr(node, 'doc') and node.doc:
137 self.write_tag('doc', [('xml:whitespace', 'preserve')],
140 def _append_node_generic(self, node, attrs):
141 if node.skip or not node.introspectable:
142 attrs.append(('introspectable', '0'))
144 attrs.append(('deprecated', node.deprecated))
145 if node.deprecated_version:
146 attrs.append(('deprecated-version',
147 node.deprecated_version))
149 attrs.append(('stability', node.stability))
151 def _append_throws(self, func, attrs):
153 attrs.append(('throws', '1'))
155 def _write_alias(self, alias):
156 attrs = [('name', alias.name)]
157 if alias.ctype is not None:
158 attrs.append(('c:type', alias.ctype))
159 self._append_node_generic(alias, attrs)
160 with self.tagcontext('alias', attrs):
161 self._write_generic(alias)
162 self._write_type_ref(alias.target)
164 def _write_callable(self, callable, tag_name, extra_attrs):
165 attrs = [('name', callable.name)]
166 attrs.extend(extra_attrs)
167 self._append_version(callable, attrs)
168 self._append_node_generic(callable, attrs)
169 self._append_throws(callable, attrs)
170 with self.tagcontext(tag_name, attrs):
171 self._write_generic(callable)
172 self._write_return_type(callable.retval, parent=callable)
173 self._write_parameters(callable, callable.parameters)
175 def _write_function(self, func, tag_name='function'):
177 if hasattr(func, 'symbol'):
178 attrs.append(('c:identifier', func.symbol))
180 attrs.append(('shadowed-by', func.shadowed_by))
182 attrs.append(('shadows', func.shadows))
183 if func.moved_to is not None:
184 attrs.append(('moved-to', func.moved_to))
185 self._write_callable(func, tag_name, attrs)
187 def _write_method(self, method):
188 self._write_function(method, tag_name='method')
190 def _write_static_method(self, method):
191 self._write_function(method, tag_name='function')
193 def _write_constructor(self, method):
194 self._write_function(method, tag_name='constructor')
196 def _write_return_type(self, return_, parent=None):
202 attrs.append(('transfer-ownership', return_.transfer))
204 attrs.append(('skip', '1'))
205 with self.tagcontext('return-value', attrs):
206 self._write_generic(return_)
207 self._write_type(return_.type, function=parent)
209 def _write_parameters(self, parent, parameters):
212 with self.tagcontext('parameters'):
213 for parameter in parameters:
214 self._write_parameter(parent, parameter)
216 def _write_parameter(self, parent, parameter):
218 if parameter.argname is not None:
219 attrs.append(('name', parameter.argname))
220 if (parameter.direction is not None) and (parameter.direction != 'in'):
221 attrs.append(('direction', parameter.direction))
222 attrs.append(('caller-allocates',
223 '1' if parameter.caller_allocates else '0'))
224 if parameter.transfer:
225 attrs.append(('transfer-ownership',
227 if parameter.allow_none:
228 attrs.append(('allow-none', '1'))
230 attrs.append(('scope', parameter.scope))
231 if parameter.closure_name is not None:
232 idx = parent.get_parameter_index(parameter.closure_name)
233 attrs.append(('closure', '%d' % (idx, )))
234 if parameter.destroy_name is not None:
235 idx = parent.get_parameter_index(parameter.destroy_name)
236 attrs.append(('destroy', '%d' % (idx, )))
238 attrs.append(('skip', '1'))
239 with self.tagcontext('parameter', attrs):
240 self._write_generic(parameter)
241 self._write_type(parameter.type, function=parent)
243 def _type_to_name(self, typeval):
244 if not typeval.resolved:
245 raise AssertionError("Caught unresolved type %r (ctype=%r)" % (typeval, typeval.ctype))
246 assert typeval.target_giname is not None
247 prefix = self._namespace.name + '.'
248 if typeval.target_giname.startswith(prefix):
249 return typeval.target_giname[len(prefix):]
250 return typeval.target_giname
252 def _write_type_ref(self, ntype):
253 """ Like _write_type, but only writes the type name rather than the full details """
254 assert isinstance(ntype, ast.Type), ntype
257 attrs.append(('c:type', ntype.ctype))
258 if isinstance(ntype, ast.Array):
259 if ntype.array_type != ast.Array.C:
260 attrs.insert(0, ('name', ntype.array_type))
261 elif isinstance(ntype, ast.List):
263 attrs.insert(0, ('name', ntype.name))
264 elif isinstance(ntype, ast.Map):
265 attrs.insert(0, ('name', 'GLib.HashTable'))
267 if ntype.target_giname:
268 attrs.insert(0, ('name', self._type_to_name(ntype)))
269 elif ntype.target_fundamental:
270 attrs.insert(0, ('name', ntype.target_fundamental))
272 self.write_tag('type', attrs)
274 def _write_type(self, ntype, relation=None, function=None):
275 assert isinstance(ntype, ast.Type), ntype
277 if ntype.complete_ctype:
278 attrs.append(('c:type', ntype.complete_ctype))
280 attrs.append(('c:type', ntype.ctype))
281 if isinstance(ntype, ast.Varargs):
282 with self.tagcontext('varargs', []):
284 elif isinstance(ntype, ast.Array):
285 if ntype.array_type != ast.Array.C:
286 attrs.insert(0, ('name', ntype.array_type))
287 # we insert an explicit 'zero-terminated' attribute
288 # when it is false, or when it would not be implied
289 # by the absence of length and fixed-size
290 if not ntype.zeroterminated:
291 attrs.insert(0, ('zero-terminated', '0'))
292 elif (ntype.zeroterminated
293 and (ntype.size is not None or ntype.length_param_name is not None)):
294 attrs.insert(0, ('zero-terminated', '1'))
295 if ntype.size is not None:
296 attrs.append(('fixed-size', '%d' % (ntype.size, )))
297 if ntype.length_param_name is not None:
299 attrs.insert(0, ('length', '%d'
300 % (function.get_parameter_index(ntype.length_param_name, ))))
302 with self.tagcontext('array', attrs):
303 self._write_type(ntype.element_type)
304 elif isinstance(ntype, ast.List):
306 attrs.insert(0, ('name', ntype.name))
307 with self.tagcontext('type', attrs):
308 self._write_type(ntype.element_type)
309 elif isinstance(ntype, ast.Map):
310 attrs.insert(0, ('name', 'GLib.HashTable'))
311 with self.tagcontext('type', attrs):
312 self._write_type(ntype.key_type)
313 self._write_type(ntype.value_type)
315 # REWRITEFIXME - enable this for 1.2
316 if ntype.target_giname:
317 attrs.insert(0, ('name', self._type_to_name(ntype)))
318 elif ntype.target_fundamental:
319 # attrs = [('fundamental', ntype.target_fundamental)]
320 attrs.insert(0, ('name', ntype.target_fundamental))
321 elif ntype.target_foreign:
322 attrs.insert(0, ('foreign', '1'))
323 self.write_tag('type', attrs)
325 def _append_registered(self, node, attrs):
326 assert isinstance(node, ast.Registered)
328 attrs.extend([('glib:type-name', node.gtype_name),
329 ('glib:get-type', node.get_type)])
331 def _write_enum(self, enum):
332 attrs = [('name', enum.name)]
333 self._append_version(enum, attrs)
334 self._append_node_generic(enum, attrs)
335 self._append_registered(enum, attrs)
336 attrs.append(('c:type', enum.ctype))
337 if enum.error_domain:
338 attrs.append(('glib:error-domain', enum.error_domain))
340 with self.tagcontext('enumeration', attrs):
341 self._write_generic(enum)
342 for member in enum.members:
343 self._write_member(member)
344 for method in sorted(enum.static_methods):
345 self._write_static_method(method)
347 def _write_bitfield(self, bitfield):
348 attrs = [('name', bitfield.name)]
349 self._append_version(bitfield, attrs)
350 self._append_node_generic(bitfield, attrs)
351 self._append_registered(bitfield, attrs)
352 attrs.append(('c:type', bitfield.ctype))
353 with self.tagcontext('bitfield', attrs):
354 self._write_generic(bitfield)
355 for member in bitfield.members:
356 self._write_member(member)
357 for method in sorted(bitfield.static_methods):
358 self._write_static_method(method)
360 def _write_member(self, member):
361 attrs = [('name', member.name),
362 ('value', str(member.value)),
363 ('c:identifier', member.symbol)]
364 if member.nick is not None:
365 attrs.append(('glib:nick', member.nick))
366 with self.tagcontext('member', attrs):
367 self._write_generic(member)
369 def _write_constant(self, constant):
370 attrs = [('name', constant.name),
371 ('value', constant.value),
372 ('c:type', constant.ctype)]
373 with self.tagcontext('constant', attrs):
374 self._write_type(constant.value_type)
376 def _write_class(self, node):
377 attrs = [('name', node.name),
378 ('c:symbol-prefix', node.c_symbol_prefix),
379 ('c:type', node.ctype)]
380 self._append_version(node, attrs)
381 self._append_node_generic(node, attrs)
382 if isinstance(node, ast.Class):
384 if node.parent is not None:
385 attrs.append(('parent',
386 self._type_to_name(node.parent)))
388 attrs.append(('abstract', '1'))
390 assert isinstance(node, ast.Interface)
391 tag_name = 'interface'
392 attrs.append(('glib:type-name', node.gtype_name))
393 if node.get_type is not None:
394 attrs.append(('glib:get-type', node.get_type))
395 if node.glib_type_struct is not None:
396 attrs.append(('glib:type-struct',
397 self._type_to_name(node.glib_type_struct)))
398 if isinstance(node, ast.Class):
400 attrs.append(('glib:fundamental', '1'))
402 attrs.append(('glib:ref-func', node.ref_func))
404 attrs.append(('glib:unref-func', node.unref_func))
405 if node.set_value_func:
406 attrs.append(('glib:set-value-func', node.set_value_func))
407 if node.get_value_func:
408 attrs.append(('glib:get-value-func', node.get_value_func))
409 with self.tagcontext(tag_name, attrs):
410 self._write_generic(node)
411 if isinstance(node, ast.Class):
412 for iface in sorted(node.interfaces):
413 self.write_tag('implements',
414 [('name', self._type_to_name(iface))])
415 if isinstance(node, ast.Interface):
416 for iface in sorted(node.prerequisites):
417 self.write_tag('prerequisite',
418 [('name', self._type_to_name(iface))])
419 if isinstance(node, ast.Class):
420 for method in sorted(node.constructors):
421 self._write_constructor(method)
422 if isinstance(node, (ast.Class, ast.Interface)):
423 for method in sorted(node.static_methods):
424 self._write_static_method(method)
425 for vfunc in sorted(node.virtual_methods):
426 self._write_vfunc(vfunc)
427 for method in sorted(node.methods):
428 self._write_method(method)
429 for prop in sorted(node.properties):
430 self._write_property(prop)
431 for field in node.fields:
432 self._write_field(field)
433 for signal in sorted(node.signals):
434 self._write_signal(signal)
436 def _write_boxed(self, boxed):
437 attrs = [('glib:name', boxed.name)]
438 if boxed.c_symbol_prefix is not None:
439 attrs.append(('c:symbol-prefix', boxed.c_symbol_prefix))
440 self._append_registered(boxed, attrs)
441 with self.tagcontext('glib:boxed', attrs):
442 self._write_generic(boxed)
443 for method in sorted(boxed.constructors):
444 self._write_constructor(method)
445 for method in sorted(boxed.methods):
446 self._write_method(method)
447 for method in sorted(boxed.static_methods):
448 self._write_static_method(method)
450 def _write_property(self, prop):
451 attrs = [('name', prop.name)]
452 self._append_version(prop, attrs)
453 self._append_node_generic(prop, attrs)
454 # Properties are assumed to be readable (see also generate.c)
455 if not prop.readable:
456 attrs.append(('readable', '0'))
458 attrs.append(('writable', '1'))
460 attrs.append(('construct', '1'))
461 if prop.construct_only:
462 attrs.append(('construct-only', '1'))
464 attrs.append(('transfer-ownership', prop.transfer))
465 with self.tagcontext('property', attrs):
466 self._write_generic(prop)
467 self._write_type(prop.type)
469 def _write_vfunc(self, vf):
472 attrs.append(('invoker', vf.invoker))
473 self._write_callable(vf, 'virtual-method', attrs)
475 def _write_callback(self, callback):
477 if callback.ctype != callback.name:
478 attrs.append(('c:type', callback.ctype))
479 self._write_callable(callback, 'callback', attrs)
481 def _write_record(self, record, extra_attrs=[]):
482 is_gtype_struct = False
483 attrs = list(extra_attrs)
484 if record.name is not None:
485 attrs.append(('name', record.name))
486 if record.ctype is not None: # the record might be anonymous
487 attrs.append(('c:type', record.ctype))
489 attrs.append(('disguised', '1'))
491 attrs.append(('foreign', '1'))
492 if record.is_gtype_struct_for is not None:
493 is_gtype_struct = True
494 attrs.append(('glib:is-gtype-struct-for',
495 self._type_to_name(record.is_gtype_struct_for)))
496 self._append_version(record, attrs)
497 self._append_node_generic(record, attrs)
498 self._append_registered(record, attrs)
499 if record.c_symbol_prefix:
500 attrs.append(('c:symbol-prefix', record.c_symbol_prefix))
501 with self.tagcontext('record', attrs):
502 self._write_generic(record)
504 for field in record.fields:
505 self._write_field(field, is_gtype_struct)
506 for method in sorted(record.constructors):
507 self._write_constructor(method)
508 for method in sorted(record.methods):
509 self._write_method(method)
510 for method in sorted(record.static_methods):
511 self._write_static_method(method)
513 def _write_union(self, union):
515 if union.name is not None:
516 attrs.append(('name', union.name))
517 if union.ctype is not None: # the union might be anonymous
518 attrs.append(('c:type', union.ctype))
519 self._append_version(union, attrs)
520 self._append_node_generic(union, attrs)
521 self._append_registered(union, attrs)
522 if union.c_symbol_prefix:
523 attrs.append(('c:symbol-prefix', union.c_symbol_prefix))
524 with self.tagcontext('union', attrs):
525 self._write_generic(union)
527 for field in union.fields:
528 self._write_field(field)
529 for method in sorted(union.constructors):
530 self._write_constructor(method)
531 for method in sorted(union.methods):
532 self._write_method(method)
533 for method in sorted(union.static_methods):
534 self._write_static_method(method)
536 def _write_field(self, field, is_gtype_struct=False):
537 if field.anonymous_node:
538 if isinstance(field.anonymous_node, ast.Callback):
539 attrs = [('name', field.name)]
540 self._append_node_generic(field, attrs)
541 with self.tagcontext('field', attrs):
542 self._write_callback(field.anonymous_node)
543 elif isinstance(field.anonymous_node, ast.Record):
544 self._write_record(field.anonymous_node)
545 elif isinstance(field.anonymous_node, ast.Union):
546 self._write_union(field.anonymous_node)
548 raise AssertionError("Unknown field anonymous: %r" \
549 % (field.anonymous_node, ))
551 attrs = [('name', field.name)]
552 self._append_node_generic(field, attrs)
553 # Fields are assumed to be read-only
554 # (see also girparser.c and generate.c)
555 if not field.readable:
556 attrs.append(('readable', '0'))
558 attrs.append(('writable', '1'))
560 attrs.append(('bits', str(field.bits)))
562 attrs.append(('private', '1'))
563 with self.tagcontext('field', attrs):
564 self._write_generic(field)
565 self._write_type(field.type)
567 def _write_signal(self, signal):
568 attrs = [('name', signal.name)]
570 attrs.append(('when', signal.when))
571 if signal.no_recurse:
572 attrs.append(('no-recurse', '1'))
574 attrs.append(('detailed', '1'))
576 attrs.append(('action', '1'))
578 attrs.append(('no-hooks', '1'))
580 self._append_version(signal, attrs)
581 self._append_node_generic(signal, attrs)
582 with self.tagcontext('glib:signal', attrs):
583 self._write_generic(signal)
584 self._write_return_type(signal.retval)
585 self._write_parameters(signal, signal.parameters)