[vala/wip/cpp] cpp: Add basic support for using C++ libraries



commit 4dfd1fdcf9be28d47ad02232d78bbf4acb393c62
Author: Luca Bruno <lucabru src gnome org>
Date:   Sat Mar 31 22:56:00 2012 +0200

    cpp: Add basic support for using C++ libraries

 ccode/Makefile.am                 |    3 +
 ccode/valacppdeletestatement.vala |   47 ++++
 ccode/valacppmethodcall.vala      |   45 ++++
 ccode/valacppobjectcreation.vala  |   38 +++
 codegen/Makefile.am               |    1 +
 codegen/valaccodebasemodule.vala  |    2 +-
 codegen/valacppmodule.vala        |  524 +++++++++++++++++++++++++++++++++++++
 codegen/valagerrormodule.vala     |    2 +-
 8 files changed, 660 insertions(+), 2 deletions(-)
---
diff --git a/ccode/Makefile.am b/ccode/Makefile.am
index c63dd06..eb542ee 100644
--- a/ccode/Makefile.am
+++ b/ccode/Makefile.am
@@ -64,6 +64,9 @@ libvalaccode_la_VALASOURCES = \
 	valaccodewhilestatement.vala \
 	valaccodewriter.vala \
 	valaccodeelementaccess.vala \
+	valacppdeletestatement.vala \
+	valacppmethodcall.vala \
+	valacppobjectcreation.vala \
 	$(NULL)
 
 libvalaccode_la_SOURCES = \
diff --git a/ccode/valacppdeletestatement.vala b/ccode/valacppdeletestatement.vala
new file mode 100644
index 0000000..ba62964
--- /dev/null
+++ b/ccode/valacppdeletestatement.vala
@@ -0,0 +1,47 @@
+/* valacppdeletestatement.vala
+ *
+ * Copyright (C) 2012  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>
+ */
+
+using GLib;
+
+/**
+ * Represents a delete statement in the C++ code.
+ */
+public class Vala.CppDeleteStatement : CCodeStatement {
+	/**
+	 * The optional expression to return.
+	 */
+	public CCodeExpression delete_expression { get; set; }
+
+	public CppDeleteStatement (CCodeExpression expr) {
+		delete_expression = expr;
+	}
+
+	public override void write (CCodeWriter writer) {
+		writer.write_indent (line);
+		writer.write_string ("delete ");
+
+		delete_expression.write (writer);
+
+		writer.write_string (";");
+		writer.write_newline ();
+	}
+}
diff --git a/ccode/valacppmethodcall.vala b/ccode/valacppmethodcall.vala
new file mode 100644
index 0000000..5411f8d
--- /dev/null
+++ b/ccode/valacppmethodcall.vala
@@ -0,0 +1,45 @@
+/* valacppmethodcall.vala
+ *
+ * Copyright (C) 2012  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>
+ */
+
+using GLib;
+
+/**
+ * Represents a method call in the C++ code.
+ */
+public class Vala.CppMethodCall : CCodeFunctionCall {
+	/**
+	 * Instance on which to call the C++ method.
+	 */
+	CCodeExpression instance;
+
+	public CppMethodCall (CCodeExpression call, CCodeExpression instance) {
+		base (call);
+		this.instance = instance;
+	}
+
+	public override void write (CCodeWriter writer) {
+		instance.write_inner (writer);
+		writer.write_string ("->");
+
+		base.write (writer);
+	}
+}
diff --git a/ccode/valacppobjectcreation.vala b/ccode/valacppobjectcreation.vala
new file mode 100644
index 0000000..47e33b8
--- /dev/null
+++ b/ccode/valacppobjectcreation.vala
@@ -0,0 +1,38 @@
+/* valacppobjectcreation.vala
+ *
+ * Copyright (C) 2012  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>
+ */
+
+using GLib;
+
+/**
+ * Represents a 'new' expression in the C++ code.
+ */
+public class Vala.CppObjectCreation : CCodeFunctionCall {
+	public CppObjectCreation (CCodeExpression? call = null) {
+		base (call);
+	}
+
+	public override void write (CCodeWriter writer) {
+		writer.write_string ("new ");
+
+		base.write (writer);
+	}
+}
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index 2535a88..dbf558f 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -27,6 +27,7 @@ libvala_la_VALASOURCES = \
 	valaccodemethodmodule.vala \
 	valaccodestructmodule.vala \
 	valaclassregisterfunction.vala \
