scanner: Don't use an O(N) lookup when we already have a hashmap
[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 import copy
23
24 from . import message
25
26 from .message import Position
27 from .odict import odict
28 from .utils import to_underscores
29
30 class Type(object):
31     """A Type can be either:
32 * A reference to a node (target_giname)
33 * A reference to a "fundamental" type like 'utf8'
34 * A "foreign" type - this can be any string."
35 If none are specified, then it's in an "unresolved" state.  An
36 unresolved type can have two data sources; a "ctype" which comes
37 from a C type string, or a gtype_name (from g_type_name()).
38 """ # '''
39
40     def __init__(self,
41                  ctype=None,
42                  gtype_name=None,
43                  target_fundamental=None,
44                  target_giname=None,
45                  target_foreign=None,
46                  _target_unknown=False,
47                  is_const=False,
48                  origin_symbol=None):
49         self.ctype = ctype
50         self.gtype_name = gtype_name
51         self.origin_symbol = origin_symbol
52         if _target_unknown:
53             assert isinstance(self, TypeUnknown)
54         elif target_fundamental:
55             assert target_giname is None
56             assert target_foreign is None
57         elif target_giname:
58             assert '.' in target_giname
59             assert target_fundamental is None
60             assert target_foreign is None
61         elif target_foreign:
62             assert ctype is not None
63             assert target_giname is None
64             assert target_fundamental is None
65         else:
66             assert (ctype is not None) or (gtype_name is not None)
67         self.target_fundamental = target_fundamental
68         self.target_giname = target_giname
69         self.target_foreign = target_foreign
70         self.is_const = is_const
71
72     @property
73     def resolved(self):
74         return (self.target_fundamental or
75                 self.target_giname or
76                 self.target_foreign)
77
78     @property
79     def unresolved_string(self):
80         if self.ctype:
81             return self.ctype
82         elif self.gtype_name:
83             return self.gtype_name
84         else:
85             assert False
86
87     @classmethod
88     def create_from_gtype_name(cls, gtype_name):
89         """Parse a GType name (as from g_type_name()), and return a
90 Type instance.  Note that this function performs namespace lookup,
91 in contrast to the other create_type() functions."""
92         # First, is it a fundamental?
93         fundamental = type_names.get(gtype_name)
94         if fundamental is not None:
95             return cls(target_fundamental=fundamental.target_fundamental)
96         if gtype_name == 'GHashTable':
97             return Map(TYPE_ANY, TYPE_ANY, gtype_name=gtype_name)
98         elif gtype_name in ('GArray', 'GPtrArray', 'GByteArray'):
99             return Array('GLib.' + gtype_name[1:], TYPE_ANY,
100                          gtype_name=gtype_name)
101         elif gtype_name == 'GStrv':
102             bare_utf8 = TYPE_STRING.clone()
103             bare_utf8.ctype = None
104             return Array(None, bare_utf8, ctype=None, gtype_name=gtype_name,
105                          is_const=False)
106
107         # Workaround for Gdk.Rectangle being boxed alias for
108         # cairo.RectangleInt.  G-I does not support boxing of aliases.
109         # See https://bugzilla.gnome.org/show_bug.cgi?id=655423
110         if gtype_name == 'GdkRectangle':
111             gtype_name = 'CairoRectangleInt'
112
113         return cls(gtype_name=gtype_name)
114
115     def get_giname(self):
116         assert self.target_giname is not None
117         return self.target_giname.split('.')[1]
118
119     def __cmp__(self, other):
120         if self.target_fundamental:
121             return cmp(self.target_fundamental, other.target_fundamental)
122         if self.target_giname:
123             return cmp(self.target_giname, other.target_giname)
124         if self.target_foreign:
125             return cmp(self.target_foreign, other.target_foreign)
126         return cmp(self.ctype, other.ctype)
127
128     def is_equiv(self, typeval):
129         """Return True if the specified types are compatible at
130         an introspection level, disregarding their C types.
131         A sequence may be given for typeval, in which case
132         this function returns True if the type is compatible with
133         any."""
134         if isinstance(typeval, (list, tuple)):
135             for val in typeval:
136                 if self.is_equiv(val):
137                     return True
138             return False
139         return self == typeval
140
141     def clone(self):
142         return Type(target_fundamental=self.target_fundamental,
143                     target_giname=self.target_giname,
144                     target_foreign=self.target_foreign,
145                     ctype=self.ctype,
146                     is_const=self.is_const)
147
148     def __str__(self):
149         if self.target_fundamental:
150             return self.target_fundamental
151         elif self.target_giname:
152             return self.target_giname
153         elif self.target_foreign:
154             return self.target_foreign
155
156     def __repr__(self):
157         if self.target_fundamental:
158             data = 'target_fundamental=%s, ' % (self.target_fundamental, )
159         elif self.target_giname:
160             data = 'target_giname=%s, ' % (self.target_giname, )
161         elif self.target_foreign:
162             data = 'target_foreign=%s, ' % (self.target_foreign, )
163         else:
164             data = ''
165         return '%s(%sctype=%s)' % (self.__class__.__name__, data, self.ctype)
166
167 class TypeUnknown(Type):
168     def __init__(self):
169         Type.__init__(self, _target_unknown=True)
170
171 ######
172 ## Fundamental types
173 ######
174 # Two special ones
175 TYPE_NONE = Type(target_fundamental='none', ctype='void')
176 TYPE_ANY = Type(target_fundamental='gpointer', ctype='gpointer')
177 # "Basic" types
178 TYPE_BOOLEAN = Type(target_fundamental='gboolean', ctype='gboolean')
179 TYPE_INT8 = Type(target_fundamental='gint8', ctype='gint8')
180 TYPE_UINT8 = Type(target_fundamental='guint8', ctype='guint8')
181 TYPE_INT16 = Type(target_fundamental='gint16', ctype='gint16')
182 TYPE_UINT16 = Type(target_fundamental='guint16', ctype='guint16')
183 TYPE_INT32 = Type(target_fundamental='gint32', ctype='gint32')
184 TYPE_UINT32 = Type(target_fundamental='guint32', ctype='guint32')
185 TYPE_INT64 = Type(target_fundamental='gint64', ctype='gint64')
186 TYPE_UINT64 = Type(target_fundamental='guint64', ctype='guint64')
187 TYPE_CHAR = Type(target_fundamental='gchar', ctype='gchar')
188 TYPE_SHORT = Type(target_fundamental='gshort', ctype='gshort')
189 TYPE_USHORT = Type(target_fundamental='gushort', ctype='gushort')
190 TYPE_INT = Type(target_fundamental='gint', ctype='gint')
191 TYPE_UINT = Type(target_fundamental='guint', ctype='guint')
192 TYPE_LONG = Type(target_fundamental='glong', ctype='glong')
193 TYPE_ULONG = Type(target_fundamental='gulong', ctype='gulong')
194 TYPE_SIZE = Type(target_fundamental='gsize', ctype='gsize')
195 TYPE_SSIZE = Type(target_fundamental='gssize', ctype='gssize')
196 TYPE_INTPTR = Type(target_fundamental='gintptr', ctype='gintptr')
197 TYPE_UINTPTR = Type(target_fundamental='guintptr', ctype='guintptr')
198 # C99 types
199 TYPE_LONG_LONG = Type(target_fundamental='long long', ctype='long long')
200 TYPE_LONG_ULONG = Type(target_fundamental='unsigned long long',
201                        ctype='unsigned long long')
202 TYPE_FLOAT = Type(target_fundamental='gfloat', ctype='gfloat')
203 TYPE_DOUBLE = Type(target_fundamental='gdouble', ctype='gdouble')
204 # ?
205 TYPE_LONG_DOUBLE = Type(target_fundamental='long double',
206                         ctype='long double')
207 TYPE_UNICHAR = Type(target_fundamental='gunichar', ctype='gunichar')
208
209 # C types with semantics overlaid
210 TYPE_GTYPE = Type(target_fundamental='GType', ctype='GType')
211 TYPE_STRING = Type(target_fundamental='utf8', ctype='gchar*')
212 TYPE_FILENAME = Type(target_fundamental='filename', ctype='gchar*')
213
214 TYPE_VALIST = Type(target_fundamental='va_list', ctype='va_list')
215
216 BASIC_GIR_TYPES = [TYPE_BOOLEAN, TYPE_INT8, TYPE_UINT8, TYPE_INT16,
217                    TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64,
218                    TYPE_UINT64, TYPE_CHAR, TYPE_SHORT, TYPE_USHORT, TYPE_INT,
219                    TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_SIZE, TYPE_SSIZE,
220                    TYPE_LONG_LONG, TYPE_LONG_ULONG, TYPE_INTPTR, TYPE_UINTPTR,
221                    TYPE_FLOAT, TYPE_DOUBLE,
222                    TYPE_LONG_DOUBLE, TYPE_UNICHAR, TYPE_GTYPE]
223 GIR_TYPES = [TYPE_NONE, TYPE_ANY]
224 GIR_TYPES.extend(BASIC_GIR_TYPES)
225 GIR_TYPES.extend([TYPE_STRING, TYPE_FILENAME, TYPE_VALIST])
226
227 # These are the only basic types that are guaranteed to
228 # be as big as a pointer (and thus are allowed in GPtrArray)
229 POINTER_TYPES = [TYPE_ANY, TYPE_INTPTR, TYPE_UINTPTR]
230
231 INTROSPECTABLE_BASIC = list(GIR_TYPES)
232 for v in [TYPE_NONE, TYPE_ANY,
233           TYPE_LONG_LONG, TYPE_LONG_ULONG,
234           TYPE_LONG_DOUBLE, TYPE_VALIST]:
235     INTROSPECTABLE_BASIC.remove(v)
236
237 type_names = {}
238 for typeval in GIR_TYPES:
239     type_names[typeval.target_fundamental] = typeval
240 basic_type_names = {}
241 for typeval in BASIC_GIR_TYPES:
242     basic_type_names[typeval.target_fundamental] = typeval
243
244 # C builtin
245 type_names['char'] = TYPE_CHAR
246 type_names['signed char'] = TYPE_INT8
247 type_names['unsigned char'] = TYPE_UINT8
248 type_names['short'] = TYPE_SHORT
249 type_names['signed short'] = TYPE_SHORT
250 type_names['unsigned short'] = TYPE_USHORT
251 type_names['int'] = TYPE_INT
252 type_names['signed int'] = TYPE_INT
253 type_names['unsigned short int'] = TYPE_USHORT
254 type_names['signed'] = TYPE_INT
255 type_names['unsigned int'] = TYPE_UINT
256 type_names['unsigned'] = TYPE_UINT
257 type_names['long'] = TYPE_LONG
258 type_names['signed long'] = TYPE_LONG
259 type_names['unsigned long'] = TYPE_ULONG
260 type_names['unsigned long int'] = TYPE_ULONG
261 type_names['float'] = TYPE_FLOAT
262 type_names['double'] = TYPE_DOUBLE
263 type_names['char*'] = TYPE_STRING
264 type_names['void*'] = TYPE_ANY
265 type_names['void'] = TYPE_NONE
266 # Also alias the signed one here
267 type_names['signed long long'] = TYPE_LONG_LONG
268 # C99 stdint exact width types
269 type_names['int8_t'] = TYPE_INT8
270 type_names['uint8_t'] = TYPE_UINT8
271 type_names['int16_t'] = TYPE_INT16
272 type_names['uint16_t'] = TYPE_UINT16
273 type_names['int32_t'] = TYPE_INT32
274 type_names['uint32_t'] = TYPE_UINT32
275 type_names['int64_t'] = TYPE_INT64
276 type_names['uint64_t'] = TYPE_UINT64
277
278 # A few additional GLib type aliases
279 type_names['guchar'] = TYPE_UINT8
280 type_names['gchararray'] = TYPE_STRING
281 type_names['gchar*'] = TYPE_STRING
282 type_names['goffset'] = TYPE_INT64
283 type_names['gunichar2'] = TYPE_UINT16
284 type_names['gsize'] = TYPE_SIZE
285 type_names['gssize'] = TYPE_SSIZE
286 type_names['gintptr'] = TYPE_INTPTR
287 type_names['guintptr'] = TYPE_UINTPTR
288 type_names['gconstpointer'] = TYPE_ANY
289
290 # We used to support these; continue to do so
291 type_names['any'] = TYPE_ANY
292 type_names['boolean'] = TYPE_BOOLEAN
293 type_names['uint'] = TYPE_UINT
294 type_names['ulong'] = TYPE_ULONG
295
296 # C stdio, used in GLib public headers; squash this for now here
297 # until we move scanning into GLib and can (skip)
298 type_names['FILE*'] = TYPE_ANY
299
300 # One off C unix type definitions; note some of these may be GNU Libc
301 # specific.  If someone is actually bitten by this, feel free to do
302 # the required configure goop to determine their size and replace
303 # here.
304 #
305 # We don't want to encourage people to use these in their APIs because
306 # they compromise the platform-independence that GLib gives you.
307 # These are here mostly to avoid blowing when random platform-specific
308 # methods are added under #ifdefs inside GLib itself.  We could just (skip)
309 # the relevant methods, but on the other hand, since these types are just
310 # integers it's easy enough to expand them.
311 type_names['size_t'] = type_names['gsize']
312 type_names['time_t'] = TYPE_LONG
313 type_names['off_t'] = type_names['gsize']
314 type_names['pid_t'] = TYPE_INT
315 type_names['uid_t'] = TYPE_UINT
316 type_names['gid_t'] = TYPE_UINT
317 type_names['dev_t'] = TYPE_INT
318 type_names['socklen_t'] = TYPE_INT32
319 type_names['size_t'] = TYPE_ULONG
320 type_names['ssize_t'] = TYPE_LONG
321
322 # Obj-C
323 type_names['id'] = TYPE_ANY
324
325 ##
326 ## Parameters
327 ##
328
329 PARAM_DIRECTION_IN = 'in'
330 PARAM_DIRECTION_OUT = 'out'
331 PARAM_DIRECTION_INOUT = 'inout'
332
333 PARAM_SCOPE_CALL = 'call'
334 PARAM_SCOPE_ASYNC = 'async'
335 PARAM_SCOPE_NOTIFIED = 'notified'
336
337 PARAM_TRANSFER_NONE = 'none'
338 PARAM_TRANSFER_CONTAINER = 'container'
339 PARAM_TRANSFER_FULL = 'full'
340
341 SIGNAL_FIRST = 'first'
342 SIGNAL_LAST = 'last'
343 SIGNAL_CLEANUP = 'cleanup'
344 SIGNAL_MUST_COLLECT = 'must-collect'
345
346
347 class Namespace(object):
348     def __init__(self, name, version,
349                  identifier_prefixes=None,
350                  symbol_prefixes=None):
351         self.name = name
352         self.version = version
353         if identifier_prefixes is not None:
354             self.identifier_prefixes = identifier_prefixes
355         else:
356             self.identifier_prefixes = [name]
357         if symbol_prefixes is not None:
358             self.symbol_prefixes = symbol_prefixes
359         else:
360             ps = self.identifier_prefixes
361             self.symbol_prefixes = [to_underscores(p).lower() for p in ps]
362         # cache upper-cased versions
363         self._ucase_symbol_prefixes = [p.upper() for p in self.symbol_prefixes]
364         self._names = odict() # Maps from GIName -> node
365         self._aliases = {} # Maps from GIName -> GIName
366         self._type_names = {} # Maps from GTName -> node
367         self._ctypes = {} # Maps from CType -> node
368         self._symbols = {} # Maps from function symbols -> Function
369
370     @property
371     def names(self):
372         return self._names
373
374     @property
375     def aliases(self):
376         return self._aliases
377
378     @property
379     def type_names(self):
380         return self._type_names
381
382     @property
383     def ctypes(self):
384         return self._ctypes
385
386     def type_from_name(self, name, ctype=None):
387         """Backwards compatibility method for older .gir files, which
388 only use the 'name' attribute.  If name refers to a fundamental type,
389 create a Type object referncing it.  If name is already a
390 fully-qualified GIName like 'Foo.Bar', returns a Type targeting it .
391 Otherwise a Type targeting name qualififed with the namespace name is
392 returned."""
393         if name in type_names:
394             return Type(target_fundamental=name, ctype=ctype)
395         if '.' in name:
396             target = name
397         else:
398             target = '%s.%s' % (self.name, name)
399         return Type(target_giname=target, ctype=ctype)
400
401     def append(self, node, replace=False):
402         previous = self._names.get(node.name)
403         if previous is not None:
404             if not replace:
405                 raise ValueError("Namespace conflict: %r" % (node, ))
406             self.remove(previous)
407         # A layering violation...but oh well.
408         if isinstance(node, Alias):
409             self._aliases[node.name] = node
410         elif isinstance(node, Registered) and node.gtype_name is not None:
411             self._type_names[node.gtype_name] = node
412         elif isinstance(node, Function):
413             self._symbols[node.symbol] = node
414         assert isinstance(node, Node)
415         assert node.namespace is None
416         node.namespace = self
417         self._names[node.name] = node
418         if hasattr(node, 'ctype'):
419             self._ctypes[node.ctype] = node
420         if hasattr(node, 'symbol'):
421             self._ctypes[node.symbol] = node
422
423     def remove(self, node):
424         if isinstance(node, Alias):
425             del self._aliases[node.name]
426         elif isinstance(node, Registered) and node.gtype_name is not None:
427             del self._type_names[node.gtype_name]
428         del self._names[node.name]
429         node.namespace = None
430         if hasattr(node, 'ctype'):
431             del self._ctypes[node.ctype]
432         if isinstance(node, Function):
433             del self._symbols[node.symbol]
434
435     def float(self, node):
436         """Like remove(), but doesn't unset the node's namespace
437 back-reference, and it's still possible to look up
438 functions via get_by_symbol()."""
439         if isinstance(node, Function):
440             symbol = node.symbol
441         self.remove(node)
442         self._symbols[symbol] = node
443         node.namespace = self
444
445     def __iter__(self):
446         return iter(self._names)
447
448     def iteritems(self):
449         return self._names.iteritems()
450
451     def itervalues(self):
452         return self._names.itervalues()
453
454     def get(self, name):
455         return self._names.get(name)
456
457     def get_by_ctype(self, ctype):
458         return self._ctypes.get(ctype)
459
460     def get_by_symbol(self, symbol):
461         return self._symbols.get(symbol)
462
463     def walk(self, callback):
464         for node in self.itervalues():
465             node.walk(callback, [])
466
467 class Include(object):
468
469     def __init__(self, name, version):
470         self.name = name
471         self.version = version
472
473     @classmethod
474     def from_string(cls, string):
475         return cls(*string.split('-', 1))
476
477     def __cmp__(self, other):
478         namecmp = cmp(self.name, other.name)
479         if namecmp != 0:
480             return namecmp
481         return cmp(self.version, other.version)
482
483     def __hash__(self):
484         return hash(str(self))
485
486     def __str__(self):
487         return '%s-%s' % (self.name, self.version)
488
489 class Annotated(object):
490     """An object which has a few generic metadata
491 properties."""
492     def __init__(self):
493         self.version = None
494         self.skip = False
495         self.introspectable = True
496         self.attributes = [] # (key, value)*
497         self.deprecated = None
498         self.deprecated_version = None
499         self.doc = None
500
501 class Node(Annotated):
502     """A node is a type of object which is uniquely identified by its
503 (namespace, name) pair.  When combined with a ., this is called a
504 GIName.  It's possible for nodes to contain or point to other nodes."""
505
506     c_name = property(lambda self: self.namespace.name + self.name)
507     gi_name = property(lambda self: '%s.%s' % (self.namespace.name, self.name))
508
509     def __init__(self, name=None):
510         Annotated.__init__(self)
511         self.namespace = None # Should be set later by Namespace.append()
512         self.name = name
513         self.foreign = False
514         self.file_positions = set()
515
516     def create_type(self):
517         """Create a Type object referencing this node."""
518         assert self.namespace is not None
519         return Type(target_giname=('%s.%s' % (self.namespace.name, self.name)))
520
521     def __cmp__(self, other):
522         nscmp = cmp(self.namespace, other.namespace)
523         if nscmp != 0:
524             return nscmp
525         return cmp(self.name, other.name)
526
527     def __repr__(self):
528         return '%s(%r)' % (self.__class__.__name__, self.name)
529
530     def inherit_file_positions(self, node):
531         self.file_positions.update(node.file_positions)
532
533     def add_file_position(self, position):
534         self.file_positions.add(position)
535
536     def add_symbol_reference(self, symbol):
537         if symbol.source_filename:
538             self.add_file_position(Position(symbol.source_filename, symbol.line))
539
540     def walk(self, callback, chain):
541         res = callback(self, chain)
542         assert res in (True, False), "Walk function must return boolean, not %r" % (res, )
543         if not res:
544             return False
545         chain.append(self)
546         self._walk(callback, chain)
547         chain.pop()
548
549     def _walk(self, callback, chain):
550         pass
551
552
553 class Registered:
554     """A node that (possibly) has gtype_name and get_type."""
555     def __init__(self, gtype_name, get_type):
556         assert (gtype_name is None and get_type is None) or \
557                (gtype_name is not None and get_type is not None)
558         self.gtype_name = gtype_name
559         self.get_type = get_type
560
561
562 class Callable(Node):
563
564     def __init__(self, name, retval, parameters, throws):
565         Node.__init__(self, name)
566         self.retval = retval
567         self.parameters = parameters
568         self.throws = not not throws
569         self.instance_parameter = None # Parameter
570         self.parent = None # A Class or Interface
571
572     def get_parameter_index(self, name):
573         for i, parameter in enumerate(self.parameters):
574             if parameter.argname == name:
575                 return i
576         raise ValueError("Unknown argument %s" % (name, ))
577
578     def get_parameter(self, name):
579         for parameter in self.parameters:
580             if parameter.argname == name:
581                 return parameter
582         raise ValueError("Unknown argument %s" % (name, ))
583
584
585 class Function(Callable):
586
587     def __init__(self, name, retval, parameters, throws, symbol):
588         Callable.__init__(self, name, retval, parameters, throws)
589         self.symbol = symbol
590         self.is_method = False
591         self.is_constructor = False
592         self.shadowed_by = None # C symbol string
593         self.shadows = None # C symbol string
594         self.moved_to = None # namespaced function name string
595
596     def clone(self):
597         clone = copy.copy(self)
598         # copy the parameters array so a change to self.parameters does not
599         # influence clone.parameters.
600         clone.parameters = self.parameters[:]
601         return clone
602
603     def is_type_meta_function(self):
604         # Named correctly
605         if not (self.name.endswith('_get_type') or
606                 self.name.endswith('_get_gtype')):
607                 return False
608
609         # Doesn't have any parameters
610         if self.parameters:
611             return False
612
613         # Returns GType
614         rettype = self.retval.type
615         if (not rettype.is_equiv(TYPE_GTYPE) and
616            rettype.target_giname != 'Gtk.Type'):
617             message.warn("function '%s' returns '%r', not a GType" %
618                          (self.name, rettype))
619             return False
620
621         return True
622
623 class ErrorQuarkFunction(Function):
624
625     def __init__(self, name, retval, parameters, throws, symbol, error_domain):
626         Function.__init__(self, name, retval, parameters, throws, symbol)
627         self.error_domain = error_domain
628
629
630 class VFunction(Callable):
631
632     def __init__(self, name, retval, parameters, throws):
633         Callable.__init__(self, name, retval, parameters, throws)
634         self.invoker = None
635
636     @classmethod
637     def from_callback(cls, cb):
638         obj = cls(cb.name, cb.retval, cb.parameters[1:],
639                   cb.throws)
640         return obj
641
642
643
644 class Varargs(Type):
645
646     def __init__(self):
647         Type.__init__(self, '<varargs>', target_fundamental='<varargs>')
648
649
650 class Array(Type):
651     C = '<c>'
652     GLIB_ARRAY = 'GLib.Array'
653     GLIB_BYTEARRAY = 'GLib.ByteArray'
654     GLIB_PTRARRAY = 'GLib.PtrArray'
655
656     def __init__(self, array_type, element_type, **kwargs):
657         Type.__init__(self, target_fundamental='<array>',
658                       **kwargs)
659         if (array_type is None or array_type == self.C):
660             self.array_type = self.C
661         else:
662             assert array_type in (self.GLIB_ARRAY,
663                                   self.GLIB_BYTEARRAY,
664                                   self.GLIB_PTRARRAY), array_type
665             self.array_type = array_type
666         assert isinstance(element_type, Type)
667         self.element_type = element_type
668         self.zeroterminated = True
669         self.length_param_name = None
670         self.size = None
671
672     def clone(self):
673         arr = Array(self.array_type, self.element_type)
674         arr.zeroterminated = self.zeroterminated
675         arr.length_param_name = self.length_param_name
676         arr.size = self.size
677         return arr
678
679 class List(Type):
680
681     def __init__(self, name, element_type, **kwargs):
682         Type.__init__(self, target_fundamental='<list>',
683                       **kwargs)
684         self.name = name
685         assert isinstance(element_type, Type)
686         self.element_type = element_type
687
688     def clone(self):
689         return List(self.name, self.element_type)
690
691 class Map(Type):
692
693     def __init__(self, key_type, value_type, **kwargs):
694         Type.__init__(self, target_fundamental='<map>', **kwargs)
695         assert isinstance(key_type, Type)
696         self.key_type = key_type
697         assert isinstance(value_type, Type)
698         self.value_type = value_type
699
700     def clone(self):
701         return Map(self.key_type, self.value_type)
702
703 class Alias(Node):
704
705     def __init__(self, name, target, ctype=None):
706         Node.__init__(self, name)
707         self.target = target
708         self.ctype = ctype
709
710
711 class TypeContainer(Annotated):
712     """A fundamental base class for Return and Parameter."""
713
714     def __init__(self, typenode, transfer):
715         Annotated.__init__(self)
716         self.type = typenode
717         if transfer is not None:
718             self.transfer = transfer
719         elif typenode.is_const:
720             self.transfer = PARAM_TRANSFER_NONE
721         else:
722             self.transfer = None
723
724
725 class Parameter(TypeContainer):
726     """An argument to a function."""
727
728     def __init__(self, argname, typenode, direction=None,
729                  transfer=None, allow_none=False, scope=None,
730                  caller_allocates=False):
731         TypeContainer.__init__(self, typenode, transfer)
732         self.argname = argname
733         self.direction = direction
734         self.allow_none = allow_none
735         self.scope = scope
736         self.caller_allocates = caller_allocates
737         self.closure_name = None
738         self.destroy_name = None
739
740
741 class Return(TypeContainer):
742     """A return value from a function."""
743
744     def __init__(self, rtype, transfer=None):
745         TypeContainer.__init__(self, rtype, transfer)
746         self.direction = PARAM_DIRECTION_OUT
747
748
749 class Enum(Node, Registered):
750
751     def __init__(self, name, ctype,
752                  gtype_name=None,
753                  get_type=None,
754                  c_symbol_prefix=None,
755                  members=None):
756         Node.__init__(self, name)
757         Registered.__init__(self, gtype_name, get_type)
758         self.c_symbol_prefix = c_symbol_prefix
759         self.ctype = ctype
760         self.members = members
761         # Associated error domain name
762         self.error_domain = None
763         self.static_methods = []
764
765     def _walk(self, callback, chain):
766         for meth in self.static_methods:
767             meth.walk(callback, chain)
768
769
770 class Bitfield(Node, Registered):
771
772     def __init__(self, name, ctype,
773                  gtype_name=None,
774                  c_symbol_prefix=None,
775                  get_type=None,
776                  members=None):
777         Node.__init__(self, name)
778         Registered.__init__(self, gtype_name, get_type)
779         self.ctype = ctype
780         self.c_symbol_prefix = c_symbol_prefix
781         self.members = members
782         self.static_methods = []
783
784     def _walk(self, callback, chain):
785         for meth in self.static_methods:
786             meth.walk(callback, chain)
787
788
789 class Member(Annotated):
790
791     def __init__(self, name, value, symbol, nick):
792         Annotated.__init__(self)
793         self.name = name
794         self.value = value
795         self.symbol = symbol
796         self.nick = nick
797
798     def __cmp__(self, other):
799         return cmp(self.name, other.name)
800
801
802
803 class Compound(Node, Registered):
804     def __init__(self, name,
805                  ctype=None,
806                  gtype_name=None,
807                  get_type=None,
808                  c_symbol_prefix=None,
809                  disguised=False):
810         Node.__init__(self, name)
811         Registered.__init__(self, gtype_name, get_type)
812         self.ctype = ctype
813         self.methods = []
814         self.static_methods = []
815         self.fields = []
816         self.constructors = []
817         self.disguised = disguised
818         self.gtype_name = gtype_name
819         self.get_type = get_type
820         self.c_symbol_prefix = c_symbol_prefix
821
822     def add_gtype(self, gtype_name, get_type):
823         self.gtype_name = gtype_name
824         self.get_type = get_type
825         self.namespace.type_names[gtype_name] = self
826
827     def _walk(self, callback, chain):
828         for ctor in self.constructors:
829             ctor.walk(callback, chain)
830         for func in self.methods:
831             func.walk(callback, chain)
832         for func in self.static_methods:
833             func.walk(callback, chain)
834         for field in self.fields:
835             if field.anonymous_node is not None:
836                 field.anonymous_node.walk(callback, chain)
837
838 class Field(Annotated):
839
840     def __init__(self, name, typenode, readable, writable, bits=None,
841                  anonymous_node=None):
842         Annotated.__init__(self)
843         assert (typenode or anonymous_node)
844         self.name = name
845         self.type = typenode
846         self.readable = readable
847         self.writable = writable
848         self.bits = bits
849         self.anonymous_node = anonymous_node
850         self.private = False
851
852     def __cmp__(self, other):
853         return cmp(self.name, other.name)
854
855
856 class Record(Compound):
857
858     def __init__(self, name,
859                  ctype=None,
860                  gtype_name=None,
861                  get_type=None,
862                  c_symbol_prefix=None,
863                  disguised=False):
864         Compound.__init__(self, name,
865                           ctype=ctype,
866                           gtype_name=gtype_name,
867                           get_type=get_type,
868                           c_symbol_prefix=c_symbol_prefix,
869                           disguised=disguised)
870         # If non-None, this record defines the FooClass C structure
871         # for some Foo GObject (or similar for GInterface)
872         self.is_gtype_struct_for = None
873
874
875 class Union(Compound):
876
877     def __init__(self, name,
878                  ctype=None,
879                  gtype_name=None,
880                  get_type=None,
881                  c_symbol_prefix=None,
882                  disguised=False):
883         Compound.__init__(self, name,
884                           ctype=ctype,
885                           gtype_name=gtype_name,
886                           get_type=get_type,
887                           c_symbol_prefix=c_symbol_prefix,
888                           disguised=disguised)
889
890
891 class Boxed(Node, Registered):
892     """A boxed type with no known associated structure/union."""
893     def __init__(self, name,
894                  gtype_name=None,
895                  get_type=None,
896                  c_symbol_prefix=None):
897         assert gtype_name is not None
898         assert get_type is not None
899         Node.__init__(self, name)
900         Registered.__init__(self, gtype_name, get_type)
901         if get_type is not None:
902             assert c_symbol_prefix is not None
903         self.c_symbol_prefix = c_symbol_prefix
904         self.constructors = []
905         self.methods = []
906         self.static_methods = []
907
908     def _walk(self, callback, chain):
909         for ctor in self.constructors:
910             ctor.walk(callback, chain)
911         for meth in self.methods:
912             meth.walk(callback, chain)
913         for meth in self.static_methods:
914             meth.walk(callback, chain)
915
916
917 class Signal(Callable):
918
919     def __init__(self, name, retval, parameters, when=None,
920                  no_recurse=False, detailed=False, action=False,
921                  no_hooks=False):
922         Callable.__init__(self, name, retval, parameters, False)
923         self.when = when
924         self.no_recurse = no_recurse
925         self.detailed = detailed
926         self.action = action
927         self.no_hooks = no_hooks
928
929
930 class Class(Node, Registered):
931
932     def __init__(self, name, parent,
933                  ctype=None,
934                  gtype_name=None,
935                  get_type=None,
936                  c_symbol_prefix=None,
937                  is_abstract=False):
938         Node.__init__(self, name)
939         Registered.__init__(self, gtype_name, get_type)
940         self.ctype = ctype
941         self.c_symbol_prefix = c_symbol_prefix
942         self.parent = parent
943         self.fundamental = False
944         self.unref_func = None
945         self.ref_func = None
946         self.set_value_func = None
947         self.get_value_func = None
948         # When we're in the scanner, we keep around a list
949         # of parents so that we can transparently fall back
950         # if there are 'hidden' parents
951         self.parent_chain = []
952         self.glib_type_struct = None
953         self.is_abstract = is_abstract
954         self.methods = []
955         self.virtual_methods = []
956         self.static_methods = []
957         self.interfaces = []
958         self.constructors = []
959         self.properties = []
960         self.fields = []
961         self.signals = []
962
963     def _walk(self, callback, chain):
964         for meth in self.methods:
965             meth.walk(callback, chain)
966         for meth in self.virtual_methods:
967             meth.walk(callback, chain)
968         for meth in self.static_methods:
969             meth.walk(callback, chain)
970         for ctor in self.constructors:
971             ctor.walk(callback, chain)
972         for field in self.fields:
973             if field.anonymous_node:
974                 field.anonymous_node.walk(callback, chain)
975         for sig in self.signals:
976             sig.walk(callback, chain)
977
978
979 class Interface(Node, Registered):
980
981     def __init__(self, name, parent,
982                  ctype=None,
983                  gtype_name=None,
984                  get_type=None,
985                  c_symbol_prefix=None):
986         Node.__init__(self, name)
987         Registered.__init__(self, gtype_name, get_type)
988         self.ctype = ctype
989         self.c_symbol_prefix = c_symbol_prefix
990         self.parent = parent
991         self.parent_chain = []
992         self.methods = []
993         self.signals = []
994         self.static_methods = []
995         self.virtual_methods = []
996         self.glib_type_struct = None
997         self.properties = []
998         self.fields = []
999         self.prerequisites = []
1000
1001     def _walk(self, callback, chain):
1002         for meth in self.methods:
1003             meth.walk(callback, chain)
1004         for meth in self.static_methods:
1005             meth.walk(callback, chain)
1006         for meth in self.virtual_methods:
1007             meth.walk(callback, chain)
1008         for field in self.fields:
1009             if field.anonymous_node:
1010                 field.anonymous_node.walk(callback, chain)
1011         for sig in self.signals:
1012             sig.walk(callback, chain)
1013
1014
1015 class Constant(Node):
1016
1017     def __init__(self, name, value_type, value, ctype):
1018         Node.__init__(self, name)
1019         self.value_type = value_type
1020         self.value = value
1021         self.ctype = ctype
1022
1023
1024 class Property(Node):
1025
1026     def __init__(self, name, typeobj, readable, writable,
1027                  construct, construct_only, transfer=None):
1028         Node.__init__(self, name)
1029         self.type = typeobj
1030         self.readable = readable
1031         self.writable = writable
1032         self.construct = construct
1033         self.construct_only = construct_only
1034         if transfer is None:
1035             self.transfer = PARAM_TRANSFER_NONE
1036         else:
1037             self.transfer = transfer
1038         self.parent = None # A Class or Interface
1039
1040
1041 class Callback(Callable):
1042
1043     def __init__(self, name, retval, parameters, throws, ctype=None):
1044         Callable.__init__(self, name, retval, parameters, throws)
1045         self.ctype = ctype