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 includes:
47 self._write_include(include)
48 self._write_namespace(namespace, shlibs)
50 def _write_include(self, include):
51 attrs = [('name', include)]
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 ('shared-library', ','.join(libraries))]
61 with self.tagcontext('namespace', attrs):
62 for node in namespace.nodes:
63 self._write_node(node)
65 def _write_node(self, node):
66 if isinstance(node, Function):
67 self._write_function(node)
68 elif isinstance(node, Enum):
69 self._write_enum(node)
70 elif isinstance(node, (Class, Interface)):
71 self._write_class(node)
72 elif isinstance(node, Callback):
73 self._write_callback(node)
74 elif isinstance(node, Struct):
75 self._write_record(node)
76 elif isinstance(node, Union):
77 self._write_union(node)
78 elif isinstance(node, GLibBoxed):
79 self._write_boxed(node)
80 elif isinstance(node, Member):
81 # FIXME: atk_misc_instance singleton
83 elif isinstance(node, Alias):
84 self._write_alias(node)
85 elif isinstance(node, Constant):
86 self._write_constant(node)
88 print 'WRITER: Unhandled node', node
90 def _append_deprecated(self, node, attrs):
92 attrs.append(('deprecated', node.deprecated))
93 if node.deprecated_version:
94 attrs.append(('deprecated-version',
95 node.deprecated_version))
97 def _write_alias(self, alias):
98 attrs = [('name', alias.name), ('target', alias.target)]
99 if alias.ctype is not None:
100 attrs.append(('c:type', alias.ctype))
101 self.write_tag('alias', attrs)
103 def _write_function(self, func, tag_name='function'):
104 attrs = [('name', func.name),
105 ('c:identifier', func.symbol)]
106 self._append_deprecated(func, attrs)
107 with self.tagcontext(tag_name, attrs):
108 self._write_return_type(func.retval)
109 self._write_parameters(func.parameters)
111 def _write_method(self, method):
112 self._write_function(method, tag_name='method')
114 def _write_constructor(self, method):
115 self._write_function(method, tag_name='constructor')
117 def _write_return_type(self, return_):
123 attrs.append(('transfer-ownership',
124 str(int(return_.transfer))))
125 with self.tagcontext('return-value', attrs):
126 self._write_type(return_.type)
128 def _write_parameters(self, parameters):
131 with self.tagcontext('parameters'):
132 for parameter in parameters:
133 self._write_parameter(parameter)
135 def _write_parameter(self, parameter):
137 if parameter.name is not None:
138 attrs.append(('name', parameter.name))
139 if parameter.direction != 'in':
140 attrs.append(('direction', parameter.direction))
141 if parameter.transfer:
142 attrs.append(('transfer-ownership',
143 str(int(parameter.transfer))))
144 if parameter.allow_none:
145 attrs.append(('allow-none', '1'))
146 with self.tagcontext('parameter', attrs):
147 self._write_type(parameter.type)
149 def _type_to_string(self, ntype):
150 if isinstance(ntype, basestring):
154 def _write_type(self, ntype, relation=None):
155 if isinstance(ntype, basestring):
159 typename = ntype.name
160 type_cname = ntype.ctype
161 if isinstance(ntype, Varargs):
162 with self.tagcontext('varargs', []):
165 if isinstance(ntype, Array):
167 if not ntype.zeroterminated:
168 attrs.append(('zero-terminated', '0'))
169 if ntype.length_param_index >= 0:
170 attrs.append(('length', '%d' % (ntype.length_param_index, )))
171 attrs.append(('c:type', ntype.ctype))
172 with self.tagcontext('array', attrs):
173 self._write_type(ntype.element_type)
175 attrs = [('name', self._type_to_string(ntype))]
176 # FIXME: figure out if type references a basic type
177 # or a boxed/class/interface etc. and skip
178 # writing the ctype if the latter.
179 if type_cname is not None:
180 attrs.append(('c:type', type_cname))
181 if isinstance(ntype, List) and ntype.element_type:
182 with self.tagcontext('type', attrs):
183 self._write_type(ntype.element_type)
185 if isinstance(ntype, Map) and ntype.key_type:
186 with self.tagcontext('type', attrs):
187 self._write_type(ntype.key_type)
188 self._write_type(ntype.value_type)
190 # Not a special type, just write it out
191 self.write_tag('type', attrs)
193 def _write_enum(self, enum):
194 attrs = [('name', enum.name)]
195 self._append_deprecated(enum, attrs)
196 if isinstance(enum, GLibFlags):
197 tag_name = 'bitfield'
199 tag_name = 'enumeration'
200 if isinstance(enum, GLibEnum) or isinstance(enum, GLibFlags):
201 attrs.extend([('glib:type-name', enum.type_name),
202 ('glib:get-type', enum.get_type),
203 ('c:type', enum.ctype)])
205 attrs.append(('c:type', enum.symbol))
206 with self.tagcontext(tag_name, attrs):
207 for member in enum.members:
208 self._write_member(member)
210 def _write_member(self, member):
211 attrs = [('name', member.name),
212 ('value', str(member.value)),
213 ('c:identifier', member.symbol)]
214 if isinstance(member, GLibEnumMember):
215 attrs.append(('glib:nick', member.nick))
216 self.write_tag('member', attrs)
218 def _write_constant(self, constant):
219 attrs = [('name', constant.name),
220 ('value', str(constant.value))]
221 with self.tagcontext('constant', attrs):
222 self._write_type(constant.type)
224 def _write_class(self, node):
225 attrs = [('name', node.name),
226 ('c:type', node.ctype)]
227 self._append_deprecated(node, attrs)
228 if isinstance(node, Class):
230 if node.parent is not None:
231 attrs.append(('parent', node.parent))
233 tag_name = 'interface'
234 if isinstance(node, (GLibObject, GLibInterface)):
235 attrs.append(('glib:type-name', node.type_name))
237 attrs.append(('glib:get-type', node.get_type))
238 with self.tagcontext(tag_name, attrs):
239 if isinstance(node, GLibObject):
240 for iface in node.interfaces:
241 self.write_tag('implements', [('name', iface)])
242 if isinstance(node, Class):
243 for method in node.constructors:
244 self._write_constructor(method)
245 for method in node.methods:
246 self._write_method(method)
247 for prop in node.properties:
248 self._write_property(prop)
249 for field in node.fields:
250 self._write_field(field)
251 for signal in node.signals:
252 self._write_signal(signal)
254 def _write_boxed(self, boxed):
255 attrs = [('c:type', boxed.ctype),
256 ('glib:name', boxed.name)]
257 attrs.extend(self._boxed_attrs(boxed))
258 with self.tagcontext('glib:boxed', attrs):
259 self._write_boxed_ctors_methods(boxed)
261 def _write_property(self, prop):
262 attrs = [('name', prop.name)]
263 # Properties are assumed to be readable
264 if not prop.readable:
265 attrs.append(('readable', '0'))
267 attrs.append(('writable', '1'))
268 if prop.construct_only:
269 attrs.append(('construct-only', '1'))
270 with self.tagcontext('property', attrs):
271 self._write_type(prop.type)
273 def _write_callback(self, callback):
274 # FIXME: reuse _write_function
275 attrs = [('name', callback.name), ('c:type', callback.ctype)]
276 self._append_deprecated(callback, attrs)
277 with self.tagcontext('callback', attrs):
278 self._write_return_type(callback.retval)
279 self._write_parameters(callback.parameters)
281 def _boxed_attrs(self, boxed):
282 return [('glib:type-name', boxed.type_name),
283 ('glib:get-type', boxed.get_type)]
285 def _write_boxed_ctors_methods(self, boxed):
286 for method in boxed.constructors:
287 self._write_constructor(method)
288 for method in boxed.methods:
289 self._write_method(method)
291 def _write_record(self, record):
292 attrs = [('name', record.name),
293 ('c:type', record.symbol)]
294 self._append_deprecated(record, attrs)
295 if isinstance(record, GLibBoxed):
296 attrs.extend(self._boxed_attrs(record))
297 with self.tagcontext('record', attrs):
299 for field in record.fields:
300 self._write_field(field)
301 if isinstance(record, GLibBoxed):
302 self._write_boxed_ctors_methods(record)
304 def _write_union(self, union):
305 attrs = [('name', union.name),
306 ('c:type', union.symbol)]
307 self._append_deprecated(union, attrs)
308 if isinstance(union, GLibBoxed):
309 attrs.extend(self._boxed_attrs(union))
310 with self.tagcontext('union', attrs):
312 for field in union.fields:
313 self._write_field(field)
314 if isinstance(union, GLibBoxed):
315 self._write_boxed_ctors_methods(union)
317 def _write_field(self, field):
318 if isinstance(field, Function):
319 self._write_method(field)
322 if isinstance(field, Callback):
323 self._write_callback(field)
326 attrs = [('name', field.name)]
328 attrs.append(('bits', str(field.bits)))
329 with self.tagcontext('field', attrs):
330 self._write_type(field.type)
332 def _write_signal(self, signal):
333 attrs = [('name', signal.name)]
334 with self.tagcontext('glib:signal', attrs):
335 self._write_return_type(signal.retval)
336 self._write_parameters(signal.parameters)