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, Enum, Function, Interface, Member,
26 Array, Struct, Alias, Union, List, Map)
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, shlib, includes):
35 super(GIRWriter, self).__init__()
36 self._write_repository(namespace, shlib, includes)
38 def _write_repository(self, namespace, shlib, 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, shlib)
50 def _write_include(self, include):
51 attrs = [('name', include)]
52 self.write_tag('include', attrs)
54 def _write_namespace(self, namespace, shlib):
55 attrs = [('name', namespace.name),
56 ('shared-library', os.path.basename(shlib))]
57 with self.tagcontext('namespace', attrs):
58 for node in namespace.nodes:
59 self._write_node(node)
61 def _write_node(self, node):
62 if isinstance(node, Function):
63 self._write_function(node)
64 elif isinstance(node, Enum):
65 self._write_enum(node)
66 elif isinstance(node, (Class, Interface)):
67 self._write_class(node)
68 elif isinstance(node, Callback):
69 self._write_callback(node)
70 elif isinstance(node, Struct):
71 self._write_record(node)
72 elif isinstance(node, Union):
73 self._write_union(node)
74 elif isinstance(node, GLibBoxed):
75 self._write_boxed(node)
76 elif isinstance(node, Member):
77 # FIXME: atk_misc_instance singleton
79 elif isinstance(node, Alias):
80 self._write_alias(node)
82 print 'WRITER: Unhandled node', node
84 def _append_deprecated(self, node, attrs):
86 attrs.append(('deprecated', node.deprecated))
87 if node.deprecated_version:
88 attrs.append(('deprecated-version',
89 node.deprecated_version))
91 def _write_alias(self, alias):
92 attrs = [('name', alias.name), ('target', alias.target)]
93 if alias.ctype is not None:
94 attrs.append(('c:type', alias.ctype))
95 self.write_tag('alias', attrs)
97 def _write_function(self, func, tag_name='function'):
98 attrs = [('name', func.name),
99 ('c:identifier', func.symbol)]
100 self._append_deprecated(func, attrs)
101 with self.tagcontext(tag_name, attrs):
102 self._write_return_type(func.retval)
103 self._write_parameters(func.parameters)
105 def _write_method(self, method):
106 self._write_function(method, tag_name='method')
108 def _write_constructor(self, method):
109 self._write_function(method, tag_name='constructor')
111 def _write_return_type(self, return_):
117 attrs.append(('transfer-ownership',
118 str(int(return_.transfer))))
119 with self.tagcontext('return-value', attrs):
120 self._write_type(return_.type)
122 def _write_parameters(self, parameters):
125 with self.tagcontext('parameters'):
126 for parameter in parameters:
127 self._write_parameter(parameter)
129 def _write_parameter(self, parameter):
131 if parameter.name is not None:
132 attrs.append(('name', parameter.name))
133 if parameter.direction != 'in':
134 attrs.append(('direction', parameter.direction))
135 if parameter.transfer:
136 attrs.append(('transfer-ownership',
137 str(int(parameter.transfer))))
138 if parameter.allow_none:
139 attrs.append(('allow-none', '1'))
140 with self.tagcontext('parameter', attrs):
141 self._write_type(parameter.type)
143 def _type_to_string(self, ntype):
144 if isinstance(ntype, basestring):
148 def _write_type(self, ntype, relation=None):
149 if isinstance(ntype, basestring):
153 typename = ntype.name
154 type_cname = ntype.ctype
155 if isinstance(ntype, Array):
157 if not ntype.zeroterminated:
158 attrs.append(('zero-terminated', '0'))
159 if ntype.length_param_index >= 0:
160 attrs.append(('length', '%d' % (ntype.length_param_index, )))
161 attrs.append(('c:type', ntype.ctype))
162 with self.tagcontext('array', attrs):
163 self._write_type(ntype.element_type)
165 attrs = [('name', self._type_to_string(ntype))]
166 # FIXME: figure out if type references a basic type
167 # or a boxed/class/interface etc. and skip
168 # writing the ctype if the latter.
169 if type_cname is not None:
170 attrs.append(('c:type', type_cname))
171 if isinstance(ntype, List) and ntype.element_type:
172 with self.tagcontext('type', attrs):
173 self._write_type(ntype.element_type)
175 if isinstance(ntype, Map) and ntype.key_type:
176 with self.tagcontext('type', attrs):
177 self._write_type(ntype.key_type)
178 self._write_type(ntype.value_type)
180 # Not a special type, just write it out
181 self.write_tag('type', attrs)
183 def _write_enum(self, enum):
184 attrs = [('name', enum.name),
185 ('c:type', enum.symbol)]
186 self._append_deprecated(enum, attrs)
187 tag_name = 'enumeration'
188 if isinstance(enum, GLibEnum):
189 attrs.extend([('glib:type-name', enum.type_name),
190 ('glib:get-type', enum.get_type)])
191 if isinstance(enum, GLibFlags):
192 tag_name = 'bitfield'
194 with self.tagcontext(tag_name, attrs):
195 for member in enum.members:
196 self._write_member(member)
198 def _write_member(self, member):
199 attrs = [('name', member.name),
200 ('value', str(member.value)),
201 ('c:identifier', member.symbol)]
202 if isinstance(member, GLibEnumMember):
203 attrs.append(('glib:nick', member.nick))
204 self.write_tag('member', attrs)
206 def _write_class(self, node):
207 attrs = [('name', node.name),
208 ('c:type', node.ctype)]
209 self._append_deprecated(node, attrs)
210 if isinstance(node, Class):
212 if node.parent is not None:
213 attrs.append(('parent', node.parent))
215 tag_name = 'interface'
216 if isinstance(node, (GLibObject, GLibInterface)):
217 attrs.append(('glib:type-name', node.type_name))
219 attrs.append(('glib:get-type', node.get_type))
220 with self.tagcontext(tag_name, attrs):
221 if isinstance(node, GLibObject):
222 for iface in node.interfaces:
223 self.write_tag('implements', [('name', iface)])
224 if isinstance(node, Class):
225 for method in node.constructors:
226 self._write_constructor(method)
227 for method in node.methods:
228 self._write_method(method)
229 for prop in node.properties:
230 self._write_property(prop)
231 for field in node.fields:
232 self._write_field(field)
233 for signal in node.signals:
234 self._write_signal(signal)
236 def _write_boxed(self, boxed):
237 attrs = [('c:type', boxed.ctype),
238 ('glib:name', boxed.name)]
239 attrs.extend(self._boxed_attrs(boxed))
240 with self.tagcontext('glib:boxed', attrs):
241 self._write_boxed_ctors_methods(boxed)
243 def _write_property(self, prop):
244 attrs = [('name', prop.name)]
245 # Properties are assumed to be readable
246 if not prop.readable:
247 attrs.append(('readable', '0'))
249 attrs.append(('writable', '1'))
250 if prop.construct_only:
251 attrs.append(('construct-only', '1'))
252 with self.tagcontext('property', attrs):
253 self._write_type(prop.type)
255 def _write_callback(self, callback):
256 # FIXME: reuse _write_function
257 attrs = [('name', callback.name), ('c:type', callback.ctype)]
258 self._append_deprecated(callback, attrs)
259 with self.tagcontext('callback', attrs):
260 self._write_return_type(callback.retval)
261 self._write_parameters(callback.parameters)
263 def _boxed_attrs(self, boxed):
264 return [('glib:type-name', boxed.type_name),
265 ('glib:get-type', boxed.get_type)]
267 def _write_boxed_ctors_methods(self, boxed):
268 for method in boxed.constructors:
269 self._write_constructor(method)
270 for method in boxed.methods:
271 self._write_method(method)
273 def _write_record(self, record):
274 attrs = [('name', record.name),
275 ('c:type', record.symbol)]
276 self._append_deprecated(record, attrs)
277 if isinstance(record, GLibBoxed):
278 attrs.extend(self._boxed_attrs(record))
279 with self.tagcontext('record', attrs):
281 for field in record.fields:
282 self._write_field(field)
283 if isinstance(record, GLibBoxed):
284 self._write_boxed_ctors_methods(record)
286 def _write_union(self, union):
287 attrs = [('name', union.name),
288 ('c:type', union.symbol)]
289 self._append_deprecated(union, attrs)
290 if isinstance(union, GLibBoxed):
291 attrs.extend(self._boxed_attrs(union))
292 with self.tagcontext('union', attrs):
294 for field in union.fields:
295 self._write_field(field)
296 if isinstance(union, GLibBoxed):
297 self._write_boxed_ctors_methods(union)
299 def _write_field(self, field):
300 # FIXME: Just function
301 if isinstance(field, (Callback, Function)):
302 self._write_callback(field)
305 attrs = [('name', field.name)]
306 with self.tagcontext('field', attrs):
307 self._write_type(field.type)
309 def _write_signal(self, signal):
310 attrs = [('name', signal.name)]
311 with self.tagcontext('glib:signal', attrs):
312 self._write_return_type(signal.retval)
313 self._write_parameters(signal.parameters)