diff options
author | Colin Walters <walters@verbum.org> | 2010-09-01 17:55:30 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2010-09-01 17:55:30 -0400 |
commit | f9db355f2f1f55307e32e0f9f2d787f46941681b (patch) | |
tree | aed47efe287c73eb9ee78914b9942267a74a1197 | |
parent | fb6979ec7555bba02ebf80cb8756ae274759ac8e (diff) | |
download | gobject-introspection-f9db355f2f1f55307e32e0f9f2d787f46941681b.tar.gz |
scanner: Better handling of GType names
Before, Type instances could be indeterminate, holding a "ctype",
which means "This is some unresolved string". However, we also get
data from GType, so add gtype_name as another indeterminate state.
Clean up how we create and resolve Type instances from GType data.
-rw-r--r-- | giscanner/ast.py | 18 | ||||
-rw-r--r-- | giscanner/gdumpparser.py | 12 | ||||
-rw-r--r-- | giscanner/introspectablepass.py | 5 | ||||
-rw-r--r-- | giscanner/transformer.py | 31 |
4 files changed, 53 insertions, 13 deletions
diff --git a/giscanner/ast.py b/giscanner/ast.py index 915c3ed5..c819d024 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -27,12 +27,14 @@ class Type(object): * A reference to a node (target_giname) * A reference to a "fundamental" type like 'utf8' * A "foreign" type - this can be any string." -If none are specified, then it's in an "unresolved" state. -In this case, the ctype must be specified. +If none are specified, then it's in an "unresolved" state. An +unresolved type can have two data sources; a "ctype" which comes +from a C type string, or a gtype_name (from g_type_name()). """ def __init__(self, ctype=None, + gtype_name=None, target_fundamental=None, target_giname=None, target_foreign=None, @@ -40,6 +42,7 @@ In this case, the ctype must be specified. is_const=False, origin_symbol=None): self.ctype = ctype + self.gtype_name = gtype_name self.origin_symbol = origin_symbol if _target_unknown: assert isinstance(self, TypeUnknown) @@ -55,7 +58,7 @@ In this case, the ctype must be specified. assert target_giname is None assert target_fundamental is None else: - assert ctype is not None + assert (ctype is not None) or (gtype_name is not None) self.target_fundamental = target_fundamental self.target_giname = target_giname self.target_foreign = target_foreign @@ -67,6 +70,15 @@ In this case, the ctype must be specified. self.target_giname or self.target_foreign) + @property + def unresolved_string(self): + if self.ctype: + return self.ctype + elif self.gtype_name: + return self.gtype_name + else: + assert False + def get_giname(self): assert self.target_giname is not None return self.target_giname.split('.')[1] diff --git a/giscanner/gdumpparser.py b/giscanner/gdumpparser.py index ce6f9a25..ca9b38a9 100644 --- a/giscanner/gdumpparser.py +++ b/giscanner/gdumpparser.py @@ -301,7 +301,7 @@ blob containing data gleaned from GObject's primitive introspection.""" self._introspect_signals(node, xmlnode) for child in xmlnode.findall('prerequisite'): name = child.attrib['name'] - prereq = self._transformer.create_type_from_user_string(name) + prereq = self._transformer.create_type_from_gtype_name(name) node.prerequisites.append(prereq) # GtkFileChooserEmbed is an example of a private interface, we # just filter them out @@ -321,7 +321,7 @@ blob containing data gleaned from GObject's primitive introspection.""" def _introspect_implemented_interfaces(self, node, xmlnode): gt_interfaces = [] for interface in xmlnode.findall('implements'): - gitype = self._transformer.create_type_from_user_string(interface.attrib['name']) + gitype = self._transformer.create_type_from_gtype_name(interface.attrib['name']) gt_interfaces.append(gitype) node.interfaces = gt_interfaces @@ -335,7 +335,7 @@ blob containing data gleaned from GObject's primitive introspection.""" construct_only = (flags & G_PARAM_CONSTRUCT_ONLY) != 0 node.properties.append(ast.Property( pspec.attrib['name'], - self._transformer.create_type_from_user_string(ctype), + self._transformer.create_type_from_gtype_name(ctype), readable, writable, construct, construct_only, ctype, )) @@ -344,7 +344,7 @@ blob containing data gleaned from GObject's primitive introspection.""" def _introspect_signals(self, node, xmlnode): for signal_info in xmlnode.findall('signal'): rctype = signal_info.attrib['return'] - rtype = self._transformer.create_type_from_user_string(rctype) + rtype = self._transformer.create_type_from_gtype_name(rctype) return_ = ast.Return(rtype) parameters = [] for i, parameter in enumerate(signal_info.findall('param')): @@ -353,7 +353,7 @@ blob containing data gleaned from GObject's primitive introspection.""" else: argname = 'p%s' % (i-1, ) pctype = parameter.attrib['type'] - ptype = self._transformer.create_type_from_user_string(pctype) + ptype = self._transformer.create_type_from_gtype_name(pctype) param = ast.Parameter(argname, ptype) param.transfer = ast.PARAM_TRANSFER_NONE parameters.append(param) @@ -364,7 +364,7 @@ blob containing data gleaned from GObject's primitive introspection.""" def _parse_parents(self, xmlnode, node): parents_str = xmlnode.attrib.get('parents', '') if parents_str != '': - parent_types = map(lambda s: self._transformer.create_type_from_user_string(s), + parent_types = map(lambda s: self._transformer.create_type_from_gtype_name(s), parents_str.split(',')) else: parent_types = [] diff --git a/giscanner/introspectablepass.py b/giscanner/introspectablepass.py index f3ab7e65..78434116 100644 --- a/giscanner/introspectablepass.py +++ b/giscanner/introspectablepass.py @@ -64,7 +64,8 @@ class IntrospectablePass(object): target = None if not node.type.resolved: - self._parameter_warning(parent, node, "Unresolved ctype: %r" % (node.type.ctype, )) + self._parameter_warning(parent, node, +"Unresolved type: %r" % (node.type.unresolved_string, )) parent.introspectable = False return @@ -113,6 +114,8 @@ class IntrospectablePass(object): def _type_is_introspectable(self, typeval, warn=False): if not typeval.resolved: return False + if isinstance(typeval, ast.TypeUnknown): + return False if isinstance(typeval, (ast.Array, ast.List)): return self._type_is_introspectable(typeval.element_type) elif isinstance(typeval, ast.Map): diff --git a/giscanner/transformer.py b/giscanner/transformer.py index a851f791..de9d7cac 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -23,6 +23,7 @@ import sys import re from . import ast +from . import glibast from .config import DATADIR, GIR_DIR, GIR_SUFFIX from .girparser import GIRParser from .sourcescanner import ( @@ -304,9 +305,8 @@ currently-scanned namespace is first.""" for ns in unprefixed_namespaces: if name in ns: return [(ns, name)] - else: - raise ValueError("Unknown namespace for %s %r" - % ('identifier' if is_identifier else 'symbol', name, )) + raise ValueError("Unknown namespace for %s %r" + % ('identifier' if is_identifier else 'symbol', name, )) def split_ctype_namespaces(self, ident): """Given a StudlyCaps string identifier like FooBar, return a @@ -791,7 +791,18 @@ Note that type resolution may not succeed.""" typeval.ctype = None return typeval + def create_type_from_gtype_name(self, gtype_name): + """Parse a GType name (as from g_type_name()), and return a +Type instance. Note that this function performs namespace lookup, +in contrast to the other create_type() functions.""" + # First, is it a fundamental? + fundamental = ast.type_names.get(gtype_name) + if fundamental is not None: + return ast.Type(target_fundamental=fundamental.target_fundamental) + return ast.Type(gtype_name=gtype_name) + def _resolve_type_from_ctype(self, typeval): + assert typeval.ctype is not None pointer_stripped = typeval.ctype.replace('*', '') try: matches = self.split_ctype_namespaces(pointer_stripped) @@ -807,6 +818,18 @@ Note that type resolution may not succeed.""" return True return False + def _resolve_type_from_gtype_name(self, typeval): + assert typeval.gtype_name is not None + for ns in self._iter_namespaces(): + for node in ns.itervalues(): + if not isinstance(node, (ast.Class, ast.Interface, + glibast.GLibBoxed)): + continue + if node.type_name == typeval.gtype_name: + typeval.target_giname = '%s.%s' % (ns.name, node.name) + return True + return False + def resolve_type(self, typeval): if isinstance(typeval, (ast.Array, ast.List)): return self.resolve_type(typeval.element_type) @@ -818,6 +841,8 @@ Note that type resolution may not succeed.""" return True elif typeval.ctype: return self._resolve_type_from_ctype(typeval) + elif typeval.gtype_name: + return self._resolve_type_from_gtype_name(typeval) def _typepair_to_str(self, item): nsname, item = item |