6a0dee06845ffced4dcdc10e08fea64f10b3815c
[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 library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import os
22 import sys
23 import re
24 import tempfile
25 import shutil
26 import subprocess
27
28 from .ast import (Alias, Bitfield, Callback, Constant, Enum, Function, Member,
29                   Namespace, Parameter, Property, Record, Return, Type, Union,
30                   Field, VFunction, type_name_from_ctype,
31                   default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL)
32 from .transformer import Names
33 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
34                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
35                       GLibBoxedUnion, GLibBoxedOther, GLibRecord,
36                       type_names)
37 from .utils import to_underscores, to_underscores_noprefix
38
39 default_array_types['guchar*'] = TYPE_UINT8
40
41 # GParamFlags
42 G_PARAM_READABLE = 1 << 0
43 G_PARAM_WRITABLE = 1 << 1
44 G_PARAM_CONSTRUCT = 1 << 2
45 G_PARAM_CONSTRUCT_ONLY = 1 << 3
46 G_PARAM_LAX_VALIDATION = 1 << 4
47 G_PARAM_STATIC_NAME = 1 << 5
48 G_PARAM_STATIC_NICK = 1 << 6
49 G_PARAM_STATIC_BLURB = 1 << 7
50
51 SYMBOL_BLACKLIST = [
52     # These ones break GError conventions
53     'g_simple_async_result_new_from_error',
54     'g_simple_async_result_set_from_error',
55     'g_simple_async_result_propagate_error',
56     'g_simple_async_result_report_error_in_idle',
57     'gtk_print_operation_get_error',
58 ]
59
60 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
61                            [r'\w+_marshal_[A-Z]+__', ]]
62
63 GET_TYPE_OVERRIDES = {
64     # this is a special case, from glibtransforer.py:create_gobject
65     'intern': 'g_object_get_type',
66     # this is presumably a typo, should be fixed upstream
67     'g_gstring_get_type': 'g_string_get_type',
68     # this is historical cruft: there's a deprecated
69     #   #define gdk_window_get_type gdk_window_get_window_type
70     # upstream; this method can be renamed properly upstream once
71     # that deprecated alias is removed (in some future release)
72     'gdk_window_object_get_type': 'gdk_window_get_type',
73 }
74
75
76 class IntrospectionBinary(object):
77
78     def __init__(self, args, tmpdir=None):
79         self.args = args
80         if tmpdir is None:
81             self.tmpdir = tempfile.mkdtemp('', 'tmp-introspect')
82         else:
83             self.tmpdir = tmpdir
84
85
86 class Unresolved(object):
87
88     def __init__(self, target):
89         self.target = target
90
91
92 class UnknownTypeError(Exception):
93     pass
94
95
96 class GLibTransformer(object):
97
98     def __init__(self, transformer, noclosure=False):
99         self._transformer = transformer
100         self._noclosure = noclosure
101         self._namespace_name = None
102         self._names = Names()
103         self._uscore_type_names = {}
104         self._binary = None
105         self._get_type_functions = []
106         self._error_quark_functions = []
107         self._gtype_data = {}
108         self._failed_types = {}
109         self._boxed_types = {}
110         self._private_internal_types = {}
111         self._validating = False
112
113     # Public API
114
115     def _print_statistics(self):
116         nodes = list(self._names.names.itervalues())
117
118         def count_type(otype):
119             return len([x for x in nodes
120                         if isinstance(x[1], otype)])
121         objectcount = count_type(GLibObject)
122         ifacecount = count_type(GLibInterface)
123         enumcount = count_type(GLibEnum)
124         print " %d nodes; %d objects, %d interfaces, %d enums" \
125             % (len(nodes), objectcount, ifacecount, enumcount)
126
127     def init_parse(self):
128         """Do parsing steps that don't involve the introspection binary
129
130         This does enough work that get_type_functions() can be called.
131
132         """
133
134         namespace = self._transformer.parse()
135         self._namespace_name = namespace.name
136         self._namespace_version = namespace.version
137
138         # First pass: parsing
139         for node in namespace.nodes:
140             self._parse_node(node)
141
142         # We don't want an alias for this - it's handled specially in
143         # the typelib compiler.
144         if namespace.name == 'GObject':
145             del self._names.aliases['Type']
146
147     def get_get_type_functions(self):
148         return self._get_type_functions
149
150     def set_introspection_binary(self, binary):
151         self._binary = binary
152
153     def parse(self):
154         """Do remaining parsing steps requiring introspection binary"""
155
156         # Get all the GObject data by passing our list of get_type
157         # functions to the compiled binary
158
159         self._execute_binary()
160
161         # Introspection is done from within parsing
162
163         # Second pass: pair boxed structures
164         for boxed in self._boxed_types.itervalues():
165             self._pair_boxed_type(boxed)
166         # Third pass: delete class structures, resolve
167         # all types we now know about
168         nodes = list(self._names.names.itervalues())
169         for (ns, node) in nodes:
170             try:
171                 self._resolve_node(node)
172             except KeyError, e:
173                 print "WARNING: DELETING node %s: %s" % (node.name, e)
174                 self._remove_attribute(node.name)
175         # Another pass, since we need to have the methods parsed
176         # in order to correctly modify them after class/record
177         # pairing
178         for (ns, node) in nodes:
179             # associate GtkButtonClass with GtkButton
180             if isinstance(node, Record):
181                 self._pair_class_record(node)
182         for (ns, alias) in self._names.aliases.itervalues():
183             self._resolve_alias(alias)
184         self._resolve_quarks()
185         # Fourth pass: ensure all types are known
186         if not self._noclosure:
187             self._resolve_types(nodes)
188
189         self._validate(nodes)
190
191         # Create a new namespace with what we found
192         namespace = Namespace(self._namespace_name, self._namespace_version)
193         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
194         for (ns, x) in self._names.names.itervalues():
195             namespace.nodes.append(x)
196         return namespace
197
198     # Private
199
200     def _add_attribute(self, node, replace=False):
201         node_name = node.name
202         if (not replace) and node_name in self._names.names:
203             return
204         self._names.names[node_name] = (None, node)
205
206     def _remove_attribute(self, name):
207         del self._names.names[name]
208
209     def _get_attribute(self, name):
210         node = self._names.names.get(name)
211         if node:
212             return node[1]
213         return None
214
215     def _lookup_node(self, name):
216         if name in type_names:
217             return None
218         node = self._get_attribute(name)
219         if node is None:
220             node = self._transformer.get_names().names.get(name)
221             if node:
222                 return node[1]
223         return node
224
225     def _register_internal_type(self, type_name, node):
226         self._names.type_names[type_name] = (None, node)
227         uscored = to_underscores(type_name).lower()
228         # prefer the prefix of the get_type method, if there is one
229         if hasattr(node, 'get_type'):
230             uscored = GET_TYPE_OVERRIDES.get(node.get_type, node.get_type)
231             uscored = uscored[:-len('_get_type')]
232         self._uscore_type_names[uscored] = node
233         # Besides the straight underscore conversion, we also try
234         # removing the underscores from the namespace as a possible C
235         # mapping; e.g. it's webkit_web_view, not web_kit_web_view
236         suffix = self._transformer.remove_prefix(type_name)
237         prefix = type_name[:-len(suffix)]
238         no_uscore_prefixed = (prefix + '_' + to_underscores(suffix)).lower()
239         # since this is a guess, don't overwrite any 'real' prefix
240         if no_uscore_prefixed not in self._uscore_type_names:
241             self._uscore_type_names[no_uscore_prefixed] = node
242
243     def _resolve_quarks(self):
244         for node in self._error_quark_functions:
245             short = node.symbol[:-len('_quark')]
246             enum = self._uscore_type_names.get(short)
247             if enum is not None:
248                 enum.error_quark = node.symbol
249
250     # Helper functions
251
252     def _resolve_gtypename(self, gtype_name):
253         try:
254             return self._transformer.gtypename_to_giname(gtype_name,
255                                                          self._names)
256         except KeyError, e:
257             return Unresolved(gtype_name)
258
259     def _execute_binary(self):
260         in_path = os.path.join(self._binary.tmpdir, 'types.txt')
261         f = open(in_path, 'w')
262         # TODO: Introspect GQuark functions
263         for func in self._get_type_functions:
264             f.write(func)
265             f.write('\n')
266         f.close()
267         out_path = os.path.join(self._binary.tmpdir, 'dump.xml')
268
269         args = []
270         args.extend(self._binary.args)
271         args.append('--introspect-dump=%s,%s' % (in_path, out_path))
272
273         # Invoke the binary, having written our get_type functions to types.txt
274         try:
275             subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr)
276         except subprocess.CalledProcessError, e:
277             raise SystemExit(e)
278         self._read_introspect_dump(out_path)
279
280         # Clean up temporaries
281         shutil.rmtree(self._binary.tmpdir)
282
283     def _read_introspect_dump(self, xmlpath):
284         from xml.etree.cElementTree import parse
285         tree = parse(xmlpath)
286         root = tree.getroot()
287         for child in root:
288             self._gtype_data[child.attrib['name']] = child
289         for child in root:
290             self._introspect_type(child)
291
292     def _create_gobject(self, node):
293         type_name = 'G' + node.name
294         if type_name == 'GObject':
295             parent_gitype = None
296             symbol = 'intern'
297         elif type_name == 'GInitiallyUnowned':
298             parent_type_name = 'GObject'
299             parent_gitype = self._resolve_gtypename(parent_type_name)
300             symbol = 'g_initially_unowned_get_type'
301         else:
302             assert False
303         gnode = GLibObject(node.name, parent_gitype, type_name, symbol, True)
304         if type_name == 'GObject':
305             gnode.fields.extend(node.fields)
306         else:
307             # http://bugzilla.gnome.org/show_bug.cgi?id=569408
308             # GInitiallyUnowned is actually a typedef for GObject, but
309             # that's not reflected in the GIR, where it appears as a
310             # subclass (as it appears in the GType hierarchy).  So
311             # what we do here is copy all of the GObject fields into
312             # GInitiallyUnowned so that struct offset computation
313             # works correctly.
314             gnode.fields = self._names.names['Object'][1].fields
315         self._add_attribute(gnode)
316         self._register_internal_type(type_name, gnode)
317
318     # Parser
319
320     def _parse_node(self, node):
321         if isinstance(node, Enum):
322             self._parse_enum(node)
323         elif isinstance(node, Bitfield):
324             self._parse_bitfield(node)
325         elif isinstance(node, Function):
326             self._parse_function(node)
327         elif isinstance(node, Record):
328             self._parse_record(node)
329         elif isinstance(node, Callback):
330             self._parse_callback(node)
331         elif isinstance(node, Alias):
332             self._parse_alias(node)
333         elif isinstance(node, Member):
334             # FIXME: atk_misc_instance singletons
335             pass
336         elif isinstance(node, Union):
337             self._parse_union(node)
338         elif isinstance(node, Constant):
339             self._parse_constant(node)
340         else:
341             print 'GLIB Transformer: Unhandled node:', node
342
343     def _parse_alias(self, alias):
344         self._names.aliases[alias.name] = (None, alias)
345
346     def _parse_enum(self, enum):
347         self._add_attribute(enum)
348
349     def _parse_bitfield(self, enum):
350         self._add_attribute(enum)
351
352     def _parse_constant(self, constant):
353         self._add_attribute(constant)
354
355     def _parse_function(self, func):
356         if func.symbol in SYMBOL_BLACKLIST:
357             return
358         if func.symbol.startswith('_'):
359             return
360         for regexp in SYMBOL_BLACKLIST_RE:
361             if regexp.match(func.symbol):
362                 return
363         if self._parse_get_type_function(func):
364             return
365         if self._parse_error_quark_function(func):
366             return
367
368         self._add_attribute(func)
369
370     def _parse_get_type_function(self, func):
371         symbol = func.symbol
372         if not symbol.endswith('_get_type'):
373             return False
374         if self._namespace_name == 'GLib':
375             # No GObjects in GLib
376             return False
377         if (self._namespace_name == 'GObject' and
378             symbol in ('g_object_get_type', 'g_initially_unowned_get_type')):
379             # We handle these internally, see _create_gobject
380             return True
381         if func.parameters:
382             return False
383         # GType *_get_type(void)
384         if func.retval.type.name not in ['Type',
385                                          'GType',
386                                          'GObject.Type',
387                                          'Gtk.Type']:
388             print ("Warning: *_get_type function returns '%r'"
389                    ", not GObject.Type") % (func.retval.type.name, )
390             return False
391
392         self._get_type_functions.append(symbol)
393         return True
394
395     def _parse_error_quark_function(self, func):
396         if not func.symbol.endswith('_error_quark'):
397             return False
398         if func.parameters:
399             return False
400         if func.retval.type.name not in ['GLib.Quark',
401                                          'GQuark']:
402             return False
403
404         self._error_quark_functions.append(func)
405         return True
406
407     def _name_is_internal_gtype(self, giname):
408         try:
409             node = self._get_attribute(giname)
410             return isinstance(node, (GLibObject, GLibInterface,
411                                      GLibBoxed, GLibEnum, GLibFlags))
412         except KeyError, e:
413             return False
414
415     def _parse_static_method(self, func):
416         components = func.symbol.split('_')
417         if len(components) < 2:
418             return None
419         target_klass = None
420         prefix_components = None
421         methname = None
422         for i in xrange(1, len(components)):
423             prefix_components = '_'.join(components[0:-i])
424             methname = '_'.join(components[-i:])
425             target_klass = self._uscore_type_names.get(prefix_components)
426             if target_klass and isinstance(target_klass, GLibObject):
427                 break
428             target_klass = None
429         if not target_klass:
430             return None
431         self._remove_attribute(func.name)
432         func.name = methname
433         target_klass.static_methods.append(func)
434         func.is_method = True
435         return func
436
437     def _parse_method(self, func):
438         if not func.parameters:
439             return False
440         return self._parse_method_common(func, True)
441
442     def _parse_constructor(self, func):
443         return self._parse_method_common(func, False)
444
445     def _parse_method_common(self, func, is_method):
446         # Skip _get_type functions, we processed them
447         # already
448         if func.symbol.endswith('_get_type'):
449             return None
450         if self._namespace_name == 'GLib':
451             # No GObjects in GLib
452             return None
453
454         if not is_method:
455             target_arg = func.retval
456         else:
457             target_arg = func.parameters[0]
458
459         if is_method:
460             # Methods require their first arg to be a known class
461             # Look at the original C type (before namespace stripping), without
462             # pointers: GtkButton -> gtk_button_, so we can figure out the
463             # method name
464             argtype = target_arg.type.ctype.replace('*', '')
465             name = self._transformer.remove_prefix(argtype)
466             name_uscore = to_underscores_noprefix(name).lower()
467             # prefer the prefix of the _get_type method, if there is one
468             if argtype in self._names.type_names:
469                 node = self._names.type_names[argtype][1]
470                 if hasattr(node, 'get_type'):
471                     name_uscore = GET_TYPE_OVERRIDES.get(node.get_type,
472                                                          node.get_type)
473                     name_uscore = name_uscore[:-len('_get_type')]
474             name_offset = func.symbol.find(name_uscore)
475             if name_offset < 0:
476                 return None
477             prefix = func.symbol[:name_offset+len(name_uscore)]
478         else:
479             # Constructors must have _new
480             # Take everything before that as class name
481             new_idx = func.symbol.find('_new')
482             if new_idx < 0:
483                 return None
484             # Constructors don't return basic types
485             derefed = self._transformer.follow_aliases(target_arg.type.name,
486                                                        self._names)
487             if derefed in type_names:
488                 #print "NOTE: Rejecting constructor returning basic: %r" \
489                 #    % (func.symbol, )
490                 return None
491             prefix = func.symbol[:new_idx]
492
493         klass = self._uscore_type_names.get(prefix)
494         if klass is None:
495             #print "NOTE: No valid matching class for likely "+\
496             #    "method or constructor: %r" % (func.symbol, )
497             return None
498         # Enums can't have ctors or methods
499         if isinstance(klass, (GLibEnum, GLibFlags)):
500             return None
501
502         # The _uscore_type_names member holds the plain GLibBoxed
503         # object; we want to actually use the struct/record associated
504         if isinstance(klass, (Record, Union)):
505             remove_prefix = klass.symbol
506         else:
507             remove_prefix = klass.type_name
508
509         name = self._transformer.remove_prefix(remove_prefix)
510         klass = self._get_attribute(name)
511         if klass is None:
512             return
513
514         if not is_method:
515             # Interfaces can't have constructors, punt to global scope
516             if isinstance(klass, GLibInterface):
517                 #print "NOTE: Rejecting constructor for"+\
518                 #    " interface type: %r" % (func.symbol, )
519                 return None
520             # TODO - check that the return type is a subclass of the
521             # class from the prefix
522             # But for now, ensure that constructor returns are always
523             # the most concrete class
524             name = self._transformer.remove_prefix(remove_prefix)
525             func.retval.type = Type(name, func.retval.type.ctype)
526
527         self._remove_attribute(func.name)
528         # Strip namespace and object prefix: gtk_window_new -> new
529         func.name = func.symbol[len(prefix)+1:]
530         if is_method:
531             # We don't need the "this" parameter
532             del func.parameters[0]
533             klass.methods.append(func)
534             func.is_method = True
535         else:
536             klass.constructors.append(func)
537         return func
538
539     def _parse_record(self, record):
540         # This is a hack, but GObject is a rather fundamental piece so.
541         internal_names = ["Object", 'InitiallyUnowned']
542         g_internal_names = ["G" + x for x in internal_names]
543         if (self._namespace_name == 'GObject' and
544             record.name in internal_names):
545             self._create_gobject(record)
546             return
547         elif record.name in g_internal_names:
548             # Avoid duplicates
549             return
550         node = self._names.names.get(record.name)
551         if node is None:
552             self._add_attribute(record, replace=True)
553             self._register_internal_type(record.symbol, record)
554             return
555         (ns, node) = node
556         node.fields = record.fields[:]
557
558     def _parse_union(self, union):
559         node = self._names.names.get(union.name)
560         if node is None:
561             self._add_attribute(union, replace=True)
562             self._register_internal_type(union.symbol, union)
563             return
564         (ns, node) = node
565         node.fields = union.fields[:]
566
567     def _parse_callback(self, callback):
568         self._add_attribute(callback)
569
570     def _strip_class_suffix(self, name):
571         if (name.endswith('Class') or
572             name.endswith('Iface')):
573             return name[:-5]
574         elif name.endswith('Interface'):
575             return name[:-9]
576         else:
577             return name
578
579     def _arg_is_failed(self, param):
580         ctype = self._transformer.ctype_of(param).replace('*', '')
581         uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
582         if uscored in self._failed_types:
583             print "Warning: failed type: %r" % (param, )
584             return True
585         return False
586
587     def _pair_class_record(self, maybe_class):
588         name = self._strip_class_suffix(maybe_class.name)
589         if name == maybe_class.name:
590             return
591
592         class_struct = maybe_class
593         if self._arg_is_failed(class_struct):
594             print "WARNING: deleting no-type %r" % (class_struct.name, )
595             del self._names.names[class_struct.name]
596             return
597
598         pair_class = self._get_attribute(name)
599         if (not pair_class or
600             not isinstance(pair_class, (GLibObject, GLibInterface))):
601             return
602
603         # Object class fields are assumed to be read-only
604         # (see also _introspect_object and transformer.py)
605         for field in maybe_class.fields:
606             if isinstance(field, Field):
607                 field.writable = False
608
609         # Loop through fields to determine which are virtual
610         # functions and which are signal slots by
611         # assuming everything that doesn't share a name
612         # with a known signal is a virtual slot.
613         for field in maybe_class.fields:
614             if not isinstance(field, Callback):
615                 continue
616             # Check the first parameter is the object
617             if len(field.parameters) == 0:
618                 continue
619             firstparam_type = field.parameters[0].type
620             if firstparam_type != pair_class:
621                 continue
622             # Also double check we don't have a signal with this
623             # name.
624             matched_signal = False
625             for signal in pair_class.signals:
626                 if signal.name.replace('-', '_') == field.name:
627                     matched_signal = True
628                     break
629             if matched_signal:
630                 continue
631             vfunc = VFunction.from_callback(field)
632             pair_class.virtual_methods.append(vfunc)
633
634         # Take the set of virtual methods we found, and try
635         # to pair up with any matching methods using the
636         # name+signature.
637         for vfunc in pair_class.virtual_methods:
638             for method in pair_class.methods:
639                 if (method.name != vfunc.name or
640                     method.retval != vfunc.retval or
641                     method.parameters != vfunc.parameters):
642                     continue
643                 vfunc.invoker = method.name
644
645         gclass_struct = GLibRecord.from_record(class_struct)
646         self._remove_attribute(class_struct.name)
647         self._add_attribute(gclass_struct, True)
648         pair_class.glib_type_struct = gclass_struct
649         gclass_struct.is_gtype_struct_for = name
650
651     # Introspection
652
653     def _introspect_type(self, xmlnode):
654         if xmlnode.tag in ('enum', 'flags'):
655             self._introspect_enum(xmlnode)
656         elif xmlnode.tag == 'class':
657             self._introspect_object(xmlnode)
658         elif xmlnode.tag == 'interface':
659             self._introspect_interface(xmlnode)
660         elif xmlnode.tag == 'boxed':
661             self._introspect_boxed(xmlnode)
662         else:
663             raise ValueError("Unhandled introspection XML tag %s", xmlnode.tag)
664
665     def _introspect_enum(self, node):
666         members = []
667         for member in node.findall('member'):
668             # Keep the name closer to what we'd take from C by default;
669             # see http://bugzilla.gnome.org/show_bug.cgi?id=575613
670             name = member.attrib['nick'].replace('-', '_')
671             members.append(GLibEnumMember(name,
672                                           member.attrib['value'],
673                                           member.attrib['name'],
674                                           member.attrib['nick']))
675
676         klass = (GLibFlags if node.tag == 'flags' else GLibEnum)
677         type_name = node.attrib['name']
678         enum_name = self._transformer.remove_prefix(type_name)
679         node = klass(enum_name, type_name, members, node.attrib['get-type'])
680         self._add_attribute(node, replace=True)
681         self._register_internal_type(type_name, node)
682
683     def _introspect_object(self, xmlnode):
684         type_name = xmlnode.attrib['name']
685         # We handle this specially above; in 2.16 and below there
686         # was no g_object_get_type, for later versions we need
687         # to skip it
688         if type_name == 'GObject':
689             return
690         parent_type_name = xmlnode.attrib['parent']
691         parent_gitype = self._resolve_gtypename(parent_type_name)
692         is_abstract = not not xmlnode.attrib.get('abstract', False)
693         node = GLibObject(
694             self._transformer.remove_prefix(type_name),
695             parent_gitype,
696             type_name,
697             xmlnode.attrib['get-type'], is_abstract)
698         self._introspect_properties(node, xmlnode)
699         self._introspect_signals(node, xmlnode)
700         self._introspect_implemented_interfaces(node, xmlnode)
701
702         # add record fields
703         record = self._get_attribute(node.name)
704         if record is not None:
705             node.fields = record.fields
706             for field in node.fields:
707                 if isinstance(field, Field):
708                     # Object instance fields are assumed to be read-only
709                     # (see also _pair_class_record and transformer.py)
710                     field.writable = False
711
712         self._add_attribute(node, replace=True)
713         self._register_internal_type(type_name, node)
714
715     def _introspect_interface(self, xmlnode):
716         type_name = xmlnode.attrib['name']
717         node = GLibInterface(
718             self._transformer.remove_prefix(type_name),
719             None,
720             type_name, xmlnode.attrib['get-type'])
721         self._introspect_properties(node, xmlnode)
722         self._introspect_signals(node, xmlnode)
723         for child in xmlnode.findall('prerequisite'):
724             name = child.attrib['name']
725             prereq = self._resolve_gtypename(name)
726             node.prerequisites.append(prereq)
727         # GtkFileChooserEmbed is an example of a private interface, we
728         # just filter them out
729         if xmlnode.attrib['get-type'].startswith('_'):
730             print "NOTICE: Marking %s as internal type" % (type_name, )
731             self._private_internal_types[type_name] = node
732         else:
733             self._add_attribute(node, replace=True)
734             self._register_internal_type(type_name, node)
735
736     def _introspect_boxed(self, xmlnode):
737         type_name = xmlnode.attrib['name']
738         # This one doesn't go in the main namespace; we associate it with
739         # the struct or union
740         node = GLibBoxed(type_name, xmlnode.attrib['get-type'])
741         self._boxed_types[node.type_name] = node
742         self._register_internal_type(type_name, node)
743
744     def _introspect_implemented_interfaces(self, node, xmlnode):
745         gt_interfaces = []
746         for interface in xmlnode.findall('implements'):
747             gitype = self._resolve_gtypename(interface.attrib['name'])
748             gt_interfaces.append(gitype)
749         node.interfaces = gt_interfaces
750
751     def _introspect_properties(self, node, xmlnode):
752         for pspec in xmlnode.findall('property'):
753             ctype = pspec.attrib['type']
754             flags = int(pspec.attrib['flags'])
755             readable = (flags & G_PARAM_READABLE) != 0
756             writable = (flags & G_PARAM_WRITABLE) != 0
757             construct = (flags & G_PARAM_CONSTRUCT) != 0
758             construct_only = (flags & G_PARAM_CONSTRUCT_ONLY) != 0
759             node.properties.append(Property(
760                 pspec.attrib['name'],
761                 type_name_from_ctype(ctype),
762                 readable, writable, construct, construct_only,
763                 ctype,
764                 ))
765
766     def _introspect_signals(self, node, xmlnode):
767         for signal_info in xmlnode.findall('signal'):
768             rctype = signal_info.attrib['return']
769             rtype = Type(self._transformer.parse_ctype(rctype), rctype)
770             return_ = Return(rtype, signal_info.attrib['return'])
771             return_.transfer = PARAM_TRANSFER_FULL
772             signal = GLibSignal(signal_info.attrib['name'], return_)
773             for i, parameter in enumerate(signal_info.findall('param')):
774                 if i == 0:
775                     name = 'object'
776                 else:
777                     name = 'p%s' % (i-1, )
778                 pctype = parameter.attrib['type']
779                 ptype = Type(self._transformer.parse_ctype(pctype), pctype)
780                 param = Parameter(name, ptype)
781                 param.transfer = 'none'
782                 signal.parameters.append(param)
783             node.signals.append(signal)
784
785     # Resolver
786
787     def _resolve_type_name(self, type_name, ctype=None):
788         # Workaround glib bug #548689, to be included in 2.18.0
789         if type_name == "GParam":
790             type_name = "GObject.ParamSpec"
791         res = self._transformer.resolve_type_name_full
792         try:
793             return res(type_name, ctype, self._names)
794         except KeyError, e:
795             return self._transformer.resolve_type_name(type_name, ctype)
796
797     def _resolve_param_type(self, ptype, **kwargs):
798         # Workaround glib bug #548689, to be included in 2.18.0
799         if ptype.name == "GParam":
800             ptype.name = "GObject.ParamSpec"
801         return self._transformer.resolve_param_type_full(ptype,
802                                                          self._names,
803                                                          **kwargs)
804
805     def _resolve_node(self, node):
806         if isinstance(node, Function):
807             self._resolve_function_toplevel(node)
808
809         elif isinstance(node, Callback):
810             self._resolve_function(node)
811         elif isinstance(node, GLibObject):
812             self._resolve_glib_object(node)
813         elif isinstance(node, GLibInterface):
814             self._resolve_glib_interface(node)
815         elif isinstance(node, Record):
816             self._resolve_record(node)
817         elif isinstance(node, Union):
818             self._resolve_union(node)
819         elif isinstance(node, Alias):
820             self._resolve_alias(node)
821
822     def _resolve_function_toplevel(self, func):
823         for parser in [self._parse_constructor,
824                        self._parse_method,
825                        self._parse_static_method]:
826             newfunc = parser(func)
827             if newfunc:
828                 self._resolve_function(newfunc)
829                 return
830         self._resolve_function(func)
831
832     def _pair_boxed_type(self, boxed):
833         name = self._transformer.remove_prefix(boxed.type_name)
834         pair_node = self._get_attribute(name)
835         if not pair_node:
836             boxed_item = GLibBoxedOther(name, boxed.type_name,
837                                         boxed.get_type)
838         elif isinstance(pair_node, Record):
839             boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
840                                          boxed.get_type)
841             boxed_item.fields = pair_node.fields
842         elif isinstance(pair_node, Union):
843             boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
844                                          boxed.get_type)
845             boxed_item.fields = pair_node.fields
846         else:
847             return False
848         self._add_attribute(boxed_item, replace=True)
849
850     def _resolve_record(self, node):
851         for field in node.fields:
852             self._resolve_field(field)
853
854     def _resolve_union(self, node):
855         for field in node.fields:
856             self._resolve_field(field)
857
858     def _force_resolve(self, item, allow_unknown=False):
859         if isinstance(item, Unresolved):
860             if item.target in self._private_internal_types:
861                 return None
862             try:
863                 return self._transformer.gtypename_to_giname(item.target,
864                                                              self._names)
865             except KeyError, e:
866                 if allow_unknown:
867                     print "WARNING: Skipping unknown interface %s" % \
868                         (item.target, )
869                     return None
870                 else:
871                     raise
872         if item in self._private_internal_types:
873             return None
874         return item
875
876     def _resolve_glib_interface(self, node):
877         node.parent = self._force_resolve(node.parent)
878         self._resolve_methods(node.methods)
879         self._resolve_properties(node.properties, node)
880         self._resolve_signals(node.signals)
881         node.prerequisites = filter(None,
882             [self._force_resolve(x, allow_unknown=True)
883              for x in node.prerequisites])
884
885     def _resolve_glib_object(self, node):
886         # If we can't find the parent class, just drop back to GObject.
887         # This supports hidden parent classes.
888         # http://bugzilla.gnome.org/show_bug.cgi?id=561360
889         try:
890             node.parent = self._force_resolve(node.parent)
891         except KeyError, e:
892             #print ("WARNING: Parent %r of class %r" +\
893             #       " not found; using GObject") % (node.parent.target,
894             #                                       node.name)
895             node.parent = self._transformer.gtypename_to_giname("GObject",
896                                                                 self._names)
897         node.interfaces = filter(None,
898             [self._force_resolve(x, allow_unknown=True)
899                                     for x in node.interfaces])
900         self._resolve_constructors(node.constructors)
901         self._resolve_methods(node.methods)
902         self._resolve_methods(node.static_methods)
903         self._resolve_properties(node.properties, node)
904         self._resolve_signals(node.signals)
905         for field in node.fields:
906             self._resolve_field(field)
907
908     def _resolve_glib_boxed(self, node):
909         self._resolve_constructors(node.constructors)
910         self._resolve_methods(node.methods)
911
912     def _resolve_constructors(self, constructors):
913         for ctor in constructors:
914             self._resolve_function(ctor)
915
916     def _resolve_methods(self, methods):
917         for method in methods:
918             self._resolve_function(method)
919
920     def _resolve_signals(self, signals):
921         for signal in signals:
922             self._resolve_function(signal)
923
924     def _resolve_properties(self, properties, context):
925         failed = []
926         for prop in properties:
927             try:
928                 self._resolve_property(prop)
929             except KeyError, e:
930                 failed.append(prop)
931         for fail in failed:
932             #print ("WARNING: Deleting object property %r (of %r) "
933             #       "with unknown type") % (fail, context)
934             properties.remove(fail)
935
936     def _resolve_property(self, prop):
937         prop.type = self._resolve_param_type(prop.type, allow_invalid=False)
938
939     def _adjust_throws(self, func):
940         if func.parameters == []:
941             return
942
943         last_param = func.parameters.pop()
944
945         if (last_param.type.name == 'GLib.Error' or
946             (self._namespace_name == 'GLib' and
947              last_param.type.name == 'Error')):
948             func.throws = True
949         else:
950             func.parameters.append(last_param)
951
952     def _resolve_function(self, func):
953         self._resolve_parameters(func.parameters)
954         func.retval.type = self._resolve_param_type(func.retval.type)
955         self._adjust_throws(func)
956
957     def _resolve_parameters(self, parameters):
958         for parameter in parameters:
959             parameter.type = self._resolve_param_type(parameter.type)
960
961     def _resolve_field(self, field):
962         if isinstance(field, Callback):
963             self._resolve_function(field)
964         elif isinstance(field, Record): # non-typedef'd struct
965             self._resolve_record(field)
966         elif isinstance(field, Union): # non-typedef'd union
967             self._resolve_union(field)
968         else:
969             field.type = self._resolve_param_type(field.type)
970
971     def _resolve_alias(self, alias):
972         alias.target = self._resolve_type_name(alias.target, alias.target)
973
974     def _resolve_types(self, nodes):
975         nodes = list(self._names.names.itervalues())
976         i = 0
977         self._validating = True
978         while True:
979             initlen = len(nodes)
980
981             #print "Type resolution; pass=%d" % (i, )
982             nodes = list(self._names.names.itervalues())
983             for node in nodes:
984                 try:
985                     self._resolve_node(node)
986                 except UnknownTypeError, e:
987                     print "WARNING: %s: Deleting %r" % (e, node)
988                     self._remove_attribute(node.name)
989             if len(nodes) == initlen:
990                 break
991             i += 1
992             self._print_statistics()
993         self._validating = False
994
995     # Validation
996
997     def _validate_interface(self, iface):
998         for vfunc in iface.virtual_methods:
999             if not vfunc.invoker:
1000                 print ("warning: Interface %r virtual function %r " + \
1001                     "has no known invoker") % (iface.name, vfunc.name)
1002
1003     # This function is called at the very end, before we hand back the
1004     # completed namespace to the writer.  Add static analysis checks here.
1005     def _validate(self, nodes):
1006         for (name, node) in nodes:
1007             if isinstance(node, GLibInterface):
1008                 self._validate_interface(node)