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