[vala/wip/transform: 32/50] GDBus server transformer



commit a3f69b0ef69e1f82ef632d6774f522a55f5857ca
Author: Luca Bruno <lucabru src gnome org>
Date:   Wed Jan 4 12:08:19 2012 +0100

    GDBus server transformer

 codegen/Makefile.am                     |    1 +
 codegen/valagdbusclienttransformer.vala |   54 ++-
 codegen/valagdbusservermodule.vala      |  741 +------------------------------
 codegen/valagdbusservertransformer.vala |  315 +++++++++++++
 codegen/valagvarianttransformer.vala    |   12 +-
 compiler/valacompiler.vala              |    2 +-
 vala/valacodebuilder.vala               |   19 +
 vala/valacodetransformer.vala           |   11 +
 vala/valasemanticanalyzer.vala          |    9 +-
 9 files changed, 398 insertions(+), 766 deletions(-)
---
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index c941c43..2c6324f 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -46,6 +46,7 @@ libvala_la_VALASOURCES = \
 	valagdbusclienttransformer.vala \
 	valagdbusmodule.vala \
 	valagdbusservermodule.vala \
+	valagdbusservertransformer.vala \
 	valagerrormodule.vala \
 	valagirwriter.vala \
 	valagobjectmodule.vala \
diff --git a/codegen/valagdbusclienttransformer.vala b/codegen/valagdbusclienttransformer.vala
index 13974bb..84456fc 100644
--- a/codegen/valagdbusclienttransformer.vala
+++ b/codegen/valagdbusclienttransformer.vala
@@ -41,7 +41,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 		return Symbol.lower_case_to_camel_case (symbol.name);
 	}
 
-	Expression read_dbus_value (DataType type, string iter, string message, ref string? fd_list, ref string? fd_index) {
+	public Expression read_dbus_value (DataType type, string iter, string message, ref string? fd_list, ref string? fd_index) {
 		string? type_name = null;
 		if (type.data_type != null) {
 			type_name = type.data_type.get_full_name ();
@@ -61,11 +61,33 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 				// socket
 				return expression (@"new GLib.Socket.from_fd ($fd_list.get ($fd_index))");
 			}
+		} else if (type_name == "GLib.Variant") {
+			return expression (@"$iter.next_value().get_variant ()");
 		} else {
 			return expression (@"($(type)) ($iter.next_value ())");
 		}
 	}
 
+	public void write_dbus_value (DataType type, string builder, string value, ref string? fd_list) {
+		string? type_name = null;
+		if (type is ObjectType) {
+			type_name = type.data_type.get_full_name ();
+		}
+		if (type_name == "GLib.Cancellable" || type_name == "GLib.BusName") {
+			return;
+		}
+		if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") {
+			if (fd_list == null) {
+				fd_list = b.add_temp_declaration (null, expression ("new GLib.UnixFDList ()"));
+			}
+			b.add_expression (expression (@"$builder.add (\"h\", $fd_list.append ($value.get_fd ()))"));
+		} else if (type_name == "GLib.Variant") {
+			b.add_expression (expression (@"$builder.add (\"v\", $value)"));
+		} else {
+			b.add_expression (expression (@"$builder.add_value ($value)"));
+		}
+	}
+
 	void generate_marshalling (Method m, string? iface_name, string? method_name) {
 		var interface_name = iface_name != null ? @"\"$iface_name\"" : "this.get_interface_name ()";
 
@@ -81,21 +103,10 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 		foreach (var param in m.get_parameters ()) {
 			if (param.direction == ParameterDirection.IN) {
 				string? type_name = null;
-				if (param.variable_type.data_type != null) {
-					type_name = param.variable_type.data_type.get_full_name ();
-				}
-				if (type_name == "GLib.Cancellable") {
+				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
 					cancellable = param.name;
-				} else if (type_name == "GLib.BusName") {
-					// ignore BusName sender
-				} else if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") {
-					if (fd_list == null) {
-						fd_list = b.add_temp_declaration (null, expression ("new GLib.UnixFDList ()"));
-					}
-					b.add_expression (expression (@"$builder.add (\"h\", $fd_list.append ($(param.name).get_fd ()))"));
-				} else {
-					b.add_expression (expression (@"$builder.add_value ($(param.name))"));
 				}
+				write_dbus_value (param.variable_type, builder, param.name, ref fd_list);
 			} else if (param.direction == ParameterDirection.OUT) {
 				has_result = true;
 			}
@@ -148,9 +159,10 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 		}
 		proxy_class.add_method (proxy);
 
-		b = new CodeBuilder.for_subroutine (proxy);
+		push_builder (new CodeBuilder.for_subroutine (proxy));
 		string dbus_iface_name = get_dbus_name (iface);
 		generate_marshalling (m, dbus_iface_name, get_dbus_name_for_member (m));
+		pop_builder ();
 	}
 
 	void generate_dbus_proxy_methods (Class proxy_class, Interface iface) {
@@ -204,7 +216,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 		}
 		proxy_class.add_method (m);
 
-		b = new CodeBuilder.for_subroutine (m);
+		push_builder (new CodeBuilder.for_subroutine (m));
 
 		b.open_switch (expression ("signal_name"), null);
 		b.add_expression (expression ("assert_not_reached ()"));
@@ -220,6 +232,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 			b.add_break ();
 		}
 		b.close ();
