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