[vala] Support delegates with delegate parameters and results



commit 63b56c1367fb640c30d9a0248f767b07c36a0930
Author: Jürg Billeter <j bitron ch>
Date:   Thu May 7 17:21:59 2009 +0200

    Support delegates with delegate parameters and results
    
    Based on patch by Levi Bard, fixes bug 578415.
---
 gobject/valaccodedelegatemodule.vala   |   56 ++++++++++++++++++++++++++++++-
 gobject/valaccodemethodcallmodule.vala |   50 ++++++++++++++++++++++++++++
 gobject/valaccodemethodmodule.vala     |    2 +-
 tests/delegates/delegates.test         |    1 +
 4 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/gobject/valaccodedelegatemodule.vala b/gobject/valaccodedelegatemodule.vala
index 7975204..99c5602 100644
--- a/gobject/valaccodedelegatemodule.vala
+++ b/gobject/valaccodedelegatemodule.vala
@@ -37,7 +37,14 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 			return;
 		}
 
-		generate_type_declaration (d.return_type, decl_space);
+		string return_type_cname = d.return_type.get_cname ();
+
+		if (return_type_cname == d.get_cname ()) {
+			// recursive delegate
+			return_type_cname = "GCallback";
+		} else {
+			generate_type_declaration (d.return_type, decl_space);
+		}
 
 		var cfundecl = new CCodeFunctionDeclarator (d.get_cname ());
 		foreach (FormalParameter param in d.get_parameters ()) {
@@ -59,6 +66,15 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 					cfundecl.add_parameter (cparam);
 				}
 			}
+			// handle delegate parameters
+			if (param.parameter_type is DelegateType) {
+				var deleg_type = (DelegateType) param.parameter_type;
+				var param_d = deleg_type.delegate_symbol;
+				if (param_d.has_target) {
+					var cparam = new CCodeFormalParameter (get_delegate_target_cname (get_variable_cname (param.name)), "void*");
+					cfundecl.add_parameter (cparam);
+				}
+			}
 		}
 		if (!d.no_array_length && d.return_type is ArrayType) {
 			// return array length if appropriate
@@ -68,6 +84,14 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
 				cfundecl.add_parameter (cparam);
 			}
+		} else if (d.return_type is DelegateType) {
+			// return delegate target if appropriate
+			var deleg_type = (DelegateType) d.return_type;
+			var result_d = deleg_type.delegate_symbol;
+			if (result_d.has_target) {
+				var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void**");
+				cfundecl.add_parameter (cparam);
+			}
 		}
 		if (d.has_target) {
 			var cparam = new CCodeFormalParameter ("user_data", "void*");
@@ -78,7 +102,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 			cfundecl.add_parameter (cparam);
 		}
 
-		var ctypedef = new CCodeTypeDefinition (d.return_type.get_cname (), cfundecl);
+		var ctypedef = new CCodeTypeDefinition (return_type_cname, cfundecl);
 
 		if (d.source_reference != null && d.source_reference.comment != null) {
 			decl_space.add_type_declaration (new CCodeComment (d.source_reference.comment));
@@ -263,6 +287,14 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
 				cparam_map.set (get_param_pos (d.carray_length_parameter_position + 0.01 * dim), cparam);
 			}
+		} else if (d.return_type is DelegateType) {
+			// return delegate target if appropriate
+			var deleg_type = (DelegateType) d.return_type;
+
+			if (deleg_type.delegate_symbol.has_target) {
+				var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void**");
+				cparam_map.set (get_param_pos (d.cdelegate_target_parameter_position), cparam);
+			}
 		}
 
 		if (m.get_error_types ().size > 0) {
@@ -337,6 +369,13 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 					}
 					carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), clength);
 				}
+			} else if (param.parameter_type is DelegateType) {
+				var deleg_type = (DelegateType) param.parameter_type;
+
+				if (deleg_type.delegate_symbol.has_target) {
+					var ctarget = new CCodeIdentifier (get_delegate_target_cname (d_params.get (i).name));
+					carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), ctarget);
+				}
 			}
 
 			i++;
@@ -352,6 +391,13 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 				}
 				carg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), clength);
 			}
