add support for instance delegates, fixes bug 508734
authorJuerg Billeter <j@bitron.ch>
Mon, 14 Jan 2008 20:47:21 +0000 (20:47 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Mon, 14 Jan 2008 20:47:21 +0000 (20:47 +0000)
2008-01-14  Juerg Billeter  <j@bitron.ch>

* 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
gobject/valaccodegenerator.vala
gobject/valaccodegeneratorinvocationexpression.vala
gobject/valaccodegeneratormethod.vala
tests/delegates.exp
tests/delegates.vala
vala/parser.y
vala/valainvocationexpression.vala

index 066a1af..3c4d613 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-01-14  Jürg Billeter  <j@bitron.ch>
+
+       * 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  <j@bitron.ch>
 
        * vala/Makefile.am, vala/parser.y, vala/vala.h,
index 2b06eb8..8d2b4f6 100644 (file)
@@ -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 ();
index f4b8c0d..a8529b6 100644 (file)
@@ -221,6 +221,7 @@ public class Vala.CCodeGenerator {
                        }
 
                        CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+                       Gee.List<CCodeExpression> extra_args = new ArrayList<CCodeExpression> ();
                        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) {
index 246e0c4..b2b5df7 100644 (file)
@@ -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)) {
index b613db0..8cf4ba3 100644 (file)
@@ -1 +1 @@
-Delegate Test: 1 2 3 4 5
+Delegate Test: 1 2 3 4 5 6 7
index a0b2256..363f73e 100644 (file)
@@ -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;
        }
 }
index 8ac31b9..198033d 100644 (file)
@@ -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);
index 550a6a5..ce9428e 100644 (file)
@@ -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<Expression> argument_list = new ArrayList<Expression> ();