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)
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):
146 if isinstance(ntype, Array):
148 if not ntype.zeroterminated:
149 options.append('zero-terminated=0')
150 if ntype.length_param_index >= 0:
151 options.append('length=%d' % (ntype.length_param_index, ))
152 return self._type_to_string(ntype.element_type) + \
153 '[%s]' % (','.join(options), )
156 def _write_type(self, ntype, relation=None):
157 if isinstance(ntype, basestring):
161 typename = ntype.name
162 type_cname = ntype.ctype
163 attrs = [('name', self._type_to_string(ntype))]
165 attrs.append(('relation', relation))
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 self.write_tag('type', attrs)
173 def _write_enum(self, enum):
174 attrs = [('name', enum.name),
175 ('c:type', enum.symbol)]
176 self._append_deprecated(enum, attrs)
177 tag_name = 'enumeration'
178 if isinstance(enum, GLibEnum):
179 attrs.extend([('glib:type-name', enum.type_name),
180 ('glib:get-type', enum.get_type)])
181 if isinstance(enum, GLibFlags):
182 tag_name = 'bitfield'
184 with self.tagcontext(tag_name, attrs):
185 for member in enum.members:
186 self._write_member(member)
188 def _write_member(self, member):
189 attrs = [('name', member.name),
190 ('value', str(member.value)),
191 ('c:identifier', member.symbol)]
192 if isinstance(member, GLibEnumMember):
193 attrs.append(('glib:nick', member.nick))
194 self.write_tag('member', attrs)
196 def _write_class(self, node):
197 attrs = [('name', node.name),
198 ('c:type', node.ctype)]
199 self._append_deprecated(node, attrs)
200 if isinstance(node, Class):
202 if node.parent is not None:
203 attrs.append(('parent', node.parent))
205 tag_name = 'interface'
206 if isinstance(node, (GLibObject, GLibInterface)):
207 attrs.append(('glib:type-name', node.type_name))
209 attrs.append(('glib:get-type', node.get_type))
210 with self.tagcontext(tag_name, attrs):
211 if isinstance(node, GLibObject):
212 for iface in node.interfaces:
213 self.write_tag('implements', [('name', iface)])
214 if isinstance(node, Class):
215 for method in node.constructors:
216 self._write_constructor(method)
217 for method in node.methods:
218 self._write_method(method)
219 for prop in node.properties:
220 self._write_property(prop)
221 for field in node.fields:
222 self._write_field(field)
223 for signal in node.signals:
224 self._write_signal(signal)
226 def _write_boxed(self, boxed):
227 attrs = [('c:type', boxed.ctype),
228 ('glib:name', boxed.name)]
229 attrs.extend(self._boxed_attrs(boxed))
230 with self.tagcontext('glib:boxed', attrs):
231 self._write_boxed_ctors_methods(boxed)
233 def _write_property(self, prop):
234 attrs = [('name', prop.name)]
235 # Properties are assumed to be readable
236 if not prop.readable:
237 attrs.append(('readable', '0'))
239 attrs.append(('writable', '1'))
240 if prop.construct_only:
241 attrs.append(('construct-only', '1'))
242 with self.tagcontext('property', attrs):
243 self._write_type(prop.type)
245 def _write_callback(self, callback):
246 # FIXME: reuse _write_function
247 attrs = [('name', callback.name), ('c:type', callback.ctype)]
248 self._append_deprecated(callback, attrs)
249 with self.tagcontext('callback', attrs):
250 self._write_return_type(callback.retval)
251 self._write_parameters(callback.parameters)
253 def _boxed_attrs(self, boxed):
254 return [('glib:type-name', boxed.type_name),
255 ('glib:get-type', boxed.get_type)]
257 def _write_boxed_ctors_methods(self, boxed):
258 for method in boxed.constructors:
259 self._write_constructor(method)
260 for method in boxed.methods:
261 self._write_method(method)
263 def _write_record(self, record):
264 attrs = [('name', record.name),
265 ('c:type', record.symbol)]
266 self._append_deprecated(record, attrs)
267 if isinstance(record, GLibBoxed):
268 attrs.extend(self._boxed_attrs(record))
269 with self.tagcontext('record', attrs):
271 for field in record.fields:
272 self._write_field(field)
273 if isinstance(record, GLibBoxed):
274 self._write_boxed_ctors_methods(record)
276 def _write_union(self, union):
277 attrs = [('name', union.name),
278 ('c:type', union.symbol)]
279 self._append_deprecated(union, attrs)
280 if isinstance(union, GLibBoxed):
281 attrs.extend(self._boxed_attrs(union))
282 with self.tagcontext('union', attrs):
284 for field in union.fields:
285 self._write_field(field)
286 if isinstance(union, GLibBoxed):
287 self._write_boxed_ctors_methods(union)
289 def _write_field(self, field):
290 # FIXME: Just function
291 if isinstance(field, (Callback, Function)):
292 self._write_callback(field)
295 attrs = [('name', field.name)]
296 with self.tagcontext('field', attrs):
297 self._write_type(field.type)
299 def _write_signal(self, signal):
300 attrs = [('name', signal.name)]
301 with self.tagcontext('glib:signal', attrs):
302 self._write_return_type(signal.retval)
303 self._write_parameters(signal.parameters)