From: Luca Bruno Date: Wed, 4 Jan 2012 11:08:19 +0000 (+0100) Subject: GDBus server transformer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e6da1255b6bcd4fe22a20b0b275712d45b601c0;p=thirdparty%2Fvala.git GDBus server transformer --- diff --git a/codegen/Makefile.am b/codegen/Makefile.am index 49421eb45..234900661 100644 --- a/codegen/Makefile.am +++ b/codegen/Makefile.am @@ -43,6 +43,7 @@ libvalaccodegen_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 5e8b9da2a..79f40ccda 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, int method_timeout) { 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; } @@ -149,9 +160,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), GDBusModule.get_dbus_timeout_for_member (m)); + pop_builder (); } void generate_dbus_proxy_methods (Class proxy_class, Interface iface) { @@ -205,7 +217,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 ()")); @@ -221,6 +233,7 @@ public class Vala.GDBusClientTransformer : GVariantTransformer { b.add_break (); } b.close (); + pop_builder (); } public int get_dbus_timeout (Symbol symbol) { @@ -251,7 +264,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")); @@ -260,14 +273,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); @@ -325,7 +340,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 (); @@ -341,6 +356,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 01fbef616..7c9297e93 100644 --- a/codegen/valagdbusservermodule.vala +++ b/codegen/valagdbusservermodule.vala @@ -21,661 +21,28 @@ */ public class Vala.GDBusServerModule : GDBusClientModule { - string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym, bool ready = false) { - string wrapper_name = "_dbus_%s".printf (get_ccode_name (m)); - bool need_goto_label = ready; - - if (m.base_method != null) { - m = m.base_method; - } else if (m.base_interface_method != null) { - m = m.base_interface_method; + 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; } - 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); - - CCodeIdentifier ready_data_expr = m.coroutine ? new CCodeIdentifier ("_ready_data") : null; - string ready_data_struct_name = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "ReadyData"; - - if (ready) { - ccode.add_declaration (ready_data_struct_name + "*", new CCodeVariableDeclarator ("_ready_data", new CCodeIdentifier ("_user_data_"))); - ccode.add_declaration ("GDBusMethodInvocation*", new CCodeVariableDeclarator ("invocation", new CCodeMemberAccess.pointer (ready_data_expr, "_invocation_"))); - } - - 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"); - ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list")); - } - - 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"))); - ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd")); - } - - CCodeStruct? ready_data_struct = null; - - if (m.coroutine) { - ready_data_struct = new CCodeStruct ("_" + ready_data_struct_name); - ready_data_struct.add_field ("GDBusMethodInvocation*", "_invocation_"); - append_struct (ready_data_struct); - - var ready_data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0")); - ready_data_alloc.add_argument (new CCodeIdentifier (ready_data_struct_name)); - - ccode.add_declaration (ready_data_struct_name + "*", new CCodeVariableDeclarator ("_ready_data")); - ccode.add_assignment (ready_data_expr, ready_data_alloc); - - ccode.add_assignment (new CCodeMemberAccess.pointer (ready_data_expr, "_invocation_"), new CCodeIdentifier ("invocation")); - } - - 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; - } - - CCodeExpression param_expr; - if (ready_data_expr != null) { - param_expr = new CCodeMemberAccess.pointer (ready_data_expr, param_name); - } else { - param_expr = new CCodeIdentifier (param_name); - } - - var owned_type = param.variable_type.copy (); - owned_type.value_owned = true; - - if (ready_data_struct != null) { - ready_data_struct.add_field (get_ccode_name (owned_type), param_name); - } else { - 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) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_variable_array_length_cname (param, dim); - - if (ready_data_struct != null) { - ready_data_struct.add_field (length_ctype, length_cname); - } else { - ccode.add_declaration (length_ctype, 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"), param_expr, 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); - - var free_error = new CCodeFunctionCall (new CCodeIdentifier ("g_error_free")); - free_error.add_argument (new CCodeIdentifier ("error")); - ccode.add_expression (free_error); - - if (need_goto_label || requires_destroy (owned_type)) { - ccode.add_goto ("_error"); - need_goto_label = true; - } else { - ccode.add_return (); - } - - ccode.close (); - } - } - } - - foreach (Parameter param in m.get_parameters ()) { - string param_name = get_variable_cname (param.name); - - CCodeExpression param_expr; - if (ready_data_expr != null && param.direction == ParameterDirection.IN) { - param_expr = new CCodeMemberAccess.pointer (ready_data_expr, param_name); - } else { - param_expr = new CCodeIdentifier (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, param_expr)); - } else { - ccall.add_argument (param_expr); - } - } else if (param.direction == ParameterDirection.OUT && (!m.coroutine || ready)) { - ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, param_expr)); - } - - 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_variable_array_length_cname (param, dim); - - CCodeExpression length_expr; - if (ready_data_expr != null && param.direction == ParameterDirection.IN) - length_expr = new CCodeMemberAccess.pointer (ready_data_expr, length_cname); - else - length_expr = new CCodeIdentifier (length_cname); - - if (param.direction == ParameterDirection.IN && !ready) { - ccall.add_argument (length_expr); - } else if (param.direction == ParameterDirection.OUT && !no_reply && (!m.coroutine || ready)) { - ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr)); - } - } - } - } - - 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 (ready_data_expr); - } - - 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); - - var free_error = new CCodeFunctionCall (new CCodeIdentifier ("g_error_free")); - free_error.add_argument (new CCodeIdentifier ("error")); - ccode.add_expression (free_error); - - if (need_goto_label) { - ccode.add_goto ("_error"); - } else { - ccode.add_return (); - } - - ccode.close (); - } - - ccode.add_declaration ("GDBusMessage*", new CCodeVariableDeclarator.zero ("_reply_message", new CCodeConstant ("NULL"))); - - 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_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) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_variable_array_length_cname (param, dim); - - ccode.add_declaration (length_ctype, 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) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_array_length_cname ("result", dim); - - ccode.add_declaration (length_ctype, 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); - } - - 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); - } - - if (need_goto_label) { - ccode.add_label ("_error"); - } - - foreach (Parameter param in m.get_parameters ()) { - if ((param.direction == ParameterDirection.IN && (ready_data_expr == null || 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)) { - if (ready_data_expr != null && param.direction == ParameterDirection.IN) { - var target = new GLibValue (owned_type, new CCodeMemberAccess.pointer (ready_data_expr, param.name), true); - - var array_type = owned_type as ArrayType; - if (array_type != null) { - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_variable_array_length_cname (param, dim); - - target.append_array_length_cvalue (new CCodeMemberAccess.pointer (ready_data_expr, length_cname)); - } - } - - ccode.add_expression (destroy_value (target)); - } else { - // 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 (ready) { - var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free")); - freecall.add_argument (new CCodeIdentifier (ready_data_struct_name)); - freecall.add_argument (ready_data_expr); - ccode.add_expression (freecall); - } else if (need_goto_label) { - ccode.add_statement (new CCodeEmptyStatement ()); - } - - 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; + return true; } - 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_lower_case_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 (), null); - - function.add_parameter (cparam); - if (param.variable_type is ArrayType) { - var array_type = (ArrayType) param.variable_type; - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - function.add_parameter (new CCodeParameter (get_variable_array_length_cname (param, dim), length_ctype)); - } - } - } - - 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); + public static string dbus_result_name (Method m) { + var dbus_name = m.get_attribute_string ("DBus", "result"); + if (dbus_name != null && dbus_name != "") { + return dbus_name; } - 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; + return "result"; } - 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) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_array_length_cname ("result", dim); - - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0"))); - ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname))); - } - } - } - - ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator ("_reply")); - - if (get_dbus_signature (prop) != null) { - // raw GVariant - ccode.add_assignment (new CCodeIdentifier ("_reply"), new CCodeIdentifier("result")); - } else { - var reply_expr = serialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("result")); - - 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) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (get_array_length_cname ("value", dim))); - ccall.add_argument (new CCodeIdentifier (get_array_length_cname ("value", dim))); - } - } - } - - var target = new CCodeIdentifier ("value"); - - if (get_dbus_signature (prop) != null) { - ccode.add_assignment (target, new CCodeIdentifier("_value")); - ccode.add_expression (ccall); - } else { - 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; + string generate_dbus_signal_wrapper (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) { + return "_dbus_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig)); } void handle_signals (ObjectTypeSymbol sym, bool connect) { @@ -710,25 +77,8 @@ 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; + CCodeExpression get_method_info (ObjectTypeSymbol sym) { + var infos = new CCodeInitializerList (); foreach (Method m in sym.get_methods ()) { if (m is CreationMethod || m.binding != MemberBinding.INSTANCE @@ -739,129 +89,149 @@ public class Vala.GDBusServerModule : GDBusClientModule { continue; } - cfile.add_include ("string.h"); + var in_args_info = new CCodeInitializerList (); + var out_args_info = new CCodeInitializerList (); - 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)))); + foreach (Parameter param in m.get_parameters ()) { + 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") { + continue; + } - 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 info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (param.name))); + info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (param.variable_type, param)))); + info.append (new CCodeConstant ("NULL")); + + var cdecl = new CCodeDeclaration ("const GDBusArgInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_" + param.name, info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); + + if (param.direction == ParameterDirection.IN) { + in_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_" + param.name))); + } else { + out_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_" + param.name))); + } } - 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 (!(m.return_type is VoidType)) { + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (dbus_result_name (m)))); + info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (m.return_type, m)))); + info.append (new CCodeConstant ("NULL")); - if (!first) { - ccode.add_else (); - } + var cdecl = new CCodeDeclaration ("const GDBusArgInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_result", info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - ccall.add_argument (new CCodeIdentifier ("invocation")); - ccode.add_expression (ccall); + out_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_result"))); + } - if (!first) { - ccode.close (); - } + in_args_info.append (new CCodeConstant ("NULL")); + out_args_info.append (new CCodeConstant ("NULL")); - pop_function (); + var cdecl = new CCodeDeclaration ("const GDBusArgInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_in[]", in_args_info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - cfile.add_function_declaration (cfunc); - cfile.add_function (cfunc); - } + cdecl = new CCodeDeclaration ("const GDBusArgInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_out[]", out_args_info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - 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")); + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m)))); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_in")), "GDBusArgInfo **")); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + m.name + "_out")), "GDBusArgInfo **")); + info.append (new CCodeConstant ("NULL")); - cfunc.modifiers |= CCodeModifiers.STATIC; + cdecl = new CCodeDeclaration ("const GDBusMethodInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_method_info_" + m.name, info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - cfile.add_function_declaration (cfunc); + infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_method_info_" + m.name))); + } - push_function (cfunc); + infos.append (new CCodeConstant ("NULL")); - ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data"))); + var cdecl = new CCodeDeclaration ("const GDBusMethodInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_method_info[]", infos)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")))); + return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_method_info"); + } - bool firstif = true; + CCodeExpression get_signal_info (ObjectTypeSymbol sym) { + var infos = new CCodeInitializerList (); - foreach (Property prop in sym.get_properties ()) { - if (prop.binding != MemberBinding.INSTANCE - || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) { - continue; - } - if (!is_dbus_visible (prop)) { + foreach (Signal sig in sym.get_signals ()) { + if (sig.access != SymbolAccessibility.PUBLIC) { continue; } - if (prop.get_accessor == null) { + if (!is_dbus_visible (sig)) { continue; } - cfile.add_include ("string.h"); + var args_info = new CCodeInitializerList (); - 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)))); + foreach (Parameter param in sig.get_parameters ()) { + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (param.name))); + info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (param.variable_type, param)))); + info.append (new CCodeConstant ("NULL")); - var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")); - if (firstif) { - ccode.open_if (cond); - firstif = false; - } else { - ccode.else_if (cond); + var cdecl = new CCodeDeclaration ("const GDBusArgInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + get_ccode_lower_case_name (sig) + "_" + param.name, info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); + + args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + get_ccode_lower_case_name (sig) + "_" + param.name))); } - var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_get_wrapper (prop, sym))); - ccall.add_argument (new CCodeIdentifier ("object")); + args_info.append (new CCodeConstant ("NULL")); - ccode.add_return (ccall); - } - if (!firstif) { - ccode.close (); - } + var cdecl = new CCodeDeclaration ("const GDBusArgInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + get_ccode_lower_case_name (sig) + "[]", args_info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - ccode.add_return (new CCodeConstant ("NULL")); + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig)))); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_arg_info_" + get_ccode_lower_case_name (sig))), "GDBusArgInfo **")); + info.append (new CCodeConstant ("NULL")); - pop_function (); - cfile.add_function (cfunc); - } + cdecl = new CCodeDeclaration ("const GDBusSignalInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_signal_info_" + get_ccode_lower_case_name (sig), info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - 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; + infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_signal_info_" + get_ccode_lower_case_name (sig)))); + } - cfile.add_function_declaration (cfunc); + infos.append (new CCodeConstant ("NULL")); - push_function (cfunc); - - ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data"))); + var cdecl = new CCodeDeclaration ("const GDBusSignalInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_signal_info[]", infos)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")))); + return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_signal_info"); + } - bool firstif = true; + CCodeExpression get_property_info (ObjectTypeSymbol sym) { + var infos = new CCodeInitializerList (); foreach (Property prop in sym.get_properties ()) { if (prop.binding != MemberBinding.INSTANCE @@ -871,38 +241,55 @@ public class Vala.GDBusServerModule : GDBusClientModule { 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; + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop)))); + info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (prop.property_type, prop)))); + if (prop.get_accessor != null && prop.set_accessor != null) { + info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE")); + } else if (prop.get_accessor != null) { + info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_READABLE")); + } else if (prop.set_accessor != null) { + info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE")); } else { - ccode.else_if (cond); + info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_NONE")); } + info.append (new CCodeConstant ("NULL")); - 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")); + var cdecl = new CCodeDeclaration ("const GDBusPropertyInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_property_info_" + prop.name, info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); - ccode.add_expression (ccall); - ccode.add_return (new CCodeConstant ("TRUE")); - } - if (!firstif) { - ccode.close (); + infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_property_info_" + prop.name))); } - ccode.add_return (new CCodeConstant ("FALSE")); - pop_function (); - cfile.add_function (cfunc); + infos.append (new CCodeConstant ("NULL")); + + var cdecl = new CCodeDeclaration ("const GDBusPropertyInfo * const"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_property_info[]", infos)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); + + return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_property_info"); + } + + CCodeExpression get_interface_info (ObjectTypeSymbol sym) { + var info = new CCodeInitializerList (); + info.append (new CCodeConstant ("-1")); + info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name (sym)))); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_method_info (sym)), "GDBusMethodInfo **")); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_signal_info (sym)), "GDBusSignalInfo **")); + info.append (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_property_info (sym)), "GDBusPropertyInfo **")); + info.append (new CCodeConstant ("NULL")); + + var cdecl = new CCodeDeclaration ("const GDBusInterfaceInfo"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_info", info)); + cdecl.modifiers = CCodeModifiers.STATIC; + cfile.add_constant_declaration (cdecl); + + return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_info"); } CCodeExpression get_interface_vtable (ObjectTypeSymbol sym) { @@ -911,10 +298,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 000000000..747c6c160 --- /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 + */ + +/** + * 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 (get_ccode_lower_case_name (sym), get_ccode_lower_case_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 81acf5cb7..e88dd05e2 100644 --- a/codegen/valagvarianttransformer.vala +++ b/codegen/valagvarianttransformer.vala @@ -416,7 +416,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 (get_ccode_name (en)))); @@ -426,6 +426,7 @@ public class Vala.GVariantTransformer : CodeTransformer { b.add_return (expression (@"$(en.get_full_name()).$(enum_value.name)")); } b.close (); + pop_builder (); check (m); } @@ -437,7 +438,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")); @@ -447,6 +448,7 @@ public class Vala.GVariantTransformer : CodeTransformer { b.add_return (expression (@"\"$dbus_value\"")); } b.close (); + pop_builder (); check (m); } @@ -465,7 +467,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; @@ -496,6 +498,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); } @@ -506,7 +509,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; @@ -536,6 +539,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 8b094f3e7..271bce19c 100644 --- a/compiler/valacompiler.vala +++ b/compiler/valacompiler.vala @@ -403,7 +403,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 fd0fbf8c0..87989c857 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 d46c10071..22d1b1ad5 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 builder_stack = new ArrayList (); public HashMap wrapper_cache = new HashMap (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. *