Bug 557383 - Virtual function support
authorColin Walters <walters@verbum.org>
Wed, 25 Feb 2009 23:43:14 +0000 (18:43 -0500)
committerColin Walters <walters@verbum.org>
Thu, 26 Feb 2009 19:07:21 +0000 (14:07 -0500)
In order to determine whether a method is virtual, by default we look
at the class table to find a callback field.  This should be fairly reliable,
but we may also later need annotations to more finely control this
in the case of a name clash with a signal.

giscanner/ast.py
giscanner/girwriter.py
giscanner/glibtransformer.py
tests/scanner/foo-1.0-expected.gir
tests/scanner/foo-1.0-expected.tgir
tests/scanner/foo.c
tests/scanner/foo.h

index e708258..4bd674d 100644 (file)
@@ -205,6 +205,7 @@ class Function(Node):
         self.symbol = symbol
         self.throws = not not throws
         self.is_method = False
+        self.is_virtual = False
         self.doc = None
 
     def get_parameter_index(self, name):
@@ -222,11 +223,6 @@ class Function(Node):
                                    self.name, self.retval,
                                    self.parameters)
 
-
-class VFunction(Function):
-    pass
-
-
 class Type(Node):
 
     def __init__(self, name, ctype=None):
index df52709..9a08aaa 100644 (file)
@@ -167,7 +167,11 @@ and/or use gtk-doc annotations. ''')
             self._write_parameters(func.parameters)
 
     def _write_method(self, method):
-        self._write_function(method, tag_name='method')
+        if method.is_virtual:
+            tag_name = 'vfunc'
+        else:
+            tag_name = 'method'
+        self._write_function(method, tag_name)
 
     def _write_static_method(self, method):
         self._write_function(method, tag_name='function')
index 5a7a96d..fc7f17c 100644 (file)
@@ -159,6 +159,10 @@ class GLibTransformer(object):
             except KeyError, e:
                 print "WARNING: DELETING node %s: %s" % (node.name, e)
                 self._remove_attribute(node.name)
+        # Another pass, since we need to have the methods parsed
+        # in order to correctly modify them after class/record
+        # pairing
+        for (ns, node) in nodes:
             # associate GtkButtonClass with GtkButton
             if isinstance(node, Record):
                 self._pair_class_record(node)
@@ -573,10 +577,19 @@ class GLibTransformer(object):
         for field in maybe_class.fields:
             if isinstance(field, Field):
                 field.writable = False
-        # TODO: remove this, we should be computing vfuncs instead
-        if isinstance(pair_class, GLibInterface):
-            for field in maybe_class.fields[1:]:
-                pair_class.fields.append(field)
+
+        # Pair up virtual methods by finding a slot in
+        # the class with the same name
+        for field in maybe_class.fields:
+            if not isinstance(field, Callback):
+                continue
+            matched = False
+            for method in pair_class.methods:
+                if (method.name == field.name and
+                    len(method.parameters)+1 == len(field.parameters)):
+                    method.is_virtual = True
+                    break
+
         gclass_struct = GLibRecord.from_record(class_struct)
         self._remove_attribute(class_struct.name)
         self._add_attribute(gclass_struct, True)
index 0f6b1f1..38bde58 100644 (file)
@@ -232,16 +232,16 @@ and/or use gtk-doc annotations.  -->
                glib:type-name="FooInterface"
                glib:get-type="foo_interface_get_type"
                glib:type-struct="InterfaceIface">
-      <callback name="do_foo" c:type="do_foo">
+      <vfunc name="do_foo" c:identifier="foo_interface_do_foo">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
         <parameters>
-          <parameter name="self" transfer-ownership="none">
-            <type name="Interface" c:type="FooInterface*"/>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int" c:type="int"/>
           </parameter>
         </parameters>
-      </callback>
+      </vfunc>
     </interface>
     <record name="InterfaceIface"
             c:type="FooInterfaceIface"
@@ -257,6 +257,9 @@ and/or use gtk-doc annotations.  -->
           <parameter name="self" transfer-ownership="none">
             <type name="Interface" c:type="FooInterface*"/>
           </parameter>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
         </parameters>
       </callback>
     </record>
@@ -359,6 +362,16 @@ and/or use gtk-doc annotations.  -->
           </parameter>
         </parameters>
       </method>
+      <vfunc name="virtual_method" c:identifier="foo_object_virtual_method">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </vfunc>
       <property name="string" writable="1" construct="1">
         <type name="utf8" c:type="gchararray"/>
       </property>
@@ -467,21 +480,11 @@ and/or use gtk-doc annotations.  -->
                glib:get-type="foo_sub_interface_get_type"
                glib:type-struct="SubInterfaceIface">
       <prerequisite name="Interface"/>
-      <method name="do_bar" c:identifier="foo_sub_interface_do_bar">
-        <return-value transfer-ownership="none">
-          <type name="none" c:type="void"/>
-        </return-value>
-      </method>
-      <callback name="do_bar" c:type="do_bar">
+      <vfunc name="do_bar" c:identifier="foo_sub_interface_do_bar">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
-        <parameters>
-          <parameter name="self" transfer-ownership="none">
-            <type name="SubInterface" c:type="FooSubInterface*"/>
-          </parameter>
-        </parameters>
-      </callback>
+      </vfunc>
     </interface>
     <record name="SubInterfaceIface"
             c:type="FooSubInterfaceIface"
index f8e1ee5..e2a02b1 100644 (file)
       <member name="second" value="2"/>
       <member name="third" value="4"/>
     </bitfield>
-    <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface"/>
+    <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface">
+      <vfunc name="do_foo" offset="0">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </vfunc>
+    </interface>
     <record name="InterfaceIface" glib:is-gtype-struct="1">
       <field name="parent_iface">
         <type name="GObject.TypeInterface"/>
           </parameter>
         </parameters>
       </glib:signal>
+      <vfunc name="virtual_method" offset="0">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </vfunc>
     </class>
     <record name="ObjectClass" glib:is-gtype-struct="1">
       <field name="parent_class">
     <record name="StructPrivate"/>
     <interface name="SubInterface" glib:type-name="FooSubInterface" glib:get-type="foo_sub_interface_get_type" glib:type-struct="SubInterfaceIface">
       <prerequisite name="Interface"/>
-      <method name="do_bar" c:identifier="foo_sub_interface_do_bar">
+      <vfunc name="do_bar" offset="0">
         <return-value transfer-ownership="none">
           <type name="none"/>
         </return-value>
-      </method>
+      </vfunc>
     </interface>
     <record name="SubInterfaceIface" glib:is-gtype-struct="1">
       <field name="parent_iface">
index 0488260..98d2f4b 100644 (file)
@@ -8,8 +8,8 @@ int foo_init_argv (int argc, char **argv);
 int foo_init_argv_address (int *argc, char ***argv);
 void foo_private_function (FooObject *foo);
 void foo_test_unsigned (unsigned int uint);
-void foo_interface_do_foo (FooInterface *self);
-void foo_do_foo (FooInterface *self);
+void foo_interface_do_foo (FooInterface *self, int x);
+void foo_do_foo (FooInterface *self, int x);
 int foo_enum_method (FooEnumType foo_enum);
 FooHidden * foo_hidden_copy (const FooHidden *boxed);
 void foo_hidden_free (FooHidden *boxed);
@@ -47,9 +47,9 @@ foo_interface_get_type (void)
   return object_type;
 }
 
-void foo_interface_do_foo (FooInterface *self)
+void foo_interface_do_foo (FooInterface *self, int x)
 {
-  FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self);
+  FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self, x);
 }
 
 enum {
@@ -191,7 +191,7 @@ foo_object_take_all (FooObject *object, int x, ...)
 }
 
 void
-foo_do_foo (FooInterface *self)
+foo_do_foo (FooInterface *self, int x)
 {
 
 
index da30df3..2eeed6d 100644 (file)
@@ -48,11 +48,13 @@ struct _FooInterfaceIface
 {
   GTypeInterface parent_iface;
 
-  void (*do_foo) (FooInterface *self);
+  void (*do_foo) (FooInterface *self, int x);
 };
 
 GType                 foo_interface_get_type       (void) G_GNUC_CONST;
 
+void foo_interface_do_foo (FooInterface *iface, int x);
+
 struct _FooSubInterfaceIface
 {
   GTypeInterface parent_iface;
@@ -105,6 +107,8 @@ char *                foo_object_dup_name          (FooObject *object);
 
 void                  foo_object_handle_glyph      (FooObject *object, UtilityGlyph glyph);
 
+void                  foo_object_virtual_method    (FooObject *object, int first_param);
+
 int                   foo_object_static_meth       ();
 
 struct _FooSubobject