Improve support for dynamic types, add `dynamic' type modifier, port
authorJuerg Billeter <j@bitron.ch>
Sun, 20 Apr 2008 18:50:28 +0000 (18:50 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sun, 20 Apr 2008 18:50:28 +0000 (18:50 +0000)
2008-04-20  Juerg Billeter  <j@bitron.ch>

* vala/Makefile.am, vala/valaclasstype.vala,
  vala/valacodecontext.vala, vala/valacodegenerator.vala,
  vala/valadatatype.vala, vala/valadynamicmethod.vala,
  vala/valadynamicsignal.vala, vala/valainterface.vala,
  vala/valainterfacetype.vala, vala/valamethod.vala,
  vala/valamethodtype.vala, vala/valaparser.vala,
  vala/valascanner.vala, vala/valasemanticanalyzer.vala,
  vala/valasymbolresolver.vala, vala/valatokentype.vala,
  vala/valaunresolvedtype.vala, vala/valavaluetype.vala,
  gobject/Makefile.am, gobject/valaccodeassignmentbinding.vala,
  gobject/valaccodebinding.vala,
  gobject/valaccodedynamicmethodbinding.vala,
  gobject/valaccodedynamicsignalbinding.vala,
  gobject/valaccodegenerator.vala,
  gobject/valaccodegeneratorsourcefile.vala,
  gobject/valaccodeinterfacebinding.vala,
  gobject/valaccodeinvocationexpressionbinding.vala,
  gobject/valaccodemethodbinding.vala, compiler/valacompiler.vala,
  vapi/dbus-glib-1.vapi:

  Improve support for dynamic types, add `dynamic' type modifier,
  port dynamic D-Bus client support

svn path=/trunk/; revision=1288

34 files changed:
ChangeLog
compiler/valacompiler.vala
gobject/Makefile.am
gobject/valaccodeassignmentbinding.vala
gobject/valaccodebinding.vala
gobject/valaccodedynamicmethodbinding.vala [new file with mode: 0644]
gobject/valaccodedynamicsignalbinding.vala [new file with mode: 0644]
gobject/valaccodegenerator.vala
gobject/valaccodegeneratorsourcefile.vala
gobject/valaccodeinterfacebinding.vala
gobject/valaccodeinvocationexpressionbinding.vala
gobject/valaccodemethodbinding.vala
gobject/valadbusbindingprovider.vala [deleted file]
gobject/valadbussignal.vala [deleted file]
vala/Makefile.am
vala/valabindingprovider.vala [deleted file]
vala/valaclasstype.vala
vala/valacodecontext.vala
vala/valacodegenerator.vala
vala/valadatatype.vala
vala/valadynamicmethod.vala [new file with mode: 0644]
vala/valadynamicsignal.vala [moved from gobject/valadbusmethod.vala with 63% similarity]
vala/valainterface.vala
vala/valainterfacetype.vala
vala/valamethod.vala
vala/valamethodtype.vala
vala/valaparser.vala
vala/valascanner.vala
vala/valasemanticanalyzer.vala
vala/valasymbolresolver.vala
vala/valatokentype.vala
vala/valaunresolvedtype.vala
vala/valavaluetype.vala
vapi/dbus-glib-1.vapi

index bf8d2bf..2067234 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,30 @@
 2008-04-20  Jürg Billeter  <j@bitron.ch>
 
