a3fcff911203b1cc282a1ad21ceead9508fae863
[gnome.gobject-introspection] / giscanner / transformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library 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 GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import os
22 import sys
23
24 from .ast import (Bitfield, Callback, Enum, Function, Namespace, Member,
25                   Parameter, Return, Struct, Field,
26                   Type, Array, Alias, Interface, Class, Node, Union,
27                   Varargs, Constant, type_name_from_ctype,
28                   type_names, TYPE_STRING, BASIC_GIR_TYPES)
29 from .config import DATADIR, GIR_DIR, GIR_SUFFIX
30 from .glibast import GLibBoxed
31 from .girparser import GIRParser
32 from .odict import odict
33 from .sourcescanner import (
34     SourceSymbol, ctype_name, CTYPE_POINTER,
35     CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF,
36     CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT,
37     CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT,
38     CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT,
39     CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST,
40     TYPE_QUALIFIER_CONST)
41 from .utils import to_underscores
42
43 _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(':') \
44                       + [DATADIR, '/usr/share'] if x]
45
46
47 class SkipError(Exception):
48     pass
49
50 class VaListSkipError(SkipError):
51     pass
52
53 class Names(object):
54     names = property(lambda self: self._names)
55     aliases = property(lambda self: self._aliases)
56     type_names = property(lambda self: self._type_names)
57     ctypes = property(lambda self: self._ctypes)
58
59     def __init__(self):
60         super(Names, self).__init__()
61         self._names = odict() # Maps from GIName -> (namespace, node)
62         self._aliases = {} # Maps from GIName -> GIName
63         self._type_names = {} # Maps from GTName -> (namespace, node)
64         self._ctypes = {} # Maps from CType -> (namespace, node)
65
66
67 class Transformer(object):
68
69     def __init__(self, cachestore, namespace_name, namespace_version):
70         self._cachestore = cachestore
71         self.generator = None
72         self._namespace = Namespace(namespace_name, namespace_version)
73         self._names = Names()
74         self._pkg_config_packages = set()
75         self._typedefs_ns = {}
76         self._strip_prefix = ''
77         self._includes = set()
78         self._includepaths = []
79
80     def get_names(self):
81         return self._names
82
83     def get_includes(self):
84         return self._includes
85
86     def set_strip_suffix(self, strip_suffix):
87         self._strip_suffix = strip_suffix
88
89     def set_strip_prefix(self, strip_prefix):
90         self._strip_prefix = strip_prefix
91
92     def get_strip_prefix(self):
93         return self._strip_prefix
94
95     def get_pkgconfig_packages(self):
96         return self._pkg_config_packages
97
98     def set_source_ast(self, src_ast):
99         self.generator = src_ast
100
101     def parse(self):
102         nodes = []
103         for symbol in self.generator.get_symbols():
104             try:
105                 node = self._traverse_one(symbol)
106             except SkipError:
107                 continue
108             self._add_node(node)
109         return self._namespace
110
111     def set_include_paths(self, paths):
112         self._includepaths = list(paths)
113
114     def register_include(self, include):
115         if include in self._includes:
116             return
117         filename = self._find_include(include)
118         self._parse_include(filename)
119         self._includes.add(include)
120
121     # Private
122
123     def _find_include(self, include):
124         searchdirs = self._includepaths[:]
125         for path in _xdg_data_dirs:
126             searchdirs.append(os.path.join(path, GIR_SUFFIX))
127         searchdirs.append(GIR_DIR)
128
129         girname = '%s-%s.gir' % (include.name, include.version)
130         for d in searchdirs:
131             path = os.path.join(d, girname)
132             if os.path.exists(path):
133                 return path
134         sys.stderr.write("Couldn't find include %r (search path: %r)\n"\
135                          % (girname, searchdirs))
136         sys.exit(1)
137
138     def _parse_include(self, filename):
139         parser = self._cachestore.load(filename)
140         if parser is None:
141             parser = GIRParser()
142             parser.set_include_parsing(True)
143             parser.parse(filename)
144             self._cachestore.store(filename, parser)
145
146         for include in parser.get_includes():
147             self.register_include(include)
148
149         for pkg in parser.get_pkgconfig_packages():
150             self._pkg_config_packages.add(pkg)
151         namespace = parser.get_namespace()
152         nsname = namespace.name
153         for node in namespace.nodes:
154             if isinstance(node, Alias):
155                 self._names.aliases[node.name] = (nsname, node)
156             elif isinstance(node, (GLibBoxed, Interface, Class)):
157                 self._names.type_names[node.type_name] = (nsname, node)
158             giname = '%s.%s' % (nsname, node.name)
159             self._names.names[giname] = (nsname, node)
160             if hasattr(node, 'ctype'):
161                 self._names.ctypes[node.ctype] = (nsname, node)
162             elif hasattr(node, 'symbol'):
163                 self._names.ctypes[node.symbol] = (nsname, node)
164
165     def _add_node(self, node):
166         if node is None:
167             return
168         if node.name.startswith('_'):
169             return
170         self._namespace.nodes.append(node)
171         self._names.names[node.name] = (None, node)
172
173     def _strip_namespace_func(self, name):
174         prefix = self._namespace.name.lower() + '_'
175         if name.lower().startswith(prefix):
176             name = name[len(prefix):]
177         else:
178             prefix = to_underscores(self._namespace.name).lower() + '_'
179             if name.lower().startswith(prefix):
180                 name = name[len(prefix):]
181         return self.remove_prefix(name, isfunction=True)
182
183     def remove_prefix(self, name, isfunction=False):
184         # when --strip-prefix=g:
185         #   GHashTable -> HashTable
186         #   g_hash_table_new -> hash_table_new
187         stripped = False
188         prefix = self._strip_prefix.lower()
189         
190         if isfunction and '_' in name:
191             prefix += '_'
192         if len(name) > len(prefix) and name.lower().startswith(prefix):
193             name = name[len(prefix):]
194             stripped = True
195
196         while name.startswith('_'):
197             name = name[1:]
198
199         if (stripped and self._strip_suffix and 
200             len(name) > len(self._strip_suffix) and
201             name.endswith(self._strip_suffix)
202             name = name[:-1*len(self._strip_suffix)]
203             
204         return name
205
206     def _traverse_one(self, symbol, stype=None):
207         assert isinstance(symbol, SourceSymbol), symbol
208
209         if stype is None:
210             stype = symbol.type
211         if stype == CSYMBOL_TYPE_FUNCTION:
212             return self._create_function(symbol)
213         elif stype == CSYMBOL_TYPE_TYPEDEF:
214             return self._create_typedef(symbol)
215         elif stype == CSYMBOL_TYPE_STRUCT:
216             return self._create_struct(symbol)
217         elif stype == CSYMBOL_TYPE_ENUM:
218             return self._create_enum(symbol)
219         elif stype == CSYMBOL_TYPE_OBJECT:
220             return self._create_object(symbol)
221         elif stype == CSYMBOL_TYPE_MEMBER:
222             return self._create_member(symbol)
223         elif stype == CSYMBOL_TYPE_UNION:
224             return self._create_union(symbol)
225         elif stype == CSYMBOL_TYPE_CONST:
226             return self._create_const(symbol)
227         else:
228             raise NotImplementedError(
229                 'Transformer: unhandled symbol: %r' % (symbol, ))
230
231     def _enum_common_prefix(self, symbol):
232         def common_prefix(a, b):
233             commonparts = []
234             for aword, bword in zip(a.split('_'), b.split('_')):
235                 if aword != bword:
236                     return '_'.join(commonparts) + '_'
237                 commonparts.append(aword)
238             return min(a, b)
239
240         # Nothing less than 2 has a common prefix
241         if len(list(symbol.base_type.child_list)) < 2:
242             return None
243         prefix = None
244         for child in symbol.base_type.child_list:
245             if prefix is None:
246                 prefix = child.ident
247             else:
248                 prefix = common_prefix(prefix, child.ident)
249                 if prefix == '':
250                     return None
251         return prefix
252
253     def _create_enum(self, symbol):
254         prefix = self._enum_common_prefix(symbol)
255         if prefix:
256             prefixlen = len(prefix)
257         else:
258             prefixlen = 0
259         members = []
260         for child in symbol.base_type.child_list:
261             if prefixlen > 0:
262                 name = child.ident[prefixlen:]
263             else:
264                 # Ok, the enum members don't have a consistent prefix
265                 # among them, so let's just remove the global namespace
266                 # prefix.
267                 name = self.remove_prefix(child.ident)
268             members.append(Member(name.lower(),
269                                   child.const_int,
270                                   child.ident))
271
272         enum_name = self.remove_prefix(symbol.ident)
273         if symbol.base_type.is_bitfield:
274             klass = Bitfield
275         else:
276             klass = Enum
277         node = klass(enum_name, symbol.ident, members)
278         self._names.type_names[symbol.ident] = (None, node)
279         return node
280
281     def _create_object(self, symbol):
282         return Member(symbol.ident, symbol.base_type.name,
283                       symbol.ident)
284
285     def _type_is_callback(self, type):
286         if isinstance(type, Callback):
287             return True
288         node = self._names.names.get(type.name)
289         if node and isinstance(node[1], Callback):
290             return True
291         return False
292
293     def _handle_closure(self, param, closure_idx, closure_param):
294         if (closure_param.type.name == 'any' and
295             closure_param.name.endswith('data')):
296             param.closure_name = closure_param.name
297             param.closure_index = closure_idx
298             return True
299         return False
300
301     def _handle_destroy(self, param, destroy_idx, destroy_param):
302         if (destroy_param.type.name == 'GLib.DestroyNotify' or
303             destroy_param.type.ctype == 'GDestroyNotify'):
304             param.destroy_name = destroy_param.name
305             param.destroy_index = destroy_idx
306             return True
307         return False
308
309     def _augment_callback_params(self, params):
310         for i, param in enumerate(params):
311             if not self._type_is_callback(param.type):
312                 continue
313
314             # set a default scope
315             if param.scope is None:
316                 param.scope = 'call'
317
318             # j is the index where we look for closure/destroy to
319             # group with the callback param
320             j = i + 1
321             if j == len(params):
322                 continue # no more args -> nothing to group
323             # look at the param directly following for either a
324             # closure or a destroy; only one of these will fire
325             had_closure = self._handle_closure(param, j, params[j])
326             had_destroy = self._handle_destroy(param, j, params[j])
327             j += 1
328             # are we out of params, or did we find neither?
329             if j == len(params) or (not had_closure and not had_destroy):
330                 continue
331             # we found either a closure or a destroy; check the
332             # parameter following for the other
333             if not had_closure:
334                 self._handle_closure(param, j, params[j])
335             if not had_destroy:
336                 self._handle_destroy(param, j, params[j])
337
338     def _create_function(self, symbol):
339         parameters = list(self._create_parameters(symbol.base_type))
340         return_ = self._create_return(symbol.base_type.base_type)
341         self._augment_callback_params(parameters)
342         name = self._strip_namespace_func(symbol.ident)
343         func = Function(name, return_, parameters, symbol.ident)
344         return func
345
346     def _create_source_type(self, source_type):
347         if source_type is None:
348             return 'None'
349         if source_type.type == CTYPE_VOID:
350             value = 'void'
351         elif source_type.type == CTYPE_BASIC_TYPE:
352             value = source_type.name
353             if source_type.base_type:
354                 value += ' ' + self._create_source_type(source_type.base_type)
355         elif source_type.type == CTYPE_TYPEDEF:
356             value = source_type.name
357         elif source_type.type == CTYPE_ARRAY:
358             return self._create_source_type(source_type.base_type)
359         elif source_type.type == CTYPE_POINTER:
360             value = self._create_source_type(source_type.base_type) + '*'
361         elif source_type.type == CTYPE_STRUCT:
362             value = source_type.name
363         else:
364             value = 'any'
365         return value
366
367     def _create_parameters(self, base_type):
368
369         # warn if we see annotations for unknown parameters
370         param_names = set(child.ident for child in base_type.child_list)
371         for child in base_type.child_list:
372             yield self._create_parameter(child)
373
374     def _create_member(self, symbol):
375         source_type = symbol.base_type
376         if (source_type.type == CTYPE_POINTER and
377             symbol.base_type.base_type.type == CTYPE_FUNCTION):
378             try:
379                 node = self._create_callback(symbol)
380             except VaListSkipError:
381                 #this handles va_list members, and converts them
382                 #to unwritable, unreadable void*
383                 ftype = Type("any", "void*")
384                 ftype = self.resolve_param_type(ftype)
385                 node = Field(symbol.ident, ftype, ftype.name,
386                          readable=False, writable=False, bits=symbol.const_int)
387
388
389         elif source_type.type == CTYPE_STRUCT and source_type.name is None:
390             node = self._create_struct(symbol, anonymous=True)
391         elif source_type.type == CTYPE_UNION and source_type.name is None:
392             node = self._create_union(symbol, anonymous=True)
393         else:
394             # Special handling for fields; we don't have annotations on them
395             # to apply later, yet.
396             if source_type.type == CTYPE_ARRAY:
397                 ctype = self._create_source_type(source_type)
398                 canonical_ctype = self._canonicalize_ctype(ctype)
399                 if canonical_ctype[-1] == '*':
400                     derefed_name = canonical_ctype[:-1]
401                 else:
402                     derefed_name = canonical_ctype
403                 derefed_name = self.resolve_param_type(derefed_name)
404                 ftype = Array(ctype, self.parse_ctype(derefed_name))
405                 child_list = list(symbol.base_type.child_list)
406                 ftype.zeroterminated = False
407                 if child_list:
408                     ftype.size = '%d' % (child_list[0].const_int, )
409             else:
410                 ftype = self._create_type(symbol.base_type,
411                                           is_param=False, is_retval=False)
412             ftype = self.resolve_param_type(ftype)
413             # Fields are assumed to be read-write
414             # (except for Objects, see also glibtransformer.py)
415             node = Field(symbol.ident, ftype, ftype.name,
416                          readable=True, writable=True, bits=symbol.const_int)
417         return node
418
419     def _create_typedef(self, symbol):
420         ctype = symbol.base_type.type
421         if (ctype == CTYPE_POINTER and
422             symbol.base_type.base_type.type == CTYPE_FUNCTION):
423             node = self._create_typedef_callback(symbol)
424         if (ctype ==  CTYPE_FUNCTION):
425             node = self._create_typedef_callback(symbol)
426         elif (ctype == CTYPE_POINTER and
427             symbol.base_type.base_type.type == CTYPE_STRUCT):
428             node = self._create_typedef_struct(symbol, disguised=True)
429         elif ctype == CTYPE_STRUCT:
430             node = self._create_typedef_struct(symbol)
431         elif ctype == CTYPE_UNION:
432             node = self._create_typedef_union(symbol)
433         elif ctype == CTYPE_ENUM:
434             return self._create_enum(symbol)
435         elif ctype in (CTYPE_TYPEDEF,
436                        CTYPE_POINTER,
437                        CTYPE_BASIC_TYPE,
438                        CTYPE_VOID):
439             name = self.remove_prefix(symbol.ident)
440             if symbol.base_type.name:
441                 target = self.remove_prefix(symbol.base_type.name)
442             elif (ctype == CTYPE_POINTER and
443                 symbol.base_type.base_type.name):
444                 target = self.remove_prefix(
445                     symbol.base_type.base_type.name) + '*'
446             elif (ctype == CTYPE_POINTER and
447                 symbol.base_type.base_type.type == CTYPE_VOID):
448                 target = 'any'
449             else:
450                 target = 'none'
451             if name in type_names:
452                 return None
453             return Alias(name, target, ctype=symbol.ident)
454         else:
455             raise NotImplementedError(
456                 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
457         return node
458
459     def _canonicalize_ctype(self, ctype):
460         # First look up the ctype including any pointers;
461         # a few type names like 'char*' have their own aliases
462         # and we need pointer information for those.
463         firstpass = type_name_from_ctype(ctype)
464
465         # If we have a particular alias for this, skip deep
466         # canonicalization to prevent changing
467         # e.g. char* -> int8*
468         if firstpass != ctype:
469             return firstpass
470
471         # We're also done if the type is already a fundamental
472         # known type, or there are no pointers.
473         if ctype in type_names or not firstpass.endswith('*'):
474             return firstpass
475
476         # We have a pointer type.
477         # Strip the end pointer, canonicalize our base type
478         base = firstpass[:-1]
479         canonical_base = self._canonicalize_ctype(base)
480
481         # Append the pointer again
482         canonical = canonical_base + '*'
483
484         return canonical
485
486     def parse_ctype(self, ctype, is_member=False):
487         canonical = self._canonicalize_ctype(ctype)
488
489         # Remove all pointers - we require standard calling
490         # conventions.  For example, an 'int' is always passed by
491         # value (unless it's out or inout).
492         derefed_typename = canonical.replace('*', '')
493
494         # Preserve "pointerness" of struct/union members
495         if (is_member and canonical.endswith('*') and
496             derefed_typename in BASIC_GIR_TYPES):
497             return 'any'
498         else:
499             return derefed_typename
500
501     def _create_type(self, source_type, is_param, is_retval):
502         ctype = self._create_source_type(source_type)
503         if ctype.startswith('va_list'):
504             raise VaListSkipError()
505         # FIXME: FILE* should not be skipped, it should be handled
506         #        properly instead
507         elif ctype == 'FILE*':
508             raise SkipError
509
510         is_member = not (is_param or is_retval)
511         # Here we handle basic type parsing; most of the heavy lifting
512         # and inference comes in annotationparser.py when we merge
513         # in annotation data.
514         derefed_name = self.parse_ctype(ctype, is_member)
515         rettype = Type(derefed_name, ctype)
516         rettype.canonical = self._canonicalize_ctype(ctype)
517         derefed_ctype = ctype.replace('*', '')
518         rettype.derefed_canonical = self._canonicalize_ctype(derefed_ctype)
519
520         canontype = type_name_from_ctype(ctype)
521         # Is it a const char * or a const gpointer?
522         if ((canontype == TYPE_STRING or source_type.type == CTYPE_POINTER) and
523             (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST)):
524             rettype.is_const = True
525         return rettype
526
527     def _create_parameter(self, symbol):
528         if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
529             ptype = Varargs()
530         else:
531             ptype = self._create_type(symbol.base_type,
532                                       is_param=True, is_retval=False)
533             ptype = self.resolve_param_type(ptype)
534         return Parameter(symbol.ident, ptype)
535
536     def _create_return(self, source_type):
537         rtype = self._create_type(source_type,
538                                   is_param=False, is_retval=True)
539         rtype = self.resolve_param_type(rtype)
540         return_ = Return(rtype)
541         return return_
542
543     def _create_const(self, symbol):
544         # Don't create constants for non-public things
545         # http://bugzilla.gnome.org/show_bug.cgi?id=572790
546         if (symbol.source_filename is None or
547             not symbol.source_filename.endswith('.h')):
548             return None
549         name = self.remove_prefix(symbol.ident)
550         if symbol.const_string is not None:
551             type_name = 'utf8'
552             value = symbol.const_string
553         elif symbol.const_int is not None:
554             type_name = 'int'
555             value = symbol.const_int
556         elif symbol.const_double is not None:
557             type_name = 'double'
558             value = symbol.const_double
559         else:
560             raise AssertionError()
561
562         const = Constant(name, type_name, value)
563         return const
564
565     def _create_typedef_struct(self, symbol, disguised=False):
566         name = self.remove_prefix(symbol.ident)
567         struct = Struct(name, symbol.ident, disguised)
568         self._typedefs_ns[symbol.ident] = struct
569         self._create_struct(symbol)
570         return struct
571
572     def _create_typedef_union(self, symbol):
573         name = self.remove_prefix(symbol.ident)
574         union = Union(name, symbol.ident)
575         self._typedefs_ns[symbol.ident] = union
576         self._create_union(symbol)
577         return union
578
579     def _create_typedef_callback(self, symbol):
580         callback = self._create_callback(symbol)
581         self._typedefs_ns[callback.name] = callback
582         return callback
583
584     def _create_compound(self, klass, symbol, anonymous):
585         if symbol.ident is None:
586             # the compound is an anonymous member of another union or a struct
587             assert anonymous
588             compound = klass(None, None)
589         else:
590             compound = self._typedefs_ns.get(symbol.ident, None)
591
592         if compound is None:
593             # This is a bit of a hack; really we should try
594             # to resolve through the typedefs to find the real
595             # name
596             if symbol.ident.startswith('_'):
597                 name = symbol.ident[1:]
598                 compound = self._typedefs_ns.get(name, None)
599             else:
600                 name = symbol.ident
601             if compound is None:
602                 name = self.remove_prefix(name)
603                 compound = klass(name, symbol.ident)
604
605         for child in symbol.base_type.child_list:
606             field = self._traverse_one(child)
607             if field:
608                 compound.fields.append(field)
609
610         return compound
611
612     def _create_struct(self, symbol, anonymous=False):
613         return self._create_compound(Struct, symbol, anonymous)
614
615     def _create_union(self, symbol, anonymous=False):
616         return self._create_compound(Union, symbol, anonymous)
617
618     def _create_callback(self, symbol):
619         parameters = list(self._create_parameters(symbol.base_type.base_type))
620         retval = self._create_return(symbol.base_type.base_type.base_type)
621         ret_type = symbol.base_type.base_type.base_type
622         if not ret_type:
623             ret_type = symbol.base_type.base_type
624         retval = self._create_return(ret_type)
625
626         # Mark the 'user_data' arguments
627         for i, param in enumerate(parameters):
628             if (param.type.name == 'any' and
629                 param.name == 'user_data'):
630                 param.closure_index = i
631
632         if symbol.ident.find('_') > 0:
633             name = self.remove_prefix(symbol.ident, True)
634         else:
635             name = self.remove_prefix(symbol.ident)
636         callback = Callback(name, retval, parameters, symbol.ident)
637
638         return callback
639
640     def _typepair_to_str(self, item):
641         nsname, item = item
642         if nsname is None:
643             return item.name
644         return '%s.%s' % (nsname, item.name)
645
646     def _resolve_type_name_1(self, type_name, ctype, names):
647         # First look using the built-in names
648         if ctype:
649             try:
650                 return type_names[ctype]
651             except KeyError, e:
652                 pass
653         try:
654             return type_names[type_name]
655         except KeyError, e:
656             pass
657
658         if ctype:
659             ctype = ctype.replace('*', '')
660             resolved = names.ctypes.get(ctype)
661             if resolved:
662                 return self._typepair_to_str(resolved)
663         type_name = self.remove_prefix(type_name)
664         resolved = names.aliases.get(type_name)
665         if resolved:
666             return self._typepair_to_str(resolved)
667         resolved = names.names.get(type_name)
668         if resolved:
669             return self._typepair_to_str(resolved)
670         resolved = names.type_names.get(type_name)
671         if resolved:
672             return self._typepair_to_str(resolved)
673         raise KeyError("failed to find %r" % (type_name, ))
674
675     def resolve_type_name_full(self, type_name, ctype,
676                                names, allow_invalid=True):
677         try:
678             return self._resolve_type_name_1(type_name, ctype, names)
679         except KeyError, e:
680             try:
681                 return self._resolve_type_name_1(type_name, ctype, self._names)
682             except KeyError, e:
683                 if not allow_invalid:
684                     raise
685                 return type_name
686
687     def resolve_type_name(self, type_name, ctype=None):
688         try:
689             return self.resolve_type_name_full(type_name, ctype, self._names)
690         except KeyError, e:
691             return type_name
692
693     def gtypename_to_giname(self, gtname, names):
694         resolved = names.type_names.get(gtname)
695         if resolved:
696             return self._typepair_to_str(resolved)
697         resolved = self._names.type_names.get(gtname)
698         if resolved:
699             return self._typepair_to_str(resolved)
700         raise KeyError("Failed to resolve GType name: %r" % (gtname, ))
701
702     def ctype_of(self, obj):
703         if hasattr(obj, 'ctype'):
704             return obj.ctype
705         elif hasattr(obj, 'symbol'):
706             return obj.symbol
707         else:
708             return None
709
710     def resolve_param_type_full(self, ptype, names, **kwargs):
711         if isinstance(ptype, Node):
712             ptype.name = self.resolve_type_name_full(ptype.name,
713                                                      self.ctype_of(ptype),
714                                                      names, **kwargs)
715         elif isinstance(ptype, basestring):
716             return self.resolve_type_name_full(ptype, ptype, names, **kwargs)
717         else:
718             raise AssertionError("Unhandled param: %r" % (ptype, ))
719         return ptype
720
721     def resolve_param_type(self, ptype):
722         try:
723             return self.resolve_param_type_full(ptype, self._names)
724         except KeyError, e:
725             return ptype
726
727     def follow_aliases(self, type_name, names):
728         while True:
729             resolved = names.aliases.get(type_name)
730             if resolved:
731                 (ns, alias) = resolved
732                 type_name = alias.target
733             else:
734                 break
735         return type_name
736
737     def iter_enums(self):
738         for node in self._namespace.nodes:
739             if isinstance(node, Enum):
740                 yield node