Add pyflakes.py and run it in make check. Update the source code to fix
[platform/upstream/gobject-introspection.git] / giscanner / glibtransformer.py
index d132890..564e2d9 100644 (file)
 #
 
 import ctypes
-import os
 
 from . import cgobject
 from .odict import odict
 from .ast import (Callback, Enum, Function, Member, Namespace, Parameter,
-                  Property, Return, Sequence, Struct, Type,
-                  type_name_from_ctype)
+                  Property, Return, Struct, Type, Alias, type_name_from_ctype)
 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
                       GLibInterface, GLibObject, GLibSignal)
-from .utils import resolve_libtool, to_underscores
+from .utils import extract_libtool, to_underscores
 
 
 class GLibTransformer(object):
+
     def __init__(self, transformer):
         self._transformer = transformer
         self._namespace_name = None
+        self._aliases = []
         self._output_ns = odict()
-        self._library = None
-        self._type_names = {}
+        self._libraries = []
+        self._internal_types = {}
 
     # Public API
 
-    def load_library(self, libname):
+    def add_library(self, libname):
         if libname.endswith('.la'):
-            libname = resolve_libtool(libname)
-        self._library = ctypes.cdll.LoadLibrary(libname)
+            libname = extract_libtool(libname)
+        self._libraries.append(ctypes.cdll.LoadLibrary(libname))
 
     def parse(self):
         namespace = self._transformer.parse()
         self._namespace_name = namespace.name
-        self._type_names = self._transformer.get_type_names()
 
+        # First pass, parsing
         for node in namespace.nodes:
             self._parse_node(node)
 
-        # Second round
+        # Introspection is done from within parsing
+
+        # Second pass, resolving types
         for node in self._output_ns.values():
             # associate GtkButtonClass with GtkButton
             if isinstance(node, Struct):
                 self._pair_class_struct(node)
+            self._resolve_node(node)
 
+        # Create a new namespace with what we found
         namespace = Namespace(namespace.name)
-        namespace.nodes = self._output_ns.values()
+        namespace.nodes = self._aliases + self._output_ns.values()
         return namespace
 
     # Private
@@ -79,21 +83,33 @@ class GLibTransformer(object):
         return self._output_ns.get(name)
 
     def _register_internal_type(self, type_name, node):
-        self._type_names[type_name] = (None, node)
+        self._internal_types[type_name] = node
 
-    def _resolve_type_name(self, type_name):
-        item = self._type_names.get(type_name)
-        if item is not None:
-            nsname, item = item
-            if nsname is None:
-                return item.name
-            return '%s.%s' % (nsname, item.name)
-        return type_name
+    # Helper functions
 
-    def _resolve_param_type(self, ptype):
-        type_name = ptype.name.replace('*', '')
-        ptype.name = self._resolve_type_name(type_name)
-        return ptype
+    def _create_type(self, type_id):
+        ctype = cgobject.type_name(type_id)
+        type_name = type_name_from_ctype(ctype)
+        return Type(type_name, ctype)
+
+    def _create_gobject(self, node):
+        type_name = 'G' + node.name
+        if type_name == 'GObject':
+            parent_type_name = None
+            symbol = 'intern'
+        else:
+            type_id = cgobject.type_from_name(type_name)
+            parent_type_name = cgobject.type_name(
+                cgobject.type_parent(type_id))
+            symbol = to_underscores(type_name).lower() + '_get_type'
+        node = GLibObject(node.name, parent_type_name, type_name, symbol)
+        type_id = cgobject.TYPE_OBJECT
+        self._introspect_properties(node, type_id)
+        self._introspect_signals(node, type_id)
+        self._add_attribute(node)
+        self._register_internal_type(type_name, node)
+
+    # Parser
 
     def _parse_node(self, node):
         if isinstance(node, Enum):
@@ -104,12 +120,17 @@ class GLibTransformer(object):
             self._parse_struct(node)
         elif isinstance(node, Callback):
             self._parse_callback(node)
+        elif isinstance(node, Alias):
+            self._parse_alias(node)
         elif isinstance(node, Member):
             # FIXME: atk_misc_instance singletons
             pass
         else:
             print 'GOBJECT BUILDER: Unhandled node:', node
 
+    def _parse_alias(self, alias):
+        self._aliases.append(alias)
+
     def _parse_enum(self, enum):
         self._add_attribute(enum)
 
@@ -121,29 +142,27 @@ class GLibTransformer(object):
         elif self._parse_method(func):
             return
 
-        self._parse_parameters(func.parameters)
-
         self._add_attribute(func)
 
-    def _parse_parameters(self, parameters):
-        for parameter in parameters:
-            parameter.type = self._resolve_param_type(parameter.type)
-
     def _parse_get_type_function(self, func):
-        if self._library is None:
+        if not self._libraries:
             return False
         # GType *_get_type(void)
         symbol = func.symbol
         if not symbol.endswith('_get_type'):
             return False
-        if func.retval.type.name != 'GType':
+        if func.retval.type.name != 'GObject.GType':
             return False
         if func.parameters:
             return False
 
-        try:
-            func = getattr(self._library, symbol)
-        except AttributeError:
+        for library in self._libraries:
+            try:
+                func = getattr(library, symbol)
+                break
+            except AttributeError:
+                continue
+        else:
             print 'Warning: could not find symbol: %s' % symbol
             return False
 
@@ -197,11 +216,14 @@ class GLibTransformer(object):
             class_.methods.append(func)
         else:
             class_.constructors.append(func)
-        self._parse_parameters(func.parameters)
-        func.retval.type = self._resolve_param_type(func.retval.type)
         return True
 
     def _parse_struct(self, struct):