+       * vala/Makefile.am, vala/valaclasstype.vala,
+         vala/valacodecontext.vala, vala/valacodegenerator.vala,
+         vala/valadatatype.vala, vala/valadynamicmethod.vala,
+         vala/valadynamicsignal.vala, vala/valainterface.vala,
+         vala/valainterfacetype.vala, vala/valamethod.vala,
+         vala/valamethodtype.vala, vala/valaparser.vala,
+         vala/valascanner.vala, vala/valasemanticanalyzer.vala,
+         vala/valasymbolresolver.vala, vala/valatokentype.vala,
+         vala/valaunresolvedtype.vala, vala/valavaluetype.vala,
+         gobject/Makefile.am, gobject/valaccodeassignmentbinding.vala,
+         gobject/valaccodebinding.vala,
+         gobject/valaccodedynamicmethodbinding.vala,
+         gobject/valaccodedynamicsignalbinding.vala,
+         gobject/valaccodegenerator.vala,
+         gobject/valaccodegeneratorsourcefile.vala,
+         gobject/valaccodeinterfacebinding.vala,
+         gobject/valaccodeinvocationexpressionbinding.vala,
+         gobject/valaccodemethodbinding.vala, compiler/valacompiler.vala,
+         vapi/dbus-glib-1.vapi:
+
+         Improve support for dynamic types, add `dynamic' type modifier,
+         port dynamic D-Bus client support
+
+2008-04-20  Jürg Billeter  <j@bitron.ch>
+
        * vapi/packages/gtk+-2.0/: fix GtkDialog.vbox binding
 
        * vapi/gtk+-2.0.vapi: regenerated
index 4f79567..d792713 100644 (file)
@@ -234,11 +234,7 @@ class Vala.Compiler : Object {
                        return quit ();
                }
 
-               var dbus_binding_provider = new DBusBindingProvider ();
-               dbus_binding_provider.context = context;
-
                var analyzer = new SemanticAnalyzer ();
-               analyzer.add_binding_provider (dbus_binding_provider);
                analyzer.analyze (context);
                
                if (Report.get_errors () > 0) {
index ba57b5f..eee0c59 100644 (file)
@@ -18,6 +18,8 @@ libvala_la_VALASOURCES = \
        valaccodeclassbinding.vala \
        valaccodecompiler.vala \
        valaccodecreationmethodbinding.vala \
+       valaccodedynamicmethodbinding.vala \
+       valaccodedynamicsignalbinding.vala \
        valaccodeelementaccessbinding.vala \
        valaccodeexpressionbinding.vala \
        valaccodegenerator.vala \
@@ -30,9 +32,6 @@ libvala_la_VALASOURCES = \
        valaccodemethodbinding.vala \
        valaccodetypesymbolbinding.vala \
        valaclassregisterfunction.vala \
-       valadbusbindingprovider.vala \
-       valadbusmethod.vala \
-       valadbussignal.vala \
        valagidlwriter.vala \
        valainterfaceregisterfunction.vala \
        valatyperegisterfunction.vala \
index 5e12b53..870e7ca 100644 (file)
@@ -106,8 +106,8 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                bool disconnect = false;
 
                if (assignment.operator == AssignmentOperator.ADD) {
-                       if (sig is DBusSignal) {
-                               connect_func = "dbus_g_proxy_connect_signal";
+                       if (sig is DynamicSignal) {
+                               connect_func = codegen.dynamic_signal_binding ((DynamicSignal) sig).get_connect_wrapper_name ();
                        } else {
                                connect_func = "g_signal_connect_object";
                                if (!m.instance) {
@@ -115,8 +115,8 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                                }
                        }
                } else if (assignment.operator == AssignmentOperator.SUB) {
-                       if (sig is DBusSignal) {
-                               connect_func = "dbus_g_proxy_disconnect_signal";
+                       if (sig is DynamicSignal) {
+                               connect_func = codegen.dynamic_signal_binding ((DynamicSignal) sig).get_disconnect_wrapper_name ();
                        } else {
                                connect_func = "g_signal_handlers_disconnect_matched";
                        }
@@ -136,8 +136,8 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                        ccall.add_argument (new CCodeIdentifier ("self"));
                }
 
-               if (sig is DBusSignal) {
-                       // dbus_g_proxy_connect_signal or dbus_g_proxy_disconnect_signal
+               if (sig is DynamicSignal) {
+                       // dynamic_signal_connect or dynamic_signal_disconnect
 
                        // second argument: signal name
                        ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
@@ -176,8 +176,8 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                }
 
                // third resp. sixth argument: handler
-               if (sig is DBusSignal) {
-                       // signal handler wrappers not used for D-Bus signals
+               if (sig is DynamicSignal) {
+                       // signal handler wrappers not used for dynamic signals
                        ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback"));
                        m.cinstance_parameter_position = -1;
                } else {
@@ -186,7 +186,7 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
 
                if (m.instance) {
                        // g_signal_connect_object or g_signal_handlers_disconnect_matched
-                       // or dbus_g_proxy_connect_signal or dbus_g_proxy_disconnect_signal
+                       // or dynamic_signal_connect or dynamic_signal_disconnect
 
                        // fourth resp. seventh argument: object/user_data
                        if (assignment.right is MemberAccess) {
@@ -199,98 +199,21 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                        } else if (assignment.right is LambdaExpression) {
                                ccall.add_argument (new CCodeIdentifier ("self"));
                        }
-                       if (!disconnect) {
-                               if (sig is DBusSignal) {
-                                       // dbus_g_proxy_connect_signal
+                       if (!disconnect && !(sig is DynamicSignal)) {
+                               // g_signal_connect_object
 
-                                       // fifth argument: free_data_func
-                                       ccall.add_argument (new CCodeConstant ("NULL"));
-                               } else {
-                                       // g_signal_connect_object
-
-                                       // fifth argument: connect_flags
-                                       ccall.add_argument (new CCodeConstant ("0"));
-                               }
+                               // fifth argument: connect_flags
+                               ccall.add_argument (new CCodeConstant ("0"));
                        }
                } else {
                        // g_signal_connect or g_signal_handlers_disconnect_matched
-                       // or dbus_g_proxy_connect_signal or dbus_g_proxy_disconnect_signal
+                       // or dynamic_signal_connect or dynamic_signal_disconnect
 
                        // fourth resp. seventh argument: user_data
                        ccall.add_argument (new CCodeConstant ("NULL"));
-
-                       if (sig is DBusSignal && !disconnect) {
-                               // fifth argument: free_data_func
-                               ccall.add_argument (new CCodeConstant ("NULL"));
-                       }
                }
                
                codenode = ccall;
-               
-               if (sig is DBusSignal && !disconnect) {
-                       bool first = true;
-                       foreach (FormalParameter param in m.get_parameters ()) {
-                               if (first) {
-                                       // skip sender parameter
-                                       first = false;
-                                       continue;
-                               }
-                               sig.add_parameter (param.copy ());
-                       }
-
-                       sig.accept (codegen);
-
-                       // FIXME should only be done once per marshaller
-                       var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
-                       register_call.add_argument (new CCodeIdentifier (codegen.get_signal_marshaller_function (sig)));
-                       register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
-
-                       var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
-                       if (ma.inner != null) {
-                               add_call.add_argument ((CCodeExpression) ma.inner.ccodenode);
-                       } else {
-                               add_call.add_argument (new CCodeIdentifier ("self"));
-                       }
-                       add_call.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
-
-                       first = true;
-                       foreach (FormalParameter param in m.get_parameters ()) {
-                               if (first) {
-                                       // skip sender parameter
-                                       first = false;
-                                       continue;
-                               }
-                               if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type != codegen.string_type.data_type) {
-                                       var array_type = (ArrayType) param.type_reference;
-                                       if (array_type.element_type.data_type.get_type_id () == null) {
-                                               Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
-                                               return;
-                                       }
-
-                                       var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
-                                       carray_type.add_argument (new CCodeConstant ("\"GArray\""));
-                                       carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
-                                       register_call.add_argument (carray_type);
-                                       add_call.add_argument (carray_type);
-                               } else {
-                                       if (param.type_reference.get_type_id () == null) {
-                                               Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
-                                               return;
-                                       }
-
-                                       register_call.add_argument (new CCodeIdentifier (param.type_reference.get_type_id ()));
-                                       add_call.add_argument (new CCodeIdentifier (param.type_reference.get_type_id ()));
-                               }
-                       }
-                       register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
-                       add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
-
-                       var ccomma = new CCodeCommaExpression ();
-                       ccomma.append_expression (register_call);
-                       ccomma.append_expression (add_call);
-                       ccomma.append_expression (ccall);
-                       codenode = ccomma;
-               }
        }
 
        private string generate_signal_handler_wrapper (Method m, Signal sig) {
index b0aeda3..525ad76 100644 (file)
@@ -34,7 +34,8 @@ public abstract class Vala.CCodeBinding : CodeBinding {
        /**
         * Generate code for this source code node.
         */
-       public abstract void emit ();
+       public virtual void emit () {
+       }
 
        public CCodeIdentifier get_value_setter_function (DataType type_reference) {
                if (type_reference.data_type != null) {
diff --git a/gobject/valaccodedynamicmethodbinding.vala b/gobject/valaccodedynamicmethodbinding.vala
new file mode 100644 (file)
index 0000000..145414c
--- /dev/null
@@ -0,0 +1,257 @@
+/* valaccodedynamicmethodbinding.vala
+ *
+ * Copyright (C) 2007-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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * The link between a dynamic method and generated code.
+ */
+public class Vala.CCodeDynamicMethodBinding : CCodeMethodBinding {
+       public CCodeDynamicMethodBinding (CCodeGenerator codegen, DynamicMethod method) {
+               this.method = method;
+               this.codegen = codegen;
+       }
+
+       public void generate_wrapper () {
+               var dynamic_method = (DynamicMethod) method;
+
+               var func = new CCodeFunction (method.get_cname (), method.return_type.get_cname ());
+
+               var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+               var instance_param = new CCodeFormalParameter ("obj", "gpointer");
+               cparam_map.set (codegen.get_param_pos (method.cinstance_parameter_position), instance_param);
+
+               generate_cparameters (method, method.return_type, cparam_map, func);
+
+               var block = new CCodeBlock ();
+               if (dynamic_method.dynamic_type.data_type == codegen.dbus_object_type) {
+                       generate_dbus_method_wrapper (block);
+               } else {
+                       Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
+               }
+
+               // append to C source file
+               codegen.source_type_member_declaration.append (func.copy ());
+
+               func.block = block;
+               codegen.source_type_member_definition.append (func);
+       }
+
+       void generate_dbus_method_wrapper (CCodeBlock block) {
+               var dynamic_method = (DynamicMethod) method;
+
+               var expr = dynamic_method.invocation;
+
+               var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_begin_call"));
+
+               ccall.add_argument (new CCodeIdentifier ("obj"));
+
+               bool found_out = false;
+               Expression callback = null;
+               int callback_index = -1;
+               int arg_index = 1;
+               foreach (Expression arg in expr.get_argument_list ()) {
+                       if (arg.symbol_reference is Method) {
+                               // callback
+                               if (callback != null) {
+                                       Report.error (expr.source_reference, "only one reply callback may be specified in invocation of DBus method");
+                                       expr.error = true;
+                                       return;
+                               } else if (found_out) {
+                                       Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
+                                       expr.error = true;
+                                       return;
+                               }
+                               callback = arg;
+                               callback_index = arg_index;
+                       } else if (arg is UnaryExpression && ((UnaryExpression) arg).operator == UnaryOperator.OUT) {
+                               // out arg
+                               if (callback != null) {
+                                       Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
+                                       expr.error = true;
+                                       return;
+                               }
+                               found_out = true;
+                       } else {
+                               // in arg
+                               if (callback != null || found_out) {
+                                       Report.error (expr.source_reference, "in argument must not follow out argument or reply callback in invocation of DBus method");
+                                       expr.error = true;
+                                       return;
+                               }
+                       }
+                       arg_index++;
+               }
+
+               ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method.name)));
+
+               if (callback != null) {
+                       var reply_method = (Method) callback.symbol_reference;
+
+                       var cb_fun = new CCodeFunction ("_%s_cb".printf (reply_method.get_cname ()), "void");
+                       cb_fun.modifiers = CCodeModifiers.STATIC;
+                       cb_fun.add_parameter (new CCodeFormalParameter ("proxy", "DBusGProxy*"));
+                       cb_fun.add_parameter (new CCodeFormalParameter ("call", "DBusGProxyCall*"));
+                       cb_fun.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
+                       cb_fun.block = new CCodeBlock ();
+                       var cerrdecl = new CCodeDeclaration ("GError*");
+                       cerrdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("error", new CCodeConstant ("NULL")));
+                       cb_fun.block.add_statement (cerrdecl);
+                       var cend_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_end_call"));
+                       cend_call.add_argument (new CCodeIdentifier ("proxy"));
+                       cend_call.add_argument (new CCodeIdentifier ("call"));
+                       cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
+                       var creply_call = new CCodeFunctionCall ((CCodeExpression) callback.ccodenode);
+                       creply_call.add_argument (new CCodeIdentifier ("user_data"));
+                       int param_count = reply_method.get_parameters ().size;
+                       int i = 0;
+                       foreach (FormalParameter param in reply_method.get_parameters ()) {
+                               if ((++i) == param_count) {
+                                       // error parameter
+                                       break;
+                               }
+                               if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type != codegen.string_type.data_type) {
+                                       var array_type = (ArrayType) param.type_reference;
+                                       var cdecl = new CCodeDeclaration ("GArray*");
+                                       cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
+                                       cb_fun.block.add_statement (cdecl);
+                                       cend_call.add_argument (get_dbus_array_type (array_type));
+                                       cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+                                       creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "data"));
+                                       creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "len"));
+                               } else {
+                                       var cdecl = new CCodeDeclaration (param.type_reference.get_cname ());
+                                       cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
+                                       cb_fun.block.add_statement (cdecl);
+                                       if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type == codegen.string_type.data_type) {
+                                               // special case string array
+                                               cend_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
+                                               var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
+                                               cstrvlen.add_argument (new CCodeIdentifier (param.name));
+                                               creply_call.add_argument (cstrvlen);
+                                       } else {
+                                               cend_call.add_argument (new CCodeIdentifier (param.type_reference.data_type.get_type_id ()));
+                                       }
+                                       cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+                                       creply_call.add_argument (new CCodeIdentifier (param.name));
+                               }
+                       }
+                       cend_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+                       cb_fun.block.add_statement (new CCodeExpressionStatement (cend_call));
+                       creply_call.add_argument (new CCodeIdentifier ("error"));
+                       cb_fun.block.add_statement (new CCodeExpressionStatement (creply_call));
+                       codegen.source_type_member_definition.append (cb_fun);
+
+                       ccall.add_argument (new CCodeIdentifier (cb_fun.name));
+                       ccall.add_argument (new CCodeConstant ("param%d_target".printf (callback_index)));
+                       ccall.add_argument (new CCodeConstant ("NULL"));
+               } else if (found_out || !(method.return_type is VoidType)) {
+                       ccall.call = new CCodeIdentifier ("dbus_g_proxy_call");
+
+                       ccall.add_argument (new CCodeIdentifier ("error"));
+               } else {
+                       ccall.call = new CCodeIdentifier ("dbus_g_proxy_call_no_reply");
+               }
+
+               foreach (FormalParameter param in method.get_parameters ()) {
+                       if (param.type_reference is MethodType) {
+                               // callback parameter
+                               break;
+                       }
+
+                       ccall.add_argument (new CCodeIdentifier (param.type_reference.data_type.get_type_id ()));
+                       ccall.add_argument (new CCodeIdentifier (param.name));
+               }
+
+               ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+
+               if (!(method.return_type is VoidType)) {
+                       // synchronous D-Bus method call with reply
+                       var array_type = method.return_type as ArrayType;
+                       if (array_type != null && array_type.element_type.data_type != codegen.string_type.data_type) {
+                               // non-string arrays (use GArray)
+                               ccall.add_argument (get_dbus_array_type (array_type));
+
+                               var garray_type_reference = codegen.get_data_type_for_symbol (codegen.garray_type);
+                               var cdecl = new CCodeDeclaration (garray_type_reference.get_cname ());
+                               cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+                               block.add_statement (cdecl);
+
+                               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+                               ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+
+                               block.add_statement (new CCodeExpressionStatement (ccall));
+
+                               block.add_statement (new CCodeReturnStatement (new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), "data")));
+
+                               if (!method.no_array_length) {
+                                       expr.append_array_size (new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), "len"));
+                               } else {
+                                       expr.append_array_size (new CCodeConstant ("-1"));
+                               }
+                       } else {
+                               // string arrays or other datatypes
+
+                               if (method.return_type is ArrayType) {
+                                       // string arrays
+                                       ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
+                               } else {
+                                       // other types
+                                       ccall.add_argument (new CCodeIdentifier (method.return_type.data_type.get_type_id ()));
+                               }
+
+                               var cdecl = new CCodeDeclaration (method.return_type.get_cname ());
+                               cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+                               block.add_statement (cdecl);
+
+                               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+                               ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+
+                               block.add_statement (new CCodeExpressionStatement (ccall));
+
+                               block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+
+                               if (array_type != null) {
+                                       // special case string array
+                                       if (!method.no_array_length) {
+                                               var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
+                                               cstrvlen.add_argument (new CCodeIdentifier ("result"));
+                                               expr.append_array_size (cstrvlen);
+                                       } else {
+                                               expr.append_array_size (new CCodeConstant ("-1"));
+                                       }
+                               }
+                       }
+               } else {
+                       block.add_statement (new CCodeExpressionStatement (ccall));
+               }
+       }
+
+       CCodeExpression get_dbus_array_type (ArrayType array_type) {
+               var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
+               carray_type.add_argument (new CCodeConstant ("\"GArray\""));
+               carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
+               return carray_type;
+       }
+}
diff --git a/gobject/valaccodedynamicsignalbinding.vala b/gobject/valaccodedynamicsignalbinding.vala
new file mode 100644 (file)
index 0000000..36919db
--- /dev/null
@@ -0,0 +1,174 @@
+/* valaccodedynamicsignalbinding.vala
+ *
+ * Copyright (C) 2007-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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * The link between a dynamic signal and generated code.
+ */
+public class Vala.CCodeDynamicSignalBinding : CCodeBinding {
+       public Signal node { get; set; }
+
+       public CCodeDynamicSignalBinding (CCodeGenerator codegen, DynamicSignal node) {
+               this.node = node;
+               this.codegen = codegen;
+       }
+
+       string? connect_wrapper_name;
+       string? disconnect_wrapper_name;
+
+       public string get_connect_wrapper_name () {
+               var dynamic_signal = (DynamicSignal) node;
+
+               if (connect_wrapper_name == null) {
+                       connect_wrapper_name = "_dynamic_%s_connect".printf (node.name);
+                       var func = new CCodeFunction (connect_wrapper_name, "void");
+                       func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
+                       func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
+                       func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
+                       func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
+                       var block = new CCodeBlock ();
+                       if (dynamic_signal.dynamic_type.data_type == codegen.dbus_object_type) {
+                               generate_dbus_connect_wrapper (block);
+                       } else {
+                               Report.error (node.source_reference, "dynamic signals are not supported for `%s'".printf (dynamic_signal.dynamic_type.to_string ()));
+                       }
+
+                       // append to C source file
+                       codegen.source_type_member_declaration.append (func.copy ());
+
+                       func.block = block;
+                       codegen.source_type_member_definition.append (func);
+               }
+
+               return connect_wrapper_name;
+       }
+
+       public string get_disconnect_wrapper_name () {
+               var dynamic_signal = (DynamicSignal) node;
+
+               if (disconnect_wrapper_name == null) {
+                       disconnect_wrapper_name = "_dynamic_%s_disconnect".printf (node.name);
+                       var func = new CCodeFunction (disconnect_wrapper_name, "void");
+                       func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
+                       func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
+                       func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
+                       func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
+                       var block = new CCodeBlock ();
+                       if (dynamic_signal.dynamic_type.data_type == codegen.dbus_object_type) {
+                               generate_dbus_disconnect_wrapper (block);
+                       } else {
+                               Report.error (node.source_reference, "dynamic signals are not supported for `%s'".printf (dynamic_signal.dynamic_type.to_string ()));
+                       }
+
+                       // append to C source file
+                       codegen.source_type_member_declaration.append (func.copy ());
+
+                       func.block = block;
+                       codegen.source_type_member_definition.append (func);
+               }
+
+               return disconnect_wrapper_name;
+       }
+
+       void generate_dbus_connect_wrapper (CCodeBlock block) {
+               var dynamic_signal = (DynamicSignal) node;
+
+               var m = (Method) dynamic_signal.handler.symbol_reference;
+
+               bool first = true;
+               foreach (FormalParameter param in m.get_parameters ()) {
+                       if (first) {
+                               // skip sender parameter
+                               first = false;
+                               continue;
+                       }
+                       node.add_parameter (param.copy ());
+               }
+
+               node.accept (codegen);
+
+               // FIXME should only be done once per marshaller
+               var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
+               register_call.add_argument (new CCodeIdentifier (codegen.get_signal_marshaller_function (node)));
+               register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
+
+               var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
+               add_call.add_argument (new CCodeIdentifier ("obj"));
+               add_call.add_argument (new CCodeConstant ("\"%s\"".printf (node.name)));
+
+               first = true;
+               foreach (FormalParameter param in m.get_parameters ()) {
+                       if (first) {
+                               // skip sender parameter
+                               first = false;
+                               continue;
+                       }
+                       if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type != codegen.string_type.data_type) {
+                               var array_type = (ArrayType) param.type_reference;
+                               if (array_type.element_type.data_type.get_type_id () == null) {
+                                       Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
+                                       return;
+                               }
+
+                               var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
+                               carray_type.add_argument (new CCodeConstant ("\"GArray\""));
+                               carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
+                               register_call.add_argument (carray_type);
+                               add_call.add_argument (carray_type);
+                       } else {
+                               if (param.type_reference.get_type_id () == null) {
+                                       Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
+                                       return;
+                               }
+
+                               register_call.add_argument (new CCodeIdentifier (param.type_reference.get_type_id ()));
+                               add_call.add_argument (new CCodeIdentifier (param.type_reference.get_type_id ()));
+                       }
+               }
+               register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+               add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+
+               block.add_statement (new CCodeExpressionStatement (register_call));
+               block.add_statement (new CCodeExpressionStatement (add_call));
+
+               var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_connect_signal"));
+               call.add_argument (new CCodeIdentifier ("obj"));
+               call.add_argument (new CCodeIdentifier ("signal_name"));
+               call.add_argument (new CCodeIdentifier ("handler"));
+               call.add_argument (new CCodeIdentifier ("data"));
+               call.add_argument (new CCodeConstant ("NULL"));
+               block.add_statement (new CCodeExpressionStatement (call));
+       }
+
+       void generate_dbus_disconnect_wrapper (CCodeBlock block) {
+               var dynamic_signal = (DynamicSignal) node;
+
+               var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_disconnect_signal"));
+               call.add_argument (new CCodeIdentifier ("obj"));
+               call.add_argument (new CCodeIdentifier ("signal_name"));
+               call.add_argument (new CCodeIdentifier ("handler"));
+               call.add_argument (new CCodeIdentifier ("data"));
+               block.add_statement (new CCodeExpressionStatement (call));
+       }
+}
index f24adc0..eca37eb 100644 (file)
@@ -113,7 +113,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        public Interface iterator_type;
        public Interface list_type;
        public Interface map_type;