+		pop_builder ();
 	}
 
 	public int get_dbus_timeout (Symbol symbol) {
@@ -250,7 +263,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 
 			proxy_get = new PropertyAccessor (true, false, false, owned_type, null, prop.get_accessor.source_reference);
 
-			b = new CodeBuilder.for_subroutine (proxy_get);
+			push_builder (new CodeBuilder.for_subroutine (proxy_get));
 			// first try cached value
 			var result = b.add_temp_declaration (null, expression (@"get_cached_property (\"$dbus_name\")"));
 			b.open_if (expression (@"$result == null"));
@@ -259,14 +272,16 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 			b.close ();
 
 			b.add_return (expression (@"($(prop.property_type)) ($result)"));
+			pop_builder ();
 		}
 
 		PropertyAccessor proxy_set = null;
 		if (prop.set_accessor != null) {
 			proxy_set = new PropertyAccessor (false, true, false, prop.set_accessor.value_type, null, prop.set_accessor.source_reference);
-			b = new CodeBuilder.for_subroutine (proxy_set);
+			push_builder (new CodeBuilder.for_subroutine (proxy_set));
 			var variant = b.add_temp_declaration (data_type ("GLib.Variant"), expression ("value"));
 			b.add_expression (expression (@"call_sync (\"org.freedesktop.DBus.Properties.Set\", new Variant (\"(ssv)\", \"$dbus_iface_name\", \"$dbus_name\", $variant), GLib.DBusCallFlags.NONE, $timeout, null)"));
+			pop_builder ();
 		}	
 
 		Property proxy = new Property (prop.name, prop.property_type, proxy_get, proxy_set, prop.source_reference);
@@ -324,7 +339,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 			return;
 		}
 
-		b = new CodeBuilder (context, expr.parent_statement, expr.source_reference);
+		push_builder (new CodeBuilder (context, expr.parent_statement, expr.source_reference));
 
 		Method wrapper;
 		var cache_key = "gdbus_client_dynamic_method_call "+m.return_type.to_string ();
@@ -340,6 +355,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer {
 			check (wrapper);
 		}
 
+		pop_builder ();
 		expr.call.symbol_reference = wrapper;
 		base.visit_method_call (expr);
 	}
diff --git a/codegen/valagdbusservermodule.vala b/codegen/valagdbusservermodule.vala
index 436db89..5d4fec9 100644
--- a/codegen/valagdbusservermodule.vala
+++ b/codegen/valagdbusservermodule.vala
@@ -41,548 +41,8 @@ public class Vala.GDBusServerModule : GDBusClientModule {
 		return "result";
 	}
 
