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