-       public Typesymbol connection_type;
+       public Typesymbol dbus_object_type;
 
        public Method substring_method;
 
@@ -257,7 +257,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
 
                var dbus_ns = root_symbol.scope.lookup ("DBus");
                if (dbus_ns != null) {
-                       connection_type = (Typesymbol) dbus_ns.scope.lookup ("Connection");
+                       dbus_object_type = (Typesymbol) dbus_ns.scope.lookup ("Object");
                }
        
                /* we're only interested in non-pkg source files */
@@ -3624,7 +3624,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        public CCodeStatement? create_type_check_statement (CodeNode method_node, DataType ret_type, Typesymbol t, bool non_null, string var_name) {
                var ccheck = new CCodeFunctionCall ();
                
-               if ((t is Class && ((Class) t).is_subtype_of (gobject_type)) || (t is Interface && !((Interface) t).declaration_only)) {
+               if ((t is Class && ((Class) t).is_subtype_of (gobject_type)) || t is Interface) {
                        var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_")));
                        ctype_check.add_argument (new CCodeIdentifier (var_name));
                        
@@ -3723,6 +3723,10 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return new CCodeMethodBinding (this, node);
        }
 
+       public override CodeBinding? create_dynamic_method_binding (DynamicMethod node) {
+               return new CCodeDynamicMethodBinding (this, node);
+       }
+
        public override CodeBinding? create_creation_method_binding (CreationMethod node) {
                return new CCodeCreationMethodBinding (this, node);
        }
@@ -3743,6 +3747,10 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return null;
        }
 
+       public override CodeBinding? create_dynamic_signal_binding (DynamicSignal node) {
+               return new CCodeDynamicSignalBinding (this, node);
+       }
+
        public override CodeBinding? create_constructor_binding (Constructor node) {
                return null;
        }
@@ -3955,6 +3963,14 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return (CCodeMethodBinding) node.get_code_binding (this);
        }
 
