2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
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.
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.
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.
27 from .config import DATADIR, GIR_DIR, GIR_SUFFIX
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,
38 class TypeResolutionException(Exception):
41 _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(':') \
42 + [DATADIR, '/usr/share'] if x]
44 class Transformer(object):
45 namespace = property(lambda self: self._namespace)
47 UCASE_CONSTANT_RE = re.compile(r'[_A-Z0-9]+')
49 def __init__(self, cachestore, namespace_name, namespace_version,
50 identifier_prefixes=None, symbol_prefixes=None,
51 accept_unprefixed=False):
52 self._cwd = os.getcwd() + os.sep
53 self._cachestore = cachestore
55 self._accept_unprefixed = accept_unprefixed
56 self._namespace = ast.Namespace(namespace_name, namespace_version,
57 identifier_prefixes=identifier_prefixes,
58 symbol_prefixes=symbol_prefixes)
59 self._pkg_config_packages = set()
60 self._typedefs_ns = {}
61 self._enable_warnings = False
64 self._include_names = set()
65 self._includepaths = []
67 def get_includes(self):
68 return self._include_names
70 def enable_warnings(self, enable):
71 self._enable_warnings = enable
76 def get_pkgconfig_packages(self):
77 return self._pkg_config_packages
79 def set_source_ast(self, src_ast):
80 self.generator = src_ast
82 def _append_new_node(self, node):
83 original = self._namespace.get(node.name)
84 # Special case constants here; we allow duplication to sort-of
85 # handle #ifdef. But this introduces an arch-dependency in the .gir
86 # file. So far this has only come up scanning glib - in theory, other
87 # modules will just depend on that.
88 if isinstance(original, ast.Constant) and isinstance(node, ast.Constant):
92 positions.update(original.file_positions)
93 positions.update(node.file_positions)
94 self.log_warning("Namespace conflict for '%s'" % (node.name, ),
95 positions, fatal=True)
97 self._namespace.append(node)
100 for symbol in self.generator.get_symbols():
101 node = self._traverse_one(symbol)
103 self._append_new_node(node)
105 # Now look through the namespace for things like
106 # typedef struct _Foo Foo;
107 # where we've never seen the struct _Foo. Just create
108 # an empty structure for these as "disguised"
109 # If we do have a class/interface, merge fields
110 for typedef, compound in self._typedefs_ns.iteritems():
111 ns_compound = self._namespace.get(compound.name)
113 ns_compound = self._namespace.get('_' + compound.name)
114 if (not ns_compound and isinstance(compound, (ast.Record, ast.Union))
115 and len(compound.fields) == 0):
116 disguised = ast.Record(compound.name, typedef, disguised=True)
117 self._namespace.append(disguised)
118 elif not ns_compound:
119 self._namespace.append(compound)
120 elif isinstance(ns_compound, (ast.Record, ast.Union)) and len(ns_compound.fields) == 0:
121 ns_compound.fields = compound.fields
122 self._typedefs_ns = None
124 def set_include_paths(self, paths):
125 self._includepaths = list(paths)
127 def register_include(self, include):
128 if include in self._include_names:
130 filename = self._find_include(include)
131 self._parse_include(filename)
132 self._include_names.add(include)
134 def lookup_giname(self, name):
135 """Given a name of the form Foo or Bar.Foo,
136 return the corresponding ast.Node, or None if none
137 available. Will throw KeyError however for unknown
140 return self._namespace.get(name)
142 (ns, name) = name.split('.', 1)
143 if ns == self._namespace.name:
144 return self._namespace.get(name)
145 include = self._includes[ns]
146 return include.get(name)
148 def lookup_typenode(self, typeobj):
149 """Given a Type object, if it points to a giname,
150 calls lookup_giname() on the name. Otherwise return
152 if typeobj.target_giname:
153 return self.lookup_giname(typeobj.target_giname)
158 def log_warning(self, text, file_positions=None, prefix=None,
160 """Log a warning, using optional file positioning information.
161 If the warning is related to a ast.Node type, see log_node_warning()."""
162 if not fatal and not self._enable_warnings:
167 if file_positions is None or len(file_positions) == 0:
168 target_file_positions = [('<unknown>', -1, -1)]
170 target_file_positions = file_positions
172 position_strings = []
173 for (filename, line, column) in target_file_positions:
174 if filename.startswith(self._cwd):
175 filename = filename[len(self._cwd):]
177 position = '%s:%d:%d' % (filename, line, column)
179 position = '%s:%d' % (filename, line, )
181 position = '%s:' % (filename, )
182 position_strings.append(position)
184 for position in position_strings[:-1]:
185 print >>sys.stderr, "%s:" % (position, )
186 last_position = position_strings[-1]
187 error_type = 'error' if fatal else 'warning'
189 print >>sys.stderr, \
190 '''%s: %s: %s: %s: %s''' % (last_position, error_type, self._namespace.name,
193 print >>sys.stderr, \
194 '''%s: %s: %s: %s''' % (last_position, error_type, self._namespace.name, text)
198 def log_symbol_warning(self, symbol, text, **kwargs):
199 """Log a warning in the context of the given symbol."""
200 if symbol.source_filename:
201 file_positions = [(symbol.source_filename, symbol.line, -1)]
203 file_positions = None
204 prefix = "symbol=%r" % (symbol.ident, )
205 self.log_warning(text, file_positions, prefix=prefix, **kwargs)
207 def log_node_warning(self, node, text, context=None, fatal=False):
208 """Log a warning, using information about file positions from
209 the given node. The optional context argument, if given, should be
210 another ast.Node type which will also be displayed. If no file position
211 information is available from the node, the position data from the
212 context will be used."""
213 if hasattr(node, 'file_positions'):
214 if (len(node.file_positions) == 0 and
215 (context is not None) and len(context.file_positions) > 0):
216 file_positions = context.file_positions
218 file_positions = node.file_positions
220 file_positions = None
222 text = "context=%r %s" % (node, text)
225 if isinstance(context, ast.Function):
226 name = context.symbol
229 text = "%s: %s" % (name, text)
230 elif len(file_positions) == 0 and hasattr(node, 'name'):
231 text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
233 self.log_warning(text, file_positions, fatal=fatal)
235 def _find_include(self, include):
236 searchdirs = self._includepaths[:]
237 for path in _xdg_data_dirs:
238 searchdirs.append(os.path.join(path, GIR_SUFFIX))
239 searchdirs.append(GIR_DIR)
241 girname = '%s-%s.gir' % (include.name, include.version)
243 path = os.path.join(d, girname)
244 if os.path.exists(path):
246 sys.stderr.write("Couldn't find include %r (search path: %r)\n"\
247 % (girname, searchdirs))
250 def _parse_include(self, filename):
251 parser = self._cachestore.load(filename)
254 parser.parse(filename)
255 self._cachestore.store(filename, parser)
257 for include in parser.get_includes():
258 self.register_include(include)
260 for pkg in parser.get_pkgconfig_packages():
261 self._pkg_config_packages.add(pkg)
262 namespace = parser.get_namespace()
263 self._includes[namespace.name] = namespace
265 def _iter_namespaces(self):
266 """Return an iterator over all included namespaces; the
267 currently-scanned namespace is first."""
268 yield self._namespace
269 for ns in self._includes.itervalues():
272 def _sort_matches(self, x, y):
273 if x[0] is self._namespace:
275 elif y[0] is self._namespace:
277 return cmp(x[2], y[2])
279 def _split_c_string_for_namespace_matches(self, name, is_identifier=False):
280 matches = [] # Namespaces which might contain this name
281 unprefixed_namespaces = [] # Namespaces with no prefix, last resort
282 for ns in self._iter_namespaces():
284 prefixes = ns.identifier_prefixes
286 prefixes = ns.symbol_prefixes
288 for prefix in prefixes:
289 if (not is_identifier) and (not prefix.endswith('_')):
290 prefix = prefix + '_'
291 if name.startswith(prefix):
292 matches.append((ns, name[len(prefix):], len(prefix)))
295 unprefixed_namespaces.append(ns)
297 matches.sort(self._sort_matches)
298 return map(lambda x: (x[0], x[1]), matches)
299 elif self._accept_unprefixed:
300 return [(self._namespace, name)]
301 elif unprefixed_namespaces:
302 # A bit of a hack; this function ideally shouldn't look through the
303 # contents of namespaces; but since we aren't scanning anything
304 # without a prefix, it's not too bad.
305 for ns in unprefixed_namespaces:
308 raise ValueError("Unknown namespace for %s %r"
309 % ('identifier' if is_identifier else 'symbol', name, ))
311 def split_ctype_namespaces(self, ident):
312 """Given a StudlyCaps string identifier like FooBar, return a
313 list of (namespace, stripped_identifier) sorted by namespace length,
314 or raise ValueError. As a special case, if the current namespace matches,
315 it is always biggest (i.e. last)."""
316 return self._split_c_string_for_namespace_matches(ident, is_identifier=True)
318 def split_csymbol_namespaces(self, symbol):
319 """Given a C symbol like foo_bar_do_baz, return a list of
320 (namespace, stripped_symbol) sorted by namespace match probablity, or
322 return self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
324 def split_csymbol(self, symbol):
325 """Given a C symbol like foo_bar_do_baz, return the most probable
326 (namespace, stripped_symbol) match, or raise ValueError."""
327 matches = self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
330 def strip_identifier_or_warn(self, ident, fatal=False):
331 hidden = ident.startswith('_')
335 matches = self.split_ctype_namespaces(ident)
336 except ValueError, e:
337 self.log_warning(str(e), fatal=fatal)
339 for ns, name in matches:
340 if ns is self._namespace:
344 (ns, name) = matches[-1]
345 self.log_warning("Skipping foreign identifier %r from namespace %s" % (ident, ns.name, ),
349 def _strip_symbol_or_warn(self, symbol, is_constant=False, fatal=False):
352 # Temporarily lowercase
353 ident = ident.lower()
354 hidden = ident.startswith('_')
358 (ns, name) = self.split_csymbol(ident)
359 except ValueError, e:
360 self.log_symbol_warning(symbol, "Unknown namespace", fatal=fatal)
362 if ns != self._namespace:
363 self.log_symbol_warning(symbol,
364 "Skipping foreign symbol from namespace %s" % (ns.name, ),
373 def _traverse_one(self, symbol, stype=None):
374 assert isinstance(symbol, SourceSymbol), symbol
378 if stype == CSYMBOL_TYPE_FUNCTION:
379 return self._create_function(symbol)
380 elif stype == CSYMBOL_TYPE_TYPEDEF:
381 return self._create_typedef(symbol)
382 elif stype == CSYMBOL_TYPE_STRUCT:
383 return self._create_struct(symbol)
384 elif stype == CSYMBOL_TYPE_ENUM:
385 return self._create_enum(symbol)
386 elif stype == CSYMBOL_TYPE_MEMBER:
387 return self._create_member(symbol)
388 elif stype == CSYMBOL_TYPE_UNION:
389 return self._create_union(symbol)
390 elif stype == CSYMBOL_TYPE_CONST:
391 return self._create_const(symbol)
392 # Ignore variable declarations in the header
393 elif stype == CSYMBOL_TYPE_OBJECT:
396 print 'transformer: unhandled symbol: %r' % (symbol, )
398 def _enum_common_prefix(self, symbol):
399 def common_prefix(a, b):
401 for aword, bword in zip(a.split('_'), b.split('_')):
403 return '_'.join(commonparts) + '_'
404 commonparts.append(aword)
407 # Nothing less than 2 has a common prefix
408 if len(list(symbol.base_type.child_list)) < 2:
411 for child in symbol.base_type.child_list:
415 prefix = common_prefix(prefix, child.ident)
420 def _create_enum(self, symbol):
421 prefix = self._enum_common_prefix(symbol)
423 prefixlen = len(prefix)
427 for child in symbol.base_type.child_list:
429 name = child.ident[prefixlen:]
431 # Ok, the enum members don't have a consistent prefix
432 # among them, so let's just remove the global namespace
434 name = self._strip_symbol_or_warn(child, is_constant=True)
437 members.append(ast.Member(name.lower(),
441 enum_name = self.strip_identifier_or_warn(symbol.ident)
444 if symbol.base_type.is_bitfield:
448 node = klass(enum_name, symbol.ident, members)
449 node.add_symbol_reference(symbol)
452 def _create_function(self, symbol):
453 parameters = list(self._create_parameters(symbol.base_type))
454 return_ = self._create_return(symbol.base_type.base_type)
455 name = self._strip_symbol_or_warn(symbol)
458 func = ast.Function(name, return_, parameters, False, symbol.ident)
459 func.add_symbol_reference(symbol)
462 def _create_source_type(self, source_type):
463 if source_type is None:
465 if source_type.type == CTYPE_VOID:
467 elif source_type.type == CTYPE_BASIC_TYPE:
468 value = source_type.name
469 elif source_type.type == CTYPE_TYPEDEF:
470 value = source_type.name
471 elif source_type.type == CTYPE_ARRAY:
472 return self._create_source_type(source_type.base_type)
473 elif source_type.type == CTYPE_POINTER:
474 value = self._create_source_type(source_type.base_type) + '*'
479 def _create_parameters(self, base_type):
480 # warn if we see annotations for unknown parameters
481 param_names = set(child.ident for child in base_type.child_list)
482 for child in base_type.child_list:
483 yield self._create_parameter(child)
485 def _create_member(self, symbol):
486 source_type = symbol.base_type
487 if (source_type.type == CTYPE_POINTER and
488 symbol.base_type.base_type.type == CTYPE_FUNCTION):
489 node = self._create_callback(symbol, member=True)
490 elif source_type.type == CTYPE_STRUCT and source_type.name is None:
491 node = self._create_struct(symbol, anonymous=True)
492 elif source_type.type == CTYPE_UNION and source_type.name is None:
493 node = self._create_union(symbol, anonymous=True)
495 # Special handling for fields; we don't have annotations on them
496 # to apply later, yet.
497 if source_type.type == CTYPE_ARRAY:
498 ctype = self._create_source_type(source_type)
499 canonical_ctype = self._canonicalize_ctype(ctype)
500 if canonical_ctype[-1] == '*':
501 derefed_name = canonical_ctype[:-1]
503 derefed_name = canonical_ctype
504 ftype = ast.Array(None, self.create_type_from_ctype_string(ctype),
506 child_list = list(symbol.base_type.child_list)
507 ftype.zeroterminated = False
509 ftype.size = child_list[0].const_int
511 ftype = self._create_type_from_base(symbol.base_type)
512 # ast.Fields are assumed to be read-write
513 # (except for Objects, see also glibtransformer.py)
514 node = ast.Field(symbol.ident, ftype,
515 readable=True, writable=True, bits=symbol.const_int)
518 def _create_typedef(self, symbol):
519 ctype = symbol.base_type.type
520 if (ctype == CTYPE_POINTER and
521 symbol.base_type.base_type.type == CTYPE_FUNCTION):
522 node = self._create_typedef_callback(symbol)
523 elif (ctype == CTYPE_POINTER and
524 symbol.base_type.base_type.type == CTYPE_STRUCT):
525 node = self._create_typedef_struct(symbol, disguised=True)
526 elif ctype == CTYPE_STRUCT:
527 node = self._create_typedef_struct(symbol)
528 elif ctype == CTYPE_UNION:
529 node = self._create_typedef_union(symbol)
530 elif ctype == CTYPE_ENUM:
531 return self._create_enum(symbol)
532 elif ctype in (CTYPE_TYPEDEF,
536 name = self.strip_identifier_or_warn(symbol.ident)
539 if symbol.base_type.name:
540 target = self.create_type_from_ctype_string(symbol.base_type.name)
542 target = ast.TYPE_ANY
543 if name in ast.type_names:
545 return ast.Alias(name, target, ctype=symbol.ident)
547 raise NotImplementedError(
548 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
551 def _canonicalize_ctype(self, ctype):
552 # First look up the ctype including any pointers;
553 # a few type names like 'char*' have their own aliases
554 # and we need pointer information for those.
555 firstpass = ast.type_names.get(ctype)
557 # If we have a particular alias for this, skip deep
558 # canonicalization to prevent changing
559 # e.g. char* -> int8*
561 return firstpass.target_fundamental
563 if not ctype.endswith('*'):
566 # We have a pointer type.
567 # Strip the end pointer, canonicalize our base type
569 canonical_base = self._canonicalize_ctype(base)
571 # Append the pointer again
572 canonical = canonical_base + '*'
576 def parse_ctype(self, ctype, is_member=False):
577 canonical = self._canonicalize_ctype(ctype)
579 # Remove all pointers - we require standard calling
580 # conventions. For example, an 'int' is always passed by
581 # value (unless it's out or inout).
582 derefed_typename = canonical.replace('*', '')
584 # Preserve "pointerness" of struct/union members
585 if (is_member and canonical.endswith('*') and
586 derefed_typename in ast.basic_type_names):
589 return derefed_typename
591 def _create_type_from_base(self, source_type, is_parameter=False, is_return=False):
592 ctype = self._create_source_type(source_type)
593 const = ((source_type.type == CTYPE_POINTER) and
594 (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST))
595 return self.create_type_from_ctype_string(ctype, is_const=const,
596 is_parameter=is_parameter, is_return=is_return)
598 def _create_bare_container_type(self, base, ctype=None,
600 if base in ('GList', 'GSList', 'GLib.List', 'GLib.SList'):
601 if base in ('GList', 'GSList'):
602 name = 'GLib.' + base[1:]
605 return ast.List(name, ast.TYPE_ANY, ctype=ctype,
607 elif base in ('GArray', 'GPtrArray', 'GByteArray',
608 'GLib.Array', 'GLib.PtrArray', 'GLib.ByteArray'):
609 if base in ('GArray', 'GPtrArray', 'GByteArray'):
610 name = 'GLib.' + base[1:]
613 return ast.Array(name, ast.TYPE_ANY, ctype=ctype,
615 elif base in ('GHashTable', 'GLib.HashTable'):
616 return ast.Map(ast.TYPE_ANY, ast.TYPE_ANY, ctype=ctype, is_const=is_const)
619 def create_type_from_ctype_string(self, ctype, is_const=False,
620 is_parameter=False, is_return=False):
621 canonical = self._canonicalize_ctype(ctype)
622 base = canonical.replace('*', '')
624 # Special default: char ** -> ast.Array, same for GStrv
625 if (is_return and canonical == 'utf8*') or base == 'GStrv':
626 bare_utf8 = ast.TYPE_STRING.clone()
627 bare_utf8.ctype = None
628 return ast.Array(None, bare_utf8, ctype=ctype,
631 fundamental = ast.type_names.get(base)
632 if fundamental is not None:
633 return ast.Type(target_fundamental=fundamental.target_fundamental,
636 container = self._create_bare_container_type(base, ctype=ctype, is_const=is_const)
639 return ast.Type(ctype=ctype, is_const=is_const)
641 def _create_parameter(self, symbol):
642 if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
643 ptype = ast.Varargs()
645 ptype = self._create_type_from_base(symbol.base_type, is_parameter=True)
646 return ast.Parameter(symbol.ident, ptype)
648 def _create_return(self, source_type):
649 typeval = self._create_type_from_base(source_type, is_return=True)
650 return ast.Return(typeval)
652 def _create_const(self, symbol):
653 # Don't create constants for non-public things
654 # http://bugzilla.gnome.org/show_bug.cgi?id=572790
655 if (symbol.source_filename is None or
656 not symbol.source_filename.endswith('.h')):
658 # ignore non-uppercase defines
659 if not self.UCASE_CONSTANT_RE.match(symbol.ident):
661 name = self._strip_symbol_or_warn(symbol, is_constant=True)
664 if symbol.const_string is not None:
665 typeval = ast.TYPE_STRING
666 value = symbol.const_string
667 elif symbol.const_int is not None:
668 typeval = ast.TYPE_INT
669 value = '%d' % (symbol.const_int, )
670 elif symbol.const_double is not None:
671 typeval = ast.TYPE_DOUBLE
672 value = '%f' % (symbol.const_double, )
674 raise AssertionError()
676 const = ast.Constant(name, typeval, value)
677 const.add_symbol_reference(symbol)
680 def _create_typedef_struct(self, symbol, disguised=False):
681 name = self.strip_identifier_or_warn(symbol.ident)
684 struct = ast.Record(name, symbol.ident, disguised)
685 self._parse_fields(symbol, struct)
686 struct.add_symbol_reference(symbol)
687 self._typedefs_ns[symbol.ident] = struct
690 def _create_typedef_union(self, symbol):
691 name = self.strip_identifier_or_warn(symbol.ident)
694 union = ast.Union(name, symbol.ident)
695 self._parse_fields(symbol, union)
696 union.add_symbol_reference(symbol)
697 self._typedefs_ns[symbol.ident] = union
700 def _create_typedef_callback(self, symbol):
701 callback = self._create_callback(symbol)
704 self._typedefs_ns[callback.name] = callback
707 def _parse_fields(self, symbol, compound):
708 for child in symbol.base_type.child_list:
709 child_node = self._traverse_one(child)
712 if isinstance(child_node, ast.Field):
715 field = ast.Field(child.ident, None, True, False,
716 anonymous_node=child_node)
717 compound.fields.append(field)
719 def _create_compound(self, klass, symbol, anonymous):
720 if symbol.ident is None:
721 # the compound is an anonymous member of another union or a struct
723 compound = klass(None, None)
725 compound = self._typedefs_ns.get(symbol.ident, None)
728 # This is a bit of a hack; really we should try
729 # to resolve through the typedefs to find the real
731 if symbol.ident.startswith('_'):
732 compound = self._typedefs_ns.get(symbol.ident[1:], None)
737 name = self.strip_identifier_or_warn(symbol.ident)
740 compound = klass(name, symbol.ident)
742 self._parse_fields(symbol, compound)
743 compound.add_symbol_reference(symbol)
746 def _create_struct(self, symbol, anonymous=False):
747 return self._create_compound(ast.Record, symbol, anonymous)
749 def _create_union(self, symbol, anonymous=False):
750 return self._create_compound(ast.Union, symbol, anonymous)
752 def _create_callback(self, symbol, member=False):
753 parameters = list(self._create_parameters(symbol.base_type.base_type))
754 retval = self._create_return(symbol.base_type.base_type.base_type)
756 # Mark the 'user_data' arguments
757 for i, param in enumerate(parameters):
758 if (param.type.target_fundamental == 'gpointer' and
759 param.argname == 'user_data'):
760 param.closure_name = param.argname
764 elif symbol.ident.find('_') > 0:
765 name = self._strip_symbol_or_warn(symbol)
769 name = self.strip_identifier_or_warn(symbol.ident)
772 callback = ast.Callback(name, retval, parameters, False)
773 callback.add_symbol_reference(symbol)
777 def create_type_from_user_string(self, typestr):
778 """Parse a C type string (as might be given from an
779 annotation) and resolve it. For compatibility, we can consume
780 both GI type string (utf8, Foo.Bar) style, as well as C (char *, FooBar) style.
782 Note that type resolution may not succeed."""
784 container = self._create_bare_container_type(typestr)
787 return self._namespace.type_from_name(typestr)
788 typeval = self.create_type_from_ctype_string(typestr)
789 self.resolve_type(typeval)
790 # Explicitly clear out the c_type; there isn't one in this case.
794 def create_type_from_gtype_name(self, gtype_name):
795 """Parse a GType name (as from g_type_name()), and return a
796 Type instance. Note that this function performs namespace lookup,
797 in contrast to the other create_type() functions."""
798 # First, is it a fundamental?
799 fundamental = ast.type_names.get(gtype_name)
800 if fundamental is not None:
801 return ast.Type(target_fundamental=fundamental.target_fundamental)
802 return ast.Type(gtype_name=gtype_name)
804 def _resolve_type_from_ctype(self, typeval):
805 assert typeval.ctype is not None
806 pointer_stripped = typeval.ctype.replace('*', '')
808 matches = self.split_ctype_namespaces(pointer_stripped)
809 except ValueError, e:
810 raise TypeResolutionException(e)
812 for namespace, name in matches:
813 target = namespace.get(name)
815 target = namespace.get_by_ctype(pointer_stripped)
817 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
821 def _resolve_type_from_gtype_name(self, typeval):
822 assert typeval.gtype_name is not None
823 for ns in self._iter_namespaces():
824 for node in ns.itervalues():
825 if not isinstance(node, (ast.Class, ast.Interface,
830 if node.type_name == typeval.gtype_name:
831 typeval.target_giname = '%s.%s' % (ns.name, node.name)
835 def resolve_type(self, typeval):
836 if isinstance(typeval, (ast.Array, ast.List)):
837 return self.resolve_type(typeval.element_type)
838 elif isinstance(typeval, ast.Map):
839 key_resolved = self.resolve_type(typeval.key_type)
840 value_resolved = self.resolve_type(typeval.value_type)
841 return key_resolved and value_resolved
842 elif typeval.resolved:
845 return self._resolve_type_from_ctype(typeval)
846 elif typeval.gtype_name:
847 return self._resolve_type_from_gtype_name(typeval)
849 def _typepair_to_str(self, item):
853 return '%s.%s' % (nsname, item.name)
855 def gtypename_to_giname(self, gtname, names):
856 resolved = names.type_names.get(gtname)
858 return self._typepair_to_str(resolved)
859 resolved = self._names.type_names.get(gtname)
861 return self._typepair_to_str(resolved)
862 raise KeyError("Failed to resolve GType name: %r" % (gtname, ))
864 def ctype_of(self, obj):
865 if hasattr(obj, 'ctype'):
867 elif hasattr(obj, 'symbol'):
872 def follow_aliases(self, type_name, names):
874 resolved = names.aliases.get(type_name)
876 (ns, alias) = resolved
877 type_name = alias.target