Adjust for added shared-library. Make pylint happy.
[gnome.gobject-introspection] / giscanner / girwriter.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
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.
9 #
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.
14 #
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
18 # 02110-1301, USA.
19 #
20
21 from __future__ import with_statement
22
23 import os
24
25 from .ast import (Callback, Class, Enum, Function, Interface, Member,
26                   Sequence, Struct, Alias, Union)
27 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
28                       GLibFlags, GLibObject, GLibInterface)
29 from .xmlwriter import XMLWriter
30
31
32 class GIRWriter(XMLWriter):
33
34     def __init__(self, namespace, shlib):
35         super(GIRWriter, self).__init__()
36         self._write_repository(namespace, shlib)
37
38     def _write_repository(self, namespace, shlib):
39         attrs = [
40             ('version', '1.0'),
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'),
44             ]
45         with self.tagcontext('repository', attrs):
46             self._write_namespace(namespace, shlib)
47
48     def _write_namespace(self, namespace, shlib):
49         attrs = [('name', namespace.name),
50                  ('shared-library', os.path.basename(shlib))]
51         with self.tagcontext('namespace', attrs):
52             for node in namespace.nodes:
53                 self._write_node(node)
54
55     def _write_node(self, node):
56         if isinstance(node, Function):
57             self._write_function(node)
58         elif isinstance(node, Enum):
59             self._write_enum(node)
60         elif isinstance(node, (Class, Interface)):
61             self._write_class(node)
62         elif isinstance(node, GLibBoxed):
63             self._write_boxed(node)
64         elif isinstance(node, Callback):
65             self._write_callback(node)
66         elif isinstance(node, Struct):
67             self._write_record(node)
68         elif isinstance(node, Union):
69             self._write_union(node)
70         elif isinstance(node, Member):
71             # FIXME: atk_misc_instance singleton
72             pass
73         elif isinstance(node, Alias):
74             self._write_alias(node)
75         else:
76             print 'WRITER: Unhandled node', node
77
78     def _write_alias(self, alias):
79         attrs = [('name', alias.name), ('target', alias.target)]
80         if alias.ctype is not None:
81             attrs.append(('c:type', alias.ctype))
82         self.write_tag('alias', attrs)
83
84     def _write_function(self, func, tag_name='function'):
85         attrs = [('name', func.name),
86                  ('c:identifier', func.symbol)]
87         with self.tagcontext(tag_name, attrs):
88             self._write_return_type(func.retval)
89             self._write_parameters(func.parameters)
90
91     def _write_method(self, method):
92         self._write_function(method, tag_name='method')
93
94     def _write_constructor(self, method):
95         self._write_function(method, tag_name='constructor')
96
97     def _write_return_type(self, return_):
98         if not return_:
99             return
100
101         attrs = []
102         if return_.transfer:
103             attrs.append(('transfer-ownership',
104                           str(int(return_.transfer))))
105         with self.tagcontext('return-value', attrs):
106             self._write_type(return_.type)
107
108     def _write_parameters(self, parameters):
109         if not parameters:
110             return
111         with self.tagcontext('parameters'):
112             for parameter in parameters:
113                 self._write_parameter(parameter)
114
115     def _write_parameter(self, parameter):
116         attrs = []
117         if parameter.name is not None:
118             attrs.append(('name', parameter.name))
119         if parameter.direction != 'in':
120             attrs.append(('direction', parameter.direction))
121         if parameter.transfer:
122             attrs.append(('transfer-ownership',
123                           str(int(parameter.transfer))))
124         if parameter.allow_none:
125             attrs.append(('allow-none', '1'))
126         with self.tagcontext('parameter', attrs):
127             self._write_type(parameter.type)
128
129     def _write_type(self, ntype, relation=None):
130         if isinstance(ntype, basestring):
131             typename = ntype
132             type_cname = None
133         else:
134             typename = ntype.name
135             type_cname = ntype.ctype
136         attrs = [('name', typename)]
137         if relation:
138             attrs.append(('relation', relation))
139         if isinstance(ntype, Sequence):
140             if ntype.transfer:
141                 attrs.append(('transfer-ownership',
142                               str(int(ntype.transfer))))
143             with self.tagcontext('type', attrs):
144                 self._write_type(ntype.element_type, relation="element")
145         else:
146             # FIXME: figure out if type references a basic type
147             #        or a boxed/class/interface etc. and skip
148             #        writing the ctype if the latter.
149             if type_cname is not None:
150                 attrs.append(('c:type', type_cname))
151             self.write_tag('type', attrs)
152
153     def _write_enum(self, enum):
154         attrs = [('name', enum.name),
155                  ('c:type', enum.symbol)]
156         tag_name = 'enumeration'
157         if isinstance(enum, GLibEnum):
158             attrs.extend([('glib:type-name', enum.type_name),
159                           ('glib:get-type', enum.get_type)])
160             if isinstance(enum, GLibFlags):
161                 tag_name = 'bitfield'
162
163         with self.tagcontext(tag_name, attrs):
164             for member in enum.members:
165                 self._write_member(member)
166
167     def _write_member(self, member):
168         attrs = [('name', member.name),
169                  ('value', str(member.value)),
170                  ('c:identifier', member.symbol)]
171         if isinstance(member, GLibEnumMember):
172             attrs.append(('glib:nick', member.nick))
173         self.write_tag('member', attrs)
174
175     def _write_class(self, node):
176         attrs = [('name', node.name),
177                  ('c:type', node.ctype)]
178         if isinstance(node, Class):
179             tag_name = 'class'
180             if node.parent is not None:
181                 attrs.append(('parent', node.parent))
182         else:
183             tag_name = 'interface'
184         if isinstance(node, (GLibObject, GLibInterface)):
185             attrs.append(('glib:type-name', node.type_name))
186             if node.get_type:
187                 attrs.append(('glib:get-type', node.get_type))
188         with self.tagcontext(tag_name, attrs):
189             if isinstance(node, Class):
190                 for method in node.constructors:
191                     self._write_constructor(method)
192             for method in node.methods:
193                 self._write_method(method)
194             for prop in node.properties:
195                 self._write_property(prop)
196             for field in node.fields:
197                 self._write_field(field)
198             for signal in node.signals:
199                 self._write_signal(signal)
200
201     def _write_boxed(self, boxed):
202         attrs = [('c:type', boxed.ctype),
203                  ('glib:name', boxed.name),
204                  ('glib:type-name', boxed.type_name),
205                  ('glib:get-type', boxed.get_type)]
206
207         with self.tagcontext('glib:boxed', attrs):
208             for method in boxed.constructors:
209                 self._write_constructor(method)
210             for method in boxed.methods:
211                 self._write_method(method)
212
213     def _write_property(self, prop):
214         attrs = [('name', prop.name)]
215         with self.tagcontext('property', attrs):
216             self._write_type(prop.type)
217
218     def _write_callback(self, callback):
219         # FIXME: reuse _write_function
220         attrs = [('name', callback.name), ('c:type', callback.ctype)]
221         with self.tagcontext('callback', attrs):
222             self._write_return_type(callback.retval)
223             self._write_parameters(callback.parameters)
224
225     def _write_record(self, record):
226         attrs = [('name', record.name),
227                  ('c:type', record.symbol)]
228         if record.fields:
229             with self.tagcontext('record', attrs):
230                 for field in record.fields:
231                     self._write_field(field)
232         else:
233             self.write_tag('record', attrs)
234
235     def _write_union(self, union):
236         attrs = [('name', union.name),
237                  ('c:type', union.symbol)]
238         if union.fields:
239             with self.tagcontext('union', attrs):
240                 for field in union.fields:
241                     self._write_field(field)
242         else:
243             self.write_tag('union', attrs)
244
245     def _write_field(self, field):
246         # FIXME: Just function
247         if isinstance(field, (Callback, Function)):
248             self._write_callback(field)
249             return
250
251         attrs = [('name', field.name)]
252         with self.tagcontext('field', attrs):
253             self._write_type(field.type)
254
255     def _write_signal(self, signal):
256         attrs = [('name', signal.name)]
257         with self.tagcontext('glib:signal', attrs):
258             self._write_return_type(signal.retval)
259             self._write_parameters(signal.parameters)