Write out and parse full GObject property information (readable, writable, etc)
[gnome.gobject-introspection] / giscanner / glibtransformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program 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
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
19 #
20
21 import os
22 import re
23 import ctypes
24 from ctypes.util import find_library
25
26 from . import cgobject
27 from .ast import (Callback, Enum, Function, Member, Namespace, Parameter,
28                   Sequence, Property, Return, Struct, Type, Alias,
29                   Union, type_name_from_ctype)
30 from .transformer import Names
31 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
32                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
33                       GLibBoxedUnion, GLibBoxedOther, type_names)
34 from .utils import extract_libtool, to_underscores
35
36
37 SYMBOL_BLACKLIST = [
38     # These ones break GError conventions
39     'g_simple_async_result_new_from_error',
40     'g_simple_async_result_set_from_error',
41     'g_simple_async_result_propagate_error',
42     'g_simple_async_result_report_error_in_idle',
43     'gtk_print_operation_get_error',
44 ]
45
46 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
47                            [r'\w+_marshal_[A-Z]+__', ]]
48
49
50 class Unresolved(object):
51
52     def __init__(self, target):
53         self.target = target
54
55
56 class UnknownTypeError(Exception):
57     pass
58
59
60 class GLibTransformer(object):
61
62     def __init__(self, transformer, noclosure=False):
63         self._transformer = transformer
64         self._namespace_name = None
65         self._names = Names()
66         self._uscore_type_names = {}
67         self._libraries = []
68         self._failed_types = {}
69         self._boxed_types = {}
70         self._private_internal_types = {}
71         self._noclosure = noclosure
72         self._validating = False
73
74     # Public API
75
76     def add_library(self, libname):
77         # For testing mainly.
78         libtool_libname = 'lib' + libname + '.la'
79         if os.path.exists(libtool_libname):
80             found_libname = extract_libtool(libtool_libname)
81         elif libname.endswith('.la'):
82             found_libname = extract_libtool(libname)
83         else:
84             found_libname = find_library(libname)
85         if not found_libname:
86             raise ValueError("Failed to find library: %r" % (libname, ))
87         self._libraries.append(ctypes.cdll.LoadLibrary(found_libname))
88
89     def _print_statistics(self):
90         nodes = list(self._names.names.itervalues())
91
92         def count_type(otype):
93             return len([x for x in nodes
94                         if isinstance(x[1], otype)])
95         objectcount = count_type(GLibObject)
96         ifacecount = count_type(GLibInterface)
97         enumcount = count_type(GLibEnum)
98         print " %d nodes; %d objects, %d interfaces, %d enumsr" \
99             % (len(nodes), objectcount, ifacecount, enumcount)
100
101     def parse(self):
102         namespace = self._transformer.parse()
103         self._namespace_name = namespace.name
104
105         # First pass: parsing
106         for node in namespace.nodes:
107             self._parse_node(node)
108
109         # Introspection is done from within parsing
110
111         # Second pass: pair boxed structures
112         for boxed in self._boxed_types.itervalues():
113             self._pair_boxed_type(boxed)
114         # Third pass: delete class structures, resolve
115         # all types we now know about
116         nodes = list(self._names.names.itervalues())
117         for (ns, node) in nodes:
118             try:
119                 self._resolve_node(node)
120             except KeyError, e:
121                 print "WARNING: DELETING node %s: %s" % (node.name, e)
122                 self._remove_attribute(node.name)
123             # associate GtkButtonClass with GtkButton
124             if isinstance(node, Struct):
125                 self._pair_class_struct(node)
126         for (ns, alias) in self._names.aliases.itervalues():
127             self._resolve_alias(alias)
128
129         self._print_statistics()
130         # Fourth pass: ensure all types are known
131         if not self._noclosure:
132             self._validate(nodes)
133
134         # Create a new namespace with what we found
135         namespace = Namespace(namespace.name)
136         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
137         for (ns, x) in self._names.names.itervalues():
138             namespace.nodes.append(x)
139         return namespace
140
141     # Private
142
143     def _add_attribute(self, node, replace=False):
144         node_name = node.name
145         if (not replace) and node_name in self._names.names:
146             return
147         self._names.names[node_name] = (None, node)
148
149     def _remove_attribute(self, name):
150         del self._names.names[name]
151
152     def _get_attribute(self, name):
153         node = self._names.names.get(name)
154         if node:
155             return node[1]
156         return None
157
158     def _register_internal_type(self, type_name, node):
159         self._names.type_names[type_name] = (None, node)
160         self._uscore_type_names[to_underscores(type_name).lower()] = node
161         # Besides the straight underscore conversion, we also try
162         # removing the underscores from the namespace as a possible C
163         # mapping; e.g. it's webkit_web_view, not web_kit_web_view
164         suffix = self._transformer.strip_namespace_object(type_name)
165         prefix = type_name[:-len(suffix)]
166         no_uscore_prefixed = (prefix + '_' + to_underscores(suffix)).lower()
167         self._uscore_type_names[no_uscore_prefixed] = node
168
169     # Helper functions
170
171     def _create_type(self, type_id):
172         ctype = cgobject.type_name(type_id)
173         type_name = type_name_from_ctype(ctype)
174         type_name = type_name.replace('*', '')
175         type_name = self._resolve_type_name(type_name)
176         return Type(type_name, ctype)
177
178     def _resolve_gtypename(self, gtype_name):
179         try:
180             return self._transformer.gtypename_to_giname(gtype_name,
181                                                          self._names)
182         except KeyError, e:
183             return Unresolved(gtype_name)
184
185     def _create_gobject(self, node):
186         type_name = 'G' + node.name
187         if type_name == 'GObject':
188             parent_gitype = None
189             symbol = 'intern'
190         else:
191             type_id = cgobject.type_from_name(type_name)
192             parent_type_name = cgobject.type_name(
193                 cgobject.type_parent(type_id))
194             parent_gitype = self._resolve_gtypename(parent_type_name)
195             symbol = to_underscores(type_name).lower() + '_get_type'
196         node = GLibObject(node.name, parent_gitype, type_name, symbol)
197         type_id = cgobject.TYPE_OBJECT
198         self._introspect_properties(node, type_id)
199         self._introspect_signals(node, type_id)
200         self._add_attribute(node)
201         self._register_internal_type(type_name, node)
202
203     # Parser
204
205     def _parse_node(self, node):
206         if isinstance(node, Enum):
207             self._parse_enum(node)
208         elif isinstance(node, Function):
209             self._parse_function(node)
210         elif isinstance(node, Struct):
211             self._parse_struct(node)
212         elif isinstance(node, Callback):
213             self._parse_callback(node)
214         elif isinstance(node, Alias):
215             self._parse_alias(node)
216         elif isinstance(node, Member):
217             # FIXME: atk_misc_instance singletons
218             pass
219         elif isinstance(node, Union):
220             self._parse_union(node)
221         else:
222             print 'GLIB Transformer: Unhandled node:', node
223
224     def _parse_alias(self, alias):
225         self._names.aliases[alias.name] = (None, alias)
226
227     def _parse_enum(self, enum):
228         self._add_attribute(enum)
229
230     def _parse_function(self, func):
231         if func.symbol in SYMBOL_BLACKLIST:
232             return
233         for regexp in SYMBOL_BLACKLIST_RE:
234             if regexp.match(func.symbol):
235                 return
236         if self._parse_get_type_function(func):
237             return
238
239         self._add_attribute(func)
240
241     def _parse_get_type_function(self, func):
242         symbol = func.symbol
243         if not symbol.endswith('_get_type'):
244             return False
245         if self._namespace_name == 'GLib':
246             # No GObjects in GLib
247             return False
248         # GType *_get_type(void)
249         # This is a bit fishy, why do we need all these aliases?
250         if func.retval.type.name not in ['Type',
251                                          'GType',
252                                          'Object.Type',
253                                          'GObject.Type',
254                                          'GObject.GType']:
255             print ("Warning: *_get_type function returns '%r'"
256                    ", not GObject.Type") % (func.retval.type.name, )
257             return False
258         if func.parameters:
259             return False
260
261         if not self._libraries:
262             print "Warning: No libraries loaded, cannot call %s" % (symbol, )
263             return False
264
265         for library in self._libraries:
266             try:
267                 func = getattr(library, symbol)
268                 break
269             except AttributeError:
270                 continue
271         else:
272             print 'Warning: could not find symbol: %s' % symbol
273             name = symbol.replace('_get_type', '')
274             self._failed_types[name] = True
275             return False
276
277         func.restype = cgobject.GType
278         func.argtypes = []
279         type_id = func()
280         self._introspect_type(type_id, symbol)
281         return True
282
283     def _name_is_internal_gtype(self, giname):
284         try:
285             node = self._get_attribute(giname)
286             return isinstance(node, (GLibObject, GLibInterface,
287                                      GLibEnum, GLibFlags))
288         except KeyError, e:
289             return False
290
291     def _parse_method(self, func):
292         if not func.parameters:
293             return False
294         return self._parse_method_common(func, True)
295
296     def _parse_constructor(self, func):
297         return self._parse_method_common(func, False)
298
299     def _parse_method_common(self, func, is_method):
300         # Skip _get_type functions, we processed them
301         # already
302         if func.symbol.endswith('_get_type'):
303             return None
304         if self._namespace_name == 'GLib':
305             # No GObjects in GLib
306             return None
307
308         if not is_method:
309             target_arg = func.retval
310         else:
311             target_arg = func.parameters[0]
312         target_arg.type = self._resolve_param_type(target_arg.type)
313
314         if is_method:
315             # Methods require their first arg to be a known class
316             # Look at the original C type (before namespace stripping), without
317             # pointers: GtkButton -> gtk_button_, so we can figure out the
318             # method name
319             argtype = target_arg.type.ctype.replace('*', '')
320             name = self._transformer.strip_namespace_object(argtype)
321             name_uscore = to_underscores(name).lower()
322             name_offset = func.symbol.find(name_uscore)
323             if name_offset < 0:
324                 return None
325             prefix = func.symbol[:name_offset+len(name_uscore)]
326         else:
327             # Constructors must have _new
328             # Take everything before that as class name
329             new_idx = func.symbol.find('_new')
330             if new_idx < 0:
331                 return None
332             # Constructors don't return basic types
333             derefed = self._transformer.follow_aliases(target_arg.type.name,
334                                                        self._names)
335             if derefed in type_names:
336                 #print "NOTE: Rejecting constructor returning basic: %r" \
337                 #    % (func.symbol, )
338                 return None
339             prefix = func.symbol[:new_idx]
340
341         klass = None
342
343         def valid_matching_klass(tclass):
344             if tclass is None:
345                 return False
346             elif isinstance(klass, (GLibEnum, GLibFlags)):
347                 return False
348             elif not isinstance(tclass, (GLibObject, GLibBoxed,
349                                           GLibInterface)):
350                 return False
351             else:
352                 return True
353
354         # First look for an exact match;
355         klass = self._uscore_type_names.get(prefix)
356         # Now try searching for a prefix as a last resort
357         if klass is None or not valid_matching_klass(klass):
358             for key in self._uscore_type_names:
359                 klass = None
360                 if key.startswith(prefix):
361                     klass = self._uscore_type_names.get(key)
362                     if valid_matching_klass(klass):
363                         break
364         if klass is None:
365             #print "NOTE: No valid matching class for likely "+\
366             #    "method or constructor: %r" % (func.symbol, )
367             return None
368         # Enums can't have ctors or methods
369         if isinstance(klass, (GLibEnum, GLibFlags)):
370             return None
371
372         # The _uscore_type_names member holds the plain GLibBoxed
373         # object; we want to actually use the struct/record associated
374         if isinstance(klass, GLibBoxed):
375             name = self._transformer.strip_namespace_object(klass.type_name)
376             klass = self._get_attribute(name)
377
378         if not is_method:
379             # Interfaces can't have constructors, punt to global scope
380             if isinstance(klass, (GLibInterface, GLibBoxed)):
381                 #print "NOTE: Rejecting constructor for"+\
382                 #    " interface type: %r" % (func.symbol, )
383                 return None
384             # TODO - check that the return type is a subclass of the
385             # class from the prefix
386
387         self._remove_attribute(func.name)
388         # Strip namespace and object prefix: gtk_window_new -> new
389         func.name = func.symbol[len(prefix)+1:]
390         if is_method:
391             klass.methods.append(func)
392         else:
393             klass.constructors.append(func)
394         return func
395
396     def _parse_struct(self, struct):
397         # This is a hack, but GObject is a rather fundamental piece so.
398         internal_names = ["Object", 'InitiallyUnowned']
399         g_internal_names = ["G" + x for x in internal_names]
400         if (self._namespace_name == 'GObject' and
401             struct.name in internal_names):
402             self._create_gobject(struct)
403             return
404         elif struct.name in g_internal_names:
405             # Avoid duplicates
406             return
407         node = self._names.names.get(struct.name)
408         if node is None:
409             self._add_attribute(struct, replace=True)
410             return
411         (ns, node) = node
412         node.fields = struct.fields[:]
413
414     def _parse_union(self, union):
415         node = self._names.names.get(union.name)
416         if node is None:
417             self._add_attribute(union, replace=True)
418             return
419         (ns, node) = node
420         node.fields = union.fields[:]
421
422     def _parse_callback(self, callback):
423         self._add_attribute(callback)
424
425     def _strip_class_suffix(self, name):
426         if (name.endswith('Class') or
427             name.endswith('Iface')):
428             return name[:-5]
429         elif name.endswith('Interface'):
430             return name[:-9]
431         else:
432             return name
433
434     def _arg_is_failed(self, param):
435         ctype = self._transformer.ctype_of(param).replace('*', '')
436         uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
437         if uscored in self._failed_types:
438             print "Warning: failed type: %r" % (param, )
439             return True
440         return False
441
442     def _pair_class_struct(self, maybe_class):
443         name = self._strip_class_suffix(maybe_class.name)
444         if name == maybe_class.name:
445             return
446
447         if self._arg_is_failed(maybe_class):
448             print "WARNING: deleting no-type %r" % (maybe_class.name, )
449             del self._names.names[maybe_class.name]
450             return
451
452         name = self._resolve_type_name(name)
453         resolved = self._transformer.strip_namespace_object(name)
454         pair_class = self._get_attribute(resolved)
455         if pair_class and isinstance(pair_class,
456                                      (GLibObject, GLibInterface)):
457             for field in maybe_class.fields[1:]:
458                 pair_class.fields.append(field)
459             return
460         name = self._transformer.strip_namespace_object(maybe_class.name)
461         pair_class = self._get_attribute(name)
462         if pair_class and isinstance(pair_class,
463                                      (GLibObject, GLibInterface)):
464
465             del self._names.names[maybe_class.name]
466
467     # Introspection
468
469     def _introspect_type(self, type_id, symbol):
470         fundamental_type_id = cgobject.type_fundamental(type_id)
471         if (fundamental_type_id == cgobject.TYPE_ENUM or
472             fundamental_type_id == cgobject.TYPE_FLAGS):
473             self._introspect_enum(fundamental_type_id, type_id, symbol)
474         elif fundamental_type_id == cgobject.TYPE_OBJECT:
475             self._introspect_object(type_id, symbol)
476         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
477             self._introspect_interface(type_id, symbol)
478         elif fundamental_type_id == cgobject.TYPE_BOXED:
479             self._introspect_boxed(type_id, symbol)
480         elif fundamental_type_id == cgobject.TYPE_BOXED:
481             self._introspect_boxed(type_id, symbol)
482         elif fundamental_type_id == cgobject.TYPE_POINTER:
483             # FIXME: Should we do something about these?
484             #        GHashTable, GValue and a few other fundamentals are
485             #        covered here
486             return
487         else:
488             print 'unhandled GType: %s(%d)' % (cgobject.type_name(type_id),
489                                                type_id)
490
491     def _introspect_enum(self, ftype_id, type_id, symbol):
492         type_class = cgobject.type_class_ref(type_id)
493         if type_class is None:
494             return
495
496         members = []
497         for enum_value in type_class.get_values():
498             members.append(GLibEnumMember(enum_value.value_nick,
499                                           enum_value.value,
500                                           enum_value.value_name,
501                                           enum_value.value_nick))
502
503         klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
504         type_name = cgobject.type_name(type_id)
505         enum_name = self._transformer.strip_namespace_object(type_name)
506         node = klass(enum_name, type_name, members, symbol)
507         self._add_attribute(node, replace=True)
508         self._register_internal_type(type_name, node)
509
510     def _introspect_object(self, type_id, symbol):
511         type_name = cgobject.type_name(type_id)
512         # We handle this specially above; in 2.16 and below there
513         # was no g_object_get_type, for later versions we need
514         # to skip it
515         if type_name == 'GObject':
516             return
517         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
518         parent_gitype = self._resolve_gtypename(parent_type_name)
519         node = GLibObject(
520             self._transformer.strip_namespace_object(type_name),
521             parent_gitype,
522             type_name, symbol)
523         self._introspect_properties(node, type_id)
524         self._introspect_signals(node, type_id)
525         self._introspect_implemented_interfaces(node, type_id)
526         self._add_attribute(node, replace=True)
527         self._register_internal_type(type_name, node)
528
529     def _introspect_interface(self, type_id, symbol):
530         type_name = cgobject.type_name(type_id)
531         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
532         if parent_type_name == 'GInterface':
533             parent_gitype = None
534         else:
535             parent_gitype = self._resolve_gtypename(parent_type_name)
536         node = GLibInterface(
537             self._transformer.strip_namespace_object(type_name),
538             parent_gitype,
539             type_name, symbol)
540         self._introspect_properties(node, type_id)
541         self._introspect_signals(node, type_id)
542         # GtkFileChooserEmbed is an example of a private interface, we
543         # just filter them out
544         if symbol.startswith('_'):
545             print "NOTICE: Marking %s as internal type" % (type_name, )
546             self._private_internal_types[type_name] = node
547         else:
548             self._add_attribute(node, replace=True)
549             self._register_internal_type(type_name, node)
550
551     def _introspect_boxed(self, type_id, symbol):
552         type_name = cgobject.type_name(type_id)
553         # This one doesn't go in the main namespace; we associate it with
554         # the struct or union
555         node = GLibBoxed(type_name, symbol)
556         self._boxed_types[node.type_name] = node
557         self._register_internal_type(type_name, node)
558
559     def _introspect_implemented_interfaces(self, node, type_id):
560         fundamental_type_id = cgobject.type_fundamental(type_id)
561         if fundamental_type_id != cgobject.TYPE_OBJECT:
562             raise AssertionError
563         interfaces = cgobject.type_interfaces(type_id)
564         gt_interfaces = []
565         for interface_typeid in interfaces:
566             iname = cgobject.type_name(interface_typeid)
567             gitype = self._resolve_gtypename(iname)
568             gt_interfaces.append(gitype)
569         node.interfaces = gt_interfaces
570
571     def _introspect_properties(self, node, type_id):
572         fundamental_type_id = cgobject.type_fundamental(type_id)
573         if fundamental_type_id == cgobject.TYPE_OBJECT:
574             pspecs = cgobject.object_class_list_properties(type_id)
575         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
576             pspecs = cgobject.object_interface_list_properties(type_id)
577         else:
578             raise AssertionError
579
580         for pspec in pspecs:
581             if pspec.owner_type != type_id:
582                 continue
583             ctype = cgobject.type_name(pspec.value_type)
584             readable = (pspec.flags & 1) != 0
585             writable = (pspec.flags & 2) != 0
586             construct = (pspec.flags & 4) != 0
587             construct_only = (pspec.flags & 8) != 0
588             node.properties.append(Property(
589                 pspec.name,
590                 type_name_from_ctype(ctype),
591                 readable, writable, construct, construct_only,
592                 ctype,
593                 ))
594
595     def _introspect_signals(self, node, type_id):
596         for signal_info in cgobject.signal_list(type_id):
597             rtype = self._create_type(signal_info.return_type)
598             return_ = Return(rtype)
599             signal = GLibSignal(signal_info.signal_name, return_)
600             for i, parameter in enumerate(signal_info.get_params()):
601                 if i == 0:
602                     name = 'object'
603                 else:
604                     name = 'p%s' % (i-1, )
605                 ptype = self._create_type(parameter)
606                 param = Parameter(name, ptype)
607                 signal.parameters.append(param)
608             node.signals.append(signal)
609
610     # Resolver
611
612     def _resolve_type_name(self, type_name, ctype=None):
613         # Workaround glib bug #548689, to be included in 2.18.0
614         if type_name == "GParam":
615             type_name = "GObject.ParamSpec"
616
617         res = self._transformer.resolve_type_name_full
618         try:
619             return res(type_name, ctype, self._names)
620         except KeyError, e:
621             return self._transformer.resolve_type_name(type_name, ctype)
622
623     def _validate_type_name(self, name):
624         if name in type_names:
625             return True
626         if name.find('.') >= 0:
627             return True
628         if name in self._names.aliases:
629             return True
630         if name in self._names.names:
631             return True
632         return False
633
634     def _validate_type(self, ptype):
635         if isinstance(ptype, Sequence):
636             etype = ptype.element_type
637             if isinstance(etype, Sequence):
638                 return self._validate_type(etype)
639             return self._validate_type_name(etype)
640         return self._validate_type_name(ptype.name)
641
642     def _resolve_param_type_validate(self, ptype):
643         ptype = self._resolve_param_type(ptype)
644         if self._validating and not self._validate_type(ptype):
645             raise UnknownTypeError("Unknown type %r" % (ptype, ))
646         return ptype
647
648     def _resolve_param_type(self, ptype):
649         try:
650             return self._transformer.resolve_param_type_full(ptype,
651                                                              self._names)
652         except KeyError, e:
653             return self._transformer.resolve_param_type(ptype)
654         return ptype
655
656     def _resolve_node(self, node):
657         if isinstance(node, Function):
658             self._resolve_function_toplevel(node)
659
660         elif isinstance(node, Callback):
661             self._resolve_function(node)
662         elif isinstance(node, GLibObject):
663             self._resolve_glib_object(node)
664         elif isinstance(node, GLibInterface):
665             self._resolve_glib_interface(node)
666         elif isinstance(node, Struct):
667             self._resolve_struct(node)
668         elif isinstance(node, Union):
669             self._resolve_union(node)
670         elif isinstance(node, Alias):
671             self._resolve_alias(node)
672
673     def _resolve_function_toplevel(self, func):
674         newfunc = self._parse_constructor(func)
675         if not newfunc:
676             newfunc = self._parse_method(func)
677             if not newfunc:
678                 self._resolve_function(func)
679                 return
680         self._resolve_function(newfunc)
681
682     def _pair_boxed_type(self, boxed):
683         name = self._transformer.strip_namespace_object(boxed.type_name)
684         pair_node = self._get_attribute(name)
685         if not pair_node:
686             boxed_item = GLibBoxedOther(name, boxed.type_name,
687                                         boxed.get_type)
688         elif isinstance(pair_node, Struct):
689             boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
690                                          boxed.get_type)
691             boxed_item.fields = pair_node.fields
692         elif isinstance(pair_node, Union):
693             boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
694                                          boxed.get_type)
695             boxed_item.fields = pair_node.fields
696         else:
697             return False
698         self._add_attribute(boxed_item, replace=True)
699
700     def _resolve_struct(self, node):
701         for field in node.fields:
702             self._resolve_field(field)
703
704     def _resolve_union(self, node):
705         for field in node.fields:
706             self._resolve_field(field)
707
708     def _force_resolve(self, item, allow_unknown=False):
709         if isinstance(item, Unresolved):
710             if item.target in self._private_internal_types:
711                 return None
712             try:
713                 return self._transformer.gtypename_to_giname(item.target,
714                                                              self._names)
715             except KeyError, e:
716                 if allow_unknown:
717                     print "WARNING: Skipping unknown interface %s" % \
718                         (item.target, )
719                     return None
720                 else:
721                     raise
722         if item in self._private_internal_types:
723             return None
724         return item
725
726     def _resolve_glib_interface(self, node):
727         node.parent = self._force_resolve(node.parent)
728         self._resolve_methods(node.methods)
729         self._resolve_properties(node.properties)
730         self._resolve_signals(node.signals)
731
732     def _resolve_glib_object(self, node):
733         node.parent = self._force_resolve(node.parent)
734         node.interfaces = filter(None,
735             [self._force_resolve(x, allow_unknown=True)
736                                     for x in node.interfaces])
737         self._resolve_constructors(node.constructors)
738         self._resolve_methods(node.methods)
739         self._resolve_properties(node.properties)
740         self._resolve_signals(node.signals)
741
742     def _resolve_glib_boxed(self, node):
743         self._resolve_constructors(node.constructors)
744         self._resolve_methods(node.methods)
745
746     def _resolve_constructors(self, constructors):
747         for ctor in constructors:
748             self._resolve_function(ctor)
749
750     def _resolve_methods(self, methods):
751         for method in methods:
752             self._resolve_function(method)
753
754     def _resolve_signals(self, signals):
755         for signal in signals:
756             self._resolve_function(signal)
757
758     def _resolve_properties(self, properties):
759         for prop in properties:
760             self._resolve_property(prop)
761
762     def _resolve_property(self, prop):
763         prop.type = self._resolve_param_type(prop.type)
764
765     def _resolve_function(self, func):
766         self._resolve_parameters(func.parameters)
767         func.retval.type = self._resolve_param_type(func.retval.type)
768
769     def _resolve_parameters(self, parameters):
770         for parameter in parameters:
771             parameter.type = self._resolve_param_type(parameter.type)
772
773     def _resolve_field(self, field):
774         if isinstance(field, Callback):
775             self._resolve_function(field)
776             return
777         field.type = self._resolve_param_type(field.type)
778
779     def _resolve_alias(self, alias):
780         alias.target = self._resolve_type_name(alias.target, alias.target)
781
782     # Validation
783
784     def _validate(self, nodes):
785         nodes = list(self._names.names.itervalues())
786         i = 0
787         self._validating = True
788         while True:
789             initlen = len(nodes)
790
791             print "Type resolution; pass=%d" % (i, )
792             nodes = list(self._names.names.itervalues())
793             for node in nodes:
794                 try:
795                     self._resolve_node(node)
796                 except UnknownTypeError, e:
797                     print "WARNING: %s: Deleting %r" % (e, node)
798                     self._remove_attribute(node.name)
799             if len(nodes) == initlen:
800                 break
801             i += 1
802             self._print_statistics()
803         self._validating = False