-	string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym, bool ready = false) {
-		string wrapper_name = "_dbus_%s".printf (get_ccode_name (m));
-
-		if (m.base_method != null) {
-			m = m.base_method;
-		} else if (m.base_interface_method != null) {
-			m = m.base_interface_method;
-		}
-
-		if (ready) {
-			// async ready function
-			wrapper_name += "_ready";
-		}
-
-		var function = new CCodeFunction (wrapper_name);
-		function.modifiers = CCodeModifiers.STATIC;
-
-		if (!ready) {
-			function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
-			function.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
-			function.add_parameter (new CCodeParameter ("invocation", "GDBusMethodInvocation*"));
-		} else {
-			function.add_parameter (new CCodeParameter ("source_object", "GObject *"));
-			function.add_parameter (new CCodeParameter ("_res_", "GAsyncResult *"));
-			function.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
-		}
-
-		push_function (function);
-
-		if (ready) {
-			ccode.add_declaration ("GDBusMethodInvocation *", new CCodeVariableDeclarator ("invocation", new CCodeIdentifier ("_user_data_")));
-		}
-
-		var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_connection"));
-		connection.add_argument (new CCodeIdentifier ("invocation"));
-
-		bool no_reply = is_dbus_no_reply (m);
-		bool uses_fd = dbus_method_uses_file_descriptor (m);
-		if (uses_fd) {
-			cfile.add_include ("gio/gunixfdlist.h");
-		}
-
-		bool uses_error = false;
-
-		if (!m.coroutine || ready) {
-			ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("error", new CCodeConstant ("NULL")));
-			uses_error = true;
-		}
-
-		if (!ready) {
-			ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter"));
-
-			var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
-			iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
-			iter_init.add_argument (new CCodeIdentifier ("parameters"));
-			ccode.add_expression (iter_init);
-		}
-
-		CCodeFunctionCall ccall;
-		if (!ready) {
-			ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
-			ccall.add_argument (new CCodeIdentifier ("self"));
-		} else {
-			ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
-			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("source_object"), get_ccode_name (sym) + "*"));
-			ccall.add_argument (new CCodeIdentifier ("_res_"));
-		}
-
-		if (!ready) {
-			if (uses_fd) {
-				ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
-			}
-
-			foreach (Parameter param in m.get_parameters ()) {
-				string param_name = get_variable_cname (param.name);
-				if (param.direction != ParameterDirection.IN) {
-					continue;
-				}
-
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
-					continue;
-				}
-
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
-					// ignore BusName sender parameters
-					continue;
-				}
-
-				var owned_type = param.variable_type.copy ();
-				owned_type.value_owned = true;
-
-				ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
-
-				var array_type = param.variable_type as ArrayType;
-				if (array_type != null) {
-					for (int dim = 1; dim <= array_type.rank; dim++) {
-						string length_cname = get_parameter_array_length_cname (param, dim);
-
-						ccode.add_declaration ("int", new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
-					}
-				}
-
-				var message_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_message"));
-				message_expr.add_argument (new CCodeIdentifier ("invocation"));
-
-				bool may_fail;
-				receive_dbus_value (param.variable_type, message_expr, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")), out may_fail);
-
-				if (may_fail) {
-					if (!uses_error) {
-						ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("error", new CCodeConstant ("NULL")));
-						uses_error = true;
-					}
-
-					ccode.open_if (new CCodeIdentifier ("error"));
-
-					var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_gerror"));
-					return_error.add_argument (new CCodeIdentifier ("invocation"));
-					return_error.add_argument (new CCodeIdentifier ("error"));
-					ccode.add_expression (return_error);
-
-					ccode.add_return ();
-
-					ccode.close ();
-				}
-			}
-		}
-
-		foreach (Parameter param in m.get_parameters ()) {
-			string param_name = get_variable_cname (param.name);
-			if (param.direction == ParameterDirection.IN && !ready) {
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
-					ccall.add_argument (new CCodeConstant ("NULL"));
-					continue;
-				}
-
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
-					// ignore BusName sender parameters
-					var sender = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_sender"));
-					sender.add_argument (new CCodeIdentifier ("invocation"));
-					ccall.add_argument (sender);
-					continue;
-				}
-
-				var st = param.variable_type.data_type as Struct;
-				if (st != null && !st.is_simple_type ()) {
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param_name)));
-				} else {
-					ccall.add_argument (new CCodeIdentifier (param_name));
-				}
-			} else if (param.direction == ParameterDirection.OUT && (!m.coroutine || ready)) {
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param_name)));
-			}
-
-			var array_type = param.variable_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					string length_cname = get_parameter_array_length_cname (param, dim);
-
-					if (param.direction == ParameterDirection.IN && !ready) {
-						ccall.add_argument (new CCodeIdentifier (length_cname));
-					} else if (param.direction == ParameterDirection.OUT && !no_reply && (!m.coroutine || ready)) {
-						ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
-					}
-				}
-			}
-		}
-
-		if (!m.coroutine || ready) {
-			if (!(m.return_type is VoidType)) {
-				if (m.return_type.is_real_non_null_struct_type ()) {
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
-				} else {
-					var array_type = m.return_type as ArrayType;
-					if (array_type != null) {
-						for (int dim = 1; dim <= array_type.rank; dim++) {
-							string length_cname = get_array_length_cname ("result", dim);
-
-							ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
-						}
-					}
-				}
-			}
-		}
-
-		if (m.coroutine && !ready) {
-			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (wrapper_name + "_ready"), "GAsyncReadyCallback"));
-			ccall.add_argument (new CCodeIdentifier ("invocation"));
-		}
-
-		if (!m.coroutine || ready) {
-			if (m.tree_can_fail) {
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
-			}
-		}
-
-		if (!no_reply && (!m.coroutine || ready)) {
-			if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
-				ccode.add_expression (ccall);
-			} else {
-				ccode.add_assignment (new CCodeIdentifier ("result"), ccall);
-			}
-
-			if (m.tree_can_fail) {
-				ccode.open_if (new CCodeIdentifier ("error"));
-
-				var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_gerror"));
-				return_error.add_argument (new CCodeIdentifier ("invocation"));
-				return_error.add_argument (new CCodeIdentifier ("error"));
-				ccode.add_expression (return_error);
-
-				ccode.add_return ();
-
-				ccode.close ();
-			}
-
-			ccode.add_declaration ("GDBusMessage*", new CCodeVariableDeclarator ("_reply_message"));
-
-			var message_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_message"));
-			message_expr.add_argument (new CCodeIdentifier ("invocation"));
-
-			ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_reply"));
-			ccall.add_argument (message_expr);
-			ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
-
-			ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator ("_reply"));
-			ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_reply_builder"));
-
-			var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
-			builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
-			builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
-			ccode.add_expression (builder_init);
-
-			if (uses_fd) {
-				ccode.add_declaration ("GUnixFDList", new CCodeVariableDeclarator ("*_fd_list"));
-				ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new")));
-			}
-
-			foreach (Parameter param in m.get_parameters ()) {
-				if (param.direction != ParameterDirection.OUT) {
-					continue;
-				}
-
-				string param_name = get_variable_cname (param.name);
-				var owned_type = param.variable_type.copy ();
-				owned_type.value_owned = true;
-
-				ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
-
-				var array_type = param.variable_type as ArrayType;
-				if (array_type != null) {
-					for (int dim = 1; dim <= array_type.rank; dim++) {
-						string length_cname = get_parameter_array_length_cname (param, dim);
-
-						ccode.add_declaration ("int", new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
-					}
-				}
-
-				send_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier (param_name), param);
-			}
-
-			if (!(m.return_type is VoidType)) {
-				if (m.return_type.is_real_non_null_struct_type ()) {
-					ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("result", default_value_for_type (m.return_type, true)));
-
-					send_dbus_value (m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"), m);
-
-					if (requires_destroy (m.return_type)) {
-						// keep local alive (symbol_reference is weak)
-						var local = new LocalVariable (m.return_type, ".result");
-						ccode.add_expression (destroy_local (local));
-					}
-				} else {
-					ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
-
-					var array_type = m.return_type as ArrayType;
-					if (array_type != null) {
-						for (int dim = 1; dim <= array_type.rank; dim++) {
-							string length_cname = get_array_length_cname ("result", dim);
-
-							ccode.add_declaration ("int", new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
-						}
-					}
-
-					send_dbus_value (m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"), m);
-
-					if (requires_destroy (m.return_type)) {
-						// keep local alive (symbol_reference is weak)
-						var local = new LocalVariable (m.return_type, ".result");
-						ccode.add_expression (destroy_local (local));
-					}
-				}
-			}
-
-			var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
-			builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
-			ccode.add_assignment (new CCodeIdentifier ("_reply"), builder_end);
-
-			var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
-			set_body.add_argument (new CCodeIdentifier ("_reply_message"));
-			set_body.add_argument (new CCodeIdentifier ("_reply"));
-			ccode.add_expression (set_body);
-
-			if (uses_fd) {
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
-				ccall.add_argument (new CCodeIdentifier ("_reply_message"));
-				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
-				ccode.add_expression (ccall);
-
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
-				ccode.add_expression (ccall);
-			}
-		} else {
-			ccode.add_expression (ccall);
-		}
-
-		foreach (Parameter param in m.get_parameters ()) {
-			if ((param.direction == ParameterDirection.IN && !ready) ||
-			    (param.direction == ParameterDirection.OUT && !no_reply && (!m.coroutine || ready))) {
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
-					continue;
-				}
-
-				if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
-					// ignore BusName sender parameters
-					continue;
-				}
-
-				var owned_type = param.variable_type.copy ();
-				owned_type.value_owned = true;
-
-				if (requires_destroy (owned_type)) {
-					// keep local alive (symbol_reference is weak)
-					var local = new LocalVariable (owned_type, get_variable_cname (param.name));
-					ccode.add_expression (destroy_local (local));
-				}
-			}
-		}
-
-		if (!no_reply && (!m.coroutine || ready)) {
-			var return_value = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
-			return_value.add_argument (connection);
-			return_value.add_argument (new CCodeIdentifier ("_reply_message"));
-			return_value.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
-			return_value.add_argument (new CCodeConstant ("NULL"));
-			return_value.add_argument (new CCodeConstant ("NULL"));
-			ccode.add_expression (return_value);
-
-			// free invocation like g_dbus_method_invocation_return_*
-			var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-			unref_call.add_argument (new CCodeIdentifier ("invocation"));
-			ccode.add_expression (unref_call);
-
-			unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-			unref_call.add_argument (new CCodeIdentifier ("_reply_message"));
-			ccode.add_expression (unref_call);
-		}
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		if (m.coroutine && !ready) {
-			// generate ready function
-			generate_dbus_wrapper (m, sym, true);
-		}
-
-		return wrapper_name;
-	}
-
 	string generate_dbus_signal_wrapper (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) {
-		string wrapper_name = "_dbus_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_name (sig));
-
-		var function = new CCodeFunction (wrapper_name, "void");
-		function.modifiers = CCodeModifiers.STATIC;
-
-		function.add_parameter (new CCodeParameter ("_sender", "GObject*"));
-
-		foreach (var param in sig.get_parameters ()) {
-			// ensure ccodenode of parameter is set
-			var cparam = generate_parameter (param, cfile, new HashMap<int,CCodeParameter> (), null);
-
-			function.add_parameter (cparam);
-			if (param.variable_type is ArrayType) {
-				var array_type = (ArrayType) param.variable_type;
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					function.add_parameter (new CCodeParameter (get_parameter_array_length_cname (param, dim), "int"));
-				}
-			}
-		}
-
-		function.add_parameter (new CCodeParameter ("_data", "gpointer*"));
-
-		push_function (function);
-
-		ccode.add_declaration ("GDBusConnection *", new CCodeVariableDeclarator ("_connection", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("1"))));
-		ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator ("_path", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("2"))));
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
-		ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
-
-		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
-		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
-		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
-		ccode.add_expression (builder_init);
-
-		foreach (Parameter param in sig.get_parameters ()) {
-			string param_name = get_variable_cname (param.name);
-			CCodeExpression expr = new CCodeIdentifier (param_name);
-			if (param.variable_type.is_real_struct_type ()) {
-				expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
-			}
-			write_expression (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
-		}
-
-		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
-		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
-		ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
-
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_emit_signal"));
-		ccall.add_argument (new CCodeIdentifier ("_connection"));
-		ccall.add_argument (new CCodeConstant ("NULL"));
-		ccall.add_argument (new CCodeIdentifier ("_path"));
-		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
-		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
-		ccall.add_argument (new CCodeIdentifier ("_arguments"));
-		ccall.add_argument (new CCodeConstant ("NULL"));
-		ccode.add_expression (ccall);
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return wrapper_name;
-	}
-
-	string generate_dbus_property_get_wrapper (Property prop, ObjectTypeSymbol sym) {
-		string wrapper_name = "_dbus_%s".printf (get_ccode_name (prop.get_accessor));
-
-		var function = new CCodeFunction (wrapper_name, "GVariant*");
-		function.modifiers = CCodeModifiers.STATIC;
-		function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
-
-		push_function (function);
-
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.get_accessor)));
-		ccall.add_argument (new CCodeIdentifier ("self"));
-
-		if (prop.get_accessor.value_type.is_real_non_null_struct_type ()) {
-			ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator.zero ("result", default_value_for_type (prop.get_accessor.value_type, true)));
-			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
-
-			ccode.add_expression (ccall);
-		} else {
-			ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("result"));
-			ccode.add_assignment (new CCodeIdentifier ("result"), ccall);
-
-			var array_type = prop.get_accessor.value_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					string length_cname = get_array_length_cname ("result", dim);
-
-					ccode.add_declaration ("int", new CCodeVariableDeclarator (length_cname));
-					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
-				}
-			}
-		}
-
-		var reply_expr = serialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("result"));
-
-		ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator ("_reply"));
-		ccode.add_assignment (new CCodeIdentifier ("_reply"), reply_expr);
-
-		if (requires_destroy (prop.get_accessor.value_type)) {
-			// keep local alive (symbol_reference is weak)
-			var local = new LocalVariable (prop.get_accessor.value_type, ".result");
-			ccode.add_expression (destroy_local (local));
-		}
-
-		ccode.add_return (new CCodeIdentifier ("_reply"));
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return wrapper_name;
-	}
-
-	string generate_dbus_property_set_wrapper (Property prop, ObjectTypeSymbol sym) {
-		string wrapper_name = "_dbus_%s".printf (get_ccode_name (prop.set_accessor));
-
-		var function = new CCodeFunction (wrapper_name);
-		function.modifiers = CCodeModifiers.STATIC;
-		function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
-		function.add_parameter (new CCodeParameter ("_value", "GVariant*"));
-
-		push_function (function);
-
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.set_accessor)));
-		ccall.add_argument (new CCodeIdentifier ("self"));
-
-		var owned_type = prop.property_type.copy ();
-		owned_type.value_owned = true;
-
-		ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero ("value", default_value_for_type (prop.property_type, true)));
-
-		var st = prop.property_type.data_type as Struct;
-		if (st != null && !st.is_simple_type ()) {
-			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
-		} else {
-			ccall.add_argument (new CCodeIdentifier ("value"));
-
-			var array_type = prop.property_type as ArrayType;
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					ccode.add_declaration ("int", new CCodeVariableDeclarator (get_array_length_cname ("value", dim)));
-					ccall.add_argument (new CCodeIdentifier (get_array_length_cname ("value", dim)));
-				}
-			}
-		}
-
-		var target = new CCodeIdentifier ("value");
-		var expr = deserialize_expression (prop.property_type, new CCodeIdentifier ("_value"), target);
-		ccode.add_assignment (target, expr);
-
-		ccode.add_expression (ccall);
-
-		if (requires_destroy (owned_type)) {
-			// keep local alive (symbol_reference is weak)
-			var local = new LocalVariable (owned_type, "value");
-			ccode.add_expression (destroy_local (local));
-		}
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return wrapper_name;
+		return "_dbus_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_name (sig));
 	}
 
 	void handle_signals (ObjectTypeSymbol sym, bool connect) {
@@ -617,201 +77,6 @@ public class Vala.GDBusServerModule : GDBusClientModule {
 		}
 	}
 
