[vala] Support [GenericAccessors] attribute for interfaces



commit 6a6a2cf59b7302b0b3b111c6a0c879c00d36ddce
Author: Jeremy Whiting <jpwhiting kde org>
Date:   Wed Jul 11 11:54:45 2012 -0600

    Support [GenericAccessors] attribute for interfaces
    
    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 |   49 ++++++++++++++++++++++++-
 codegen/valagtypemodule.vala     |   74 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 1 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 9a82e5d..2e0fded 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -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");
 			}
 
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index eca78af..487918f 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -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);
 		}



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