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