Major rewrite
[platform/upstream/gobject-introspection.git] / giscanner / ast.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 # Copyright (C) 2008, 2009 Red Hat, Inc.
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the
18 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 # Boston, MA 02111-1307, USA.
20 #
21
22 from .odict import odict
23 from .utils import to_underscores
24
25 class Type(object):
26     """A Type can be either:
27 * A reference to a node (target_giname)
28 * A reference to a "fundamental" type like 'utf8'
29 * A "foreign" type - this can be any string."
30 If none are specified, then it's in an "unresolved" state.
31 In this case, the ctype must be specified.
32 """
33
34     def __init__(self,
35                  ctype=None,
36                  target_fundamental=None,
37                  target_giname=None,
38                  target_foreign=None,
39                  _target_unknown=False,
40                  is_const=False,
41                  origin_symbol=None):
42         self.ctype = ctype
43         self.origin_symbol = origin_symbol
44         if _target_unknown:
45             assert isinstance(self, TypeUnknown)
46         elif target_fundamental:
47             assert target_giname is None
48             assert target_foreign is None
49         elif target_giname:
50             assert '.' in target_giname
51             assert target_fundamental is None
52             assert target_foreign is None
53         elif target_foreign:
54             assert ctype is not None
55             assert target_giname is None
56             assert target_fundamental is None
57         else:
58             assert ctype is not None
59         self.target_fundamental = target_fundamental
60         self.target_giname = target_giname
61         self.target_foreign = target_foreign
62         self.is_const = is_const
63
64     @property
65     def resolved(self):
66         return (self.target_fundamental or
67                 self.target_giname or
68                 self.target_foreign)
69
70     def get_giname(self):
71         assert self.target_giname is not None
72         return self.target_giname.split('.')[1]
73
74     def __cmp__(self, other):
75         if self.target_fundamental:
76             return cmp(self.target_fundamental, other.target_fundamental)
77         if self.target_giname:
78             return cmp(self.target_giname, other.target_giname)
79         if self.target_foreign:
80             return cmp(self.target_foreign, other.target_foreign)
81         return cmp(self.ctype, other.ctype)
82
83     def is_equiv(self, typeval):
84         """Return True if the specified types are compatible at
85         an introspection level, disregarding their C types.
86         A sequence may be given for typeval, in which case
87         this function returns True if the type is compatible with
88         any."""
89         if isinstance(typeval, (list, tuple)):
90             for val in typeval:
91                 if self.is_equiv(val):
92                     return True
93             return False
94         return self == typeval
95
96     def clone(self):
97         return Type(target_fundamental=self.target_fundamental,
98                     target_giname=self.target_giname,
99                     target_foreign=self.target_foreign,
100                     ctype=self.ctype,
101                     is_const=self.is_const)
102
103     def __str__(self):
104         if self.target_fundamental:
105             return self.target_fundamental
106         elif self.target_giname:
107             return self.target_giname
108         elif self.target_foreign:
109             return self.target_foreign
110
111     def __repr__(self):
112         if self.target_fundamental:
113             data = 'target_fundamental=%s, ' % (self.target_fundamental, )
114         elif self.target_giname:
115             data = 'target_giname=%s, ' % (self.target_giname, )
116         elif self.target_foreign:
117             data = 'target_foreign=%s, ' % (self.target_foreign, )
118         else:
119             data = ''
120         return '%s(%sctype=%s)' % (self.__class__.__name__, data, self.ctype)
121
122 class TypeUnknown(Type):
123     def __init__(self):
124         Type.__init__(self, _target_unknown=True)
125
126 ######
127 ## Fundamental types
128 ######
129 # Two special ones
130 TYPE_NONE = Type(target_fundamental='none', ctype='void')
131 TYPE_ANY = Type(target_fundamental='gpointer', ctype='gpointer')
132 # "Basic" types
133 TYPE_BOOLEAN = Type(target_fundamental='gboolean', ctype='gboolean')
134 TYPE_INT8 = Type(target_fundamental='gint8', ctype='gint8')
135 TYPE_UINT8 = Type(target_fundamental='guint8', ctype='guint8')
136 TYPE_INT16 = Type(target_fundamental='gint16', ctype='gint16')
137 TYPE_UINT16 = Type(target_fundamental='guint16', ctype='guint16')
138 TYPE_INT32 = Type(target_fundamental='gint32', ctype='gint32')
139 TYPE_UINT32 = Type(target_fundamental='guint32', ctype='guint32')
140 TYPE_INT64 = Type(target_fundamental='gint64', ctype='gint64')
141 TYPE_UINT64 = Type(target_fundamental='guint64', ctype='guint64')
142 TYPE_CHAR = Type(target_fundamental='gchar', ctype='gchar')
143 TYPE_SHORT = Type(target_fundamental='gshort', ctype='gshort')
144 TYPE_USHORT = Type(target_fundamental='gushort', ctype='gushort')
145 TYPE_INT = Type(target_fundamental='gint', ctype='gint')
146 TYPE_UINT = Type(target_fundamental='guint', ctype='guint')
147 TYPE_LONG = Type(target_fundamental='glong', ctype='glong')
148 TYPE_ULONG = Type(target_fundamental='gulong', ctype='gulong')
149 # C99 types
150 TYPE_LONG_LONG = Type(target_fundamental='long long', ctype='long long')
151 TYPE_LONG_ULONG = Type(target_fundamental='unsigned long long',
152                        ctype='unsigned long long')
153 TYPE_FLOAT = Type(target_fundamental='gfloat', ctype='gfloat')
154 TYPE_DOUBLE = Type(target_fundamental='gdouble', ctype='gdouble')
155 # ?
156 TYPE_LONG_DOUBLE = Type(target_fundamental='long double',
157                         ctype='long double')
158 TYPE_UNICHAR = Type(target_fundamental='gunichar', ctype='gunichar')
159
160 # C types with semantics overlaid
161 TYPE_GTYPE = Type(target_fundamental='GType', ctype='GType')
162 TYPE_STRING = Type(target_fundamental='utf8', ctype='gchar*')
163 TYPE_FILENAME = Type(target_fundamental='filename', ctype='gchar*')
164
165 TYPE_VALIST = Type(target_fundamental='va_list', ctype='va_list')
166
167 BASIC_GIR_TYPES = [TYPE_BOOLEAN, TYPE_INT8, TYPE_UINT8, TYPE_INT16,
168                    TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64,
169                    TYPE_UINT64, TYPE_CHAR, TYPE_SHORT, TYPE_USHORT, TYPE_INT,
170                    TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_LONG_LONG,
171                    TYPE_LONG_ULONG, TYPE_FLOAT, TYPE_DOUBLE,
172                    TYPE_LONG_DOUBLE, TYPE_UNICHAR, TYPE_GTYPE]
173 GIR_TYPES = [TYPE_NONE, TYPE_ANY]
174 GIR_TYPES.extend(BASIC_GIR_TYPES)
175 GIR_TYPES.extend([TYPE_STRING, TYPE_FILENAME, TYPE_VALIST])
176
177 INTROSPECTABLE_BASIC = list(GIR_TYPES)
178 for v in [TYPE_NONE, TYPE_ANY,
179           TYPE_LONG_LONG, TYPE_LONG_ULONG,
180           TYPE_LONG_DOUBLE, TYPE_VALIST]:
181     INTROSPECTABLE_BASIC.remove(v)
182
183 type_names = {}
184 for typeval in GIR_TYPES:
185     type_names[typeval.target_fundamental] = typeval
186 basic_type_names = {}
187 for typeval in BASIC_GIR_TYPES:
188     basic_type_names[typeval.target_fundamental] = typeval
189
190 # C builtin
191 type_names['char'] = TYPE_CHAR
192 type_names['signed char'] = TYPE_INT8
193 type_names['unsigned char'] = TYPE_UINT8
194 type_names['short'] = TYPE_SHORT
195 type_names['signed short'] = TYPE_SHORT
196 type_names['unsigned short'] = TYPE_USHORT
197 type_names['int'] = TYPE_INT
198 type_names['signed int'] = TYPE_INT
199 type_names['unsigned short int'] = TYPE_USHORT
200 type_names['signed'] = TYPE_INT
201 type_names['unsigned int'] = TYPE_UINT
202 type_names['unsigned'] = TYPE_UINT
203 type_names['long'] = TYPE_LONG
204 type_names['signed long'] = TYPE_LONG
205 type_names['unsigned long'] = TYPE_ULONG
206 type_names['unsigned long int'] = TYPE_ULONG
207 type_names['float'] = TYPE_FLOAT
208 type_names['double'] = TYPE_DOUBLE
209 type_names['char*'] = TYPE_STRING
210 type_names['void*'] = TYPE_ANY
211 type_names['void'] = TYPE_NONE
212 # Also alias the signed one here
213 type_names['signed long long'] = TYPE_LONG_LONG
214
215 # A few additional GLib type aliases
216 type_names['guchar'] = TYPE_UINT8
217 type_names['gchararray'] = TYPE_STRING
218 type_names['gchar*'] = TYPE_STRING
219 type_names['goffset'] = TYPE_INT64
220 type_names['gunichar2'] = TYPE_UINT16
221 type_names['gsize'] = TYPE_ULONG
222 type_names['gssize'] = TYPE_LONG
223 type_names['gconstpointer'] = TYPE_ANY
224
225 # C stdio, used in GLib public headers; squash this for now here
226 # until we move scanning into GLib and can (skip)
227 type_names['FILE*'] = TYPE_ANY
228
229 # One off C unix type definitions; note some of these may be GNU Libc
230 # specific.  If someone is actually bitten by this, feel free to do
231 # the required configure goop to determine their size and replace
232 # here.
233 #
234 # We don't want to encourage people to use these in their APIs because
235 # they compromise the platform-independence that GLib gives you.
236 # These are here mostly to avoid blowing when random platform-specific
237 # methods are added under #ifdefs inside GLib itself.  We could just (skip)
238 # the relevant methods, but on the other hand, since these types are just
239 # integers it's easy enough to expand them.
240 type_names['size_t'] = type_names['gsize']
241 type_names['time_t'] = TYPE_LONG
242 type_names['off_t'] = type_names['gsize']
243 type_names['pid_t'] = TYPE_INT
244 type_names['uid_t'] = TYPE_UINT
245 type_names['gid_t'] = TYPE_UINT
246 type_names['dev_t'] = TYPE_INT
247 type_names['socklen_t'] = TYPE_INT32
248 type_names['size_t'] = TYPE_ULONG
249 type_names['ssize_t'] = TYPE_LONG
250
251 # Obj-C
252 type_names['id'] = TYPE_ANY
253
254 ##
255 ## Parameters
256 ##
257
258 PARAM_DIRECTION_IN = 'in'
259 PARAM_DIRECTION_OUT = 'out'
260 PARAM_DIRECTION_INOUT = 'inout'
261
262 PARAM_SCOPE_CALL = 'call'
263 PARAM_SCOPE_ASYNC = 'async'
264 PARAM_SCOPE_NOTIFIED = 'notified'
265
266 PARAM_TRANSFER_NONE = 'none'
267 PARAM_TRANSFER_CONTAINER = 'container'
268 PARAM_TRANSFER_FULL = 'full'
269
270 class Namespace(object):
271     def __init__(self, name, version,
272                  identifier_prefixes=None,
273                  symbol_prefixes=None):
274         self.name = name
275         self.version = version
276         if identifier_prefixes:
277             self.identifier_prefixes = identifier_prefixes
278         else:
279             self.identifier_prefixes = [name]
280         if symbol_prefixes:
281             self.symbol_prefixes = symbol_prefixes
282         else:
283             ps = self.identifier_prefixes
284             self.symbol_prefixes = [to_underscores(p).lower() for p in ps]
285         self._names = odict() # Maps from GIName -> node
286         self._aliases = {} # Maps from GIName -> GIName
287         self._type_names = {} # Maps from GTName -> node
288         self._ctypes = {} # Maps from CType -> node
289         self._symbols = {} # Maps from function symbols -> Function
290
291     @property
292     def names(self):
293         return self._names
294
295     @property
296     def aliases(self):
297         return self._aliases
298
299     @property
300     def type_names(self):
301         return self._type_names
302
303     @property
304     def ctypes(self):
305         return self._ctypes
306
307     def type_from_name(self, name, ctype=None):
308         """Backwards compatibility method for older .gir files, which
309 only use the 'name' attribute.  If name refers to a fundamental type,
310 create a Type object referncing it.  If name is already a
311 fully-qualified GIName like 'Foo.Bar', returns a Type targeting it .
312 Otherwise a Type targeting name qualififed with the namespace name is
313 returned."""
314         if name in type_names:
315             return Type(target_fundamental=name, ctype=ctype)
316         if '.' in name:
317             target = name
318         else:
319             target = '%s.%s' % (self.name, name)
320         return Type(target_giname=target, ctype=ctype)
321
322     def contains_ident(self, ident):
323         """Return True if this namespace should contain the given C
324 identifier string."""
325         return any(ident.startswith(prefix) for prefix in self.identifier_prefixes)
326
327     def append(self, node, replace=False):
328         previous = self._names.get(node.name)
329         if previous is not None:
330             if not replace:
331                 raise ValueError("Namespace conflict")
332             self.remove(previous)
333         # A layering violation...but oh well.
334         from .glibast import GLibBoxed
335         if isinstance(node, Alias):
336             self._aliases[node.name] = node
337         elif isinstance(node, (GLibBoxed, Interface, Class)):
338             self._type_names[node.type_name] = node
339         elif isinstance(node, Function):
340             self._symbols[node.symbol] = node
341         assert isinstance(node, Node)
342         assert node.namespace is None
343         node.namespace = self
344         self._names[node.name] = node
345         if hasattr(node, 'ctype'):
346             self._ctypes[node.ctype] = node
347         if hasattr(node, 'symbol'):
348             self._ctypes[node.symbol] = node
349
350     def remove(self, node):
351         from .glibast import GLibBoxed
352         if isinstance(node, Alias):
353             del self._aliases[node.name]
354         elif isinstance(node, (GLibBoxed, Interface, Class)):
355             del self._type_names[node.type_name]
356         del self._names[node.name]
357         node.namespace = None
358         if hasattr(node, 'ctype'):
359             del self._ctypes[node.ctype]
360         if isinstance(node, Function):
361             del self._symbols[node.symbol]
362
363     def float(self, node):
364         """Like remove(), but doesn't unset the node's namespace
365 back-reference, and it's still possible to look up
366 functions via get_by_symbol()."""
367         if isinstance(node, Function):
368             symbol = node.symbol
369         self.remove(node)
370         self._symbols[symbol] = node
371         node.namespace = self
372
373     def __iter__(self):
374         return iter(self._names)
375
376     def iteritems(self):
377         return self._names.iteritems()
378
379     def itervalues(self):
380         return self._names.itervalues()
381
382     def get(self, name):
383         return self._names.get(name)
384
385     def get_by_ctype(self, ctype):
386         return self._ctypes.get(ctype)
387
388     def get_by_symbol(self, symbol):
389         return self._symbols.get(symbol)
390
391     def walk(self, callback):
392         for node in self.itervalues():
393             node.walk(callback, [])
394
395 class Include(object):
396
397     def __init__(self, name, version):
398         self.name = name
399         self.version = version
400
401     @classmethod
402     def from_string(cls, string):
403         return cls(*string.split('-', 1))
404
405     def __cmp__(self, other):
406         namecmp = cmp(self.name, other.name)
407         if namecmp != 0:
408             return namecmp
409         return cmp(self.version, other.version)
410
411     def __hash__(self):
412         return hash(str(self))
413
414     def __str__(self):
415         return '%s-%s' % (self.name, self.version)
416
417 class Annotated(object):
418     """An object which has a few generic metadata
419 properties."""
420     def __init__(self):
421         self.version = None
422         self.skip = False
423         self.introspectable = True
424         self.attributes = [] # (key, value)*
425         self.deprecated = None
426         self.deprecated_version = None
427         self.doc = None
428
429 class Node(Annotated):
430     """A node is a type of object which is uniquely identified by its
431 (namespace, name) pair.  When combined with a ., this is called a
432 GIName.  It's possible for nodes to contain or point to other nodes."""
433
434     c_name = property(lambda self: self.namespace.name + self.name)
435     gi_name = property(lambda self: '%s.%s' % (self.namespace.name, self.name))
436
437     def __init__(self, name=None):
438         Annotated.__init__(self)
439         self.namespace = None # Should be set later by Namespace.append()
440         self.name = name
441         self.foreign = False
442         self.file_positions = set()
443
444     def create_type(self):
445         """Create a Type object referencing this node."""
446         assert self.namespace is not None
447         return Type(target_giname=('%s.%s' % (self.namespace.name, self.name)))
448
449     def __cmp__(self, other):
450         nscmp = cmp(self.namespace, other.namespace)
451         if nscmp != 0:
452             return nscmp
453         return cmp(self.name, other.name)
454
455     def __repr__(self):
456         return '%s(%r)' % (self.__class__.__name__, self.name)
457
458     def remove_matching_children(self, pred):
459         pass
460
461     def inherit_file_positions(self, node):
462         self.file_positions.update(node.file_positions)
463
464     def add_file_position(self, filename, line, column):
465         self.file_positions.add((filename, line, column))
466
467     def add_symbol_reference(self, symbol):
468         if symbol.source_filename:
469             self.add_file_position(symbol.source_filename, symbol.line, -1)
470
471     def walk(self, callback, chain):
472         res = callback(self, chain)
473         assert res in (True, False), "Walk function must return boolean, not %r" % (res, )
474         if not res:
475             return False
476         chain.append(self)
477         self._walk(callback, chain)
478         chain.pop()
479
480     def _walk(self, callback, chain):
481         pass
482
483 class Callable(Node):
484
485     def __init__(self, name, retval, parameters, throws):
486         Node.__init__(self, name)
487         self.retval = retval
488         self.parameters = parameters
489         self.throws = not not throws
490
491     def get_parameter_index(self, name):
492         for i, parameter in enumerate(self.parameters):
493             if parameter.argname == name:
494                 return i
495         raise ValueError("Unknown argument %s" % (name, ))
496
497     def get_parameter(self, name):
498         for parameter in self.parameters:
499             if parameter.argname == name:
500                 return parameter
501         raise ValueError("Unknown argument %s" % (name, ))
502
503
504 class Function(Callable):
505
506     def __init__(self, name, retval, parameters, throws, symbol):
507         Callable.__init__(self, name, retval, parameters, throws)
508         self.symbol = symbol
509         self.is_method = False
510         self.is_constructor = False
511         self.shadowed_by = None # C symbol string
512         self.shadows = None # C symbol string
513
514
515 class VFunction(Callable):
516
517     def __init__(self, name, retval, parameters, throws):
518         Callable.__init__(self, name, retval, parameters, throws)
519         self.invoker = None
520
521     @classmethod
522     def from_callback(cls, cb):
523         obj = cls(cb.name, cb.retval, cb.parameters[1:],
524                   cb.throws)
525         return obj
526
527
528
529 class Varargs(Type):
530
531     def __init__(self):
532         Type.__init__(self, '<varargs>', target_fundamental='<varargs>')
533
534
535 class Array(Type):
536     C = '<c>'
537     GLIB_ARRAY = 'GLib.Array'
538     GLIB_BYTEARRAY = 'GLib.ByteArray'
539     GLIB_PTRARRAY = 'GLib.PtrArray'
540
541     def __init__(self, array_type, element_type, **kwargs):
542         Type.__init__(self, target_fundamental='<array>',
543                       **kwargs)
544         if (array_type is None or array_type == self.C):
545             self.array_type = self.C
546         else:
547             assert array_type in (self.GLIB_ARRAY,
548                                   self.GLIB_BYTEARRAY,
549                                   self.GLIB_PTRARRAY)
550             self.array_type = array_type
551         assert isinstance(element_type, Type)
552         self.element_type = element_type
553         self.zeroterminated = True
554         self.length_param_name = None
555         self.size = None
556
557     def clone(self):
558         arr = Array(self.array_type, self.element_type)
559         arr.element_type = self.element_type
560         arr.zeroterminated = self.zeroterminated
561         arr.length_param_name = self.length_param_name
562         arr.size = self.size
563         return arr
564
565 class List(Type):
566
567     def __init__(self, name, element_type, **kwargs):
568         Type.__init__(self, target_fundamental='<list>',
569                       **kwargs)
570         self.name = name
571         assert isinstance(element_type, Type)
572         self.element_type = element_type
573
574     def clone(self):
575         l = List(self.name, self.element_type)
576         l.element_type = self.element_type
577         l.zeroterminated = self.zeroterminated
578         l.length_param_name = self.length_param_name
579         l.size = self.size
580         return l
581
582 class Map(Type):
583
584     def __init__(self, key_type, value_type, **kwargs):
585         Type.__init__(self, target_fundamental='<map>', **kwargs)
586         assert isinstance(key_type, Type)
587         self.key_type = key_type
588         assert isinstance(value_type, Type)
589         self.value_type = value_type
590
591     def clone(self):
592         m = Map(self.key_type, self.value_type)
593         return m
594
595 class Alias(Node):
596
597     def __init__(self, name, target, ctype=None):
598         Node.__init__(self, name)
599         self.target = target
600         self.ctype = ctype
601
602
603 class TypeContainer(Annotated):
604     """A fundamental base class for Return and Parameter."""
605
606     def __init__(self, typenode, transfer):
607         Annotated.__init__(self)
608         self.type = typenode
609         if transfer is not None:
610             self.transfer = transfer
611         elif typenode.is_const:
612             self.transfer = PARAM_TRANSFER_NONE
613         else:
614             self.transfer = None
615
616
617 class Parameter(TypeContainer):
618     """An argument to a function."""
619
620     def __init__(self, argname, typenode, direction=None,
621                  transfer=None, allow_none=False, scope=None,
622                  caller_allocates=False):
623         TypeContainer.__init__(self, typenode, transfer)
624         self.argname = argname
625         self.direction = direction
626         self.allow_none = allow_none
627         self.scope = scope
628         self.caller_allocates = caller_allocates
629         self.closure_name = None
630         self.destroy_name = None
631
632
633 class Return(TypeContainer):
634     """A return value from a function."""
635
636     def __init__(self, rtype, transfer=None):
637         TypeContainer.__init__(self, rtype, transfer)
638         self.direction = PARAM_DIRECTION_OUT
639
640
641 class Enum(Node):
642
643     def __init__(self, name, symbol, members):
644         Node.__init__(self, name)
645         self.symbol = symbol
646         self.members = members
647
648
649 class Bitfield(Node):
650
651     def __init__(self, name, symbol, members):
652         Node.__init__(self, name)
653         self.symbol = symbol
654         self.members = members
655
656
657 class Member(Annotated):
658
659     def __init__(self, name, value, symbol):
660         Annotated.__init__(self)
661         self.name = name
662         self.value = value
663         self.symbol = symbol
664
665     def __cmp__(self, other):
666         return cmp(self.name, other.name)
667
668
669 class Record(Node):
670
671     def __init__(self, name, symbol, disguised=False):
672         Node.__init__(self, name)
673         self.fields = []
674         self.constructors = []
675         self.symbol = symbol
676         self.disguised = disguised
677         self.methods = []
678         self.static_methods = []
679
680     def _walk(self, callback, chain):
681         for ctor in self.constructors:
682             ctor.walk(callback, chain)
683         for func in self.methods:
684             func.walk(callback, chain)
685         for func in self.static_methods:
686             func.walk(callback, chain)
687         for field in self.fields:
688             if field.anonymous_node is not None:
689                 field.anonymous_node.walk(callback, chain)
690
691     def remove_matching_children(self, pred):
692         self.fields = filter(pred, self.fields)
693         self.constructors = filter(pred, self.constructors)
694         self.methods = filter(pred, self.methods)
695
696
697 class Field(Annotated):
698
699     def __init__(self, name, typenode, readable, writable, bits=None,
700                  anonymous_node=None):
701         Annotated.__init__(self)
702         assert (typenode or anonymous_node)
703         self.name = name
704         self.type = typenode
705         self.readable = readable
706         self.writable = writable
707         self.bits = bits
708         self.anonymous_node = anonymous_node
709
710     def __cmp__(self, other):
711         return cmp(self.name, other.name)
712
713
714 class Class(Node):
715
716     def __init__(self, name, parent, is_abstract):
717         Node.__init__(self, name)
718         self.ctype = name
719         self.c_symbol_prefix = None
720         self.parent = parent
721         # When we're in the scanner, we keep around a list
722         # of parents so that we can transparently fall back
723         # if there are 'hidden' parents
724         self.parent_chain = []
725         self.glib_type_struct = None
726         self.is_abstract = is_abstract
727         self.methods = []
728         self.virtual_methods = []
729         self.static_methods = []
730         self.interfaces = []
731         self.constructors = []
732         self.properties = []
733         self.fields = []
734
735     def remove_matching_children(self, pred):
736         self.methods = filter(pred, self.methods)
737         self.constructors = filter(pred, self.constructors)
738         self.properties = filter(pred, self.properties)
739         self.fields = filter(pred, self.fields)
740
741     def _walk(self, callback, chain):
742         for meth in self.methods:
743             meth.walk(callback, chain)
744         for meth in self.virtual_methods:
745             meth.walk(callback, chain)
746         for meth in self.static_methods:
747             meth.walk(callback, chain)
748         for ctor in self.constructors:
749             ctor.walk(callback, chain)
750         for field in self.fields:
751             if field.anonymous_node:
752                 field.anonymous_node.walk(callback, chain)
753
754 class Interface(Node):
755
756     def __init__(self, name, parent):
757         Node.__init__(self, name)
758         self.c_symbol_prefix = None
759         self.parent = parent
760         self.parent_chain = []
761         self.methods = []
762         self.static_methods = []
763         self.virtual_methods = []
764         self.glib_type_struct = None
765         self.properties = []
766         self.fields = []
767         self.prerequisites = []
768
769     def _walk(self, callback, chain):
770         for meth in self.methods:
771             meth.walk(callback, chain)
772         for meth in self.static_methods:
773             meth.walk(callback, chain)
774         for meth in self.virtual_methods:
775             meth.walk(callback, chain)
776         for field in self.fields:
777             if field.anonymous_node:
778                 field.anonymous_node.walk(callback, chain)
779
780 class Constant(Node):
781
782     def __init__(self, name, value_type, value):
783         Node.__init__(self, name)
784         self.value_type = value_type
785         self.value = value
786
787
788 class Property(Node):
789
790     def __init__(self, name, typeobj, readable, writable,
791                  construct, construct_only, transfer=None):
792         Node.__init__(self, name)
793         self.type = typeobj
794         self.readable = readable
795         self.writable = writable
796         self.construct = construct
797         self.construct_only = construct_only
798         self.transfer = PARAM_TRANSFER_NONE
799
800
801 class Callback(Callable):
802
803     def __init__(self, name, retval, parameters, throws, ctype=None):
804         Callable.__init__(self, name, retval, parameters, throws)
805         self.ctype = ctype
806
807
808 class Union(Node):
809
810     def __init__(self, name, symbol):
811         Node.__init__(self, name)
812         self.fields = []
813         self.constructors = []
814         self.methods = []
815         self.static_methods = []
816         self.symbol = symbol
817
818     def _walk(self, callback, chain):
819         for ctor in self.constructors:
820             ctor.walk(callback, chain)
821         for meth in self.methods:
822             meth.walk(callback, chain)
823         for meth in self.static_methods:
824             meth.walk(callback, chain)
825         for field in self.fields:
826             if field.anonymous_node:
827                 field.anonymous_node.walk(callback, chain)