[gobject-introspection/wip/transformer] Fix class pairing, handle '_' prefix correctly



commit 7c8e06d49437d46f910a105a031b0ddb0912d116
Author: Colin Walters <walters verbum org>
Date:   Fri Jul 23 03:19:56 2010 -0400

    Fix class pairing, handle '_' prefix correctly

 giscanner/ast.py             |   23 ++++--
 giscanner/glibtransformer.py |  170 +++++++++++++++++++++++-------------------
 giscanner/transformer.py     |   20 +++--
 3 files changed, 119 insertions(+), 94 deletions(-)
---
diff --git a/giscanner/ast.py b/giscanner/ast.py
index d37af5a..464c794 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -67,6 +67,15 @@ In this case, the ctype must be specified.
         assert self.target_giname is not None
         return self.target_giname.split('.')[1]
 
+    def __cmp__(self, other):
+        if self.target_fundamental:
+            return cmp(self.target_fundamental, other.target_fundamental)
+        if self.target_giname:
+            return cmp(self.target_giname, other.target_giname)
+        if self.target_foreign:
+            return cmp(self.target_foreign, other.target_foreign)
+        return cmp(self.ctype, other.ctype)
+
     def is_equiv(self, typeval):
         """Return True if the specified types are compatible at
         an introspection level, disregarding their C types.
@@ -78,14 +87,7 @@ In this case, the ctype must be specified.
                 if self.is_equiv(val):
                     return True
             return False
-        if not (self.resolved and typeval.resolved):
-            return False
-        if self.target_fundamental:
-            return typeval.target_fundamental == self.target_fundamental
-        elif self.target_giname:
-            return typeval.target_giname == self.target_giname
-        elif self.target_foreign:
-            return typeval.target_foreign == self.target_foreign
+        return self == typeval
 
     def clone(self):
         return Type(target_fundamental=self.target_fundamental,
@@ -152,6 +154,9 @@ GIR_TYPES.extend([TYPE_STRING, TYPE_FILENAME])
 type_names = {}
 for typeval in GIR_TYPES:
     type_names[typeval.target_fundamental] = typeval
+basic_type_names = {}
+for typeval in BASIC_GIR_TYPES:
+    basic_type_names[typeval.target_fundamental] = typeval
 
 # C builtin
 type_names['char'] = TYPE_CHAR
@@ -269,7 +274,7 @@ create a Type object referncing it.  If name is already a
 fully-qualified GIName like 'Foo.Bar', returns a Type targeting it .
 Otherwise a Type targeting name qualififed with the namespace name is
 returned."""
-        if name in GIR_TYPES:
+        if name in type_names:
             return Type(target_fundamental=name, ctype=ctype)
         if '.' in name:
             target = name
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 8405177..10fa187 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -145,13 +145,13 @@ class GLibTransformer(object):
                 self._uscore_type_names[uscored] = node
 
         for node in list(self._namespace.itervalues()):
-            # Discover which functions are actually methods
+            # Discover which toplevel functions are actually methods
             if isinstance(node, Function):
                 self._pair_function(node)
 
-        self._namespace.walk(self._pass3_callable)
+        self._namespace.walk(self._pass3)
 
-        # Third pass
+        # TODO - merge into pass3
         for node in self._namespace.itervalues():
             self._resolve_quarks()
 
@@ -381,7 +381,7 @@ _split_uscored_by_type(text_buffer_try_new) -> (Class(TextBuffer), 'try_new')"""
     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'):
+        if func.symbol.endswith('_get_type') or func.symbol.startswith('_'):
             return
         (ns, subsymbol) = self._transformer.split_csymbol(func.symbol)
         assert ns == self._namespace
@@ -472,76 +472,6 @@ method or constructor of some type."""
             record.fields = self._namespace.get('ObjectClass').fields
         self._namespace.append(record, replace=True)
 