+		} else if (m.return_type is DelegateType) {
+			var deleg_type = (DelegateType) m.return_type;
+
+			if (deleg_type.delegate_symbol.has_target) {
+				var ctarget = new CCodeIdentifier (get_delegate_target_cname ("result"));
+				carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), ctarget);
+			}
 		}
 
 		if (m.get_error_types ().size > 0) {
@@ -402,6 +448,12 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		string ctypename = param.parameter_type.get_cname ();
 		string target_ctypename = "void*";
 
+		if (param.parent_symbol is Delegate
+		    && param.parameter_type.get_cname () == ((Delegate) param.parent_symbol).get_cname ()) {
+			// recursive delegate
+			ctypename = "GCallback";
+		}
+
 		if (param.direction != ParameterDirection.IN) {
 			ctypename += "*";
 			target_ctypename += "*";
diff --git a/gobject/valaccodemethodcallmodule.vala b/gobject/valaccodemethodcallmodule.vala
index adb0106..8e328ca 100644
--- a/gobject/valaccodemethodcallmodule.vala
+++ b/gobject/valaccodemethodcallmodule.vala
@@ -39,6 +39,7 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 		CCodeFunctionCall async_call = null;
 
 		Method m = null;
+		Delegate deleg = null;
 		Gee.List<FormalParameter> params;
 		
 		var ma = expr.call as MemberAccess;
@@ -62,6 +63,8 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			m = cl.default_construction_method;
 			generate_method_declaration (m, source_declarations);
 			ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+		} else if (itype is DelegateType) {
+			deleg = ((DelegateType) itype).delegate_symbol;
 		}
 
 		HashMap<int,CCodeExpression> in_arg_map, out_arg_map;
@@ -463,6 +466,53 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			}
 		}
 
+		// add length argument for delegates returning arrays
+		// TODO: avoid code duplication with methods returning arrays, see above
+		if (deleg != null && deleg.return_type is ArrayType) {
+			var array_type = (ArrayType) deleg.return_type;
+			for (int dim = 1; dim <= array_type.rank; dim++) {
+				if (deleg.array_null_terminated) {
+					// handle calls to methods returning null-terminated arrays
+					var temp_var = get_temp_variable (itype.get_return_type ());
+					var temp_ref = get_variable_cexpression (temp_var.name);
+
+					temp_vars.insert (0, temp_var);
+
+					ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
+
+					requires_array_length = true;
+					var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
+					len_call.add_argument (temp_ref);
+
+					expr.append_array_size (len_call);
+				} else if (!deleg.no_array_length) {
+					var temp_var = get_temp_variable (int_type);
+					var temp_ref = get_variable_cexpression (temp_var.name);
+
+					temp_vars.insert (0, temp_var);
+
+					out_arg_map.set (get_param_pos (deleg.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+					expr.append_array_size (temp_ref);
+				} else {
+					expr.append_array_size (new CCodeConstant ("-1"));
+				}
+			}
+		} else if (deleg != null && deleg.return_type is DelegateType) {
+			var deleg_type = (DelegateType) deleg.return_type;
+			var d = deleg_type.delegate_symbol;
+			if (d.has_target) {
+				var temp_var = get_temp_variable (new PointerType (new VoidType ()));
+				var temp_ref = get_variable_cexpression (temp_var.name);
+
+				temp_vars.insert (0, temp_var);
+
+				out_arg_map.set (get_param_pos (deleg.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+				expr.delegate_target = temp_ref;
+			}
+		}
+
 		if (m != null && m.coroutine) {
 			if ((current_method != null && current_method.coroutine)
 			    || (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference)) {
diff --git a/gobject/valaccodemethodmodule.vala b/gobject/valaccodemethodmodule.vala
index 5643639..ffbe24d 100644
--- a/gobject/valaccodemethodmodule.vala
+++ b/gobject/valaccodemethodmodule.vala
@@ -96,7 +96,7 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
 			var deleg_type = (DelegateType) m.return_type;
 			var d = deleg_type.delegate_symbol;
 			if (d.has_target) {
-				var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void*");
+				var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void**");
 				cparam_map.set (get_param_pos (m.cdelegate_target_parameter_position), cparam);
 				if (carg_map != null) {
 					carg_map.set (get_param_pos (m.cdelegate_target_parameter_position), get_variable_cexpression (cparam.name));
diff --git a/tests/delegates/delegates.test b/tests/delegates/delegates.test
index 0885f3e..b225dd3 100644
--- a/tests/delegates/delegates.test
+++ b/tests/delegates/delegates.test
@@ -8,6 +8,7 @@ public static delegate void Maman.VoidCallback ();
 public static delegate int Maman.ActionCallback ();
 
 public delegate void Maman.InstanceCallback (int i);
+public delegate Maman.SelfCallback Maman.SelfCallback (Maman.SelfCallback scb);
 
 struct Maman.DelegateStruct {
 	public VoidCallback callback;



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