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 (Callback, Class, Constant, Enum, Function, Interface, Member,
27 Array, Struct, Alias, Union, List, Map, Varargs)
28 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
29 GLibFlags, GLibObject, GLibInterface)
30 from .xmlwriter import XMLWriter
33 class GIRWriter(XMLWriter):
35 def __init__(self, namespace, shlibs, includes):
36 super(GIRWriter, self).__init__()
37 self._write_repository(namespace, shlibs, includes)
39 def _write_repository(self, namespace, shlibs, includes=set()):
42 ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
43 ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
44 ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0'),
46 with self.tagcontext('repository', attrs):
47 for include in sorted(includes):
48 self._write_include(include)
49 self._write_namespace(namespace, shlibs)
51 def _write_include(self, include):
52 attrs = [('name', include.name), ('version', include.version)]
53 self.write_tag('include', attrs)
55 def _write_namespace(self, namespace, shlibs):
58 found_libname = find_library(l)
61 libraries.append(os.path.basename(found_libname))
63 attrs = [('name', namespace.name),
64 ('version', namespace.version),
65 ('shared-library', ','.join(libraries))]
66 with self.tagcontext('namespace', attrs):
67 for node in namespace.nodes:
68 self._write_node(node)
70 def _write_node(self, node):
71 if isinstance(node, Function):
72 self._write_function(node)
73 elif isinstance(node, Enum):
74 self._write_enum(node)
75 elif isinstance(node, (Class, Interface)):
76 self._write_class(node)
77 elif isinstance(node, Callback):
78 self._write_callback(node)
79 elif isinstance(node, Struct):
80 self._write_record(node)
81 elif isinstance(node, Union):
82 self._write_union(node)
83 elif isinstance(node, GLibBoxed):
84 self._write_boxed(node)
85 elif isinstance(node, Member):
86 # FIXME: atk_misc_instance singleton
88 elif isinstance(node, Alias):
89 self._write_alias(node)
90 elif isinstance(node, Constant):
91 self._write_constant(node)
93 print 'WRITER: Unhandled node', node
95 def _append_deprecated(self, node, attrs):
97 attrs.append(('deprecated', node.deprecated))
98 if node.deprecated_version:
99 attrs.append(('deprecated-version',
100 node.deprecated_version))
102 def _append_throws(self, func, attrs):
104 attrs.append(('throws', '1'))
106 def _write_alias(self, alias):
107 attrs = [('name', alias.name), ('target', alias.target)]
108 if alias.ctype is not None:
109 attrs.append(('c:type', alias.ctype))
110 self.write_tag('alias', attrs)
112 def _write_function(self, func, tag_name='function'):
113 attrs = [('name', func.name),
114 ('c:identifier', func.symbol)]
115 self._append_deprecated(func, attrs)
116 self._append_throws(func, attrs)
117 with self.tagcontext(tag_name, attrs):
118 self._write_return_type(func.retval)
119 self._write_parameters(func.parameters)
121 def _write_method(self, method):
122 self._write_function(method, tag_name='method')
124 def _write_constructor(self, method):
125 self._write_function(method, tag_name='constructor')
127 def _write_return_type(self, return_):
131 assert return_.transfer is not None, return_
134 attrs.append(('transfer-ownership', return_.transfer))
135 with self.tagcontext('return-value', attrs):
136 self._write_type(return_.type)
138 def _write_parameters(self, parameters):
141 with self.tagcontext('parameters'):
142 for parameter in parameters:
143 self._write_parameter(parameter)
145 def _write_parameter(self, parameter):
146 assert parameter.transfer is not None, parameter
149 if parameter.name is not None:
150 attrs.append(('name', parameter.name))
151 if parameter.direction != 'in':
152 attrs.append(('direction', parameter.direction))
153 attrs.append(('transfer-ownership',
155 if parameter.allow_none:
156 attrs.append(('allow-none', '1'))
157 with self.tagcontext('parameter', attrs):
158 self._write_type(parameter.type)
160 def _type_to_string(self, ntype):
161 if isinstance(ntype, basestring):
165 def _write_type(self, ntype, relation=None):
166 if isinstance(ntype, basestring):
170 typename = ntype.name
171 type_cname = ntype.ctype
172 if isinstance(ntype, Varargs):
173 with self.tagcontext('varargs', []):
176 if isinstance(ntype, Array):
178 if not ntype.zeroterminated:
179 attrs.append(('zero-terminated', '0'))
180 if ntype.length_param_index >= 0:
181 attrs.append(('length', '%d' % (ntype.length_param_index, )))
182 attrs.append(('c:type', ntype.ctype))
183 if ntype.size is not None:
184 attrs.append(('fixed-size', ntype.size))
185 with self.tagcontext('array', attrs):
186 self._write_type(ntype.element_type)
188 attrs = [('name', self._type_to_string(ntype))]
189 # FIXME: figure out if type references a basic type
190 # or a boxed/class/interface etc. and skip
191 # writing the ctype if the latter.
192 if type_cname is not None:
193 attrs.append(('c:type', type_cname))
194 if isinstance(ntype, List) and ntype.element_type:
195 with self.tagcontext('type', attrs):
196 self._write_type(ntype.element_type)
198 if isinstance(ntype, Map) and ntype.key_type:
199 with self.tagcontext('type', attrs):
200 self._write_type(ntype.key_type)
201 self._write_type(ntype.value_type)
203 # Not a special type, just write it out
204 self.write_tag('type', attrs)
206 def _write_enum(self, enum):
207 attrs = [('name', enum.name)]
208 self._append_deprecated(enum, attrs)
209 if isinstance(enum, GLibFlags):
210 tag_name = 'bitfield'
212 tag_name = 'enumeration'
213 if isinstance(enum, GLibEnum) or isinstance(enum, GLibFlags):
214 attrs.extend([('glib:type-name', enum.type_name),
215 ('glib:get-type', enum.get_type),
216 ('c:type', enum.ctype)])
218 attrs.append(('c:type', enum.symbol))
219 with self.tagcontext(tag_name, attrs):
220 for member in enum.members:
221 self._write_member(member)
223 def _write_member(self, member):
224 attrs = [('name', member.name),
225 ('value', str(member.value)),
226 ('c:identifier', member.symbol)]
227 if isinstance(member, GLibEnumMember):
228 attrs.append(('glib:nick', member.nick))
229 self.write_tag('member', attrs)
231 def _write_constant(self, constant):
232 attrs = [('name', constant.name),
233 ('value', str(constant.value))]
234 with self.tagcontext('constant', attrs):
235 self._write_type(constant.type)
237 def _write_class(self, node):
238 attrs = [('name', node.name),
239 ('c:type', node.ctype)]
240 self._append_deprecated(node, attrs)
241 if isinstance(node, Class):
243 if node.parent is not None:
244 attrs.append(('parent', node.parent))
246 attrs.append(('abstract', '1'))
248 tag_name = 'interface'
249 if isinstance(node, (GLibObject, GLibInterface)):
250 attrs.append(('glib:type-name', node.type_name))
252 attrs.append(('glib:get-type', node.get_type))
253 with self.tagcontext(tag_name, attrs):
254 if isinstance(node, GLibObject):
255 for iface in node.interfaces:
256 self.write_tag('implements', [('name', iface)])
257 if isinstance(node, Class):
258 for method in node.constructors:
259 self._write_constructor(method)
260 for method in node.methods:
261 self._write_method(method)
262 for prop in node.properties:
263 self._write_property(prop)
264 for field in node.fields:
265 self._write_field(field)
266 for signal in node.signals:
267 self._write_signal(signal)
269 def _write_boxed(self, boxed):
270 attrs = [('c:type', boxed.ctype),
271 ('glib:name', boxed.name)]
272 attrs.extend(self._boxed_attrs(boxed))
273 with self.tagcontext('glib:boxed', attrs):
274 self._write_boxed_ctors_methods(boxed)
276 def _write_property(self, prop):
277 attrs = [('name', prop.name)]
278 # Properties are assumed to be readable (see also generate.c)
279 if not prop.readable:
280 attrs.append(('readable', '0'))
282 attrs.append(('writable', '1'))
284 attrs.append(('construct', '1'))
285 if prop.construct_only:
286 attrs.append(('construct-only', '1'))
287 with self.tagcontext('property', attrs):
288 self._write_type(prop.type)
290 def _write_callback(self, callback):
291 # FIXME: reuse _write_function
292 attrs = [('name', callback.name), ('c:type', callback.ctype)]
293 self._append_deprecated(callback, attrs)
294 with self.tagcontext('callback', attrs):
295 self._write_return_type(callback.retval)
296 self._write_parameters(callback.parameters)
298 def _boxed_attrs(self, boxed):
299 return [('glib:type-name', boxed.type_name),
300 ('glib:get-type', boxed.get_type)]
302 def _write_boxed_ctors_methods(self, boxed):
303 for method in boxed.constructors:
304 self._write_constructor(method)
305 for method in boxed.methods:
306 self._write_method(method)
308 def _write_record(self, record):
309 attrs = [('name', record.name),
310 ('c:type', record.symbol)]
311 self._append_deprecated(record, attrs)
312 if isinstance(record, GLibBoxed):
313 attrs.extend(self._boxed_attrs(record))
314 with self.tagcontext('record', attrs):
316 for field in record.fields:
317 self._write_field(field)
318 if isinstance(record, GLibBoxed):
319 self._write_boxed_ctors_methods(record)
321 def _write_union(self, union):
322 attrs = [('name', union.name),
323 ('c:type', union.symbol)]
324 self._append_deprecated(union, attrs)
325 if isinstance(union, GLibBoxed):
326 attrs.extend(self._boxed_attrs(union))
327 with self.tagcontext('union', attrs):
329 for field in union.fields:
330 self._write_field(field)
331 if isinstance(union, GLibBoxed):
332 self._write_boxed_ctors_methods(union)
334 def _write_field(self, field):
335 if isinstance(field, Function):
336 self._write_method(field)
339 if isinstance(field, Callback):
340 self._write_callback(field)
343 attrs = [('name', field.name)]
344 # Fields are assumed to be read-only
345 # (see also girparser.c and generate.c)
346 if not field.readable:
347 attrs.append(('readable', '0'))
349 attrs.append(('writable', '1'))
351 attrs.append(('bits', str(field.bits)))
352 with self.tagcontext('field', attrs):
353 self._write_type(field.type)
355 def _write_signal(self, signal):
356 attrs = [('name', signal.name)]
357 with self.tagcontext('glib:signal', attrs):
358 self._write_return_type(signal.retval)
359 self._write_parameters(signal.parameters)