Add pyflakes.py and run it in make check. Update the source code to fix
[platform/upstream/gobject-introspection.git] / giscanner / transformer.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 giscanner.ast import (Callback, Enum, Function, Namespace, Member,
22                            Parameter, Return, Sequence, Struct, Field,
23                            Type, Alias, type_name_from_ctype)
24 from .glibast import GLibBoxed, GLibInterface, GLibObject
25 from giscanner.sourcescanner import (
26     SourceSymbol, ctype_name, CTYPE_POINTER,
27     CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF,
28     CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT,
29     CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT,
30     CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT,
31     CSYMBOL_TYPE_MEMBER)
32 from .utils import strip_common_prefix
33
34
35 class Transformer(object):
36
37     def __init__(self, generator, namespace_name):
38         self.generator = generator
39         self._namespace = Namespace(namespace_name)
40         self._output_ns = {}
41         self._alias_names = {}
42         self._type_names = {}
43         self._ctype_names = {}
44         self._typedefs_ns = {}
45         self._strip_prefix = ''
46         self._typedefs = {}
47
48     def get_type_names(self):
49         return self._type_names
50
51     def get_alias_names(self):
52         return self._alias_names
53
54     def set_strip_prefix(self, strip_prefix):
55         self._strip_prefix = strip_prefix
56
57     def resolve_possible_typedef(self, tname):
58         return self._typedefs.get(tname, tname)
59
60     def parse(self):
61         nodes = []
62         for symbol in self.generator.get_symbols():
63             node = self._traverse_one(symbol)
64             if node is None:
65                 continue
66             if node.name.startswith('_'):
67                 continue
68             self._namespace.nodes.append(node)
69             self._output_ns[node.name] = node
70         return self._namespace
71
72     def register_include(self, filename):
73         if filename.endswith('.gir'):
74             from .girparser import GIRParser
75             parser = GIRParser(filename)
76         elif filename.endswith('.gidl'):
77             from .gidlparser import GIDLParser
78             parser = GIDLParser(filename)
79         else:
80             raise NotImplementedError(filename)
81         nsname = parser.get_namespace_name()
82         for node in parser.get_nodes():
83             if hasattr(node, 'ctype'):
84                 self._ctype_names[node.ctype] = (nsname, node)
85             if isinstance(node, (GLibBoxed, GLibInterface, GLibObject)):
86                 self._type_names[node.type_name] = (nsname, node)
87             elif isinstance(node, Alias):
88                 self._alias_names[node.name] = (nsname, node)
89             else:
90                 self._type_names[node.name] = (nsname, node)
91
92     def strip_namespace_object(self, name):
93         orig_name = name
94         prefix = self._namespace.name.lower()
95         name = name.lower()
96         if name.startswith(prefix):
97             name = orig_name[len(prefix):]
98         return name
99
100     # Private
101
102     def _strip_namespace_func(self, name):
103         orig_name = name
104         prefix = self._namespace.name.lower() + '_'
105         name = name.lower()
106         if name.startswith(prefix):
107             name = orig_name[len(prefix):]
108         return name
109
110     def _remove_prefix(self, name):
111         # when --strip-prefix=g:
112         #   GHashTable -> HashTable
113         #   g_hash_table_new -> hash_table_new
114         if name.lower().startswith(self._strip_prefix.lower()):
115             name = name[len(self._strip_prefix):]
116
117         while name.startswith('_'):
118             name = name[1:]
119         return name
120
121     def _traverse_one(self, symbol, stype=None):
122         assert isinstance(symbol, SourceSymbol), symbol
123
124         if stype is None:
125             stype = symbol.type
126         if stype == CSYMBOL_TYPE_FUNCTION:
127             return self._create_function(symbol)
128         elif stype == CSYMBOL_TYPE_TYPEDEF:
129             return self._create_typedef(symbol)
130         elif stype == CSYMBOL_TYPE_STRUCT:
131             return self._create_struct(symbol)
132         elif stype == CSYMBOL_TYPE_ENUM:
133             return self._create_enum(symbol)
134         elif stype == CSYMBOL_TYPE_OBJECT:
135             return self._create_object(symbol)
136         elif stype == CSYMBOL_TYPE_MEMBER:
137             return self._create_member(symbol)
138         elif stype == CSYMBOL_TYPE_UNION:
139             # Unions are not supported
140             pass
141         else:
142             raise NotImplementedError(
143                 'Transformer: unhandled symbol: %r' % (symbol, ))
144
145     def _create_enum(self, symbol):
146         members = []
147         for child in symbol.base_type.child_list:
148             name = strip_common_prefix(symbol.ident, child.ident).lower()
149             members.append(Member(name,
150                                   child.const_int,
151                                   child.ident))
152
153         enum_name = self.strip_namespace_object(symbol.ident)
154         return Enum(enum_name, symbol.ident, members)
155
156     def _create_object(self, symbol):
157         return Member(symbol.ident, symbol.base_type.name,
158                       symbol.ident)
159
160     def _create_function(self, symbol):
161         directives = symbol.directives()
162         parameters = list(self._create_parameters(
163             symbol.base_type, directives))
164         return_ = self._create_return(symbol.base_type.base_type,
165                                       directives.get('return', []))
166         name = self._remove_prefix(symbol.ident)
167         name = self._strip_namespace_func(name)
168         return Function(name, return_, parameters, symbol.ident)
169
170     def _create_source_type(self, source_type):
171         if source_type is None:
172             return 'None'
173         if source_type.type == CTYPE_VOID:
174             value = 'void'
175         elif source_type.type == CTYPE_BASIC_TYPE:
176             value = source_type.name
177         elif source_type.type == CTYPE_TYPEDEF:
178             value = source_type.name
179         elif source_type.type == CTYPE_ARRAY:
180             return self._create_source_type(source_type.base_type)
181         elif source_type.type == CTYPE_POINTER:
182             value = self._create_source_type(source_type.base_type) + '*'
183         else:
184             print 'TRANSFORMER: Unhandled source type %r' % (
185                 source_type, )
186             value = '???'
187         return value
188
189     def _create_parameters(self, base_type, options=None):
190         if not options:
191             options = {}
192         for child in base_type.child_list:
193             yield self._create_parameter(
194                 child, options.get(child.ident, []))
195
196     def _create_member(self, symbol):
197         ctype = symbol.base_type.type
198         if (ctype == CTYPE_POINTER and
199             symbol.base_type.base_type.type == CTYPE_FUNCTION):
200             node = self._create_callback(symbol)
201         else:
202             ftype = self._create_type(symbol.base_type)
203             node = Field(symbol.ident, ftype, symbol.ident)
204         return node
205
206     def _create_typedef(self, symbol):
207         ctype = symbol.base_type.type
208         if (ctype == CTYPE_POINTER and
209             symbol.base_type.base_type.type == CTYPE_FUNCTION):
210             node = self._create_callback(symbol)
211         elif ctype == CTYPE_STRUCT:
212             node = self._create_typedef_struct(symbol)
213         elif ctype == CTYPE_ENUM:
214             return self._create_enum(symbol)
215         elif ctype in (CTYPE_TYPEDEF,
216                        CTYPE_POINTER,
217                        CTYPE_BASIC_TYPE,
218                        CTYPE_UNION,
219                        CTYPE_VOID):
220             if symbol.base_type.name:
221                 return Alias(symbol.ident, symbol.base_type.name)
222             return None
223         else:
224             raise NotImplementedError(
225                 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
226         return node
227
228     def _create_type(self, source_type):
229         ctype = self._create_source_type(source_type)
230         type_name = type_name_from_ctype(ctype)
231         resolved_type_name = self.resolve_type_name(type_name)
232         return Type(resolved_type_name, ctype)
233
234     def _create_parameter(self, symbol, options):
235         ptype = self._create_type(symbol.base_type)
236         param = Parameter(symbol.ident, ptype)
237         for option in options:
238             if option in ['in-out', 'inout']:
239                 param.direction = 'inout'
240             elif option == 'in':
241                 param.direction = 'in'
242             elif option == 'out':
243                 param.direction = 'out'
244             elif option == 'callee-owns':
245                 param.transfer = True
246             elif option == 'allow-none':
247                 param.allow_none = True
248             else:
249                 print 'Unhandled parameter annotation option: %s' % (
250                     option, )
251         return param
252
253     def _create_return(self, source_type, options=None):
254         if not options:
255             options = []
256         rtype = self._create_type(source_type)
257         rtype = self.resolve_param_type(rtype)
258         return_ = Return(rtype)
259         for option in options:
260             if option == 'caller-owns':
261                 return_.transfer = True
262             elif option.startswith('seq '):
263                 value, element_options = option[3:].split(None, 2)
264                 element_type = self._parse_type_annotation(value)
265                 seq = Sequence(rtype.name,
266                                type_name_from_ctype(rtype.name),
267                                element_type)
268                 seq.transfer = True
269                 return_.type = seq
270             else:
271                 print 'Unhandled parameter annotation option: %s' % (
272                     option, )
273         return return_
274
275     def _create_typedef_struct(self, symbol):
276         name = self._remove_prefix(symbol.ident)
277         struct = Struct(name, symbol.ident)
278         self._typedefs_ns[symbol.ident] = struct
279         return struct
280
281     def _create_struct(self, symbol):
282         struct = self._typedefs_ns.get(symbol.ident, None)
283         if struct is None:
284             name = self._remove_prefix(symbol.ident)
285             name = self.resolve_type_name(name)
286             struct = Struct(name, symbol.ident)
287
288         for child in symbol.base_type.child_list:
289             field = self._traverse_one(child)
290             if field:
291                 struct.fields.append(field)
292
293         return struct
294
295     def _create_callback(self, symbol):
296         parameters = self._create_parameters(symbol.base_type.base_type)
297         retval = self._create_return(symbol.base_type.base_type.base_type)
298         return Callback(symbol.ident, retval, list(parameters))
299
300     def _parse_type_annotation(self, annotation):
301         if (annotation[0] == "[" and
302             annotation[-1] == "]"):
303             return Sequence(self._parse_type_annotation(annotation[1:-1]))
304         return annotation
305
306     def _typepair_to_str(self, item):
307         nsname, item = item
308         if nsname is None:
309             return item.name
310         return '%s.%s' % (nsname, item.name)
311
312     def resolve_type_name(self, type_name):
313         resolved = self._type_names.get(type_name)
314         if resolved:
315             return self._typepair_to_str(resolved)
316         resolved = self._alias_names.get(type_name)
317         if resolved:
318             return self._typepair_to_str(resolved)
319         return type_name
320
321     def resolve_param_type(self, ptype):
322         type_name = ptype.name.replace('*', '')
323         resolved = self._type_names.get(type_name)
324         if resolved:
325             ptype.name = self._typepair_to_str(resolved)
326             return ptype
327         if hasattr(ptype, 'ctype'):
328             ctype = ptype.ctype
329             resolved = self._ctype_names.get(ctype)
330             if resolved:
331                 ptype.name = self._typepair_to_str(resolved)
332                 return ptype
333         resolved = self._alias_names.get(type_name)
334         if resolved:
335             ptype.name = self._typepair_to_str(resolved)
336             return ptype
337         return ptype