+       public CCodeDynamicMethodBinding dynamic_method_binding (DynamicMethod node) {
+               return (CCodeDynamicMethodBinding) node.get_code_binding (this);
+       }
+
+       public CCodeDynamicSignalBinding dynamic_signal_binding (DynamicSignal node) {
+               return (CCodeDynamicSignalBinding) node.get_code_binding (this);
+       }
+
        public CCodeArrayCreationExpressionBinding array_creation_expression_binding (ArrayCreationExpression node) {
                return (CCodeArrayCreationExpressionBinding) node.get_code_binding (this);
        }
index 7d64f88..de7f9bc 100644 (file)
@@ -251,7 +251,7 @@ public class Vala.CCodeGenerator {
                                                }
                                        } else if (node is Interface) {
                                                var iface = (Interface) node;
-                                               if (!iface.is_static && !iface.declaration_only) {
+                                               if (!iface.is_static) {
                                                        header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
                                                        header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
                                                }
index bde841e..949bc9b 100644 (file)
@@ -51,7 +51,7 @@ public class Vala.CCodeInterfaceBinding : CCodeTypesymbolBinding {
                        def_frag = codegen.source_type_definition;
                }
 
-               if (!iface.is_static && !iface.declaration_only) {
+               if (!iface.is_static) {
                        codegen.type_struct = new CCodeStruct ("_%s".printf (iface.get_type_cname ()));
                        
                        decl_frag.append (new CCodeNewline ());
@@ -84,7 +84,7 @@ public class Vala.CCodeInterfaceBinding : CCodeTypesymbolBinding {
 
                iface.accept_children (codegen);
 
-               if (!iface.is_static && !iface.declaration_only) {
+               if (!iface.is_static) {
                        add_interface_base_init_function (iface);
 
                        var type_fun = new InterfaceRegisterFunction (iface);
index c7a00fd..8da52f3 100644 (file)
@@ -122,111 +122,31 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                        var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
                        csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
                        carg_map.set (codegen.get_param_pos (0.1), csizeof);
-               } else if (m is DBusMethod) {
-                       bool found_out = false;
-                       Expression callback = null;
+               } else if (m is DynamicMethod) {
+                       m.clear_parameters ();
+                       int param_nr = 1;
                        foreach (Expression arg in expr.get_argument_list ()) {
-                               if (arg.symbol_reference is Method) {
-                                       // callback
-                                       if (callback != null) {
-                                               Report.error (expr.source_reference, "only one reply callback may be specified in invocation of DBus method");
-                                               expr.error = true;
-                                               return;
-                                       } else if (found_out) {
-                                               Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
-                                               expr.error = true;
-                                               return;
-                                       }
-                                       callback = arg;
-                               } else if (arg is UnaryExpression && ((UnaryExpression) arg).operator == UnaryOperator.OUT) {
-                                       // out arg
-                                       if (callback != null) {
-                                               Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
-                                               expr.error = true;
-                                               return;
-                                       }
-                                       found_out = true;
+                               var unary = arg as UnaryExpression;
+                               if (unary != null && unary.operator == UnaryOperator.OUT) {
+                                       // out argument
+                                       var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.static_type);
+                                       param.direction = ParameterDirection.OUT;
+                                       m.add_parameter (param);
+                               } else if (unary != null && unary.operator == UnaryOperator.REF) {
+                                       // ref argument
+                                       var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.static_type);
+                                       param.direction = ParameterDirection.REF;
+                                       m.add_parameter (param);
                                } else {
-                                       // in arg
-                                       if (callback != null || found_out) {
-                                               Report.error (expr.source_reference, "in argument must not follow out argument or reply callback in invocation of DBus method");
-                                               expr.error = true;
-                                               return;
-                                       }
+                                       // in argument
+                                       m.add_parameter (new FormalParameter ("param%d".printf (param_nr), arg.static_type));
                                }
+                               param_nr++;
                        }
-
-                       carg_map.set (codegen.get_param_pos (0.1), new CCodeConstant ("\"%s\"".printf (m.name)));
-
-                       if (callback != null) {
-                               var reply_method = (Method) callback.symbol_reference;
-
-                               var cb_fun = new CCodeFunction ("_%s_cb".printf (reply_method.get_cname ()), "void");
-                               cb_fun.modifiers = CCodeModifiers.STATIC;
-                               cb_fun.add_parameter (new CCodeFormalParameter ("proxy", "DBusGProxy*"));
-                               cb_fun.add_parameter (new CCodeFormalParameter ("call", "DBusGProxyCall*"));
-                               cb_fun.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
-                               cb_fun.block = new CCodeBlock ();
-                               var cerrdecl = new CCodeDeclaration ("GError*");
-                               cerrdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("error", new CCodeConstant ("NULL")));
-                               cb_fun.block.add_statement (cerrdecl);
-                               var cend_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_end_call"));
-                               cend_call.add_argument (new CCodeIdentifier ("proxy"));
-                               cend_call.add_argument (new CCodeIdentifier ("call"));
-                               cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
-                               var creply_call = new CCodeFunctionCall ((CCodeExpression) callback.ccodenode);
-                               creply_call.add_argument (new CCodeIdentifier ("user_data"));
-                               int param_count = reply_method.get_parameters ().size;
-                               int i = 0;
-                               foreach (FormalParameter param in reply_method.get_parameters ()) {
-                                       if ((++i) == param_count) {
-                                               // error parameter
-                                               break;
-                                       }
-                                       if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type != codegen.string_type.data_type) {
-                                               var array_type = (ArrayType) param.type_reference;
-                                               var cdecl = new CCodeDeclaration ("GArray*");
-                                               cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-                                               cb_fun.block.add_statement (cdecl);
-                                               cend_call.add_argument (get_dbus_array_type (array_type));
-                                               cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-                                               creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "data"));
-                                               creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "len"));
-                                       } else {
-                                               var cdecl = new CCodeDeclaration (param.type_reference.get_cname ());
-                                               cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
-                                               cb_fun.block.add_statement (cdecl);
-                                               if (param.type_reference is ArrayType && ((ArrayType) param.type_reference).element_type.data_type == codegen.string_type.data_type) {
-                                                       // special case string array
-                                                       cend_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
-                                                       var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
-                                                       cstrvlen.add_argument (new CCodeIdentifier (param.name));
-                                                       creply_call.add_argument (cstrvlen);
-                                               } else {
-                                                       cend_call.add_argument (new CCodeIdentifier (param.type_reference.data_type.get_type_id ()));
-                                               }
-                                               cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
-                                               creply_call.add_argument (new CCodeIdentifier (param.name));
-                                       }
-                               }
-                               cend_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
-                               cb_fun.block.add_statement (new CCodeExpressionStatement (cend_call));
-                               creply_call.add_argument (new CCodeIdentifier ("error"));
-                               cb_fun.block.add_statement (new CCodeExpressionStatement (creply_call));
-                               codegen.source_type_member_definition.append (cb_fun);
-
-                               carg_map.set (codegen.get_param_pos (0.2), new CCodeIdentifier (cb_fun.name));
-                               carg_map.set (codegen.get_param_pos (0.3), new CCodeConstant ("self"));
-                               carg_map.set (codegen.get_param_pos (0.4), new CCodeConstant ("NULL"));
-                       } else if (found_out || !(m.return_type is VoidType)) {
-                               ccall.call = new CCodeIdentifier ("dbus_g_proxy_call");
-
-                               // method can fail
-                               codegen.current_method_inner_error = true;
-                               carg_map.set (codegen.get_param_pos (0.2), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("inner_error")));
-                       } else {
-                               ccall.call = new CCodeIdentifier ("dbus_g_proxy_call_no_reply");
+                       foreach (FormalParameter param in m.get_parameters ()) {
+                               param.accept (codegen);
                        }
+                       codegen.dynamic_method_binding ((DynamicMethod) m).generate_wrapper ();
                }
 
                bool ellipsis = false;