-    def _strip_class_suffix(self, name):
-        if (name.endswith('Class') or
-            name.endswith('Iface')):
-            return name[:-5]
-        elif name.endswith('Interface'):
-            return name[:-9]
-        else:
-            return name
-
-    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
-        pair_class = self._namespace.get(name)
-        if not pair_class:
-            return
-        if not isinstance(pair_class, (GLibObject, GLibInterface)):
-            return
-
-        # Object class fields are assumed to be read-only
-        # (see also _introspect_object and transformer.py)
-        for field in maybe_class.fields:
-            if isinstance(field, Field):
-                field.writable = False
-
-        # Loop through fields to determine which are virtual
-        # functions and which are signal slots by
-        # assuming everything that doesn't share a name
-        # with a known signal is a virtual slot.
-        for field in maybe_class.fields:
-            if not isinstance(field, Callback):
-                continue
-            # Check the first parameter is the object
-            if len(field.parameters) == 0:
-                continue
-            firstparam_type = field.parameters[0].type
-            if firstparam_type != pair_class:
-                continue
-            # Also double check we don't have a signal with this
-            # name.
-            matched_signal = False
-            for signal in pair_class.signals:
-                if signal.name.replace('-', '_') == field.name:
-                    matched_signal = True
-                    break
-            if matched_signal:
-                continue
-            vfunc = VFunction.from_callback(field)
-            vfunc.inherit_file_positions(field)
-            pair_class.virtual_methods.append(vfunc)
-
-        # Take the set of virtual methods we found, and try
-        # to pair up with any matching methods using the
-        # name+signature.
-        for vfunc in pair_class.virtual_methods:
-            for method in pair_class.methods:
-                if (method.name != vfunc.name or
-                    method.retval != vfunc.retval or
-                    method.parameters != vfunc.parameters):
-                    continue
-                vfunc.invoker = method
-
-        gclass_struct = GLibRecord.from_record(class_struct)
-        self._namespace.append(gclass_struct, replace=True)
-        pair_class.glib_type_struct = gclass_struct.create_type()
-        pair_class.inherit_file_positions(class_struct)
-        gclass_struct.is_gtype_struct_for = pair_class.create_type()
-
     # Introspection over the data we get from the dynamic
     # GObject/GType system out of the binary
 
