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'
32 class GIRWriter(XMLWriter):
34 def __init__(self, namespace):
35 super(GIRWriter, self).__init__()
37 'This file was automatically generated from C sources - DO NOT EDIT!\n'
38 'To affect the contents of this file, edit the original C definitions,\n'
39 'and/or use gtk-doc annotations. ')
40 self._write_repository(namespace)
42 def _write_repository(self, namespace):
44 ('version', COMPATIBLE_GIR_VERSION),
45 ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
46 ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
47 ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0')]
48 with self.tagcontext('repository', attrs):
49 for include in sorted(namespace.includes):
50 self._write_include(include)
51 for pkg in sorted(set(namespace.exported_packages)):
52 self._write_pkgconfig_pkg(pkg)
53 for c_include in sorted(set(namespace.c_includes)):
54 self._write_c_include(c_include)
55 self._namespace = namespace
56 self._write_namespace(namespace)
57 self._namespace = None
59 def _write_include(self, include):
60 attrs = [('name', include.name), ('version', include.version)]
61 self.write_tag('include', attrs)
63 def _write_pkgconfig_pkg(self, package):
64 attrs = [('name', package)]
65 self.write_tag('package', attrs)
67 def _write_c_include(self, c_include):
68 attrs = [('name', c_include)]
69 self.write_tag('c:include', attrs)
71 def _write_namespace(self, namespace):
72 attrs = [('name', namespace.name),
73 ('version', namespace.version),
74 ('shared-library', ','.join(namespace.shared_libraries)),
75 ('c:identifier-prefixes', ','.join(namespace.identifier_prefixes)),
76 ('c:symbol-prefixes', ','.join(namespace.symbol_prefixes))]
77 with self.tagcontext('namespace', attrs):
78 # We define a custom sorting function here because
79 # we want aliases to be first. They're a bit
80 # special because the typelib compiler expands them.
82 if isinstance(a, ast.Alias):
83 if isinstance(b, ast.Alias):
84 return cmp(a.name, b.name)
87 elif isinstance(b, ast.Alias):
91 for node in sorted(namespace.itervalues(), cmp=nscmp):
92 self._write_node(node)
94 def _write_node(self, node):
95 if isinstance(node, ast.Function):
96 self._write_function(node)
97 elif isinstance(node, ast.Enum):
98 self._write_enum(node)
99 elif isinstance(node, ast.Bitfield):
100 self._write_bitfield(node)
101 elif isinstance(node, (ast.Class, ast.Interface)):
102 self._write_class(node)
103 elif isinstance(node, ast.Callback):
104 self._write_callback(node)
105 elif isinstance(node, ast.Record):
106 self._write_record(node)
107 elif isinstance(node, ast.Union):
108 self._write_union(node)
109 elif isinstance(node, ast.Boxed):
110 self._write_boxed(node)
111 elif isinstance(node, ast.Member):
112 # FIXME: atk_misc_instance singleton
114 elif isinstance(node, ast.Alias):
115 self._write_alias(node)
116 elif isinstance(node, ast.Constant):
117 self._write_constant(node)
119 print 'WRITER: Unhandled node', node
121 def _append_version(self, node, attrs):
123 attrs.append(('version', node.version))
125 def _write_generic(self, node):
126 for key, value in node.attributes.items():
127 self.write_tag('attribute', [('name', key), ('value', value)])
129 if hasattr(node, 'doc') and node.doc:
130 self.write_tag('doc', [('xml:space', 'preserve')],
133 if hasattr(node, 'version_doc') and node.version_doc:
134 self.write_tag('doc-version', [('xml:space', 'preserve')],
137 if hasattr(node, 'deprecated_doc') and node.deprecated_doc:
138 self.write_tag('doc-deprecated', [('xml:space', 'preserve')],
141 if hasattr(node, 'stability_doc') and node.stability_doc:
142 self.write_tag('doc-stability', [('xml:space', 'preserve')],
145 def _append_node_generic(self, node, attrs):
146 if node.skip or not node.introspectable:
147 attrs.append(('introspectable', '0'))
149 if node.deprecated or node.deprecated_doc:
150 # The deprecated attribute used to contain node.deprecated_doc as an attribute. As
151 # an xml attribute cannot preserve whitespace, deprecated_doc has been moved into
152 # it's own tag, written in _write_generic() above. We continue to write the deprecated
153 # attribute for backwards compatibility
154 attrs.append(('deprecated', '1'))
157 attrs.append(('deprecated-version', node.deprecated))
160 attrs.append(('stability', node.stability))
162 def _append_throws(self, func, attrs):
164 attrs.append(('throws', '1'))
166 def _write_alias(self, alias):
167 attrs = [('name', alias.name)]
168 if alias.ctype is not None:
169 attrs.append(('c:type', alias.ctype))
170 self._append_node_generic(alias, attrs)
171 with self.tagcontext('alias', attrs):
172 self._write_generic(alias)
173 self._write_type_ref(alias.target)
175 def _write_callable(self, callable, tag_name, extra_attrs):
176 attrs = [('name', callable.name)]
177 attrs.extend(extra_attrs)
178 self._append_version(callable, attrs)
179 self._append_node_generic(callable, attrs)
180 self._append_throws(callable, attrs)
181 with self.tagcontext(tag_name, attrs):
182 self._write_generic(callable)
183 self._write_return_type(callable.retval, parent=callable)
184 self._write_parameters(callable)
186 def _write_function(self, func, tag_name='function'):
187 if func.internal_skipped:
190 if hasattr(func, 'symbol'):
191 attrs.append(('c:identifier', func.symbol))
193 attrs.append(('shadowed-by', func.shadowed_by))
195 attrs.append(('shadows', func.shadows))
196 if func.moved_to is not None:
197 attrs.append(('moved-to', func.moved_to))
198 self._write_callable(func, tag_name, attrs)
200 def _write_method(self, method):
201 self._write_function(method, tag_name='method')
203 def _write_static_method(self, method):
204 self._write_function(method, tag_name='function')
206 def _write_constructor(self, method):
207 self._write_function(method, tag_name='constructor')
209 def _write_return_type(self, return_, parent=None):
215 attrs.append(('transfer-ownership', return_.transfer))
217 attrs.append(('skip', '1'))
218 with self.tagcontext('return-value', attrs):
219 self._write_generic(return_)
220 self._write_type(return_.type, parent=parent)
222 def _write_parameters(self, callable):
223 if not callable.parameters and callable.instance_parameter is None:
225 with self.tagcontext('parameters'):
226 if callable.instance_parameter:
227 self._write_parameter(callable, callable.instance_parameter, 'instance-parameter')
228 for parameter in callable.parameters:
229 self._write_parameter(callable, parameter)
231 def _write_parameter(self, parent, parameter, nodename='parameter'):
233 if parameter.argname is not None:
234 attrs.append(('name', parameter.argname))
235 if (parameter.direction is not None) and (parameter.direction != 'in'):
236 attrs.append(('direction', parameter.direction))
237 attrs.append(('caller-allocates',
238 '1' if parameter.caller_allocates else '0'))
239 if parameter.transfer:
240 attrs.append(('transfer-ownership',
242 if parameter.allow_none:
243 attrs.append(('allow-none', '1'))
245 attrs.append(('scope', parameter.scope))
246 if parameter.closure_name is not None:
247 idx = parent.get_parameter_index(parameter.closure_name)
248 attrs.append(('closure', '%d' % (idx, )))
249 if parameter.destroy_name is not None:
250 idx = parent.get_parameter_index(parameter.destroy_name)
251 attrs.append(('destroy', '%d' % (idx, )))
253 attrs.append(('skip', '1'))
254 with self.tagcontext(nodename, attrs):
255 self._write_generic(parameter)
256 self._write_type(parameter.type, parent=parent)
258 def _type_to_name(self, typeval):
259 if not typeval.resolved:
260 raise AssertionError("Caught unresolved type %r (ctype=%r)" % (typeval, typeval.ctype))
261 assert typeval.target_giname is not None
262 prefix = self._namespace.name + '.'
263 if typeval.target_giname.startswith(prefix):
264 return typeval.target_giname[len(prefix):]
265 return typeval.target_giname
267 def _write_type_ref(self, ntype):
268 """ Like _write_type, but only writes the type name rather than the full details """
269 assert isinstance(ntype, ast.Type), ntype
272 attrs.append(('c:type', ntype.ctype))
273 if isinstance(ntype, ast.Array):
274 if ntype.array_type != ast.Array.C:
275 attrs.insert(0, ('name', ntype.array_type))
276 elif isinstance(ntype, ast.List):
278 attrs.insert(0, ('name', ntype.name))
279 elif isinstance(ntype, ast.Map):
280 attrs.insert(0, ('name', 'GLib.HashTable'))
282 if ntype.target_giname:
283 attrs.insert(0, ('name', self._type_to_name(ntype)))
284 elif ntype.target_fundamental:
285 attrs.insert(0, ('name', ntype.target_fundamental))
287 self.write_tag('type', attrs)
289 def _write_type(self, ntype, relation=None, parent=None):
290 assert isinstance(ntype, ast.Type), ntype
292 if ntype.complete_ctype:
293 attrs.append(('c:type', ntype.complete_ctype))
295 attrs.append(('c:type', ntype.ctype))
296 if isinstance(ntype, ast.Varargs):
297 self.write_tag('varargs', [])
298 elif isinstance(ntype, ast.Array):
299 if ntype.array_type != ast.Array.C:
300 attrs.insert(0, ('name', ntype.array_type))
301 # we insert an explicit 'zero-terminated' attribute
302 # when it is false, or when it would not be implied
303 # by the absence of length and fixed-size
304 if not ntype.zeroterminated:
305 attrs.insert(0, ('zero-terminated', '0'))
306 elif (ntype.zeroterminated
307 and (ntype.size is not None or ntype.length_param_name is not None)):
308 attrs.insert(0, ('zero-terminated', '1'))
309 if ntype.size is not None:
310 attrs.append(('fixed-size', '%d' % (ntype.size, )))
311 if ntype.length_param_name is not None:
312 if isinstance(parent, ast.Callable):
313 length = parent.get_parameter_index(ntype.length_param_name)
314 elif isinstance(parent, ast.Compound):
315 length = parent.get_field_index(ntype.length_param_name)
317 assert False, "parent not a callable or compound: %r" % parent
318 attrs.insert(0, ('length', '%d' % (length, )))
320 with self.tagcontext('array', attrs):
321 self._write_type(ntype.element_type)
322 elif isinstance(ntype, ast.List):
324 attrs.insert(0, ('name', ntype.name))
325 with self.tagcontext('type', attrs):
326 self._write_type(ntype.element_type)
327 elif isinstance(ntype, ast.Map):
328 attrs.insert(0, ('name', 'GLib.HashTable'))
329 with self.tagcontext('type', attrs):
330 self._write_type(ntype.key_type)
331 self._write_type(ntype.value_type)
333 # REWRITEFIXME - enable this for 1.2
334 if ntype.target_giname:
335 attrs.insert(0, ('name', self._type_to_name(ntype)))
336 elif ntype.target_fundamental:
337 # attrs = [('fundamental', ntype.target_fundamental)]
338 attrs.insert(0, ('name', ntype.target_fundamental))
339 elif ntype.target_foreign:
340 attrs.insert(0, ('foreign', '1'))
341 self.write_tag('type', attrs)
343 def _append_registered(self, node, attrs):
344 assert isinstance(node, ast.Registered)
346 attrs.extend([('glib:type-name', node.gtype_name),
347 ('glib:get-type', node.get_type)])
349 def _write_enum(self, enum):
350 attrs = [('name', enum.name)]
351 self._append_version(enum, attrs)
352 self._append_node_generic(enum, attrs)
353 self._append_registered(enum, attrs)
354 attrs.append(('c:type', enum.ctype))
355 if enum.error_domain:
356 attrs.append(('glib:error-domain', enum.error_domain))
358 with self.tagcontext('enumeration', attrs):
359 self._write_generic(enum)
360 for member in enum.members:
361 self._write_member(member)
362 for method in sorted(enum.static_methods):
363 self._write_static_method(method)
365 def _write_bitfield(self, bitfield):
366 attrs = [('name', bitfield.name)]
367 self._append_version(bitfield, attrs)
368 self._append_node_generic(bitfield, attrs)
369 self._append_registered(bitfield, attrs)
370 attrs.append(('c:type', bitfield.ctype))
371 with self.tagcontext('bitfield', attrs):
372 self._write_generic(bitfield)
373 for member in bitfield.members:
374 self._write_member(member)
375 for method in sorted(bitfield.static_methods):
376 self._write_static_method(method)
378 def _write_member(self, member):
379 attrs = [('name', member.name),
380 ('value', str(member.value)),
381 ('c:identifier', member.symbol)]
382 if member.nick is not None:
383 attrs.append(('glib:nick', member.nick))
384 with self.tagcontext('member', attrs):
385 self._write_generic(member)
387 def _write_constant(self, constant):
388 attrs = [('name', constant.name),
389 ('value', constant.value),
390 ('c:type', constant.ctype)]
391 self._append_version(constant, attrs)
392 self._append_node_generic(constant, attrs)
393 with self.tagcontext('constant', attrs):
394 self._write_generic(constant)
395 self._write_type(constant.value_type)
397 def _write_class(self, node):
398 attrs = [('name', node.name),
399 ('c:symbol-prefix', node.c_symbol_prefix),
400 ('c:type', node.ctype)]
401 self._append_version(node, attrs)
402 self._append_node_generic(node, attrs)
403 if isinstance(node, ast.Class):
405 if node.parent_type is not None:
406 attrs.append(('parent',
407 self._type_to_name(node.parent_type)))
409 attrs.append(('abstract', '1'))
411 assert isinstance(node, ast.Interface)
412 tag_name = 'interface'
413 attrs.append(('glib:type-name', node.gtype_name))
414 if node.get_type is not None:
415 attrs.append(('glib:get-type', node.get_type))
416 if node.glib_type_struct is not None:
417 attrs.append(('glib:type-struct',
418 self._type_to_name(node.glib_type_struct)))
419 if isinstance(node, ast.Class):
421 attrs.append(('glib:fundamental', '1'))
423 attrs.append(('glib:ref-func', node.ref_func))
425 attrs.append(('glib:unref-func', node.unref_func))
426 if node.set_value_func:
427 attrs.append(('glib:set-value-func', node.set_value_func))
428 if node.get_value_func:
429 attrs.append(('glib:get-value-func', node.get_value_func))
430 with self.tagcontext(tag_name, attrs):
431 self._write_generic(node)
432 if isinstance(node, ast.Class):
433 for iface in sorted(node.interfaces):
434 self.write_tag('implements',
435 [('name', self._type_to_name(iface))])
436 if isinstance(node, ast.Interface):
437 for iface in sorted(node.prerequisites):
438 self.write_tag('prerequisite',
439 [('name', self._type_to_name(iface))])
440 if isinstance(node, ast.Class):
441 for method in sorted(node.constructors):
442 self._write_constructor(method)
443 for method in sorted(node.static_methods):
444 self._write_static_method(method)
445 for vfunc in sorted(node.virtual_methods):
446 self._write_vfunc(vfunc)
447 for method in sorted(node.methods):
448 self._write_method(method)
449 for prop in sorted(node.properties):
450 self._write_property(prop)
451 for field in node.fields:
452 self._write_field(field, node)
453 for signal in sorted(node.signals):
454 self._write_signal(signal)
456 def _write_boxed(self, boxed):
457 attrs = [('glib:name', boxed.name)]
458 if boxed.c_symbol_prefix is not None:
459 attrs.append(('c:symbol-prefix', boxed.c_symbol_prefix))
460 self._append_registered(boxed, attrs)
461 with self.tagcontext('glib:boxed', attrs):
462 self._write_generic(boxed)
463 for method in sorted(boxed.constructors):
464 self._write_constructor(method)
465 for method in sorted(boxed.methods):
466 self._write_method(method)
467 for method in sorted(boxed.static_methods):
468 self._write_static_method(method)
470 def _write_property(self, prop):
471 attrs = [('name', prop.name)]
472 self._append_version(prop, attrs)
473 self._append_node_generic(prop, attrs)
474 # Properties are assumed to be readable (see also generate.c)
475 if not prop.readable:
476 attrs.append(('readable', '0'))
478 attrs.append(('writable', '1'))
480 attrs.append(('construct', '1'))
481 if prop.construct_only:
482 attrs.append(('construct-only', '1'))
484 attrs.append(('transfer-ownership', prop.transfer))
485 with self.tagcontext('property', attrs):
486 self._write_generic(prop)
487 self._write_type(prop.type)
489 def _write_vfunc(self, vf):
492 attrs.append(('invoker', vf.invoker))
493 self._write_callable(vf, 'virtual-method', attrs)
495 def _write_callback(self, callback):
497 if callback.ctype != callback.name:
498 attrs.append(('c:type', callback.ctype))
499 self._write_callable(callback, 'callback', attrs)
501 def _write_record(self, record, extra_attrs=[]):
502 is_gtype_struct = False
503 attrs = list(extra_attrs)
504 if record.name is not None:
505 attrs.append(('name', record.name))
506 if record.ctype is not None: # the record might be anonymous
507 attrs.append(('c:type', record.ctype))
509 attrs.append(('disguised', '1'))
511 attrs.append(('foreign', '1'))
512 if record.is_gtype_struct_for is not None:
513 is_gtype_struct = True
514 attrs.append(('glib:is-gtype-struct-for',
515 self._type_to_name(record.is_gtype_struct_for)))
516 self._append_version(record, attrs)
517 self._append_node_generic(record, attrs)
518 self._append_registered(record, attrs)
519 if record.c_symbol_prefix:
520 attrs.append(('c:symbol-prefix', record.c_symbol_prefix))
521 with self.tagcontext('record', attrs):
522 self._write_generic(record)
524 for field in record.fields:
525 self._write_field(field, record, is_gtype_struct)
526 for method in sorted(record.constructors):
527 self._write_constructor(method)
528 for method in sorted(record.methods):
529 self._write_method(method)
530 for method in sorted(record.static_methods):
531 self._write_static_method(method)
533 def _write_union(self, union):
535 if union.name is not None:
536 attrs.append(('name', union.name))
537 if union.ctype is not None: # the union might be anonymous
538 attrs.append(('c:type', union.ctype))
539 self._append_version(union, attrs)
540 self._append_node_generic(union, attrs)
541 self._append_registered(union, attrs)
542 if union.c_symbol_prefix:
543 attrs.append(('c:symbol-prefix', union.c_symbol_prefix))
544 with self.tagcontext('union', attrs):
545 self._write_generic(union)
547 for field in union.fields:
548 self._write_field(field, union)
549 for method in sorted(union.constructors):
550 self._write_constructor(method)
551 for method in sorted(union.methods):
552 self._write_method(method)
553 for method in sorted(union.static_methods):
554 self._write_static_method(method)
556 def _write_field(self, field, parent, is_gtype_struct=False):
557 if field.anonymous_node:
558 if isinstance(field.anonymous_node, ast.Callback):
559 attrs = [('name', field.name)]
560 self._append_node_generic(field, attrs)
561 with self.tagcontext('field', attrs):
562 self._write_callback(field.anonymous_node)
563 elif isinstance(field.anonymous_node, ast.Record):
564 self._write_record(field.anonymous_node)
565 elif isinstance(field.anonymous_node, ast.Union):
566 self._write_union(field.anonymous_node)
568 raise AssertionError("Unknown field anonymous: %r" % (field.anonymous_node, ))
570 attrs = [('name', field.name)]
571 self._append_node_generic(field, attrs)
572 # Fields are assumed to be read-only
573 # (see also girparser.c and generate.c)
574 if not field.readable:
575 attrs.append(('readable', '0'))
577 attrs.append(('writable', '1'))
579 attrs.append(('bits', str(field.bits)))
581 attrs.append(('private', '1'))
582 with self.tagcontext('field', attrs):
583 self._write_generic(field)
584 self._write_type(field.type, parent=parent)
586 def _write_signal(self, signal):
587 attrs = [('name', signal.name)]
589 attrs.append(('when', signal.when))
590 if signal.no_recurse:
591 attrs.append(('no-recurse', '1'))
593 attrs.append(('detailed', '1'))
595 attrs.append(('action', '1'))
597 attrs.append(('no-hooks', '1'))
599 self._append_version(signal, attrs)
600 self._append_node_generic(signal, attrs)
601 with self.tagcontext('glib:signal', attrs):
602 self._write_generic(signal)
603 self._write_return_type(signal.retval)
604 self._write_parameters(signal)