@@ -235,15 +155,6 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                int arg_pos;
                Iterator<FormalParameter> params_it = params.iterator ();
                foreach (Expression arg in expr.get_argument_list ()) {
-                       if (m is DBusMethod) {
-                               if (arg.symbol_reference is Method) {
-                                       // callback parameter
-                                       break;
-                               }
-                               
-                               carg_map.set (codegen.get_param_pos (i - 0.1, true), new CCodeIdentifier (arg.static_type.data_type.get_type_id ()));
-                       }
-
                        CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
                        Gee.List<CCodeExpression> extra_args = new ArrayList<CCodeExpression> ();
                        if (params_it.next ()) {
@@ -270,6 +181,9 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                                                        carg_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), codegen.get_delegate_target_cexpression (arg));
                                                        multiple_cargs = true;
                                                }
+                                       } else if (param.type_reference is MethodType) {
+                                               carg_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), codegen.get_delegate_target_cexpression (arg));
+                                               multiple_cargs = true;
                                        }
                                        cexpr = codegen.get_implicit_cast_expression (cexpr, arg.static_type, param.type_reference);
 
@@ -389,7 +303,7 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                }
 
                /* add length argument for methods returning arrays */
-               if (m != null && m.return_type is ArrayType && !(m is DBusMethod)) {
+               if (m != null && m.return_type is ArrayType) {
                        var array_type = (ArrayType) m.return_type;
                        for (int dim = 1; dim <= array_type.rank; dim++) {
                                if (!m.no_array_length) {
@@ -420,15 +334,7 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                        }
                }
 
-               if (codegen.connection_type != null && ma.inner != null && ma.inner.static_type != null && ma.inner.static_type.data_type == codegen.connection_type && m.name == "get_object") {
-                       var dbus_iface = (Interface) m.return_type.data_type;
-                       var dbus_attr = dbus_iface.get_attribute ("DBusInterface");
-                       carg_map.set (codegen.get_param_pos (-1), new CCodeConstant ("\"%s\"".printf (dbus_attr.get_string ("name"))));
-               } else if (m is DBusMethod) {
-                       carg_map.set (codegen.get_param_pos (-1, true), new CCodeIdentifier ("G_TYPE_INVALID"));
-               }
-
-               if (expr.can_fail && !(m is DBusMethod)) {
+               if (expr.can_fail) {
                        // method can fail
                        codegen.current_method_inner_error = true;
                        // add &inner_error before the ellipsis arguments
@@ -438,7 +344,7 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                if (ellipsis) {
                        /* ensure variable argument list ends with NULL
                         * except when using printf-style arguments */
-                       if ((m == null || !m.printf_format) && !(m is DBusMethod)) {
+                       if ((m == null || !m.printf_format)) {
                                carg_map.set (codegen.get_param_pos (-1, true), new CCodeConstant (m.sentinel));
                        }
                } else if (itype is DelegateType) {
@@ -540,72 +446,7 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
                        ccomma.append_expression (cndupcall);
 
                        expr.ccodenode = ccomma;
-               } else if (m is DBusMethod && !(m.return_type is VoidType)) {
-                       // synchronous D-Bus method call with reply
-                       if (m.return_type is ArrayType && ((ArrayType) m.return_type).element_type.data_type != codegen.string_type.data_type) {
-                               // non-string arrays (use GArray)
-                               var array_type = (ArrayType) m.return_type;
-
-                               ccall.add_argument (get_dbus_array_type (array_type));
-
-                               var garray_type_reference = codegen.get_data_type_for_symbol (codegen.garray_type);
-                               var temp_decl = codegen.get_temp_variable (garray_type_reference);
-                               codegen.temp_vars.insert (0, temp_decl);
-                               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
-
-                               ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
-
-                               var ccomma = new CCodeCommaExpression ();
-                               ccomma.append_expression (ccall);
-                               ccomma.append_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier (temp_decl.name), "data"));
-                               expr.ccodenode = ccomma;
-
-                               if (!m.no_array_length) {
-                                       expr.append_array_size (new CCodeMemberAccess.pointer (new CCodeIdentifier (temp_decl.name), "len"));
-                               } else {
-                                       expr.append_array_size (new CCodeConstant ("-1"));
-                               }
-                       } else if (m.return_type is ArrayType || m.return_type.data_type != null) {
-                               // string arrays or other datatypes
-
-                               if (m.return_type is ArrayType) {
-                                       // string arrays
-                                       ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
-                               } else {
-                                       // other types
-                                       ccall.add_argument (new CCodeIdentifier (m.return_type.data_type.get_type_id ()));
-                               }
-
-                               var temp_decl = codegen.get_temp_variable (m.return_type);
-                               codegen.temp_vars.insert (0, temp_decl);
-                               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
-
-                               ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
-
-                               var ccomma = new CCodeCommaExpression ();
-                               ccomma.append_expression (ccall);
-                               ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
-                               expr.ccodenode = ccomma;
-
-                               if (m.return_type is ArrayType && ((ArrayType) m.return_type).element_type.data_type == codegen.string_type.data_type) {
-                                       // special case string array
-                                       if (!m.no_array_length) {
-                                               var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
-                                               cstrvlen.add_argument (new CCodeIdentifier (temp_decl.name));
-                                               expr.append_array_size (cstrvlen);
-                                       } else {
-                                               expr.append_array_size (new CCodeConstant ("-1"));
-                                       }
-                               }
-                       }
                }
        }
-
-       private CCodeExpression get_dbus_array_type (ArrayType array_type) {
-               var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
-               carray_type.add_argument (new CCodeConstant ("\"GArray\""));
-               carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
-               return carray_type;
-       }
 }
 
index 1c6c46b..9bef115 100644 (file)
@@ -188,76 +188,7 @@ public class Vala.CCodeMethodBinding : CCodeBinding {
                        }
                }
 
-               var params = m.get_parameters ();
-               foreach (FormalParameter param in params) {
-                       if (!param.no_array_length && param.type_reference is ArrayType) {
-                               var array_type = (ArrayType) param.type_reference;
-                               
-                               var length_ctype = "int";
-                               if (param.direction != ParameterDirection.IN) {
-                                       length_ctype = "int*";
-                               }
-                               
-                               for (int dim = 1; dim <= array_type.rank; dim++) {
-                                       var cparam = new CCodeFormalParameter (codegen.get_array_length_cname (param.name, dim), length_ctype);
-                                       cparam_map.set (codegen.get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
-                               }
-                       }
-
-                       cparam_map.set (codegen.get_param_pos (param.cparameter_position), (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 (codegen.get_delegate_target_cname (param.name), "void*");
-                                       cparam_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), cparam);
-                               }
-                       }
-               }
-
-               if (!m.no_array_length && creturn_type is ArrayType) {
-                       // return array length if appropriate
-                       var array_type = (ArrayType) creturn_type;
-
-                       for (int dim = 1; dim <= array_type.rank; dim++) {
-                               var cparam = new CCodeFormalParameter (codegen.get_array_length_cname ("result", dim), "int*");
-                               cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), 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 (codegen.get_delegate_target_cname ("result"), "void*");
-                               cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
-                       }
-               }
-
-               if (m.get_error_domains ().size > 0) {
-                       var cparam = new CCodeFormalParameter ("error", "GError**");
-                       cparam_map.set (codegen.get_param_pos (-1), cparam);
-               }
-
-               // append C parameters in the right order
-               int last_pos = -1;
-               int min_pos;
-               while (true) {
-                       min_pos = -1;
-                       foreach (int pos in cparam_map.get_keys ()) {
-                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
-                                       min_pos = pos;
-                               }
-                       }
-                       if (min_pos == -1) {
-                               break;
-                       }
-                       codegen.function.add_parameter (cparam_map.get (min_pos));
-                       if (vdeclarator != null) {
-                               vdeclarator.add_parameter (cparam_map.get (min_pos));
-                       }
-                       last_pos = min_pos;
-               }
+               generate_cparameters (m, creturn_type, cparam_map, codegen.function, vdeclarator);
 
                bool visible = !m.is_internal_symbol ();
 