@@ -741,11 +671,95 @@ method or constructor of some type."""
             return True
         return False
 
-    def _pass3_callable(self, node, chain):
-        if not isinstance(node, Callable):
+    def _strip_class_suffix(self, name):
+        if (name.endswith('Class') or
+            name.endswith('Iface')):
+            return name[:-5]
+        elif name.endswith('Interface'):
+            return name[:-9]
+        else:
+            return name
+
+    def _pair_class_record(self, maybe_class):
+        name = self._strip_class_suffix(maybe_class.name)
+        if name == maybe_class.name:
             return
-        self._pass3_callable_callbacks(node)
-        self._pass3_callable_throws(node)
+
+        class_struct = maybe_class
+        pair_class = self._namespace.get(name)
+        if not pair_class:
+            return
+        if not isinstance(pair_class, (GLibObject, GLibInterface)):
+            return
+
+        gclass_struct = GLibRecord.from_record(class_struct)
+        self._namespace.append(gclass_struct, replace=True)
+        pair_class.glib_type_struct = gclass_struct.create_type()
+        pair_class.inherit_file_positions(class_struct)
+        gclass_struct.is_gtype_struct_for = pair_class.create_type()
+
+    def _pass3_class(self, node):
+        """Look for virtual methods from the class structure."""
+        if not node.glib_type_struct:
+            self._transformer.log_node_warning(node,
+                "Failed to find class structure for %r" % (node.name, ))
+            return
+
+        node_type = node.create_type()
+        class_struct = self._transformer.lookup_typenode(node.glib_type_struct)
+        
+        # Object class fields are assumed to be read-only
+        # (see also _introspect_object and transformer.py)
+        for field in class_struct.fields:
+            if isinstance(field, Field):
+                field.writable = False
+
+        # Loop through fields to determine which are virtual
+        # functions and which are signal slots by
+        # assuming everything that doesn't share a name
+        # with a known signal is a virtual slot.
+        for field in class_struct.fields:
+            if not isinstance(field.anonymous_node, Callback):
+                continue
+            callback = field.anonymous_node
+            # Check the first parameter is the object
+            if len(callback.parameters) == 0:
+                continue
+            firstparam_type = callback.parameters[0].type
+            if firstparam_type != node_type:
+                continue
+            # Also double check we don't have a signal with this
+            # name.
+            matched_signal = False
+            for signal in node.signals:
+                if signal.name.replace('-', '_') == callback.name:
+                    matched_signal = True
+                    break
+            if matched_signal:
+                continue
+            vfunc = VFunction.from_callback(callback)
+            vfunc.inherit_file_positions(callback)
+            node.virtual_methods.append(vfunc)
+
+        # Take the set of virtual methods we found, and try
+        # to pair up with any matching methods using the
+        # name+signature.
+        for vfunc in node.virtual_methods:
+            for method in node.methods:
+                if (method.name != vfunc.name or
+                    method.retval != vfunc.retval or
+                    method.parameters != vfunc.parameters):
+                    continue
+                vfunc.invoker = method
+
+    def _pass3(self, node, chain):
+        """Pass 3 is after we've loaded GType data and performed type
+        closure."""
+        if isinstance(node, Callable):
+            self._pass3_callable_callbacks(node)
+            self._pass3_callable_throws(node)
+        elif isinstance(node, Class):
+            self._pass3_class(node)
 
     def _pass3_callable_callbacks(self, node):
         """Check to see if we have anything that looks like a
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 4ad2ef1..23657ed 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -24,8 +24,8 @@ import sys
 from .ast import (Bitfield, Callback, Enum, Function, Namespace, Member,
                   Parameter, Return, Record, Field,
                   Type, Array, List, Map, Alias, Interface, Class, Node, Union,
-                  Varargs, Constant, type_names, default_array_types, TYPE_STRING, TYPE_ANY,
-                  BASIC_GIR_TYPES)
+                  Varargs, Constant, type_names, basic_type_names,
+                  default_array_types, TYPE_STRING, TYPE_ANY)
 from .config import DATADIR, GIR_DIR, GIR_SUFFIX
 from .girparser import GIRParser
 from .odict import odict
@@ -252,15 +252,21 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
             return matches[0]
         raise ValueError("Unknown namespace for symbol %r" % (symbol, ))
 
-    def _strip_csymbol_or_warn(self, symbol):
+    def _strip_symbol_or_warn(self, symbol):
+        ident = symbol.ident
+        hidden = ident.startswith('_')
+        if hidden:
+            ident = ident[1:]
         try:
-            (ns, name) = self.split_csymbol(symbol.ident)
+            (ns, name) = self.split_csymbol(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
+        if hidden:
+            return '_' + name
         return name
 
     def remove_prefix(self, name, isfunction=False):
@@ -358,7 +364,7 @@ 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_csymbol_or_warn(symbol)
+        name = self._strip_symbol_or_warn(symbol)
         if not name:
             return None
         func = Function(name, return_, parameters, False, symbol.ident)
@@ -486,7 +492,7 @@ pair of (namespace, stripped_identifier) or raise ValueError."""
 
         # Preserve "pointerness" of struct/union members
         if (is_member and canonical.endswith('*') and
-            derefed_typename in BASIC_GIR_TYPES):
+            derefed_typename in basic_type_names):
             return 'gpointer'
         else:
             return derefed_typename
@@ -534,7 +540,7 @@ 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_csymbol_or_warn(symbol)
+        name = self._strip_symbol_or_warn(symbol)
         if not name:
             return None
         if symbol.const_string is not None:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]