-	void generate_interface_method_call_function (ObjectTypeSymbol sym) {
-		var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_method_call", "void");
-		cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
-		cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("method_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
-		cfunc.add_parameter (new CCodeParameter ("invocation", "GDBusMethodInvocation*"));
-		cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
-
-		cfunc.modifiers |= CCodeModifiers.STATIC;
-
-		push_function (cfunc);
-
-		ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
-		ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
-
-		bool first = true;
-
-		foreach (Method m in sym.get_methods ()) {
-			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
-			    || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-			if (!is_dbus_visible (m)) {
-				continue;
-			}
-
-			cfile.add_include ("string.h");
-
-			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
-			ccheck.add_argument (new CCodeIdentifier ("method_name"));
-			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m))));
-
-			if (first) {
-				ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")));
-				first = false;
-			} else {
-				ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")));
-			}
-
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_wrapper (m, sym)));
-			ccall.add_argument (new CCodeIdentifier ("object"));
-			ccall.add_argument (new CCodeIdentifier ("parameters"));
-			ccall.add_argument (new CCodeIdentifier ("invocation"));
-			ccode.add_expression (ccall);
-		}
-
-		if (!first) {
-			ccode.add_else ();
-		}
-
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-		ccall.add_argument (new CCodeIdentifier ("invocation"));
-		ccode.add_expression (ccall);
-
-		if (!first) {
-			ccode.close ();
-		}
-
-		pop_function ();
-
-		cfile.add_function_declaration (cfunc);
-		cfile.add_function (cfunc);
-	}
-
-	void generate_interface_get_property_function (ObjectTypeSymbol sym) {
-		var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_get_property", "GVariant*");
-		cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
-		cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("property_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
-		cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
-
-		cfunc.modifiers |= CCodeModifiers.STATIC;
-
-		cfile.add_function_declaration (cfunc);
-
-		push_function (cfunc);
-
-		ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
-
-		ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
-
-		bool firstif = true;
-
-		foreach (Property prop in sym.get_properties ()) {
-			if (prop.binding != MemberBinding.INSTANCE
-			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-			if (!is_dbus_visible (prop)) {
-				continue;
-			}
-			if (prop.get_accessor == null) {
-				continue;
-			}
-
-			cfile.add_include ("string.h");
-
-			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
-			ccheck.add_argument (new CCodeIdentifier ("property_name"));
-			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
-
-			var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
-			if (firstif) {
-				ccode.open_if (cond);
-				firstif = false;
-			} else {
-				ccode.else_if (cond);
-			}
-
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_get_wrapper (prop, sym)));
-			ccall.add_argument (new CCodeIdentifier ("object"));
-
-			ccode.add_return (ccall);
-		}
-		if (!firstif) {
-			ccode.close ();
-		}
-
-		ccode.add_return (new CCodeConstant ("NULL"));
-
-		pop_function ();
-		cfile.add_function (cfunc);
-	}
-
-	void generate_interface_set_property_function (ObjectTypeSymbol sym) {
-		var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_set_property", "gboolean");
-		cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
-		cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("property_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
-		cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
-		cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
-
-		cfunc.modifiers |= CCodeModifiers.STATIC;
-
-		cfile.add_function_declaration (cfunc);
-
-		push_function (cfunc);
-
-		ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
-
-		ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
-
-		bool firstif = true;
-
-		foreach (Property prop in sym.get_properties ()) {
-			if (prop.binding != MemberBinding.INSTANCE
-			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-			if (!is_dbus_visible (prop)) {
-				continue;
-			}
-			if (prop.set_accessor == null) {
-				continue;
-			}
-
-			cfile.add_include ("string.h");
-
-			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
-			ccheck.add_argument (new CCodeIdentifier ("property_name"));
-			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
-
-			var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
-			if (firstif) {
-				ccode.open_if (cond);
-				firstif = false;
-			} else {
-				ccode.else_if (cond);
-			}
-
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_set_wrapper (prop, sym)));
-			ccall.add_argument (new CCodeIdentifier ("object"));
-			ccall.add_argument (new CCodeIdentifier ("value"));
-
-			ccode.add_expression (ccall);
-			ccode.add_return (new CCodeConstant ("TRUE"));
-		}
-		if (!firstif) {
-			ccode.close ();
-		}
-		ccode.add_return (new CCodeConstant ("FALSE"));
-
-		pop_function ();
-		cfile.add_function (cfunc);
-	}
-
 	CCodeExpression get_method_info (ObjectTypeSymbol sym) {
 		var infos = new CCodeInitializerList ();
 
@@ -1026,10 +291,6 @@ public class Vala.GDBusServerModule : GDBusClientModule {
 		vtable.append (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "dbus_interface_get_property"));
 		vtable.append (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "dbus_interface_set_property"));
 
