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