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.
26 from .config import DATADIR, GIR_DIR, GIR_SUFFIX
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,
37 class TypeResolutionException(Exception):
40 _xdg_data_dirs = [x for x in os.environ.get('XDG_DATA_DIRS', '').split(':') \
41 + [DATADIR, '/usr/share'] if x]
43 class Transformer(object):
44 namespace = property(lambda self: self._namespace)
46 UCASE_CONSTANT_RE = re.compile(r'[_A-Z0-9]+')
48 def __init__(self, cachestore, namespace_name, namespace_version,
49 identifier_prefixes=None, symbol_prefixes=None):
50 self._cwd = os.getcwd() + os.sep
51 self._cachestore = cachestore
53 self._namespace = ast.Namespace(namespace_name, namespace_version,
54 identifier_prefixes=identifier_prefixes,
55 symbol_prefixes=symbol_prefixes)
56 self._pkg_config_packages = set()
57 self._typedefs_ns = {}
58 self._enable_warnings = False
61 self._include_names = set()
62 self._includepaths = []
64 def get_includes(self):
65 return self._include_names
67 def enable_warnings(self, enable):
68 self._enable_warnings = enable
73 def get_pkgconfig_packages(self):
74 return self._pkg_config_packages
76 def set_source_ast(self, src_ast):
77 self.generator = src_ast
79 def _append_new_node(self, node):
80 original = self._namespace.get(node.name)
81 # Special case constants here; we allow duplication to sort-of
82 # handle #ifdef. But this introduces an arch-dependency in the .gir
83 # file. So far this has only come up scanning glib - in theory, other
84 # modules will just depend on that.
85 if isinstance(original, ast.Constant) and isinstance(node, ast.Constant):
89 positions.update(original.file_positions)
90 positions.update(node.file_positions)
91 self.log_warning("Namespace conflict for '%s'" % (node.name, ),
92 positions, fatal=True)
94 self._namespace.append(node)
97 for symbol in self.generator.get_symbols():
98 node = self._traverse_one(symbol)
100 self._append_new_node(node)
102 # Now look through the namespace for things like
103 # typedef struct _Foo Foo;
104 # where we've never seen the struct _Foo. Just create
105 # an empty structure for these as "disguised"
106 # If we do have a class/interface, merge fields
107 for typedef, compound in self._typedefs_ns.iteritems():
108 ns_compound = self._namespace.get(compound.name)
110 ns_compound = self._namespace.get('_' + compound.name)
111 if (not ns_compound and isinstance(compound, (ast.Record, ast.Union))
112 and len(compound.fields) == 0):
113 disguised = ast.Record(compound.name, typedef, disguised=True)
114 self._namespace.append(disguised)
115 elif not ns_compound:
116 self._namespace.append(compound)
117 elif isinstance(ns_compound, (ast.Record, ast.Union)) and len(ns_compound.fields) == 0:
118 ns_compound.fields = compound.fields
119 self._typedefs_ns = None
121 def set_include_paths(self, paths):
122 self._includepaths = list(paths)
124 def register_include(self, include):
125 if include in self._include_names:
127 filename = self._find_include(include)
128 self._parse_include(filename)
129 self._include_names.add(include)
131 def lookup_giname(self, name):
132 """Given a name of the form Foo or Bar.Foo,
133 return the corresponding ast.Node, or None if none
134 available. Will throw KeyError however for unknown
137 return self._namespace.get(name)
139 (ns, name) = name.split('.', 1)
140 if ns == self._namespace.name:
141 return self._namespace.get(name)
142 include = self._includes[ns]
143 return include.get(name)
145 def lookup_typenode(self, typeobj):
146 """Given a Type object, if it points to a giname,
147 calls lookup_giname() on the name. Otherwise return
149 if typeobj.target_giname:
150 return self.lookup_giname(typeobj.target_giname)
155 def log_warning(self, text, file_positions=None, prefix=None,
157 """Log a warning, using optional file positioning information.
158 If the warning is related to a ast.Node type, see log_node_warning()."""
159 if not fatal and not self._enable_warnings:
164 if file_positions is None or len(file_positions) == 0:
165 target_file_positions = [('<unknown>', -1, -1)]
167 target_file_positions = file_positions
169 position_strings = []
170 for (filename, line, column) in target_file_positions:
171 if filename.startswith(self._cwd):
172 filename = filename[len(self._cwd):]
174 position = '%s:%d:%d' % (filename, line, column)
176 position = '%s:%d' % (filename, line, )
178 position = '%s:' % (filename, )
179 position_strings.append(position)
181 for position in position_strings[:-1]:
182 print >>sys.stderr, "%s:" % (position, )
183 last_position = position_strings[-1]
184 error_type = 'error' if fatal else 'warning'
186 print >>sys.stderr, \
187 '''%s: %s: %s: %s: %s''' % (last_position, error_type, self._namespace.name,
190 print >>sys.stderr, \
191 '''%s: %s: %s: %s''' % (last_position, error_type, self._namespace.name, text)
195 def log_symbol_warning(self, symbol, text, **kwargs):
196 """Log a warning in the context of the given symbol."""
197 if symbol.source_filename:
198 file_positions = [(symbol.source_filename, symbol.line, -1)]
200 file_positions = None
201 prefix = "symbol=%r" % (symbol.ident, )
202 self.log_warning(text, file_positions, prefix=prefix, **kwargs)
204 def log_node_warning(self, node, text, context=None, fatal=False):
205 """Log a warning, using information about file positions from
206 the given node. The optional context argument, if given, should be
207 another ast.Node type which will also be displayed. If no file position
208 information is available from the node, the position data from the
209 context will be used."""
210 if hasattr(node, 'file_positions'):
211 if (len(node.file_positions) == 0 and
212 (context is not None) and len(context.file_positions) > 0):
213 file_positions = context.file_positions
215 file_positions = node.file_positions
217 file_positions = None
219 text = "context=%r %s" % (node, text)
222 if isinstance(context, ast.Function):
223 name = context.symbol
226 text = "%s: %s" % (name, text)
227 elif len(file_positions) == 0 and hasattr(node, 'name'):
228 text = "(%s)%s: %s" % (node.__class__.__name__, node.name, text)
230 self.log_warning(text, file_positions, fatal=fatal)
232 def _find_include(self, include):
233 searchdirs = self._includepaths[:]
234 for path in _xdg_data_dirs:
235 searchdirs.append(os.path.join(path, GIR_SUFFIX))
236 searchdirs.append(GIR_DIR)
238 girname = '%s-%s.gir' % (include.name, include.version)
240 path = os.path.join(d, girname)
241 if os.path.exists(path):
243 sys.stderr.write("Couldn't find include %r (search path: %r)\n"\
244 % (girname, searchdirs))
247 def _parse_include(self, filename):
248 parser = self._cachestore.load(filename)
251 parser.parse(filename)
252 self._cachestore.store(filename, parser)
254 for include in parser.get_includes():
255 self.register_include(include)
257 for pkg in parser.get_pkgconfig_packages():
258 self._pkg_config_packages.add(pkg)
259 namespace = parser.get_namespace()
260 self._includes[namespace.name] = namespace
262 def _iter_namespaces(self):
263 """Return an iterator over all included namespaces; the
264 currently-scanned namespace is first."""
265 yield self._namespace
266 for ns in self._includes.itervalues():
269 def _sort_matches(self, x, y):
270 if x[0] is self._namespace:
272 elif y[0] is self._namespace:
274 return cmp(x[2], y[2])
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)."""
282 for ns in self._iter_namespaces():
283 if ns.identifier_prefixes:
284 for prefix in ns.identifier_prefixes:
285 if ident.startswith(prefix):
286 matches.append((ns, ident[len(prefix):], len(prefix)))
289 # A special case for namespaces without a prefix, such as X
290 matches.append((ns, ident, 0))
292 matches.sort(self._sort_matches)
293 return map(lambda x: (x[0], x[1]), matches)
294 raise ValueError("Unknown namespace for identifier %r" % (ident, ))
296 def split_csymbol(self, symbol):
297 """Given a C symbol like foo_bar_do_baz, return a pair of
298 (namespace, stripped_symbol) or raise ValueError."""
300 for ns in self._iter_namespaces():
301 for prefix in ns.symbol_prefixes:
302 if not prefix.endswith('_'):
303 prefix = prefix + '_'
304 if symbol.startswith(prefix):
305 matches.append((ns, symbol[len(prefix):], len(prefix)))
308 matches.sort(self._sort_matches)
309 return (matches[-1][0], matches[-1][1])
310 raise ValueError("Unknown namespace for symbol %r" % (symbol, ))
312 def strip_identifier_or_warn(self, ident, fatal=False):
313 hidden = ident.startswith('_')
317 matches = self.split_ctype_namespaces(ident)
318 except ValueError, e:
319 self.log_warning(str(e), fatal=fatal)
321 for ns, name in matches:
322 if ns is self._namespace:
326 (ns, name) = matches[-1]
327 self.log_warning("Skipping foreign identifier %r from namespace %s" % (ident, ns.name, ),
331 def _strip_symbol_or_warn(self, symbol, is_constant=False, fatal=False):
334 # Temporarily lowercase
335 ident = ident.lower()
336 hidden = ident.startswith('_')
340 (ns, name) = self.split_csymbol(ident)
341 except ValueError, e:
342 self.log_symbol_warning(symbol, "Unknown namespace", fatal=fatal)
344 if ns != self._namespace:
345 self.log_symbol_warning(symbol,
346 "Skipping foreign symbol from namespace %s" % (ns.name, ),
355 def _traverse_one(self, symbol, stype=None):
356 assert isinstance(symbol, SourceSymbol), symbol
360 if stype == CSYMBOL_TYPE_FUNCTION:
361 return self._create_function(symbol)
362 elif stype == CSYMBOL_TYPE_TYPEDEF:
363 return self._create_typedef(symbol)
364 elif stype == CSYMBOL_TYPE_STRUCT:
365 return self._create_struct(symbol)
366 elif stype == CSYMBOL_TYPE_ENUM:
367 return self._create_enum(symbol)
368 elif stype == CSYMBOL_TYPE_MEMBER:
369 return self._create_member(symbol)
370 elif stype == CSYMBOL_TYPE_UNION:
371 return self._create_union(symbol)
372 elif stype == CSYMBOL_TYPE_CONST:
373 return self._create_const(symbol)
374 # Ignore variable declarations in the header
375 elif stype == CSYMBOL_TYPE_OBJECT:
378 print 'transformer: unhandled symbol: %r' % (symbol, )
380 def _enum_common_prefix(self, symbol):
381 def common_prefix(a, b):
383 for aword, bword in zip(a.split('_'), b.split('_')):
385 return '_'.join(commonparts) + '_'
386 commonparts.append(aword)
389 # Nothing less than 2 has a common prefix
390 if len(list(symbol.base_type.child_list)) < 2:
393 for child in symbol.base_type.child_list:
397 prefix = common_prefix(prefix, child.ident)
402 def _create_enum(self, symbol):
403 prefix = self._enum_common_prefix(symbol)
405 prefixlen = len(prefix)
409 for child in symbol.base_type.child_list:
411 name = child.ident[prefixlen:]
413 # Ok, the enum members don't have a consistent prefix
414 # among them, so let's just remove the global namespace
416 name = self._strip_symbol_or_warn(child, is_constant=True)
419 members.append(ast.Member(name.lower(),
423 enum_name = self.strip_identifier_or_warn(symbol.ident)
426 if symbol.base_type.is_bitfield:
430 node = klass(enum_name, symbol.ident, members)
431 node.add_symbol_reference(symbol)
434 def _create_function(self, symbol):
435 parameters = list(self._create_parameters(symbol.base_type))
436 return_ = self._create_return(symbol.base_type.base_type)
437 name = self._strip_symbol_or_warn(symbol)
440 func = ast.Function(name, return_, parameters, False, symbol.ident)
441 func.add_symbol_reference(symbol)
444 def _create_source_type(self, source_type):
445 if source_type is None:
447 if source_type.type == CTYPE_VOID:
449 elif source_type.type == CTYPE_BASIC_TYPE:
450 value = source_type.name
451 elif source_type.type == CTYPE_TYPEDEF:
452 value = source_type.name
453 elif source_type.type == CTYPE_ARRAY:
454 return self._create_source_type(source_type.base_type)
455 elif source_type.type == CTYPE_POINTER:
456 value = self._create_source_type(source_type.base_type) + '*'
461 def _create_parameters(self, base_type):
462 # warn if we see annotations for unknown parameters
463 param_names = set(child.ident for child in base_type.child_list)
464 for child in base_type.child_list:
465 yield self._create_parameter(child)
467 def _create_member(self, symbol):
468 source_type = symbol.base_type
469 if (source_type.type == CTYPE_POINTER and
470 symbol.base_type.base_type.type == CTYPE_FUNCTION):
471 node = self._create_callback(symbol, member=True)
472 elif source_type.type == CTYPE_STRUCT and source_type.name is None:
473 node = self._create_struct(symbol, anonymous=True)
474 elif source_type.type == CTYPE_UNION and source_type.name is None:
475 node = self._create_union(symbol, anonymous=True)
477 # Special handling for fields; we don't have annotations on them
478 # to apply later, yet.
479 if source_type.type == CTYPE_ARRAY:
480 ctype = self._create_source_type(source_type)
481 canonical_ctype = self._canonicalize_ctype(ctype)
482 if canonical_ctype[-1] == '*':
483 derefed_name = canonical_ctype[:-1]
485 derefed_name = canonical_ctype
486 ftype = ast.Array(None, self.create_type_from_ctype_string(ctype),
488 child_list = list(symbol.base_type.child_list)
489 ftype.zeroterminated = False
491 ftype.size = child_list[0].const_int
493 ftype = self._create_type_from_base(symbol.base_type)
494 # ast.Fields are assumed to be read-write
495 # (except for Objects, see also glibtransformer.py)
496 node = ast.Field(symbol.ident, ftype,
497 readable=True, writable=True, bits=symbol.const_int)
500 def _create_typedef(self, symbol):
501 ctype = symbol.base_type.type
502 if (ctype == CTYPE_POINTER and
503 symbol.base_type.base_type.type == CTYPE_FUNCTION):
504 node = self._create_typedef_callback(symbol)
505 elif (ctype == CTYPE_POINTER and
506 symbol.base_type.base_type.type == CTYPE_STRUCT):
507 node = self._create_typedef_struct(symbol, disguised=True)
508 elif ctype == CTYPE_STRUCT:
509 node = self._create_typedef_struct(symbol)
510 elif ctype == CTYPE_UNION:
511 node = self._create_typedef_union(symbol)
512 elif ctype == CTYPE_ENUM:
513 return self._create_enum(symbol)
514 elif ctype in (CTYPE_TYPEDEF,
518 name = self.strip_identifier_or_warn(symbol.ident)
521 if symbol.base_type.name:
522 target = self.create_type_from_ctype_string(symbol.base_type.name)
524 target = ast.TYPE_ANY
525 if name in ast.type_names:
527 return ast.Alias(name, target, ctype=symbol.ident)
529 raise NotImplementedError(
530 "symbol %r of type %s" % (symbol.ident, ctype_name(ctype)))
533 def _canonicalize_ctype(self, ctype):
534 # First look up the ctype including any pointers;
535 # a few type names like 'char*' have their own aliases
536 # and we need pointer information for those.
537 firstpass = ast.type_names.get(ctype)
539 # If we have a particular alias for this, skip deep
540 # canonicalization to prevent changing
541 # e.g. char* -> int8*
543 return firstpass.target_fundamental
545 if not ctype.endswith('*'):
548 # We have a pointer type.
549 # Strip the end pointer, canonicalize our base type
551 canonical_base = self._canonicalize_ctype(base)
553 # Append the pointer again
554 canonical = canonical_base + '*'
558 def parse_ctype(self, ctype, is_member=False):
559 canonical = self._canonicalize_ctype(ctype)
561 # Remove all pointers - we require standard calling
562 # conventions. For example, an 'int' is always passed by
563 # value (unless it's out or inout).
564 derefed_typename = canonical.replace('*', '')
566 # Preserve "pointerness" of struct/union members
567 if (is_member and canonical.endswith('*') and
568 derefed_typename in ast.basic_type_names):
571 return derefed_typename
573 def _create_type_from_base(self, source_type, is_parameter=False, is_return=False):
574 ctype = self._create_source_type(source_type)
575 const = ((source_type.type == CTYPE_POINTER) and
576 (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST))
577 return self.create_type_from_ctype_string(ctype, is_const=const,
578 is_parameter=is_parameter, is_return=is_return)
580 def _create_bare_container_type(self, base, ctype=None,
582 if base in ('GList', 'GSList', 'GLib.List', 'GLib.SList'):
583 if base in ('GList', 'GSList'):
584 name = 'GLib.' + base[1:]
587 return ast.List(name, ast.TYPE_ANY, ctype=ctype,
589 elif base in ('GArray', 'GPtrArray', 'GByteArray',
590 'GLib.Array', 'GLib.PtrArray', 'GLib.ByteArray'):
591 if base in ('GArray', 'GPtrArray', 'GByteArray'):
592 name = 'GLib.' + base[1:]
595 return ast.Array(name, ast.TYPE_ANY, ctype=ctype,
597 elif base in ('GHashTable', 'GLib.HashTable'):
598 return ast.Map(ast.TYPE_ANY, ast.TYPE_ANY, ctype=ctype, is_const=is_const)
601 def create_type_from_ctype_string(self, ctype, is_const=False,
602 is_parameter=False, is_return=False):
603 canonical = self._canonicalize_ctype(ctype)
604 base = canonical.replace('*', '')
606 # Special default: char ** -> ast.Array, same for GStrv
607 if (is_return and canonical == 'utf8*') or base == 'GStrv':
608 bare_utf8 = ast.TYPE_STRING.clone()
609 bare_utf8.ctype = None
610 return ast.Array(None, bare_utf8, ctype=ctype,
613 fundamental = ast.type_names.get(base)
614 if fundamental is not None:
615 return ast.Type(target_fundamental=fundamental.target_fundamental,
618 container = self._create_bare_container_type(base, ctype=ctype, is_const=is_const)
621 return ast.Type(ctype=ctype, is_const=is_const)
623 def _create_parameter(self, symbol):
624 if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
625 ptype = ast.Varargs()
627 ptype = self._create_type_from_base(symbol.base_type, is_parameter=True)
628 return ast.Parameter(symbol.ident, ptype)
630 def _create_return(self, source_type):
631 typeval = self._create_type_from_base(source_type, is_return=True)
632 return ast.Return(typeval)
634 def _create_const(self, symbol):
635 # Don't create constants for non-public things
636 # http://bugzilla.gnome.org/show_bug.cgi?id=572790
637 if (symbol.source_filename is None or
638 not symbol.source_filename.endswith('.h')):
640 # ignore non-uppercase defines
641 if not self.UCASE_CONSTANT_RE.match(symbol.ident):
643 name = self._strip_symbol_or_warn(symbol, is_constant=True)
646 if symbol.const_string is not None:
647 typeval = ast.TYPE_STRING
648 value = symbol.const_string
649 elif symbol.const_int is not None:
650 typeval = ast.TYPE_INT
651 value = '%d' % (symbol.const_int, )
652 elif symbol.const_double is not None:
653 typeval = ast.TYPE_DOUBLE
654 value = '%f' % (symbol.const_double, )
656 raise AssertionError()
658 const = ast.Constant(name, typeval, value)
659 const.add_symbol_reference(symbol)
662 def _create_typedef_struct(self, symbol, disguised=False):
663 name = self.strip_identifier_or_warn(symbol.ident)
666 struct = ast.Record(name, symbol.ident, disguised)
667 self._parse_fields(symbol, struct)
668 struct.add_symbol_reference(symbol)
669 self._typedefs_ns[symbol.ident] = struct
672 def _create_typedef_union(self, symbol):
673 name = self.strip_identifier_or_warn(symbol.ident)
676 union = ast.Union(name, symbol.ident)
677 self._parse_fields(symbol, union)
678 union.add_symbol_reference(symbol)
679 self._typedefs_ns[symbol.ident] = union
682 def _create_typedef_callback(self, symbol):
683 callback = self._create_callback(symbol)
686 self._typedefs_ns[callback.name] = callback
689 def _parse_fields(self, symbol, compound):
690 for child in symbol.base_type.child_list:
691 child_node = self._traverse_one(child)
694 if isinstance(child_node, ast.Field):
697 field = ast.Field(child.ident, None, True, False,
698 anonymous_node=child_node)
699 compound.fields.append(field)
701 def _create_compound(self, klass, symbol, anonymous):
702 if symbol.ident is None:
703 # the compound is an anonymous member of another union or a struct
705 compound = klass(None, None)
707 compound = self._typedefs_ns.get(symbol.ident, None)
710 # This is a bit of a hack; really we should try
711 # to resolve through the typedefs to find the real
713 if symbol.ident.startswith('_'):
714 compound = self._typedefs_ns.get(symbol.ident[1:], None)
719 name = self.strip_identifier_or_warn(symbol.ident)
722 compound = klass(name, symbol.ident)
724 self._parse_fields(symbol, compound)
725 compound.add_symbol_reference(symbol)
728 def _create_struct(self, symbol, anonymous=False):
729 return self._create_compound(ast.Record, symbol, anonymous)
731 def _create_union(self, symbol, anonymous=False):
732 return self._create_compound(ast.Union, symbol, anonymous)
734 def _create_callback(self, symbol, member=False):
735 parameters = list(self._create_parameters(symbol.base_type.base_type))
736 retval = self._create_return(symbol.base_type.base_type.base_type)
738 # Mark the 'user_data' arguments
739 for i, param in enumerate(parameters):
740 if (param.type.target_fundamental == 'gpointer' and
741 param.argname == 'user_data'):
742 param.closure_name = param.argname
746 elif symbol.ident.find('_') > 0:
747 name = self._strip_symbol_or_warn(symbol)
751 name = self.strip_identifier_or_warn(symbol.ident)
754 callback = ast.Callback(name, retval, parameters, False)
755 callback.add_symbol_reference(symbol)
759 def create_type_from_user_string(self, typestr):
760 """Parse a C type string (as might be given from an
761 annotation) and resolve it. For compatibility, we can consume
762 both GI type string (utf8, Foo.Bar) style, as well as C (char *, FooBar) style.
764 Note that type resolution may not succeed."""
766 container = self._create_bare_container_type(typestr)
769 return self._namespace.type_from_name(typestr)
770 typeval = self.create_type_from_ctype_string(typestr)
771 self.resolve_type(typeval)
772 # Explicitly clear out the c_type; there isn't one in this case.
776 def _resolve_type_from_ctype(self, typeval):
777 pointer_stripped = typeval.ctype.replace('*', '')
779 matches = self.split_ctype_namespaces(pointer_stripped)
780 except ValueError, e:
781 raise TypeResolutionException(e)
783 for namespace, name in matches:
784 target = namespace.get(name)
786 target = namespace.get_by_ctype(pointer_stripped)
788 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
792 def resolve_type(self, typeval):
793 if isinstance(typeval, (ast.Array, ast.List)):
794 return self.resolve_type(typeval.element_type)
795 elif isinstance(typeval, ast.Map):
796 key_resolved = self.resolve_type(typeval.key_type)
797 value_resolved = self.resolve_type(typeval.value_type)
798 return key_resolved and value_resolved
799 elif typeval.resolved:
802 return self._resolve_type_from_ctype(typeval)
804 def _typepair_to_str(self, item):
808 return '%s.%s' % (nsname, item.name)
810 def gtypename_to_giname(self, gtname, names):
811 resolved = names.type_names.get(gtname)
813 return self._typepair_to_str(resolved)
814 resolved = self._names.type_names.get(gtname)
816 return self._typepair_to_str(resolved)
817 raise KeyError("Failed to resolve GType name: %r" % (gtname, ))
819 def ctype_of(self, obj):
820 if hasattr(obj, 'ctype'):
822 elif hasattr(obj, 'symbol'):
827 def follow_aliases(self, type_name, names):
829 resolved = names.aliases.get(type_name)
831 (ns, alias) = resolved
832 type_name = alias.target