From 9b2aa0e3d3cd88549934ce69a22fd78bcda8a548 Mon Sep 17 00:00:00 2001 From: Juerg Billeter Date: Mon, 14 Jan 2008 20:47:21 +0000 Subject: [PATCH] add support for instance delegates, fixes bug 508734 2008-01-14 Juerg Billeter * vala/parser.y, vala/valainvocationexpression.vala, gobject/valaccodegenerator.vala, gobject/valaccodegeneratorinvocationexpression.vala, gobject/valaccodegeneratormethod.vala: add support for instance delegates, fixes bug 508734 * tests/delegates.exp, tests/delegates.vala: test instance delegates svn path=/trunk/; revision=837 --- ChangeLog | 10 ++ gobject/valaccodegenerator.vala | 161 ++++++++++++++++++++- .../valaccodegeneratorinvocationexpression.vala | 31 ++++ gobject/valaccodegeneratormethod.vala | 29 +++- tests/delegates.exp | 2 +- tests/delegates.vala | 26 +++- vala/parser.y | 5 +- vala/valainvocationexpression.vala | 4 +- 8 files changed, 249 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 066a1af..3c4d613 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-01-14 Jürg Billeter + + * vala/parser.y, vala/valainvocationexpression.vala, + gobject/valaccodegenerator.vala, + gobject/valaccodegeneratorinvocationexpression.vala, + gobject/valaccodegeneratormethod.vala: add support for instance + delegates, fixes bug 508734 + + * tests/delegates.exp, tests/delegates.vala: test instance delegates + 2008-01-12 Jürg Billeter * vala/Makefile.am, vala/parser.y, vala/vala.h, diff --git a/gobject/valaccodegenerator.vala b/gobject/valaccodegenerator.vala index 2b06eb8..8d2b4f6 100644 --- a/gobject/valaccodegenerator.vala +++ b/gobject/valaccodegenerator.vala @@ -298,17 +298,21 @@ public class Vala.CCodeGenerator : CodeGenerator { } } - public override void visit_delegate (Delegate! cb) { - cb.accept_children (this); + public override void visit_delegate (Delegate! d) { + d.accept_children (this); - var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ()); - foreach (FormalParameter param in cb.get_parameters ()) { + var cfundecl = new CCodeFunctionDeclarator (d.get_cname ()); + foreach (FormalParameter param in d.get_parameters ()) { cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode); } - - var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl); - - if (!cb.is_internal_symbol ()) { + if (d.instance) { + var cparam = new CCodeFormalParameter ("user_data", "void*"); + cfundecl.add_parameter (cparam); + } + + var ctypedef = new CCodeTypeDefinition (d.return_type.get_cname (), cfundecl); + + if (!d.is_internal_symbol ()) { header_type_definition.append (ctypedef); } else { source_type_member_declaration.append (ctypedef); @@ -876,6 +880,16 @@ public class Vala.CCodeGenerator : CodeGenerator { temp_vars.insert (0, len_decl); } + } else if (decl.type_reference is DelegateType) { + var deleg_type = (DelegateType) decl.type_reference; + var d = deleg_type.delegate_symbol; + if (d.instance) { + // create variable to store delegate target + var target_decl = new VariableDeclarator (get_delegate_target_cname (decl.name)); + target_decl.type_reference = new PointerType (new VoidType ()); + + temp_vars.insert (0, target_decl); + } } CCodeExpression rhs = null; @@ -901,6 +915,24 @@ public class Vala.CCodeGenerator : CodeGenerator { ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); rhs = ccomma; + } else if (decl.type_reference is DelegateType) { + var deleg_type = (DelegateType) decl.type_reference; + var d = deleg_type.delegate_symbol; + if (d.instance) { + var ccomma = new CCodeCommaExpression (); + + var temp_decl = get_temp_variable_declarator (decl.type_reference, true, decl); + temp_vars.insert (0, temp_decl); + ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs)); + + var lhs_delegate_target = new CCodeIdentifier (get_delegate_target_cname (decl.name)); + var rhs_delegate_target = get_delegate_target_cexpression (decl.initializer); + ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target)); + + ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); + + rhs = ccomma; + } } } else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) { rhs = new CCodeConstant ("NULL"); @@ -2034,6 +2066,10 @@ public class Vala.CCodeGenerator : CodeGenerator { visit_expression (expr); } + + private string! get_array_length_cname (string! array_cname, int dim) { + return "%s_length%d".printf (array_cname, dim); + } public CCodeExpression! get_array_length_cexpression (Expression! array_expr, int dim) { bool is_out = false; @@ -2150,6 +2186,115 @@ public class Vala.CCodeGenerator : CodeGenerator { return new CCodeConstant ("NULL"); } } + + private string! get_delegate_target_cname (string! delegate_cname) { + return "%s_target".printf (delegate_cname); + } + + public CCodeExpression! get_delegate_target_cexpression (Expression! delegate_expr) { + bool is_out = false; + + if (delegate_expr is UnaryExpression) { + var unary_expr = (UnaryExpression) delegate_expr; + if (unary_expr.operator == UnaryOperator.OUT || unary_expr.operator == UnaryOperator.REF) { + delegate_expr = unary_expr.inner; + is_out = true; + } + } + + if (delegate_expr is InvocationExpression) { + var invocation_expr = (InvocationExpression) delegate_expr; + return invocation_expr.delegate_target; + } 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 (param.name)); + if (param.type_reference.is_out || param.type_reference.is_ref) { + // accessing argument of out/ref param + target_expr = new CCodeParenthesizedExpression (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 VariableDeclarator) { + var decl = (VariableDeclarator) delegate_expr.symbol_reference; + var target_expr = new CCodeIdentifier (get_delegate_target_cname (decl.name)); + if (is_out) { + return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr); + } else { + return target_expr; + } + } else if (delegate_expr.symbol_reference is Field) { + var field = (Field) delegate_expr.symbol_reference; + var target_cname = get_delegate_target_cname (field.name); + + var ma = (MemberAccess) delegate_expr; + + CCodeExpression pub_inst = null; + Typesymbol base_type = null; + CCodeExpression target_expr = null; + + if (ma.inner == null) { + pub_inst = new CCodeIdentifier ("self"); + + if (current_type_symbol != null) { + /* base type is available if this is a type method */ + base_type = (Typesymbol) current_type_symbol; + } + } else { + pub_inst = (CCodeExpression) ma.inner.ccodenode; + + if (ma.inner.static_type != null) { + base_type = ma.inner.static_type.data_type; + } + } + + if (field.instance) { + var instance_expression_type = new DataType (); + instance_expression_type.data_type = base_type; + var instance_target_type = new DataType (); + instance_target_type.data_type = (Typesymbol) field.parent_symbol; + CCodeExpression typed_inst = get_implicit_cast_expression (pub_inst, instance_expression_type, instance_target_type); + + CCodeExpression inst; + if (field.access == SymbolAccessibility.PRIVATE) { + inst = new CCodeMemberAccess.pointer (typed_inst, "priv"); + } else { + inst = typed_inst; + } + if (((Typesymbol) field.parent_symbol).is_reference_type ()) { + target_expr = new CCodeMemberAccess.pointer (inst, target_cname); + } else { + target_expr = new CCodeMemberAccess (inst, target_cname); + } + } else { + target_expr = new CCodeIdentifier (target_cname); + } + + if (is_out) { + return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, target_expr); + } else { + return target_expr; + } + } else if (delegate_expr.symbol_reference is Method) { + var ma = (MemberAccess) delegate_expr; + if (ma.inner == null) { + if (current_method != null && current_method.instance) { + return new CCodeIdentifier ("self"); + } else { + return new CCodeConstant ("NULL"); + } + } else { + return (CCodeExpression) ma.inner.ccodenode; + } + } + } + + return new CCodeConstant ("NULL"); + } public override void visit_element_access (ElementAccess! expr) { expr.code_binding.emit (); diff --git a/gobject/valaccodegeneratorinvocationexpression.vala b/gobject/valaccodegeneratorinvocationexpression.vala index f4b8c0d..a8529b6 100644 --- a/gobject/valaccodegeneratorinvocationexpression.vala +++ b/gobject/valaccodegeneratorinvocationexpression.vala @@ -221,6 +221,7 @@ public class Vala.CCodeGenerator { } CCodeExpression cexpr = (CCodeExpression) arg.ccodenode; + Gee.List extra_args = new ArrayList (); if (params_it.next ()) { var param = params_it.get (); ellipsis = param.ellipsis; @@ -233,6 +234,12 @@ public class Vala.CCodeGenerator { for (int dim = 1; dim <= arr.rank; dim++) { ccall.add_argument (get_array_length_cexpression (arg, dim)); } + } else if (param.type_reference is DelegateType) { + var deleg_type = (DelegateType) param.type_reference; + var d = deleg_type.delegate_symbol; + if (d.instance) { + extra_args.add (get_delegate_target_cexpression (arg)); + } } cexpr = get_implicit_cast_expression (cexpr, arg.static_type, param.type_reference); @@ -287,6 +294,11 @@ public class Vala.CCodeGenerator { } ccall.add_argument (cexpr); + + foreach (CCodeExpression extra_arg in extra_args) { + ccall.add_argument (extra_arg); + } + i++; } while (params_it.next ()) { @@ -341,6 +353,19 @@ public class Vala.CCodeGenerator { expr.append_array_size (new CCodeConstant ("-1")); } } + } else if (m != null && m.return_type is DelegateType) { + var deleg_type = (DelegateType) m.return_type; + var d = deleg_type.delegate_symbol; + if (d.instance) { + var temp_decl = get_temp_variable_declarator (new PointerType (new VoidType ())); + var temp_ref = new CCodeIdentifier (temp_decl.name); + + temp_vars.insert (0, temp_decl); + + ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref)); + + expr.delegate_target = temp_ref; + } } if (connection_type != null && ma.inner != null && ma.inner.static_type != null && ma.inner.static_type.data_type == connection_type && m.name == "get_object") { @@ -365,6 +390,12 @@ public class Vala.CCodeGenerator { if ((m == null || !m.printf_format) && !(m is DBusMethod)) { ccall.add_argument (new CCodeConstant (m.sentinel)); } + } else if (itype is DelegateType) { + var deleg_type = (DelegateType) itype; + var d = deleg_type.delegate_symbol; + if (d.instance) { + ccall.add_argument (get_delegate_target_cexpression (expr.call)); + } } if (m != null && m.instance && m.returns_modified_pointer) { diff --git a/gobject/valaccodegeneratormethod.vala b/gobject/valaccodegeneratormethod.vala index 246e0c4..b2b5df7 100644 --- a/gobject/valaccodegeneratormethod.vala +++ b/gobject/valaccodegeneratormethod.vala @@ -197,10 +197,22 @@ public class Vala.CCodeGenerator { if (vdeclarator != null) { vdeclarator.add_parameter ((CCodeFormalParameter) param.ccodenode); } + + if (param.type_reference is DelegateType) { + var deleg_type = (DelegateType) param.type_reference; + var d = deleg_type.delegate_symbol; + if (d.instance) { + var cparam = new CCodeFormalParameter (get_delegate_target_cname (param.name), "void*"); + function.add_parameter (cparam); + if (vdeclarator != null) { + vdeclarator.add_parameter (cparam); + } + } + } } - // return array length if appropriate if (!m.no_array_length && creturn_type.data_type is Array) { + // return array length if appropriate var arr = (Array) creturn_type.data_type; for (int dim = 1; dim <= arr.rank; dim++) { @@ -210,6 +222,17 @@ public class Vala.CCodeGenerator { vdeclarator.add_parameter (cparam); } } + } else if (creturn_type is DelegateType) { + // return delegate target if appropriate + var deleg_type = (DelegateType) creturn_type; + var d = deleg_type.delegate_symbol; + if (d.instance) { + var cparam = new CCodeFormalParameter (get_delegate_target_cname ("result"), "void*"); + function.add_parameter (cparam); + if (vdeclarator != null) { + vdeclarator.add_parameter (cparam); + } + } } if (m.instance && m.instance_last) { @@ -627,10 +650,6 @@ public class Vala.CCodeGenerator { } return null; } - - private string! get_array_length_cname (string! array_cname, int dim) { - return "%s_length%d".printf (array_cname, dim); - } public override void visit_creation_method (CreationMethod! m) { if (m.body != null && current_type_symbol is Class && current_class.is_subtype_of (gobject_type)) { diff --git a/tests/delegates.exp b/tests/delegates.exp index b613db0..8cf4ba3 100644 --- a/tests/delegates.exp +++ b/tests/delegates.exp @@ -1 +1 @@ -Delegate Test: 1 2 3 4 5 +Delegate Test: 1 2 3 4 5 6 7 diff --git a/tests/delegates.vala b/tests/delegates.vala index a0b2256..363f73e 100644 --- a/tests/delegates.vala +++ b/tests/delegates.vala @@ -4,7 +4,12 @@ public static delegate void Maman.VoidCallback (); public static delegate int Maman.ActionCallback (); +public delegate void Maman.InstanceCallback (); + class Maman.Bar : Object { + public Bar () { + } + static void do_void_action () { stdout.printf (" 2"); } @@ -13,6 +18,14 @@ class Maman.Bar : Object { return 4; } + void do_instance_action () { + stdout.printf (" 6"); + } + + static void call_instance_delegate (InstanceCallback instance_cb) { + instance_cb (); + } + static int main (string[] args) { stdout.printf ("Delegate Test: 1"); @@ -25,9 +38,16 @@ class Maman.Bar : Object { ActionCallback cb = do_action; stdout.printf (" %d", cb ()); - - stdout.printf (" 5\n"); - + + stdout.printf (" 5"); + + var bar = new Bar (); + + InstanceCallback instance_cb = bar.do_instance_action; + call_instance_delegate (instance_cb); + + stdout.printf (" 7\n"); + return 0; } } diff --git a/vala/parser.y b/vala/parser.y index 8ac31b9..198033d 100644 --- a/vala/parser.y +++ b/vala/parser.y @@ -3797,7 +3797,10 @@ delegate_declaration vala_symbol_set_access (VALA_SYMBOL (cb), $3); } VALA_CODE_NODE (cb)->attributes = $2; - + if (($4 & VALA_MODIFIER_STATIC) == 0) { + vala_delegate_set_instance (cb, TRUE); + } + if ($9 != NULL) { for (l = $9; l != NULL; l = l->next) { vala_delegate_add_type_parameter (cb, l->data); diff --git a/vala/valainvocationexpression.vala b/vala/valainvocationexpression.vala index 550a6a5..ce9428e 100644 --- a/vala/valainvocationexpression.vala +++ b/vala/valainvocationexpression.vala @@ -1,6 +1,6 @@ /* valainvocationexpression.vala * - * Copyright (C) 2006-2007 Jürg Billeter + * Copyright (C) 2006-2008 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 @@ -38,6 +38,8 @@ public class Vala.InvocationExpression : Expression { } } + public CCodeExpression delegate_target { get; set; } + public Expression! _call; private Gee.List argument_list = new ArrayList (); -- 2.7.4