]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Support [GenericAccessors] attribute for interfaces
authorJeremy Whiting <jpwhiting@kde.org>
Wed, 11 Jul 2012 17:54:45 +0000 (11:54 -0600)
committerJürg Billeter <j@bitron.ch>
Mon, 6 Aug 2012 10:44:48 +0000 (12:44 +0200)
This adds internal abstract functions to enable access to the element
type from within a generic interface. These functions are implicitly
implemented by all classes that implement interfaces with the
[GenericAccessors] attribute.

Fixes bug 640330.

codegen/valaccodebasemodule.vala
codegen/valagtypemodule.vala

index 9a82e5d3f6e8a9985a373c93d5110bcbac5bee31..2e0fdedf28dced60fc95b76dc0cc3ad1e7968afc 100644 (file)
@@ -2501,9 +2501,30 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                }
        }
 
+       void require_generic_accessors (Interface iface) {
+               if (iface.get_attribute ("GenericAccessors") == null) {
+                       Report.error (iface.source_reference,
+                                     "missing generic type for interface `%s', add GenericAccessors attribute to interface declaration"
+                                     .printf (iface.get_full_name ()));
+               }
+       }
+
        public CCodeExpression get_type_id_expression (DataType type, bool is_chainup = false) {
                if (type is GenericType) {
                        string var_name = "%s_type".printf (type.type_parameter.name.down ());
+
+                       if (type.type_parameter.parent_symbol is Interface) {
+                               var iface = (Interface) type.type_parameter.parent_symbol;
+                               require_generic_accessors (iface);
+
+                               string method_name = "get_%s_type".printf (type.type_parameter.name.down ());
+                               var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
+                               cast_self.add_argument (new CCodeIdentifier ("self"));
+                               var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
+                               function_call.add_argument (new CCodeIdentifier ("self"));
+                               return function_call;
+                       }
+
                        if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
                                return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), var_name);
                        } else {
@@ -2560,6 +2581,19 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        return new CCodeIdentifier (dup_function);
                } else if (type.type_parameter != null) {
                        string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
+
+                       if (type.type_parameter.parent_symbol is Interface) {
+                               var iface = (Interface) type.type_parameter.parent_symbol;
+                               require_generic_accessors (iface);
+
+                               string method_name = "get_%s_dup_func".printf (type.type_parameter.name.down ());
+                               var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
+                               cast_self.add_argument (new CCodeIdentifier ("self"));
+                               var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
+                               function_call.add_argument (new CCodeIdentifier ("self"));
+                               return function_call;
+                       }
+
                        if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
                                return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
                        } else {
@@ -3035,6 +3069,19 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        return new CCodeIdentifier (unref_function);
                } else if (type.type_parameter != null) {
                        string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
+
+                       if (type.type_parameter.parent_symbol is Interface) {
+                               var iface = (Interface) type.type_parameter.parent_symbol;
+                               require_generic_accessors (iface);
+
+                               string method_name = "get_%s_destroy_func".printf (type.type_parameter.name.down ());
+                               var cast_self = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
+                               cast_self.add_argument (new CCodeIdentifier ("self"));
+                               var function_call = new CCodeFunctionCall (new CCodeMemberAccess.pointer (cast_self, method_name));
+                               function_call.add_argument (new CCodeIdentifier ("self"));
+                               return function_call;
+                       }
+
                        if (is_in_generic_type (type) && !is_chainup && !in_creation_method) {
                                return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (get_result_cexpression ("self"), "priv"), func_name);
                        } else {
@@ -3238,7 +3285,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                if (type.type_parameter != null) {
                        var parent = type.type_parameter.parent_symbol;
                        var cl = parent as Class;
-                       if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact) || parent is Interface) {
+                       if ((!(parent is Method) && !(parent is ObjectTypeSymbol)) || (cl != null && cl.is_compact)) {
                                return new CCodeConstant ("NULL");
                        }
 
index eca78afb368b176fe1ac177a1cf4d52d06ab7dad..487918f592e393d211fd24a39fe37ed6e7439556 100644 (file)
@@ -1281,6 +1281,27 @@ public class Vala.GTypeModule : GErrorModule {
                cfile.add_function (class_init_context.ccode);
        }
        
+       private void add_generic_accessor_function (string base_name, string return_type, CCodeExpression? expression, TypeParameter p, Class cl, Interface iface) {
+               string name = "%s_%s_%s".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface), base_name);
+
+               var function = new CCodeFunction (name, return_type);
+               function.modifiers = CCodeModifiers.STATIC;
+               var this_type = get_data_type_for_symbol (cl);
+               function.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
+               push_function (function);
+               ccode.add_return (expression);
+               pop_function ();
+               cfile.add_function (function);
+
+               CCodeExpression cfunc = new CCodeIdentifier (function.name);
+               string cast = return_type + "(*)";
+               string cast_args = get_ccode_name (iface) + "*";
+               cast += "(" + cast_args + ")";
+               cfunc = new CCodeCastExpression (cfunc, cast);
+               var ciface = new CCodeIdentifier ("iface");
+               ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, base_name), cfunc);
+       }
+
        private void add_interface_init_function (Class cl, Interface iface) {
                var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface)), "void");
                iface_init.add_parameter (new CCodeParameter ("iface", "%s *".printf (get_ccode_type_name (iface))));
