Revert "[TYPEDEF] revert change that broke build"
[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, CTYPE_INVALID,
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 <<<<<<< HEAD
354             # skip adding invalid types.
355 =======
356             # share the const down the tree..
357 >>>>>>> 0abc74b... [TYPEDEF] revert change that broke build
358             if not source_type.base_type:
359                 return value
360             value_add = self._create_source_type(source_type.base_type)
361             if len(value_add):
362                 value += ' ' + value_add
363         elif source_type.type == CTYPE_TYPEDEF:
364             value = source_type.name
365         elif source_type.type == CTYPE_ARRAY:
366             return self._create_source_type(source_type.base_type)
367         elif source_type.type == CTYPE_POINTER:
368             value = self._create_source_type(source_type.base_type) + '*'
369 <<<<<<< HEAD
370 =======
371         elif source_type.type == CTYPE_STRUCT:
372             value = source_type.name
373 >>>>>>> 0abc74b... [TYPEDEF] revert change that broke build
374         elif source_type.type == CTYPE_INVALID:
375             #this happens if const is after the type..
376             value = ''
377         else:
378             value = 'any'
379         return value
380
381     def _create_parameters(self, base_type):
382
383         # warn if we see annotations for unknown parameters
384         param_names = set(child.ident for child in base_type.child_list)
385         for child in base_type.child_list:
386             yield self._create_parameter(child)
387
388     def _create_member(self, symbol):
389         source_type = symbol.base_type
390         if (source_type.type == CTYPE_POINTER and
391             symbol.base_type.base_type.type == CTYPE_FUNCTION):
392             try:
393                 node = self._create_callback(symbol)
394             except VaListSkipError:
395                 #this handles va_list members, and converts them
396                 #to unwritable, unreadable void*
397                 ftype = Type("any", "void*")
398                 ftype = self.resolve_param_type(ftype)
399                 node = Field(symbol.ident, ftype, ftype.name,
400                          readable=False, writable=False, bits=symbol.const_int)
401
402
403         elif source_type.type == CTYPE_STRUCT and source_type.name is None:
404             node = self._create_struct(symbol, anonymous=True)
405         elif source_type.type == CTYPE_UNION and source_type.name is None:
406             node = self._create_union(symbol, anonymous=True)
407         else:
408             # Special handling for fields; we don't have annotations on them
409             # to apply later, yet.
410             if source_type.type == CTYPE_ARRAY:
411                 ctype = self._create_source_type(source_type)
412                 canonical_ctype = self._canonicalize_ctype(ctype)
413                 if canonical_ctype[-1] == '*':
414                     derefed_name = canonical_ctype[:-1]
415                 else:
416                     derefed_name = canonical_ctype
417                 derefed_name = self.resolve_param_type(derefed_name)
418                 ftype = Array(ctype, self.parse_ctype(derefed_name))
419                 child_list = list(symbol.base_type.child_list)
420                 ftype.zeroterminated = False
421                 if child_list:
422                     ftype.size = '%d' % (child_list[0].const_int, )
423             else:
424                 ftype = self._create_type(symbol.base_type,
425                                           is_param=False, is_retval=False)
426             ftype = self.resolve_param_type(ftype)
427             # Fields are assumed to be read-write
428             # (except for Objects, see also glibtransformer.py)
429             node = Field(symbol.ident, ftype, ftype.name,
430                          readable=True, writable=True, bits=symbol.const_int)
431         return node
432
433     def _create_typedef(self, symbol):
434         ctype = symbol.base_type.type
435         if (ctype == CTYPE_POINTER and
436             symbol.base_type.base_type.type == CTYPE_FUNCTION):
437             node = self._create_typedef_callback(symbol)
438 #        if (ctype ==  CTYPE_FUNCTION):
439 #            node = self._create_typedef_callback(symbol)
440         elif (ctype == CTYPE_POINTER and
441             symbol.base_type.base_type.type == CTYPE_STRUCT):
442             node = self._create_typedef_struct(symbol, disguised=True)
443         elif ctype == CTYPE_STRUCT:
444             node = self._create_typedef_struct(symbol)
445         elif ctype == CTYPE_UNION:
446             node = self._create_typedef_union(symbol)
447         elif ctype == CTYPE_ENUM:
448             return self._create_enum(symbol)
449         elif ctype in (CTYPE_TYPEDEF,
450                        CTYPE_POINTER,
451                        CTYPE_BASIC_TYPE,
452                        CTYPE_VOID):
453             name = self.remove_prefix(symbol.ident)
454             if symbol.base_type.name:
455                 target = self.remove_prefix(symbol.base_type.name)
456             elif (ctype == CTYPE_POINTER and
457                 symbol.base_type.base_type.name):
458                 target = self.remove_prefix(
459                     symbol.base_type.base_type.name) + '*'
460             elif (ctype == CTYPE_POINTER and
461                 symbol.base_type.base_type.type == CTYPE_VOID):
462                 target = 'any'
463             else:
464                 target = 'none'
465             if name in type_names:
466                 return None
467             return Alias(name, target, ctype=symbol.ident)
468         else:
469             raise NotImplementedError(
470                 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
471         return node
472
473     def _canonicalize_ctype(self, ctype):
474         # First look up the ctype including any pointers;
475         # a few type names like 'char*' have their own aliases
476         # and we need pointer information for those.
477         firstpass = type_name_from_ctype(ctype)
478
479         # If we have a particular alias for this, skip deep
480         # canonicalization to prevent changing
481         # e.g. char* -> int8*
482         if firstpass != ctype:
483             return firstpass
484
485         # We're also done if the type is already a fundamental
486         # known type, or there are no pointers.
487         if ctype in type_names or not firstpass.endswith('*'):
488             return firstpass
489
490         # We have a pointer type.
491         # Strip the end pointer, canonicalize our base type
492         base = firstpass[:-1]
493         canonical_base = self._canonicalize_ctype(base)
494
495         # Append the pointer again
496         canonical = canonical_base + '*'
497
498         return canonical
499
500     def parse_ctype(self, ctype, is_member=False):
501         canonical = self._canonicalize_ctype(ctype)
502
503         # Remove all pointers - we require standard calling
504         # conventions.  For example, an 'int' is always passed by
505         # value (unless it's out or inout).
506         derefed_typename = canonical.replace('*', '')
507
508         # Preserve "pointerness" of struct/union members
509         if (is_member and canonical.endswith('*') and
510             derefed_typename in BASIC_GIR_TYPES):
511             return 'any'
512         else:
513             return derefed_typename
514
515     def _create_type(self, source_type, is_param, is_retval):
516         ctype = self._create_source_type(source_type)
517         if ctype.startswith('va_list'):
518             raise VaListSkipError()
519         # FIXME: FILE* should not be skipped, it should be handled
520         #        properly instead
521         elif ctype == 'FILE*':
522             raise SkipError
523
524         is_member = not (is_param or is_retval)
525         # Here we handle basic type parsing; most of the heavy lifting
526         # and inference comes in annotationparser.py when we merge
527         # in annotation data.
528         derefed_name = self.parse_ctype(ctype, is_member)
529         rettype = Type(derefed_name, ctype)
530         rettype.canonical = self._canonicalize_ctype(ctype)
531         derefed_ctype = ctype.replace('*', '')
532         rettype.derefed_canonical = self._canonicalize_ctype(derefed_ctype)
533
534         canontype = type_name_from_ctype(ctype)
535         # Is it a const char * or a const gpointer?
536         if ((canontype == TYPE_STRING or source_type.type == CTYPE_POINTER) and
537             (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST)):
538             rettype.is_const = True
539         return rettype
540
541     def _create_parameter(self, symbol):
542         if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
543             ptype = Varargs()
544         else:
545             ptype = self._create_type(symbol.base_type,
546                                       is_param=True, is_retval=False)
547             ptype = self.resolve_param_type(ptype)
548         return Parameter(symbol.ident, ptype)
549
550     def _create_return(self, source_type):
551         rtype = self._create_type(source_type,
552                                   is_param=False, is_retval=True)
553         rtype = self.resolve_param_type(rtype)
554         return_ = Return(rtype)
555         return return_
556
557     def _create_const(self, symbol):
558         # Don't create constants for non-public things
559         # http://bugzilla.gnome.org/show_bug.cgi?id=572790
560         if (symbol.source_filename is None or
561             not symbol.source_filename.endswith('.h')):
562             return None
563         name = self.remove_prefix(symbol.ident)
564         if symbol.const_string is not None:
565             type_name = 'utf8'
566             value = symbol.const_string
567         elif symbol.const_int is not None:
568             type_name = 'int'
569             value = symbol.const_int
570         elif symbol.const_double is not None:
571             type_name = 'double'
572             value = symbol.const_double
573         else:
574             raise AssertionError()
575
576         const = Constant(name, type_name, value)
577         return const
578
579     def _create_typedef_struct(self, symbol, disguised=False):
580         name = self.remove_prefix(symbol.ident)
581         struct = Struct(name, symbol.ident, disguised)
582         self._typedefs_ns[symbol.ident] = struct
583         self._create_struct(symbol)
584         return struct
585
586     def _create_typedef_union(self, symbol):
587         name = self.remove_prefix(symbol.ident)
588         union = Union(name, symbol.ident)
589         self._typedefs_ns[symbol.ident] = union
590         self._create_union(symbol)
591         return union
592
593     def _create_typedef_callback(self, symbol):
594         callback = self._create_callback(symbol)
595         self._typedefs_ns[callback.name] = callback
596         return callback
597
598     def _create_compound(self, klass, symbol, anonymous):
599         if symbol.ident is None:
600             # the compound is an anonymous member of another union or a struct
601             assert anonymous
602             compound = klass(None, None)
603         else:
604             compound = self._typedefs_ns.get(symbol.ident, None)
605
606         if compound is None:
607             # This is a bit of a hack; really we should try
608             # to resolve through the typedefs to find the real
609             # name
610             if symbol.ident.startswith('_'):
611                 name = symbol.ident[1:]
612                 compound = self._typedefs_ns.get(name, None)
613             else:
614                 name = symbol.ident
615             if compound is None:
616                 name = self.remove_prefix(name)
617                 compound = klass(name, symbol.ident)
618
619         for child in symbol.base_type.child_list:
620             field = self._traverse_one(child)
621             if field:
622                 compound.fields.append(field)
623
624         return compound
625
626     def _create_struct(self, symbol, anonymous=False):
627         return self._create_compound(Struct, symbol, anonymous)
628
629     def _create_union(self, symbol, anonymous=False):
630         return self._create_compound(Union, symbol, anonymous)
631
632     def _create_callback(self, symbol):
633         parameters = list(self._create_parameters(symbol.base_type.base_type))
634         retval = self._create_return(symbol.base_type.base_type.base_type)
635         ret_type = symbol.base_type.base_type.base_type
636         if not ret_type:
637             ret_type = symbol.base_type.base_type
638         retval = self._create_return(ret_type)
639
640         # Mark the 'user_data' arguments
641         for i, param in enumerate(parameters):
642             if (param.type.name == 'any' and
643                 param.name == 'user_data'):
644                 param.closure_index = i
645
646         if symbol.ident.find('_') > 0:
647             name = self.remove_prefix(symbol.ident, True)
648         else:
649             name = self.remove_prefix(symbol.ident)
650         callback = Callback(name, retval, parameters, symbol.ident)
651
652         return callback
653
654     def _typepair_to_str(self, item):
655         nsname, item = item
656         if nsname is None:
657             return item.name
658         return '%s.%s' % (nsname, item.name)
659
660     def _resolve_type_name_1(self, type_name, ctype, names):
661         # First look using the built-in names
662         if ctype:
663             try:
664                 return type_names[ctype]
665             except KeyError, e:
666                 pass
667         try:
668             return type_names[type_name]
669         except KeyError, e:
670             pass
671
672         if ctype:
673             ctype = ctype.replace('*', '')
674             resolved = names.ctypes.get(ctype)
675             if resolved:
676                 return self._typepair_to_str(resolved)
677         type_name = self.remove_prefix(type_name)
678         resolved = names.aliases.get(type_name)
679         if resolved:
680             return self._typepair_to_str(resolved)
681         resolved = names.names.get(type_name)
682         if resolved:
683             return self._typepair_to_str(resolved)
684         resolved = names.type_names.get(type_name)
685         if resolved:
686             return self._typepair_to_str(resolved)
687         raise KeyError("failed to find %r" % (type_name, ))
688
689     def resolve_type_name_full(self, type_name, ctype,
690                                names, allow_invalid=True):
691         try:
692             return self._resolve_type_name_1(type_name, ctype, names)
693         except KeyError, e:
694             try:
695                 return self._resolve_type_name_1(type_name, ctype, self._names)
696             except KeyError, e:
697                 if not allow_invalid:
698                     raise
699                 return type_name
700
701     def resolve_type_name(self, type_name, ctype=None):
702         try:
703             return self.resolve_type_name_full(type_name, ctype, self._names)
704         except KeyError, e:
705             return type_name
706
707     def gtypename_to_giname(self, gtname, names):
708         resolved = names.type_names.get(gtname)
709         if resolved:
710             return self._typepair_to_str(resolved)
711         resolved = self._names.type_names.get(gtname)
712         if resolved:
713             return self._typepair_to_str(resolved)
714         raise KeyError("Failed to resolve GType name: %r" % (gtname, ))
715
716     def ctype_of(self, obj):
717         if hasattr(obj, 'ctype'):
718             return obj.ctype
719         elif hasattr(obj, 'symbol'):
720             return obj.symbol
721         else:
722             return None
723
724     def resolve_param_type_full(self, ptype, names, **kwargs):
725         if isinstance(ptype, Node):
726             ptype.name = self.resolve_type_name_full(ptype.name,
727                                                      self.ctype_of(ptype),
728                                                      names, **kwargs)
729         elif isinstance(ptype, basestring):
730             return self.resolve_type_name_full(ptype, ptype, names, **kwargs)
731         else:
732             raise AssertionError("Unhandled param: %r" % (ptype, ))
733         return ptype
734
735     def resolve_param_type(self, ptype):
736         try:
737             return self.resolve_param_type_full(ptype, self._names)
738         except KeyError, e:
739             return ptype
740
741     def follow_aliases(self, type_name, names):
742         while True:
743             resolved = names.aliases.get(type_name)
744             if resolved:
745                 (ns, alias) = resolved
746                 type_name = alias.target
747             else:
748                 break
749         return type_name
750
751     def iter_enums(self):
752         for node in self._namespace.nodes:
753             if isinstance(node, Enum):
754                 yield node