[gobject-introspection/wip/transformer] lots more hacking



commit 859da02b3e2e96990ece0ba6df586f917a5b5e06
Author: Colin Walters <walters verbum org>
Date:   Wed Jul 14 18:48:37 2010 -0400

    lots more hacking

 giscanner/ast.py             |   13 +++++-
 giscanner/glibast.py         |    2 +-
 giscanner/glibtransformer.py |   84 ++++++++++++-----------------------------
 giscanner/transformer.py     |   19 +++++++--
 4 files changed, 51 insertions(+), 67 deletions(-)
---
diff --git a/giscanner/ast.py b/giscanner/ast.py
index d6fe47f..8af0198 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -273,9 +273,7 @@ identifier string."""
         previous = self._names.get(node.name)
         if previous is not None:
             if not replace:
-                raise SystemExit(
-                    "transformer: conflict: ns=%r orig=%r new=%r" % 
-                    (self.name, previous, node))
+                raise ValueError("Namespace conflict")
             self.remove(previous)
         # A layering violation...but oh well.
         from .glibast import GLibBoxed
@@ -365,6 +363,11 @@ GIName.  It's possible for nodes to contain or point to other nodes."""
         self.foreign = False
         self.file_positions = set()
 
+    def create_type(self):
+        """Create a Type object referencing this node."""
+        assert self.namespace is not None
+        return Type(target_giname=('%s.%s' % (self.namespace.name, self.name)))
+
     def __cmp__(self, other):
         nscmp = cmp(self.namespace, other.namespace)
         if nscmp != 0:
@@ -599,6 +602,10 @@ class Class(Node):
         Node.__init__(self, name)
         self.ctype = name
         self.parent = parent
+        # When we're in the scanner, we keep around a list
+        # of parents so that we can transparently fall back
+        # if there are 'hidden' parents
+        self.parent_chain = None
         self.glib_type_struct = None
         self.is_abstract = is_abstract
         self.methods = []
diff --git a/giscanner/glibast.py b/giscanner/glibast.py
index dd6079d..c2b2600 100644
--- a/giscanner/glibast.py
+++ b/giscanner/glibast.py
@@ -27,7 +27,7 @@ class GLibRecord(Record):
 
     @classmethod
     def from_record(cls, record):
-        obj = cls(record.namespace, record.name, record.symbol)
+        obj = cls(record.name, record.symbol)
         obj.fields = record.fields
         obj.constructors = record.constructors
         obj.disguised = record.disguised
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 0fcec82..05ba2f1 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -29,7 +29,7 @@ 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,
-                  TYPE_ANY, TYPE_UINT8, PARAM_TRANSFER_FULL, Array, List,
+                  TYPE_ANY, TYPE_GTYPE, TYPE_UINT8, PARAM_TRANSFER_FULL, Array, List,
                   Map, Varargs, type_names)
 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
@@ -48,18 +48,6 @@ G_PARAM_STATIC_NAME = 1 << 5
 G_PARAM_STATIC_NICK = 1 << 6
 G_PARAM_STATIC_BLURB = 1 << 7
 
-GET_TYPE_OVERRIDES = {
-    # this is a special case, from glibtransforer.py:create_gobject
-    'intern': 'g_object_get_type',
-    # this is presumably a typo, should be fixed upstream
-    'g_gstring_get_type': 'g_string_get_type',
-    # this is historical cruft: there's a deprecated
-    #   #define gdk_window_get_type gdk_window_get_window_type
-    # upstream; this method can be renamed properly upstream once
-    # that deprecated alias is removed (in some future release)
-    'gdk_window_object_get_type': 'gdk_window_get_type',
-}
-
 
 class IntrospectionBinary(object):
 
@@ -172,20 +160,6 @@ class GLibTransformer(object):
         prefix = type_name[:-len(suffix)]
         return (prefix + '_' + to_underscores(suffix)).lower()
 
-    def _register_internal_type(self, type_name, node):
-        self._names.type_names[type_name] = (None, node)
-        uscored = to_underscores(type_name).lower()
-        # prefer the prefix of the get_type method, if there is one
-        if hasattr(node, 'get_type'):
-            uscored = GET_TYPE_OVERRIDES.get(node.get_type, node.get_type)
-            uscored = uscored[:-len('_get_type')]
-        self._uscore_type_names[uscored] = node
-
-        no_uscore_prefixed = self._get_no_uscore_prefixed_name(type_name)
-        # since this is a guess, don't overwrite any 'real' prefix
-        if no_uscore_prefixed not in self._uscore_type_names:
-            self._uscore_type_names[no_uscore_prefixed] = node
-
     def _pass_type_resolution(self, node, chain):
         if isinstance(node, Alias):
             self._transformer.resolve_type(node.target)