@@ -649,6 +580,81 @@ public class Vala.CCodeMethodBinding : CCodeBinding {
                }
        }
 
+       public void generate_cparameters (Method m, DataType creturn_type, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null) {
+               foreach (FormalParameter param in m.get_parameters ()) {
+                       if (!param.no_array_length && param.type_reference is ArrayType) {
+                               var array_type = (ArrayType) param.type_reference;
+                               
+                               var length_ctype = "int";
+                               if (param.direction != ParameterDirection.IN) {
+                                       length_ctype = "int*";
+                               }
+                               
+                               for (int dim = 1; dim <= array_type.rank; dim++) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_array_length_cname (param.name, dim), length_ctype);
+                                       cparam_map.set (codegen.get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
+                               }
+                       }
+
+                       cparam_map.set (codegen.get_param_pos (param.cparameter_position), (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 (codegen.get_delegate_target_cname (param.name), "void*");
+                                       cparam_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), cparam);
+                               }
+                       } else if (param.type_reference is MethodType) {
+                               var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname (param.name), "void*");
+                               cparam_map.set (codegen.get_param_pos (param.cdelegate_target_parameter_position), cparam);
+                       }
+               }
+
+               if (!m.no_array_length && creturn_type is ArrayType) {
+                       // return array length if appropriate
+                       var array_type = (ArrayType) creturn_type;
+
+                       for (int dim = 1; dim <= array_type.rank; dim++) {
+                               var cparam = new CCodeFormalParameter (codegen.get_array_length_cname ("result", dim), "int*");
+                               cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), 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 (codegen.get_delegate_target_cname ("result"), "void*");
+                               cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
+                       }
+               }
+
+               if (m.get_error_domains ().size > 0) {
+                       var cparam = new CCodeFormalParameter ("error", "GError**");
+                       cparam_map.set (codegen.get_param_pos (-1), cparam);
+               }
+
+               // append C parameters in the right order
+               int last_pos = -1;
+               int min_pos;
+               while (true) {
+                       min_pos = -1;
+                       foreach (int pos in cparam_map.get_keys ()) {
+                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+                                       min_pos = pos;
+                               }
+                       }
+                       if (min_pos == -1) {
+                               break;
+                       }
+                       func.add_parameter (cparam_map.get (min_pos));
+                       if (vdeclarator != null) {
+                               vdeclarator.add_parameter (cparam_map.get (min_pos));
+                       }
+                       last_pos = min_pos;
+               }
+       }
+
        private CCodeStatement create_method_type_check_statement (Method m, DataType return_type, Typesymbol t, bool non_null, string var_name) {
                return codegen.create_type_check_statement (m, return_type, t, non_null, var_name);
        }
diff --git a/gobject/valadbusbindingprovider.vala b/gobject/valadbusbindingprovider.vala
deleted file mode 100644 (file)
index 2edf0aa..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* valadbusbindingprovider.vala
- *
- * Copyright (C) 2007-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
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- *
- * Author:
- *     Jürg Billeter <j@bitron.ch>
- */
-
-using GLib;
-using Gee;
-
-/**
- * Dynamic binding provider for DBus objects.
- */
-public class Vala.DBusBindingProvider : Object, BindingProvider {
-       public CodeContext context {
-               set {
-                       _context = value;
-
-                       string_type = (Class) _context.root.scope.lookup ("string");
-
-                       var dbus_ns = _context.root.scope.lookup ("DBus");
-                       if (dbus_ns != null) {
-                               connection_type = (Typesymbol) dbus_ns.scope.lookup ("Connection");
-                               dbus_error_type = (Typesymbol) dbus_ns.scope.lookup ("Error");
-                       }
-               }
-       }
-
-       private CodeContext _context;
-       private Class string_type;
-       private Typesymbol connection_type;
-       private Typesymbol dbus_error_type;
-
-       private Collection<Symbol> symbols = new ArrayList<Symbol> ();
-
-       public DBusBindingProvider () {
-       }
-
-       public Symbol? get_binding (MemberAccess ma) {
-               if (connection_type != null && ma.inner != null && ma.inner.static_type != null && ma.inner.static_type.data_type == connection_type) {
-                       var type_args = ma.get_type_arguments ();
-                       if (type_args.size != 1) {
-                               return null;
-                       }
-                       Iterator<DataType> type_args_it = type_args.iterator ();
-                       type_args_it.next ();
-                       var ret_type = type_args_it.get ().copy ();
-                       if (!is_dbus_interface (ret_type)) {
-                               return null;
-                       }
-                       var m = new Method ("get_object", ret_type, ma.source_reference);
-                       m.set_cname ("dbus_g_proxy_new_for_name");
-                       m.add_cheader_filename ("dbus/dbus-glib.h");
-                       m.access = SymbolAccessibility.PUBLIC;
-                       var string_type_ref = new ClassType (string_type);
-                       m.add_parameter (new FormalParameter ("name", string_type_ref));
-                       m.add_parameter (new FormalParameter ("path", string_type_ref));
-                       symbols.add (m);
-                       return m;
-               } else if (ma.inner != null && ma.inner.static_type != null && is_dbus_interface (ma.inner.static_type)) {
-                       if (ma.parent_node is InvocationExpression) {
-                               var expr = (InvocationExpression) ma.parent_node;
-                               DataType ret_type;
-                               if (expr.expected_type != null) {
-                                       ret_type = expr.expected_type.copy ();
-                                       ret_type.transfers_ownership = ret_type.is_reference_type_or_type_parameter ();
-                               } else {
-                                       ret_type = new VoidType ();
-                               }
-                               var m = new DBusMethod (ma.member_name, ret_type, ma.source_reference);
-                               if (expr.expected_type != null) {
-                                       var error_type = CCodeGenerator.get_data_type_for_symbol (dbus_error_type);
-                                       m.add_error_domain (error_type);
-                               }
-                               m.access = SymbolAccessibility.PUBLIC;
-                               m.add_parameter (new FormalParameter.with_ellipsis ());
-                               symbols.add (m);
-                               return m;
-                       } else if (ma.parent_node is Assignment) {
-                               var a = (Assignment) ma.parent_node;
-                               if (a.left != ma) {
-                                       return null;
-                               }
-                               var s = new DBusSignal (ma.member_name, new VoidType (), ma.source_reference);
-                               s.access = SymbolAccessibility.PUBLIC;
-                               symbols.add (s);
-                               return s;
-                       }
-               }
-               return null;
-       }
-
-       private bool is_dbus_interface (DataType t) {
-               if (!(t.data_type is Interface)) {
-                       return false;
-               }
-               return (t.data_type.get_attribute ("DBusInterface") != null);
-       }
-}
-
diff --git a/gobject/valadbussignal.vala b/gobject/valadbussignal.vala
deleted file mode 100644 (file)
index 7fdb546..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* valadbussignal.vala
- *
- * Copyright (C) 2007  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
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- *
- * Author:
- *     Jürg Billeter <j@bitron.ch>
- */
-
-using GLib;
-
-/**
- * Represents a dynamic bound DBus signal.
- */
-public class Vala.DBusSignal : Signal {
-       public DBusSignal (string name, DataType return_type, SourceReference? source_reference = null) {
-               this.return_type = return_type;
-               this.source_reference = source_reference;
-               this.name = name;
-       }
-}
index bcdc947..c951a22 100644 (file)
@@ -26,7 +26,6 @@ libvalacore_la_VALASOURCES = \
        valabaseaccess.vala \
        valabasicblock.vala \
        valabinaryexpression.vala \
-       valabindingprovider.vala \
        valablock.vala \
        valabooleanliteral.vala \
        valabreakstatement.vala \
@@ -53,6 +52,8 @@ libvalacore_la_VALASOURCES = \
        valadeletestatement.vala \
        valadestructor.vala \
        valadostatement.vala \
+       valadynamicmethod.vala \
+       valadynamicsignal.vala \
        valaelementaccess.vala \
        valaemptystatement.vala \
        valaenum.vala \
