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 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,
32 from .utils import strip_common_prefix
35 class Transformer(object):
37 def __init__(self, generator, namespace_name):
38 self.generator = generator
39 self._namespace = Namespace(namespace_name)
41 self._alias_names = {}
43 self._ctype_names = {}
44 self._typedefs_ns = {}
45 self._strip_prefix = ''
48 def get_type_names(self):
49 return self._type_names
51 def get_alias_names(self):
52 return self._alias_names
54 def set_strip_prefix(self, strip_prefix):
55 self._strip_prefix = strip_prefix
57 def resolve_possible_typedef(self, tname):
58 return self._typedefs.get(tname, tname)
62 for symbol in self.generator.get_symbols():
63 node = self._traverse_one(symbol)
66 if node.name.startswith('_'):
68 self._namespace.nodes.append(node)
69 self._output_ns[node.name] = node
70 return self._namespace
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)
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)
90 self._type_names[node.name] = (nsname, node)
92 def strip_namespace_object(self, name):
94 prefix = self._namespace.name.lower()
96 if name.startswith(prefix):
97 name = orig_name[len(prefix):]
102 def _strip_namespace_func(self, name):
104 prefix = self._namespace.name.lower() + '_'
106 if name.startswith(prefix):
107 name = orig_name[len(prefix):]
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):]
117 while name.startswith('_'):
121 def _traverse_one(self, symbol, stype=None):
122 assert isinstance(symbol, SourceSymbol), symbol
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
142 raise NotImplementedError(
143 'Transformer: unhandled symbol: %r' % (symbol, ))
145 def _create_enum(self, symbol):
147 for child in symbol.base_type.child_list:
148 name = strip_common_prefix(symbol.ident, child.ident).lower()
149 members.append(Member(name,
153 enum_name = self.strip_namespace_object(symbol.ident)
154 return Enum(enum_name, symbol.ident, members)
156 def _create_object(self, symbol):
157 return Member(symbol.ident, symbol.base_type.name,
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)
170 def _create_source_type(self, source_type):
171 if source_type is None:
173 if source_type.type == CTYPE_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) + '*'
184 print 'TRANSFORMER: Unhandled source type %r' % (
189 def _create_parameters(self, base_type, options=None):
192 for child in base_type.child_list:
193 yield self._create_parameter(
194 child, options.get(child.ident, []))
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)
202 ftype = self._create_type(symbol.base_type)
203 node = Field(symbol.ident, ftype, symbol.ident)
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,
220 if symbol.base_type.name:
221 return Alias(symbol.ident, symbol.base_type.name)
224 raise NotImplementedError(
225 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
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)
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'
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
249 print 'Unhandled parameter annotation option: %s' % (
253 def _create_return(self, source_type, options=None):
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),
271 print 'Unhandled parameter annotation option: %s' % (
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
281 def _create_struct(self, symbol):
282 struct = self._typedefs_ns.get(symbol.ident, None)
284 name = self._remove_prefix(symbol.ident)
285 name = self.resolve_type_name(name)
286 struct = Struct(name, symbol.ident)
288 for child in symbol.base_type.child_list:
289 field = self._traverse_one(child)
291 struct.fields.append(field)
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))
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]))
306 def _typepair_to_str(self, item):
310 return '%s.%s' % (nsname, item.name)
312 def resolve_type_name(self, type_name):
313 resolved = self._type_names.get(type_name)
315 return self._typepair_to_str(resolved)
316 resolved = self._alias_names.get(type_name)
318 return self._typepair_to_str(resolved)
321 def resolve_param_type(self, ptype):
322 type_name = ptype.name.replace('*', '')
323 resolved = self._type_names.get(type_name)
325 ptype.name = self._typepair_to_str(resolved)
327 if hasattr(ptype, 'ctype'):
329 resolved = self._ctype_names.get(ctype)
331 ptype.name = self._typepair_to_str(resolved)
333 resolved = self._alias_names.get(type_name)
335 ptype.name = self._typepair_to_str(resolved)