diff options
Diffstat (limited to 'giscanner/transformer.py')
-rw-r--r-- | giscanner/transformer.py | 177 |
1 files changed, 100 insertions, 77 deletions
diff --git a/giscanner/transformer.py b/giscanner/transformer.py index 6afad889..f70d756a 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -34,6 +34,7 @@ from .sourcescanner import ( CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST, TYPE_QUALIFIER_CONST, TYPE_QUALIFIER_VOLATILE) + class TransformerException(Exception): pass @@ -54,14 +55,9 @@ class Transformer(object): self._namespace = namespace self._pkg_config_packages = set() self._typedefs_ns = {} - self._includes = {} # <string namespace -> Namespace> - self._include_names = set() # string namespace + self._parsed_includes = {} # <string namespace -> Namespace> self._includepaths = [] self._passthrough_mode = False - self._annotations = {} - - def get_includes(self): - return self._include_names def get_pkgconfig_packages(self): return self._pkg_config_packages @@ -72,9 +68,6 @@ class Transformer(object): def set_passthrough_mode(self): self._passthrough_mode = True - def set_annotations(self, annotations): - self._annotations = annotations - def _append_new_node(self, node): original = self._namespace.get(node.name) # Special case constants here; we allow duplication to sort-of @@ -112,7 +105,7 @@ class Transformer(object): if not ns_compound: ns_compound = self._namespace.get('_' + compound.name) if (not ns_compound and isinstance(compound, (ast.Record, ast.Union)) - and len(compound.fields) == 0): + and len(compound.fields) == 0): disguised = ast.Record(compound.name, typedef, disguised=True) self._namespace.append(disguised) elif not ns_compound: @@ -125,23 +118,23 @@ class Transformer(object): self._includepaths = list(paths) def register_include(self, include): - if include in self._include_names: + if include in self._namespace.includes: return + self._namespace.includes.add(include) filename = self._find_include(include) self._parse_include(filename) - self._include_names.add(include) def register_include_uninstalled(self, include_path): basename = os.path.basename(include_path) if not basename.endswith('.gir'): - raise SystemExit( -"Include path %r must be a filename path ending in .gir" % (include_path, )) + raise SystemExit("Include path %r must be a filename path " + "ending in .gir" % (include_path, )) girname = basename[:-4] include = ast.Include.from_string(girname) - if include in self._include_names: + if include in self._namespace.includes: return + self._namespace.includes.add(include) self._parse_include(include_path, uninstalled=True) - self._include_names.add(include) def lookup_giname(self, name): """Given a name of the form Foo or Bar.Foo, @@ -151,11 +144,16 @@ namespaces.""" if '.' not in name: return self._namespace.get(name) else: - (ns, name) = name.split('.', 1) + (ns, giname) = name.split('.', 1) if ns == self._namespace.name: - return self._namespace.get(name) - include = self._includes[ns] - return include.get(name) + return self._namespace.get(giname) + # Fallback to the main namespace if not a dependency and matches a prefix + if ns in self._namespace.identifier_prefixes and not ns in self._parsed_includes: + message.warn(("Deprecated reference to identifier " + + "prefix %s in GIName %s") % (ns, name)) + return self._namespace.get(giname) + include = self._parsed_includes[ns] + return include.get(giname) def lookup_typenode(self, typeobj): """Given a Type object, if it points to a giname, @@ -178,8 +176,7 @@ None.""" path = os.path.join(d, girname) if os.path.exists(path): return path - sys.stderr.write("Couldn't find include %r (search path: %r)\n"\ - % (girname, searchdirs)) + sys.stderr.write("Couldn't find include %r (search path: %r)\n" % (girname, searchdirs)) sys.exit(1) @classmethod @@ -191,7 +188,7 @@ None.""" self._parse_include(filename) parser = self._cachestore.load(filename) self._namespace = parser.get_namespace() - del self._includes[self._namespace.name] + del self._parsed_includes[self._namespace.name] return self def _parse_include(self, filename, uninstalled=False): @@ -204,20 +201,22 @@ None.""" if self._cachestore is not None: self._cachestore.store(filename, parser) - for include in parser.get_includes(): - self.register_include(include) + for include in parser.get_namespace().includes: + if include.name not in self._parsed_includes: + dep_filename = self._find_include(include) + self._parse_include(dep_filename) if not uninstalled: - for pkg in parser.get_pkgconfig_packages(): + for pkg in parser.get_namespace().exported_packages: self._pkg_config_packages.add(pkg) namespace = parser.get_namespace() - self._includes[namespace.name] = namespace + self._parsed_includes[namespace.name] = namespace def _iter_namespaces(self): """Return an iterator over all included namespaces; the currently-scanned namespace is first.""" yield self._namespace - for ns in self._includes.itervalues(): + for ns in self._parsed_includes.itervalues(): yield ns def _sort_matches(self, x, y): @@ -229,7 +228,7 @@ currently-scanned namespace is first.""" def _split_c_string_for_namespace_matches(self, name, is_identifier=False): matches = [] # Namespaces which might contain this name - unprefixed_namespaces = [] # Namespaces with no prefix, last resort + unprefixed_namespaces = [] # Namespaces with no prefix, last resort for ns in self._iter_namespaces(): if is_identifier: prefixes = ns.identifier_prefixes @@ -286,7 +285,7 @@ raise ValueError.""" ident = ident[1:] try: matches = self.split_ctype_namespaces(ident) - except ValueError, e: + except ValueError as e: raise TransformerException(str(e)) for ns, name in matches: if ns is self._namespace: @@ -306,7 +305,7 @@ raise ValueError.""" ident = ident[1:] try: (ns, name) = self.split_csymbol(ident) - except ValueError, e: + except ValueError as e: raise TransformerException(str(e)) if ns != self._namespace: raise TransformerException( @@ -333,10 +332,7 @@ raise ValueError.""" elif stype == CSYMBOL_TYPE_UNION: return self._create_union(symbol) elif stype == CSYMBOL_TYPE_CONST: - # Don't parse constants which are marked (skip) - docblock = self._annotations.get(symbol.ident) - if not docblock or not 'skip' in docblock.options: - return self._create_const(symbol) + return self._create_const(symbol) # Ignore variable declarations in the header elif stype == CSYMBOL_TYPE_OBJECT: pass @@ -383,7 +379,7 @@ raise ValueError.""" # prefix. try: name = self._strip_symbol(child) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None members.append(ast.Member(name.lower(), @@ -393,7 +389,7 @@ raise ValueError.""" try: enum_name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None if symbol.base_type.is_bitfield: @@ -408,11 +404,11 @@ raise ValueError.""" # Drop functions that start with _ very early on here if symbol.ident.startswith('_'): return None - parameters = list(self._create_parameters(symbol.base_type)) + parameters = list(self._create_parameters(symbol, symbol.base_type)) return_ = self._create_return(symbol.base_type.base_type) try: name = self._strip_symbol(symbol) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None func = ast.Function(name, return_, parameters, False, symbol.ident) @@ -476,11 +472,11 @@ raise ValueError.""" return value - def _create_parameters(self, base_type): + def _create_parameters(self, symbol, base_type): # warn if we see annotations for unknown parameters param_names = set(child.ident for child in base_type.child_list) - for child in base_type.child_list: - yield self._create_parameter(child) + for i, child in enumerate(base_type.child_list): + yield self._create_parameter(symbol, i, child) def _synthesize_union_type(self, symbol, parent_symbol): # Synthesize a named union so that it can be referenced. @@ -506,8 +502,8 @@ raise ValueError.""" def _create_member(self, symbol, parent_symbol=None): source_type = symbol.base_type - if (source_type.type == CTYPE_POINTER and - symbol.base_type.base_type.type == CTYPE_FUNCTION): + if (source_type.type == CTYPE_POINTER + and symbol.base_type.base_type.type == CTYPE_FUNCTION): node = self._create_callback(symbol, member=True) elif source_type.type == CTYPE_STRUCT and source_type.name is None: node = self._create_struct(symbol, anonymous=True) @@ -523,8 +519,8 @@ raise ValueError.""" # to be able to properly calculate the size of the compound # type (e.g. GValue) that contains this array, see # <https://bugzilla.gnome.org/show_bug.cgi?id=657040>. - if (source_type.base_type.type == CTYPE_UNION and - source_type.base_type.name is None): + if (source_type.base_type.type == CTYPE_UNION + and source_type.base_type.name is None): synthesized_type = self._synthesize_union_type(symbol, parent_symbol) ftype = ast.Array(None, synthesized_type, complete_ctype=complete_ctype) else: @@ -562,11 +558,9 @@ raise ValueError.""" def _create_typedef(self, symbol): ctype = symbol.base_type.type - if (ctype == CTYPE_POINTER and - symbol.base_type.base_type.type == CTYPE_FUNCTION): + if (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_FUNCTION): node = self._create_typedef_callback(symbol) - elif (ctype == CTYPE_POINTER and - symbol.base_type.base_type.type == CTYPE_STRUCT): + elif (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_STRUCT): node = self._create_typedef_struct(symbol, disguised=True) elif ctype == CTYPE_STRUCT: node = self._create_typedef_struct(symbol) @@ -580,7 +574,7 @@ raise ValueError.""" CTYPE_VOID): try: name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn(e) return None if symbol.base_type.name: @@ -631,8 +625,7 @@ raise ValueError.""" derefed_typename = canonical.replace('*', '') # Preserve "pointerness" of struct/union members - if (is_member and canonical.endswith('*') and - derefed_typename in ast.basic_type_names): + if (is_member and canonical.endswith('*') and derefed_typename in ast.basic_type_names): return 'gpointer' else: return derefed_typename @@ -693,26 +686,36 @@ raise ValueError.""" return container return ast.Type(ctype=ctype, is_const=is_const, complete_ctype=complete_ctype) - def _create_parameter(self, symbol): + def _create_parameter(self, parent_symbol, index, symbol): if symbol.type == CSYMBOL_TYPE_ELLIPSIS: ptype = ast.Varargs() else: ptype = self._create_type_from_base(symbol.base_type, is_parameter=True) - return ast.Parameter(symbol.ident, ptype) + + if symbol.ident is None: + if symbol.base_type and symbol.base_type.type != CTYPE_VOID: + message.warn_symbol(parent_symbol, "missing parameter name; undocumentable") + ident = 'arg%d' % (index, ) + else: + ident = symbol.ident + + return ast.Parameter(ident, ptype) def _create_return(self, source_type): typeval = self._create_type_from_base(source_type, is_return=True) return ast.Return(typeval) def _create_const(self, symbol): + if symbol.ident.startswith('_'): + return None + # Don't create constants for non-public things # http://bugzilla.gnome.org/show_bug.cgi?id=572790 - if (symbol.source_filename is None or - not symbol.source_filename.endswith('.h')): + if (symbol.source_filename is None or not symbol.source_filename.endswith('.h')): return None try: name = self._strip_symbol(symbol) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None if symbol.const_string is not None: @@ -731,13 +734,13 @@ raise ValueError.""" if isinstance(target, ast.Type): unaliased = target if unaliased == ast.TYPE_UINT64: - value = str(symbol.const_int % 2**64) + value = str(symbol.const_int % 2 ** 64) elif unaliased == ast.TYPE_UINT32: - value = str(symbol.const_int % 2**32) + value = str(symbol.const_int % 2 ** 32) elif unaliased == ast.TYPE_UINT16: - value = str(symbol.const_int % 2**16) + value = str(symbol.const_int % 2 ** 16) elif unaliased == ast.TYPE_UINT8: - value = str(symbol.const_int % 2**16) + value = str(symbol.const_int % 2 ** 16) else: value = str(symbol.const_int) elif symbol.const_double is not None: @@ -754,7 +757,7 @@ raise ValueError.""" def _create_typedef_struct(self, symbol, disguised=False): try: name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None struct = ast.Record(name, symbol.ident, disguised=disguised) @@ -766,7 +769,7 @@ raise ValueError.""" def _create_typedef_union(self, symbol): try: name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn(e) return None union = ast.Union(name, symbol.ident) @@ -814,7 +817,7 @@ raise ValueError.""" else: try: name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn(e) return None compound = klass(name, symbol.ident) @@ -830,13 +833,12 @@ raise ValueError.""" return self._create_compound(ast.Union, symbol, anonymous) def _create_callback(self, symbol, member=False): - parameters = list(self._create_parameters(symbol.base_type.base_type)) + parameters = list(self._create_parameters(symbol, symbol.base_type.base_type)) retval = self._create_return(symbol.base_type.base_type.base_type) # Mark the 'user_data' arguments for i, param in enumerate(parameters): - if (param.type.target_fundamental == 'gpointer' and - param.argname == 'user_data'): + if (param.type.target_fundamental == 'gpointer' and param.argname == 'user_data'): param.closure_name = param.argname if member: @@ -844,13 +846,13 @@ raise ValueError.""" elif symbol.ident.find('_') > 0: try: name = self._strip_symbol(symbol) - except TransformerException, e: + except TransformerException as e: message.warn_symbol(symbol, e) return None else: try: name = self.strip_identifier(symbol.ident) - except TransformerException, e: + except TransformerException as e: message.warn(e) return None callback = ast.Callback(name, retval, parameters, False, @@ -868,9 +870,12 @@ Note that type resolution may not succeed.""" if '.' in typestr: container = self._create_bare_container_type(typestr) if container: - return container - return self._namespace.type_from_name(typestr) - typeval = self.create_type_from_ctype_string(typestr) + typeval = container + else: + typeval = self._namespace.type_from_name(typestr) + else: + typeval = self.create_type_from_ctype_string(typestr) + self.resolve_type(typeval) if typeval.resolved: # Explicitly clear out the c_type; there isn't one in this case. @@ -883,7 +888,7 @@ Note that type resolution may not succeed.""" # which has nominal namespace of "Meta", but a few classes are # "Mutter". We don't export that data in introspection currently. # Basically the library should be fixed, but we'll hack around it here. - for namespace in self._includes.itervalues(): + for namespace in self._parsed_includes.itervalues(): target = namespace.get_by_ctype(pointer_stripped) if target: typeval.target_giname = '%s.%s' % (namespace.name, target.name) @@ -895,9 +900,8 @@ Note that type resolution may not succeed.""" pointer_stripped = typeval.ctype.replace('*', '') try: matches = self.split_ctype_namespaces(pointer_stripped) - except ValueError, e: + except ValueError: return self._resolve_type_from_ctype_all_namespaces(typeval, pointer_stripped) - target_giname = None for namespace, name in matches: target = namespace.get(name) if not target: @@ -916,7 +920,7 @@ Note that type resolution may not succeed.""" return True return False - def resolve_type(self, typeval): + def _resolve_type_internal(self, typeval): if isinstance(typeval, (ast.Array, ast.List)): return self.resolve_type(typeval.element_type) elif isinstance(typeval, ast.Map): @@ -930,6 +934,25 @@ Note that type resolution may not succeed.""" elif typeval.gtype_name: return self._resolve_type_from_gtype_name(typeval) + def resolve_type(self, typeval): + if not self._resolve_type_internal(typeval): + return False + + if typeval.target_fundamental or typeval.target_foreign: + return True + + assert typeval.target_giname is not None + + try: + type_ = self.lookup_giname(typeval.target_giname) + except KeyError: + type_ = None + + if type_ is None: + typeval.target_giname = None + + return typeval.resolved + def _typepair_to_str(self, item): nsname, item = item if nsname is None: |