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