2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
4 # Copyright (C) 2008, 2009 Red Hat, Inc.
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.
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.
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.
22 from .odict import odict
23 from .utils import to_underscores
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. An
31 unresolved type can have two data sources; a "ctype" which comes
32 from a C type string, or a gtype_name (from g_type_name()).
38 target_fundamental=None,
41 _target_unknown=False,
45 self.gtype_name = gtype_name
46 self.origin_symbol = origin_symbol
48 assert isinstance(self, TypeUnknown)
49 elif target_fundamental:
50 assert target_giname is None
51 assert target_foreign is None
53 assert '.' in target_giname
54 assert target_fundamental is None
55 assert target_foreign is None
57 assert ctype is not None
58 assert target_giname is None
59 assert target_fundamental is None
61 assert (ctype is not None) or (gtype_name is not None)
62 self.target_fundamental = target_fundamental
63 self.target_giname = target_giname
64 self.target_foreign = target_foreign
65 self.is_const = is_const
69 return (self.target_fundamental or
74 def unresolved_string(self):
78 return self.gtype_name
83 def create_from_gtype_name(cls, gtype_name):
84 """Parse a GType name (as from g_type_name()), and return a
85 Type instance. Note that this function performs namespace lookup,
86 in contrast to the other create_type() functions."""
87 # First, is it a fundamental?
88 fundamental = type_names.get(gtype_name)
89 if fundamental is not None:
90 return cls(target_fundamental=fundamental.target_fundamental)
91 return cls(gtype_name=gtype_name)
94 assert self.target_giname is not None
95 return self.target_giname.split('.')[1]
97 def __cmp__(self, other):
98 if self.target_fundamental:
99 return cmp(self.target_fundamental, other.target_fundamental)
100 if self.target_giname:
101 return cmp(self.target_giname, other.target_giname)
102 if self.target_foreign:
103 return cmp(self.target_foreign, other.target_foreign)
104 return cmp(self.ctype, other.ctype)
106 def is_equiv(self, typeval):
107 """Return True if the specified types are compatible at
108 an introspection level, disregarding their C types.
109 A sequence may be given for typeval, in which case
110 this function returns True if the type is compatible with
112 if isinstance(typeval, (list, tuple)):
114 if self.is_equiv(val):
117 return self == typeval
120 return Type(target_fundamental=self.target_fundamental,
121 target_giname=self.target_giname,
122 target_foreign=self.target_foreign,
124 is_const=self.is_const)
127 if self.target_fundamental:
128 return self.target_fundamental
129 elif self.target_giname:
130 return self.target_giname
131 elif self.target_foreign:
132 return self.target_foreign
135 if self.target_fundamental:
136 data = 'target_fundamental=%s, ' % (self.target_fundamental, )
137 elif self.target_giname:
138 data = 'target_giname=%s, ' % (self.target_giname, )
139 elif self.target_foreign:
140 data = 'target_foreign=%s, ' % (self.target_foreign, )
143 return '%s(%sctype=%s)' % (self.__class__.__name__, data, self.ctype)
145 class TypeUnknown(Type):
147 Type.__init__(self, _target_unknown=True)
153 TYPE_NONE = Type(target_fundamental='none', ctype='void')
154 TYPE_ANY = Type(target_fundamental='gpointer', ctype='gpointer')
156 TYPE_BOOLEAN = Type(target_fundamental='gboolean', ctype='gboolean')
157 TYPE_INT8 = Type(target_fundamental='gint8', ctype='gint8')
158 TYPE_UINT8 = Type(target_fundamental='guint8', ctype='guint8')
159 TYPE_INT16 = Type(target_fundamental='gint16', ctype='gint16')
160 TYPE_UINT16 = Type(target_fundamental='guint16', ctype='guint16')
161 TYPE_INT32 = Type(target_fundamental='gint32', ctype='gint32')
162 TYPE_UINT32 = Type(target_fundamental='guint32', ctype='guint32')
163 TYPE_INT64 = Type(target_fundamental='gint64', ctype='gint64')
164 TYPE_UINT64 = Type(target_fundamental='guint64', ctype='guint64')
165 TYPE_CHAR = Type(target_fundamental='gchar', ctype='gchar')
166 TYPE_SHORT = Type(target_fundamental='gshort', ctype='gshort')
167 TYPE_USHORT = Type(target_fundamental='gushort', ctype='gushort')
168 TYPE_INT = Type(target_fundamental='gint', ctype='gint')
169 TYPE_UINT = Type(target_fundamental='guint', ctype='guint')
170 TYPE_LONG = Type(target_fundamental='glong', ctype='glong')
171 TYPE_ULONG = Type(target_fundamental='gulong', ctype='gulong')
173 TYPE_LONG_LONG = Type(target_fundamental='long long', ctype='long long')
174 TYPE_LONG_ULONG = Type(target_fundamental='unsigned long long',
175 ctype='unsigned long long')
176 TYPE_FLOAT = Type(target_fundamental='gfloat', ctype='gfloat')
177 TYPE_DOUBLE = Type(target_fundamental='gdouble', ctype='gdouble')
179 TYPE_LONG_DOUBLE = Type(target_fundamental='long double',
181 TYPE_UNICHAR = Type(target_fundamental='gunichar', ctype='gunichar')
183 # C types with semantics overlaid
184 TYPE_GTYPE = Type(target_fundamental='GType', ctype='GType')
185 TYPE_STRING = Type(target_fundamental='utf8', ctype='gchar*')
186 TYPE_FILENAME = Type(target_fundamental='filename', ctype='gchar*')
188 TYPE_VALIST = Type(target_fundamental='va_list', ctype='va_list')
190 BASIC_GIR_TYPES = [TYPE_BOOLEAN, TYPE_INT8, TYPE_UINT8, TYPE_INT16,
191 TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64,
192 TYPE_UINT64, TYPE_CHAR, TYPE_SHORT, TYPE_USHORT, TYPE_INT,
193 TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_LONG_LONG,
194 TYPE_LONG_ULONG, TYPE_FLOAT, TYPE_DOUBLE,
195 TYPE_LONG_DOUBLE, TYPE_UNICHAR, TYPE_GTYPE]
196 GIR_TYPES = [TYPE_NONE, TYPE_ANY]
197 GIR_TYPES.extend(BASIC_GIR_TYPES)
198 GIR_TYPES.extend([TYPE_STRING, TYPE_FILENAME, TYPE_VALIST])
200 INTROSPECTABLE_BASIC = list(GIR_TYPES)
201 for v in [TYPE_NONE, TYPE_ANY,
202 TYPE_LONG_LONG, TYPE_LONG_ULONG,
203 TYPE_LONG_DOUBLE, TYPE_VALIST]:
204 INTROSPECTABLE_BASIC.remove(v)
207 for typeval in GIR_TYPES:
208 type_names[typeval.target_fundamental] = typeval
209 basic_type_names = {}
210 for typeval in BASIC_GIR_TYPES:
211 basic_type_names[typeval.target_fundamental] = typeval
214 type_names['char'] = TYPE_CHAR
215 type_names['signed char'] = TYPE_INT8
216 type_names['unsigned char'] = TYPE_UINT8
217 type_names['short'] = TYPE_SHORT
218 type_names['signed short'] = TYPE_SHORT
219 type_names['unsigned short'] = TYPE_USHORT
220 type_names['int'] = TYPE_INT
221 type_names['signed int'] = TYPE_INT
222 type_names['unsigned short int'] = TYPE_USHORT
223 type_names['signed'] = TYPE_INT
224 type_names['unsigned int'] = TYPE_UINT
225 type_names['unsigned'] = TYPE_UINT
226 type_names['long'] = TYPE_LONG
227 type_names['signed long'] = TYPE_LONG
228 type_names['unsigned long'] = TYPE_ULONG
229 type_names['unsigned long int'] = TYPE_ULONG
230 type_names['float'] = TYPE_FLOAT
231 type_names['double'] = TYPE_DOUBLE
232 type_names['char*'] = TYPE_STRING
233 type_names['void*'] = TYPE_ANY
234 type_names['void'] = TYPE_NONE
235 # Also alias the signed one here
236 type_names['signed long long'] = TYPE_LONG_LONG
238 # A few additional GLib type aliases
239 type_names['guchar'] = TYPE_UINT8
240 type_names['gchararray'] = TYPE_STRING
241 type_names['gchar*'] = TYPE_STRING
242 type_names['goffset'] = TYPE_INT64
243 type_names['gunichar2'] = TYPE_UINT16
244 type_names['gsize'] = TYPE_ULONG
245 type_names['gssize'] = TYPE_LONG
246 type_names['gconstpointer'] = TYPE_ANY
248 # C stdio, used in GLib public headers; squash this for now here
249 # until we move scanning into GLib and can (skip)
250 type_names['FILE*'] = TYPE_ANY
252 # One off C unix type definitions; note some of these may be GNU Libc
253 # specific. If someone is actually bitten by this, feel free to do
254 # the required configure goop to determine their size and replace
257 # We don't want to encourage people to use these in their APIs because
258 # they compromise the platform-independence that GLib gives you.
259 # These are here mostly to avoid blowing when random platform-specific
260 # methods are added under #ifdefs inside GLib itself. We could just (skip)
261 # the relevant methods, but on the other hand, since these types are just
262 # integers it's easy enough to expand them.
263 type_names['size_t'] = type_names['gsize']
264 type_names['time_t'] = TYPE_LONG
265 type_names['off_t'] = type_names['gsize']
266 type_names['pid_t'] = TYPE_INT
267 type_names['uid_t'] = TYPE_UINT
268 type_names['gid_t'] = TYPE_UINT
269 type_names['dev_t'] = TYPE_INT
270 type_names['socklen_t'] = TYPE_INT32
271 type_names['size_t'] = TYPE_ULONG
272 type_names['ssize_t'] = TYPE_LONG
275 type_names['id'] = TYPE_ANY
281 PARAM_DIRECTION_IN = 'in'
282 PARAM_DIRECTION_OUT = 'out'
283 PARAM_DIRECTION_INOUT = 'inout'
285 PARAM_SCOPE_CALL = 'call'
286 PARAM_SCOPE_ASYNC = 'async'
287 PARAM_SCOPE_NOTIFIED = 'notified'
289 PARAM_TRANSFER_NONE = 'none'
290 PARAM_TRANSFER_CONTAINER = 'container'
291 PARAM_TRANSFER_FULL = 'full'
293 class Namespace(object):
294 def __init__(self, name, version,
295 identifier_prefixes=None,
296 symbol_prefixes=None):
298 self.version = version
299 if identifier_prefixes is not None:
300 self.identifier_prefixes = identifier_prefixes
302 self.identifier_prefixes = [name]
303 if symbol_prefixes is not None:
304 self.symbol_prefixes = symbol_prefixes
306 ps = self.identifier_prefixes
307 self.symbol_prefixes = [to_underscores(p).lower() for p in ps]
308 self._names = odict() # Maps from GIName -> node
309 self._aliases = {} # Maps from GIName -> GIName
310 self._type_names = {} # Maps from GTName -> node
311 self._ctypes = {} # Maps from CType -> node
312 self._symbols = {} # Maps from function symbols -> Function
323 def type_names(self):
324 return self._type_names
330 def type_from_name(self, name, ctype=None):
331 """Backwards compatibility method for older .gir files, which
332 only use the 'name' attribute. If name refers to a fundamental type,
333 create a Type object referncing it. If name is already a
334 fully-qualified GIName like 'Foo.Bar', returns a Type targeting it .
335 Otherwise a Type targeting name qualififed with the namespace name is
337 if name in type_names:
338 return Type(target_fundamental=name, ctype=ctype)
342 target = '%s.%s' % (self.name, name)
343 return Type(target_giname=target, ctype=ctype)
345 def contains_ident(self, ident):
346 """Return True if this namespace should contain the given C
347 identifier string."""
348 return any(ident.startswith(prefix) for prefix in self.identifier_prefixes)
350 def append(self, node, replace=False):
351 previous = self._names.get(node.name)
352 if previous is not None:
354 raise ValueError("Namespace conflict")
355 self.remove(previous)
356 # A layering violation...but oh well.
357 from .glibast import GLibBoxed
358 if isinstance(node, Alias):
359 self._aliases[node.name] = node
360 elif isinstance(node, (GLibBoxed, Interface, Class)):
361 self._type_names[node.type_name] = node
362 elif isinstance(node, Function):
363 self._symbols[node.symbol] = node
364 assert isinstance(node, Node)
365 assert node.namespace is None
366 node.namespace = self
367 self._names[node.name] = node
368 if hasattr(node, 'ctype'):
369 self._ctypes[node.ctype] = node
370 if hasattr(node, 'symbol'):
371 self._ctypes[node.symbol] = node
373 def remove(self, node):
374 from .glibast import GLibBoxed
375 if isinstance(node, Alias):
376 del self._aliases[node.name]
377 elif isinstance(node, (GLibBoxed, Interface, Class)):
378 del self._type_names[node.type_name]
379 del self._names[node.name]
380 node.namespace = None
381 if hasattr(node, 'ctype'):
382 del self._ctypes[node.ctype]
383 if isinstance(node, Function):
384 del self._symbols[node.symbol]
386 def float(self, node):
387 """Like remove(), but doesn't unset the node's namespace
388 back-reference, and it's still possible to look up
389 functions via get_by_symbol()."""
390 if isinstance(node, Function):
393 self._symbols[symbol] = node
394 node.namespace = self
397 return iter(self._names)
400 return self._names.iteritems()
402 def itervalues(self):
403 return self._names.itervalues()
406 return self._names.get(name)
408 def get_by_ctype(self, ctype):
409 return self._ctypes.get(ctype)
411 def get_by_symbol(self, symbol):
412 return self._symbols.get(symbol)
414 def walk(self, callback):
415 for node in self.itervalues():
416 node.walk(callback, [])
418 class Include(object):
420 def __init__(self, name, version):
422 self.version = version
425 def from_string(cls, string):
426 return cls(*string.split('-', 1))
428 def __cmp__(self, other):
429 namecmp = cmp(self.name, other.name)
432 return cmp(self.version, other.version)
435 return hash(str(self))
438 return '%s-%s' % (self.name, self.version)
440 class Annotated(object):
441 """An object which has a few generic metadata
446 self.introspectable = True
447 self.attributes = [] # (key, value)*
448 self.deprecated = None
449 self.deprecated_version = None
452 class Node(Annotated):
453 """A node is a type of object which is uniquely identified by its
454 (namespace, name) pair. When combined with a ., this is called a
455 GIName. It's possible for nodes to contain or point to other nodes."""
457 c_name = property(lambda self: self.namespace.name + self.name)
458 gi_name = property(lambda self: '%s.%s' % (self.namespace.name, self.name))
460 def __init__(self, name=None):
461 Annotated.__init__(self)
462 self.namespace = None # Should be set later by Namespace.append()
465 self.file_positions = set()
467 def create_type(self):
468 """Create a Type object referencing this node."""
469 assert self.namespace is not None
470 return Type(target_giname=('%s.%s' % (self.namespace.name, self.name)))
472 def __cmp__(self, other):
473 nscmp = cmp(self.namespace, other.namespace)
476 return cmp(self.name, other.name)
479 return '%s(%r)' % (self.__class__.__name__, self.name)
481 def remove_matching_children(self, pred):
484 def inherit_file_positions(self, node):
485 self.file_positions.update(node.file_positions)
487 def add_file_position(self, filename, line, column):
488 self.file_positions.add((filename, line, column))
490 def add_symbol_reference(self, symbol):
491 if symbol.source_filename:
492 self.add_file_position(symbol.source_filename, symbol.line, -1)
494 def walk(self, callback, chain):
495 res = callback(self, chain)
496 assert res in (True, False), "Walk function must return boolean, not %r" % (res, )
500 self._walk(callback, chain)
503 def _walk(self, callback, chain):
506 class Callable(Node):
508 def __init__(self, name, retval, parameters, throws):
509 Node.__init__(self, name)
511 self.parameters = parameters
512 self.throws = not not throws
514 def get_parameter_index(self, name):
515 for i, parameter in enumerate(self.parameters):
516 if parameter.argname == name:
518 raise ValueError("Unknown argument %s" % (name, ))
520 def get_parameter(self, name):
521 for parameter in self.parameters:
522 if parameter.argname == name:
524 raise ValueError("Unknown argument %s" % (name, ))
527 class Function(Callable):
529 def __init__(self, name, retval, parameters, throws, symbol):
530 Callable.__init__(self, name, retval, parameters, throws)
532 self.is_method = False
533 self.is_constructor = False
534 self.shadowed_by = None # C symbol string
535 self.shadows = None # C symbol string
538 class VFunction(Callable):
540 def __init__(self, name, retval, parameters, throws):
541 Callable.__init__(self, name, retval, parameters, throws)
545 def from_callback(cls, cb):
546 obj = cls(cb.name, cb.retval, cb.parameters[1:],
555 Type.__init__(self, '<varargs>', target_fundamental='<varargs>')
560 GLIB_ARRAY = 'GLib.Array'
561 GLIB_BYTEARRAY = 'GLib.ByteArray'
562 GLIB_PTRARRAY = 'GLib.PtrArray'
564 def __init__(self, array_type, element_type, **kwargs):
565 Type.__init__(self, target_fundamental='<array>',
567 if (array_type is None or array_type == self.C):
568 self.array_type = self.C
570 assert array_type in (self.GLIB_ARRAY,
573 self.array_type = array_type
574 assert isinstance(element_type, Type)
575 self.element_type = element_type
576 self.zeroterminated = True
577 self.length_param_name = None
581 arr = Array(self.array_type, self.element_type)
582 arr.element_type = self.element_type
583 arr.zeroterminated = self.zeroterminated
584 arr.length_param_name = self.length_param_name
590 def __init__(self, name, element_type, **kwargs):
591 Type.__init__(self, target_fundamental='<list>',
594 assert isinstance(element_type, Type)
595 self.element_type = element_type
598 l = List(self.name, self.element_type)
599 l.element_type = self.element_type
600 l.zeroterminated = self.zeroterminated
601 l.length_param_name = self.length_param_name
607 def __init__(self, key_type, value_type, **kwargs):
608 Type.__init__(self, target_fundamental='<map>', **kwargs)
609 assert isinstance(key_type, Type)
610 self.key_type = key_type
611 assert isinstance(value_type, Type)
612 self.value_type = value_type
615 m = Map(self.key_type, self.value_type)
620 def __init__(self, name, target, ctype=None):
621 Node.__init__(self, name)
626 class TypeContainer(Annotated):
627 """A fundamental base class for Return and Parameter."""
629 def __init__(self, typenode, transfer):
630 Annotated.__init__(self)
632 if transfer is not None:
633 self.transfer = transfer
634 elif typenode.is_const:
635 self.transfer = PARAM_TRANSFER_NONE
640 class Parameter(TypeContainer):
641 """An argument to a function."""
643 def __init__(self, argname, typenode, direction=None,
644 transfer=None, allow_none=False, scope=None,
645 caller_allocates=False):
646 TypeContainer.__init__(self, typenode, transfer)
647 self.argname = argname
648 self.direction = direction
649 self.allow_none = allow_none
651 self.caller_allocates = caller_allocates
652 self.closure_name = None
653 self.destroy_name = None
656 class Return(TypeContainer):
657 """A return value from a function."""
659 def __init__(self, rtype, transfer=None):
660 TypeContainer.__init__(self, rtype, transfer)
661 self.direction = PARAM_DIRECTION_OUT
666 def __init__(self, name, symbol, members):
667 Node.__init__(self, name)
669 self.members = members
672 class Bitfield(Node):
674 def __init__(self, name, symbol, members):
675 Node.__init__(self, name)
677 self.members = members
680 class Member(Annotated):
682 def __init__(self, name, value, symbol):
683 Annotated.__init__(self)
688 def __cmp__(self, other):
689 return cmp(self.name, other.name)
694 def __init__(self, name, symbol, disguised=False):
695 Node.__init__(self, name)
697 self.constructors = []
699 self.disguised = disguised
701 self.static_methods = []
703 def _walk(self, callback, chain):
704 for ctor in self.constructors:
705 ctor.walk(callback, chain)
706 for func in self.methods:
707 func.walk(callback, chain)
708 for func in self.static_methods:
709 func.walk(callback, chain)
710 for field in self.fields:
711 if field.anonymous_node is not None:
712 field.anonymous_node.walk(callback, chain)
714 def remove_matching_children(self, pred):
715 self.fields = filter(pred, self.fields)
716 self.constructors = filter(pred, self.constructors)
717 self.methods = filter(pred, self.methods)
720 class Field(Annotated):
722 def __init__(self, name, typenode, readable, writable, bits=None,
723 anonymous_node=None):
724 Annotated.__init__(self)
725 assert (typenode or anonymous_node)
728 self.readable = readable
729 self.writable = writable
731 self.anonymous_node = anonymous_node
733 def __cmp__(self, other):
734 return cmp(self.name, other.name)
739 def __init__(self, name, parent, is_abstract):
740 Node.__init__(self, name)
742 self.c_symbol_prefix = None
744 # When we're in the scanner, we keep around a list
745 # of parents so that we can transparently fall back
746 # if there are 'hidden' parents
747 self.parent_chain = []
748 self.glib_type_struct = None
749 self.is_abstract = is_abstract
751 self.virtual_methods = []
752 self.static_methods = []
754 self.constructors = []
758 def remove_matching_children(self, pred):
759 self.methods = filter(pred, self.methods)
760 self.constructors = filter(pred, self.constructors)
761 self.properties = filter(pred, self.properties)
762 self.fields = filter(pred, self.fields)
764 def _walk(self, callback, chain):
765 for meth in self.methods:
766 meth.walk(callback, chain)
767 for meth in self.virtual_methods:
768 meth.walk(callback, chain)
769 for meth in self.static_methods:
770 meth.walk(callback, chain)
771 for ctor in self.constructors:
772 ctor.walk(callback, chain)
773 for field in self.fields:
774 if field.anonymous_node:
775 field.anonymous_node.walk(callback, chain)
777 class Interface(Node):
779 def __init__(self, name, parent):
780 Node.__init__(self, name)
781 self.c_symbol_prefix = None
783 self.parent_chain = []
785 self.static_methods = []
786 self.virtual_methods = []
787 self.glib_type_struct = None
790 self.prerequisites = []
792 def _walk(self, callback, chain):
793 for meth in self.methods:
794 meth.walk(callback, chain)
795 for meth in self.static_methods:
796 meth.walk(callback, chain)
797 for meth in self.virtual_methods:
798 meth.walk(callback, chain)
799 for field in self.fields:
800 if field.anonymous_node:
801 field.anonymous_node.walk(callback, chain)
803 class Constant(Node):
805 def __init__(self, name, value_type, value):
806 Node.__init__(self, name)
807 self.value_type = value_type
811 class Property(Node):
813 def __init__(self, name, typeobj, readable, writable,
814 construct, construct_only, transfer=None):
815 Node.__init__(self, name)
817 self.readable = readable
818 self.writable = writable
819 self.construct = construct
820 self.construct_only = construct_only
821 self.transfer = PARAM_TRANSFER_NONE
824 class Callback(Callable):
826 def __init__(self, name, retval, parameters, throws, ctype=None):
827 Callable.__init__(self, name, retval, parameters, throws)
833 def __init__(self, name, symbol):
834 Node.__init__(self, name)
836 self.constructors = []
838 self.static_methods = []
841 def _walk(self, callback, chain):
842 for ctor in self.constructors:
843 ctor.walk(callback, chain)
844 for meth in self.methods:
845 meth.walk(callback, chain)
846 for meth in self.static_methods:
847 meth.walk(callback, chain)
848 for field in self.fields:
849 if field.anonymous_node:
850 field.anonymous_node.walk(callback, chain)