-		generate_interface_method_call_function (sym);
-		generate_interface_get_property_function (sym);
-		generate_interface_set_property_function (sym);
-
 		var cdecl = new CCodeDeclaration ("const GDBusInterfaceVTable");
 		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_vtable", vtable));
 		cdecl.modifiers = CCodeModifiers.STATIC;
diff --git a/codegen/valagdbusservertransformer.vala b/codegen/valagdbusservertransformer.vala
new file mode 100644
index 0000000..16570c7
--- /dev/null
+++ b/codegen/valagdbusservertransformer.vala
@@ -0,0 +1,315 @@
+/* valagdbusservertransformer.vala
+ *
+ * Copyright (C) 2011  Luca Bruno
+ *
+ * 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:
+ * 	Luca Bruno <lucabru src gnome org>
+ */
+
+/**
+ * Code visitor for transforming the code tree related to DBus server.
+ */
+public class Vala.GDBusServerTransformer : GDBusClientTransformer {
+	public override void visit_class (Class cl) {
+		visit_object_type_symbol (cl);
+
+		base.visit_class (cl);
+	}
+
+	public override void visit_interface (Interface iface) {
+		visit_object_type_symbol (iface);
+
+		base.visit_interface (iface);
+	}
+
+	string generate_dbus_method_wrapper (Method m, ObjectTypeSymbol sym) {
+		Method wrapper;
+		wrapper_method (new VoidType (), "gdbus_server "+m.get_full_name (), out wrapper);
+		var object_type = context.analyzer.get_data_type_for_symbol (sym);
+		wrapper.add_parameter (new Parameter ("object", object_type));
+		wrapper.add_parameter (new Parameter ("arguments", data_type ("GLib.Variant", false)));
+		wrapper.add_parameter (new Parameter ("invocation", data_type ("GLib.DBusMethodInvocation", false)));
+		b.push_method (wrapper);
+
+		var iter = b.add_temp_declaration (null, expression ("arguments.iterator ()"));
+
+		var call = (MethodCall) expression (@"object.$(m.name) ()");
+		var finish_call = call;
+		Method ready = null;
+		CodeBuilder ready_builder = null;
+		if (m.coroutine) {
+			wrapper_method (new VoidType (), "gdbus_server_async_ready "+m.get_full_name (), out ready);
+			ready.add_parameter (new Parameter ("source_object", data_type ("GLib.Object", false)));
+			ready.add_parameter (new Parameter ("res", data_type ("GLib.AsyncResult", false)));
+			ready.add_parameter (new Parameter ("invocation", data_type ("GLib.DBusMethodInvocation", false)));
+			ready_builder = new CodeBuilder.for_subroutine (ready);
+
+			finish_call = (MethodCall) expression (@"(($object_type)(source_object)).$(m.name).end (res)");
+		}
+
+		var out_args = new string[0];
+		var out_types = new DataType[0];
+		string fd_list = null;
+		string fd_index = null;
+		foreach (var param in m.get_parameters ()) {
+			string? type_name = null;
+			if (param.variable_type is ObjectType) {
+				type_name = param.variable_type.data_type.get_full_name ();
+			}
+			if (type_name == "GLib.Cancellable") {
+				call.add_argument (expression ("null"));
+				continue;
+			}
+			if (type_name == "GLib.BusName") {
+				continue;
+			}
+
+			if (param.direction == ParameterDirection.IN) {
+				var arg = b.add_temp_declaration (copy_type (param.variable_type, true));
+				b.add_assignment (expression (arg), read_dbus_value (param.variable_type, iter, "invocation.get_message ()", ref fd_list, ref fd_index));
+				call.add_argument (expression (arg));
+			} else if (param.direction == ParameterDirection.OUT) {
+				if (m.coroutine) {
+					// declare the out argument in the ready callback
+					push_builder (ready_builder);
+				}
+				var arg = b.add_temp_declaration (copy_type (param.variable_type, true));
+				out_args += arg;
+				out_types += param.variable_type;
+				finish_call.add_argument (new UnaryExpression (UnaryOperator.OUT, expression (arg), m.source_reference));
+				if (m.coroutine) {
+					pop_builder ();
+				}
+			}
+		}
+
+		if (m.coroutine) {
+			call.add_argument (expression (@"(s,r) => $(ready.name) (s, r, invocation)"));
+			b.add_expression (call);
+			push_builder (ready_builder);
+		}
+
+		b.open_try ();
+		string result = null;
+		if (m.has_result) {
+			result = b.add_temp_declaration (m.return_type);
+			b.add_assignment (expression (result), finish_call);
+		} else {
+			b.add_expression (finish_call);
+		}
+		b.add_catch (data_type ("GLib.Error"), "e");
+		b.add_expression (expression ("invocation.return_gerror (e)"));
+		b.add_return ();
+		b.close ();
+
+		fd_list = null;
+		var reply = b.add_temp_declaration (null, expression ("new GLib.DBusMessage.method_reply (invocation.get_message ())"));
+		var builder = b.add_temp_declaration (null, expression ("new GLib.VariantBuilder (GLib.VariantType.TUPLE)"));
+		for (int i=0; i < out_args.length; i++) {
+			write_dbus_value (out_types[i], builder, out_args[i], ref fd_list);
+		}
+		if (result != null) {
+			write_dbus_value (m.return_type, builder, result, ref fd_list);
+		}
+		b.add_expression (expression (@"$reply.set_body ($builder.end ())"));
+		if (fd_list != null) {
+			b.add_expression (expression (@"$reply.set_unix_fd_list ($fd_list)"));
+		}
+		b.add_expression (expression (@"invocation.get_connection().send_message ($reply, GLib.DBusSendMessageFlags.NONE, null)"));
+
+		if (m.coroutine) {
+			pop_builder ();
+			check (ready);
+		}
+
+		b.pop_method ();
+		check (wrapper);
+		return wrapper.name;
+	}
+
+	public static bool is_dbus_visible (CodeNode node) {
+		var dbus_attribute = node.get_attribute ("DBus");
+		if (dbus_attribute != null
+		    && dbus_attribute.has_argument ("visible")
+		    && !dbus_attribute.get_bool ("visible")) {
+			return false;
+		}
+
+		return true;
+	}
+
+	void generate_interface_method_call (ObjectTypeSymbol sym) {
+		if (sym.scope.lookup ("dbus_interface_method_call") != null) {
+			return;
+		}
+
+		var im = new Method ("dbus_interface_method_call", new VoidType (), sym.source_reference);
+		im.access = SymbolAccessibility.PRIVATE;
+		im.binding = MemberBinding.STATIC;
+		im.add_parameter (new Parameter ("connection", data_type ("GLib.DBusConnection", false)));
+		im.add_parameter (new Parameter ("sender", data_type ("string", false)));
+		im.add_parameter (new Parameter ("object_path", data_type ("string", false)));
+		im.add_parameter (new Parameter ("interface_name", data_type ("string", false)));
+		im.add_parameter (new Parameter ("method_name", data_type ("string", false)));
+		im.add_parameter (new Parameter ("parameters", data_type ("GLib.Variant", false)));
+		im.add_parameter (new Parameter ("invocation", data_type ("GLib.DBusMethodInvocation", false)));
+		im.add_parameter (new Parameter ("user_data", new PointerType (new VoidType ())));
+		sym.add_method (im);
+
+		push_builder (new CodeBuilder.for_subroutine (im));
+		var object_type = context.analyzer.get_data_type_for_symbol (sym);
+		var object = b.add_temp_declaration (null, expression (@"($object_type) (((Object[])user_data)[0])"));
+		b.open_switch (expression ("method_name"), null);
+		b.add_return ();
+		foreach (var m in sym.get_methods ()) {
+			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
+			    || m.overrides || m.access != SymbolAccessibility.PUBLIC
+				|| !is_dbus_visible (m)) {
+				continue;
+			}
+			b.add_section (expression (@"\"$(get_dbus_name_for_member (m))\""));
+			var wrapper = generate_dbus_method_wrapper (m, sym);
+			b.add_expression (expression (@"$wrapper ($object, parameters, invocation)"));
+			b.add_break ();
+		}
+		b.close ();
+		pop_builder ();
+		check (im);
+	}
+
+	void generate_interface_get_property (ObjectTypeSymbol sym) {
+		if (sym.scope.lookup ("dbus_interface_get_property") != null) {
+			return;
+		}
+
+		var m = new Method ("dbus_interface_get_property", data_type ("GLib.Variant", true, true), sym.source_reference);
+		m.access = SymbolAccessibility.PRIVATE;
+		m.binding = MemberBinding.STATIC;
+		m.add_parameter (new Parameter ("connection", data_type ("GLib.DBusConnection", false)));
+		m.add_parameter (new Parameter ("sender", data_type ("string", false)));
+		m.add_parameter (new Parameter ("object_path", data_type ("string", false)));
+		m.add_parameter (new Parameter ("interface_name", data_type ("string", false)));
+		m.add_parameter (new Parameter ("property_name", data_type ("string", false)));
+		m.add_parameter (new Parameter ("error", new PointerType (new PointerType (new VoidType ()))));
+		m.add_parameter (new Parameter ("user_data", new PointerType (new VoidType ())));
+		sym.add_method (m);
+
+		push_builder (new CodeBuilder.for_subroutine (m));
+		var object_type = context.analyzer.get_data_type_for_symbol (sym);
+		var object = b.add_temp_declaration (null, expression (@"($object_type) (((Object[])user_data)[0])"));
+		b.open_switch (expression ("property_name"), null);
+		b.add_return (expression ("null"));
+		foreach (var prop in sym.get_properties ()) {
+			if (prop.binding != MemberBinding.INSTANCE
+			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC
+				|| !is_dbus_visible (prop)
+				|| prop.get_accessor == null) {
+				continue;
+			}
+			b.add_section (expression (@"\"$(get_dbus_name_for_member (prop))\""));
+			b.add_return (expression (@"$object.$(prop.name)"));
+		}
+		pop_builder ();
+		check (m);
+	}
+
+	void generate_interface_set_property (ObjectTypeSymbol sym) {
+		if (sym.scope.lookup ("dbus_interface_set_property") != null) {
+			return;
+		}
+
+		var m = new Method ("dbus_interface_set_property", data_type ("bool"), sym.source_reference);
+		m.access = SymbolAccessibility.PRIVATE;
+		m.binding = MemberBinding.STATIC;
+		m.add_parameter (new Parameter ("connection", data_type ("GLib.DBusConnection", false)));
+		m.add_parameter (new Parameter ("sender", data_type ("string", false)));
+		m.add_parameter (new Parameter ("object_path", data_type ("string", false)));
+		m.add_parameter (new Parameter ("interface_name", data_type ("string", false)));
+		m.add_parameter (new Parameter ("property_name", data_type ("string", false)));
+		m.add_parameter (new Parameter ("value", data_type ("GLib.Variant", false)));
+		m.add_parameter (new Parameter ("error", new PointerType (new PointerType (new VoidType ()))));
+		m.add_parameter (new Parameter ("user_data", new PointerType (new VoidType ())));
+		sym.add_method (m);
+
+		push_builder (new CodeBuilder.for_subroutine (m));
+		var object_type = context.analyzer.get_data_type_for_symbol (sym);
+		var object = b.add_temp_declaration (null, expression (@"($object_type) (((Object[])user_data)[0])"));
+		b.open_switch (expression ("property_name"), null);
+		b.add_return (expression ("false"));
+		foreach (var prop in sym.get_properties ()) {
+			if (prop.binding != MemberBinding.INSTANCE
+			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC
+				|| !is_dbus_visible (prop)
+				|| prop.set_accessor == null) {
+				continue;
+			}
+			b.add_section (expression (@"\"$(get_dbus_name_for_member (prop))\""));
+			b.add_expression (expression (@"$object.$(prop.name) = ($(prop.property_type)) value"));
+			b.add_return (expression ("true"));
+		}
+		pop_builder ();
+		check (m);
+	}
+
+	void generate_interface_signal_emitter (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) {
+		var wrapper_name = "_dbus_%s_%s".printf (CCodeBaseModule.get_ccode_lower_case_name (sym), CCodeBaseModule.get_ccode_name (sig));
+		if (context.root.scope.lookup (wrapper_name) != null) {
+			return;
+		}
+
+		var m = new Method (wrapper_name, new VoidType (), sym.source_reference);
+		context.root.add_method (m);
+		m.access = SymbolAccessibility.PRIVATE;
+		m.binding = MemberBinding.STATIC;
+		m.add_parameter (new Parameter ("_sender", data_type ("GLib.Object", false)));
+		foreach (var param in sig.get_parameters ()) {
+			m.add_parameter (param.copy ());
+		}
+		m.add_parameter (new Parameter ("_data", new PointerType (new PointerType (new VoidType ()))));
+		push_builder (new CodeBuilder.for_subroutine (m));
+
+		var builder = b.add_temp_declaration (null, expression ("new GLib.VariantBuilder (GLib.VariantType.TUPLE)"));
+		foreach (var param in sig.get_parameters ()) {
+			if (param.variable_type.data_type == context.analyzer.gvariant_type.data_type) {
+				b.add_expression (expression (@"$builder.add (\"v\", $(param.name))"));
+			} else {
+				b.add_expression (expression (@"$builder.add_value ($(param.name))"));
+			}
+		}
+		b.add_expression (expression (@"((GLib.DBusConnection) _data[1]).emit_signal (null, (string) _data[2], \"$dbus_iface_name\", \"$(get_dbus_name_for_member (sig))\", $builder.end ())"));
+		pop_builder ();
+		check (m);
+	}
+
+	void visit_object_type_symbol (ObjectTypeSymbol sym) {
+		string dbus_iface_name = get_dbus_name (sym);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		generate_interface_method_call (sym);
+		generate_interface_get_property (sym);
+		generate_interface_set_property (sym);
+
+		foreach (var sig in sym.get_signals ()) {
+			if (sig.access != SymbolAccessibility.PUBLIC || !is_dbus_visible (sig)) {
+				continue;
+			}
+			generate_interface_signal_emitter (sig, sym, dbus_iface_name);
+		}
+	}
+}
diff --git a/codegen/valagvarianttransformer.vala b/codegen/valagvarianttransformer.vala
index 491240c..f1b9e51 100644
--- a/codegen/valagvarianttransformer.vala
+++ b/codegen/valagvarianttransformer.vala
@@ -414,7 +414,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		en.add_method (m);
 		m.binding = MemberBinding.STATIC;
 		m.access = SymbolAccessibility.PUBLIC;
