2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program 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
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 from __future__ import with_statement
25 from .ast import (Callback, Class, Constant, Enum, Function, Interface, Member,
26 Array, Struct, Alias, Union, List, Map, Varargs)
27 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
28 GLibFlags, GLibObject, GLibInterface)
29 from .xmlwriter import XMLWriter
32 class GIRWriter(XMLWriter):
34 def __init__(self, namespace, shlibs, includes):
35 super(GIRWriter, self).__init__()
36 self._write_repository(namespace, shlibs, includes)
38 def _write_repository(self, namespace, shlibs, includes=set()):
41 ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
42 ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
43 ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0'),
45 with self.tagcontext('repository', attrs):
46 for include in sorted(includes):
47 self._write_include(include)
48 self._write_namespace(namespace, shlibs)
50 def _write_include(self, include):
51 attrs = [('name', include.name), ('version', include.version)]
52 self.write_tag('include', attrs)
54 def _write_namespace(self, namespace, shlibs):
57 libraries.append(os.path.basename(l))
59 attrs = [('name', namespace.name),
60 ('version', namespace.version),
61 ('shared-library', ','.join(libraries))]
62 with self.tagcontext('namespace', attrs):
63 for node in namespace.nodes:
64 self._write_node(node)
66 def _write_node(self, node):
67 if isinstance(node, Function):
68 self._write_function(node)
69 elif isinstance(node, Enum):
70 self._write_enum(node)
71 elif isinstance(node, (Class, Interface)):
72 self._write_class(node)
73 elif isinstance(node, Callback):
74 self._write_callback(node)
75 elif isinstance(node, Struct):
76 self._write_record(node)
77 elif isinstance(node, Union):
78 self._write_union(node)
79 elif isinstance(node, GLibBoxed):
80 self._write_boxed(node)
81 elif isinstance(node, Member):
82 # FIXME: atk_misc_instance singleton
84 elif isinstance(node, Alias):
85 self._write_alias(node)
86 elif isinstance(node, Constant):
87 self._write_constant(node)
89 print 'WRITER: Unhandled node', node
91 def _append_deprecated(self, node, attrs):
93 attrs.append(('deprecated', node.deprecated))
94 if node.deprecated_version:
95 attrs.append(('deprecated-version',
96 node.deprecated_version))
98 def _append_throws(self, func, attrs):
100 attrs.append(('throws', '1'))
102 def _write_alias(self, alias):
103 attrs = [('name', alias.name), ('target', alias.target)]
104 if alias.ctype is not None:
105 attrs.append(('c:type', alias.ctype))
106 self.write_tag('alias', attrs)
108 def _write_function(self, func, tag_name='function'):
109 attrs = [('name', func.name),
110 ('c:identifier', func.symbol)]
111 self._append_deprecated(func, attrs)
112 self._append_throws(func, attrs)
113 with self.tagcontext(tag_name, attrs):
114 self._write_return_type(func.retval)
115 self._write_parameters(func.parameters)
117 def _write_method(self, method):
118 self._write_function(method, tag_name='method')
120 def _write_constructor(self, method):
121 self._write_function(method, tag_name='constructor')
123 def _write_return_type(self, return_):
129 attrs.append(('transfer-ownership',
131 with self.tagcontext('return-value', attrs):
132 self._write_type(return_.type)
134 def _write_parameters(self, parameters):
137 with self.tagcontext('parameters'):
138 for parameter in parameters:
139 self._write_parameter(parameter)
141 def _write_parameter(self, parameter):
143 if parameter.name is not None:
144 attrs.append(('name', parameter.name))
145 if parameter.direction != 'in':
146 attrs.append(('direction', parameter.direction))
147 if parameter.transfer:
148 attrs.append(('transfer-ownership',
150 if parameter.allow_none:
151 attrs.append(('allow-none', '1'))
152 with self.tagcontext('parameter', attrs):
153 self._write_type(parameter.type)
155 def _type_to_string(self, ntype):
156 if isinstance(ntype, basestring):
160 def _write_type(self, ntype, relation=None):
161 if isinstance(ntype, basestring):
165 typename = ntype.name
166 type_cname = ntype.ctype
167 if isinstance(ntype, Varargs):
168 with self.tagcontext('varargs', []):
171 if isinstance(ntype, Array):
173 if not ntype.zeroterminated:
174 attrs.append(('zero-terminated', '0'))
175 if ntype.length_param_index >= 0:
176 attrs.append(('length', '%d' % (ntype.length_param_index, )))
177 attrs.append(('c:type', ntype.ctype))
178 with self.tagcontext('array', attrs):
179 self._write_type(ntype.element_type)
181 attrs = [('name', self._type_to_string(ntype))]
182 # FIXME: figure out if type references a basic type
183 # or a boxed/class/interface etc. and skip
184 # writing the ctype if the latter.
185 if type_cname is not None:
186 attrs.append(('c:type', type_cname))
187 if isinstance(ntype, List) and ntype.element_type:
188 with self.tagcontext('type', attrs):
189 self._write_type(ntype.element_type)
191 if isinstance(ntype, Map) and ntype.key_type:
192 with self.tagcontext('type', attrs):
193 self._write_type(ntype.key_type)
194 self._write_type(ntype.value_type)
196 # Not a special type, just write it out
197 self.write_tag('type', attrs)
199 def _write_enum(self, enum):
200 attrs = [('name', enum.name)]
201 self._append_deprecated(enum, attrs)
202 if isinstance(enum, GLibFlags):
203 tag_name = 'bitfield'
205 tag_name = 'enumeration'
206 if isinstance(enum, GLibEnum) or isinstance(enum, GLibFlags):
207 attrs.extend([('glib:type-name', enum.type_name),
208 ('glib:get-type', enum.get_type),
209 ('c:type', enum.ctype)])
211 attrs.append(('c:type', enum.symbol))
212 with self.tagcontext(tag_name, attrs):
213 for member in enum.members:
214 self._write_member(member)
216 def _write_member(self, member):
217 attrs = [('name', member.name),
218 ('value', str(member.value)),
219 ('c:identifier', member.symbol)]
220 if isinstance(member, GLibEnumMember):
221 attrs.append(('glib:nick', member.nick))
222 self.write_tag('member', attrs)
224 def _write_constant(self, constant):
225 attrs = [('name', constant.name),
226 ('value', str(constant.value))]
227 with self.tagcontext('constant', attrs):
228 self._write_type(constant.type)
230 def _write_class(self, node):
231 attrs = [('name', node.name),
232 ('c:type', node.ctype)]
233 self._append_deprecated(node, attrs)
234 if isinstance(node, Class):
236 if node.parent is not None:
237 attrs.append(('parent', node.parent))
239 attrs.append(('abstract', '1'))
241 tag_name = 'interface'
242 if isinstance(node, (GLibObject, GLibInterface)):
243 attrs.append(('glib:type-name', node.type_name))
245 attrs.append(('glib:get-type', node.get_type))
246 with self.tagcontext(tag_name, attrs):
247 if isinstance(node, GLibObject):
248 for iface in node.interfaces:
249 self.write_tag('implements', [('name', iface)])
250 if isinstance(node, Class):
251 for method in node.constructors:
252 self._write_constructor(method)
253 for method in node.methods:
254 self._write_method(method)
255 for prop in node.properties:
256 self._write_property(prop)
257 for field in node.fields:
258 self._write_field(field)
259 for signal in node.signals:
260 self._write_signal(signal)
262 def _write_boxed(self, boxed):
263 attrs = [('c:type', boxed.ctype),
264 ('glib:name', boxed.name)]
265 attrs.extend(self._boxed_attrs(boxed))
266 with self.tagcontext('glib:boxed', attrs):
267 self._write_boxed_ctors_methods(boxed)
269 def _write_property(self, prop):
270 attrs = [('name', prop.name)]
271 # Properties are assumed to be readable (see also generate.c)
272 if not prop.readable:
273 attrs.append(('readable', '0'))
275 attrs.append(('writable', '1'))
277 attrs.append(('construct', '1'))
278 if prop.construct_only:
279 attrs.append(('construct-only', '1'))
280 with self.tagcontext('property', attrs):
281 self._write_type(prop.type)
283 def _write_callback(self, callback):
284 # FIXME: reuse _write_function
285 attrs = [('name', callback.name), ('c:type', callback.ctype)]
286 self._append_deprecated(callback, attrs)
287 with self.tagcontext('callback', attrs):
288 self._write_return_type(callback.retval)
289 self._write_parameters(callback.parameters)
291 def _boxed_attrs(self, boxed):
292 return [('glib:type-name', boxed.type_name),
293 ('glib:get-type', boxed.get_type)]
295 def _write_boxed_ctors_methods(self, boxed):
296 for method in boxed.constructors:
297 self._write_constructor(method)
298 for method in boxed.methods:
299 self._write_method(method)
301 def _write_record(self, record):
302 attrs = [('name', record.name),
303 ('c:type', record.symbol)]
304 self._append_deprecated(record, attrs)
305 if isinstance(record, GLibBoxed):
306 attrs.extend(self._boxed_attrs(record))
307 with self.tagcontext('record', attrs):
309 for field in record.fields:
310 self._write_field(field)
311 if isinstance(record, GLibBoxed):
312 self._write_boxed_ctors_methods(record)
314 def _write_union(self, union):
315 attrs = [('name', union.name),
316 ('c:type', union.symbol)]
317 self._append_deprecated(union, attrs)
318 if isinstance(union, GLibBoxed):
319 attrs.extend(self._boxed_attrs(union))
320 with self.tagcontext('union', attrs):
322 for field in union.fields:
323 self._write_field(field)
324 if isinstance(union, GLibBoxed):
325 self._write_boxed_ctors_methods(union)
327 def _write_field(self, field):
328 if isinstance(field, Function):
329 self._write_method(field)
332 if isinstance(field, Callback):
333 self._write_callback(field)
336 attrs = [('name', field.name)]
337 # Fields are assumed to be read-only
338 # (see also girparser.c and generate.c)
339 if not field.readable:
340 attrs.append(('readable', '0'))
342 attrs.append(('writable', '1'))
344 attrs.append(('bits', str(field.bits)))
345 with self.tagcontext('field', attrs):
346 self._write_type(field.type)
348 def _write_signal(self, signal):
349 attrs = [('name', signal.name)]
350 with self.tagcontext('glib:signal', attrs):
351 self._write_return_type(signal.retval)
352 self._write_parameters(signal.parameters)