diff --git a/vala/valabindingprovider.vala b/vala/valabindingprovider.vala
deleted file mode 100644 (file)
index ea12a9f..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* valabindingprovider.vala
- *
- * Copyright (C) 2007-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
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- *
- * Author:
- *     Jürg Billeter <j@bitron.ch>
- */
-
-using GLib;
-
-/**
- * Interface for dynamic binding providers.
- */
-public interface Vala.BindingProvider : Object {
-       /**
-        * Return custom binding for the specified member access expression.
-        *
-        * @param ma member access expression
-        * @return   resolved symbol or null if no binding can be provided
-        */
-       public abstract Symbol? get_binding (MemberAccess ma);
-}
-
index 506630c..0bd7159 100644 (file)
@@ -42,6 +42,7 @@ public class Vala.ClassType : ReferenceType {
                result.transfers_ownership = transfers_ownership;
                result.takes_ownership = takes_ownership;
                result.nullable = nullable;
+               result.is_dynamic = is_dynamic;
                result.floating_reference = floating_reference;
                
                foreach (DataType arg in get_type_arguments ()) {
index e884aaa..953faed 100644 (file)
@@ -128,6 +128,8 @@ public class Vala.CodeContext : Object {
 
        private Gee.List<string> defines = new ArrayList<string> (str_equal);
 
+       private Gee.List<Symbol> dynamic_members = new ArrayList<Symbol> ();
+
        /**
         * The root namespace of the symbol tree.
         *
@@ -408,4 +410,8 @@ public class Vala.CodeContext : Object {
 
                return null;
        }
+
+       public void add_dynamic_member (Symbol dynamic_member) {
+               dynamic_members.add (dynamic_member);
+       }
 }
index 85467fc..3367e83 100644 (file)
@@ -82,6 +82,10 @@ public class Vala.CodeGenerator : CodeVisitor {
                return null;
        }
 
+       public virtual CodeBinding? create_dynamic_method_binding (DynamicMethod node) {
+               return null;
+       }
+
        public virtual CodeBinding? create_creation_method_binding (CreationMethod node) {
                return null;
        }
@@ -102,6 +106,10 @@ public class Vala.CodeGenerator : CodeVisitor {
                return null;
        }
 
+       public virtual CodeBinding? create_dynamic_signal_binding (DynamicSignal node) {
+               return null;
+       }
+
        public virtual CodeBinding? create_constructor_binding (Constructor node) {
                return null;
        }
index e3b1208..90c78d2 100644 (file)
@@ -60,6 +60,11 @@ public abstract class Vala.DataType : CodeNode {
         */
        public bool floating_reference { get; set; }
 
+       /**
+        * Specifies that the type supports dynamic lookup.
+        */
+       public bool is_dynamic { get; set; }
+
        private Gee.List<DataType> type_argument_list = new ArrayList<DataType> ();
 
        /**
diff --git a/vala/valadynamicmethod.vala b/vala/valadynamicmethod.vala
new file mode 100644 (file)
index 0000000..d63146c
--- /dev/null
@@ -0,0 +1,59 @@
+/* valadynamicmethod.vala
+ *
+ * Copyright (C) 2007-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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Represents a late bound method.
+ */
+public class Vala.DynamicMethod : Method {
+       public DataType dynamic_type { get; set; }
+
+       public InvocationExpression invocation { get; set; }
+
+       private string cname;
+
+       public DynamicMethod (DataType dynamic_type, string name, DataType return_type, SourceReference? source_reference = null) {
+               this.dynamic_type = dynamic_type;
+               this.name = name;
+               this.return_type = return_type;
+               this.source_reference = source_reference;
+       }
+
+       public override Collection<string> get_cheader_filenames () {
+               return new ReadOnlyCollection<string> ();
+       }
+
+       public override string get_default_cname () {
+               // return cname of wrapper method
+               if (cname == null) {
+                       // FIXME support multiple dynamic methods with the same name
+                       cname = "_dynamic_%s".printf (name);
+               }
+               return cname;
+       }
+
+       public override CodeBinding? create_code_binding (CodeGenerator codegen) {
+               return codegen.create_dynamic_method_binding (this);
+       }
+}
similarity index 63%
rename from gobject/valadbusmethod.vala
rename to vala/valadynamicsignal.vala
index 57a3305..459ddb3 100644 (file)
@@ -1,6 +1,6 @@
-/* valadbusmethod.vala
+/* valadynamicsignal.vala
  *
- * Copyright (C) 2007  Jürg Billeter
+ * Copyright (C) 2007-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
  */
 
 using GLib;
-using Gee;
 
 /**
- * Represents a dynamic bound DBus method.
+ * Represents a late bound signal.
  */
-public class Vala.DBusMethod : Method {
-       public DBusMethod (string name, DataType return_type, SourceReference? source_reference = null) {
+public class Vala.DynamicSignal : Signal {
+       public DataType dynamic_type { get; set; }
+
+       public Expression handler { get; set; }
+
+       public DynamicSignal (DataType dynamic_type, string name, DataType return_type, SourceReference? source_reference = null) {
+               this.dynamic_type = dynamic_type;
+               this.name = name;
                this.return_type = return_type;
                this.source_reference = source_reference;
-               this.name = name;
-       }
-
-       public override Collection<string> get_cheader_filenames () {
-               return new ReadOnlyCollection<string> ();
        }
 
-       public override string get_default_cname () {
-               return "dbus_g_proxy_begin_call";
+       public override CodeBinding? create_code_binding (CodeGenerator codegen) {
+               return codegen.create_dynamic_signal_binding (this);
        }
 }
index 7c1b3ed..fa09b04 100644 (file)
@@ -33,8 +33,6 @@ public class Vala.Interface : Typesymbol {
         */
        public bool is_static { get; set; }
 
-       public bool declaration_only { get; set; }
-
        private Gee.List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
        
        private Gee.List<DataType> prerequisites = new ArrayList<DataType> ();
@@ -407,12 +405,6 @@ public class Vala.Interface : Typesymbol {
                }
        }
 
-       private void process_dbus_interface_attribute (Attribute a) {
-               if (declaration_only) {
-                       cname = "DBusGProxy";
-               }
-       }
-
        /**
         * Process all associated attributes.
         */
@@ -420,8 +412,6 @@ public class Vala.Interface : Typesymbol {
                foreach (Attribute a in attributes) {
                        if (a.name == "CCode") {
                                process_ccode_attribute (a);
-                       } else if (a.name == "DBusInterface") {
-                               process_dbus_interface_attribute (a);
                        }
                }
        }
index 3d202f2..bc389a9 100644 (file)
@@ -42,6 +42,7 @@ public class Vala.InterfaceType : ReferenceType {
                result.transfers_ownership = transfers_ownership;
                result.takes_ownership = takes_ownership;
                result.nullable = nullable;
+               result.is_dynamic = is_dynamic;
                result.floating_reference = floating_reference;
                
                foreach (DataType arg in get_type_arguments ()) {
index 10cd38d..cf3fa03 100644 (file)
@@ -246,6 +246,18 @@ public class Vala.Method : Member {
                return new ReadOnlyCollection<FormalParameter> (parameters);
        }
 
+       /**
+        * Remove all parameters from this method.
+        */
+       public void clear_parameters () {
+               foreach (FormalParameter param in parameters) {
+                       if (!param.ellipsis) {
+                               scope.remove (param.name);
+                       }
+               }
+               parameters.clear ();
+       }
+
        public override void accept (CodeVisitor visitor) {
                visitor.visit_method (this);
        }
index 09f6bf8..0b5d68e 100644 (file)
@@ -62,4 +62,8 @@ public class Vala.MethodType : DataType {
        public override string to_string () {
                return method_symbol.get_full_name ();
        }
+
+       public override string? get_cname (bool var_type, bool const_type) {
+               return "gpointer";
+       }
 }
index f17363f..fc59158 100644 (file)
@@ -183,6 +183,7 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.DELEGATE:
                case TokenType.DELETE:
                case TokenType.DO:
+               case TokenType.DYNAMIC:
                case TokenType.ELSE:
                case TokenType.ENUM:
                case TokenType.ENSURES:
@@ -312,8 +313,7 @@ public class Vala.Parser : CodeVisitor {
                        }
                        return;
                }
-               accept (TokenType.REF);
-               accept (TokenType.OUT);
+               accept (TokenType.DYNAMIC);
                accept (TokenType.WEAK);
                skip_symbol_name ();
                skip_type_argument_list ();
@@ -343,6 +343,8 @@ public class Vala.Parser : CodeVisitor {
                        return type;
                }
 
+               bool is_dynamic = accept (TokenType.DYNAMIC);
+
                bool is_weak = accept (TokenType.WEAK);
 
                var sym = parse_symbol_name ();
@@ -383,6 +385,7 @@ public class Vala.Parser : CodeVisitor {
                                type.add_type_argument (type_arg);
                        }
                }
+               type.is_dynamic = is_dynamic;
                type.is_weak = is_weak;
                type.pointer_level = stars;
                type.array_rank = array_rank;
@@ -737,6 +740,7 @@ public class Vala.Parser : CodeVisitor {
                        next ();
                        switch (current ()) {
                        case TokenType.VOID:
+                       case TokenType.DYNAMIC:
                        case TokenType.WEAK:
                        case TokenType.IDENTIFIER:
                                var type = parse_type ();
@@ -2319,12 +2323,7 @@ public class Vala.Parser : CodeVisitor {
                        iface.add_prerequisite (base_type);
                }
 
-               if (accept (TokenType.SEMICOLON)) {
-                       iface.external = true;
-                       iface.declaration_only = true;
-               } else {
-                       parse_declarations (iface);
-               }
+               parse_declarations (iface);
 
                Symbol result = iface;
                while (sym.inner != null) {
@@ -2708,6 +2707,7 @@ public class Vala.Parser : CodeVisitor {
                        do {
                                switch (current ()) {
                                case TokenType.VOID:
+                               case TokenType.DYNAMIC:
                                case TokenType.WEAK:
                                case TokenType.IDENTIFIER:
                                        var type = parse_type ();
index 62017b7..e946406 100644 (file)
@@ -239,7 +239,14 @@ public class Vala.Scanner : Object {
                case 7:
                        switch (begin[0]) {
                        case 'd':
-                               if (matches (begin, "default")) return TokenType.DEFAULT;
+                               switch (begin[1]) {
+                               case 'e':
+                                       if (matches (begin, "default")) return TokenType.DEFAULT;
+                                       break;
+                               case 'y':
+                                       if (matches (begin, "dynamic")) return TokenType.DYNAMIC;
+                                       break;
+                               }
                                break;
                        case 'e':
                                if (matches (begin, "ensures")) return TokenType.ENSURES;
index 9ed5263..790048b 100644 (file)
@@ -59,15 +59,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
        private int next_lambda_id = 0;
 
-       private Collection<BindingProvider> binding_providers = new ArrayList<BindingProvider> ();
-
        public SemanticAnalyzer () {
        }
 
-       public void add_binding_provider (BindingProvider binding_provider) {
-               binding_providers.add (binding_provider);
-       }
-
        /**
         * Analyze and check code in the specified context.
         *
@@ -1586,31 +1580,55 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                // check for named struct creation method
                                expr.symbol_reference = base_symbol.scope.lookup (".new." + expr.member_name);
                        }
-               }
 
-               if (expr.symbol_reference == null) {
-                       /* allow plug-ins to provide custom member bindings */
-                       foreach (BindingProvider binding_provider in binding_providers) {
-                               expr.symbol_reference = binding_provider.get_binding (expr);
+                       if (expr.symbol_reference == null && expr.inner.static_type != null && expr.inner.static_type.is_dynamic) {
+                               // allow late bound members for dynamic types
+                               if (expr.parent_node is InvocationExpression) {
+                                       var invoc = (InvocationExpression) expr.parent_node;
+                                       DataType ret_type;
+                                       if (invoc.expected_type != null) {
+                                               ret_type = invoc.expected_type.copy ();
+                                               ret_type.transfers_ownership = ret_type.is_reference_type_or_type_parameter ();
+                                       } else {
+                                               ret_type = new VoidType ();
+                                       }
+                                       var m = new DynamicMethod (expr.inner.static_type, expr.member_name, ret_type, expr.source_reference);
+                                       m.invocation = invoc;
+                                       m.add_error_domain (new ErrorType (null));
+                                       m.access = SymbolAccessibility.PUBLIC;
+                                       m.add_parameter (new FormalParameter.with_ellipsis ());
+                                       context.add_dynamic_member (m);
+                                       expr.symbol_reference = m;
+                               } else if (expr.parent_node is Assignment) {
+                                       var a = (Assignment) expr.parent_node;
+                                       if (a.left == expr
+                                           && (a.operator == AssignmentOperator.ADD
+                                               || a.operator == AssignmentOperator.SUB)) {
+                                               var s = new DynamicSignal (expr.inner.static_type, expr.member_name, new VoidType (), expr.source_reference);
+                                               s.handler = a.right;
+                                               s.access = SymbolAccessibility.PUBLIC;
+                                               context.add_dynamic_member (s);
+                                               expr.symbol_reference = s;
+                                       }
+                               }
                                if (expr.symbol_reference != null) {
                                        may_access_instance_members = true;
-                                       break;
                                }
                        }
+               }
 
-                       if (expr.symbol_reference == null) {
-                               expr.error = true;
-
-                               string base_type_name = "(null)";
-                               if (expr.inner != null && expr.inner.static_type != null) {
-                                       base_type_name = expr.inner.static_type.to_string ();
-                               } else if (base_symbol != null) {
-                                       base_type_name = base_symbol.get_full_name ();
-                               }
+               if (expr.symbol_reference == null) {
+                       expr.error = true;
 
-                               Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_type_name));
-                               return;
+                       string base_type_name = "(null)";
+                       if (expr.inner != null && expr.inner.static_type != null) {
+                               base_type_name = expr.inner.static_type.to_string ();
+                       } else if (base_symbol != null) {
+                               base_type_name = base_symbol.get_full_name ();
                        }
+
+                       Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_type_name));
+                       return;
                }
 
                var member = expr.symbol_reference;
index db86996..3f1b686 100644 (file)
@@ -268,6 +268,7 @@ public class Vala.SymbolResolver : CodeVisitor {
                type.takes_ownership = unresolved_type.takes_ownership;
                type.transfers_ownership = unresolved_type.transfers_ownership;
                type.nullable = unresolved_type.nullable;
+               type.is_dynamic = unresolved_type.is_dynamic;
                foreach (DataType type_arg in unresolved_type.get_type_arguments ()) {
                        type.add_type_argument (type_arg);
                }
@@ -277,6 +278,7 @@ public class Vala.SymbolResolver : CodeVisitor {
                        base_type.takes_ownership = false;
                        base_type.transfers_ownership = false;
                        base_type.nullable = false;
+                       base_type.is_dynamic = false;
 
                        type = new PointerType (base_type);
                }
index decb290..9137c6d 100644 (file)
@@ -59,6 +59,7 @@ public enum Vala.TokenType {
        DIV,
        DO,
        DOT,
+       DYNAMIC,
        ELLIPSIS,
        ELSE,
        ENUM,
index 0e05b7c..5be0095 100644 (file)
@@ -108,6 +108,7 @@ public class Vala.UnresolvedType : DataType {
                result.transfers_ownership = transfers_ownership;
                result.takes_ownership = takes_ownership;
                result.nullable = nullable;
+               result.is_dynamic = is_dynamic;
                result.unresolved_symbol = unresolved_symbol.copy ();
                result.array_rank = array_rank;
                result.pointer_level = pointer_level;
index d7b668a..1ff207d 100644 (file)
@@ -42,6 +42,7 @@ public class Vala.ValueType : DataType {
                result.transfers_ownership = transfers_ownership;
                result.takes_ownership = takes_ownership;
                result.nullable = nullable;
+               result.is_dynamic = is_dynamic;
                result.floating_reference = floating_reference;
                
                foreach (DataType arg in get_type_arguments ()) {
index a3adac3..e262164 100644 (file)
@@ -95,19 +95,20 @@ namespace DBus {
 
        [CCode (ref_function = "dbus_g_connection_ref", unref_function = "dbus_g_connection_unref", cname = "DBusGConnection")]
        public class Connection {
+               [CCode (cname = "dbus_g_proxy_new_for_name")]
+               public Object get_object (string name, string path, string interface_);
        }
 
        [CCode (cname = "DBusGProxy", lower_case_csuffix = "g_proxy")]
-       public class Proxy {
-               public Proxy.for_name (Connection connection, string name, string path, string interface_);
+       public class Object : GLib.Object {
                public bool call (string method, out GLib.Error error, GLib.Type first_arg_type, ...);
-               public weak ProxyCall begin_call (string method, ProxyCallNotify notify, void* data, GLib.DestroyNotify destroy, GLib.Type first_arg_type, ...);
+               public weak ProxyCall begin_call (string method, ProxyCallNotify notify, GLib.DestroyNotify destroy, GLib.Type first_arg_type, ...);
                public bool end_call (ProxyCall call, out GLib.Error error, GLib.Type first_arg_type, ...);
                public void cancel_call (ProxyCall call);
        }
 
        [CCode (cname = "DBusGProxyCallNotify")]
-       public static delegate void ProxyCallNotify (Proxy proxy, ProxyCall call_id, void* user_data);
+       public delegate void ProxyCallNotify (Object obj, ProxyCall call_id);
 
        [CCode (cname = "DBusGProxyCall")]
        public class ProxyCall {