-		b = new CodeBuilder.for_subroutine (m);
+		push_builder (new CodeBuilder.for_subroutine (m));
 
 		b.open_switch (expression ("str"), null);
 		b.add_throw (expression ("new GLib.DBusError.INVALID_ARGS (\"Invalid value for enum `%s'\")".printf (CCodeBaseModule.get_ccode_name (en))));
@@ -424,6 +424,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 			b.add_return (expression (@"$(en.get_full_name()).$(enum_value.name)"));
 		}
 		b.close ();
+		pop_builder ();
 
 		check (m);
 	}
@@ -435,7 +436,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		var m = new Method ("to_string", data_type ("string", false, true), en.source_reference);
 		en.add_method (m);
 		m.access = SymbolAccessibility.PUBLIC;
-		b = new CodeBuilder.for_subroutine (m);
+		push_builder (new CodeBuilder.for_subroutine (m));
 
 		b.open_switch (expression ("this"), null);
 		b.add_return (expression ("null"));
@@ -445,6 +446,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 			b.add_return (expression (@"\"$dbus_value\""));
 		}
 		b.close ();
+		pop_builder ();
 
 		check (m);
 	}
@@ -463,7 +465,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 			return;
 		}
 
-		b = new CodeBuilder (context, expr.parent_statement, expr.source_reference);
+		push_builder (new CodeBuilder (context, expr.parent_statement, expr.source_reference));
 		var old_parent_node = expr.parent_node;
 		var target_type = expr.target_type.copy ();
 		var type = expr.value_type;
