[vala] dova: Add support for closures



commit 9d89bd50cff087c209b003cd7dff668bf973f137
Author: Jürg Billeter <j bitron ch>
Date:   Sat Jun 26 18:02:37 2010 +0200

    dova: Add support for closures

 codegen/valadovabasemodule.vala         |  292 +++++++++++++++++++++++++++++--
 codegen/valadovamemberaccessmodule.vala |   55 ++++---
 codegen/valadovaobjectmodule.vala       |   38 ++++-
 3 files changed, 348 insertions(+), 37 deletions(-)
---
diff --git a/codegen/valadovabasemodule.vala b/codegen/valadovabasemodule.vala
index a0b2641..77befcc 100644
--- a/codegen/valadovabasemodule.vala
+++ b/codegen/valadovabasemodule.vala
@@ -89,6 +89,29 @@ internal class Vala.DovaBaseModule : CCodeModule {
 		}
 	}
 
+	public Block? current_closure_block {
+		get {
+			return next_closure_block (current_symbol);
+		}
+	}
+
+	public unowned Block? next_closure_block (Symbol sym) {
+		unowned Block block = null;
+		while (true) {
+			block = sym as Block;
+			if (!(sym is Block || sym is Method)) {
+				// no closure block
+				break;
+			}
+			if (block != null && block.captured) {
+				// closure block found
+				break;
+			}
+			sym = sym.parent_symbol;
+		}
+		return block;
+	}
+
 	public CCodeDeclarationSpace header_declarations;
 	public CCodeDeclarationSpace internal_header_declarations;
 	public CCodeDeclarationSpace source_declarations;
