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