@@ -494,6 +496,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		context.analyzer.replaced_nodes.add (expr);
 		old_parent_node.replace_expression (expr, result);
 		b.check (this);
+		pop_builder ();
 		check (result);
 	}
 
@@ -504,7 +507,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 			return;
 		}
 
-		b = new CodeBuilder (context, expr.parent_statement, expr.source_reference);
+		push_builder (new CodeBuilder (context, expr.parent_statement, expr.source_reference));
 		var old_parent_node = expr.parent_node;
 		var target_type = expr.target_type.copy ();
 		var type = expr.value_type;
@@ -534,6 +537,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		context.analyzer.replaced_nodes.add (expr);
 		old_parent_node.replace_expression (expr, result);
 		b.check (this);
+		pop_builder ();
 		check (result);
 	}
 }
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index 5ccf586..fe8f8ed 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -342,7 +342,7 @@ class Vala.Compiler {
 			}
 		}
 
-		var transformer = new GDBusClientTransformer ();
+		var transformer = new GDBusServerTransformer ();
 		transformer.transform (context);
 
 		if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) {
diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala
index 825fd12..f32cca3 100644
--- a/vala/valacodebuilder.vala
+++ b/vala/valacodebuilder.vala
@@ -196,6 +196,25 @@ public class Vala.CodeBuilder {
 		section.add_label (label);
 	}
 
+	public void open_try () {
+		build_context.statement_stack.add (build_context.current_block);
+		var parent_block = build_context.current_block;
+
+		build_context.current_block = new Block (source_reference);
+
+		var stmt = new TryStatement (build_context.current_block, null, source_reference);
+		build_context.statement_stack.add (stmt);
+
+		parent_block.add_statement (stmt);
+	}
+
+	public void add_catch (DataType? error_type, string? variable_name) {
+		build_context.current_block = new Block (source_reference);
+
+		var stmt = (TryStatement) build_context.statement_stack[build_context.statement_stack.size-1];
+		stmt.add_catch_clause (new CatchClause (error_type, variable_name, build_context.current_block, source_reference));
+	}
+
 	public void add_statement (Statement statement) {
 		build_context.current_block.add_statement (statement);
 	}
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index 8df4099..6ee1e77 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -27,8 +27,19 @@ public class Vala.CodeTransformer : CodeVisitor {
 	public CodeContext context;
 
 	public CodeBuilder b;
+	public ArrayList<CodeBuilder> builder_stack = new ArrayList<CodeBuilder> ();
 	public HashMap<string, CodeNode> wrapper_cache = new HashMap<string, CodeNode> (str_hash, str_equal);
 
+	public void push_builder (CodeBuilder builder) {
+		builder_stack.add (b);
+		b = builder;
+	}
+
+	public void pop_builder () {
+		b = builder_stack[builder_stack.size - 1];
+		builder_stack.remove_at (builder_stack.size - 1);
+	}
+
 	/**
 	 * Transform the code tree for the specified code context.
 	 *
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index ad30589..198b074 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -357,8 +357,13 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
 		List<TypeParameter> type_parameters = null;
 		if (sym is ObjectTypeSymbol) {
-			type = new ObjectType ((ObjectTypeSymbol) sym);
-			type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
+			var cl = sym as Class;
+			if (cl != null && cl.is_error_base) {
+				type = new ErrorType (null, null);
+			} else {
+				type = new ObjectType ((ObjectTypeSymbol) sym);
+				type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
+			}
 		} else if (sym is Struct) {
 			var st = (Struct) sym;
 			if (st.is_boolean_type ()) {



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