@@ -302,9 +276,8 @@ blob containing data gleaned from GObject's primitive introspection."""
             # what we do here is copy all of the GObject fields into
             # GInitiallyUnowned so that struct offset computation
             # works correctly.
-            gnode.fields = self._names.names['Object'][1].fields
+            gnode.fields = self._namespace.get('Object').fields
         self._namespace.append(gnode, replace=True)
-        self._register_internal_type(type_name, gnode)
 
     # Parser
 
@@ -322,21 +295,19 @@ blob containing data gleaned from GObject's primitive introspection."""
             # No GObjects in GLib
             return False
         if (self._namespace.name == 'GObject' and
-            symbol in ('g_object_get_type', 'g_initially_unowned_get_type')):
+            func.symbol in ('g_object_get_type', 'g_initially_unowned_get_type')):
             # We handle these internally, see _create_gobject
             return True
         if func.parameters:
             return False
         # GType *_get_type(void)
-        if func.retval.type.name not in ['Type',
-                                         'GType',
-                                         'GObject.Type',
-                                         'Gtk.Type']:
-            self._transformer.log_("Warning: *_get_type function returns '%r'"
-                   ", not GObject.Type") % (func.retval.type.name, )
+        rettype = func.retval.type
+        if not (rettype.is_equiv(TYPE_GTYPE)
+                or rettype.target_giname == 'Gtk.Type'):
+            self._transformer.log_warning("function returns '%r', not a GType") % (func.retval.type, )
             return False
 
-        self._get_type_functions.append(symbol)
+        self._get_type_functions.append(func.symbol)
         return True
 
     def _initparse_error_quark_function(self, func):
@@ -350,7 +321,7 @@ blob containing data gleaned from GObject's primitive introspection."""
 
     def _name_is_internal_gtype(self, giname):
         try:
-            node = self._get_attribute(giname)
+            node = self._namespace.get(giname)
             return isinstance(node, (GLibObject, GLibInterface,
                                      GLibBoxed, GLibEnum, GLibFlags))
         except KeyError, e:
@@ -422,9 +393,6 @@ blob containing data gleaned from GObject's primitive introspection."""
             new_idx = func.symbol.find('_new')
             if new_idx < 0:
                 return None
-            # Constructors don't return basic types
-            derefed = self._transformer.follow_aliases(target_arg.type.name,
-                                                       self._names)
             if derefed in type_names:
                 #print "NOTE: Rejecting constructor returning basic: %r" \
                 #    % (func.symbol, )
@@ -448,7 +416,7 @@ blob containing data gleaned from GObject's primitive introspection."""
             remove_prefix = klass.type_name
 
         name = self._transformer.remove_prefix(remove_prefix)
-        klass = self._get_attribute(name)
+        klass = self._namespace.get(name)
         if klass is None:
             return
 
@@ -484,7 +452,7 @@ blob containing data gleaned from GObject's primitive introspection."""
             self._create_gobject(record)
             return
         if record.name == 'InitiallyUnownedClass':
-            record.fields = self._names.names['ObjectClass'][1].fields
+            record.fields = self._namespace.get('ObjectClass').fields
         self._namespace.append(record, replace=True)
 
     def _strip_class_suffix(self, name):
@@ -515,7 +483,7 @@ blob containing data gleaned from GObject's primitive introspection."""
             del self._names.names[class_struct.name]
             return
 
-        pair_class = self._get_attribute(name)
+        pair_class = self._namespace.get(name)
         if (not pair_class or
             not isinstance(pair_class, (GLibObject, GLibInterface))):
             return
@@ -567,7 +535,7 @@ blob containing data gleaned from GObject's primitive introspection."""
         self._namespace.append(gclass_struct, replace=True)
         pair_class.glib_type_struct = gclass_struct
         pair_class.inherit_file_positions(class_struct)
-        gclass_struct.is_gtype_struct_for = name
+        gclass_struct.is_gtype_struct_for = maybe_class.create_type()
 
     # Introspection over the data we get from the dynamic
     # GObject/GType system out of the binary
@@ -635,7 +603,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._resolve_gtypename(name)
+            prereq = self._transformer.create_type(name)
             node.prerequisites.append(prereq)
         # GtkFileChooserEmbed is an example of a private interface, we
         # just filter them out
@@ -650,12 +618,11 @@ blob containing data gleaned from GObject's primitive introspection."""
         # the struct or union
         node = GLibBoxed(type_name, xmlnode.attrib['get-type'])
         self._boxed_types[node.type_name] = node
