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