summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-09-01 17:55:30 -0400
committerColin Walters <walters@verbum.org>2010-09-01 17:55:30 -0400
commitf9db355f2f1f55307e32e0f9f2d787f46941681b (patch)
treeaed47efe287c73eb9ee78914b9942267a74a1197
parentfb6979ec7555bba02ebf80cb8756ae274759ac8e (diff)
downloadgobject-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.py18
-rw-r--r--giscanner/gdumpparser.py12
-rw-r--r--giscanner/introspectablepass.py5
-rw-r--r--giscanner/transformer.py31
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