-        self._register_internal_type(type_name, node)
 
     def _introspect_implemented_interfaces(self, node, xmlnode):
         gt_interfaces = []
         for interface in xmlnode.findall('implements'):
-            gitype = self._resolve_gtypename(interface.attrib['name'])
+            gitype = self._transformer.create_type(interface.attrib['name'])
             gt_interfaces.append(gitype)
         node.interfaces = sorted(gt_interfaces)
 
@@ -669,7 +636,7 @@ blob containing data gleaned from GObject's primitive introspection."""
             construct_only = (flags & G_PARAM_CONSTRUCT_ONLY) != 0
             node.properties.append(Property(
                 pspec.attrib['name'],
-                self._transformer._create_type(ctype),
+                self._transformer.create_type(ctype),
                 readable, writable, construct, construct_only,
                 ctype,
                 ))
@@ -704,29 +671,28 @@ blob containing data gleaned from GObject's primitive introspection."""
 
         type_name = xmlnode.attrib['name']
 
-        # 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.
         if 'parents' in xmlnode.attrib:
-            parent_type_names = xmlnode.attrib['parents'].split(',')
-            parent_gitype = self._resolve_gtypename_chain(parent_type_names)
+            parent_types = map(lambda s: self._transformer.create_type(s),
+                               xmlnode.attrib['parents'].split(','))
         else:
-            parent_gitype = None
+            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_gitype,
+            parent_type,
             type_name,
             xmlnode.attrib['get-type'], is_abstract)
+        node.parent_types = parent_types
         node.fundamental = True
         self._introspect_implemented_interfaces(node, xmlnode)
 
         self._add_record_fields(node)
-        self._add_attribute(node, replace=True)
-        self._register_internal_type(type_name, node)
+        self._namespace.append(node, replace=True)
 
     def _add_record_fields(self, node):
         # add record fields
-        record = self._get_attribute(node.name)
+        record = self._namespace.get(node.name)
         if record is None:
             return
         node.fields = record.fields
@@ -738,7 +704,7 @@ blob containing data gleaned from GObject's primitive introspection."""
 
     def _pair_boxed_type(self, boxed):
         name = self._transformer.remove_prefix(boxed.type_name)
-        pair_node = self._get_attribute(name)
+        pair_node = self._namespace.get(name)
         if not pair_node:
             boxed_item = GLibBoxedOther(name, boxed.type_name,
                                         boxed.get_type)
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index f23bf3c..1e4a28d 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -83,7 +83,15 @@ class Transformer(object):
                 continue
             node = self._traverse_one(symbol)
             if node:
-                self._namespace.append(node)
+                try:
+                    self._namespace.append(node)
+                except ValueError, e:
+                    original = self._namespace.get(node.name)
+                    positions = set()
+                    positions.update(original.file_positions)
+                    positions.update(node.file_positions)
+                    self.log_warning("Namespace conflict for '%s'" % (node.name, ),
+                                     positions, fatal=True)
 
     def set_include_paths(self, paths):
         self._includepaths = list(paths)
@@ -120,7 +128,8 @@ None."""
 
     # Private
 
-    def log_warning(self, text, file_positions=None, prefix=None):
+    def log_warning(self, text, file_positions=None, prefix=None,
+                    fatal=False):
         """Log a warning, using optional file positioning information.
 If the warning is related to a Node type, see log_node_warning()."""
         if not self._enable_warnings:
@@ -148,6 +157,8 @@ If the warning is related to a Node type, see log_node_warning()."""
         else:
             print >>sys.stderr, \
 '''%s: warning: ns=%r: %s''' % (position, self._namespace.name, text)
+        if fatal:
+            sys.exit(1)
 
     def log_symbol_warning(self, symbol, text):
         """Log a warning in the context of the given symbol."""
@@ -155,7 +166,7 @@ If the warning is related to a Node type, see log_node_warning()."""
         prefix = "symbol=%r" % (symbol.ident, )
         self.log_warning(text, file_positions, prefix=prefix)
 
-    def log_node_warning(self, node, text, context=None):
+    def log_node_warning(self, node, text, context=None, fatal=False):
         """Log a warning, using information about file positions from
 the given node.  The optional context argument, if given, should be
 another Node type which will also be displayed.  If no file position
@@ -170,7 +181,7 @@ context will be used."""
         if context:
             text = "context=%r %s" % (context.name, text)
 
-        self.log_warning(text, file_positions)
+        self.log_warning(text, file_positions, fatal=fatal)
 
     def _find_include(self, include):
         searchdirs = self._includepaths[:]



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