[gobject-introspection/wip/transformer] pair up methods/constructors
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gobject-introspection/wip/transformer] pair up methods/constructors
- Date: Wed, 21 Jul 2010 20:10:01 +0000 (UTC)
commit ca9e1df4b881c923284f0776929dbc44431eed1d
Author: Colin Walters <walters verbum org>
Date: Wed Jul 21 16:09:05 2010 -0400
pair up methods/constructors
giscanner/annotationparser.py | 4 +
giscanner/ast.py | 84 +++++++++-
giscanner/girwriter.py | 7 +-
giscanner/glibast.py | 14 ++-
giscanner/glibtransformer.py | 364 ++++++++++++++++------------------------
giscanner/transformer.py | 56 +++++--
6 files changed, 286 insertions(+), 243 deletions(-)
---
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 7ee6c0e..0e98556 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -375,6 +375,7 @@ class AnnotationApplier(object):
block = self._blocks.get(interface.type_name)
self._parse_node_common(interface, block)
self._parse_methods(interface, interface.methods)
+ self._parse_methods(interface, interface.static_methods)
self._parse_vfuncs(interface, interface.virtual_methods)
self._parse_properties(interface, interface.properties)
self._parse_signals(interface, interface.signals)
@@ -387,6 +388,7 @@ class AnnotationApplier(object):
self._parse_node_common(record, block)
self._parse_constructors(record.constructors)
self._parse_methods(record, record.methods)
+ self._parse_methods(record, record.static_methods)
self._parse_fields(record, record.fields, block)
if block:
record.doc = block.comment
@@ -396,6 +398,7 @@ class AnnotationApplier(object):
self._parse_node_common(boxed, block)
self._parse_constructors(boxed.constructors)
self._parse_methods(boxed, boxed.methods)
+ self._parse_methods(boxed, boxed.static_methods)
if block:
boxed.doc = block.comment
@@ -405,6 +408,7 @@ class AnnotationApplier(object):
self._parse_fields(union, union.fields, block)
self._parse_constructors(union.constructors)
self._parse_methods(union, union.methods)
+ self._parse_methods(union, union.static_methods)
if block:
union.doc = block.comment
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 92a047f..d37af5a 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -20,11 +20,9 @@
#
from .odict import odict
+from .utils import to_underscores
class Type(object):
- resolved = property(lambda self: (self.target_fundamental or
- self.target_giname or
- self.target_foreign))
"""A Type can be either:
* A reference to a node (target_giname)
* A reference to a "fundamental" type like 'utf8'
@@ -32,6 +30,11 @@ class Type(object):
If none are specified, then it's in an "unresolved" state.
In this case, the ctype must be specified.
"""
+
+ resolved = property(lambda self: (self.target_fundamental or
+ self.target_giname or
+ self.target_foreign))
+
def __init__(self,
ctype=None,
target_fundamental=None,
@@ -60,6 +63,10 @@ In this case, the ctype must be specified.
self.target_foreign = target_foreign
self.is_const = is_const
+ def get_giname(self):
+ assert self.target_giname is not None
+ return self.target_giname.split('.')[1]
+
def is_equiv(self, typeval):
"""Return True if the specified types are compatible at
an introspection level, disregarding their C types.
@@ -87,6 +94,14 @@ In this case, the ctype must be specified.
ctype=self.ctype,
is_const=self.is_const)
+ def __str__(self):
+ if self.target_fundamental:
+ return 'Type(target_fundamental=%s)' % (self.target_fundamental, )
+ elif self.target_giname:
+ return 'Type(target_giname=%s)' % (self.target_giname, )
+ elif self.target_foreign:
+ return 'Type(target_foreign=%s)' % (self.target_foreign, )
+
######
## Fundamental types
######
@@ -241,6 +256,7 @@ class Namespace(object):
self.version = version
self.c_prefix = c_prefix or name
self._lower_c_prefix = c_prefix.lower()
+ self.uscore_prefix = to_underscores(c_prefix).lower()
self._names = odict() # Maps from GIName -> node
self._aliases = {} # Maps from GIName -> GIName
self._type_names = {} # Maps from GTName -> node
@@ -296,12 +312,19 @@ identifier string."""
del self._aliases[node.name]
elif isinstance(node, (GLibBoxed, Interface, Class)):
del self._type_names[node.type_name]
+ del self._names[node.name]
node.namespace = None
if hasattr(node, 'ctype'):
del self._ctypes[node.ctype]
if hasattr(node, 'symbol'):
del self._ctypes[node.symbol]
+ def float(self, node):
+ """Like remove(), but doesn't unset the node's namespace
+back-reference."""
+ self.remove(node)
+ node.namespace = self
+
def __iter__(self):
return iter(self._names)
@@ -314,6 +337,15 @@ identifier string."""
def get(self, name):
return self._names.get(name)
+ def walk(self, callback):
+ for node in self.itervalues():
+ node.walk(callback, [])
+
+ def iter_recursive(self):
+ """Recursively iterate over all Node instances."""
+ def doyield(node, chain):
+ yield node
+ self.walk(test)
class Include(object):
@@ -390,6 +422,15 @@ GIName. It's possible for nodes to contain or point to other nodes."""
if symbol.source_filename:
self.add_file_position(symbol.source_filename, symbol.line, -1)
+ def walk(self, callback, chain):
+ if not callback(self, chain):
+ return False
+ chain.append(self)
+ self._walk(callback, chain)
+ chain.pop()
+
+ def _walk(self, callback, chain):
+ pass
class Callable(Node):
@@ -576,6 +617,15 @@ class Record(Node):
self.symbol = symbol
self.disguised = disguised
self.methods = []
+ self.static_methods = []
+
+ def _walk(self, callback, chain):
+ for ctor in self.constructors:
+ ctor.walk(callback, chain)
+ for func in self.methods:
+ func.walk(callback, chain)
+ for func in self.static_methods:
+ func.walk(callback, chain)
def remove_matching_children(self, pred):
self.fields = filter(pred, self.fields)
@@ -595,7 +645,6 @@ class Field(Annotated):
self.bits = bits
self.anonymous_node = anonymous_node
-
class Class(Node):
def __init__(self, name, parent, is_abstract):
@@ -622,7 +671,15 @@ class Class(Node):
self.properties = filter(pred, self.properties)
self.fields = filter(pred, self.fields)
-
+ def _walk(self, callback, chain):
+ for meth in self.methods:
+ meth.walk(callback, chain)
+ for meth in self.virtual_methods:
+ meth.walk(callback, chain)
+ for meth in self.static_methods:
+ meth.walk(callback, chain)
+ for ctor in self.constructors:
+ ctor.walk(callback, chain)
class Interface(Node):
@@ -631,12 +688,20 @@ class Interface(Node):
self.parent = parent
self.parent_chain = []
self.methods = []
+ self.static_methods = []
self.virtual_methods = []
self.glib_type_struct = None
self.properties = []
self.fields = []
self.prerequisites = []
+ def _walk(self, callback, chain):
+ for meth in self.methods:
+ meth.walk(callback, chain)
+ for meth in self.static_methods:
+ meth.walk(callback, chain)
+ for meth in self.virtual_methods:
+ meth.walk(callback, chain)
class Constant(Node):
@@ -673,4 +738,13 @@ class Union(Node):
self.fields = []
self.constructors = []
self.methods = []
+ self.static_methods = []
self.symbol = symbol
+
+ def _walk(self, callback, chain):
+ for ctor in self.constructors:
+ ctor.walk(callback, chain)
+ for meth in self.methods:
+ meth.walk(callback, chain)
+ for meth in self.static_methods:
+ meth.walk(callback, chain)
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 7d73364..09d27bd 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -176,7 +176,6 @@ and/or use gtk-doc annotations. ''')
attrs = []
if hasattr(func, 'symbol'):
attrs.append(('c:identifier', func.symbol))
- print "writing %r" % (func, )
self._write_callable(func, tag_name, attrs)
def _write_method(self, method):
@@ -399,6 +398,8 @@ and/or use gtk-doc annotations. ''')
self._write_constructor(method)
for method in boxed.methods:
self._write_method(method)
+ for method in boxed.static_methods:
+ self._write_static_method(method)
def _write_property(self, prop):
attrs = [('name', prop.name)]
@@ -461,6 +462,8 @@ and/or use gtk-doc annotations. ''')
self._write_constructor(method)
for method in record.methods:
self._write_method(method)
+ for method in record.static_methods:
+ self._write_static_method(method)
def _write_union(self, union):
attrs = []
@@ -481,6 +484,8 @@ and/or use gtk-doc annotations. ''')
self._write_constructor(method)
for method in union.methods:
self._write_method(method)
+ for method in union.static_methods:
+ self._write_static_method(method)
def _write_field(self, field, is_gtype_struct=False):
if field.anonymous_node:
diff --git a/giscanner/glibast.py b/giscanner/glibast.py
index 72be10f..69f1c0b 100644
--- a/giscanner/glibast.py
+++ b/giscanner/glibast.py
@@ -86,8 +86,6 @@ class GLibObject(Class):
self.get_value_func = None
self.signals = []
self.ctype = ctype or type_name
- # Unresolved state
- self.parent_gtype_names = []
class GLibBoxed:
@@ -97,6 +95,8 @@ class GLibBoxed:
self.get_type = get_type
+
+
class GLibBoxedStruct(Record, GLibBoxed):
def __init__(self, name, type_name, get_type, ctype=None):
@@ -118,9 +118,19 @@ class GLibBoxedOther(Node, GLibBoxed):
GLibBoxed.__init__(self, type_name, get_type)
self.constructors = []
self.methods = []
+ self.static_methods = []
self.ctype = type_name
self.doc = None
+ def _walk(self, callback, chain):
+ for ctor in self.constructors:
+ ctor.walk(callback, chain)
+ for meth in self.methods:
+ meth.walk(callback, chain)
+ for meth in self.static_methods:
+ meth.walk(callback, chain)
+
+
class GLibInterface(Interface):
def __init__(self, name, parent, type_name, get_type,
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 10a980d..92c35d8 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -28,7 +28,7 @@ import subprocess
from .ast import (Alias, Bitfield, Callable, Callback, Class, Constant, Enum,
Function, Interface, Member, Namespace, Node, Parameter,
Property, Record, Return, Type, TypeContainer, Union,
- Field, VFunction, default_array_types,
+ Class, Field, VFunction, default_array_types,
TYPE_ANY, TYPE_GTYPE, TYPE_UINT8, PARAM_TRANSFER_FULL, Array, List,
Map, Varargs, type_names)
from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
@@ -79,7 +79,6 @@ class GLibTransformer(object):
self._get_type_functions = []
self._error_quark_functions = []
self._gtype_data = {}
- self._failed_types = {}
self._boxed_types = {}
self._private_internal_types = {}
@@ -126,26 +125,35 @@ class GLibTransformer(object):
for child in root:
self._introspect_type(child)
- # Pair boxed structures; doesn't depend on anything else.
- for boxed in self._boxed_types.itervalues():
- self._pair_boxed_type(boxed)
-
- # Second pass; Initial type resolution
+ # Pair up boxed structures and class structures
+ for node in self._namespace.itervalues():
+ if isinstance(node, GLibBoxed):
+ self._pair_boxed_type(node)
+ elif isinstance(node, Record):
+ self._pair_class_record(node)
+
+ # We have a rough tree which should have all
+ # of the types we know about. Let's attempt closure; walk
+ # over all of the Type() types and see if they match up
+ # with something.
+ self._namespace.walk(self._pass_type_resolution)
+
+ # Generate a reverse mapping "bar_baz" -> BarBaz
for node in self._namespace.itervalues():
- self.walk_node(node, self._pass_type_resolution, [])
+ uscored = to_underscores_noprefix(node.name).lower()
+ if isinstance(node, (Class, Interface, Record, Union, GLibBoxedOther)):
+ self._uscore_type_names[uscored] = node
- # Now move around the functions that are actually methods
- #for node in self._namespace:
- # if isinstance(node, Function):
- # self._pair_function(node)
+ for node in list(self._namespace.itervalues()):
+ # Discover which functions are actually methods
+ if isinstance(node, Function):
+ self._pair_function(node)
+
+ self._namespace.walk(self._pass3_callable)
# Third pass
for node in self._namespace.itervalues():
- if isinstance(node, Record):
- self._pass3_pair_class_record(node)
- elif isinstance(node, Callable):
- self._pass3_callable(node)
- self._resolve_quarks()
+ self._resolve_quarks()
return self._namespace
@@ -176,10 +184,10 @@ class GLibTransformer(object):
for parent in node.parent_chain:
try:
self._transformer.resolve_type(parent)
- resolved_parent = parent
except ValueError, e:
continue
- node.parent = resolved_parent
+ node.parent = parent
+ break
for prop in node.properties:
self._transformer.resolve_type(prop.type)
for sig in node.signals:
@@ -280,7 +288,7 @@ blob containing data gleaned from GObject's primitive introspection."""
parent_gitype = None
symbol = 'intern'
elif type_name == 'GInitiallyUnowned':
- parent_gitype = 'GLib.Object'
+ parent_gitype = Type(target_giname='GLib.Object')
symbol = 'g_initially_unowned_get_type'
else:
assert False
@@ -346,123 +354,110 @@ blob containing data gleaned from GObject's primitive introspection."""
except KeyError, e:
return False
- def _parse_static_method(self, func):
- components = func.symbol.split('_')
- if len(components) < 2:
- return None
- target_klass = None
- prefix_components = None
- methname = None
- for i in xrange(1, len(components)):
- prefix_components = '_'.join(components[0:-i])
- methname = '_'.join(components[-i:])
- target_klass = self._uscore_type_names.get(prefix_components)
- if target_klass and isinstance(target_klass, GLibObject):
- break
- target_klass = None
- if not target_klass:
- return None
- self._namespace.remove(func)
- func.name = methname
- target_klass.static_methods.append(func)
- func.is_method = True
- return func
-
- def _parse_method(self, func):
- if not func.parameters:
- return False
- return self._parse_method_common(func, True)
-
- def _parse_constructor(self, func):
- return self._parse_method_common(func, False)
+ def _split_uscored_by_type(self, uscored):
+ """'uscored' should be an un-prefixed uscore string. This
+function searches through the namespace for the longest type which
+prefixes uscored, and returns (type, suffix). Example, assuming
+namespace Gtk, type is TextBuffer:
+
+_split_uscored_by_type(text_buffer_try_new) -> (Class(TextBuffer), 'try_new')"""
+ node = None
+ count = 0
+ prev_split_count = -1
+ while True:
+ components = uscored.rsplit('_', count)
+ if len(components) == prev_split_count:
+ return None
+ prev_split_count = len(components)
+ type_string = components[0]
+ node = self._uscore_type_names.get(type_string)
+ if node:
+ return (node, '_'.join(components[1:]))
+ count += 1
- def _parse_method_common(self, func, is_method):
- # Skip _get_type functions, we processed them
- # already
+ def _pair_function(self, func):
+ """Check to see whether a toplevel function should be a
+method or constructor of some type."""
if func.symbol.endswith('_get_type'):
- return None
+ return
+ (ns, subsymbol) = self._transformer.split_csymbol(func.symbol)
+ assert ns == self._namespace
+ if self._pair_constructor(func, subsymbol):
+ return
+ elif self._pair_method(func, subsymbol):
+ return
+ elif self._pair_static_method(func, subsymbol):
+ return
- if not is_method:
- target_arg = func.retval
- else:
- target_arg = func.parameters[0]
-
- if is_method:
- # Methods require their first arg to be a known class
- # Look at the original C type (before namespace stripping), without
- # pointers: GtkButton -> gtk_button_, so we can figure out the
- # method name
- argtype = target_arg.type.ctype.replace('*', '')
- name = self._transformer.remove_prefix(argtype)
- name_uscore = to_underscores_noprefix(name).lower()
- # prefer the prefix of the _get_type method, if there is one
- if argtype in self._namespace.type_names:
- node = self._names.type_names[argtype][1]
- if hasattr(node, 'get_type'):
- name_uscore = GET_TYPE_OVERRIDES.get(node.get_type,
- node.get_type)
- name_uscore = name_uscore[:-len('_get_type')]
- name_offset = func.symbol.find(name_uscore + '_')
- if name_offset < 0:
- return None
- prefix = func.symbol[:name_offset+len(name_uscore)]
- else:
- # Constructors must have _new
- # Take everything before that as class name
- new_idx = func.symbol.find('_new')
- if new_idx < 0:
- return None
- if derefed in type_names:
- #print "NOTE: Rejecting constructor returning basic: %r" \
- # % (func.symbol, )
- return None
- prefix = func.symbol[:new_idx]
-
- klass = self._uscore_type_names.get(prefix)
- if klass is None:
- #print "NOTE: No valid matching class for likely "+\
- # "method or constructor: %r" % (func.symbol, )
- return None
- # Enums can't have ctors or methods
- if isinstance(klass, (GLibEnum, GLibFlags)):
- return None
-
- # The _uscore_type_names member holds the plain GLibBoxed
- # object; we want to actually use the struct/record associated
- if isinstance(klass, (Record, Union)):
- remove_prefix = klass.symbol
- else:
- remove_prefix = klass.type_name
+ def _uscored_identifier_for_type(self, typeval):
+ """Given a Type(target_giname='Foo.BarBaz'), return 'bar_baz'."""
+ name = typeval.get_giname()
+ return to_underscores_noprefix(name).lower()
- name = self._transformer.remove_prefix(remove_prefix)
- klass = self._namespace.get(name)
- if klass is None:
- return
+ def _pair_method(self, func, subsymbol):
+ if not func.parameters:
+ return False
+ first = func.parameters[0]
+ target = self._transformer.lookup_typenode(first.type)
+ if not isinstance(target, (Class, Interface, Record, Union, GLibBoxedOther)):
+ return False
+ uscored = self._uscored_identifier_for_type(first.type)
+ if not subsymbol.startswith(uscored):
+ return False
+ del func.parameters[0]
+ subsym_idx = func.symbol.find(subsymbol)
+ self._namespace.float(func)
+ func.name = func.symbol[(subsym_idx + len(uscored) + 1):]
+ target.methods.append(func)
+ func.is_method = True
+ return True
- if not is_method:
- # Interfaces can't have constructors, punt to global scope
- if isinstance(klass, GLibInterface):
- #print "NOTE: Rejecting constructor for"+\
- # " interface type: %r" % (func.symbol, )
- return None
- # TODO - check that the return type is a subclass of the
- # class from the prefix
- # But for now, ensure that constructor returns are always
- # the most concrete class
- name = self._transformer.remove_prefix(remove_prefix)
- func.retval.type = Type(name, func.retval.type.ctype)
-
- self._namespace.remove(func)
- # Strip namespace and object prefix: gtk_window_new -> new
- func.name = func.symbol[len(prefix)+1:]
- if is_method:
- # We don't need the "this" parameter
- del func.parameters[0]
- klass.methods.append(func)
- func.is_method = True
+ def _pair_static_method(self, func, subsymbol):
+ split = self._split_uscored_by_type(subsymbol)
+ if split is None:
+ return False
+ (node, funcname) = split
+ if not isinstance(node, (Class, Interface, Record, Union, GLibBoxedOther)):
+ return False
+ self._namespace.float(func)
+ func.name = funcname
+ node.static_methods.append(func)
+
+ def _pair_constructor(self, func, subsymbol):
+ if not (func.symbol.find('_new_') >= 0 or func.symbol.endswith('_new')):
+ return False
+ target = self._transformer.lookup_typenode(func.retval.type)
+ if not isinstance(target, (Class, Record, Union, GLibBoxedOther)):
+ return False
+ new_idx = func.symbol.rfind('_new')
+ assert (new_idx >= 0)
+ prefix = func.symbol[:new_idx]
+ split = self._split_uscored_by_type(subsymbol)
+ if split is None:
+ # TODO - need a e.g. (method) annotation
+ self._transformer.log_node_warning(func,
+ "Can't find matching type for constructor; symbol=%r" % (func.symbol, ))
+ return False
+ (origin_node, funcname) = split
+ if isinstance(target, Class):
+ parent = origin_node
+ while parent:
+ if parent == target:
+ break
+ parent = self._transformer.lookup_typenode(parent.parent)
+ if parent is None:
+ self._transformer.log_node_warning(func,
+ "Return value is not superclass for constructor; symbol=%r constructed=%r return=%r" % (func.symbol, str(origin_node.create_type()), str(func.retval.type)))
+ return False
else:
- klass.constructors.append(func)
- return func
+ if origin_node != target:
+ self._transformer.log_node_warning(func,
+ "Constructor return type mismatch symbol=%r constructed=%r return=%r" % (func.symbol, str(origin_node.create_type()), str(func.retval.type)))
+ return False
+ self._namespace.float(func)
+ func.name = funcname
+ target.constructors.append(func)
+ return True
def _initparse_gobject_record(self, record):
# Special handling for when we're parsing GObject
@@ -483,25 +478,12 @@ blob containing data gleaned from GObject's primitive introspection."""
else:
return name
- def _arg_is_failed(self, param):
- ctype = self._transformer.ctype_of(param).replace('*', '')
- uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
- if uscored in self._failed_types:
- print "Warning: failed type: %r" % (param, )
- return True
- return False
-
- def _pass3_pair_class_record(self, maybe_class):
+ def _pair_class_record(self, maybe_class):
name = self._strip_class_suffix(maybe_class.name)
if name == maybe_class.name:
return
class_struct = maybe_class
- if self._arg_is_failed(class_struct):
- print "WARNING: deleting no-type %r" % (class_struct.name, )
- del self._names.names[class_struct.name]
- return
-
pair_class = self._namespace.get(name)
if (not pair_class or
not isinstance(pair_class, (GLibObject, GLibInterface))):
@@ -597,15 +579,12 @@ blob containing data gleaned from GObject's primitive introspection."""
# to skip it
if type_name == 'GObject':
return
- # Get a list of parents here; some of them may be hidden, and what
- # we really want to do is use the most-derived one that we know of.
- #
is_abstract = bool(xmlnode.attrib.get('abstract', False))
node = GLibObject(self._transformer.remove_prefix(type_name),
None,
type_name,
xmlnode.attrib['get-type'], is_abstract)
- node.parent_gtype_names = xmlnode.attrib['parents'].split(',')
+ self._parse_parents(xmlnode, node)
self._introspect_properties(node, xmlnode)
self._introspect_signals(node, xmlnode)
self._introspect_implemented_interfaces(node, xmlnode)
@@ -636,7 +615,6 @@ blob containing data gleaned from GObject's primitive introspection."""
# This one doesn't go in the main namespace; we associate it with
# the struct or union
node = GLibBoxed(type_name, xmlnode.attrib['get-type'])
- self._boxed_types[node.type_name] = node
def _introspect_implemented_interfaces(self, node, xmlnode):
gt_interfaces = []
@@ -680,6 +658,14 @@ blob containing data gleaned from GObject's primitive introspection."""
node.signals.append(signal)
node.signals = sorted(node.signals)
+ def _parse_parents(self, xmlnode, node):
+ if 'parents' in xmlnode.attrib:
+ parent_types = map(lambda s: self._transformer.create_type(s),
+ xmlnode.attrib['parents'].split(','))
+ else:
+ parent_types = []
+ node.parent_chain = parent_types
+
def _introspect_fundamental(self, xmlnode):
# We only care about types that can be instantiatable, other
# fundamental types such as the Clutter.Fixed/CoglFixed registers
@@ -689,20 +675,12 @@ blob containing data gleaned from GObject's primitive introspection."""
return
type_name = xmlnode.attrib['name']
-
- if 'parents' in xmlnode.attrib:
- parent_types = map(lambda s: self._transformer.create_type(s),
- xmlnode.attrib['parents'].split(','))
- else:
- parent_types = []
- parent_type = parent_types[0] if parent_types else None
is_abstract = bool(xmlnode.attrib.get('abstract', False))
- node = GLibObject(
- self._transformer.remove_prefix(type_name),
- parent_type,
- type_name,
- xmlnode.attrib['get-type'], is_abstract)
- node.parent_chain = parent_types
+ node = GLibObject(self._transformer.remove_prefix(type_name),
+ None,
+ type_name,
+ xmlnode.attrib['get-type'], is_abstract)
+ self._parse_parents(xmlnode, node)
node.fundamental = True
self._introspect_implemented_interfaces(node, xmlnode)
@@ -743,56 +721,6 @@ blob containing data gleaned from GObject's primitive introspection."""
# Node walking
- def walk_node(self, node, callback, chain):
- assert isinstance(node, Node)
- if not callback(node, chain):
- return
- chain.append(node)
- def _subwalk(subnode):
- self._walk(subnode, callback, chain)
- if isinstance(node, Record):
- for ctor in node.constructors:
- _subwalk(ctor)
- for func in node.methods:
- _subwalk(func)
- elif isinstance(node, Field):
- _subwalk(node.type)
- elif isinstance(node, Class):
- for meth in node.methods:
- _subwalk(meth)
- for meth in node.virtual_methods:
- _subwalk(meth)
- for meth in node.static_methods:
- _subwalk(meth)
- for ctor in node.constructors:
- _subwalk(ctor)
- elif isinstance(node, Interface):
- for meth in node.methods:
- _subwalk(meth)
- for meth in node.virtual_methods:
- _subwalk(meth)
- elif isinstance(node, Union):
- for ctor in node.constructors:
- _subwalk(ctor)
- for meth in node.methods:
- _subwalk(meth)
- elif isinstance(node, GLibBoxed):
- for ctor in node.constructors:
- _subwalk(ctor)
- for meth in node.methods:
- _subwalk(meth)
-
- chain.pop()
-
- def _pair_function(self, func):
- for parser in [self._parse_constructor,
- self._parse_method,
- self._parse_static_method]:
- newfunc = parser(func)
- if newfunc:
- self._resolve_function(newfunc)
- return
- self._resolve_function(func)
def _handle_closure(self, param, closure_idx, closure_param):
if (closure_param.type is TYPE_ANY and
@@ -809,7 +737,9 @@ blob containing data gleaned from GObject's primitive introspection."""
return True
return False
- def _pass3_callable(self, node):
+ def _pass3_callable(self, node, chain):
+ if not isinstance(node, Callable):
+ return
self._pass3_callable_callbacks(node)
self._pass3_callable_throws(node)
@@ -910,7 +840,5 @@ blob containing data gleaned from GObject's primitive introspection."""
# This function is called at the very end, before we hand back the
# completed namespace to the writer. Add static analysis checks here.
def final_analyze(self):
- for node in self._namespace.itervalues():
- self.walk_node(node, self._analyze_node, [])
- for node in self._namespace.itervalues():
- self.walk_node(node, self._introspectable_pass2, [])
+ self._namespace.walk(self._analyze_node)
+ self._namespace.walk(self._introspectable_pass2)
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 0ab6839..6129b1a 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -223,7 +223,7 @@ currently-scanned namespace is first."""
for ns in self._includes.itervalues():
yield ns
- def _split_ctype(self, ident):
+ def split_ctype(self, ident):
"""Given a StudlyCaps string identifier like FooBar, return a
pair of (namespace, stripped_identifier) or raise ValueError."""
matches = []
@@ -235,15 +235,29 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
return matches[0]
raise ValueError("Unknown namespace for identifier %r" % (ident, ))
- def _strip_namespace_func(self, name):
- prefix = self._namespace.name.lower() + '_'
- if name.lower().startswith(prefix):
- name = name[len(prefix):]
- else:
- prefix = to_underscores(self._namespace.name).lower() + '_'
- if name.lower().startswith(prefix):
- name = name[len(prefix):]
- return self.remove_prefix(name, isfunction=True)
+ def split_csymbol(self, symbol):
+ """Given a C symbol like foo_bar_do_baz, return a pair of
+(namespace, stripped_symbol) or raise ValueError."""
+ matches = []
+ for ns in self._iter_namespaces():
+ prefix = ns.uscore_prefix + '_'
+ if symbol.startswith(prefix):
+ matches.append((ns, symbol[len(prefix):]))
+ if matches:
+ matches.sort(lambda x,y : cmp(len(x[0].uscore_prefix), len(y[0].uscore_prefix)))
+ return matches[0]
+ raise ValueError("Unknown namespace for symbol %r" % (symbol, ))
+
+ def _strip_csymbol_or_warn(self, symbol):
+ try:
+ (ns, name) = self.split_csymbol(symbol.ident)
+ except ValueError, e:
+ self.log_symbol_warning(symbol, "Unknown namespace")
+ return None
+ if ns != self._namespace:
+ self.log_symbol_warning(symbol, "Skipping foreign symbol from namespace %s" % (ns.name, ))
+ return None
+ return name
def remove_prefix(self, name, isfunction=False):
# when --strip-prefix=g:
@@ -276,10 +290,14 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
return self._create_member(symbol)
elif stype == CSYMBOL_TYPE_UNION:
return self._create_union(symbol)
- # FIXME - we should require an annotation on
- # #defines to have them be constants, really
- #elif stype == CSYMBOL_TYPE_CONST:
- # return self._create_const(symbol)
+ # FIXME - we need to require an annotation on
+ # #defines to have them be constants, otherwise
+ # namespace explosion can occur
+ elif stype == CSYMBOL_TYPE_CONST:
+ pass
+ # Ignore variable declarations in the header
+ elif stype == CSYMBOL_TYPE_OBJECT:
+ pass
else:
print 'transformer: unhandled symbol: %r' % (symbol, )
@@ -336,7 +354,9 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
def _create_function(self, symbol):
parameters = list(self._create_parameters(symbol.base_type))
return_ = self._create_return(symbol.base_type.base_type)
- name = self._strip_namespace_func(symbol.ident)
+ name = self._strip_csymbol_or_warn(symbol)
+ if not name:
+ return None
func = Function(name, return_, parameters, False, symbol.ident)
func.add_symbol_reference(symbol)
return func
@@ -511,7 +531,9 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
if (symbol.source_filename is None or
not symbol.source_filename.endswith('.h')):
return None
- name = self._strip_namespace_func(symbol.ident)
+ name = self._strip_csymbol_or_warn(symbol)
+ if not name:
+ return None
if symbol.const_string is not None:
typeval = TYPE_STRING
value = symbol.const_string
@@ -621,7 +643,7 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
elif not typeval.resolved:
pointer_stripped = typeval.ctype.replace('*', '')
try:
- (ns, name) = self._split_ctype(pointer_stripped)
+ (ns, name) = self.split_ctype(pointer_stripped)
except ValueError, e:
raise TypeResolutionException(e)
typeval.target_giname = '%s.%s' % (ns.name, name)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]