+        # This is a hack, but GObject is a rather fundamental piece so.
+        if (self._namespace_name == 'GObject' and
+            struct.name in ["Object", 'InitiallyUnowned']):
+            self._create_gobject(struct)
+            return
         node = self._output_ns.get(struct.name)
         if node is None:
             self._add_attribute(struct, replace=True)
@@ -228,10 +250,7 @@ class GLibTransformer(object):
         for field in class_node.fields[1:]:
             node.fields.append(field)
 
-    def _create_type(self, type_id):
-        ctype = cgobject.type_name(type_id)
-        type_name = type_name_from_ctype(ctype)
-        return Type(type_name, ctype)
+    # Introspection
 
     def _introspect_type(self, type_id, symbol):
         fundamental_type_id = cgobject.type_fundamental(type_id)
@@ -245,7 +264,7 @@ class GLibTransformer(object):
         elif fundamental_type_id == cgobject.TYPE_BOXED:
             self._introspect_boxed(type_id, symbol)
         else:
-            print 'unhandled GType: %s' % (cgobject.type_name(type_id),)
+            print 'unhandled GType: %s' % (cgobject.type_name(type_id), )
 
     def _introspect_enum(self, ftype_id, type_id, symbol):
         type_class = cgobject.type_class_ref(type_id)
@@ -269,9 +288,10 @@ class GLibTransformer(object):
     def _introspect_object(self, type_id, symbol):
         type_name = cgobject.type_name(type_id)
         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
-        node = GLibObject(self._transformer.strip_namespace_object(type_name),
-                          self._resolve_type_name(parent_type_name),
-                          type_name, symbol)
+        node = GLibObject(
+            self._transformer.strip_namespace_object(type_name),
+            self._resolve_type_name(parent_type_name),
+            type_name, symbol)
         self._introspect_properties(node, type_id)
         self._introspect_signals(node, type_id)
         self._add_attribute(node)
@@ -284,8 +304,10 @@ class GLibTransformer(object):
 
     def _introspect_interface(self, type_id, symbol):
         type_name = cgobject.type_name(type_id)
+        parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
         node = GLibInterface(
             self._transformer.strip_namespace_object(type_name),
+            self._resolve_type_name(parent_type_name),
             type_name, symbol)
         self._introspect_properties(node, type_id)
         self._introspect_signals(node, type_id)
@@ -332,8 +354,95 @@ class GLibTransformer(object):
                 if i == 0:
                     name = 'object'
                 else:
-                    name = 'p%s' % (i-1,)
+                    name = 'p%s' % (i-1, )
                 ptype = self._create_type(parameter)
                 param = Parameter(name, ptype)
                 signal.parameters.append(param)
             node.signals.append(signal)
+
+    # Resolver
+
+    def _resolve_type_name(self, type_name):
+        type_name = type_name.replace('*', '')
+        possible_name = self._transformer.resolve_type_name(type_name)
+        if possible_name != type_name:
+            return possible_name
+        possible_node = self._internal_types.get(type_name)
+        if possible_node:
+            return possible_node.name
+        return type_name
+
+    def _resolve_param_type(self, ptype):
+        ptype.name = ptype.name.replace('*', '')
+        type_name = ptype.name
+        type_name = self._transformer.resolve_possible_typedef(type_name)
+        possible_node = self._internal_types.get(type_name)
+        if possible_node:
+            ptype.name = possible_node.name
+        else:
+            ptype = self._transformer.resolve_param_type(ptype)
+        return ptype
+
+    def _resolve_node(self, node):
+        if isinstance(node, (Callback, Function)):
+            self._resolve_function(node)
+        elif isinstance(node, GLibObject):
+            self._resolve_glib_object(node)
+        elif isinstance(node, GLibInterface):
+            self._resolve_glib_interface(node)
+        elif isinstance(node, GLibBoxed):
+            self._resolve_glib_boxed(node)
+        elif isinstance(node, Struct):
+            self._resolve_struct(node)
+
+    def _resolve_struct(self, node):
+        for field in node.fields:
+            self._resolve_field(field)
+
+    def _resolve_glib_interface(self, node):
+        self._resolve_methods(node.methods)
+        self._resolve_properties(node.properties)
+        self._resolve_signals(node.signals)
+
+    def _resolve_glib_object(self, node):
+        self._resolve_constructors(node.constructors)
+        self._resolve_methods(node.methods)
+        self._resolve_properties(node.properties)
+        self._resolve_signals(node.signals)
+
+    def _resolve_glib_boxed(self, node):
+        self._resolve_constructors(node.constructors)
+        self._resolve_methods(node.methods)
+
+    def _resolve_constructors(self, constructors):
+        for ctor in constructors:
+            self._resolve_function(ctor)
+
+    def _resolve_methods(self, methods):
+        for method in methods:
+            self._resolve_function(method)
+
+    def _resolve_signals(self, signals):
+        for signal in signals:
+            self._resolve_function(signal)
+
+    def _resolve_properties(self, properties):
+        for prop in properties:
+            self._resolve_property(prop)
+
+    def _resolve_property(self, prop):
+        prop.type = self._resolve_param_type(prop.type)
+
+    def _resolve_function(self, func):
+        self._resolve_parameters(func.parameters)
+        func.retval.type = self._resolve_param_type(func.retval.type)
+
+    def _resolve_parameters(self, parameters):
+        for parameter in parameters:
+            parameter.type = self._resolve_param_type(parameter.type)
+
+    def _resolve_field(self, field):
+        if isinstance(field, Callback):
+            self._resolve_function(field)
+            return
+        field.type = self._resolve_param_type(field.type)