From: Jürg Billeter Date: Tue, 15 Sep 2009 15:48:44 +0000 (+0200) Subject: Support capturing parameters in closures X-Git-Tag: 0.7.6~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c2326dde18ca91c135831edf9be33fe1ea6b0664;p=thirdparty%2Fvala.git Support capturing parameters in closures --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 44b5e4bd6..efc3d0b88 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 357e1dcf9..3ff96666e 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 (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 027d4a227..85424fc9a 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 6c6e575b5..3a35aebcc 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 1e076e435..79f64df37 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;