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