@@ -1332,6 +1353,28 @@ public class Vala.GTypeModule : GErrorModule {
                        }
                }
 
+               if (iface.get_attribute ("GenericAccessors") != null) {
+                       foreach (TypeParameter p in iface.get_type_parameters ()) {
+                               GenericType p_type = new GenericType (p);
+                               DataType p_data_type = p_type.get_actual_type (get_data_type_for_symbol (cl), null, cl);
+
+                               add_generic_accessor_function ("get_%s_type".printf (p.name.down ()),
+                                                              "GType",
+                                                              get_type_id_expression (p_data_type),
+                                                              p, cl, iface);
+
+                               add_generic_accessor_function ("get_%s_dup_func".printf (p.name.down ()),
+                                                              "GBoxedCopyFunc",
+                                                              get_dup_func_expression (p_data_type, null),
+                                                              p, cl, iface);
+
+                               add_generic_accessor_function ("get_%s_destroy_func".printf (p.name.down ()),
+                                                              "GDestroyNotify",
+                                                              get_destroy_func_expression (p_data_type),
+                                                              p, cl, iface);
+                       }
+               }
+
                // connect inherited implementations
                foreach (Method m in iface.get_methods ()) {
                        if (m.is_abstract) {
@@ -1894,6 +1937,37 @@ public class Vala.GTypeModule : GErrorModule {
 
                type_struct.add_field ("GTypeInterface", "parent_iface");
 
+               if (iface.get_attribute ("GenericAccessors") != null) {
+                       foreach (TypeParameter p in iface.get_type_parameters ()) {
+                               string method_name = "get_%s_type".printf (p.name.down ());
+                               var vdeclarator = new CCodeFunctionDeclarator (method_name);
+                               var this_type = get_data_type_for_symbol (iface);
+                               vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
+
+                               var vdecl = new CCodeDeclaration ("GType");
+                               vdecl.add_declarator (vdeclarator);
+                               type_struct.add_declaration (vdecl);
+
+                               method_name = "get_%s_dup_func".printf (p.name.down ());
+                               vdeclarator = new CCodeFunctionDeclarator (method_name);
+                               this_type = get_data_type_for_symbol (iface);
+                               vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
+
+                               vdecl = new CCodeDeclaration ("GBoxedCopyFunc");
+                               vdecl.add_declarator (vdeclarator);
+                               type_struct.add_declaration (vdecl);
+
+                               method_name = "get_%s_destroy_func".printf (p.name.down ());
+                               vdeclarator = new CCodeFunctionDeclarator (method_name);
+                               this_type = get_data_type_for_symbol (iface);
+                               vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
+
+                               vdecl = new CCodeDeclaration ("GDestroyNotify");
+                               vdecl.add_declarator (vdeclarator);
+                               type_struct.add_declaration (vdecl);
+                       }
+               }
+
                foreach (Method m in iface.get_methods ()) {
                        generate_virtual_method_declaration (m, decl_space, type_struct);
                }