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
24 from giscanner.ast import (Callback, Enum, Function, Namespace, Member,
25 Parameter, Return, Sequence, Struct, Field,
26 Type, Alias, type_name_from_ctype)
27 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
28 GLibInterface, GLibObject, GLibSignal)
29 from giscanner.sourcescanner import (
30 SourceSymbol, ctype_name, symbol_type_name, CTYPE_POINTER,
31 CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY,
32 CTYPE_TYPEDEF, CTYPE_VOID, CTYPE_BASIC_TYPE, CTYPE_ENUM,
33 CTYPE_FUNCTION, CTYPE_STRUCT, CSYMBOL_TYPE_FUNCTION,
34 CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT, CSYMBOL_TYPE_ENUM,
35 CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT, CSYMBOL_TYPE_MEMBER)
36 from .utils import strip_common_prefix
39 class Transformer(object):
41 def __init__(self, generator, namespace_name):
42 self.generator = generator
43 self._namespace = Namespace(namespace_name)
45 self._alias_names = {}
47 self._ctype_names = {}
48 self._typedefs_ns = {}
49 self._strip_prefix = ''
52 def get_type_names(self):
53 return self._type_names
55 def get_alias_names(self):
56 return self._alias_names
58 def set_strip_prefix(self, strip_prefix):
59 self._strip_prefix = strip_prefix
61 def resolve_possible_typedef(self, tname):
62 return self._typedefs.get(tname, tname)
66 for symbol in self.generator.get_symbols():
67 node = self._traverse_one(symbol)
70 if node.name.startswith('_'):
72 self._namespace.nodes.append(node)
73 self._output_ns[node.name] = node
74 return self._namespace
76 def register_include(self, filename):
77 if filename.endswith('.gir'):
78 from .girparser import GIRParser
79 parser = GIRParser(filename)
80 elif filename.endswith('.gidl'):
81 from .gidlparser import GIDLParser
82 parser = GIDLParser(filename)
84 raise NotImplementedError(filename)
85 nsname = parser.get_namespace_name()
86 for node in parser.get_nodes():
87 if hasattr(node, 'ctype'):
88 self._ctype_names[node.ctype] = (nsname, node)
89 if isinstance(node, GLibBoxed) or isinstance(node, GLibInterface) \
90 or isinstance(node, GLibObject):
91 self._type_names[node.type_name] = (nsname, node)
92 elif isinstance(node, Alias):
93 self._alias_names[node.name] = (nsname, node)
95 self._type_names[node.name] = (nsname, node)
97 def strip_namespace_object(self, name):
99 prefix = self._namespace.name.lower()
101 if name.startswith(prefix):
102 name = orig_name[len(prefix):]
107 def _strip_namespace_func(self, name):
109 prefix = self._namespace.name.lower() + '_'
111 if name.startswith(prefix):
112 name = orig_name[len(prefix):]
115 def _remove_prefix(self, name):
116 # when --strip-prefix=g:
117 # GHashTable -> HashTable
118 # g_hash_table_new -> hash_table_new
119 if name.lower().startswith(self._strip_prefix.lower()):
120 name = name[len(self._strip_prefix):]
122 while name.startswith('_'):
126 def _traverse_one(self, symbol, stype=None):
127 assert isinstance(symbol, SourceSymbol), symbol
131 if stype == CSYMBOL_TYPE_FUNCTION:
132 return self._create_function(symbol)
133 elif stype == CSYMBOL_TYPE_TYPEDEF:
134 return self._create_typedef(symbol)
135 elif stype == CSYMBOL_TYPE_STRUCT:
136 return self._create_struct(symbol)
137 elif stype == CSYMBOL_TYPE_ENUM:
138 return self._create_enum(symbol)
139 elif stype == CSYMBOL_TYPE_OBJECT:
140 return self._create_object(symbol)
141 elif stype == CSYMBOL_TYPE_MEMBER:
142 return self._create_member(symbol)
143 elif stype == CSYMBOL_TYPE_UNION:
144 # Unions are not supported
147 raise NotImplementedError(
148 'Transformer: unhandled symbol: %r' % (symbol, ))
150 def _create_enum(self, symbol):
152 for child in symbol.base_type.child_list:
153 name = strip_common_prefix(symbol.ident, child.ident).lower()
154 members.append(Member(name,
158 enum_name = self.strip_namespace_object(symbol.ident)
159 return Enum(enum_name, symbol.ident, members)
161 def _create_object(self, symbol):
162 return Member(symbol.ident, symbol.base_type.name,
165 def _create_function(self, symbol):
166 directives = symbol.directives()
167 parameters = list(self._create_parameters(
168 symbol.base_type, directives))
169 return_ = self._create_return(symbol.base_type.base_type,
170 directives.get('return', []))
171 name = self._remove_prefix(symbol.ident)
172 name = self._strip_namespace_func(name)
173 return Function(name, return_, parameters, symbol.ident)
175 def _create_source_type(self, source_type):
176 if source_type is None:
178 if source_type.type == CTYPE_VOID:
180 elif source_type.type == CTYPE_BASIC_TYPE:
181 value = source_type.name
182 elif source_type.type == CTYPE_TYPEDEF:
183 value = source_type.name
184 elif source_type.type == CTYPE_ARRAY:
185 return self._create_source_type(source_type.base_type)
186 elif source_type.type == CTYPE_POINTER:
187 value = self._create_source_type(source_type.base_type) + '*'
189 print 'TRANSFORMER: Unhandled source type %r' % (
194 def _create_parameters(self, base_type, options=None):
197 for child in base_type.child_list:
198 yield self._create_parameter(
199 child, options.get(child.ident, []))
201 def _create_member(self, symbol):
202 ctype = symbol.base_type.type
203 if (ctype == CTYPE_POINTER and
204 symbol.base_type.base_type.type == CTYPE_FUNCTION):
205 node = self._create_callback(symbol)
207 ftype = self._create_type(symbol.base_type)
208 node = Field(symbol.ident, ftype, symbol.ident)
211 def _create_typedef(self, symbol):
212 ctype = symbol.base_type.type
213 if (ctype == CTYPE_POINTER and
214 symbol.base_type.base_type.type == CTYPE_FUNCTION):
215 node = self._create_callback(symbol)
216 elif ctype == CTYPE_STRUCT:
217 node = self._create_typedef_struct(symbol)
218 elif ctype == CTYPE_ENUM:
219 return self._create_enum(symbol)
220 elif ctype in (CTYPE_TYPEDEF,
225 if symbol.base_type.name:
226 return Alias(symbol.ident, symbol.base_type.name)
229 raise NotImplementedError(
230 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
233 def _create_type(self, source_type):
234 ctype = self._create_source_type(source_type)
235 type_name = type_name_from_ctype(ctype)
236 resolved_type_name = self.resolve_type_name(type_name)
237 return Type(resolved_type_name, ctype)
239 def _create_parameter(self, symbol, options):
240 ptype = self._create_type(symbol.base_type)
241 param = Parameter(symbol.ident, ptype)
242 for option in options:
243 if option in ['in-out', 'inout']:
244 param.direction = 'inout'
246 param.direction = 'in'
247 elif option == 'out':
248 param.direction = 'out'
249 elif option == 'callee-owns':
250 param.transfer = True
251 elif option == 'allow-none':
252 param.allow_none = True
254 print 'Unhandled parameter annotation option: %s' % (
258 def _create_return(self, source_type, options=None):
261 rtype = self._create_type(source_type)
262 rtype = self.resolve_param_type(rtype)
263 return_ = Return(rtype)
264 for option in options:
265 if option == 'caller-owns':
266 return_.transfer = True
267 elif option.startswith('seq '):
268 value, element_options = option[3:].split(None, 2)
269 element_type = self._parse_type_annotation(value)
270 seq = Sequence(rtype.name,
271 type_name_from_ctype(rtype.name),
276 print 'Unhandled parameter annotation option: %s' % (
280 def _create_typedef_struct(self, symbol):
281 name = self._remove_prefix(symbol.ident)
282 struct = Struct(name, symbol.ident)
283 self._typedefs_ns[symbol.ident] = struct
286 def _create_struct(self, symbol):
287 struct = self._typedefs_ns.get(symbol.ident, None)
289 name = self._remove_prefix(symbol.ident)
290 name = self.resolve_type_name(name)
291 struct = Struct(name, symbol.ident)
293 for child in symbol.base_type.child_list:
294 field = self._traverse_one(child)
296 struct.fields.append(field)
300 def _create_callback(self, symbol):
301 parameters = self._create_parameters(symbol.base_type.base_type)
302 retval = self._create_return(symbol.base_type.base_type.base_type)
303 return Callback(symbol.ident, retval, list(parameters))
305 def _parse_type_annotation(self, annotation):
306 if (annotation[0] == "[" and
307 annotation[-1] == "]"):
308 return Sequence(self._parse_type_annotation(annotation[1:-1]))
311 def _typepair_to_str(self, item):
315 return '%s.%s' % (nsname, item.name)
317 def resolve_type_name(self, type_name):
318 resolved = self._type_names.get(type_name)
320 return self._typepair_to_str(resolved)
321 resolved = self._alias_names.get(type_name)
323 return self._typepair_to_str(resolved)
326 def resolve_param_type(self, ptype):
327 type_name = ptype.name.replace('*', '')
328 resolved = self._type_names.get(type_name)
330 ptype.name = self._typepair_to_str(resolved)
332 if hasattr(ptype, 'ctype'):
334 resolved = self._ctype_names.get(ctype)
336 ptype.name = self._typepair_to_str(resolved)
338 resolved = self._alias_names.get(type_name)
340 ptype.name = self._typepair_to_str(resolved)