+	valacppmodule.vala \
 	valactype.vala \
 	valadovaarraymodule.vala \
 	valadovaassignmentmodule.vala \
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 866e8b9..c3e9c7d 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -2878,7 +2878,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 		return element_destroy_func_expression;
 	}
 
-	public CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
+	public virtual CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
 		if (context.profile == Profile.GOBJECT && (type.data_type == glist_type || type.data_type == gslist_type || type.data_type == gnode_type || type.data_type == gqueue_type)) {
 			// create wrapper function to free list elements if necessary
 
diff --git a/codegen/valacppmodule.vala b/codegen/valacppmodule.vala
new file mode 100644
index 0000000..1f65236
--- /dev/null
+++ b/codegen/valacppmodule.vala
@@ -0,0 +1,524 @@
+/* valacppmodule.vala
+ *
+ * Copyright (C) 2012  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>
+ */
+
+
+public class Vala.CppModule : CCodeDelegateModule {
+	public string get_cpp_name (Symbol sym) {
+		return sym.name;
+	}
+
+	public string get_cpp_full_name (Symbol sym) {
+		if (sym.parent_symbol == context.root) {
+			return get_cpp_name (sym);
+		} else {
+			return "%s::%s".printf (get_cpp_full_name (sym.parent_symbol), get_cpp_name (sym));
+		}
+	}
+
+	public string get_cpp_wrapper_name (Symbol sym) {
+		return get_cpp_full_name (sym).replace ("::", "__");
+	}
+
+	public override CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
+		var cl = type.data_type as Class;
+		if (cl == null || cl.get_attribute ("Cpp") == null) {
+			return base.get_destroy_func_expression (type, is_chainup);
+		}
+
+		string destroy_func = "_vala_cpp_%s_free".printf (get_cpp_wrapper_name (cl));
+		if (!add_wrapper (destroy_func)) {
+			// wrapper already defined
+			return new CCodeIdentifier (destroy_func);
+		}
+
+		var function = new CCodeFunction (destroy_func, "void");
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeParameter ("self", get_cpp_full_name (cl)+"*"));
+
+		push_function (function);
+
+		ccode.add_statement (new CppDeleteStatement (new CCodeIdentifier ("self")));
+
+		pop_function ();
+
+		cfile.add_function_declaration (function);
+		cfile.add_function (function);
+
+		return new CCodeIdentifier (destroy_func);
+	}
+
+	public override void visit_object_creation_expression (ObjectCreationExpression expr) {	
+		var cl = expr.type_reference.data_type as Class;
+		var m = expr.symbol_reference as CreationMethod;
+		if (cl == null || m == null || cl.get_attribute ("Cpp") == null) {
+			base.visit_object_creation_expression (expr);
+			return;
+		}
+
+		check_type (expr.type_reference);
+		generate_method_declaration (m, cfile);
+
+		var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+		var creation_call = new CppObjectCreation (new CCodeIdentifier (get_cpp_full_name (cl)));
+
+		bool ellipsis = false;
+		int i = 1;
+		int arg_pos;
+		Iterator<Parameter> params_it = m.get_parameters().iterator ();
+		foreach (Expression arg in expr.get_argument_list ()) {
+			CCodeExpression cexpr = get_cvalue (arg);
+			Parameter param = null;
+			if (params_it.next ()) {
+				param = params_it.get ();
+				ellipsis = param.ellipsis;
+				if (!ellipsis) {
+					if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
+						var array_type = (ArrayType) param.variable_type;
+						for (int dim = 1; dim <= array_type.rank; dim++) {
+							carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_array_length_cexpression (arg, dim));
+						}
+					} else if (param.variable_type is DelegateType) {
+						var deleg_type = (DelegateType) param.variable_type;
+						var d = deleg_type.delegate_symbol;
+						if (d.has_target) {
+							CCodeExpression delegate_target_destroy_notify;
+							var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
+							carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
+							if (deleg_type.value_owned) {
+								carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
+							}
+						}
+					}
+
+					cexpr = handle_struct_argument (param, arg, cexpr);
+
+					if (get_ccode_type (param) != null) {
+						cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
+					}
+				} else {
+					cexpr = handle_struct_argument (null, arg, cexpr);
+				}
+
+				arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
+			} else {
+				// default argument position
+				cexpr = handle_struct_argument (null, arg, cexpr);
+				arg_pos = get_param_pos (i, ellipsis);
+			}
+
+			carg_map.set (arg_pos, cexpr);
+
+			i++;
+		}
+		while (params_it.next ()) {
+			var param = params_it.get ();
+
+			if (param.ellipsis) {
+				ellipsis = true;
+				break;
+			}
+
+			if (param.initializer == null) {
+				Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+				return;
+			}
+
+			/* evaluate default expression here as the code
+			 * generator might not have visited the formal
+			 * parameter yet */
+			param.initializer.emit (this);
+
+			carg_map.set (get_param_pos (get_ccode_pos (param)), get_cvalue (param.initializer));
+			i++;
+		}
+
+		// append C arguments in the right order
+		int last_pos = -1;
+		int min_pos;
+		while (true) {
+			min_pos = -1;
+			foreach (int pos in carg_map.get_keys ()) {
+				if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+					min_pos = pos;
+				}
+			}
+			if (min_pos == -1) {
+				break;
+			}
+			creation_call.add_argument (carg_map.get (min_pos));
+			last_pos = min_pos;
+		}
+		var temp_value = create_temp_value (expr.value_type, false, expr);
+		ccode.add_assignment (get_cvalue_ (temp_value), creation_call);
+		expr.target_value = temp_value;
+		((GLibValue) expr.target_value).lvalue = true;
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		var itype = expr.call.value_type;
+		var ma = expr.call as MemberAccess;
+		Method m;
+		if (ma != null && ma.inner != null && ma.symbol_reference is Method) {
+			m = (Method) ma.symbol_reference;
+			if (m.parent_symbol.get_attribute ("Cpp") == null) {
+				base.visit_method_call (expr);
+				return;
+			}
+		} else {
+			base.visit_method_call (expr);
+			return;
+		}
+
+		var ccall = new CppMethodCall (new CCodeIdentifier (get_cpp_name (m)), get_cvalue (ma.inner));
+		CCodeExpression ccall_expr = ccall;
+
+		var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+		var out_arg_map = in_arg_map;
+
+		bool ellipsis = false;
+
+		int i = 1;
+		int arg_pos;
+		Iterator<Parameter> params_it = m.get_parameters().iterator ();
+		foreach (Expression arg in expr.get_argument_list ()) {
+			CCodeExpression cexpr = get_cvalue (arg);
+
+			var carg_map = in_arg_map;
+
+			if (params_it.next ()) {
+				var param = params_it.get ();
+				ellipsis = param.params_array || param.ellipsis;
+				if (!ellipsis) {
+					if (param.direction == ParameterDirection.OUT) {
+						carg_map = out_arg_map;
+					}
+
+					var unary = arg as UnaryExpression;
+					if (unary == null || unary.operator != UnaryOperator.OUT) {
+						if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
+							var array_type = (ArrayType) param.variable_type;
+							for (int dim = 1; dim <= array_type.rank; dim++) {
+								CCodeExpression? array_length_expr = null;
+								if (get_ccode_array_length_type (param) != null) {
+									array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), get_ccode_array_length_type (param));
+								} else {
+									array_length_expr = get_array_length_cexpression (arg, dim);
+								}
+								carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), array_length_expr);
+							}
+						} else if (param.variable_type is DelegateType) {
+							var deleg_type = (DelegateType) param.variable_type;
+							var d = deleg_type.delegate_symbol;
+							if (d.has_target) {
+								CCodeExpression delegate_target_destroy_notify;
+								var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
+								assert (delegate_target != null);
+								if (get_ccode_type (param) == "GClosure*") {
+									// one single GClosure parameter
+									var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
+									closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
+									closure_new.add_argument (delegate_target);
+									closure_new.add_argument (delegate_target_destroy_notify);
+									cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeIdentifier ("NULL")), new CCodeIdentifier ("NULL"), closure_new);
+								} else {
+									carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
+									if (deleg_type.value_owned) {
+										assert (delegate_target_destroy_notify != null);
+										carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), delegate_target_destroy_notify);
+									}
+								}
+							}
+						} else if (param.variable_type is MethodType) {
+							// callbacks in dynamic method calls
+							CCodeExpression delegate_target_destroy_notify;
+							carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
+						} else if (param.variable_type is GenericType) {
+							if (m != null && get_ccode_simple_generics (m)) {
+								var generic_type = (GenericType) param.variable_type;
+								int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
+								var type_arg = ma.get_type_arguments ().get (type_param_index);
+								if (param.variable_type.value_owned) {
+									if (requires_copy (type_arg)) {
+										carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), get_destroy_func_expression (type_arg));
+									} else {
+										carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeConstant ("NULL"));
+									}
+								}
+							}
+						}
+
+						cexpr = handle_struct_argument (param, arg, cexpr);
+					} else {
+						arg.target_value = null;
+
+						var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned);
+						emit_temp_var (temp_var);
+						set_cvalue (arg, get_variable_cexpression (temp_var.name));
+						arg.target_value.value_type = arg.target_type;
+
+						cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
+
+						if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
+							var array_type = (ArrayType) param.variable_type;
+							var array_length_type = int_type;
+							if (get_ccode_array_length_type (param) != null) {
+								array_length_type = new CType (get_ccode_array_length_type (param));
+							}
+							for (int dim = 1; dim <= array_type.rank; dim++) {
+								var temp_array_length = get_temp_variable (array_length_type);
+								emit_temp_var (temp_array_length);
+								append_array_length (arg, get_variable_cexpression (temp_array_length.name));
+								carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_lengths (arg).get (dim - 1)));
+							}
+						} else if (param.variable_type is DelegateType) {
+							var deleg_type = (DelegateType) param.variable_type;
+							var d = deleg_type.delegate_symbol;
+							if (d.has_target) {
+								temp_var = get_temp_variable (new PointerType (new VoidType ()));
+								emit_temp_var (temp_var);
+								set_delegate_target (arg, get_variable_cexpression (temp_var.name));
+								carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
+								if (deleg_type.value_owned) {
+									temp_var = get_temp_variable (gdestroynotify_type);
+									emit_temp_var (temp_var);
+									set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
+									carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param) + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
+								}
+							}
+						}
+					}
+
+					if (get_ccode_type (param) != null) {
+						cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
+					}
+				} else {
+					cexpr = handle_struct_argument (null, arg, cexpr);
+				}
+				arg_pos = get_param_pos (get_ccode_pos (param), ellipsis);
+			} else {
+				// default argument position
+				cexpr = handle_struct_argument (null, arg, cexpr);
+				arg_pos = get_param_pos (i, ellipsis);
+			}
+
+			carg_map.set (arg_pos, cexpr);
+
+			if (arg is NamedArgument && ellipsis) {
+				var named_arg = (NamedArgument) arg;
+				string name = string.joinv ("-", named_arg.name.split ("_"));
+				carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
+			}
+
+			i++;
+		}
+		if (params_it.next ()) {
+			var param = params_it.get ();
+
+			/* if there are more parameters than arguments,
+			 * the additional parameter is an ellipsis parameter
+			 * otherwise there is a bug in the semantic analyzer
+			 */
+			assert (param.params_array || param.ellipsis);
+			ellipsis = true;
+		}
+
+		/* add length argument for methods returning arrays */
+		if (m != null && m.return_type is ArrayType) {
+			var array_type = (ArrayType) m.return_type;
+			for (int dim = 1; dim <= array_type.rank; dim++) {
+				if (get_ccode_array_null_terminated (m)) {
+					// handle calls to methods returning null-terminated arrays
+					var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
+					var temp_ref = get_variable_cexpression (temp_var.name);
+
+					emit_temp_var (temp_var);
+
+					ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
+
+					requires_array_length = true;
+					var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
+					len_call.add_argument (temp_ref);
+
+					append_array_length (expr, len_call);
+				} else if (get_ccode_array_length (m)) {
+					LocalVariable temp_var;
+
+					if (get_ccode_array_length_type (m) == null) {
+						temp_var = get_temp_variable (int_type);
+					} else {
+						temp_var = get_temp_variable (new CType (get_ccode_array_length_type (m)));
+					}
+					var temp_ref = get_variable_cexpression (temp_var.name);
+
+					emit_temp_var (temp_var);
+
+					out_arg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+					append_array_length (expr, temp_ref);
+				} else {
+					append_array_length (expr, new CCodeConstant ("-1"));
+				}
+			}
+		} else if (m != null && m.return_type is DelegateType) {
+			var deleg_type = (DelegateType) m.return_type;
+			var d = deleg_type.delegate_symbol;
+			if (d.has_target) {
+				var temp_var = get_temp_variable (new PointerType (new VoidType ()));
+				var temp_ref = get_variable_cexpression (temp_var.name);
+
+				emit_temp_var (temp_var);
+
+				out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+				set_delegate_target (expr, temp_ref);
+
+				if (deleg_type.value_owned) {
+					temp_var = get_temp_variable (gdestroynotify_type);
+					temp_ref = get_variable_cexpression (temp_var.name);
+
+					emit_temp_var (temp_var);
+
+					out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
+
+					set_delegate_target_destroy_notify (expr, temp_ref);
+				} else {
+					set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
+				}
+			} else {
+				set_delegate_target (expr, new CCodeConstant ("NULL"));
+			}
+		}
+
+		if (ellipsis) {
+			/* ensure variable argument list ends with NULL
+			 * except when using printf-style arguments */
+			if (m == null) {
+				in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
+			} else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "") {
+				in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
+			}
+		}
+
+		if (itype is DelegateType) {
+			var deleg_type = (DelegateType) itype;
+			var d = deleg_type.delegate_symbol;
+			if (d.has_target) {
+				CCodeExpression delegate_target_destroy_notify;
+				in_arg_map.set (get_param_pos (get_ccode_instance_pos (d)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
+				out_arg_map.set (get_param_pos (get_ccode_instance_pos (d)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
+			}
+		}
+
+		// structs are returned via out parameter
+		bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
+
+		CCodeExpression out_param_ref = null;
+
+		if (return_result_via_out_param) {
+			var out_param_var = get_temp_variable (itype.get_return_type ());
+			out_param_ref = get_variable_cexpression (out_param_var.name);
+			emit_temp_var (out_param_var);
+			out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, out_param_ref));
+		}
+
+		// append C arguments in the right order
+
+		int last_pos;
+		int min_pos;
+
+		last_pos = -1;
+		while (true) {
+			min_pos = -1;
+			foreach (int pos in in_arg_map.get_keys ()) {
+				if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+					min_pos = pos;
+				}
+			}
+			if (min_pos == -1) {
+				break;
+			}
+			ccall.add_argument (in_arg_map.get (min_pos));
+			last_pos = min_pos;
+		}
+
+		if (return_result_via_out_param) {
+			ccode.add_expression (ccall_expr);
+			ccall_expr = out_param_ref;
+		}
+
+		if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
+			if (ccall_expr != null && !return_result_via_out_param) {
+				ccode.add_expression (ccall_expr);
+			}
+		} else {
+			var result_type = itype.get_return_type ();
+
+			if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
+				var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
+				if (expr.formal_value_type.type_parameter.parent_symbol == garray_type ||
+				    (st != null && get_ccode_name (st) == "va_list")) {
+					// GArray and va_list don't use pointer-based generics
+					// above logic copied from visit_expression ()
+					// TODO avoid code duplication
+					result_type = expr.value_type;
+				}
+			}
+
+			if (!return_result_via_out_param) {
+				var temp_var = get_temp_variable (result_type, result_type.value_owned);
+				var temp_ref = get_variable_cexpression (temp_var.name);
+
+				emit_temp_var (temp_var);
+
+				ccode.add_assignment (temp_ref, ccall_expr);
+				set_cvalue (expr, temp_ref);
+			} else {
+				set_cvalue (expr, ccall_expr);
+			}
+			((GLibValue) expr.target_value).lvalue = true;
+		}
+
+		params_it = m.get_parameters().iterator ();
+		foreach (Expression arg in expr.get_argument_list ()) {
+			if (params_it.next ()) {
+				var param = params_it.get ();
+				if (param.params_array || param.ellipsis) {
+					// ignore ellipsis arguments as we currently don't use temporary variables for them
+					break;
+				}
+			}
+
+			var unary = arg as UnaryExpression;
+			if (unary == null || unary.operator != UnaryOperator.OUT) {
+				continue;
+			}
+
+			if (requires_destroy (unary.inner.value_type)) {
+				// unref old value
+				ccode.add_expression (destroy_value (unary.inner.target_value));
+			}
+
+			// assign new value
+			store_value (unary.inner.target_value, transform_value (unary.target_value, unary.inner.value_type, arg));
+		}
+	}
+}
diff --git a/codegen/valagerrormodule.vala b/codegen/valagerrormodule.vala
index 23d11a3..3047ad4 100644
--- a/codegen/valagerrormodule.vala
+++ b/codegen/valagerrormodule.vala
@@ -23,7 +23,7 @@
 
 using GLib;
 
-public class Vala.GErrorModule : CCodeDelegateModule {
+public class Vala.GErrorModule : CppModule {
 	private int current_try_id = 0;
 	private int next_try_id = 0;
 	private bool is_in_catch = false;



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