bd476cc78b207ffdcde786dae33f2160ee10b326
[platform/upstream/gobject-introspection.git] / giscanner / transformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import os
22 import sys
23
24 from . import ast
25 from . import message
26 from .cachestore import CacheStore
27 from .girparser import GIRParser
28 from .sourcescanner import (
29     SourceSymbol, ctype_name, CTYPE_POINTER,
30     CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF,
31     CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT,
32     CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT,
33     CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT,
34     CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST,
35     TYPE_QUALIFIER_CONST, TYPE_QUALIFIER_VOLATILE)
36
37
38 class TransformerException(Exception):
39     pass
40
41
42 _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(os.pathsep)]
43 _xdg_data_dirs.append(DATADIR)
44
45 if os.name != 'nt':
46     _xdg_data_dirs.append('/usr/share')
47
48
49 class Transformer(object):
50     namespace = property(lambda self: self._namespace)
51
52     def __init__(self, namespace, accept_unprefixed=False):
53         self._cachestore = CacheStore()
54         self._accept_unprefixed = accept_unprefixed
55         self._namespace = namespace
56         self._pkg_config_packages = set()
57         self._typedefs_ns = {}
58         self._parsed_includes = {}  # <string namespace -> Namespace>
59         self._includepaths = []
60         self._passthrough_mode = False
61
62     def get_pkgconfig_packages(self):
63         return self._pkg_config_packages
64
65     def disable_cache(self):
66         self._cachestore = None
67
68     def set_passthrough_mode(self):
69         self._passthrough_mode = True
70
71     def _append_new_node(self, node):
72         original = self._namespace.get(node.name)
73         # Special case constants here; we allow duplication to sort-of
74         # handle #ifdef.  But this introduces an arch-dependency in the .gir
75         # file.  So far this has only come up scanning glib - in theory, other
76         # modules will just depend on that.
77         if isinstance(original, ast.Constant) and isinstance(node, ast.Constant):
78             pass
79         elif original:
80             positions = set()
81             positions.update(original.file_positions)
82             positions.update(node.file_positions)
83             message.fatal("Namespace conflict for '%s'" % (node.name, ),
84                           positions)
85         else:
86             self._namespace.append(node)
87
88     def parse(self, symbols):
89         for symbol in symbols:
90             ## WORKAROUND ##
91             # https://bugzilla.gnome.org/show_bug.cgi?id=550616
92             if symbol.ident in ['gst_g_error_get_type']:
93                 continue
94             node = self._traverse_one(symbol)
95             if node:
96                 self._append_new_node(node)
97
98         # Now look through the namespace for things like
99         # typedef struct _Foo Foo;
100         # where we've never seen the struct _Foo.  Just create
101         # an empty structure for these as "disguised"
102         # If we do have a class/interface, merge fields
103         for typedef, compound in self._typedefs_ns.iteritems():
104             ns_compound = self._namespace.get(compound.name)
105             if not ns_compound:
106                 ns_compound = self._namespace.get('_' + compound.name)
107             if (not ns_compound and isinstance(compound, (ast.Record, ast.Union))
108             and len(compound.fields) == 0):
109                 disguised = ast.Record(compound.name, typedef, disguised=True)
110                 self._namespace.append(disguised)
111             elif not ns_compound:
112                 self._namespace.append(compound)
113             elif isinstance(ns_compound, (ast.Record, ast.Union)) and len(ns_compound.fields) == 0:
114                 ns_compound.fields = compound.fields
115         self._typedefs_ns = None
116
117     def set_include_paths(self, paths):
118         self._includepaths = list(paths)
119
120     def register_include(self, include):
121         if include in self._namespace.includes:
122             return
123         self._namespace.includes.add(include)
124         filename = self._find_include(include)
125         self._parse_include(filename)
126
127     def register_include_uninstalled(self, include_path):
128         basename = os.path.basename(include_path)
129         if not basename.endswith('.gir'):
130             raise SystemExit("Include path %r must be a filename path "
131                              "ending in .gir" % (include_path, ))
132         girname = basename[:-4]
133         include = ast.Include.from_string(girname)
134         if include in self._namespace.includes:
135             return
136         self._namespace.includes.add(include)
137         self._parse_include(include_path, uninstalled=True)
138
139     def lookup_giname(self, name):
140         """Given a name of the form Foo or Bar.Foo,
141 return the corresponding ast.Node, or None if none
142 available.  Will throw KeyError however for unknown
143 namespaces."""
144         if '.' not in name:
145             return self._namespace.get(name)
146         else:
147             (ns, giname) = name.split('.', 1)
148             if ns == self._namespace.name:
149                 return self._namespace.get(giname)
150             # Fallback to the main namespace if not a dependency and matches a prefix
151             if ns in self._namespace.identifier_prefixes and not ns in self._parsed_includes:
152                 message.warn(("Deprecated reference to identifier " +
153                               "prefix %s in GIName %s") % (ns, name))
154                 return self._namespace.get(giname)
155             include = self._parsed_includes[ns]
156             return include.get(giname)
157
158     def lookup_typenode(self, typeobj):
159         """Given a Type object, if it points to a giname,
160 calls lookup_giname() on the name.  Otherwise return
161 None."""
162         if typeobj.target_giname:
163             return self.lookup_giname(typeobj.target_giname)
164         return None
165
166     # Private
167
168     def _find_include(self, include):
169         searchdirs = self._includepaths[:]
170         for path in _xdg_data_dirs:
171             searchdirs.append(os.path.join(path, 'gir-1.0'))
172         searchdirs.append(os.path.join(DATADIR, 'gir-1.0'))
173
174         girname = '%s-%s.gir' % (include.name, include.version)
175         for d in searchdirs:
176             path = os.path.join(d, girname)
177             if os.path.exists(path):
178                 return path
179         sys.stderr.write("Couldn't find include %r (search path: %r)\n" % (girname, searchdirs))
180         sys.exit(1)
181
182     @classmethod
183     def parse_from_gir(cls, filename, extra_include_dirs=None):
184         self = cls(None)
185         if extra_include_dirs is not None:
186             self.set_include_paths(extra_include_dirs)
187         self.set_passthrough_mode()
188         self._parse_include(filename)
189         parser = self._cachestore.load(filename)
190         self._namespace = parser.get_namespace()
191         del self._parsed_includes[self._namespace.name]
192         return self
193
194     def _parse_include(self, filename, uninstalled=False):
195         parser = None
196         if self._cachestore is not None:
197             parser = self._cachestore.load(filename)
198         if parser is None:
199             parser = GIRParser(types_only=not self._passthrough_mode)
200             parser.parse(filename)
201             if self._cachestore is not None:
202                 self._cachestore.store(filename, parser)
203
204         for include in parser.get_namespace().includes:
205             if include.name not in self._parsed_includes:
206                 dep_filename = self._find_include(include)
207                 self._parse_include(dep_filename)
208
209         if not uninstalled:
210             for pkg in parser.get_namespace().exported_packages:
211                 self._pkg_config_packages.add(pkg)
212         namespace = parser.get_namespace()
213         self._parsed_includes[namespace.name] = namespace
214
215     def _iter_namespaces(self):
216         """Return an iterator over all included namespaces; the
217 currently-scanned namespace is first."""
218         yield self._namespace
219         for ns in self._parsed_includes.itervalues():
220             yield ns
221
222     def _sort_matches(self, x, y):
223         if x[0] is self._namespace:
224             return 1
225         elif y[0] is self._namespace:
226             return -1
227         return cmp(x[2], y[2])
228
229     def _split_c_string_for_namespace_matches(self, name, is_identifier=False):
230         matches = []  # Namespaces which might contain this name
231         unprefixed_namespaces = []  # Namespaces with no prefix, last resort
232         for ns in self._iter_namespaces():
233             if is_identifier:
234                 prefixes = ns.identifier_prefixes
235             elif name[0].isupper():
236                 prefixes = ns._ucase_symbol_prefixes
237             else:
238                 prefixes = ns.symbol_prefixes
239             if prefixes:
240                 for prefix in prefixes:
241                     if (not is_identifier) and (not prefix.endswith('_')):
242                         prefix = prefix + '_'
243                     if name.startswith(prefix):
244                         matches.append((ns, name[len(prefix):], len(prefix)))
245                         break
246             else:
247                 unprefixed_namespaces.append(ns)
248         if matches:
249             matches.sort(self._sort_matches)
250             return map(lambda x: (x[0], x[1]), matches)
251         elif self._accept_unprefixed:
252             return [(self._namespace, name)]
253         elif unprefixed_namespaces:
254             # A bit of a hack; this function ideally shouldn't look through the
255             # contents of namespaces; but since we aren't scanning anything
256             # without a prefix, it's not too bad.
257             for ns in unprefixed_namespaces:
258                 if name in ns:
259                     return [(ns, name)]
260         raise ValueError("Unknown namespace for %s %r"
261                          % ('identifier' if is_identifier else 'symbol', name, ))
262
263     def split_ctype_namespaces(self, ident):
264         """Given a StudlyCaps string identifier like FooBar, return a
265 list of (namespace, stripped_identifier) sorted by namespace length,
266 or raise ValueError.  As a special case, if the current namespace matches,
267 it is always biggest (i.e. last)."""
268         return self._split_c_string_for_namespace_matches(ident, is_identifier=True)
269
270     def split_csymbol_namespaces(self, symbol):
271         """Given a C symbol like foo_bar_do_baz, return a list of
272 (namespace, stripped_symbol) sorted by namespace match probablity, or
273 raise ValueError."""
274         return self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
275
276     def split_csymbol(self, symbol):
277         """Given a C symbol like foo_bar_do_baz, return the most probable
278 (namespace, stripped_symbol) match, or raise ValueError."""
279         matches = self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
280         return matches[-1]
281
282     def strip_identifier(self, ident):
283         hidden = ident.startswith('_')
284         if hidden:
285             ident = ident[1:]
286         try:
287             matches = self.split_ctype_namespaces(ident)
288         except ValueError as e:
289             raise TransformerException(str(e))
290         for ns, name in matches:
291             if ns is self._namespace:
292                 if hidden:
293                     return '_' + name
294                 return name
295         (ns, name) = matches[-1]
296         raise TransformerException(
297             "Skipping foreign identifier %r from namespace %s" % (ident, ns.name, ))
298         return None
299
300     def _strip_symbol(self, symbol):
301         ident = symbol.ident
302         hidden = ident.startswith('_')
303         if hidden:
304             ident = ident[1:]
305         try:
306             (ns, name) = self.split_csymbol(ident)
307         except ValueError as e:
308             raise TransformerException(str(e))
309         if ns != self._namespace:
310             raise TransformerException(
311                 "Skipping foreign symbol from namespace %s" % (ns.name, ))
312         if hidden:
313             return '_' + name
314         return name
315
316     def _traverse_one(self, symbol, stype=None, parent_symbol=None):
317         assert isinstance(symbol, SourceSymbol), symbol
318
319         if stype is None:
320             stype = symbol.type
321         if stype == CSYMBOL_TYPE_FUNCTION:
322             return self._create_function(symbol)
323         elif stype == CSYMBOL_TYPE_TYPEDEF:
324             return self._create_typedef(symbol)
325         elif stype == CSYMBOL_TYPE_STRUCT:
326             return self._create_struct(symbol)
327         elif stype == CSYMBOL_TYPE_ENUM:
328             return self._create_enum(symbol)
329         elif stype == CSYMBOL_TYPE_MEMBER:
330             return self._create_member(symbol, parent_symbol)
331         elif stype == CSYMBOL_TYPE_UNION:
332             return self._create_union(symbol)
333         elif stype == CSYMBOL_TYPE_CONST:
334             return self._create_const(symbol)
335         # Ignore variable declarations in the header
336         elif stype == CSYMBOL_TYPE_OBJECT:
337             pass
338         else:
339             print 'transformer: unhandled symbol: %r' % (symbol, )
340
341     def _enum_common_prefix(self, symbol):
342         def common_prefix(a, b):
343             commonparts = []
344             for aword, bword in zip(a.split('_'), b.split('_')):
345                 if aword != bword:
346                     return '_'.join(commonparts) + '_'
347                 commonparts.append(aword)
348             return min(a, b)
349
350         # Nothing less than 2 has a common prefix
351         if len(list(symbol.base_type.child_list)) < 2:
352             return None
353         prefix = None
354         for child in symbol.base_type.child_list:
355             if prefix is None:
356                 prefix = child.ident
357             else:
358                 prefix = common_prefix(prefix, child.ident)
359                 if prefix == '':
360                     return None
361         return prefix
362
363     def _create_enum(self, symbol):
364         prefix = self._enum_common_prefix(symbol)
365         if prefix:
366             prefixlen = len(prefix)
367         else:
368             prefixlen = 0
369         members = []
370         for child in symbol.base_type.child_list:
371             if child.private:
372                 continue
373             if prefixlen > 0:
374                 name = child.ident[prefixlen:]
375             else:
376                 # Ok, the enum members don't have a consistent prefix
377                 # among them, so let's just remove the global namespace
378                 # prefix.
379                 try:
380                     name = self._strip_symbol(child)
381                 except TransformerException as e:
382                     message.warn_symbol(symbol, e)
383                     return None
384             members.append(ast.Member(name.lower(),
385                                       child.const_int,
386                                       child.ident,
387                                       None))
388
389         try:
390             enum_name = self.strip_identifier(symbol.ident)
391         except TransformerException as e:
392             message.warn_symbol(symbol, e)
393             return None
394         if symbol.base_type.is_bitfield:
395             klass = ast.Bitfield
396         else:
397             klass = ast.Enum
398         node = klass(enum_name, symbol.ident, members=members)
399         node.add_symbol_reference(symbol)
400         return node
401
402     def _create_function(self, symbol):
403         # Drop functions that start with _ very early on here
404         if symbol.ident.startswith('_'):
405             return None
406         parameters = list(self._create_parameters(symbol, symbol.base_type))
407         return_ = self._create_return(symbol.base_type.base_type)
408         try:
409             name = self._strip_symbol(symbol)
410         except TransformerException as e:
411             message.warn_symbol(symbol, e)
412             return None
413         func = ast.Function(name, return_, parameters, False, symbol.ident)
414         func.add_symbol_reference(symbol)
415         return func
416
417     def _create_source_type(self, source_type):
418         assert source_type is not None
419         if source_type.type == CTYPE_VOID:
420             value = 'void'
421         elif source_type.type == CTYPE_BASIC_TYPE:
422             value = source_type.name
423         elif source_type.type == CTYPE_TYPEDEF:
424             value = source_type.name
425         elif source_type.type == CTYPE_ARRAY:
426             return self._create_source_type(source_type.base_type)
427         elif source_type.type == CTYPE_POINTER:
428             value = self._create_source_type(source_type.base_type) + '*'
429         else:
430             value = 'gpointer'
431         return value
432
433     def _create_complete_source_type(self, source_type):
434         assert source_type is not None
435
436         const = (source_type.type_qualifier & TYPE_QUALIFIER_CONST)
437         volatile = (source_type.type_qualifier & TYPE_QUALIFIER_VOLATILE)
438
439         if source_type.type == CTYPE_VOID:
440             return 'void'
441         elif source_type.type in [CTYPE_BASIC_TYPE,
442                                   CTYPE_TYPEDEF,
443                                   CTYPE_STRUCT,
444                                   CTYPE_UNION,
445                                   CTYPE_ENUM]:
446             value = source_type.name
447             if not value:
448                 value = 'gpointer'
449             if const:
450                 value = 'const ' + value
451             if volatile:
452                 value = 'volatile ' + value
453         elif source_type.type == CTYPE_ARRAY:
454             return self._create_complete_source_type(source_type.base_type)
455         elif source_type.type == CTYPE_POINTER:
456             value = self._create_complete_source_type(source_type.base_type) + '*'
457             # TODO: handle pointer to function as a special case?
458             if const:
459                 value += ' const'
460             if volatile:
461                 value += ' volatile'
462
463         else:
464             if const:
465                 value = 'gconstpointer'
466             else:
467                 value = 'gpointer'
468             if volatile:
469                 value = 'volatile ' + value
470             return value
471
472         return value
473
474     def _create_parameters(self, symbol, base_type):
475         # warn if we see annotations for unknown parameters
476         param_names = set(child.ident for child in base_type.child_list)
477         for i, child in enumerate(base_type.child_list):
478             yield self._create_parameter(symbol, i, child)
479
480     def _synthesize_union_type(self, symbol, parent_symbol):
481         # Synthesize a named union so that it can be referenced.
482         parent_ident = parent_symbol.ident
483         # FIXME: Should split_ctype_namespaces handle the hidden case?
484         hidden = parent_ident.startswith('_')
485         if hidden:
486             parent_ident = parent_ident[1:]
487         matches = self.split_ctype_namespaces(parent_ident)
488         (namespace, parent_name) = matches[-1]
489         assert namespace and parent_name
490         if hidden:
491             parent_name = '_' + parent_name
492         fake_union = ast.Union("%s__%s__union" % (parent_name, symbol.ident))
493         # _parse_fields accesses <type>.base_type.child_list, so we have to
494         # pass symbol.base_type even though that refers to the array, not the
495         # union.
496         self._parse_fields(symbol.base_type, fake_union)
497         self._append_new_node(fake_union)
498         fake_type = ast.Type(
499             target_giname="%s.%s" % (namespace.name, fake_union.name))
500         return fake_type
501
502     def _create_member(self, symbol, parent_symbol=None):
503         source_type = symbol.base_type
504         if (source_type.type == CTYPE_POINTER
505         and symbol.base_type.base_type.type == CTYPE_FUNCTION):
506             node = self._create_callback(symbol, member=True)
507         elif source_type.type == CTYPE_STRUCT and source_type.name is None:
508             node = self._create_struct(symbol, anonymous=True)
509         elif source_type.type == CTYPE_UNION and source_type.name is None:
510             node = self._create_union(symbol, anonymous=True)
511         else:
512             # Special handling for fields; we don't have annotations on them
513             # to apply later, yet.
514             if source_type.type == CTYPE_ARRAY:
515                 complete_ctype = self._create_complete_source_type(source_type)
516                 # If the array contains anonymous unions, like in the GValue
517                 # struct, we need to handle this specially.  This is necessary
518                 # to be able to properly calculate the size of the compound
519                 # type (e.g. GValue) that contains this array, see
520                 # <https://bugzilla.gnome.org/show_bug.cgi?id=657040>.
521                 if (source_type.base_type.type == CTYPE_UNION
522                 and source_type.base_type.name is None):
523                     synthesized_type = self._synthesize_union_type(symbol, parent_symbol)
524                     ftype = ast.Array(None, synthesized_type, complete_ctype=complete_ctype)
525                 else:
526                     ctype = self._create_source_type(source_type)
527                     canonical_ctype = self._canonicalize_ctype(ctype)
528                     if canonical_ctype[-1] == '*':
529                         derefed_name = canonical_ctype[:-1]
530                     else:
531                         derefed_name = canonical_ctype
532                     if complete_ctype[-1] == '*':
533                         derefed_complete_ctype = complete_ctype[:-1]
534                     else:
535                         derefed_complete_ctype = complete_ctype
536                     from_ctype = self.create_type_from_ctype_string(ctype,
537                                                                     complete_ctype=complete_ctype)
538                     ftype = ast.Array(None, from_ctype,
539                                       ctype=derefed_name,
540                                       complete_ctype=derefed_complete_ctype)
541                 child_list = list(symbol.base_type.child_list)
542                 ftype.zeroterminated = False
543                 if child_list:
544                     ftype.size = child_list[0].const_int
545             else:
546                 ftype = self._create_type_from_base(symbol.base_type)
547             # ast.Fields are assumed to be read-write
548             # (except for Objects, see also glibtransformer.py)
549             node = ast.Field(symbol.ident, ftype,
550                              readable=True, writable=True,
551                              bits=symbol.const_int)
552             if symbol.private:
553                 node.readable = False
554                 node.writable = False
555                 node.private = True
556         return node
557
558     def _create_typedef(self, symbol):
559         ctype = symbol.base_type.type
560         if (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_FUNCTION):
561             node = self._create_typedef_callback(symbol)
562         elif (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_STRUCT):
563             node = self._create_typedef_struct(symbol, disguised=True)
564         elif ctype == CTYPE_STRUCT:
565             node = self._create_typedef_struct(symbol)
566         elif ctype == CTYPE_UNION:
567             node = self._create_typedef_union(symbol)
568         elif ctype == CTYPE_ENUM:
569             return self._create_enum(symbol)
570         elif ctype in (CTYPE_TYPEDEF,
571                        CTYPE_POINTER,
572                        CTYPE_BASIC_TYPE,
573                        CTYPE_VOID):
574             try:
575                 name = self.strip_identifier(symbol.ident)
576             except TransformerException as e:
577                 message.warn(e)
578                 return None
579             if symbol.base_type.name:
580                 complete_ctype = self._create_complete_source_type(symbol.base_type)
581                 target = self.create_type_from_ctype_string(symbol.base_type.name,
582                                                             complete_ctype=complete_ctype)
583             else:
584                 target = ast.TYPE_ANY
585             if name in ast.type_names:
586                 return None
587             return ast.Alias(name, target, ctype=symbol.ident)
588         else:
589             raise NotImplementedError(
590                 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
591         return node
592
593     def _canonicalize_ctype(self, ctype):
594         # First look up the ctype including any pointers;
595         # a few type names like 'char*' have their own aliases
596         # and we need pointer information for those.
597         firstpass = ast.type_names.get(ctype)
598
599         # If we have a particular alias for this, skip deep
600         # canonicalization to prevent changing
601         # e.g. char* -> int8*
602         if firstpass:
603             return firstpass.target_fundamental
604
605         if not ctype.endswith('*'):
606             return ctype
607
608         # We have a pointer type.
609         # Strip the end pointer, canonicalize our base type
610         base = ctype[:-1]
611         canonical_base = self._canonicalize_ctype(base)
612
613         # Append the pointer again
614         canonical = canonical_base + '*'
615
616         return canonical
617
618     def _create_type_from_base(self, source_type, is_parameter=False, is_return=False):
619         ctype = self._create_source_type(source_type)
620         complete_ctype = self._create_complete_source_type(source_type)
621         const = ((source_type.type == CTYPE_POINTER) and
622                  (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST))
623         return self.create_type_from_ctype_string(ctype, is_const=const,
624                                                   is_parameter=is_parameter, is_return=is_return,
625                                                   complete_ctype=complete_ctype)
626
627     def _create_bare_container_type(self, base, ctype=None,
628                                     is_const=False, complete_ctype=None):
629         if base in ('GList', 'GSList', 'GLib.List', 'GLib.SList'):
630             if base in ('GList', 'GSList'):
631                 name = 'GLib.' + base[1:]
632             else:
633                 name = base
634             return ast.List(name, ast.TYPE_ANY, ctype=ctype,
635                         is_const=is_const, complete_ctype=complete_ctype)
636         elif base in ('GArray', 'GPtrArray', 'GByteArray',
637                       'GLib.Array', 'GLib.PtrArray', 'GLib.ByteArray',
638                       'GObject.Array', 'GObject.PtrArray', 'GObject.ByteArray'):
639             if '.' in base:
640                 name = 'GLib.' + base.split('.', 1)[1]
641             else:
642                 name = 'GLib.' + base[1:]
643             return ast.Array(name, ast.TYPE_ANY, ctype=ctype,
644                          is_const=is_const, complete_ctype=complete_ctype)
645         elif base in ('GHashTable', 'GLib.HashTable', 'GObject.HashTable'):
646             return ast.Map(ast.TYPE_ANY, ast.TYPE_ANY, ctype=ctype, is_const=is_const,
647                            complete_ctype=complete_ctype)
648         return None
649
650     def create_type_from_ctype_string(self, ctype, is_const=False,
651                                       is_parameter=False, is_return=False,
652                                       complete_ctype=None):
653         canonical = self._canonicalize_ctype(ctype)
654         base = canonical.replace('*', '')
655
656         # Special default: char ** -> ast.Array, same for GStrv
657         if (is_return and canonical == 'utf8*') or base == 'GStrv':
658             bare_utf8 = ast.TYPE_STRING.clone()
659             bare_utf8.ctype = None
660             return ast.Array(None, bare_utf8, ctype=ctype,
661                              is_const=is_const, complete_ctype=complete_ctype)
662
663         fundamental = ast.type_names.get(base)
664         if fundamental is not None:
665             return ast.Type(target_fundamental=fundamental.target_fundamental,
666                         ctype=ctype,
667                         is_const=is_const, complete_ctype=complete_ctype)
668         container = self._create_bare_container_type(base, ctype=ctype, is_const=is_const,
669                                                      complete_ctype=complete_ctype)
670         if container:
671             return container
672         return ast.Type(ctype=ctype, is_const=is_const, complete_ctype=complete_ctype)
673
674     def _create_parameter(self, parent_symbol, index, symbol):
675         if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
676             return ast.Parameter('...', ast.Varargs())
677         else:
678             ptype = self._create_type_from_base(symbol.base_type, is_parameter=True)
679
680             if symbol.ident is None:
681                 if symbol.base_type and symbol.base_type.type != CTYPE_VOID:
682                     message.warn_symbol(parent_symbol, "missing parameter name; undocumentable")
683                 ident = 'arg%d' % (index, )
684             else:
685                 ident = symbol.ident
686
687             return ast.Parameter(ident, ptype)
688
689     def _create_return(self, source_type):
690         typeval = self._create_type_from_base(source_type, is_return=True)
691         return ast.Return(typeval)
692
693     def _create_const(self, symbol):
694         if symbol.ident.startswith('_'):
695             return None
696
697         # Don't create constants for non-public things
698         # http://bugzilla.gnome.org/show_bug.cgi?id=572790
699         if (symbol.source_filename is None or not symbol.source_filename.endswith('.h')):
700             return None
701         try:
702             name = self._strip_symbol(symbol)
703         except TransformerException as e:
704             message.warn_symbol(symbol, e)
705             return None
706         if symbol.const_string is not None:
707             typeval = ast.TYPE_STRING
708             value = unicode(symbol.const_string, 'utf-8')
709         elif symbol.const_int is not None:
710             if symbol.base_type is not None:
711                 typeval = self._create_type_from_base(symbol.base_type)
712             else:
713                 typeval = ast.TYPE_INT
714             unaliased = typeval
715             self._resolve_type_from_ctype(unaliased)
716             if typeval.target_giname and typeval.ctype:
717                 target = self.lookup_giname(typeval.target_giname)
718                 target = self.resolve_aliases(target)
719                 if isinstance(target, ast.Type):
720                     unaliased = target
721             if unaliased == ast.TYPE_UINT64:
722                 value = str(symbol.const_int % 2 ** 64)
723             elif unaliased == ast.TYPE_UINT32:
724                 value = str(symbol.const_int % 2 ** 32)
725             elif unaliased == ast.TYPE_UINT16:
726                 value = str(symbol.const_int % 2 ** 16)
727             elif unaliased == ast.TYPE_UINT8:
728                 value = str(symbol.const_int % 2 ** 16)
729             else:
730                 value = str(symbol.const_int)
731         elif symbol.const_double is not None:
732             typeval = ast.TYPE_DOUBLE
733             value = '%f' % (symbol.const_double, )
734         else:
735             raise AssertionError()
736
737         const = ast.Constant(name, typeval, value,
738                              symbol.ident)
739         const.add_symbol_reference(symbol)
740         return const
741
742     def _create_typedef_struct(self, symbol, disguised=False):
743         try:
744             name = self.strip_identifier(symbol.ident)
745         except TransformerException as e:
746             message.warn_symbol(symbol, e)
747             return None
748         struct = ast.Record(name, symbol.ident, disguised=disguised)
749         self._parse_fields(symbol, struct)
750         struct.add_symbol_reference(symbol)
751         self._typedefs_ns[symbol.ident] = struct
752         return None
753
754     def _create_typedef_union(self, symbol):
755         try:
756             name = self.strip_identifier(symbol.ident)
757         except TransformerException as e:
758             message.warn(e)
759             return None
760         union = ast.Union(name, symbol.ident)
761         self._parse_fields(symbol, union)
762         union.add_symbol_reference(symbol)
763         self._typedefs_ns[symbol.ident] = union
764         return None
765
766     def _create_typedef_callback(self, symbol):
767         callback = self._create_callback(symbol)
768         if not callback:
769             return None
770         self._typedefs_ns[callback.name] = callback
771         return callback
772
773     def _parse_fields(self, symbol, compound):
774         for child in symbol.base_type.child_list:
775             child_node = self._traverse_one(child, parent_symbol=symbol)
776             if not child_node:
777                 continue
778             if isinstance(child_node, ast.Field):
779                 field = child_node
780             else:
781                 field = ast.Field(child.ident, None, True, False,
782                               anonymous_node=child_node)
783             compound.fields.append(field)
784
785     def _create_compound(self, klass, symbol, anonymous):
786         if symbol.ident is None:
787             # the compound is an anonymous member of another union or a struct
788             assert anonymous
789             compound = klass(None, None)
790         else:
791             compound = self._typedefs_ns.get(symbol.ident, None)
792
793         if compound is None:
794             # This is a bit of a hack; really we should try
795             # to resolve through the typedefs to find the real
796             # name
797             if symbol.ident.startswith('_'):
798                 compound = self._typedefs_ns.get(symbol.ident[1:], None)
799             if compound is None:
800                 if anonymous:
801                     name = symbol.ident
802                 else:
803                     try:
804                         name = self.strip_identifier(symbol.ident)
805                     except TransformerException as e:
806                         message.warn(e)
807                         return None
808                 compound = klass(name, symbol.ident)
809
810         self._parse_fields(symbol, compound)
811         compound.add_symbol_reference(symbol)
812         return compound
813
814     def _create_struct(self, symbol, anonymous=False):
815         return self._create_compound(ast.Record, symbol, anonymous)
816
817     def _create_union(self, symbol, anonymous=False):
818         return self._create_compound(ast.Union, symbol, anonymous)
819
820     def _create_callback(self, symbol, member=False):
821         parameters = list(self._create_parameters(symbol, symbol.base_type.base_type))
822         retval = self._create_return(symbol.base_type.base_type.base_type)
823
824         # Mark the 'user_data' arguments
825         for i, param in enumerate(parameters):
826             if (param.type.target_fundamental == 'gpointer' and param.argname == 'user_data'):
827                 param.closure_name = param.argname
828
829         if member:
830             name = symbol.ident
831         elif symbol.ident.find('_') > 0:
832             try:
833                 name = self._strip_symbol(symbol)
834             except TransformerException as e:
835                 message.warn_symbol(symbol, e)
836                 return None
837         else:
838             try:
839                 name = self.strip_identifier(symbol.ident)
840             except TransformerException as e:
841                 message.warn(e)
842                 return None
843         callback = ast.Callback(name, retval, parameters, False,
844                                 ctype=symbol.ident)
845         callback.add_symbol_reference(symbol)
846
847         return callback
848
849     def create_type_from_user_string(self, typestr):
850         """Parse a C type string (as might be given from an
851         annotation) and resolve it.  For compatibility, we can consume
852 both GI type string (utf8, Foo.Bar) style, as well as C (char *, FooBar) style.
853
854 Note that type resolution may not succeed."""
855         if '.' in typestr:
856             container = self._create_bare_container_type(typestr)
857             if container:
858                 typeval = container
859             else:
860                 typeval = self._namespace.type_from_name(typestr)
861         else:
862             typeval = self.create_type_from_ctype_string(typestr)
863
864         self.resolve_type(typeval)
865         if typeval.resolved:
866             # Explicitly clear out the c_type; there isn't one in this case.
867             typeval.ctype = None
868         return typeval
869
870     def _resolve_type_from_ctype_all_namespaces(self, typeval, pointer_stripped):
871         # If we can't determine the namespace from the type name,
872         # fall back to trying all of our includes.  An example of this is mutter,
873         # which has nominal namespace of "Meta", but a few classes are
874         # "Mutter".  We don't export that data in introspection currently.
875         # Basically the library should be fixed, but we'll hack around it here.
876         for namespace in self._parsed_includes.itervalues():
877             target = namespace.get_by_ctype(pointer_stripped)
878             if target:
879                 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
880                 return True
881         return False
882
883     def _resolve_type_from_ctype(self, typeval):
884         assert typeval.ctype is not None
885         pointer_stripped = typeval.ctype.replace('*', '')
886         try:
887             matches = self.split_ctype_namespaces(pointer_stripped)
888         except ValueError:
889             return self._resolve_type_from_ctype_all_namespaces(typeval, pointer_stripped)
890         for namespace, name in matches:
891             target = namespace.get(name)
892             if not target:
893                 target = namespace.get_by_ctype(pointer_stripped)
894             if target:
895                 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
896                 return True
897         return False
898
899     def _resolve_type_from_gtype_name(self, typeval):
900         assert typeval.gtype_name is not None
901         for ns in self._iter_namespaces():
902             node = ns.type_names.get(typeval.gtype_name, None)
903             if node is not None:
904                 typeval.target_giname = '%s.%s' % (ns.name, node.name)
905                 return True
906         return False
907
908     def _resolve_type_internal(self, typeval):
909         if isinstance(typeval, (ast.Array, ast.List)):
910             return self.resolve_type(typeval.element_type)
911         elif isinstance(typeval, ast.Map):
912             key_resolved = self.resolve_type(typeval.key_type)
913             value_resolved = self.resolve_type(typeval.value_type)
914             return key_resolved and value_resolved
915         elif typeval.resolved:
916             return True
917         elif typeval.ctype:
918             return self._resolve_type_from_ctype(typeval)
919         elif typeval.gtype_name:
920             return self._resolve_type_from_gtype_name(typeval)
921
922     def resolve_type(self, typeval):
923         if not self._resolve_type_internal(typeval):
924             return False
925
926         if typeval.target_fundamental or typeval.target_foreign:
927             return True
928
929         assert typeval.target_giname is not None
930
931         try:
932             type_ = self.lookup_giname(typeval.target_giname)
933         except KeyError:
934             type_ = None
935
936         if type_ is None:
937             typeval.target_giname = None
938
939         return typeval.resolved
940
941     def resolve_aliases(self, typenode):
942         """Removes all aliases from typenode, returns first non-alias
943         in the typenode alias chain.  Returns typenode argument if it
944         is not an alias."""
945         while isinstance(typenode, ast.Alias):
946             if typenode.target.target_giname is not None:
947                 typenode = self.lookup_giname(typenode.target.target_giname)
948             elif typenode.target.target_fundamental is not None:
949                 typenode = ast.type_names[typenode.target.target_fundamental]
950             else:
951                 break
952         return typenode