@@ -112,6 +135,8 @@ internal class Vala.DovaBaseModule : CCodeModule {
 	public int next_string_const_id = 0;
 	public bool in_creation_method { get { return current_method is CreationMethod; } }
 	public bool current_method_inner_error = false;
+	int next_block_id = 0;
+	Map<Block,int> block_map = new HashMap<Block,int> ();
 
 	public DataType void_type = new VoidType ();
 	public DataType bool_type;
@@ -643,6 +668,44 @@ internal class Vala.DovaBaseModule : CCodeModule {
 		current_method_inner_error = old_method_inner_error;
 	}
 
+	public int get_block_id (Block b) {
+		int result = block_map[b];
+		if (result == 0) {
+			result = ++next_block_id;
+			block_map[b] = result;
+		}
+		return result;
+	}
+
+	void capture_parameter (FormalParameter param, CCodeStruct data, CCodeBlock cblock, int block_id, CCodeBlock free_block) {
+		generate_type_declaration (param.parameter_type, source_declarations);
+
+		var param_type = param.parameter_type.copy ();
+		param_type.value_owned = true;
+		data.add_field (param_type.get_cname (), get_variable_cname (param.name));
+
+		// create copy if necessary as captured variables may need to be kept alive
+		CCodeExpression cparam = get_variable_cexpression (param.name);
+		if (requires_copy (param_type) && !param.parameter_type.value_owned)  {
+			var ma = new MemberAccess.simple (param.name);
+			ma.symbol_reference = param;
+			ma.value_type = param.parameter_type.copy ();
+			// directly access parameters in ref expressions
+			param.captured = false;
+			cparam = get_ref_cexpression (param.parameter_type, cparam, ma, param);
+			param.captured = true;
+		}
+
+		cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), get_variable_cname (param.name)), cparam)));
+
+		if (requires_destroy (param_type)) {
+			var ma = new MemberAccess.simple (param.name);
+			ma.symbol_reference = param;
+			ma.value_type = param_type.copy ();
+			free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (param.name)), param.parameter_type, ma)));
+		}
+	}
+
 	public override void visit_block (Block b) {
 		var old_symbol = current_symbol;
 		current_symbol = b;
@@ -656,6 +719,154 @@ internal class Vala.DovaBaseModule : CCodeModule {
 
 		var cblock = new CCodeBlock ();
 
+
+		if (b.captured) {
+			var parent_block = next_closure_block (b.parent_symbol);
+
+			int block_id = get_block_id (b);
+			string struct_name = "Block%dData".printf (block_id);
+
+			var free_block = new CCodeBlock ();
+
+			var data = new CCodeStruct ("_" + struct_name);
+			data.add_field ("DovaType*", "type");
+			data.add_field ("int", "_ref_count_");
+			if (parent_block != null) {
+				int parent_block_id = get_block_id (parent_block);
+
+				data.add_field ("Block%dData *".printf (parent_block_id), "_data%d_".printf (parent_block_id));
+
+				var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+				unref_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)));
+				free_block.add_statement (new CCodeExpressionStatement (unref_call));
+			} else if ((current_method != null && current_method.binding == MemberBinding.INSTANCE) ||
+			           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
+				data.add_field ("%s *".printf (current_class.get_cname ()), "this");
+
+				var ma = new MemberAccess.simple ("this");
+				ma.symbol_reference = current_class;
+				free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "this"), new ObjectType (current_class), ma)));
+			}
+			foreach (var local in local_vars) {
+				if (local.captured) {
+					generate_type_declaration (local.variable_type, source_declarations);
+
+					data.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
+
+					if (requires_destroy (local.variable_type)) {
+						var ma = new MemberAccess.simple (local.name);
+						ma.symbol_reference = local;
+						ma.value_type = local.variable_type.copy ();
+						free_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), get_variable_cname (local.name)), local.variable_type, ma)));
+					}
+				}
+			}
+
+			var data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_alloc"));
+			data_alloc.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_type_get".printf (block_id))));
+
+			var data_decl = new CCodeDeclaration (struct_name + "*");
+			data_decl.add_declarator (new CCodeVariableDeclarator ("_data%d_".printf (block_id), data_alloc));
+			cblock.add_statement (data_decl);
+
+			if (parent_block != null) {
+				int parent_block_id = get_block_id (parent_block);
+
+				var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_ref"));
+				ref_call.add_argument (get_variable_cexpression ("_data%d_".printf (parent_block_id)));
+
+				cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)), ref_call)));
+			} else if ((current_method != null && current_method.binding == MemberBinding.INSTANCE &&
+			            (!(current_method is CreationMethod) || current_method.body != b)) ||
+			           (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE)) {
+				var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), b.source_reference));
+				ref_call.add_argument (new CCodeIdentifier ("this"));
+
+				cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), "this"), ref_call)));
+			}
+
+			if (b.parent_symbol is Method) {
+				var m = (Method) b.parent_symbol;
+
+				// parameters are captured with the top-level block of the method
+				foreach (var param in m.get_parameters ()) {
+					if (param.captured) {
+						capture_parameter (param, data, cblock, block_id, free_block);
+					}
+				}
+
+				var cfrag = new CCodeFragment ();
+				append_temp_decl (cfrag, temp_vars);
+				temp_vars.clear ();
+				cblock.add_statement (cfrag);
+			} else if (b.parent_symbol is PropertyAccessor) {
+				var acc = (PropertyAccessor) b.parent_symbol;
+
+				if (!acc.readable && acc.value_parameter.captured) {
+					capture_parameter (acc.value_parameter, data, cblock, block_id, free_block);
+				}
+
+				var cfrag = new CCodeFragment ();
+				append_temp_decl (cfrag, temp_vars);
+				temp_vars.clear ();
+				cblock.add_statement (cfrag);
+			}
+
+			var typedef = new CCodeTypeDefinition ("struct _" + struct_name, new CCodeVariableDeclarator (struct_name));
+			source_declarations.add_type_declaration (typedef);
+			source_declarations.add_type_definition (data);
+
+			var data_free = new CCodeFunctionCall (new CCodeIdentifier ("free"));
+			data_free.add_argument (new CCodeIdentifier ("_data%d_".printf (block_id)));
+			free_block.add_statement (new CCodeExpressionStatement (data_free));
+
+			// create type_get/finalize functions
+			var type_get_fun = new CCodeFunction ("block%d_data_type_get".printf (block_id), "DovaType*");
+			type_get_fun.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_type_member_declaration (type_get_fun.copy ());
+			type_get_fun.block = new CCodeBlock ();
+
+			var cdecl = new CCodeDeclaration ("int");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_block%d_data_object_offset".printf (block_id), new CCodeConstant ("0")));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_type_member_declaration (cdecl);
+
+			cdecl = new CCodeDeclaration ("int");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_block%d_data_type_offset".printf (block_id), new CCodeConstant ("0")));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_type_member_declaration (cdecl);
+
+			cdecl = new CCodeDeclaration ("DovaType *");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("block%d_data_type".printf (block_id), new CCodeConstant ("NULL")));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_type_member_declaration (cdecl);
+
+			var type_init_block = new CCodeBlock ();
+			var alloc_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_alloc"));
+			alloc_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("dova_object_type_get")));
+			alloc_call.add_argument (new CCodeConstant ("sizeof (%s)".printf (struct_name)));
+			alloc_call.add_argument (new CCodeConstant ("0"));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("block%d_data_type".printf (block_id))));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_block%d_data_object_offset".printf (block_id))));
+			alloc_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_block%d_data_type_offset".printf (block_id))));
+			type_init_block.add_statement (new CCodeExpressionStatement (alloc_call));
+			var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_type_init"));
+			type_init_call.add_argument (new CCodeIdentifier ("block%d_data_type".printf (block_id)));
+			type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
+			type_get_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("block%d_data_type".printf (block_id))), type_init_block));
+			type_get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("block%d_data_type".printf (block_id))));
+
+			source_type_member_definition.append (type_get_fun);
+
+			var unref_fun = new CCodeFunction ("block%d_data_finalize".printf (block_id), "void");
+			unref_fun.add_parameter (new CCodeFormalParameter ("_data%d_".printf (block_id), struct_name + "*"));
+			unref_fun.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_type_member_declaration (unref_fun.copy ());
+			unref_fun.block = free_block;
+
+			source_type_member_definition.append (unref_fun);
+		}
+
 		foreach (CodeNode stmt in b.get_statements ()) {
 			if (stmt.error) {
 				continue;
@@ -671,7 +882,7 @@ internal class Vala.DovaBaseModule : CCodeModule {
 		}
 
 		foreach (LocalVariable local in local_vars) {
-			if (!local.floating && requires_destroy (local.variable_type)) {
+			if (!local.floating && !local.captured && requires_destroy (local.variable_type)) {
 				var ma = new MemberAccess.simple (local.name);
 				ma.symbol_reference = local;
 				cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
@@ -681,7 +892,7 @@ internal class Vala.DovaBaseModule : CCodeModule {
 		if (b.parent_symbol is Method) {
 			var m = (Method) b.parent_symbol;
 			foreach (FormalParameter param in m.get_parameters ()) {
-				if (requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
+				if (!param.captured && requires_destroy (param.parameter_type) && param.direction == ParameterDirection.IN) {
 					var ma = new MemberAccess.simple (param.name);
 					ma.symbol_reference = param;
 					cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (param.name), param.parameter_type, ma)));
@@ -689,6 +900,14 @@ internal class Vala.DovaBaseModule : CCodeModule {
 			}
 		}
 
+		if (b.captured) {
+			int block_id = get_block_id (b);
+
+			var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+			data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
+			cblock.add_statement (new CCodeExpressionStatement (data_unref));
+		}
+
 		b.ccodenode = cblock;
 
 		current_symbol = old_symbol;
@@ -748,17 +967,23 @@ internal class Vala.DovaBaseModule : CCodeModule {
 			pre_statement_fragment = null;
 		}
 
-		var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
+		if (local.captured) {
+			if (local.initializer != null) {
+				cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id ((Block) local.parent_symbol))), get_variable_cname (local.name)), rhs)));
+			}
+		} else {
+			var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
 
-		var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
-		cdecl.add_declarator (cvar);
-		cfrag.append (cdecl);
+			var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
+			cdecl.add_declarator (cvar);
+			cfrag.append (cdecl);
 
-		// try to initialize uninitialized variables
-		// initialization not necessary for variables stored in closure
-		if (cvar.initializer == null) {
-			cvar.initializer = default_value_for_type (local.variable_type, true);
-			cvar.init0 = true;
+			// try to initialize uninitialized variables
+			// initialization not necessary for variables stored in closure
+			if (cvar.initializer == null) {
+				cvar.initializer = default_value_for_type (local.variable_type, true);
+				cvar.init0 = true;
+			}
 		}
 
 		if (local.initializer != null && local.initializer.tree_can_fail) {
@@ -1162,13 +1387,21 @@ internal class Vala.DovaBaseModule : CCodeModule {
 
 		var local_vars = b.get_local_variables ();
 		foreach (LocalVariable local in local_vars) {
-			if (local.active && !local.floating && requires_destroy (local.variable_type)) {
+			if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
 				var ma = new MemberAccess.simple (local.name);
 				ma.symbol_reference = local;
 				cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
 			}
 		}
 
+		if (b.captured) {
+			int block_id = get_block_id (b);
+
+			var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+			data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
+			cfrag.append (new CCodeExpressionStatement (data_unref));
+		}
+
 		if (stop_at_loop) {
 			if (b.parent_node is Loop ||
 			    b.parent_node is ForeachStatement ||
@@ -1189,13 +1422,21 @@ internal class Vala.DovaBaseModule : CCodeModule {
 
 		var local_vars = b.get_local_variables ();
 		foreach (LocalVariable local in local_vars) {
-			if (local.active && !local.floating && requires_destroy (local.variable_type)) {
+			if (local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
 				var ma = new MemberAccess.simple (local.name);
 				ma.symbol_reference = local;
 				cfrag.append (new CCodeExpressionStatement (get_unref_expression (get_variable_cexpression (local.name), local.variable_type, ma)));
 			}
 		}
 
+		if (b.captured) {
+			int block_id = get_block_id (b);
+
+			var data_unref = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+			data_unref.add_argument (get_variable_cexpression ("_data%d_".printf (block_id)));
+			cfrag.append (new CCodeExpressionStatement (data_unref));
+		}
+
 		if (sym == current_try.body) {
 			return;
 		}
@@ -1995,8 +2236,20 @@ internal class Vala.DovaBaseModule : CCodeModule {
 			var method_type = (MethodType) expression_type;
 			CCodeExpression delegate_target = new CCodeConstant ("NULL");
 			if (method_type.method_symbol.binding == MemberBinding.INSTANCE) {
-				var ma = (MemberAccess) expr;
-				delegate_target = (CCodeExpression) get_ccodenode (ma.inner);
+				if (expr is LambdaExpression) {
+					var lambda = (LambdaExpression) expr;
+					if (lambda.method.closure) {
+						int block_id = get_block_id (current_closure_block);
+						delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
+					} else if (get_this_type () != null) {
+						delegate_target = new CCodeIdentifier ("this");
+					} else {
+						delegate_target = new CCodeConstant ("NULL");
+					}
+				} else {
+					var ma = (MemberAccess) expr;
+					delegate_target = (CCodeExpression) get_ccodenode (ma.inner);
+				}
 			}
 			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_new".printf (deleg_type.delegate_symbol.get_lower_case_cname ())));
 			ccall.add_argument (delegate_target);
@@ -2132,6 +2385,15 @@ internal class Vala.DovaBaseModule : CCodeModule {
 	public override void visit_class (Class cl) {
 	}
 
+	public DataType? get_this_type () {
+		if (current_method != null && current_method.binding == MemberBinding.INSTANCE) {
+			return current_method.this_parameter.parameter_type;
+		} else if (current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE) {
+			return current_property_accessor.prop.this_parameter.parameter_type;
+		}
+		return null;
+	}
+
 	public CCodeFunctionCall generate_instance_cast (CCodeExpression expr, TypeSymbol type) {
 		var result = new CCodeFunctionCall (new CCodeIdentifier (type.get_upper_case_cname (null)));
 		result.add_argument (expr);
diff --git a/codegen/valadovamemberaccessmodule.vala b/codegen/valadovamemberaccessmodule.vala
index 8bc36c7..8a3ade7 100644
--- a/codegen/valadovamemberaccessmodule.vala
+++ b/codegen/valadovamemberaccessmodule.vala
@@ -1,6 +1,6 @@
 /* valadovamemberaccessmodule.vala
  *
- * Copyright (C) 2006-2009  Jürg Billeter
+ * Copyright (C) 2006-2010  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -204,6 +204,10 @@ internal class Vala.DovaMemberAccessModule : DovaControlFlowModule {
 			if (local.is_result) {
 				// used in postconditions
 				expr.ccodenode = new CCodeIdentifier ("result");
+			} else if (local.captured) {
+				// captured variables are stored on the heap
+				var block = (Block) local.parent_symbol;
+				expr.ccodenode = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (local.name));
 			} else {
 				expr.ccodenode = get_variable_cexpression (local.name);
 			}
@@ -222,29 +226,38 @@ internal class Vala.DovaMemberAccessModule : DovaControlFlowModule {
 					}
 				}
 			} else {
-				if (current_method != null && current_method.coroutine) {
-					// use closure
-					expr.ccodenode = get_variable_cexpression (p.name);
+				if (p.captured) {
+					// captured variables are stored on the heap
+					var block = p.parent_symbol as Block;
+					if (block == null) {
+						block = ((Method) p.parent_symbol).body;
+					}
+					expr.ccodenode = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (p.name));
 				} else {
-					var type_as_struct = p.parameter_type.data_type as Struct;
-					if (p.direction != ParameterDirection.IN
-					    || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.parameter_type.nullable)) {
-						if (p.parameter_type is GenericType) {
-							expr.ccodenode = get_variable_cexpression (p.name);
-						} else {
-							expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name)));
-						}
+					if (current_method != null && current_method.coroutine) {
+						// use closure
+						expr.ccodenode = get_variable_cexpression (p.name);
 					} else {
-						// Property setters of non simple structs shall replace all occurences
-						// of the "value" formal parameter with a dereferencing version of that
-						// parameter.
-						if (current_property_accessor != null &&
-						    current_property_accessor.writable &&
-						    current_property_accessor.value_parameter == p &&
-						    current_property_accessor.prop.property_type.is_real_struct_type ()) {
-							expr.ccodenode = new CCodeIdentifier ("(*value)");
+						var type_as_struct = p.parameter_type.data_type as Struct;
+						if (p.direction != ParameterDirection.IN
+						    || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.parameter_type.nullable)) {
+							if (p.parameter_type is GenericType) {
+								expr.ccodenode = get_variable_cexpression (p.name);
+							} else {
+								expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name)));
+							}
 						} else {
-							expr.ccodenode = get_variable_cexpression (p.name);
+							// Property setters of non simple structs shall replace all occurences
+							// of the "value" formal parameter with a dereferencing version of that
+							// parameter.
+							if (current_property_accessor != null &&
+							    current_property_accessor.writable &&
+							    current_property_accessor.value_parameter == p &&
+							    current_property_accessor.prop.property_type.is_real_struct_type ()) {
+								expr.ccodenode = new CCodeIdentifier ("(*value)");
+							} else {
+								expr.ccodenode = get_variable_cexpression (p.name);
+							}
 						}
 					}
 				}
diff --git a/codegen/valadovaobjectmodule.vala b/codegen/valadovaobjectmodule.vala
index f6bf313..8c8edfe 100644
--- a/codegen/valadovaobjectmodule.vala
+++ b/codegen/valadovaobjectmodule.vala
@@ -1153,6 +1153,38 @@ internal class Vala.DovaObjectModule : DovaArrayModule {
 				var cinit = new CCodeFragment ();
 				function.block.prepend_statement (cinit);
 
+				if (m.closure) {
+					// add variables for parent closure blocks
+					// as closures only have one parameter for the innermost closure block
+					var closure_block = current_closure_block;
+					int block_id = get_block_id (closure_block);
+					while (true) {
+						var parent_closure_block = next_closure_block (closure_block.parent_symbol);
+						if (parent_closure_block == null) {
+							break;
+						}
+						int parent_block_id = get_block_id (parent_closure_block);
+
+						var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
+						var cdecl = new CCodeDeclaration ("Block%dData*".printf (parent_block_id));
+						cdecl.add_declarator (new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id), parent_data));
+
+						cinit.append (cdecl);
+
+						closure_block = parent_closure_block;
+						block_id = parent_block_id;
+					}
+
+					// add self variable for closures
+					// as closures have block data parameter
+					if (m.binding == MemberBinding.INSTANCE) {
+						var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "this");
+						var cdecl = new CCodeDeclaration ("%s *".printf (current_class.get_cname ()));
+						cdecl.add_declarator (new CCodeVariableDeclarator ("this", cself));
+
+						cinit.append (cdecl);
+					}
+				}
 				foreach (FormalParameter param in m.get_parameters ()) {
 					if (param.ellipsis) {
 						break;
@@ -1462,7 +1494,11 @@ internal class Vala.DovaObjectModule : DovaArrayModule {
 
 	public override void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, CCodeFunctionCall? vcall = null) {
 		CCodeFormalParameter instance_param = null;
-		if (m.parent_symbol is Class && m is CreationMethod) {
+		if (m.closure) {
+			var closure_block = current_closure_block;
+			int block_id = get_block_id (closure_block);
+			instance_param = new CCodeFormalParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
+		} else if (m.parent_symbol is Class && m is CreationMethod) {
 			if (vcall == null) {
 				instance_param = new CCodeFormalParameter ("this", ((Class) m.parent_symbol).get_cname () + "*");
 			}



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