From: Jeremy Whiting Date: Wed, 11 Jul 2012 17:54:45 +0000 (-0600) Subject: Support [GenericAccessors] attribute for interfaces X-Git-Tag: 0.17.4~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a6a2cf59b7302b0b3b111c6a0c879c00d36ddce;p=thirdparty%2Fvala.git 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. --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 9a82e5d3f..2e0fdedf2 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 eca78afb3..487918f59 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); }