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 _write_alias(self, alias):
99 attrs = [('name', alias.name), ('target', alias.target)]
100 if alias.ctype is not None:
101 attrs.append(('c:type', alias.ctype))
102 self.write_tag('alias', attrs)
104 def _write_function(self, func, tag_name='function'):
105 attrs = [('name', func.name),
106 ('c:identifier', func.symbol)]
107 self._append_deprecated(func, attrs)
108 with self.tagcontext(tag_name, attrs):
109 self._write_return_type(func.retval)
110 self._write_parameters(func.parameters)
112 def _write_method(self, method):
113 self._write_function(method, tag_name='method')
115 def _write_constructor(self, method):
116 self._write_function(method, tag_name='constructor')
118 def _write_return_type(self, return_):
124 attrs.append(('transfer-ownership',
126 with self.tagcontext('return-value', attrs):
127 self._write_type(return_.type)
129 def _write_parameters(self, parameters):
132 with self.tagcontext('parameters'):
133 for parameter in parameters:
134 self._write_parameter(parameter)
136 def _write_parameter(self, parameter):
138 if parameter.name is not None:
139 attrs.append(('name', parameter.name))
140 if parameter.direction != 'in':
141 attrs.append(('direction', parameter.direction))
142 if parameter.transfer:
143 attrs.append(('transfer-ownership',
145 if parameter.allow_none:
146 attrs.append(('allow-none', '1'))
147 with self.tagcontext('parameter', attrs):
148 self._write_type(parameter.type)
150 def _type_to_string(self, ntype):
151 if isinstance(ntype, basestring):
155 def _write_type(self, ntype, relation=None):
156 if isinstance(ntype, basestring):
160 typename = ntype.name
161 type_cname = ntype.ctype
162 if isinstance(ntype, Varargs):
163 with self.tagcontext('varargs', []):
166 if isinstance(ntype, Array):
168 if not ntype.zeroterminated:
169 attrs.append(('zero-terminated', '0'))
170 if ntype.length_param_index >= 0:
171 attrs.append(('length', '%d' % (ntype.length_param_index, )))
172 attrs.append(('c:type', ntype.ctype))
173 with self.tagcontext('array', attrs):
174 self._write_type(ntype.element_type)
176 attrs = [('name', self._type_to_string(ntype))]
177 # FIXME: figure out if type references a basic type
178 # or a boxed/class/interface etc. and skip
179 # writing the ctype if the latter.
180 if type_cname is not None:
181 attrs.append(('c:type', type_cname))
182 if isinstance(ntype, List) and ntype.element_type:
183 with self.tagcontext('type', attrs):
184 self._write_type(ntype.element_type)
186 if isinstance(ntype, Map) and ntype.key_type:
187 with self.tagcontext('type', attrs):
188 self._write_type(ntype.key_type)
189 self._write_type(ntype.value_type)
191 # Not a special type, just write it out
192 self.write_tag('type', attrs)
194 def _write_enum(self, enum):
195 attrs = [('name', enum.name)]
196 self._append_deprecated(enum, attrs)
197 if isinstance(enum, GLibFlags):
198 tag_name = 'bitfield'
200 tag_name = 'enumeration'
201 if isinstance(enum, GLibEnum) or isinstance(enum, GLibFlags):
202 attrs.extend([('glib:type-name', enum.type_name),
203 ('glib:get-type', enum.get_type),
204 ('c:type', enum.ctype)])
206 attrs.append(('c:type', enum.symbol))
207 with self.tagcontext(tag_name, attrs):
208 for member in enum.members:
209 self._write_member(member)
211 def _write_member(self, member):
212 attrs = [('name', member.name),
213 ('value', str(member.value)),
214 ('c:identifier', member.symbol)]
215 if isinstance(member, GLibEnumMember):
216 attrs.append(('glib:nick', member.nick))
217 self.write_tag('member', attrs)
219 def _write_constant(self, constant):
220 attrs = [('name', constant.name),
221 ('value', str(constant.value))]
222 with self.tagcontext('constant', attrs):
223 self._write_type(constant.type)
225 def _write_class(self, node):
226 attrs = [('name', node.name),
227 ('c:type', node.ctype)]
228 self._append_deprecated(node, attrs)
229 if isinstance(node, Class):
231 if node.parent is not None:
232 attrs.append(('parent', node.parent))
234 attrs.append(('abstract', '1'))
236 tag_name = 'interface'
237 if isinstance(node, (GLibObject, GLibInterface)):
238 attrs.append(('glib:type-name', node.type_name))
240 attrs.append(('glib:get-type', node.get_type))
241 with self.tagcontext(tag_name, attrs):
242 if isinstance(node, GLibObject):
243 for iface in node.interfaces:
244 self.write_tag('implements', [('name', iface)])
245 if isinstance(node, Class):
246 for method in node.constructors:
247 self._write_constructor(method)
248 for method in node.methods:
249 self._write_method(method)
250 for prop in node.properties:
251 self._write_property(prop)
252 for field in node.fields:
253 self._write_field(field)
254 for signal in node.signals:
255 self._write_signal(signal)
257 def _write_boxed(self, boxed):
258 attrs = [('c:type', boxed.ctype),
259 ('glib:name', boxed.name)]
260 attrs.extend(self._boxed_attrs(boxed))
261 with self.tagcontext('glib:boxed', attrs):
262 self._write_boxed_ctors_methods(boxed)
264 def _write_property(self, prop):
265 attrs = [('name', prop.name)]
266 # Properties are assumed to be readable (see also generate.c)
267 if not prop.readable:
268 attrs.append(('readable', '0'))
270 attrs.append(('writable', '1'))
272 attrs.append(('construct', '1'))
273 if prop.construct_only:
274 attrs.append(('construct-only', '1'))
275 with self.tagcontext('property', attrs):
276 self._write_type(prop.type)
278 def _write_callback(self, callback):
279 # FIXME: reuse _write_function
280 attrs = [('name', callback.name), ('c:type', callback.ctype)]
281 self._append_deprecated(callback, attrs)
282 with self.tagcontext('callback', attrs):
283 self._write_return_type(callback.retval)
284 self._write_parameters(callback.parameters)
286 def _boxed_attrs(self, boxed):
287 return [('glib:type-name', boxed.type_name),
288 ('glib:get-type', boxed.get_type)]
290 def _write_boxed_ctors_methods(self, boxed):
291 for method in boxed.constructors:
292 self._write_constructor(method)
293 for method in boxed.methods:
294 self._write_method(method)
296 def _write_record(self, record):
297 attrs = [('name', record.name),
298 ('c:type', record.symbol)]
299 self._append_deprecated(record, attrs)
300 if isinstance(record, GLibBoxed):
301 attrs.extend(self._boxed_attrs(record))
302 with self.tagcontext('record', attrs):
304 for field in record.fields:
305 self._write_field(field)
306 if isinstance(record, GLibBoxed):
307 self._write_boxed_ctors_methods(record)
309 def _write_union(self, union):
310 attrs = [('name', union.name),
311 ('c:type', union.symbol)]
312 self._append_deprecated(union, attrs)
313 if isinstance(union, GLibBoxed):
314 attrs.extend(self._boxed_attrs(union))
315 with self.tagcontext('union', attrs):
317 for field in union.fields:
318 self._write_field(field)
319 if isinstance(union, GLibBoxed):
320 self._write_boxed_ctors_methods(union)
322 def _write_field(self, field):
323 if isinstance(field, Function):
324 self._write_method(field)
327 if isinstance(field, Callback):
328 self._write_callback(field)
331 attrs = [('name', field.name)]
332 # Fields are assumed to be read-only
333 # (see also girparser.c and generate.c)
334 if not field.readable:
335 attrs.append(('readable', '0'))
337 attrs.append(('writable', '1'))
339 attrs.append(('bits', str(field.bits)))
340 with self.tagcontext('field', attrs):
341 self._write_type(field.type)
343 def _write_signal(self, signal):
344 attrs = [('name', signal.name)]
345 with self.tagcontext('glib:signal', attrs):
346 self._write_return_type(signal.retval)
347 self._write_parameters(signal.parameters)