[vala] Support capturing parameters in closures



commit c2326dde18ca91c135831edf9be33fe1ea6b0664
Author: Jürg Billeter <j bitron ch>
Date:   Tue Sep 15 17:48:44 2009 +0200

    Support capturing parameters in closures

 codegen/valaccodebasemodule.vala         |   19 +++++++++++++++++++
 codegen/valaccodedelegatemodule.vala     |   26 ++++++++++++++++----------
 codegen/valaccodememberaccessmodule.vala |    6 +++++-
 vala/valaformalparameter.vala            |    2 ++
 vala/valamemberaccess.vala               |    8 ++++++++
 5 files changed, 50 insertions(+), 11 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 44b5e4b..efc3d0b 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1670,6 +1670,21 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 				cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self"), ref_call)));
 			}
 
+			if (b.parent_symbol is Method) {
+				// parameters are captured with the top-level block of the method
+				foreach (var param in ((Method) b.parent_symbol).get_parameters ()) {
+					if (param.captured) {
+						data.add_field (param.parameter_type.get_cname (), get_variable_cname (param.name));
+						cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (param.name)), new CCodeIdentifier (get_variable_cname (param.name)))));
+
+						if (param.parameter_type is DelegateType) {
+							data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param.name)));
+							cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_delegate_target_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name))))));
+						}
+					}
+				}
+			}
+
 			var data_free = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
 			data_free.add_argument (new CCodeIdentifier (struct_name));
 			data_free.add_argument (new CCodeIdentifier ("data"));
@@ -1856,6 +1871,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 					ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs));
 
 					var lhs_delegate_target = get_variable_cexpression (get_delegate_target_cname (get_variable_cname (local.name)));
+					if (local.captured) {
+						var block = (Block) local.parent_symbol;
+						lhs_delegate_target = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (local.name));
+					}
 					var rhs_delegate_target = get_delegate_target_cexpression (local.initializer);
 					ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
 				
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 357e1dc..3ff9666 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -150,16 +150,22 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		} else if (delegate_expr.symbol_reference != null) {
 			if (delegate_expr.symbol_reference is FormalParameter) {
 				var param = (FormalParameter) delegate_expr.symbol_reference;
-				CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name)));
-				if (param.direction != ParameterDirection.IN) {
-					// accessing argument of out/ref param
-					target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
-				}
-				if (is_out) {
-					// passing array as out/ref
-					return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
+				if (param.captured) {
+					// captured variables are stored on the heap
+					var block = ((Method) param.parent_symbol).body;
+					return new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (param.name));
 				} else {
-					return target_expr;
+					CCodeExpression target_expr = new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name)));
+					if (param.direction != ParameterDirection.IN) {
+						// accessing argument of out/ref param
+						target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
+					}
+					if (is_out) {
+						// passing array as out/ref
+						return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr);
+					} else {
+						return target_expr;
+					}
 				}
 			} else if (delegate_expr.symbol_reference is LocalVariable) {
 				var local = (LocalVariable) delegate_expr.symbol_reference;
@@ -337,7 +343,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
 		var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
 		int i = 0;
-		if (m.binding == MemberBinding.INSTANCE) {
+		if (m.binding == MemberBinding.INSTANCE || m.closure) {
 			CCodeExpression arg;
 			if (d.has_target) {
 				arg = new CCodeIdentifier ("self");
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index 027d4a2..85424fc 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -366,7 +366,11 @@ internal class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
 					}
 				}
 			} else {
-				if (current_method != null && current_method.coroutine) {
+				if (p.captured) {
+					// captured variables are stored on the heap
+					var block = ((Method) p.parent_symbol).body;
+					expr.ccodenode = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (get_block_id (block))), get_variable_cname (p.name));
+				} else if (current_method != null && current_method.coroutine) {
 					// use closure
 					expr.ccodenode = get_variable_cexpression (p.name);
 				} else {
diff --git a/vala/valaformalparameter.vala b/vala/valaformalparameter.vala
index 6c6e575..3a35aeb 100644
--- a/vala/valaformalparameter.vala
+++ b/vala/valaformalparameter.vala
@@ -101,6 +101,8 @@ public class Vala.FormalParameter : Symbol {
 	 */
 	public string? ctype { get; set; }
 
+	public bool captured { get; set; }
+
 	private DataType _data_type;
 	private Expression? _default_expression;
 
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 1e076e4..79f64df 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -427,6 +427,14 @@ public class Vala.MemberAccess : Expression {
 				block.captured = true;
 				analyzer.current_method.closure = true;
 			}
+		} else if (member is FormalParameter) {
+			var param = (FormalParameter) member;
+			var m = param.parent_symbol as Method;
+			if (m != null && m != analyzer.current_method) {
+				param.captured = true;
+				m.body.captured = true;
+				analyzer.current_method.closure = true;
+			}
 		} else if (member is Field) {
 			var f = (Field) member;
 			access = f.access;



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