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.
28 from .cachestore import CacheStore
29 from .config import DATADIR, GIR_DIR, GIR_SUFFIX
30 from .girparser import GIRParser
31 from .sourcescanner import (
32 SourceSymbol, ctype_name, CTYPE_POINTER,
33 CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF,
34 CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT,
35 CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT,
36 CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT,
37 CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST,
40 class TransformerException(Exception):
44 _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(':') \
45 + [DATADIR, '/usr/share'] if x]
47 class Transformer(object):
48 namespace = property(lambda self: self._namespace)
50 UCASE_CONSTANT_RE = re.compile(r'[_A-Z0-9]+')
52 def __init__(self, namespace, accept_unprefixed=False):
53 self._cwd = os.getcwd() + os.sep
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._enable_warnings = False
62 self._include_names = set()
63 self._includepaths = []
65 def get_includes(self):
66 return self._include_names
68 def enable_warnings(self, enable):
69 self._enable_warnings = enable
74 def get_pkgconfig_packages(self):
75 return self._pkg_config_packages
77 def _append_new_node(self, node):
78 original = self._namespace.get(node.name)
79 # Special case constants here; we allow duplication to sort-of
80 # handle #ifdef. But this introduces an arch-dependency in the .gir
81 # file. So far this has only come up scanning glib - in theory, other
82 # modules will just depend on that.
83 if isinstance(original, ast.Constant) and isinstance(node, ast.Constant):
87 positions.update(original.file_positions)
88 positions.update(node.file_positions)
89 message.fatal("Namespace conflict for '%s'" % (node.name, ),
92 self._namespace.append(node)
94 def parse(self, symbols):
95 for symbol in symbols:
96 node = self._traverse_one(symbol)
98 self._append_new_node(node)
100 # Now look through the namespace for things like
101 # typedef struct _Foo Foo;
102 # where we've never seen the struct _Foo. Just create
103 # an empty structure for these as "disguised"
104 # If we do have a class/interface, merge fields
105 for typedef, compound in self._typedefs_ns.iteritems():
106 ns_compound = self._namespace.get(compound.name)
108 ns_compound = self._namespace.get('_' + compound.name)
109 if (not ns_compound and isinstance(compound, (ast.Record, ast.Union))
110 and len(compound.fields) == 0):
111 disguised = ast.Record(compound.name, typedef, disguised=True)
112 self._namespace.append(disguised)
113 elif not ns_compound:
114 self._namespace.append(compound)
115 elif isinstance(ns_compound, (ast.Record, ast.Union)) and len(ns_compound.fields) == 0:
116 ns_compound.fields = compound.fields
117 self._typedefs_ns = None
119 def set_include_paths(self, paths):
120 self._includepaths = list(paths)
122 def register_include(self, include):
123 if include in self._include_names:
125 filename = self._find_include(include)
126 self._parse_include(filename)
127 self._include_names.add(include)
129 def lookup_giname(self, name):
130 """Given a name of the form Foo or Bar.Foo,
131 return the corresponding ast.Node, or None if none
132 available. Will throw KeyError however for unknown
135 return self._namespace.get(name)
137 (ns, name) = name.split('.', 1)
138 if ns == self._namespace.name:
139 return self._namespace.get(name)
140 include = self._includes[ns]
141 return include.get(name)
143 def lookup_typenode(self, typeobj):
144 """Given a Type object, if it points to a giname,
145 calls lookup_giname() on the name. Otherwise return
147 if typeobj.target_giname:
148 return self.lookup_giname(typeobj.target_giname)
153 def log_warning(self, text, file_positions=None, prefix=None,
155 """Log a warning, using optional file positioning information.
156 If the warning is related to a ast.Node type, see log_node_warning()."""
157 if not fatal and not self._enable_warnings:
162 if file_positions is None or len(file_positions) == 0:
163 target_file_positions = [('<unknown>', -1, -1)]
165 target_file_positions = file_positions
167 position_strings = []
168 for (filename, line, column) in target_file_positions:
169 if filename.startswith(self._cwd):
170 filename = filename[len(self._cwd):]
172 position = '%s:%d:%d' % (filename, line, column)
174 position = '%s:%d' % (filename, line, )
176 position = '%s:' % (filename, )
177 position_strings.append(position)
179 for position in position_strings[:-1]:
180 print >>sys.stderr, "%s:" % (position, )
181 last_position = position_strings[-1]
182 error_type = 'error' if fatal else 'warning'
184 print >>sys.stderr, \
185 '''%s: %s: %s: %s: %s''' % (last_position, error_type, self._namespace.name,
188 print >>sys.stderr, \
189 '''%s: %s: %s: %s''' % (last_position, error_type, self._namespace.name, text)
193 def log_symbol_warning(self, symbol, text, **kwargs):
194 """Log a warning in the context of the given symbol."""
195 if symbol.source_filename:
196 file_positions = [(symbol.source_filename, symbol.line, -1)]
198 file_positions = None
199 prefix = "symbol=%r" % (symbol.ident, )
200 self.log_warning(text, file_positions, prefix=prefix, **kwargs)
202 def log_node_warning(self, node, text, context=None, fatal=False):
203 """Log a warning, using information about file positions from
204 the given node. The optional context argument, if given, should be
205 another ast.Node type which will also be displayed. If no file position
206 information is available from the node, the position data from the
207 context will be used."""
208 if hasattr(node, 'file_positions'):
209 if (len(node.file_positions) == 0 and
210 (context is not None) and len(context.file_positions) > 0):
211 file_positions = context.file_positions
213 file_positions = node.file_positions
215 file_positions = None
217 text = "context=%r %s" % (node, text)
220 if isinstance(context, ast.Function):
221 name = context.symbol
224 text = "%s: %s" % (name, text)
225 elif len(file_positions) == 0 and hasattr(node, 'name'):
226 text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
228 self.log_warning(text, file_positions, fatal=fatal)
230 def _find_include(self, include):
231 searchdirs = self._includepaths[:]
232 for path in _xdg_data_dirs:
233 searchdirs.append(os.path.join(path, GIR_SUFFIX))
234 searchdirs.append(GIR_DIR)
236 girname = '%s-%s.gir' % (include.name, include.version)
238 path = os.path.join(d, girname)
239 if os.path.exists(path):
241 sys.stderr.write("Couldn't find include %r (search path: %r)\n"\
242 % (girname, searchdirs))
245 def _parse_include(self, filename):
246 parser = self._cachestore.load(filename)
249 parser.parse(filename)
250 self._cachestore.store(filename, parser)
252 for include in parser.get_includes():
253 self.register_include(include)
255 for pkg in parser.get_pkgconfig_packages():
256 self._pkg_config_packages.add(pkg)
257 namespace = parser.get_namespace()
258 self._includes[namespace.name] = namespace
260 def _iter_namespaces(self):
261 """Return an iterator over all included namespaces; the
262 currently-scanned namespace is first."""
263 yield self._namespace
264 for ns in self._includes.itervalues():
267 def _sort_matches(self, x, y):
268 if x[0] is self._namespace:
270 elif y[0] is self._namespace:
272 return cmp(x[2], y[2])
274 def _split_c_string_for_namespace_matches(self, name, is_identifier=False):
275 matches = [] # Namespaces which might contain this name
276 unprefixed_namespaces = [] # Namespaces with no prefix, last resort
277 for ns in self._iter_namespaces():
279 prefixes = ns.identifier_prefixes
281 prefixes = ns.symbol_prefixes
283 for prefix in prefixes:
284 if (not is_identifier) and (not prefix.endswith('_')):
285 prefix = prefix + '_'
286 if name.startswith(prefix):
287 matches.append((ns, name[len(prefix):], len(prefix)))
290 unprefixed_namespaces.append(ns)
292 matches.sort(self._sort_matches)
293 return map(lambda x: (x[0], x[1]), matches)
294 elif self._accept_unprefixed:
295 return [(self._namespace, name)]
296 elif unprefixed_namespaces:
297 # A bit of a hack; this function ideally shouldn't look through the
298 # contents of namespaces; but since we aren't scanning anything
299 # without a prefix, it's not too bad.
300 for ns in unprefixed_namespaces:
303 raise ValueError("Unknown namespace for %s %r"
304 % ('identifier' if is_identifier else 'symbol', name, ))
306 def split_ctype_namespaces(self, ident):
307 """Given a StudlyCaps string identifier like FooBar, return a
308 list of (namespace, stripped_identifier) sorted by namespace length,
309 or raise ValueError. As a special case, if the current namespace matches,
310 it is always biggest (i.e. last)."""
311 return self._split_c_string_for_namespace_matches(ident, is_identifier=True)
313 def split_csymbol_namespaces(self, symbol):
314 """Given a C symbol like foo_bar_do_baz, return a list of
315 (namespace, stripped_symbol) sorted by namespace match probablity, or
317 return self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
319 def split_csymbol(self, symbol):
320 """Given a C symbol like foo_bar_do_baz, return the most probable
321 (namespace, stripped_symbol) match, or raise ValueError."""
322 matches = self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
325 def strip_identifier(self, ident):
326 hidden = ident.startswith('_')
330 matches = self.split_ctype_namespaces(ident)
331 except ValueError, e:
332 raise TransformerException(str(e))
333 for ns, name in matches:
334 if ns is self._namespace:
338 (ns, name) = matches[-1]
339 raise TransformerException(
340 "Skipping foreign identifier %r from namespace %s" % (
344 def _strip_symbol(self, symbol, is_constant=False):
347 # Temporarily lowercase
348 ident = ident.lower()
349 hidden = ident.startswith('_')
353 (ns, name) = self.split_csymbol(ident)
354 except ValueError, e:
355 raise TransformerException("Unknown namespace")
356 if ns != self._namespace:
357 raise TransformerException(
358 "Skipping foreign symbol from namespace %s" % (ns.name, ))
365 def _traverse_one(self, symbol, stype=None):
366 assert isinstance(symbol, SourceSymbol), symbol
370 if stype == CSYMBOL_TYPE_FUNCTION:
371 return self._create_function(symbol)
372 elif stype == CSYMBOL_TYPE_TYPEDEF:
373 return self._create_typedef(symbol)
374 elif stype == CSYMBOL_TYPE_STRUCT:
375 return self._create_struct(symbol)
376 elif stype == CSYMBOL_TYPE_ENUM:
377 return self._create_enum(symbol)
378 elif stype == CSYMBOL_TYPE_MEMBER:
379 return self._create_member(symbol)
380 elif stype == CSYMBOL_TYPE_UNION:
381 return self._create_union(symbol)
382 elif stype == CSYMBOL_TYPE_CONST:
383 return self._create_const(symbol)
384 # Ignore variable declarations in the header
385 elif stype == CSYMBOL_TYPE_OBJECT:
388 print 'transformer: unhandled symbol: %r' % (symbol, )
390 def _enum_common_prefix(self, symbol):
391 def common_prefix(a, b):
393 for aword, bword in zip(a.split('_'), b.split('_')):
395 return '_'.join(commonparts) + '_'
396 commonparts.append(aword)
399 # Nothing less than 2 has a common prefix
400 if len(list(symbol.base_type.child_list)) < 2:
403 for child in symbol.base_type.child_list:
407 prefix = common_prefix(prefix, child.ident)
412 def _create_enum(self, symbol):
413 prefix = self._enum_common_prefix(symbol)
415 prefixlen = len(prefix)
419 for child in symbol.base_type.child_list:
421 name = child.ident[prefixlen:]
423 # Ok, the enum members don't have a consistent prefix
424 # among them, so let's just remove the global namespace
427 name = self._strip_symbol(child, is_constant=True)
428 except TransformerException, e:
429 message.warn_symbol(child, e)
431 members.append(ast.Member(name.lower(),
436 enum_name = self.strip_identifier(symbol.ident)
437 except TransformerException, e:
440 if symbol.base_type.is_bitfield:
444 node = klass(enum_name, symbol.ident, members)
445 node.add_symbol_reference(symbol)
448 def _create_function(self, symbol):
449 parameters = list(self._create_parameters(symbol.base_type))
450 return_ = self._create_return(symbol.base_type.base_type)
452 name = self._strip_symbol(symbol)
453 except TransformerException, e:
454 message.warn_symbol(symbol, e)
456 func = ast.Function(name, return_, parameters, False, symbol.ident)
457 func.add_symbol_reference(symbol)
460 def _create_source_type(self, source_type):
461 if source_type is None:
463 if source_type.type == CTYPE_VOID:
465 elif source_type.type == CTYPE_BASIC_TYPE:
466 value = source_type.name
467 elif source_type.type == CTYPE_TYPEDEF:
468 value = source_type.name
469 elif source_type.type == CTYPE_ARRAY:
470 return self._create_source_type(source_type.base_type)
471 elif source_type.type == CTYPE_POINTER:
472 value = self._create_source_type(source_type.base_type) + '*'
477 def _create_parameters(self, base_type):
478 # warn if we see annotations for unknown parameters
479 param_names = set(child.ident for child in base_type.child_list)
480 for child in base_type.child_list:
481 yield self._create_parameter(child)
483 def _create_member(self, symbol):
484 source_type = symbol.base_type
485 if (source_type.type == CTYPE_POINTER and
486 symbol.base_type.base_type.type == CTYPE_FUNCTION):
487 node = self._create_callback(symbol, member=True)
488 elif source_type.type == CTYPE_STRUCT and source_type.name is None:
489 node = self._create_struct(symbol, anonymous=True)
490 elif source_type.type == CTYPE_UNION and source_type.name is None:
491 node = self._create_union(symbol, anonymous=True)
493 # Special handling for fields; we don't have annotations on them
494 # to apply later, yet.
495 if source_type.type == CTYPE_ARRAY:
496 ctype = self._create_source_type(source_type)
497 canonical_ctype = self._canonicalize_ctype(ctype)
498 if canonical_ctype[-1] == '*':
499 derefed_name = canonical_ctype[:-1]
501 derefed_name = canonical_ctype
502 ftype = ast.Array(None, self.create_type_from_ctype_string(ctype),
504 child_list = list(symbol.base_type.child_list)
505 ftype.zeroterminated = False
507 ftype.size = child_list[0].const_int
509 ftype = self._create_type_from_base(symbol.base_type)
510 # ast.Fields are assumed to be read-write
511 # (except for Objects, see also glibtransformer.py)
512 node = ast.Field(symbol.ident, ftype,
513 readable=True, writable=True, bits=symbol.const_int)
516 def _create_typedef(self, symbol):
517 ctype = symbol.base_type.type
518 if (ctype == CTYPE_POINTER and
519 symbol.base_type.base_type.type == CTYPE_FUNCTION):
520 node = self._create_typedef_callback(symbol)
521 elif (ctype == CTYPE_POINTER and
522 symbol.base_type.base_type.type == CTYPE_STRUCT):
523 node = self._create_typedef_struct(symbol, disguised=True)
524 elif ctype == CTYPE_STRUCT:
525 node = self._create_typedef_struct(symbol)
526 elif ctype == CTYPE_UNION:
527 node = self._create_typedef_union(symbol)
528 elif ctype == CTYPE_ENUM:
529 return self._create_enum(symbol)
530 elif ctype in (CTYPE_TYPEDEF,
535 name = self.strip_identifier(symbol.ident)
536 except TransformerException, e:
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):
662 name = self._strip_symbol(symbol, is_constant=True)
663 except TransformerException, e:
664 message.warn_symbol(symbol, e)
666 if symbol.const_string is not None:
667 typeval = ast.TYPE_STRING
668 value = symbol.const_string
669 elif symbol.const_int is not None:
670 typeval = ast.TYPE_INT
671 value = '%d' % (symbol.const_int, )
672 elif symbol.const_double is not None:
673 typeval = ast.TYPE_DOUBLE
674 value = '%f' % (symbol.const_double, )
676 raise AssertionError()
678 const = ast.Constant(name, typeval, value)
679 const.add_symbol_reference(symbol)
682 def _create_typedef_struct(self, symbol, disguised=False):
684 name = self.strip_identifier(symbol.ident)
685 except TransformerException, e:
688 struct = ast.Record(name, symbol.ident, disguised)
689 self._parse_fields(symbol, struct)
690 struct.add_symbol_reference(symbol)
691 self._typedefs_ns[symbol.ident] = struct
694 def _create_typedef_union(self, symbol):
696 name = self.strip_identifier(symbol.ident)
697 except TransformerException, e:
700 union = ast.Union(name, symbol.ident)
701 self._parse_fields(symbol, union)
702 union.add_symbol_reference(symbol)
703 self._typedefs_ns[symbol.ident] = union
706 def _create_typedef_callback(self, symbol):
707 callback = self._create_callback(symbol)
710 self._typedefs_ns[callback.name] = callback
713 def _parse_fields(self, symbol, compound):
714 for child in symbol.base_type.child_list:
715 child_node = self._traverse_one(child)
718 if isinstance(child_node, ast.Field):
721 field = ast.Field(child.ident, None, True, False,
722 anonymous_node=child_node)
723 compound.fields.append(field)
725 def _create_compound(self, klass, symbol, anonymous):
726 if symbol.ident is None:
727 # the compound is an anonymous member of another union or a struct
729 compound = klass(None, None)
731 compound = self._typedefs_ns.get(symbol.ident, None)
734 # This is a bit of a hack; really we should try
735 # to resolve through the typedefs to find the real
737 if symbol.ident.startswith('_'):
738 compound = self._typedefs_ns.get(symbol.ident[1:], None)
744 name = self.strip_identifier(symbol.ident)
745 except TransformerException, e:
748 compound = klass(name, symbol.ident)
750 self._parse_fields(symbol, compound)
751 compound.add_symbol_reference(symbol)
754 def _create_struct(self, symbol, anonymous=False):
755 return self._create_compound(ast.Record, symbol, anonymous)
757 def _create_union(self, symbol, anonymous=False):
758 return self._create_compound(ast.Union, symbol, anonymous)
760 def _create_callback(self, symbol, member=False):
761 parameters = list(self._create_parameters(symbol.base_type.base_type))
762 retval = self._create_return(symbol.base_type.base_type.base_type)
764 # Mark the 'user_data' arguments
765 for i, param in enumerate(parameters):
766 if (param.type.target_fundamental == 'gpointer' and
767 param.argname == 'user_data'):
768 param.closure_name = param.argname
772 elif symbol.ident.find('_') > 0:
774 name = self._strip_symbol(symbol)
775 except TransformerException, e:
776 message.warn_symbol(symbol, e)
780 name = self.strip_identifier(symbol.ident)
781 except TransformerException, e:
784 callback = ast.Callback(name, retval, parameters, False)
785 callback.add_symbol_reference(symbol)
789 def create_type_from_user_string(self, typestr):
790 """Parse a C type string (as might be given from an
791 annotation) and resolve it. For compatibility, we can consume
792 both GI type string (utf8, Foo.Bar) style, as well as C (char *, FooBar) style.
794 Note that type resolution may not succeed."""
796 container = self._create_bare_container_type(typestr)
799 return self._namespace.type_from_name(typestr)
800 typeval = self.create_type_from_ctype_string(typestr)
801 self.resolve_type(typeval)
802 # Explicitly clear out the c_type; there isn't one in this case.
806 def create_type_from_gtype_name(self, gtype_name):
807 """Parse a GType name (as from g_type_name()), and return a
808 Type instance. Note that this function performs namespace lookup,
809 in contrast to the other create_type() functions."""
810 # First, is it a fundamental?
811 fundamental = ast.type_names.get(gtype_name)
812 if fundamental is not None:
813 return ast.Type(target_fundamental=fundamental.target_fundamental)
814 return ast.Type(gtype_name=gtype_name)
816 def _resolve_type_from_ctype(self, typeval):
817 assert typeval.ctype is not None
818 pointer_stripped = typeval.ctype.replace('*', '')
820 matches = self.split_ctype_namespaces(pointer_stripped)
821 except ValueError, e:
824 for namespace, name in matches:
825 target = namespace.get(name)
827 target = namespace.get_by_ctype(pointer_stripped)
829 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
833 def _resolve_type_from_gtype_name(self, typeval):
834 assert typeval.gtype_name is not None
835 for ns in self._iter_namespaces():
836 for node in ns.itervalues():
837 if not isinstance(node, (ast.Class, ast.Interface,
842 if node.type_name == typeval.gtype_name:
843 typeval.target_giname = '%s.%s' % (ns.name, node.name)
847 def resolve_type(self, typeval):
848 if isinstance(typeval, (ast.Array, ast.List)):
849 return self.resolve_type(typeval.element_type)
850 elif isinstance(typeval, ast.Map):
851 key_resolved = self.resolve_type(typeval.key_type)
852 value_resolved = self.resolve_type(typeval.value_type)
853 return key_resolved and value_resolved
854 elif typeval.resolved:
857 return self._resolve_type_from_ctype(typeval)
858 elif typeval.gtype_name:
859 return self._resolve_type_from_gtype_name(typeval)
861 def _typepair_to_str(self, item):
865 return '%s.%s' % (nsname, item.name)
867 def gtypename_to_giname(self, gtname, names):
868 resolved = names.type_names.get(gtname)
870 return self._typepair_to_str(resolved)
871 resolved = self._names.type_names.get(gtname)
873 return self._typepair_to_str(resolved)
874 raise KeyError("Failed to resolve GType name: %r" % (gtname, ))
876 def ctype_of(self, obj):
877 if hasattr(obj, 'ctype'):
879 elif hasattr(obj, 'symbol'):
884 def follow_aliases(self, type_name, names):
886 resolved = names.aliases.get(type_name)
888 (ns, alias) = resolved
889 type_name = alias.target